From 3ac7add4d5bcd33f2b4dfec2d0ccafa815048a87 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 20:34:11 +0200 Subject: [PATCH 01/99] Add opt-in Node runtime and upstream framework suites --- .github/workflows/frameworks.yml | 143 + AGENTS.md | 10 + CHANGELOG.md | 7 + README.md | 11 + bin/phasis | 14 +- composer.json | 4 +- docs/api.md | 29 + docs/cli.md | 27 +- docs/modules.md | 84 +- phpcs.xml | 5 + scripts/node-http/build.py | 43 + scripts/node-http/upstream.json | 7 + scripts/node-portable/.gitignore | 2 + scripts/node-portable/build.py | 126 + scripts/node-portable/http2-constants.json | 242 + scripts/node-portable/node-sources.json | 29 + scripts/node-portable/package-lock.json | 1348 + scripts/node-portable/package.json | 14 + scripts/node-primitives/.gitignore | 2 + scripts/node-primitives/README.md | 65 + scripts/node-primitives/brotli-LICENSES.txt | 234 + .../node-primitives/brotli-decoder-entry.cjs | 2 + .../node-primitives/brotli-encoder-entry.cjs | 18 + scripts/node-primitives/buffer-entry.cjs | 62 + scripts/node-primitives/build.mjs | 110 + scripts/node-primitives/events-entry.cjs | 175 + scripts/node-primitives/generate-oracles.mjs | 18 + scripts/node-primitives/package-lock.json | 661 + scripts/node-primitives/package.json | 18 + .../stream-consumers-entry.cjs | 17 + scripts/node-primitives/stream-entry.cjs | 133 + .../node-primitives/stream-promises-entry.cjs | 2 + scripts/node-primitives/stream-web-entry.cjs | 55 + .../node-primitives/string_decoder-entry.cjs | 2 + src/BuiltIn/AbortControllerConstructor.php | 54 +- src/BuiltIn/CryptoKeyConstructor.php | 47 + src/BuiltIn/CryptoObject.php | 1 + src/BuiltIn/DomExceptionConstructor.php | 1 + src/BuiltIn/Ed25519Crypto.php | 193 + src/BuiltIn/EventTargetConstructor.php | 120 + src/BuiltIn/Fetch/BodyExtraction.php | 46 +- src/BuiltIn/Fetch/BodyMixin.php | 210 +- src/BuiltIn/FetchFunction.php | 62 +- src/BuiltIn/GlobalObject.php | 16 +- src/BuiltIn/HeadersConstructor.php | 22 + src/BuiltIn/JsonObject.php | 12 +- src/BuiltIn/RequestConstructor.php | 58 +- src/BuiltIn/ResponseConstructor.php | 31 +- src/BuiltIn/Streams/ByteStream.php | 40 +- src/BuiltIn/Streams/PipeOperations.php | 34 +- src/BuiltIn/Streams/ReadableStream.php | 50 +- src/BuiltIn/Streams/StreamHelpers.php | 20 + src/BuiltIn/String/StringIteration.php | 30 +- src/BuiltIn/String/StringSearch.php | 28 +- src/BuiltIn/StructuredCloneFunction.php | 14 +- src/BuiltIn/SubtleCryptoObject.php | 63 +- src/BuiltIn/TextDecoderConstructor.php | 50 +- src/Bytecode/CompilationFailures.php | 61 + src/Bytecode/CompilationTemplates.php | 39 + src/Bytecode/CompiledFunction.php | 3 + src/Bytecode/Compiler.php | 107 +- src/Bytecode/JsToPhp.php | 12 + src/Bytecode/Op.php | 26 + .../Parts/CompilerBailoutAnalysis.php | 107 +- src/Bytecode/Parts/CompilerEmit.php | 27 +- src/Bytecode/Parts/CompilerExpression.php | 117 +- src/Bytecode/Parts/CompilerScope.php | 205 +- src/Bytecode/Parts/CompilerStatement.php | 115 +- src/Bytecode/VM.php | 96 +- src/Engine.php | 76 +- src/Module/CommonJsLoader.php | 184 +- src/Module/ModuleLoader.php | 110 +- src/Module/ModuleOptions.php | 17 + src/Module/ModuleResolver.php | 47 +- src/Node/ChildProcessBindings.php | 526 + src/Node/ChildProcessState.php | 43 + src/Node/CryptoBindings.php | 166 + src/Node/ErrorStack.php | 121 + src/Node/FileSystemBindings.php | 470 + src/Node/FileSystemError.php | 18 + src/Node/HostBindings.php | 234 + src/Node/IoBindings.php | 636 + src/Node/Lib/assert.cjs | 4629 +++ src/Node/Lib/async_hooks.cjs | 89 + src/Node/Lib/broadcast_channel.cjs | 92 + src/Node/Lib/brotli-decoder.cjs | 3335 ++ src/Node/Lib/brotli-encoder.cjs | 30266 ++++++++++++++++ src/Node/Lib/buffer.cjs | 1804 + src/Node/Lib/child_process.cjs | 301 + src/Node/Lib/crypto.cjs | 206 + src/Node/Lib/events.cjs | 613 + src/Node/Lib/fetch.cjs | 88 + src/Node/Lib/fs.cjs | 535 + src/Node/Lib/http-common.cjs | 45 + src/Node/Lib/http-constants.cjs | 106 + src/Node/Lib/http-parser.LICENSE.md | 110 + src/Node/Lib/http-parser.cjs | 470 + src/Node/Lib/http.cjs | 544 + src/Node/Lib/http2.cjs | 496 + src/Node/Lib/https.cjs | 40 + src/Node/Lib/module.cjs | 12 + src/Node/Lib/net.cjs | 216 + src/Node/Lib/path.cjs | 1712 + src/Node/Lib/portable/LICENSES.json | 64 + src/Node/Lib/portable/NODE_LICENSE.txt | 2923 ++ src/Node/Lib/portable/constants.cjs | 58 + src/Node/Lib/portable/errors.cjs | 28 + src/Node/Lib/portable/format.cjs | 67 + src/Node/Lib/portable/glob.cjs | 26 + src/Node/Lib/portable/helpers.cjs | 15 + src/Node/Lib/portable/hpack.cjs | 6152 ++++ src/Node/Lib/portable/http2-constants.json | 242 + .../Lib/portable/internal-querystring.cjs | 119 + src/Node/Lib/portable/minimatch.cjs | 1733 + src/Node/Lib/portable/primordials.cjs | 33 + src/Node/Lib/portable/punycode.cjs | 254 + src/Node/Lib/portable/sources.json | 30 + src/Node/Lib/portable/tr46.cjs | 578 + src/Node/Lib/portable/util-base.cjs | 2362 ++ src/Node/Lib/portable/validators.cjs | 15 + src/Node/Lib/portable/whatwg-url.cjs | 123 + src/Node/Lib/primitives-LICENSES.txt | 439 + src/Node/Lib/primitives-manifest.json | 91 + src/Node/Lib/process.cjs | 57 + src/Node/Lib/querystring.cjs | 615 + src/Node/Lib/stdio.cjs | 43 + src/Node/Lib/stream-consumers.cjs | 26 + src/Node/Lib/stream-promises.cjs | 5 + src/Node/Lib/stream-web.cjs | 92 + src/Node/Lib/stream.cjs | 5636 +++ src/Node/Lib/string_decoder.cjs | 310 + src/Node/Lib/timers-promises.cjs | 52 + src/Node/Lib/timers.cjs | 74 + src/Node/Lib/tls.cjs | 171 + src/Node/Lib/tty.cjs | 11 + src/Node/Lib/url.cjs | 1045 + src/Node/Lib/util.cjs | 44 + src/Node/Lib/vm.cjs | 63 + src/Node/Lib/zlib.cjs | 250 + src/Node/NodeCommand.php | 82 + src/Node/NodeOptions.php | 21 + src/Node/NodeRuntime.php | 304 + src/Node/OsModule.php | 191 + src/Node/PathBindings.php | 57 + src/Node/SocketState.php | 43 + src/Node/VmBindings.php | 172 + src/Node/VmContext.php | 22 + src/Node/VmGlobalObject.php | 157 + src/Node/VmRealmState.php | 101 + src/Node/ZlibBindings.php | 195 + src/Node/child-runtime.php | 24 + src/Runtime/CallFrame.php | 1 + src/Runtime/CallStack.php | 8 +- src/Runtime/Environment.php | 71 +- src/Runtime/EventLoop.php | 239 +- src/Runtime/EventLoopTask.php | 1 + src/Runtime/Interpreter.php | 23 +- src/Runtime/Parts/ExpressionEvaluation.php | 233 +- src/Runtime/Parts/Helpers/RegExpHelpers.php | 16 +- src/Runtime/Parts/StatementExecution.php | 11 +- src/Spec/AbstractOperations.php | 29 + src/Value/JsGenerator.php | 60 +- src/Value/JsPromise.php | 77 +- src/Value/JsString.php | 17 +- tests/Frameworks/.gitignore | 4 + tests/Frameworks/express/manifest.json | 5666 +++ tests/Frameworks/express/run-node.cjs | 33 + tests/Frameworks/express/run-phasis.php | 108 + tests/Frameworks/express/run.py | 218 + tests/Frameworks/express/runner.cjs | 97 + tests/Frameworks/express/setup.py | 45 + tests/Frameworks/express/test_runner.py | 44 + tests/Frameworks/express/upstream.json | 7 + tests/Frameworks/hono/.gitignore | 3 + tests/Frameworks/hono/README.md | 117 + tests/Frameworks/hono/build-selftest.mjs | 14 + tests/Frameworks/hono/build.mjs | 100 + tests/Frameworks/hono/compare-native.py | 49 + tests/Frameworks/hono/deadline.mjs | 50 + .../hono/fixtures/timeouts-entry.mjs | 7 + .../hono/fixtures/timeouts.test.mjs | 47 + tests/Frameworks/hono/harness.mjs | 298 + tests/Frameworks/hono/inventory.py | 39 + tests/Frameworks/hono/prepare-toolchain.mjs | 19 + tests/Frameworks/hono/run-php.php | 63 + tests/Frameworks/hono/run-toolchain.py | 53 + tests/Frameworks/hono/run.py | 192 + tests/Frameworks/hono/selftest.config.mjs | 7 + tests/Frameworks/hono/selftest.py | 69 + tests/Frameworks/hono/setup.py | 51 + tests/Frameworks/hono/test_runner.py | 35 + tests/Frameworks/hono/upstream.json | 10 + tests/Frameworks/hono/vitest.config.mjs | 21 + tests/Frameworks/http2/certificate.php | 20 + tests/Frameworks/http2/client.cjs | 27 + tests/Frameworks/http2/interop.mjs | 69 + tests/Frameworks/http2/run-php.php | 23 + tests/Frameworks/http2/server.cjs | 22 + tests/Frameworks/package-lock.json | 5630 +++ tests/Frameworks/package.json | 41 + tests/Unit/BuiltIn/AsyncContextTest.php | 22 + tests/Unit/BuiltIn/Ed25519CryptoTest.php | 77 + tests/Unit/BuiltIn/FunctionProxyCallTest.php | 47 + tests/Unit/BuiltIn/JsonPropertyNamesTest.php | 49 + tests/Unit/BuiltIn/LiveFetchBodyTest.php | 89 + tests/Unit/BuiltIn/MessageEventTest.php | 41 + .../BuiltIn/ReadableStreamSchedulingTest.php | 86 + tests/Unit/BuiltIn/RequestTest.php | 19 +- tests/Unit/BuiltIn/StringCodeUnitTest.php | 83 + tests/Unit/BuiltIn/StructuredCloneTest.php | 8 - tests/Unit/BuiltIn/TextDecoderTest.php | 12 + tests/Unit/Bytecode/ArraySpreadTest.php | 49 + tests/Unit/Bytecode/CapturedBindingTest.php | 140 + .../Unit/Bytecode/CompilationFailuresTest.php | 94 + .../Bytecode/CompilationTemplatesTest.php | 54 + tests/Unit/Bytecode/DefaultBindingTest.php | 71 + .../Bytecode/ObjectLiteralPrototypeTest.php | 31 + tests/Unit/Bytecode/RegExpLiteralTest.php | 42 + tests/Unit/Bytecode/TailCallTest.php | 70 + tests/Unit/Bytecode/UnaryReferenceTest.php | 45 + .../fixtures/object-literal-prototype.js | 80 + .../fixtures/object-literal-prototype.json | 259 + .../Bytecode/fixtures/unary-references.js | 64 + .../Bytecode/fixtures/unary-references.json | 163 + tests/Unit/ExecutionBudgetTest.php | 32 + tests/Unit/Module/CommonJsCacheTest.php | 107 + tests/Unit/Module/ResolverTest.php | 45 + tests/Unit/Node/AbortRealmTest.php | 44 + tests/Unit/Node/BroadcastChannelTest.php | 87 + tests/Unit/Node/ChildProcessTest.php | 43 + tests/Unit/Node/ErrorStackTest.php | 49 + tests/Unit/Node/FetchHeadersTest.php | 67 + tests/Unit/Node/FetchTest.php | 75 + tests/Unit/Node/FileSystemTest.php | 66 + tests/Unit/Node/Http2Test.php | 25 + tests/Unit/Node/HttpTest.php | 107 + tests/Unit/Node/NetTest.php | 75 + tests/Unit/Node/NodeCommandTest.php | 81 + tests/Unit/Node/NodeRuntimeTest.php | 120 + tests/Unit/Node/PortableModulesTest.php | 53 + tests/Unit/Node/PrimitivesTest.php | 32 + tests/Unit/Node/TimersTest.php | 85 + tests/Unit/Node/TlsTest.php | 131 + tests/Unit/Node/VmTest.php | 50 + tests/Unit/Node/ZlibTest.php | 31 + tests/Unit/Node/fixtures/crypto.cjs | 40 + tests/Unit/Node/fixtures/crypto.json | 79 + tests/Unit/Node/fixtures/http2.cjs | 43 + tests/Unit/Node/fixtures/http2.json | 42 + .../Unit/Node/fixtures/path-normalization.cjs | 32 + .../Node/fixtures/path-normalization.json | 1656 + tests/Unit/Node/fixtures/portable.cjs | 46 + tests/Unit/Node/fixtures/portable.json | 114 + .../Unit/Node/fixtures/primitives/buffer.cjs | 50 + .../Unit/Node/fixtures/primitives/buffer.json | 141 + .../Unit/Node/fixtures/primitives/buffer.mjs | 1 + .../fixtures/primitives/child-process.cjs | 101 + .../fixtures/primitives/child-process.json | 144 + .../fixtures/primitives/child-process.mjs | 1 + .../Node/fixtures/primitives/child-worker.cjs | 7 + .../Unit/Node/fixtures/primitives/events.cjs | 49 + .../Unit/Node/fixtures/primitives/events.json | 74 + .../Unit/Node/fixtures/primitives/events.mjs | 1 + tests/Unit/Node/fixtures/primitives/fs.cjs | 110 + tests/Unit/Node/fixtures/primitives/fs.json | 183 + tests/Unit/Node/fixtures/primitives/fs.mjs | 1 + .../Unit/Node/fixtures/primitives/helpers.cjs | 11 + .../Node/fixtures/primitives/stream-web.cjs | 44 + .../Node/fixtures/primitives/stream-web.json | 52 + .../Node/fixtures/primitives/stream-web.mjs | 1 + .../Unit/Node/fixtures/primitives/stream.cjs | 43 + .../Unit/Node/fixtures/primitives/stream.json | 61 + .../Unit/Node/fixtures/primitives/stream.mjs | 1 + tests/Unit/Node/fixtures/primitives/vm.cjs | 59 + tests/Unit/Node/fixtures/primitives/vm.json | 116 + tests/Unit/Node/fixtures/primitives/vm.mjs | 1 + .../Node/fixtures/primitives/zlib-inputs.json | 6 + tests/Unit/Node/fixtures/primitives/zlib.cjs | 49 + tests/Unit/Node/fixtures/primitives/zlib.json | 111 + tests/Unit/Node/fixtures/primitives/zlib.mjs | 1 + tests/Unit/Runtime/AsyncReturnCallTest.php | 95 + .../Unit/Runtime/CrossRealmGeneratorTest.php | 80 + .../Runtime/FunctionArgumentsAnalysisTest.php | 39 + .../Runtime/GlobalObjectEnvironmentTest.php | 35 + 284 files changed, 99588 insertions(+), 724 deletions(-) create mode 100644 .github/workflows/frameworks.yml create mode 100644 scripts/node-http/build.py create mode 100644 scripts/node-http/upstream.json create mode 100644 scripts/node-portable/.gitignore create mode 100644 scripts/node-portable/build.py create mode 100644 scripts/node-portable/http2-constants.json create mode 100644 scripts/node-portable/node-sources.json create mode 100644 scripts/node-portable/package-lock.json create mode 100644 scripts/node-portable/package.json create mode 100644 scripts/node-primitives/.gitignore create mode 100644 scripts/node-primitives/README.md create mode 100644 scripts/node-primitives/brotli-LICENSES.txt create mode 100644 scripts/node-primitives/brotli-decoder-entry.cjs create mode 100644 scripts/node-primitives/brotli-encoder-entry.cjs create mode 100644 scripts/node-primitives/buffer-entry.cjs create mode 100644 scripts/node-primitives/build.mjs create mode 100644 scripts/node-primitives/events-entry.cjs create mode 100644 scripts/node-primitives/generate-oracles.mjs create mode 100644 scripts/node-primitives/package-lock.json create mode 100644 scripts/node-primitives/package.json create mode 100644 scripts/node-primitives/stream-consumers-entry.cjs create mode 100644 scripts/node-primitives/stream-entry.cjs create mode 100644 scripts/node-primitives/stream-promises-entry.cjs create mode 100644 scripts/node-primitives/stream-web-entry.cjs create mode 100644 scripts/node-primitives/string_decoder-entry.cjs create mode 100644 src/BuiltIn/CryptoKeyConstructor.php create mode 100644 src/BuiltIn/Ed25519Crypto.php create mode 100644 src/Bytecode/CompilationFailures.php create mode 100644 src/Bytecode/CompilationTemplates.php create mode 100644 src/Node/ChildProcessBindings.php create mode 100644 src/Node/ChildProcessState.php create mode 100644 src/Node/CryptoBindings.php create mode 100644 src/Node/ErrorStack.php create mode 100644 src/Node/FileSystemBindings.php create mode 100644 src/Node/FileSystemError.php create mode 100644 src/Node/HostBindings.php create mode 100644 src/Node/IoBindings.php create mode 100644 src/Node/Lib/assert.cjs create mode 100644 src/Node/Lib/async_hooks.cjs create mode 100644 src/Node/Lib/broadcast_channel.cjs create mode 100644 src/Node/Lib/brotli-decoder.cjs create mode 100644 src/Node/Lib/brotli-encoder.cjs create mode 100644 src/Node/Lib/buffer.cjs create mode 100644 src/Node/Lib/child_process.cjs create mode 100644 src/Node/Lib/crypto.cjs create mode 100644 src/Node/Lib/events.cjs create mode 100644 src/Node/Lib/fetch.cjs create mode 100644 src/Node/Lib/fs.cjs create mode 100644 src/Node/Lib/http-common.cjs create mode 100644 src/Node/Lib/http-constants.cjs create mode 100644 src/Node/Lib/http-parser.LICENSE.md create mode 100644 src/Node/Lib/http-parser.cjs create mode 100644 src/Node/Lib/http.cjs create mode 100644 src/Node/Lib/http2.cjs create mode 100644 src/Node/Lib/https.cjs create mode 100644 src/Node/Lib/module.cjs create mode 100644 src/Node/Lib/net.cjs create mode 100644 src/Node/Lib/path.cjs create mode 100644 src/Node/Lib/portable/LICENSES.json create mode 100644 src/Node/Lib/portable/NODE_LICENSE.txt create mode 100644 src/Node/Lib/portable/constants.cjs create mode 100644 src/Node/Lib/portable/errors.cjs create mode 100644 src/Node/Lib/portable/format.cjs create mode 100644 src/Node/Lib/portable/glob.cjs create mode 100644 src/Node/Lib/portable/helpers.cjs create mode 100644 src/Node/Lib/portable/hpack.cjs create mode 100644 src/Node/Lib/portable/http2-constants.json create mode 100644 src/Node/Lib/portable/internal-querystring.cjs create mode 100644 src/Node/Lib/portable/minimatch.cjs create mode 100644 src/Node/Lib/portable/primordials.cjs create mode 100644 src/Node/Lib/portable/punycode.cjs create mode 100644 src/Node/Lib/portable/sources.json create mode 100644 src/Node/Lib/portable/tr46.cjs create mode 100644 src/Node/Lib/portable/util-base.cjs create mode 100644 src/Node/Lib/portable/validators.cjs create mode 100644 src/Node/Lib/portable/whatwg-url.cjs create mode 100644 src/Node/Lib/primitives-LICENSES.txt create mode 100644 src/Node/Lib/primitives-manifest.json create mode 100644 src/Node/Lib/process.cjs create mode 100644 src/Node/Lib/querystring.cjs create mode 100644 src/Node/Lib/stdio.cjs create mode 100644 src/Node/Lib/stream-consumers.cjs create mode 100644 src/Node/Lib/stream-promises.cjs create mode 100644 src/Node/Lib/stream-web.cjs create mode 100644 src/Node/Lib/stream.cjs create mode 100644 src/Node/Lib/string_decoder.cjs create mode 100644 src/Node/Lib/timers-promises.cjs create mode 100644 src/Node/Lib/timers.cjs create mode 100644 src/Node/Lib/tls.cjs create mode 100644 src/Node/Lib/tty.cjs create mode 100644 src/Node/Lib/url.cjs create mode 100644 src/Node/Lib/util.cjs create mode 100644 src/Node/Lib/vm.cjs create mode 100644 src/Node/Lib/zlib.cjs create mode 100644 src/Node/NodeCommand.php create mode 100644 src/Node/NodeOptions.php create mode 100644 src/Node/NodeRuntime.php create mode 100644 src/Node/OsModule.php create mode 100644 src/Node/PathBindings.php create mode 100644 src/Node/SocketState.php create mode 100644 src/Node/VmBindings.php create mode 100644 src/Node/VmContext.php create mode 100644 src/Node/VmGlobalObject.php create mode 100644 src/Node/VmRealmState.php create mode 100644 src/Node/ZlibBindings.php create mode 100644 src/Node/child-runtime.php create mode 100644 tests/Frameworks/.gitignore create mode 100644 tests/Frameworks/express/manifest.json create mode 100644 tests/Frameworks/express/run-node.cjs create mode 100644 tests/Frameworks/express/run-phasis.php create mode 100644 tests/Frameworks/express/run.py create mode 100644 tests/Frameworks/express/runner.cjs create mode 100644 tests/Frameworks/express/setup.py create mode 100644 tests/Frameworks/express/test_runner.py create mode 100644 tests/Frameworks/express/upstream.json create mode 100644 tests/Frameworks/hono/.gitignore create mode 100644 tests/Frameworks/hono/README.md create mode 100644 tests/Frameworks/hono/build-selftest.mjs create mode 100644 tests/Frameworks/hono/build.mjs create mode 100644 tests/Frameworks/hono/compare-native.py create mode 100644 tests/Frameworks/hono/deadline.mjs create mode 100644 tests/Frameworks/hono/fixtures/timeouts-entry.mjs create mode 100644 tests/Frameworks/hono/fixtures/timeouts.test.mjs create mode 100644 tests/Frameworks/hono/harness.mjs create mode 100644 tests/Frameworks/hono/inventory.py create mode 100644 tests/Frameworks/hono/prepare-toolchain.mjs create mode 100644 tests/Frameworks/hono/run-php.php create mode 100644 tests/Frameworks/hono/run-toolchain.py create mode 100644 tests/Frameworks/hono/run.py create mode 100644 tests/Frameworks/hono/selftest.config.mjs create mode 100644 tests/Frameworks/hono/selftest.py create mode 100644 tests/Frameworks/hono/setup.py create mode 100644 tests/Frameworks/hono/test_runner.py create mode 100644 tests/Frameworks/hono/upstream.json create mode 100644 tests/Frameworks/hono/vitest.config.mjs create mode 100644 tests/Frameworks/http2/certificate.php create mode 100644 tests/Frameworks/http2/client.cjs create mode 100644 tests/Frameworks/http2/interop.mjs create mode 100644 tests/Frameworks/http2/run-php.php create mode 100644 tests/Frameworks/http2/server.cjs create mode 100644 tests/Frameworks/package-lock.json create mode 100644 tests/Frameworks/package.json create mode 100644 tests/Unit/BuiltIn/Ed25519CryptoTest.php create mode 100644 tests/Unit/BuiltIn/FunctionProxyCallTest.php create mode 100644 tests/Unit/BuiltIn/JsonPropertyNamesTest.php create mode 100644 tests/Unit/BuiltIn/LiveFetchBodyTest.php create mode 100644 tests/Unit/BuiltIn/MessageEventTest.php create mode 100644 tests/Unit/BuiltIn/ReadableStreamSchedulingTest.php create mode 100644 tests/Unit/BuiltIn/StringCodeUnitTest.php create mode 100644 tests/Unit/Bytecode/ArraySpreadTest.php create mode 100644 tests/Unit/Bytecode/CapturedBindingTest.php create mode 100644 tests/Unit/Bytecode/CompilationFailuresTest.php create mode 100644 tests/Unit/Bytecode/CompilationTemplatesTest.php create mode 100644 tests/Unit/Bytecode/DefaultBindingTest.php create mode 100644 tests/Unit/Bytecode/ObjectLiteralPrototypeTest.php create mode 100644 tests/Unit/Bytecode/RegExpLiteralTest.php create mode 100644 tests/Unit/Bytecode/TailCallTest.php create mode 100644 tests/Unit/Bytecode/UnaryReferenceTest.php create mode 100644 tests/Unit/Bytecode/fixtures/object-literal-prototype.js create mode 100644 tests/Unit/Bytecode/fixtures/object-literal-prototype.json create mode 100644 tests/Unit/Bytecode/fixtures/unary-references.js create mode 100644 tests/Unit/Bytecode/fixtures/unary-references.json create mode 100644 tests/Unit/Module/CommonJsCacheTest.php create mode 100644 tests/Unit/Node/AbortRealmTest.php create mode 100644 tests/Unit/Node/BroadcastChannelTest.php create mode 100644 tests/Unit/Node/ChildProcessTest.php create mode 100644 tests/Unit/Node/ErrorStackTest.php create mode 100644 tests/Unit/Node/FetchHeadersTest.php create mode 100644 tests/Unit/Node/FetchTest.php create mode 100644 tests/Unit/Node/FileSystemTest.php create mode 100644 tests/Unit/Node/Http2Test.php create mode 100644 tests/Unit/Node/HttpTest.php create mode 100644 tests/Unit/Node/NetTest.php create mode 100644 tests/Unit/Node/NodeCommandTest.php create mode 100644 tests/Unit/Node/NodeRuntimeTest.php create mode 100644 tests/Unit/Node/PortableModulesTest.php create mode 100644 tests/Unit/Node/PrimitivesTest.php create mode 100644 tests/Unit/Node/TimersTest.php create mode 100644 tests/Unit/Node/TlsTest.php create mode 100644 tests/Unit/Node/VmTest.php create mode 100644 tests/Unit/Node/ZlibTest.php create mode 100644 tests/Unit/Node/fixtures/crypto.cjs create mode 100644 tests/Unit/Node/fixtures/crypto.json create mode 100644 tests/Unit/Node/fixtures/http2.cjs create mode 100644 tests/Unit/Node/fixtures/http2.json create mode 100644 tests/Unit/Node/fixtures/path-normalization.cjs create mode 100644 tests/Unit/Node/fixtures/path-normalization.json create mode 100644 tests/Unit/Node/fixtures/portable.cjs create mode 100644 tests/Unit/Node/fixtures/portable.json create mode 100644 tests/Unit/Node/fixtures/primitives/buffer.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/buffer.json create mode 100644 tests/Unit/Node/fixtures/primitives/buffer.mjs create mode 100644 tests/Unit/Node/fixtures/primitives/child-process.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/child-process.json create mode 100644 tests/Unit/Node/fixtures/primitives/child-process.mjs create mode 100644 tests/Unit/Node/fixtures/primitives/child-worker.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/events.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/events.json create mode 100644 tests/Unit/Node/fixtures/primitives/events.mjs create mode 100644 tests/Unit/Node/fixtures/primitives/fs.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/fs.json create mode 100644 tests/Unit/Node/fixtures/primitives/fs.mjs create mode 100644 tests/Unit/Node/fixtures/primitives/helpers.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/stream-web.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/stream-web.json create mode 100644 tests/Unit/Node/fixtures/primitives/stream-web.mjs create mode 100644 tests/Unit/Node/fixtures/primitives/stream.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/stream.json create mode 100644 tests/Unit/Node/fixtures/primitives/stream.mjs create mode 100644 tests/Unit/Node/fixtures/primitives/vm.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/vm.json create mode 100644 tests/Unit/Node/fixtures/primitives/vm.mjs create mode 100644 tests/Unit/Node/fixtures/primitives/zlib-inputs.json create mode 100644 tests/Unit/Node/fixtures/primitives/zlib.cjs create mode 100644 tests/Unit/Node/fixtures/primitives/zlib.json create mode 100644 tests/Unit/Node/fixtures/primitives/zlib.mjs create mode 100644 tests/Unit/Runtime/AsyncReturnCallTest.php create mode 100644 tests/Unit/Runtime/CrossRealmGeneratorTest.php create mode 100644 tests/Unit/Runtime/FunctionArgumentsAnalysisTest.php diff --git a/.github/workflows/frameworks.yml b/.github/workflows/frameworks.yml new file mode 100644 index 00000000..8a111652 --- /dev/null +++ b/.github/workflows/frameworks.yml @@ -0,0 +1,143 @@ +name: Framework Compatibility + +on: + push: + branches: [main] + paths: + - 'src/**' + - 'tests/Frameworks/**' + - 'scripts/node-*/**' + - 'composer.json' + - 'composer.lock' + - '.github/workflows/frameworks.yml' + pull_request: + branches: [main] + paths: + - 'src/**' + - 'tests/Frameworks/**' + - 'scripts/node-*/**' + - 'composer.json' + - 'composer.lock' + - '.github/workflows/frameworks.yml' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: frameworks-${{ github.ref }} + cancel-in-progress: true + +env: + XDEBUG_MODE: 'off' + TZ: UTC + +jobs: + upstream: + name: PHP ${{ matrix.php }} / ${{ matrix.suite }} + runs-on: ubuntu-latest + timeout-minutes: 45 + strategy: + fail-fast: false + matrix: + php: ['8.4', '8.5'] + suite: [express, hono-main, hono-jsx-runtime-default, hono-jsx-runtime-dom, hono-node, http2] + steps: + - uses: actions/checkout@v5 + + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: mbstring, bcmath, curl, intl, openssl, sodium, zlib, sockets + coverage: none + + - uses: actions/setup-node@v6 + with: + node-version: '26.12.0' + cache: npm + cache-dependency-path: tests/Frameworks/package-lock.json + + - uses: actions/setup-python@v6 + with: + python-version: '3.13' + + - name: Install pinned dependencies + run: | + composer install --no-interaction --prefer-dist + npm ci --prefix tests/Frameworks + + - name: Prepare Express source + if: matrix.suite == 'express' + run: python3 -B tests/Frameworks/express/setup.py + + - name: Prepare Hono source + if: startsWith(matrix.suite, 'hono-') + run: python3 -B tests/Frameworks/hono/setup.py + + - name: Express original tests + if: matrix.suite == 'express' + run: | + python3 -B tests/Frameworks/express/test_runner.py + python3 -B tests/Frameworks/express/run.py --runtime both --jobs 1 --output framework-results/express + + - name: Hono harness deadline differential + if: startsWith(matrix.suite, 'hono-') + run: | + python3 -B tests/Frameworks/hono/test_runner.py + python3 -B tests/Frameworks/hono/selftest.py + + - name: Hono original runtime tests + if: startsWith(matrix.suite, 'hono-') + env: + FRAMEWORK_SUITE: ${{ matrix.suite }} + run: python3 -B tests/Frameworks/hono/run.py --project "${FRAMEWORK_SUITE#hono-}" --timeout 1800 + + - name: Hono independent native Vitest baseline + if: startsWith(matrix.suite, 'hono-') && !cancelled() + env: + FRAMEWORK_SUITE: ${{ matrix.suite }} + run: | + mkdir -p framework-results + if [ "$FRAMEWORK_SUITE" = 'hono-main' ]; then + node tests/Frameworks/hono/prepare-toolchain.mjs + fi + PHASIS_HONO_PROJECT="${FRAMEWORK_SUITE#hono-}" node tests/Frameworks/node_modules/vitest/vitest.mjs run \ + --config tests/Frameworks/hono/vitest.config.mjs \ + --reporter=json --outputFile="$PWD/framework-results/hono-native.json" + + - name: Compare every Hono case with native Vitest + if: startsWith(matrix.suite, 'hono-') && !cancelled() + run: | + python3 -B - <<'PY' + import json + from pathlib import Path + import subprocess + results = Path('tests/Frameworks/hono/results') + run_id = json.loads((results / 'manifest.json').read_text())['id'] + manifest = results / 'runs' / run_id / 'manifest.json' + statuses = [subprocess.run([ + 'python3', '-B', 'tests/Frameworks/hono/compare-native.py', + 'framework-results/hono-native.json', str(manifest), '--runtime', runtime, + ]).returncode for runtime in ['node', 'phasis']] + raise SystemExit(int(any(statuses))) + PY + + - name: Hono original declaration tests + if: matrix.suite == 'hono-main' && !cancelled() + run: python3 -B tests/Frameworks/hono/run-toolchain.py + + - name: HTTP2 native Node interoperability + if: matrix.suite == 'http2' + run: | + mkdir -p framework-results + node tests/Frameworks/http2/interop.mjs | tee framework-results/http2.jsonl + + - name: Preserve complete manifests and failure logs + if: always() + uses: actions/upload-artifact@v6 + with: + name: frameworks-php${{ matrix.php }}-${{ matrix.suite }}-${{ github.sha }} + path: | + framework-results/ + tests/Frameworks/hono/results/runs/ + if-no-files-found: warn diff --git a/AGENTS.md b/AGENTS.md index 6fa540e0..aeddcd99 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,6 +8,16 @@ Keep agent instructions in `AGENTS.md` only. Use nested `AGENTS.md` files when guidance needs a narrower scope. Do not add `CLAUDE.md` files, symlinks, or forwarding stubs for repository guidance. +Node compatibility is opt-in through `Engine::enableNode()` or `phasis --node`. +JavaScript still executes entirely in PHP. Node/npm may prepare pinned assets or +run test oracles, but must never become an execution backend. Explicit +`child_process` operations use PHP host processes; a JavaScript child launched +through `process.execPath` runs the Phasis PHP entry point. New host resources +must register cleanup with their owning NodeRuntime. Keep original framework +assertions and timeouts, report all discovered cases and upstream skips, and +retain source identity for complete-run claims. Close and reap owned test +processes and listeners after every run. + ## Releases Follow the [shared release rule](https://github.com/inline0/_cp/blob/main/AGENTS.md#canonical-github-releases). diff --git a/CHANGELOG.md b/CHANGELOG.md index ce28303e..d5f09079 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,16 @@ ## [Unreleased] ### Added +- Opt-in Node-compatible realms and `phasis --node`, with CommonJS package loading, Buffer and streams, filesystem and process I/O, HTTP/HTTPS/HTTP2, TLS, compression, timers, async context, and isolated VM realms. +- Pinned Express and Hono upstream runners with original assertions, case inventories, source hashes, bounded workers and real network interoperability checks. +- Ed25519 WebCrypto keys, MessageEvent and in-process BroadcastChannel support. - Keyed Promise combinators, iterator chunk/window/zip helpers, and immutable ArrayBuffers with protected typed-array, DataView, and Atomics writes. - Locale variants and locale-specific calendar, collation, hour-cycle, text-direction, and week information. ### Fixed +- Live Fetch request and response bodies retain streaming, cancellation and clone behavior; Node fetch can communicate with servers in the same engine. +- Promise reactions preserve registration-time async context; cross-realm generators preserve their realm prototypes; global-property deletion and CommonJS cache behavior remain observable. +- JSON property names and Unicode separators, callable proxies, and UTF-16 string indexing preserve JavaScript behavior across framework workloads. - Temporal calendar fields, arithmetic, rounding, parsing, timezone boundaries, and Intl formatting use consistent calendar data and option validation. - Module evaluation, source and typed imports, resource disposal, cross-realm intrinsics, numeric serialization, and compiled global bindings follow current language semantics. - Array callbacks observe mutations and holes, and global declarations create own properties without invoking inherited accessors. @@ -15,6 +21,7 @@ - Intl option precedence, legacy constructors, plural notation, numbering systems, and plain date/time formatting. ### Changed +- Bytecode compilation handles captured bindings, default initializers, spread arrays, object prototypes, regular-expression literals and strict tail calls; reusable syntax templates keep closure state separate. - The test262 runner executes both variants of unflagged scripts, preserves raw sources and module parse goals, requires async completion, and checks negative-test error types and phases. - Compatibility shards retain full file manifests; merging rejects overlapping or stale results and keeps missing coverage visible. Incomplete or failing coverage cannot round up to 100%. diff --git a/README.md b/README.md index 7d9a3648..61b547e9 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Phasis lexes, parses, and executes ECMAScript in pure PHP. No `exec('node …')` - **Fetch Pack**: `fetch`, `Request`, `Response`, `Headers`, `Body`, `AbortController`/`AbortSignal`, `Blob`/`File`, `FormData`, `EventTarget`/`Event`, full WHATWG Streams, `navigator` - **Crypto**: `crypto.getRandomValues`, `crypto.randomUUID`, full `SubtleCrypto` (SHA family, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2) - **WebSocket** (RFC 6455 + replaceable transport), **XMLHttpRequest** (layered over fetch), and a real **event loop** (`setTimeout` / `setInterval` / `queueMicrotask`, plus Stage-3 `AsyncContext`) +- **Opt-in Node compatibility** for Express and Hono: CommonJS packages, Buffer, streams, filesystem access, HTTP/HTTPS/HTTP2 servers and clients, TLS, crypto, timers, and async context, executed inside PHP. See the [module coverage and host limits](./docs/modules.md#node-compatibility). - **JSX Pack**: render JSX components to HTML from PHP with `Engine::render()`, no build step - **Native React 19.3 server renderer** in PHP: `react`, `react-dom/server` and `react-dom/static` are built in, with HTML byte-identical to `react-dom@19.3.1` and hydratable by React on the client (hooks, context, Suspense, `useId`, async components, resource hints) - **General HTML renderer** (`phasis`, `phasis/jsx-runtime`) for emails, feeds and static pages, byte-identical to preact-render-to-string 6.8.1, plus `raw()` @@ -88,6 +89,9 @@ echo $engine->call('add', 2, 3); // 5 # Dump the AST as JSON ./vendor/bin/phasis --ast script.js + +# Run a Node-compatible package or server with live stdout/stderr +./vendor/bin/phasis --node server.cjs ``` `bin/test262`, the conformance runner, needs the `test262` submodule and the dev autoloader, so run it from a clone of this repository (see Testing below). @@ -112,6 +116,13 @@ composer cs # Full quality gate (PHPStan + PHPCS + PHPUnit + oracle) ./bin/verify-all +# Original Express and Hono suites, with pinned development dependencies +npm ci --prefix tests/Frameworks +python3 tests/Frameworks/express/setup.py +python3 tests/Frameworks/hono/setup.py +python3 tests/Frameworks/express/run.py --output /tmp/phasis-express-report +python3 tests/Frameworks/hono/run.py + # test262 conformance sample (needs: git submodule update --init test262) ./bin/test262 --category built-ins/Array --jobs 4 ``` diff --git a/bin/phasis b/bin/phasis index dc60b347..835bddab 100755 --- a/bin/phasis +++ b/bin/phasis @@ -19,10 +19,12 @@ declare(strict_types=1); use Phasis\Ast\Serializer; use Phasis\Engine; +use Phasis\Node\NodeCommand; use Phasis\Parser\Parser; $args = array_slice($argv, 1); -$opts = getopt('e:', ['ast', 'repl', 'render:', 'props:']); +$opts = getopt('e:', ['ast', 'repl', 'render:', 'props:', 'node'], $restIndex); +$nodeMode = isset($opts['node']); if (isset($opts['render'])) { $file = (string) $opts['render']; @@ -50,6 +52,8 @@ if (isset($opts['e'])) { if (isset($opts['ast'])) { outputAst($source); + } elseif ($nodeMode) { + exit(NodeCommand::runSource($source, array_slice($argv, $restIndex))); } else { executeSource($source); } @@ -68,12 +72,16 @@ if (in_array('--ast', $args, true)) { } // Default: execute a file -$file = $args[0] ?? null; +$file = $argv[$restIndex] ?? null; if ($file === null || !file_exists($file)) { - fwrite(STDERR, "Usage: phasis | phasis -e '' | phasis --ast | phasis --render [--props '']\n"); + fwrite(STDERR, "Usage: phasis [--node] [args] | phasis [--node] -e '' | phasis --ast | phasis --render [--props '']\n"); exit(1); } +if ($nodeMode) { + exit(NodeCommand::runFile($file, array_slice($argv, $restIndex + 1))); +} + $jsx = new \Phasis\Parser\Jsx\JsxOptions(); if (str_ends_with(strtolower($file), '.mjs') || $jsx->appliesTo($file)) { // Modules (.mjs, .jsx) go through the module loader so imports resolve. diff --git a/composer.json b/composer.json index 6028ee3b..91d213d1 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,9 @@ }, "suggest": { "ext-intl": "Required for Intl.* APIs (Collator, NumberFormat, DateTimeFormat, etc.) and full Temporal calendar support. Without it, Intl constructors throw and non-ISO calendars fall back to limited semantics.", - "ext-openssl": "Required for crypto.subtle AES-CBC / AES-CTR / AES-GCM encrypt/decrypt. crypto.subtle.digest, sign, and verify (HMAC) work without it via PHP's built-in hash() / hash_hmac()." + "ext-openssl": "Required for WebCrypto AES/RSA/EC operations and Node TLS/HTTPS/secure HTTP2 transports.", + "ext-sodium": "Required for WebCrypto Ed25519 key generation, signing, and verification.", + "ext-zlib": "Required for Node gzip/deflate compression and decompression. Brotli uses the bundled JavaScript codec." }, "require-dev": { "phpunit/phpunit": "^13.1", diff --git a/docs/api.md b/docs/api.md index b7b0ab32..2f746ef6 100644 --- a/docs/api.md +++ b/docs/api.md @@ -19,12 +19,18 @@ use Phasis\Engine; $engine = new Engine(); // lazy mode (default) $engine = new Engine(eager: true); // install every built-in up front +$engine = new Engine(node: true); // opt-in Node modules and host I/O ``` A fresh `Engine` exposes the full standard library — `Object`, `Array`, `String`, `Number`, `Symbol`, `BigInt`, `Promise`, `RegExp`, `Error` and the core language intrinsics install eagerly so the spec works (you can't have classes without `Function.prototype`, async/await without `Promise`, regex literals without `RegExp`). Everything else — `Math`, `JSON`, `Map`, `Set`, `Date`, `TypedArray` and the array-buffer family, `Atomics`, `Proxy`, `Reflect`, `console`, `Intl`, the weak-ref family, `Temporal`, `ShadowRealm`, the Web Platform Pack, and the Fetch Pack — is registered as a placeholder accessor and materializes on first read. Reading the global is transparent: `Map`, `typeof Map`, `'Map' in globalThis`, `Object.keys(globalThis).includes('Map')` all work, and after the first read the placeholder is replaced with a regular data descriptor. Pass `eager: true` if you specifically need the pre-lazy behavior — every built-in installed at construction with the full descriptor surface visible to introspection. The conformance harness (`bin/test262`, `bin/wpt`) constructs engines in eager mode so test262/WPT see the descriptor shapes they expect. +`enableNode(?Phasis\Node\NodeOptions $options = null)` enables Node mode on an +existing engine. Options select its initial directory, environment and program +arguments. See [Node compatibility](/docs/modules#node-compatibility) for the +built-in registry, host requirements and limitations. + ## eval ```php @@ -243,6 +249,20 @@ Clears all user-defined globals and the console buffer, and rebuilds the standar Both lazy and eager engines rebuild their global object, standard built-ins and aliases, so the same engine is reusable after reset. +In Node mode, reset first closes owned sockets, file descriptors, codec contexts +and child processes, then reinstalls Node mode with its original `NodeOptions`. + +## close + +```php +public function close(): void +``` + +Cancels pending timers and releases owned Node resources, including terminating +and reaping direct child processes. Call it in a `finally` block when an embedded +program finishes or fails. Repeated calls are harmless. Use `reset()` to prepare +a closed Node engine for another program. + ## Event loop The engine ships a JavaScript event loop with `setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`, and `queueMicrotask` on the global object. Microtasks (Promise handlers, `queueMicrotask`) drain between every macrotask; timers fire in deadline order via a per-realm task queue. @@ -270,6 +290,15 @@ while ($engine->pendingTaskCount() > 0) { A runaway `setInterval` is bounded: `runEventLoop()` caps at 100,000 cycles and throws a plain `\RuntimeException` — the JS code's fault surfaces as a clear PHP error rather than a hang. The interval stays scheduled, so every later `eval()` on the same engine throws the same error; discard the engine afterwards. Uncaught errors in a timer callback are emitted via `error_log()` and the loop keeps draining; one bad timer doesn't kill the program. +Node mode uses elapsed time and polls sockets and child pipes between timer +phases. Referenced servers, sockets and timers keep `runEventLoop()` alive; +`unref()` handles do not. Node timers return handles with `ref`, `unref`, +`hasRef`, `refresh` and disposal, and `setImmediate` runs in the check phase. +Long-lived Node programs have no iteration-count ceiling; an explicit execution +budget still applies. Uncaught Node timer errors propagate to the PHP caller. +Use `evalScript($source, drainEventLoop: false)` followed by `tickEventLoop()` +when the PHP application needs to drive a server's loop itself. + ## Fetch hooks Phasis ships `fetch()` enabled by default with PHP's `ext-curl` as the underlying transport. Three hooks let an embedder swap the transport, gate requests, or enable cookie storage. All three accept either a PHP callable or a method-on-object; see [Web APIs](/docs/compatibility/web-apis) for the value-shape contract. diff --git a/docs/cli.md b/docs/cli.md index 6efcdce8..fbb5b9af 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -16,15 +16,15 @@ Phasis ships three main executables in `bin/`: - **`bin/test262`** — run the official ECMAScript conformance suite against Phasis. - **`bin/wpt`** — run the Web Platform Tests fixtures against Phasis (URL, encoding, fetch, headers, Blob, AbortSignal, streams, …). -After `composer require phasis/phasis`, `bin/phasis` and `bin/test262` are linked from `vendor/bin/`. Only `bin/phasis` works from there: `bin/test262` needs the `test262` git submodule and the test classes, which the Composer package does not include, and `bin/wpt` is not shipped at all. Run both from a clone of the Phasis repository. +After `composer require phasis/phasis`, the runtime CLI is linked at `vendor/bin/phasis`. The development runners need a source checkout and are excluded from the Composer archive. ## bin/phasis ``` -phasis | phasis -e '' | phasis --ast | phasis --render [--props ''] +phasis [--node] [args] | phasis [--node] -e '' | phasis --ast | phasis --render [--props ''] ``` -These four forms are the whole interface. There is no REPL, no stdin input and no module flag: the file extension decides. +The `--node` flag enables Node-compatible packages and host I/O. There is no REPL or source-code input from stdin. ### Run a file @@ -45,6 +45,22 @@ Executes `script.js` as a classic script. When it finishes, everything the scrip The argument is evaluated as a complete script. Only `console` output is printed; the value of the last expression is not, so `phasis -e '1 + 2'` prints nothing. +### Run a Node-compatible server + +```bash +./vendor/bin/phasis --node server.cjs --port 3000 +./vendor/bin/phasis --node -e 'console.log(require("node:path").basename(process.cwd()))' +``` + +Node mode resolves packages from `node_modules`, exposes `process.argv` and a +copy of the host environment, and runs the real event loop while referenced +handles remain active. `console.log`/`info`/`debug` write immediately to stdout; +`console.warn`/`error` write immediately to stderr. `process.stdout` and +`process.stderr` accept raw bytes. The CLI closes owned resources on completion +or failure. `process.exitCode` and `process.exit(code)` select the process exit +status. See [Node compatibility](/docs/modules#node-compatibility) for module +coverage and host limitations. + ### Dump the AST ```bash @@ -139,7 +155,7 @@ Machine-readable pass/fail summary for CI pipelines or scripted analysis. ## Exit codes -`bin/phasis` exits with one of two codes: +In default mode, `bin/phasis` exits with one of two codes: | Code | Meaning | |---|---| @@ -148,6 +164,9 @@ Machine-readable pass/fail summary for CI pipelines or scripted analysis. Errors from the script print their message to stderr. Invalid arguments and missing files print the usage line to stderr. +Node mode additionally returns the program's explicit `process.exitCode` or +`process.exit(code)` status. + ## Resource limits `bin/phasis` runs with the engine defaults and has no flags for limits: a 4,096-frame JS call-stack ceiling, an 8,192-frame guard for transpiled closures, and the default `maxLoopIterations` of 100,000, which applies across the interpreter, bytecode VM and transpiled closures (see [API: setLimit](/docs/api#setlimit)). There is no time limit; wrap the command in `timeout` if a script may not terminate. diff --git a/docs/modules.md b/docs/modules.md index 6e03207f..0b875373 100644 --- a/docs/modules.md +++ b/docs/modules.md @@ -18,13 +18,13 @@ For each specifier, the first rule that applies wins: 1. **Import map** (`Engine::setImportMap()`): exact keys, then keys ending in `/` as prefixes. A `null` value loads the module as an empty stub. 2. **Built-in modules**: `react`, `react/jsx-runtime`, `react-dom`, `react-dom/server`, `react-dom/static`, `phasis`, `phasis/jsx-runtime`. -3. **`node:` specifiers** are an error naming the module. +3. **`node:` specifiers** resolve supported built-ins when [Node compatibility](#node-compatibility) is enabled; otherwise they are an error naming the module. 4. **`#` specifiers** through the nearest `package.json` `imports` field. 5. **Relative and absolute paths**, trying the extensions (`.jsx`, `.js`, `.mjs`, `.cjs`, `.json` by default), then `index` files. 6. **Path aliases** from the nearest `jsconfig.json` or `tsconfig.json` (`compilerOptions.paths` and `baseUrl`; comments and trailing commas allowed). 7. **`node_modules`**, walking up from the importing file: `package.json` `exports` (with conditions, subpath patterns and blocked `null` subpaths), then `module`, then `main`. -Bare Node built-in names (`fs`, `path`, ...) with no package of that name in `node_modules` are an error too. Stub them through the import map when a dependency imports one it does not use while rendering. +In the default mode, bare Node built-in names (`fs`, `path`, ...) with no package of that name in `node_modules` are an error too. An import-map stub can represent a dependency that is unused while rendering. Node mode resolves the supported built-ins under both their bare and `node:` names. ```php $engine->setImportMap([ @@ -63,6 +63,84 @@ Packages that ship only CommonJS (`classnames`, `dayjs`, `lodash`, `prop-types`, In ES modules, `process.env.NODE_ENV` is replaced with the configured value at parse time, the way bundlers define it, so `if (process.env.NODE_ENV !== 'production')` branches work without a `process` object. +## Node compatibility + +Enable Node mode explicitly for packages that use Node APIs: + +```php +use Phasis\Engine; +use Phasis\Node\NodeOptions; + +$engine = new Engine(); +$engine->enableNode(new NodeOptions( + cwd: __DIR__, + env: ['NODE_ENV' => 'production'], + argv: ['phasis', __DIR__ . '/server.cjs'], +)); +try { + $engine->execFile(__DIR__ . '/server.cjs'); +} finally { + $engine->close(); +} +``` + +`new Engine(node: true)` enables the same mode with default options. The default +directory and environment are inherited from PHP; an explicit `env` replaces the +inherited environment. `process.chdir()` changes the realm's directory without +changing PHP's working directory. Node mode uses the PHP host's filesystem, +network and subprocess permissions; `cwd` is a starting directory, not an access +restriction. + +Entry files and packages use Node-aware module resolution, the `node` package +condition, and a live `process.env`. CommonJS wrappers expose `module.parent`, +`module.children`, `require.main`, `require.resolve` and `require.cache`. +Deleting a cache entry causes the next require to execute the module again; +cycles see partial exports. Built-in bare and `node:` aliases share identity. +ES module imports of CommonJS retain the complete `module.exports` as their +default export. + +The built-in registry includes these modules and their listed subpaths: + +| Area | Modules | +|---|---| +| Binary data and streams | `buffer`, `string_decoder`, `events`, `stream`, `stream/promises`, `stream/consumers`, `stream/web` | +| Files and paths | `fs`, `fs/promises`, `path`, `path/posix`, `path/win32`, `os` | +| Networking | `net`, `http`, `https`, `tls`, `http2` | +| Encoding and security | `url`, `querystring`, `zlib`, `crypto` | +| Utilities | `util`, `util/types`, `assert`, `assert/strict` | +| Execution | `process`, `module`, `vm`, `child_process`, `tty`, `timers`, `timers/promises`, `async_hooks` | + +These modules combine interpreted JavaScript implementations with PHP host +operations. TCP, Unix sockets, files and child pipes use real host resources. +HTTP2 uses real frames and HPACK, including multiplexing and TLS ALPN. Node-mode +`fetch` uses asynchronous HTTP transports so a client and server can share one +engine. `AsyncLocalStorage` follows Promise reactions, timers and I/O callbacks. +`BroadcastChannel` communicates between channels inside the same engine. + +PHP's OpenSSL extension supplies TLS and AES/RSA/EC cryptography; sodium supplies +Ed25519; zlib supplies incremental gzip/deflate codecs. Brotli is bundled +JavaScript. No Node installation is needed to execute JavaScript. An explicit +`child_process` request launches the requested host program through PHP; +launching `process.execPath` with a JavaScript file starts another Phasis PHP +process. + +Framework coverage is measured by the pinned test suites; the registry is a +subset of Node's API surface. Current host limits include filesystem watching and portable +subsecond/birth timestamps, raw TTY mode, optional unverified TLS client +certificates, Worker threads, child-process IPC/detached sessions, V8 cache +serialization and VM code-generation controls. Brotli transforms buffer a full +frame; partial flush and changing zlib compression parameters after construction +are unavailable. Asymmetric Node key/sign APIs are not exposed; WebCrypto +provides its documented algorithms. Some OS memory/uptime queries require Linux +`/proc` and report unavailability on other hosts. Process memory figures describe PHP allocations. Unsupported +host operations report errors or remain absent from the module surface. + +The pinned original Express and Hono test runners live in +`tests/Frameworks`. Their manifests retain discovered cases, upstream skips, +failures, blocked tests, source hashes and process timeouts. Framework versions +and suite revisions are recorded there; passing a framework suite does not imply +that the complete Node test suite or Hono's Bun/Deno/Fastly/workerd hosts pass. + ## Styles and assets - **Style imports** (`import './Card.css'`) load as empty modules on the server. @@ -125,5 +203,5 @@ Entries are keyed by the source text and the options that change parsing (JSX op ## Not supported - Bundler-specific import features: query suffixes (`?raw`, `?url`), SVG-as-component imports, `import.meta.glob`, `import.meta.env`, webpack loaders. -- Node's built-in modules and packages that need them at render time. +- Node built-ins outside the opt-in registry above, and native Node addons. - TypeScript sources. diff --git a/phpcs.xml b/phpcs.xml index ae8c2a27..64215a35 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -11,6 +11,11 @@ src/BuiltIn/Jsx/React/Fizz/Scripts.php tests/Popular/* + + tests/Frameworks/node_modules/* + tests/Frameworks/*/upstream/* + tests/Frameworks/*/.generated/* + tests/Frameworks/*/results/* tests/Jsx/*/* tests/Unit/Formatter/fixtures/* diff --git a/scripts/node-http/build.py b/scripts/node-http/build.py new file mode 100644 index 00000000..6fb9d4dc --- /dev/null +++ b/scripts/node-http/build.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +"""Reproduce the unchanged, integrity-pinned HTTP parser and its license.""" + +import argparse +import base64 +import hashlib +import io +import json +from pathlib import Path +import tarfile +import urllib.request + + +DIRECTORY = Path(__file__).resolve().parent +LIBRARY = DIRECTORY.parents[1] / 'src' / 'Node' / 'Lib' + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--check', action='store_true', help='Verify committed assets without writing them.') + args = parser.parse_args() + metadata = json.loads((DIRECTORY / 'upstream.json').read_text())['http-parser-js'] + payload = urllib.request.urlopen(metadata['url'], timeout=30).read() + integrity = 'sha512-' + base64.b64encode(hashlib.sha512(payload).digest()).decode() + if integrity != metadata['integrity']: + raise RuntimeError('HTTP parser archive integrity mismatch') + with tarfile.open(fileobj=io.BytesIO(payload), mode='r:gz') as archive: + package = json.loads(archive.extractfile('package/package.json').read()) + if package['version'] != metadata['version']: + raise RuntimeError('HTTP parser archive version mismatch') + for source, target in [('http-parser.js', 'http-parser.cjs'), ('LICENSE.md', 'http-parser.LICENSE.md')]: + contents = archive.extractfile('package/' + source).read() + destination = LIBRARY / target + if args.check: + if not destination.exists() or destination.read_bytes() != contents: + raise RuntimeError('HTTP parser asset differs: ' + str(destination)) + else: + destination.write_bytes(contents) + print('Verified http-parser-js ' + metadata['version'] + ' and its license') + + +if __name__ == '__main__': + main() diff --git a/scripts/node-http/upstream.json b/scripts/node-http/upstream.json new file mode 100644 index 00000000..695e0c4f --- /dev/null +++ b/scripts/node-http/upstream.json @@ -0,0 +1,7 @@ +{ + "http-parser-js": { + "version": "0.5.10", + "url": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==" + } +} diff --git a/scripts/node-portable/.gitignore b/scripts/node-portable/.gitignore new file mode 100644 index 00000000..d24582cc --- /dev/null +++ b/scripts/node-portable/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +!package-lock.json diff --git a/scripts/node-portable/build.py b/scripts/node-portable/build.py new file mode 100644 index 00000000..0eb2b0f4 --- /dev/null +++ b/scripts/node-portable/build.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +"""Regenerate the portable Node modules from pinned upstream sources.""" + +from pathlib import Path +import hashlib +import json +import re +import subprocess +import urllib.request + +ROOT = Path(__file__).resolve().parents[2] +HERE = Path(__file__).resolve().parent +LIB = ROOT / 'src/Node/Lib' +PINNED = json.loads((HERE / 'node-sources.json').read_text()) +VERSION = PINNED['node'] +SOURCES = { + 'path': 'path.cjs', + 'querystring': 'querystring.cjs', + 'url': 'url.cjs', + 'internal/querystring': 'portable/internal-querystring.cjs', + 'internal/constants': 'portable/constants.cjs', +} + + +def main(): + LIB.mkdir(parents=True, exist_ok=True) + (LIB / 'portable').mkdir(exist_ok=True) + hashes = {} + primordial_names = set() + for source, target in SOURCES.items(): + url = PINNED['sources'][source]['url'] + original = urllib.request.urlopen(url, timeout=30).read() + if hashlib.sha256(original).hexdigest() != PINNED['sources'][source]['sha256']: + raise RuntimeError(f'Node source checksum mismatch: {source}') + hashes[source] = {'url': url, 'sha256': hashlib.sha256(original).hexdigest()} + text = original.decode() + for match in re.finditer(r'const \{([^}]+)\} = primordials;', text): + primordial_names.update(re.findall(r'\b\w+\b', match.group(1))) + prefix = './portable/' if '/' not in target else './' + text = text.replace('} = primordials;', "} = require('" + prefix + "primordials.cjs');") + text = text.replace("require('internal/constants')", "require('" + prefix + "constants.cjs')") + text = text.replace("require('internal/validators')", "require('" + prefix + "validators.cjs')") + text = text.replace("require('internal/errors')", "require('" + prefix + "errors.cjs')") + text = text.replace("require('internal/querystring')", "require('" + prefix + "internal-querystring.cjs')") + text = text.replace("require('internal/util')", "require('" + prefix + "helpers.cjs')") + text = text.replace("require('internal/fs/glob')", "require('./portable/glob.cjs')") + text = text.replace("require('internal/url')", "require('./portable/whatwg-url.cjs')") + text = text.replace("internalBinding('url_pattern')", 'globalThis') + text = text.replace("internalBinding('encoding_binding')", "{ toASCII: require('./portable/whatwg-url.cjs').domainToASCII }") + text = text.replace("internalBinding('util')", "require('./portable/helpers.cjs')") + text = text.replace("internalBinding('url')", "require('./portable/whatwg-url.cjs')") + if source == 'path': + signature = 'function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {' + if text.count(signature) != 1: + raise RuntimeError('Pinned Node path normalizer signature changed') + text = text.replace(signature, signature + "\n if (globalThis.__phasisNodeHost && __phasisNodeHost.path)\n return __phasisNodeHost.path.normalizeString(path, allowAboveRoot, separator);") + (LIB / target).write_text(text) + + license_source = PINNED['sources']['LICENSE'] + license_text = urllib.request.urlopen(license_source['url'], timeout=30).read() + if hashlib.sha256(license_text).hexdigest() != license_source['sha256']: + raise RuntimeError('Node license checksum mismatch') + (LIB / 'portable/NODE_LICENSE.txt').write_bytes(license_text) + hashes['LICENSE'] = license_source + + entries = [] + for name in sorted(primordial_names): + match = re.fullmatch(r'(\w+)Prototype(\w+)', name) + if match: + kind, method = match.groups() + method = method[0].lower() + method[1:] + value = f'Function.call.bind({kind}.prototype.{method})' + elif name == 'ArrayIsArray': + value = 'Array.isArray' + elif name == 'MathAbs': + value = 'Math.abs' + elif name == 'NumberIsFinite': + value = 'Number.isFinite' + elif name == 'ObjectKeys': + value = 'Object.keys' + elif name == 'ObjectAssign': + value = 'Object.assign' + else: + value = name + entries.append(f' {name}: {value},') + (LIB / 'portable/primordials.cjs').write_text( + "'use strict';\n\n// Capture intrinsics before user code can replace their prototype methods.\nmodule.exports = {\n" + + '\n'.join(entries) + '\n};\n' + ) + + esbuild = HERE / 'node_modules/esbuild/bin/esbuild' + for name, entry in [('util-base', 'util/util.js'), ('assert', 'assert/build/assert.js'), ('minimatch', 'minimatch'), ('punycode', 'punycode/punycode.js'), ('tr46', 'tr46'), ('hpack', 'hpack.js')]: + source = HERE / f'.entry-{name}.cjs' + source.write_text(f'module.exports = require({json.dumps(entry)});\n') + output = LIB / ('assert.cjs' if name == 'assert' else f'portable/{name}.cjs') + try: + arguments = [str(esbuild), str(source), '--bundle', '--platform=node', '--format=cjs', '--target=es2022', '--legal-comments=inline', f'--outfile={output}'] + if name == 'hpack': + arguments.append('--alias:readable-stream=stream') + subprocess.run(arguments, check=True) + finally: + source.unlink(missing_ok=True) + lock = json.loads((HERE / 'package-lock.json').read_text()) + licenses = {} + for package, details in lock['packages'].items(): + if not package: + continue + path = HERE / package + for candidate in ['LICENSE', 'LICENSE.md', 'LICENSE.txt', 'license', 'COPYING']: + if (path / candidate).is_file(): + licenses[f'{package.removeprefix("node_modules/")}@{details["version"]}'] = (path / candidate).read_text(errors='replace') + break + else: + readme = path / 'README.md' + if readme.is_file(): + content = readme.read_text(errors='replace') + match = re.search(r'^#+.*LICENSE.*$', content, re.MULTILINE | re.IGNORECASE) + if match: + licenses[f'{package.removeprefix("node_modules/")}@{details["version"]}'] = content[match.start():] + (LIB / 'portable/LICENSES.json').write_text(json.dumps(licenses, indent=2) + '\n') + (LIB / 'portable/http2-constants.json').write_bytes((HERE / 'http2-constants.json').read_bytes()) + (LIB / 'portable/sources.json').write_text(json.dumps({'node': VERSION, 'sources': hashes, 'npmLockSha256': hashlib.sha256((HERE / 'package-lock.json').read_bytes()).hexdigest()}, indent=2) + '\n') + + +if __name__ == '__main__': + main() diff --git a/scripts/node-portable/http2-constants.json b/scripts/node-portable/http2-constants.json new file mode 100644 index 00000000..ee6069ec --- /dev/null +++ b/scripts/node-portable/http2-constants.json @@ -0,0 +1,242 @@ +{ + "NGHTTP2_ERR_FRAME_SIZE_ERROR": -522, + "NGHTTP2_SESSION_SERVER": 0, + "NGHTTP2_SESSION_CLIENT": 1, + "NGHTTP2_STREAM_STATE_IDLE": 1, + "NGHTTP2_STREAM_STATE_OPEN": 2, + "NGHTTP2_STREAM_STATE_RESERVED_LOCAL": 3, + "NGHTTP2_STREAM_STATE_RESERVED_REMOTE": 4, + "NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL": 5, + "NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE": 6, + "NGHTTP2_STREAM_STATE_CLOSED": 7, + "NGHTTP2_FLAG_NONE": 0, + "NGHTTP2_FLAG_END_STREAM": 1, + "NGHTTP2_FLAG_END_HEADERS": 4, + "NGHTTP2_FLAG_ACK": 1, + "NGHTTP2_FLAG_PADDED": 8, + "NGHTTP2_FLAG_PRIORITY": 32, + "DEFAULT_SETTINGS_HEADER_TABLE_SIZE": 4096, + "DEFAULT_SETTINGS_ENABLE_PUSH": 1, + "DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS": 4294967295, + "DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE": 65535, + "DEFAULT_SETTINGS_MAX_FRAME_SIZE": 16384, + "DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE": 65535, + "DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL": 0, + "MAX_MAX_FRAME_SIZE": 16777215, + "MIN_MAX_FRAME_SIZE": 16384, + "MAX_INITIAL_WINDOW_SIZE": 2147483647, + "NGHTTP2_SETTINGS_HEADER_TABLE_SIZE": 1, + "NGHTTP2_SETTINGS_ENABLE_PUSH": 2, + "NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS": 3, + "NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE": 4, + "NGHTTP2_SETTINGS_MAX_FRAME_SIZE": 5, + "NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE": 6, + "NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL": 8, + "PADDING_STRATEGY_NONE": 0, + "PADDING_STRATEGY_ALIGNED": 1, + "PADDING_STRATEGY_MAX": 2, + "PADDING_STRATEGY_CALLBACK": 1, + "NGHTTP2_NO_ERROR": 0, + "NGHTTP2_PROTOCOL_ERROR": 1, + "NGHTTP2_INTERNAL_ERROR": 2, + "NGHTTP2_FLOW_CONTROL_ERROR": 3, + "NGHTTP2_SETTINGS_TIMEOUT": 4, + "NGHTTP2_STREAM_CLOSED": 5, + "NGHTTP2_FRAME_SIZE_ERROR": 6, + "NGHTTP2_REFUSED_STREAM": 7, + "NGHTTP2_CANCEL": 8, + "NGHTTP2_COMPRESSION_ERROR": 9, + "NGHTTP2_CONNECT_ERROR": 10, + "NGHTTP2_ENHANCE_YOUR_CALM": 11, + "NGHTTP2_INADEQUATE_SECURITY": 12, + "NGHTTP2_HTTP_1_1_REQUIRED": 13, + "NGHTTP2_DEFAULT_WEIGHT": 16, + "HTTP2_HEADER_STATUS": ":status", + "HTTP2_HEADER_METHOD": ":method", + "HTTP2_HEADER_AUTHORITY": ":authority", + "HTTP2_HEADER_SCHEME": ":scheme", + "HTTP2_HEADER_PATH": ":path", + "HTTP2_HEADER_PROTOCOL": ":protocol", + "HTTP2_HEADER_ACCEPT_ENCODING": "accept-encoding", + "HTTP2_HEADER_ACCEPT_LANGUAGE": "accept-language", + "HTTP2_HEADER_ACCEPT_RANGES": "accept-ranges", + "HTTP2_HEADER_ACCEPT": "accept", + "HTTP2_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS": "access-control-allow-credentials", + "HTTP2_HEADER_ACCESS_CONTROL_ALLOW_HEADERS": "access-control-allow-headers", + "HTTP2_HEADER_ACCESS_CONTROL_ALLOW_METHODS": "access-control-allow-methods", + "HTTP2_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN": "access-control-allow-origin", + "HTTP2_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS": "access-control-expose-headers", + "HTTP2_HEADER_ACCESS_CONTROL_REQUEST_HEADERS": "access-control-request-headers", + "HTTP2_HEADER_ACCESS_CONTROL_REQUEST_METHOD": "access-control-request-method", + "HTTP2_HEADER_AGE": "age", + "HTTP2_HEADER_AUTHORIZATION": "authorization", + "HTTP2_HEADER_CACHE_CONTROL": "cache-control", + "HTTP2_HEADER_CONNECTION": "connection", + "HTTP2_HEADER_CONTENT_DISPOSITION": "content-disposition", + "HTTP2_HEADER_CONTENT_ENCODING": "content-encoding", + "HTTP2_HEADER_CONTENT_LENGTH": "content-length", + "HTTP2_HEADER_CONTENT_TYPE": "content-type", + "HTTP2_HEADER_COOKIE": "cookie", + "HTTP2_HEADER_DATE": "date", + "HTTP2_HEADER_ETAG": "etag", + "HTTP2_HEADER_FORWARDED": "forwarded", + "HTTP2_HEADER_HOST": "host", + "HTTP2_HEADER_IF_MODIFIED_SINCE": "if-modified-since", + "HTTP2_HEADER_IF_NONE_MATCH": "if-none-match", + "HTTP2_HEADER_IF_RANGE": "if-range", + "HTTP2_HEADER_LAST_MODIFIED": "last-modified", + "HTTP2_HEADER_LINK": "link", + "HTTP2_HEADER_LOCATION": "location", + "HTTP2_HEADER_RANGE": "range", + "HTTP2_HEADER_REFERER": "referer", + "HTTP2_HEADER_SERVER": "server", + "HTTP2_HEADER_SET_COOKIE": "set-cookie", + "HTTP2_HEADER_STRICT_TRANSPORT_SECURITY": "strict-transport-security", + "HTTP2_HEADER_TRANSFER_ENCODING": "transfer-encoding", + "HTTP2_HEADER_TE": "te", + "HTTP2_HEADER_UPGRADE_INSECURE_REQUESTS": "upgrade-insecure-requests", + "HTTP2_HEADER_UPGRADE": "upgrade", + "HTTP2_HEADER_USER_AGENT": "user-agent", + "HTTP2_HEADER_VARY": "vary", + "HTTP2_HEADER_X_CONTENT_TYPE_OPTIONS": "x-content-type-options", + "HTTP2_HEADER_X_FRAME_OPTIONS": "x-frame-options", + "HTTP2_HEADER_KEEP_ALIVE": "keep-alive", + "HTTP2_HEADER_PROXY_CONNECTION": "proxy-connection", + "HTTP2_HEADER_X_XSS_PROTECTION": "x-xss-protection", + "HTTP2_HEADER_ALT_SVC": "alt-svc", + "HTTP2_HEADER_CONTENT_SECURITY_POLICY": "content-security-policy", + "HTTP2_HEADER_EARLY_DATA": "early-data", + "HTTP2_HEADER_EXPECT_CT": "expect-ct", + "HTTP2_HEADER_ORIGIN": "origin", + "HTTP2_HEADER_PURPOSE": "purpose", + "HTTP2_HEADER_TIMING_ALLOW_ORIGIN": "timing-allow-origin", + "HTTP2_HEADER_X_FORWARDED_FOR": "x-forwarded-for", + "HTTP2_HEADER_PRIORITY": "priority", + "HTTP2_HEADER_ACCEPT_CHARSET": "accept-charset", + "HTTP2_HEADER_ACCESS_CONTROL_MAX_AGE": "access-control-max-age", + "HTTP2_HEADER_ALLOW": "allow", + "HTTP2_HEADER_CONTENT_LANGUAGE": "content-language", + "HTTP2_HEADER_CONTENT_LOCATION": "content-location", + "HTTP2_HEADER_CONTENT_MD5": "content-md5", + "HTTP2_HEADER_CONTENT_RANGE": "content-range", + "HTTP2_HEADER_DNT": "dnt", + "HTTP2_HEADER_EXPECT": "expect", + "HTTP2_HEADER_EXPIRES": "expires", + "HTTP2_HEADER_FROM": "from", + "HTTP2_HEADER_IF_MATCH": "if-match", + "HTTP2_HEADER_IF_UNMODIFIED_SINCE": "if-unmodified-since", + "HTTP2_HEADER_MAX_FORWARDS": "max-forwards", + "HTTP2_HEADER_PREFER": "prefer", + "HTTP2_HEADER_PROXY_AUTHENTICATE": "proxy-authenticate", + "HTTP2_HEADER_PROXY_AUTHORIZATION": "proxy-authorization", + "HTTP2_HEADER_REFRESH": "refresh", + "HTTP2_HEADER_RETRY_AFTER": "retry-after", + "HTTP2_HEADER_TRAILER": "trailer", + "HTTP2_HEADER_TK": "tk", + "HTTP2_HEADER_VIA": "via", + "HTTP2_HEADER_WARNING": "warning", + "HTTP2_HEADER_WWW_AUTHENTICATE": "www-authenticate", + "HTTP2_HEADER_HTTP2_SETTINGS": "http2-settings", + "HTTP2_METHOD_ACL": "ACL", + "HTTP2_METHOD_BASELINE_CONTROL": "BASELINE-CONTROL", + "HTTP2_METHOD_BIND": "BIND", + "HTTP2_METHOD_CHECKIN": "CHECKIN", + "HTTP2_METHOD_CHECKOUT": "CHECKOUT", + "HTTP2_METHOD_CONNECT": "CONNECT", + "HTTP2_METHOD_COPY": "COPY", + "HTTP2_METHOD_DELETE": "DELETE", + "HTTP2_METHOD_GET": "GET", + "HTTP2_METHOD_HEAD": "HEAD", + "HTTP2_METHOD_LABEL": "LABEL", + "HTTP2_METHOD_LINK": "LINK", + "HTTP2_METHOD_LOCK": "LOCK", + "HTTP2_METHOD_MERGE": "MERGE", + "HTTP2_METHOD_MKACTIVITY": "MKACTIVITY", + "HTTP2_METHOD_MKCALENDAR": "MKCALENDAR", + "HTTP2_METHOD_MKCOL": "MKCOL", + "HTTP2_METHOD_MKREDIRECTREF": "MKREDIRECTREF", + "HTTP2_METHOD_MKWORKSPACE": "MKWORKSPACE", + "HTTP2_METHOD_MOVE": "MOVE", + "HTTP2_METHOD_OPTIONS": "OPTIONS", + "HTTP2_METHOD_ORDERPATCH": "ORDERPATCH", + "HTTP2_METHOD_PATCH": "PATCH", + "HTTP2_METHOD_POST": "POST", + "HTTP2_METHOD_PRI": "PRI", + "HTTP2_METHOD_PROPFIND": "PROPFIND", + "HTTP2_METHOD_PROPPATCH": "PROPPATCH", + "HTTP2_METHOD_PUT": "PUT", + "HTTP2_METHOD_REBIND": "REBIND", + "HTTP2_METHOD_REPORT": "REPORT", + "HTTP2_METHOD_SEARCH": "SEARCH", + "HTTP2_METHOD_TRACE": "TRACE", + "HTTP2_METHOD_UNBIND": "UNBIND", + "HTTP2_METHOD_UNCHECKOUT": "UNCHECKOUT", + "HTTP2_METHOD_UNLINK": "UNLINK", + "HTTP2_METHOD_UNLOCK": "UNLOCK", + "HTTP2_METHOD_UPDATE": "UPDATE", + "HTTP2_METHOD_UPDATEREDIRECTREF": "UPDATEREDIRECTREF", + "HTTP2_METHOD_VERSION_CONTROL": "VERSION-CONTROL", + "HTTP_STATUS_CONTINUE": 100, + "HTTP_STATUS_SWITCHING_PROTOCOLS": 101, + "HTTP_STATUS_PROCESSING": 102, + "HTTP_STATUS_EARLY_HINTS": 103, + "HTTP_STATUS_OK": 200, + "HTTP_STATUS_CREATED": 201, + "HTTP_STATUS_ACCEPTED": 202, + "HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION": 203, + "HTTP_STATUS_NO_CONTENT": 204, + "HTTP_STATUS_RESET_CONTENT": 205, + "HTTP_STATUS_PARTIAL_CONTENT": 206, + "HTTP_STATUS_MULTI_STATUS": 207, + "HTTP_STATUS_ALREADY_REPORTED": 208, + "HTTP_STATUS_IM_USED": 226, + "HTTP_STATUS_MULTIPLE_CHOICES": 300, + "HTTP_STATUS_MOVED_PERMANENTLY": 301, + "HTTP_STATUS_FOUND": 302, + "HTTP_STATUS_SEE_OTHER": 303, + "HTTP_STATUS_NOT_MODIFIED": 304, + "HTTP_STATUS_USE_PROXY": 305, + "HTTP_STATUS_TEMPORARY_REDIRECT": 307, + "HTTP_STATUS_PERMANENT_REDIRECT": 308, + "HTTP_STATUS_BAD_REQUEST": 400, + "HTTP_STATUS_UNAUTHORIZED": 401, + "HTTP_STATUS_PAYMENT_REQUIRED": 402, + "HTTP_STATUS_FORBIDDEN": 403, + "HTTP_STATUS_NOT_FOUND": 404, + "HTTP_STATUS_METHOD_NOT_ALLOWED": 405, + "HTTP_STATUS_NOT_ACCEPTABLE": 406, + "HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED": 407, + "HTTP_STATUS_REQUEST_TIMEOUT": 408, + "HTTP_STATUS_CONFLICT": 409, + "HTTP_STATUS_GONE": 410, + "HTTP_STATUS_LENGTH_REQUIRED": 411, + "HTTP_STATUS_PRECONDITION_FAILED": 412, + "HTTP_STATUS_PAYLOAD_TOO_LARGE": 413, + "HTTP_STATUS_URI_TOO_LONG": 414, + "HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE": 415, + "HTTP_STATUS_RANGE_NOT_SATISFIABLE": 416, + "HTTP_STATUS_EXPECTATION_FAILED": 417, + "HTTP_STATUS_TEAPOT": 418, + "HTTP_STATUS_MISDIRECTED_REQUEST": 421, + "HTTP_STATUS_UNPROCESSABLE_ENTITY": 422, + "HTTP_STATUS_LOCKED": 423, + "HTTP_STATUS_FAILED_DEPENDENCY": 424, + "HTTP_STATUS_TOO_EARLY": 425, + "HTTP_STATUS_UPGRADE_REQUIRED": 426, + "HTTP_STATUS_PRECONDITION_REQUIRED": 428, + "HTTP_STATUS_TOO_MANY_REQUESTS": 429, + "HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE": 431, + "HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS": 451, + "HTTP_STATUS_INTERNAL_SERVER_ERROR": 500, + "HTTP_STATUS_NOT_IMPLEMENTED": 501, + "HTTP_STATUS_BAD_GATEWAY": 502, + "HTTP_STATUS_SERVICE_UNAVAILABLE": 503, + "HTTP_STATUS_GATEWAY_TIMEOUT": 504, + "HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED": 505, + "HTTP_STATUS_VARIANT_ALSO_NEGOTIATES": 506, + "HTTP_STATUS_INSUFFICIENT_STORAGE": 507, + "HTTP_STATUS_LOOP_DETECTED": 508, + "HTTP_STATUS_BANDWIDTH_LIMIT_EXCEEDED": 509, + "HTTP_STATUS_NOT_EXTENDED": 510, + "HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED": 511 +} diff --git a/scripts/node-portable/node-sources.json b/scripts/node-portable/node-sources.json new file mode 100644 index 00000000..fe76da38 --- /dev/null +++ b/scripts/node-portable/node-sources.json @@ -0,0 +1,29 @@ +{ + "node": "v26.12.0", + "sources": { + "path": { + "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/path.js", + "sha256": "f05ab2a1f33102880bb8c5052cb0e634a001112883da897f3498492bef67f3f6" + }, + "querystring": { + "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/querystring.js", + "sha256": "35c87b8230aef78ab162579a6820e78a4de8266a2983e36272ad3b248a357441" + }, + "url": { + "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/url.js", + "sha256": "9037c1cae0efe6af02ea18da109ff0c406496cccaf9df4c3308ef057d009150f" + }, + "internal/querystring": { + "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/internal/querystring.js", + "sha256": "92d0cbd561d7cce93936b083d56d2a41063d177f3aa6772ae2c1871f160163d1" + }, + "internal/constants": { + "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/internal/constants.js", + "sha256": "4548f10f15035b415bfa69a158e7bcf7e320355625d744d7318715c9acc21212" + }, + "LICENSE": { + "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/LICENSE", + "sha256": "8e603aa87c70d36e497004f0dec63111511cb61b7d65ace12e10ea791599286c" + } + } +} diff --git a/scripts/node-portable/package-lock.json b/scripts/node-portable/package-lock.json new file mode 100644 index 00000000..af2f0659 --- /dev/null +++ b/scripts/node-portable/package-lock.json @@ -0,0 +1,1348 @@ +{ + "name": "phasis-node-portable-build", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "phasis-node-portable-build", + "version": "0.0.0", + "devDependencies": { + "assert": "2.1.0", + "esbuild": "0.27.0", + "hpack.js": "2.1.6", + "minimatch": "10.2.2", + "tr46": "7.0.0", + "url": "0.11.4", + "util": "0.12.5" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz", + "integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.0.tgz", + "integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz", + "integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.0.tgz", + "integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz", + "integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz", + "integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz", + "integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz", + "integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz", + "integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz", + "integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz", + "integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz", + "integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz", + "integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz", + "integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz", + "integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz", + "integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz", + "integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz", + "integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz", + "integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz", + "integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz", + "integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz", + "integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz", + "integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz", + "integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz", + "integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz", + "integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz", + "integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.0", + "@esbuild/android-arm": "0.27.0", + "@esbuild/android-arm64": "0.27.0", + "@esbuild/android-x64": "0.27.0", + "@esbuild/darwin-arm64": "0.27.0", + "@esbuild/darwin-x64": "0.27.0", + "@esbuild/freebsd-arm64": "0.27.0", + "@esbuild/freebsd-x64": "0.27.0", + "@esbuild/linux-arm": "0.27.0", + "@esbuild/linux-arm64": "0.27.0", + "@esbuild/linux-ia32": "0.27.0", + "@esbuild/linux-loong64": "0.27.0", + "@esbuild/linux-mips64el": "0.27.0", + "@esbuild/linux-ppc64": "0.27.0", + "@esbuild/linux-riscv64": "0.27.0", + "@esbuild/linux-s390x": "0.27.0", + "@esbuild/linux-x64": "0.27.0", + "@esbuild/netbsd-arm64": "0.27.0", + "@esbuild/netbsd-x64": "0.27.0", + "@esbuild/openbsd-arm64": "0.27.0", + "@esbuild/openbsd-x64": "0.27.0", + "@esbuild/openharmony-arm64": "0.27.0", + "@esbuild/sunos-x64": "0.27.0", + "@esbuild/win32-arm64": "0.27.0", + "@esbuild/win32-ia32": "0.27.0", + "@esbuild/win32-x64": "0.27.0" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", + "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.1.tgz", + "integrity": "sha512-5Px6J7rfHBAGUhNQ3es4YzcOdBBw0SDcVtThJml4RdnKw4tKs2epA0kPZ+K8X+WiHktT93RHVcQ/3ym5aTCgtg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tr46": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-7.0.0.tgz", + "integrity": "sha512-BcDSDW+SIGWVOns1Zm6Yg91q9AEj7eaID0QDY9oIqJD1A8dscNwMcl9Sms2DeuWCNov1X0/oXanHGYQBSLwZsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": "^22.14.0 || >=24.0.0" + } + }, + "node_modules/tr46/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.24", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.24.tgz", + "integrity": "sha512-wk4Mf4pR5mRP7eYuuTBCIQ9d0ud2Fv2jRLQpfgnRjbOxAFHmjKFValgTpitVKzJJS8ajnYQV2Du1SZ8j6b/EUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + } + } +} diff --git a/scripts/node-portable/package.json b/scripts/node-portable/package.json new file mode 100644 index 00000000..510c3f70 --- /dev/null +++ b/scripts/node-portable/package.json @@ -0,0 +1,14 @@ +{ + "name": "phasis-node-portable-build", + "private": true, + "version": "0.0.0", + "devDependencies": { + "assert": "2.1.0", + "esbuild": "0.27.0", + "hpack.js": "2.1.6", + "minimatch": "10.2.2", + "tr46": "7.0.0", + "url": "0.11.4", + "util": "0.12.5" + } +} diff --git a/scripts/node-primitives/.gitignore b/scripts/node-primitives/.gitignore new file mode 100644 index 00000000..d0685460 --- /dev/null +++ b/scripts/node-primitives/.gitignore @@ -0,0 +1,2 @@ +/node_modules/ +!package-lock.json diff --git a/scripts/node-primitives/README.md b/scripts/node-primitives/README.md new file mode 100644 index 00000000..a64a11ec --- /dev/null +++ b/scripts/node-primitives/README.md @@ -0,0 +1,65 @@ +# Node compatibility foundations + +The runtime assets under `src/Node/Lib` execute inside Phasis. Node and npm are +development tools only; no runtime JavaScript execution is delegated to Node. + +Regenerate the pinned upstream implementations and their license manifest with: + +```sh +npm ci --ignore-scripts --prefix scripts/node-primitives +node scripts/node-primitives/build.mjs +node scripts/node-primitives/generate-oracles.mjs +XDEBUG_MODE=off vendor/bin/phpunit tests/Unit/Node +``` + +The lockfile records exact tarball integrity. The builder uses real `buffer`, +`events`, `readable-stream`, `string_decoder`, and Brotli implementations. The +entry files add modern Node APIs and Web Stream adapters while retaining shared +builtin identity. The readable-stream source includes the actual stream state +machines, error propagation, async iteration, pipeline, and backpressure. +Buffer fills use typed-array fills and doubling copies, preserving overlapping +patterns while avoiding interpreted byte loops for large allocations. +UTF-8 sizing and writes use the realm's TextEncoder, including replacement of +isolated surrogates and writes that stop before an incomplete encoded character. + +Brotli 1.3.3 supplies a synchronous pure-JavaScript encoder and decoder. Its +immutable dictionary and compiler memory are represented as base64 rather than +large numeric literals or decompressed on every load. The encoder uses a 64 MiB +heap within Phasis's buffer allocation limits. C memory operations and two large +table fills map to equivalent typed-array methods. The wrapper corrects the +upstream output-capacity argument for incompressible input. All changes are +deterministic and checked against the pinned source before replacement. + +The filesystem and zlib JavaScript adapters use PHP host operations and own +their descriptors and codec contexts through `NodeRuntime::onClose`. Filesystem +callbacks run through the Node job queue; file streams use actual descriptors +and demand-driven reads. PHP exposes second-resolution file timestamps and no +portable birth timestamp, so the stat adapter cannot reproduce native subsecond +or birth-time precision on every host. Filesystem watching and platform-specific +descriptor ownership operations are not currently exported. + +Gzip/deflate streams are incremental native PHP zlib codecs. The bundled Brotli +stream fallback buffers whole frames, and partial flush reports an explicit +unsupported-feature error. Default quality 11 compression is substantially +slower in Phasis than the native zlib codecs. Changing zlib compression parameters +after construction is unavailable when PHP provides no `deflateParams` binding. + +The VM adapter uses separate Engine realms and live sandbox globals, preserving +the caller's intrinsic defaults, Promise hooks, and async context. V8 cache +serialization, per-context code-generation controls, and compileFunction context +extensions report explicit unsupported-feature errors. + +Child processes use PHP `proc_open` with nonblocking pipes and a realm-owned I/O +driver. Sync spawn/exec, async spawn/exec, binary stdin/stdout/stderr, backpressure, +timeouts, signals, aborts and cleanup are covered against native Node. Requests +to launch `process.execPath` with a JavaScript file run a separate Phasis PHP +entry point. JavaScript evaluation never goes through Node. IPC/fork, detached +sessions, uid/gid changes, custom argv0 and inherited descriptors beyond standard +streams report explicit unsupported-feature errors. Runtime cleanup terminates +and reaps each child process it directly owns. + +The fixtures compare individual observable results with Node 26, including raw +binary payloads, malformed input, listener mutation, stream backpressure/errors, +filesystem range reads, resource cleanup, compression interoperability, and +cross-realm identity. These probes are regression coverage, not a claim that the +complete upstream Node test suite passes. diff --git a/scripts/node-primitives/brotli-LICENSES.txt b/scripts/node-primitives/brotli-LICENSES.txt new file mode 100644 index 00000000..ff5ed7b0 --- /dev/null +++ b/scripts/node-primitives/brotli-LICENSES.txt @@ -0,0 +1,234 @@ +brotli 1.3.3 by Devon Govett. The npm package declares MIT. +The bundled Google decoder source retains its Apache-2.0 notices. +Decoder copyright: Copyright 2013 Google Inc. All Rights Reserved. +Phasis changes: compact dictionary and compiler-memory representation, a 64 MiB +encoder heap, typed-array equivalents of C memory/table operations, removal of +the process-wide Emscripten exception listener, and corrected output capacity. +The compiled Google Brotli encoder is distributed under the following MIT license. + +Source: https://github.com/google/brotli/blob/master/LICENSE + +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Decoder source license: https://www.apache.org/licenses/LICENSE-2.0.txt + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/scripts/node-primitives/brotli-decoder-entry.cjs b/scripts/node-primitives/brotli-decoder-entry.cjs new file mode 100644 index 00000000..801b2085 --- /dev/null +++ b/scripts/node-primitives/brotli-decoder-entry.cjs @@ -0,0 +1,2 @@ +'use strict'; +module.exports = require('./node_modules/brotli/decompress.js'); diff --git a/scripts/node-primitives/brotli-encoder-entry.cjs b/scripts/node-primitives/brotli-encoder-entry.cjs new file mode 100644 index 00000000..557fd6f5 --- /dev/null +++ b/scripts/node-primitives/brotli-encoder-entry.cjs @@ -0,0 +1,18 @@ +'use strict'; +const encoder = require('./node_modules/brotli/build/encode.js'); + +module.exports = function compress(bytes, options = {}) { + const input = encoder._malloc(Math.max(bytes.length, 1)); + const capacity = bytes.length + 1024; + const output = encoder._malloc(capacity); + try { + encoder.HEAPU8.set(bytes, input); + // Upstream's convenience wrapper passes input.length as capacity and rejects incompressible data. + const length = encoder._encode(options.quality ?? 11, options.lgwin ?? 22, options.mode ?? 0, bytes.length, input, capacity, output); + if (length === -1) throw new Error('Brotli compression failed'); + return encoder.HEAPU8.slice(output, output + length); + } finally { + encoder._free(input); + encoder._free(output); + } +}; diff --git a/scripts/node-primitives/buffer-entry.cjs b/scripts/node-primitives/buffer-entry.cjs new file mode 100644 index 00000000..02d4454b --- /dev/null +++ b/scripts/node-primitives/buffer-entry.cjs @@ -0,0 +1,62 @@ +'use strict'; + +const exported = require('./node_modules/buffer/index.js'); +const { Buffer } = exported; +const from = Buffer.from; +const byteLength = Buffer.byteLength; +const isEncoding = Buffer.isEncoding; +const toString = Buffer.prototype.toString; +const write = Buffer.prototype.write; +const normalize = (encoding) => typeof encoding === 'string' && encoding.toLowerCase() === 'base64url' ? 'base64' : encoding; +Buffer.from = function (value, encodingOrOffset, length) { + return from(value, normalize(encodingOrOffset), length); +}; +Buffer.byteLength = function (value, encoding) { return byteLength(value, normalize(encoding)); }; +Buffer.isEncoding = function (encoding) { return isEncoding(normalize(encoding)); }; +Buffer.prototype.toString = function (encoding, start, end) { + if (!encoding || typeof encoding === 'string' && /^(utf8|utf-8)$/i.test(encoding)) { + if (start === undefined || start < 0) start = 0; + if (start > this.length) return ''; + if (end === undefined || end > this.length) end = this.length; + if (end <= 0) return ''; + end >>>= 0; start >>>= 0; + if (end <= start) return ''; + // Node consumes incomplete UTF-8 prefixes as one replacement and retains BOMs. + return new TextDecoder('utf-8', { ignoreBOM: true }).decode(new Uint8Array(this.buffer, this.byteOffset + start, end - start)); + } + const result = toString.call(this, normalize(encoding), start, end); + return typeof encoding === 'string' && encoding.toLowerCase() === 'base64url' + ? result.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') : result; +}; +Buffer.prototype.write = function (string, offset, length, encoding) { + return write.call(this, string, normalize(offset), normalize(length), normalize(encoding)); +}; +Buffer.copyBytesFrom = function (view, offset = 0, length) { + if (!ArrayBuffer.isView(view) || view instanceof DataView) throw new TypeError('The "view" argument must be a TypedArray.'); + length ??= Math.max(view.length - offset, 0); + for (const [name, value] of [['offset', offset], ['length', length]]) { + if (!Number.isInteger(value) || value < 0) throw new RangeError(`The "${name}" argument is out of range.`); + } + const start = Math.min(offset, view.length); + const count = Math.min(length, view.length - start); + return Buffer.from(new Uint8Array(view.buffer, view.byteOffset + start * view.BYTES_PER_ELEMENT, count * view.BYTES_PER_ELEMENT)); +}; +Buffer.prototype.readBigUint64LE = Buffer.prototype.readBigUInt64LE; +Buffer.prototype.readBigUint64BE = Buffer.prototype.readBigUInt64BE; +Buffer.prototype.writeBigUint64LE = Buffer.prototype.writeBigUInt64LE; +Buffer.prototype.writeBigUint64BE = Buffer.prototype.writeBigUInt64BE; +exported.Blob = globalThis.Blob; +exported.File = globalThis.File; +exported.atob = globalThis.atob; +exported.btoa = globalThis.btoa; +exported.constants = Object.freeze({ MAX_LENGTH: exported.kMaxLength, MAX_STRING_LENGTH: 536870888 }); +exported.isAscii = function (input) { + if (!ArrayBuffer.isView(input) && !(input instanceof ArrayBuffer)) throw new TypeError('The "input" argument must be an ArrayBuffer or ArrayBufferView.'); + const bytes = input instanceof ArrayBuffer ? new Uint8Array(input) : new Uint8Array(input.buffer, input.byteOffset, input.byteLength); + return bytes.every((byte) => byte < 128); +}; +exported.isUtf8 = function (input) { + if (!ArrayBuffer.isView(input) && !(input instanceof ArrayBuffer)) throw new TypeError('The "input" argument must be an ArrayBuffer or ArrayBufferView.'); + try { new TextDecoder('utf-8', { fatal: true }).decode(input); return true; } catch { return false; } +}; +module.exports = exported; diff --git a/scripts/node-primitives/build.mjs b/scripts/node-primitives/build.mjs new file mode 100644 index 00000000..48ec5a91 --- /dev/null +++ b/scripts/node-primitives/build.mjs @@ -0,0 +1,110 @@ +import { build } from 'esbuild'; +import { readFile, writeFile, mkdir } from 'node:fs/promises'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createRequire } from 'node:module'; + +const directory = dirname(fileURLToPath(import.meta.url)); +const require = createRequire(import.meta.url); +const output = resolve(directory, '../../src/Node/Lib'); +await mkdir(output, { recursive: true }); +const entries = ['buffer', 'events', 'stream', 'string_decoder', 'stream-promises', 'stream-consumers', 'stream-web', 'brotli-decoder', 'brotli-encoder']; +const packages = new Set(); +const outputs = {}; +for (const name of entries) { + const result = await build({ + absWorkingDir: directory, + entryPoints: [`${name}-entry.cjs`], + outfile: resolve(output, `${name}.cjs`), + bundle: true, + format: 'cjs', + platform: 'node', + target: 'esnext', + legalComments: 'inline', + metafile: true, + external: ['buffer', 'events', 'stream', 'string_decoder', 'process', 'async_hooks', 'abort-controller', 'fs', 'path'], + plugins: [{ + name: 'canonical-core-module-names', + setup(builder) { + builder.onResolve({ filter: /^(?:process|string_decoder)\/$/ }, ({ path }) => ({ path: path.slice(0, -1), external: true })); + builder.onLoad({ filter: /node_modules\/buffer\/index\.js$/ }, async ({ path }) => { + let source = await readFile(path, 'utf8'); + for (const [loop, replacement] of [ + ['return utf8ToBytes(string).length', 'return new TextEncoder().encode(string).length'], + ['return mustMatch ? -1 : utf8ToBytes(string).length', 'return mustMatch ? -1 : new TextEncoder().encode(string).length'], + ['return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)', 'return new TextEncoder().encodeInto(string, new Uint8Array(buf.buffer, buf.byteOffset + offset, length)).written'], + ['for (i = start; i < end; ++i) {\n this[i] = val\n }', 'Uint8Array.prototype.fill.call(this, val, start, end)'], + ['for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }', `const count = end - start + const seed = Math.min(len, count) + Uint8Array.prototype.set.call(this, bytes.subarray(0, seed), start) + for (let filled = seed; filled < count; filled *= 2) { + Uint8Array.prototype.copyWithin.call(this, start + filled, start, start + Math.min(filled, count - filled)) + }`], + ]) { + if (!source.includes(loop)) throw new Error('Unexpected pinned Buffer fill loop'); + source = source.replace(loop, replacement); + } + return { contents: source, loader: 'js' }; + }); + builder.onLoad({ filter: /brotli\/dec\/dictionary-data\.js$/ }, async ({ path }) => { + const source = await readFile(path, 'utf8'); + const data = Buffer.from(require(path).dictionary).toString('base64'); + return { contents: `${source.slice(0, source.indexOf('exports.dictionary'))}\n// Equivalent dictionary bytes avoid parsing 122,784 numeric literals at runtime.\nexports.dictionary = Uint8Array.fromBase64(${JSON.stringify(data)});\nexports.init = function () { return exports.dictionary; };`, loader: 'js' }; + }); + builder.onLoad({ filter: /brotli\/build\/encode\.js$/ }, async ({ path }) => { + let source = await readFile(path, 'utf8'); + const compressed = require(resolve(directory, 'node_modules/brotli/build/mem.js')); + const memory = require(resolve(directory, 'node_modules/brotli/decompress.js'))(Buffer.from(compressed, 'base64')); + const prefix = 'var b={},aa=require("../decompress"),ba=require("base64-js");b.readBinary=function(){var a=ba.toByteArray(require("../build/mem.js"));return aa(a)};'; + if (!source.startsWith(prefix)) throw new Error('Unexpected pinned Brotli encoder prelude'); + // Predecode immutable compiler memory during the reproducible build, not each engine bootstrap. + source = `var b={TOTAL_MEMORY:67108864};b.readBinary=function(){return Uint8Array.fromBase64(${JSON.stringify(Buffer.from(memory).toString('base64'))})};` + source.slice(prefix.length); + source = source.replace('process.on("uncaughtException",function(a){if(!(a instanceof y))throw a;});', ''); + for (const [loop, fill] of [ + ['i=0;while(1){if((i|0)==131072)break;c[d+4+(i<<2)>>2]=e;i=i+1|0}', 'c.fill(e,d+4>>2,(d+4>>2)+131072);i=131072;'], + ['n=0;while(1){if((n|0)==131072)break;c[ua+4+(n<<2)>>2]=f;n=n+1|0}', 'c.fill(f,ua+4>>2,(ua+4>>2)+131072);n=131072;'], + ]) { + if (!source.includes(loop)) throw new Error('Unexpected pinned Brotli hash-table initialization'); + source = source.replace(loop, fill); + } + // These C memory primitives map directly to typed-array operations and avoid multi-million-step JS byte loops. + for (const [name, replacement] of [ + ['ac', 'function ac(b,d,e){b=b|0;d=d|0;e=e|0;a.fill(d&255,b,b+e);return b|0}'], + ['dc', 'function dc(b,d,e){b=b|0;d=d|0;e=e|0;a.copyWithin(b,d,d+e);return b|0}'], + ['fc', 'function fc(b,c,d){b=b|0;c=c|0;d=d|0;a.copyWithin(b,c,c+d);return b|0}'], + ]) { + const start = source.indexOf(`function ${name}(`); + const end = source.indexOf('function ', start + 9); + if (start < 0 || end < 0) throw new Error(`Unexpected pinned Brotli memory primitive: ${name}`); + source = source.slice(0, start) + replacement + source.slice(end); + } + return { contents: source, loader: 'js' }; + }); + }, + }], + banner: { js: '// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt.' }, + }); + for (const input of Object.keys(result.metafile.inputs)) { + const match = /^node_modules\/((?:@[^/]+\/)?[^/]+)\//.exec(input); + if (match) packages.add(match[1]); + } + const metadata = Object.values(result.metafile.outputs)[0]; + outputs[name] = { bytes: metadata.bytes, requires: [...new Set(metadata.imports.filter((entry) => entry.external).map((entry) => entry.path))].sort() }; +} +const lock = JSON.parse(await readFile(resolve(directory, 'package-lock.json'), 'utf8')); +const upstream = {}; +const licenses = []; +for (const name of [...packages].sort()) { + const metadata = JSON.parse(await readFile(resolve(directory, 'node_modules', name, 'package.json'), 'utf8')); + upstream[name] = { version: metadata.version, integrity: lock.packages[`node_modules/${name}`].integrity }; + let license; + for (const file of ['LICENSE', 'LICENSE.md', 'LICENSE-MIT.txt']) { + try { license = await readFile(resolve(directory, 'node_modules', name, file), 'utf8'); break; } catch {} + } + if (!license && name === 'brotli') license = await readFile(resolve(directory, 'brotli-LICENSES.txt'), 'utf8'); + if (!license) throw new Error(`Missing upstream license: ${name}`); + licenses.push(`${name} ${metadata.version}\n${license.trim()}\n`); +} +await writeFile(resolve(output, 'primitives-manifest.json'), `${JSON.stringify({ upstream, outputs }, null, 2)}\n`); +await writeFile(resolve(output, 'primitives-LICENSES.txt'), licenses.join('\n')); +console.log(`Built ${entries.length} Node primitive modules from ${packages.size} pinned packages.`); diff --git a/scripts/node-primitives/events-entry.cjs b/scripts/node-primitives/events-entry.cjs new file mode 100644 index 00000000..6f13f40a --- /dev/null +++ b/scripts/node-primitives/events-entry.cjs @@ -0,0 +1,175 @@ +'use strict'; + +const Base = require('./node_modules/events/events.js'); +const capture = Symbol('captureRejections'); +const rejection = Symbol.for('nodejs.rejection'); +const errorMonitor = Symbol('events.errorMonitor'); +const targetLimits = new WeakMap(); +let defaultCapture = false; +function EventEmitter(options) { + Base.call(this); + const value = options?.captureRejections; + if (value !== undefined && typeof value !== 'boolean') throw new TypeError('The "options.captureRejections" property must be boolean.'); + this[capture] = value ?? defaultCapture; +} +Object.setPrototypeOf(EventEmitter, Base); +EventEmitter.prototype = Base.prototype; +Object.defineProperty(EventEmitter.prototype, 'constructor', { value: EventEmitter, writable: true, configurable: true }); +const emit = Base.prototype.emit; +EventEmitter.prototype.emit = function (name, ...args) { + if (name === 'error') emit.call(this, errorMonitor, ...args); + if (!this[capture]) return emit.call(this, name, ...args); + const listeners = this.rawListeners(name); + if (!listeners.length) return emit.call(this, name, ...args); + for (const listener of listeners) { + const result = Reflect.apply(listener, this, args); + if (result !== null && (typeof result === 'object' || typeof result === 'function')) { + try { + if (typeof result.then === 'function') result.then(undefined, (error) => queueMicrotask(() => { + if (typeof this[rejection] === 'function') this[rejection](error, name, ...args); + else { + const previous = this[capture]; + this[capture] = false; + try { this.emit('error', error); } finally { this[capture] = previous; } + } + })); + } catch (error) { this.emit('error', error); } + } + } + return true; +}; +const listenerCount = Base.prototype.listenerCount; +EventEmitter.prototype.listenerCount = function (name, listener) { + return listener === undefined ? listenerCount.call(this, name) : this.rawListeners(name).filter((item) => item === listener || item.listener === listener).length; +}; +Object.defineProperty(EventEmitter, 'captureRejections', { + enumerable: true, + get() { return defaultCapture; }, + set(value) { if (typeof value !== 'boolean') throw new TypeError('captureRejections must be boolean.'); defaultCapture = value; }, +}); +function abortError(signal) { + const error = new Error('The operation was aborted', { cause: signal?.reason }); + error.name = 'AbortError'; + error.code = 'ABORT_ERR'; + return error; +} +function validateSignal(signal) { + if (signal !== undefined && (!signal || typeof signal.aborted !== 'boolean' || typeof signal.addEventListener !== 'function')) throw new TypeError('The "signal" argument must be an AbortSignal.'); +} +function listen(target, name, listener, once = false) { + if (typeof target.on === 'function') { + target[once ? 'once' : 'on'](name, listener); + return () => target.removeListener(name, listener); + } + if (typeof target.addEventListener === 'function') { + target.addEventListener(name, listener, { once }); + return () => target.removeEventListener(name, listener); + } + throw new TypeError('The emitter must be an EventEmitter or EventTarget.'); +} +function once(emitter, name, options = {}) { + const signal = options.signal; + validateSignal(signal); + return new Promise((resolve, reject) => { + if (signal?.aborted) { reject(abortError(signal)); return; } + const removers = []; + const cleanup = () => { for (const remove of removers) remove(); }; + removers.push(listen(emitter, name, (...args) => { cleanup(); resolve(args); }, true)); + if (name !== 'error' && typeof emitter.on === 'function') removers.push(listen(emitter, 'error', (error) => { cleanup(); reject(error); }, true)); + if (signal) removers.push(listen(signal, 'abort', () => { cleanup(); reject(abortError(signal)); }, true)); + }); +} +function on(emitter, name, options = {}) { + const signal = options.signal; + validateSignal(signal); + if (signal?.aborted) throw abortError(signal); + const high = options.highWaterMark ?? options.highWatermark ?? Number.MAX_SAFE_INTEGER; + const low = options.lowWaterMark ?? options.lowWatermark ?? 1; + if (!Number.isInteger(high) || high < 1 || !Number.isInteger(low) || low < 1) throw new RangeError('Invalid event iterator water mark.'); + const values = []; + const waiters = []; + const removers = []; + let error; + let done = false; + let paused = false; + function cleanup() { for (const remove of removers) remove(); } + function finish(reason) { + done = true; + error = reason; + cleanup(); + while (waiters.length) { + const waiter = waiters.shift(); + if (error) { waiter.reject(error); error = undefined; } + else waiter.resolve({ value: undefined, done: true }); + } + } + removers.push(listen(emitter, name, (...args) => { + if (waiters.length) waiters.shift().resolve({ value: args, done: false }); + else { + values.push(args); + if (!paused && values.length > high) { paused = true; emitter.pause(); } + } + })); + if (name !== 'error' && typeof emitter.on === 'function') removers.push(listen(emitter, 'error', finish)); + if (signal) removers.push(listen(signal, 'abort', () => finish(abortError(signal)), true)); + for (const event of options.close || []) removers.push(listen(emitter, event, () => finish(), true)); + return { + next() { + if (values.length) { + const value = values.shift(); + if (paused && values.length < low) { paused = false; emitter.resume(); } + return Promise.resolve({ value, done: false }); + } + if (error) { const reason = error; error = undefined; return Promise.reject(reason); } + if (done) return Promise.resolve({ value: undefined, done: true }); + return new Promise((resolve, reject) => waiters.push({ resolve, reject })); + }, + return() { finish(); return Promise.resolve({ value: undefined, done: true }); }, + throw(reason) { if (!(reason instanceof Error)) throw new TypeError('The "error" argument must be an Error.'); finish(reason); return Promise.resolve({ value: undefined, done: true }); }, + [Symbol.asyncIterator]() { return this; }, + }; +} +function addAbortListener(signal, listener) { + validateSignal(signal); + if (!signal) throw new TypeError('The "signal" argument must be an AbortSignal.'); + if (typeof listener !== 'function') throw new TypeError('The "listener" argument must be a function.'); + let dispose; + if (signal.aborted) queueMicrotask(() => listener()); + else dispose = listen(signal, 'abort', listener, true); + return { [Symbol.dispose]() { dispose?.(); dispose = undefined; } }; +} +EventEmitter.EventEmitter = EventEmitter; +EventEmitter.captureRejectionSymbol = rejection; +EventEmitter.errorMonitor = errorMonitor; +EventEmitter.once = once; +EventEmitter.on = on; +EventEmitter.addAbortListener = addAbortListener; +EventEmitter.getEventListeners = (emitter, name) => { + if (typeof emitter.listeners === 'function') return emitter.listeners(name); + if (typeof globalThis.__phasisNodeHost?.eventListeners === 'function') return globalThis.__phasisNodeHost.eventListeners(emitter, name); + throw new TypeError('EventTarget listener inspection requires the host listener adapter.'); +}; +EventEmitter.getMaxListeners = (emitter) => typeof emitter.getMaxListeners === 'function' ? emitter.getMaxListeners() : targetLimits.get(emitter) ?? EventEmitter.defaultMaxListeners; +EventEmitter.setMaxListeners = (count, ...targets) => { + if (typeof count !== 'number' || count < 0 || Number.isNaN(count)) throw new RangeError('The "n" argument is out of range.'); + if (!targets.length) EventEmitter.defaultMaxListeners = count; + for (const target of targets) { + if (typeof target.setMaxListeners === 'function') target.setMaxListeners(count); + else if (typeof target.addEventListener === 'function') targetLimits.set(target, count); + else throw new TypeError('The target must be an EventEmitter or EventTarget.'); + } +}; +class EventEmitterAsyncResource extends EventEmitter { + constructor(options = {}) { + if (typeof options === 'string') options = { name: options }; + super(options); + const { AsyncResource } = require('async_hooks'); + this.asyncResource = new AsyncResource(options.name || new.target.name, options); + } + emit(name, ...args) { return this.asyncResource.runInAsyncScope(super.emit, this, name, ...args); } + emitDestroy() { this.asyncResource.emitDestroy(); } + get asyncId() { return this.asyncResource.asyncId(); } + get triggerAsyncId() { return this.asyncResource.triggerAsyncId(); } +} +EventEmitter.EventEmitterAsyncResource = EventEmitterAsyncResource; +module.exports = EventEmitter; diff --git a/scripts/node-primitives/generate-oracles.mjs b/scripts/node-primitives/generate-oracles.mjs new file mode 100644 index 00000000..ffdb3855 --- /dev/null +++ b/scripts/node-primitives/generate-oracles.mjs @@ -0,0 +1,18 @@ +import { execFileSync } from 'node:child_process'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { writeFile } from 'node:fs/promises'; +import * as zlib from 'node:zlib'; + +const directory = resolve(dirname(fileURLToPath(import.meta.url)), '../../tests/Unit/Node/fixtures/primitives'); +const compressionInput = Buffer.from('hello 🌍\0 binary\xff hello hello'); +const compressed = {}; +for (const name of ['gzip', 'deflate', 'deflateRaw', 'brotliCompress']) compressed[name] = zlib[name + 'Sync'](compressionInput).toString('base64'); +await writeFile(resolve(directory, 'zlib-inputs.json'), `${JSON.stringify(compressed, null, 2)}\n`); +for (const name of ['buffer', 'events', 'stream', 'stream-web', 'fs', 'zlib', 'vm', 'child-process']) { + const output = execFileSync(process.execPath, [resolve(directory, `${name}.cjs`)], { encoding: 'utf8', timeout: 15000 }); + const value = JSON.parse(output.trim()); + await writeFile(resolve(directory, `${name}.json`), `${JSON.stringify(value, null, 2)}\n`); + await writeFile(resolve(directory, `${name}.mjs`), `import './${name}.cjs';\n`); + console.log(`${name}: ${value.length} oracle observations`); +} diff --git a/scripts/node-primitives/package-lock.json b/scripts/node-primitives/package-lock.json new file mode 100644 index 00000000..5891971d --- /dev/null +++ b/scripts/node-primitives/package-lock.json @@ -0,0 +1,661 @@ +{ + "name": "phasis-node-primitives-build", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "phasis-node-primitives-build", + "dependencies": { + "brotli": "1.3.3", + "buffer": "6.0.3", + "events": "3.3.0", + "readable-stream": "4.8.0", + "string_decoder": "1.3.0" + }, + "devDependencies": { + "esbuild": "0.28.2" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/readable-stream": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.8.0.tgz", + "integrity": "sha512-2jhTTU3Eilp/2DMT71gbcoqC35eQHasMJH0RHkYxwlxIv3+FR6Y5xAFZIwEGLxKkjZYEFlsiMNIdwUqjK2lLHQ==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + } + } +} diff --git a/scripts/node-primitives/package.json b/scripts/node-primitives/package.json new file mode 100644 index 00000000..3032ba56 --- /dev/null +++ b/scripts/node-primitives/package.json @@ -0,0 +1,18 @@ +{ + "name": "phasis-node-primitives-build", + "private": true, + "type": "module", + "scripts": { + "build": "node build.mjs" + }, + "dependencies": { + "brotli": "1.3.3", + "buffer": "6.0.3", + "events": "3.3.0", + "readable-stream": "4.8.0", + "string_decoder": "1.3.0" + }, + "devDependencies": { + "esbuild": "0.28.2" + } +} diff --git a/scripts/node-primitives/stream-consumers-entry.cjs b/scripts/node-primitives/stream-consumers-entry.cjs new file mode 100644 index 00000000..7ccc1d5c --- /dev/null +++ b/scripts/node-primitives/stream-consumers-entry.cjs @@ -0,0 +1,17 @@ +'use strict'; +const { Buffer } = require('buffer'); +async function blob(stream) { + const chunks = []; + for await (const chunk of stream) chunks.push(chunk); + return new Blob(chunks); +} +async function arrayBuffer(stream) { return (await blob(stream)).arrayBuffer(); } +async function buffer(stream) { return Buffer.from(await arrayBuffer(stream)); } +async function text(stream) { + const decoder = new TextDecoder(); + let output = ''; + for await (const chunk of stream) output += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true }); + return output + decoder.decode(); +} +async function json(stream) { return JSON.parse(await text(stream)); } +module.exports = { arrayBuffer, blob, buffer, json, text }; diff --git a/scripts/node-primitives/stream-entry.cjs b/scripts/node-primitives/stream-entry.cjs new file mode 100644 index 00000000..09d14f7a --- /dev/null +++ b/scripts/node-primitives/stream-entry.cjs @@ -0,0 +1,133 @@ +'use strict'; +const Stream = require('./node_modules/readable-stream/lib/stream.js'); +const process = require('process'); +const { Buffer } = require('buffer'); +Stream.setDefaultHighWaterMark(false, process.platform === 'win32' ? 16384 : 65536); + +function invalidStream(name) { return new TypeError(`The "${name}" argument must be a stream.`); } +Stream.Readable.fromWeb = function (web, options = {}) { + if (!web || typeof web.getReader !== 'function') throw invalidStream('readableStream'); + const reader = web.getReader(); + let pending = false; + let ended = false; + let released = false; + // Node's adapter owns the reader lock even after reaching EOF. + const release = () => { released = true; }; + const readable = new Stream.Readable({ + ...options, + read() { + if (pending || ended) return; + pending = true; + reader.read().then(({ value, done }) => { + pending = false; + if (done) { ended = true; release(); this.push(null); } + else this.push(value); + }, (error) => { pending = false; this.destroy(error); }); + }, + destroy(error, callback) { + if (ended || released) { callback(error); return; } + ended = true; + Promise.resolve(reader.cancel(error)).then(() => { release(); callback(error); }, (reason) => { release(); callback(reason || error); }); + }, + }); + return readable; +}; +Stream.Readable.toWeb = function (readable, options = {}) { + if (!readable || typeof readable.on !== 'function' || typeof readable.pause !== 'function') throw invalidStream('streamReadable'); + let controller; + let ended = false; + function cleanup() { + readable.removeListener('data', data); + readable.removeListener('end', end); + readable.removeListener('error', error); + readable.removeListener('close', close); + } + function data(chunk) { + if (ended) return; + controller.enqueue(Buffer.isBuffer(chunk) ? new Uint8Array(chunk) : chunk); + if (controller.desiredSize <= 0) readable.pause(); + } + function end() { if (ended) return; ended = true; cleanup(); controller.close(); } + function error(reason) { if (ended) return; ended = true; cleanup(); controller.error(reason); } + function close() { + if (ended) return; + if (readable.readableEnded) end(); + else { const reason = new Error('Premature close'); reason.code = 'ERR_STREAM_PREMATURE_CLOSE'; error(reason); } + } + return new ReadableStream({ + start(value) { + controller = value; + readable.on('data', data); + readable.on('end', end); + readable.on('error', error); + readable.on('close', close); + readable.pause(); + if (readable.readableEnded) end(); + else if (readable.destroyed) close(); + }, + pull() { if (!ended) readable.resume(); }, + cancel(reason) { + ended = true; + cleanup(); + readable.once('error', () => {}); + readable.destroy(reason); + }, + }, { highWaterMark: readable.readableHighWaterMark, ...options.strategy }); +}; +Stream.Writable.fromWeb = function (web, options = {}) { + if (!web || typeof web.getWriter !== 'function') throw invalidStream('writableStream'); + const writer = web.getWriter(); + let ended = false; + let released = false; + // Node retains the writer lock for the lifetime of this adapter. + const release = () => { released = true; }; + return new Stream.Writable({ + ...options, + write(chunk, encoding, callback) { Promise.resolve(writer.write(chunk)).then(() => callback(), callback); }, + final(callback) { + Promise.resolve(writer.close()).then(() => { ended = true; release(); callback(); }, callback); + }, + destroy(error, callback) { + if (ended || released) { callback(error); return; } + ended = true; + Promise.resolve(writer.abort(error)).then(() => { release(); callback(error); }, (reason) => { release(); callback(reason || error); }); + }, + }); +}; +Stream.Writable.toWeb = function (writable) { + if (!writable || typeof writable.write !== 'function' || typeof writable.on !== 'function') throw invalidStream('streamWritable'); + let controller; + let rejectPending; + let ended = false; + function error(reason) { if (!ended) controller.error(reason); rejectPending?.(reason); rejectPending = undefined; } + function cleanup() { writable.removeListener('error', error); } + return new WritableStream({ + start(value) { controller = value; writable.on('error', error); if (writable.errored) error(writable.errored); }, + write(chunk) { + return new Promise((resolve, reject) => { + rejectPending = reject; + writable.write(chunk, (reason) => { rejectPending = undefined; reason ? reject(reason) : resolve(); }); + }); + }, + close() { + return new Promise((resolve, reject) => { + rejectPending = reject; + writable.end((reason) => { ended = true; rejectPending = undefined; cleanup(); reason ? reject(reason) : resolve(); }); + }); + }, + abort(reason) { + ended = true; + cleanup(); + writable.once('error', () => {}); + writable.destroy(reason); + }, + }, { highWaterMark: writable.writableHighWaterMark }); +}; +Stream.Duplex.fromWeb = function (pair, options = {}) { + if (!pair || !pair.readable || !pair.writable) throw invalidStream('pair'); + return Stream.Duplex.from({ readable: Stream.Readable.fromWeb(pair.readable, options), writable: Stream.Writable.fromWeb(pair.writable, options) }); +}; +Stream.Duplex.toWeb = function (duplex) { + return { readable: Stream.Readable.toWeb(duplex), writable: Stream.Writable.toWeb(duplex) }; +}; +module.exports = Stream; diff --git a/scripts/node-primitives/stream-promises-entry.cjs b/scripts/node-primitives/stream-promises-entry.cjs new file mode 100644 index 00000000..9d4abe90 --- /dev/null +++ b/scripts/node-primitives/stream-promises-entry.cjs @@ -0,0 +1,2 @@ +'use strict'; +module.exports = require('stream').promises; diff --git a/scripts/node-primitives/stream-web-entry.cjs b/scripts/node-primitives/stream-web-entry.cjs new file mode 100644 index 00000000..4541c759 --- /dev/null +++ b/scripts/node-primitives/stream-web-entry.cjs @@ -0,0 +1,55 @@ +'use strict'; +class TextEncoderStream { + #stream; + constructor() { + const encoder = new TextEncoder(); + let pending = ''; + this.#stream = new TransformStream({ + transform(value, controller) { + let text = pending + `${value}`; + pending = ''; + if (text.length && text.charCodeAt(text.length - 1) >= 0xd800 && text.charCodeAt(text.length - 1) <= 0xdbff) { + pending = text.slice(-1); + text = text.slice(0, -1); + } + if (text.length) controller.enqueue(encoder.encode(text)); + }, + flush(controller) { if (pending) controller.enqueue(encoder.encode(pending)); }, + }); + } + get encoding() { return 'utf-8'; } + get readable() { return this.#stream.readable; } + get writable() { return this.#stream.writable; } + get [Symbol.toStringTag]() { return 'TextEncoderStream'; } +} +class TextDecoderStream { + #stream; + #decoder; + constructor(label = 'utf-8', options = {}) { + this.#decoder = new TextDecoder(label, options); + const decoder = this.#decoder; + this.#stream = new TransformStream({ + transform(value, controller) { + const text = decoder.decode(value, { stream: true }); + if (text.length) controller.enqueue(text); + }, + flush(controller) { + const text = decoder.decode(); + if (text.length) controller.enqueue(text); + }, + }); + } + get encoding() { return this.#decoder.encoding; } + get fatal() { return this.#decoder.fatal; } + get ignoreBOM() { return this.#decoder.ignoreBOM; } + get readable() { return this.#stream.readable; } + get writable() { return this.#stream.writable; } + get [Symbol.toStringTag]() { return 'TextDecoderStream'; } +} +module.exports = { + ReadableStream, ReadableStreamDefaultReader, ReadableStreamBYOBReader, + ReadableStreamDefaultController, ReadableByteStreamController, ReadableStreamBYOBRequest, + WritableStream, WritableStreamDefaultWriter, WritableStreamDefaultController, + TransformStream, TransformStreamDefaultController, ByteLengthQueuingStrategy, CountQueuingStrategy, + TextEncoderStream, TextDecoderStream, CompressionStream, DecompressionStream, +}; diff --git a/scripts/node-primitives/string_decoder-entry.cjs b/scripts/node-primitives/string_decoder-entry.cjs new file mode 100644 index 00000000..b73c2a0e --- /dev/null +++ b/scripts/node-primitives/string_decoder-entry.cjs @@ -0,0 +1,2 @@ +'use strict'; +module.exports = require('./node_modules/string_decoder/lib/string_decoder.js'); diff --git a/src/BuiltIn/AbortControllerConstructor.php b/src/BuiltIn/AbortControllerConstructor.php index fc400287..58635539 100644 --- a/src/BuiltIn/AbortControllerConstructor.php +++ b/src/BuiltIn/AbortControllerConstructor.php @@ -85,12 +85,8 @@ class AbortControllerConstructor public const SLOT_IS_CONTROLLER = '[[IsAbortController]]'; public const SLOT_LINKED_SIGNAL = '[[LinkedSignal]]'; - private static ?Environment $env = null; - public static function install(Environment $env): void { - self::$env = $env; - // Locate EventTarget.prototype for the prototype-chain wire-in. // EventTargetConstructor::install() runs before us in Engine.php, // but be defensive against rearrangement. @@ -106,6 +102,9 @@ public static function install(Environment $env): void } $signalProto = self::buildSignalPrototype($eventTargetProto); + $env->get('DOMException'); + $signalProto->setInternalProperty('[[AbortEventConstructor]]', $env->getIntrinsic('Event')); + $signalProto->setInternalProperty('[[AbortExceptionConstructor]]', $env->getIntrinsic('DOMException')); $signalCtor = self::buildSignalConstructor($signalProto, $eventTargetProto); $controllerCtor = self::buildControllerConstructor($signalProto); @@ -372,7 +371,7 @@ static function (JsValue $this_): JsValue { if ($self->getInternalProperty(self::SLOT_ABORTED) === true) { $reason = $self->getInternalProperty(self::SLOT_REASON); if (!$reason instanceof JsValue) { - $reason = self::defaultAbortReason(); + $reason = self::defaultAbortReason($self); } // Throw the JS value directly. Phasis's exception // bridge will surface this as a JS-level throw. @@ -506,6 +505,8 @@ private static function makeSignal(JsObject $proto): JsObject $signal->setInternalProperty(self::SLOT_SOURCES, []); $signal->setInternalProperty(self::SLOT_DEPENDENTS, []); $signal->setInternalProperty(self::SLOT_TIMEOUT_DEADLINE, null); + $signal->setInternalProperty('[[AbortEventConstructor]]', $proto->getInternalProperty('[[AbortEventConstructor]]')); + $signal->setInternalProperty('[[AbortExceptionConstructor]]', $proto->getInternalProperty('[[AbortExceptionConstructor]]')); // Brand as EventTarget so inherited addEventListener/dispatchEvent // accept this receiver. EventTargetConstructor::brandAsEventTarget // initialises [[EventListeners]] alongside the brand. @@ -527,7 +528,7 @@ private static function signalAbort(JsObject $signal, JsValue $reason): void return; } if ($reason instanceof JsUndefined) { - $reason = self::defaultAbortReason(); + $reason = self::defaultAbortReason($signal); } $signal->setInternalProperty(self::SLOT_ABORTED, true); $signal->setInternalProperty(self::SLOT_REASON, $reason); @@ -547,11 +548,7 @@ private static function signalAbort(JsObject $signal, JsValue $reason): void $algo(); } - // Build and dispatch an abort event. We call the engine's Event - // constructor through the env so subclassing / Event.prototype - // mutations are respected, with a fallback to a hand-built event - // object if Event is somehow not installed yet. - $event = self::buildAbortEvent(); + $event = self::buildAbortEvent($signal); // Per spec the user-agent-fired abort event is a trusted event. $event->setInternalProperty('[[IsTrusted]]', true); $dispatch = $signal->get('dispatchEvent'); @@ -568,21 +565,15 @@ private static function signalAbort(JsObject $signal, JsValue $reason): void } /** - * Construct an Event("abort") via the public Event constructor so - * subclass / prototype mutations are honoured. Falls back to a - * synthetic event object branded with [[IsEvent]] for environments - * where Event somehow is not yet installed. + * Construct the abort event using the signal's realm-owned intrinsic. */ - private static function buildAbortEvent(): JsObject + private static function buildAbortEvent(JsObject $signal): JsObject { - $env = self::$env; - if ($env !== null && $env->has('Event')) { - $eventCtor = $env->get('Event'); - if ($eventCtor instanceof JsFunction) { - $result = $eventCtor->construct([new JsString('abort')]); - if ($result instanceof JsObject) { - return $result; - } + $eventCtor = $signal->getInternalProperty('[[AbortEventConstructor]]'); + if ($eventCtor instanceof JsFunction) { + $result = $eventCtor->construct([new JsString('abort')]); + if ($result instanceof JsObject) { + return $result; } } // Fallback: synthetic event with the slots dispatchEvent needs. @@ -621,6 +612,7 @@ private static function tripTimeoutIfDue(JsObject $signal): void return; } $reason = self::makeDomException( + $signal, 'signal timed out', 'TimeoutError', ); @@ -667,19 +659,23 @@ private static function signalReason(JsObject $signal): JsValue * plain Error-shaped object so reads of `.name` / `.message` still * give useful output. */ - private static function defaultAbortReason(): JsObject + private static function defaultAbortReason(JsObject $signal): JsObject { return self::makeDomException( + $signal, 'signal is aborted without reason', 'AbortError', ); } - private static function makeDomException(string $message, string $name): JsObject + private static function makeDomException(JsObject $signal, string $message, string $name): JsObject { - $env = self::$env; - if ($env !== null) { - return DomExceptionConstructor::create($env, $message, $name); + $constructor = $signal->getInternalProperty('[[AbortExceptionConstructor]]'); + if ($constructor instanceof JsFunction) { + $exception = $constructor->construct([new JsString($message), new JsString($name)]); + if ($exception instanceof JsObject) { + return $exception; + } } // Last-ditch fallback shape — should never run in practice. $obj = new JsObject(); diff --git a/src/BuiltIn/CryptoKeyConstructor.php b/src/BuiltIn/CryptoKeyConstructor.php new file mode 100644 index 00000000..a56f11e9 --- /dev/null +++ b/src/BuiltIn/CryptoKeyConstructor.php @@ -0,0 +1,47 @@ +setConstructable(); + $constructor->defineOwnProperty('prototype', PropertyDescriptor::data($prototype, false, false, false)); + $prototype->defineOwnProperty('constructor', PropertyDescriptor::data($constructor, true, false, true)); + $prototype->definePropertyBySymbol( + SymbolConstructor::toStringTag(), + PropertyDescriptor::data(new JsString('CryptoKey'), false, false, true), + ); + $environment->defineVar('CryptoKey', $constructor); + } + + /** Return the prototype belonging to the active realm. */ + public static function prototype(): ?JsObject + { + $environment = Engine::getCurrentRealm()?->getGlobalEnv(); + if ($environment === null || !$environment->has('CryptoKey')) { + return null; + } + $constructor = $environment->get('CryptoKey'); + $prototype = $constructor instanceof JsObject ? $constructor->get('prototype') : null; + return $prototype instanceof JsObject ? $prototype : null; + } +} diff --git a/src/BuiltIn/CryptoObject.php b/src/BuiltIn/CryptoObject.php index af54b2af..76a5e0e7 100644 --- a/src/BuiltIn/CryptoObject.php +++ b/src/BuiltIn/CryptoObject.php @@ -38,6 +38,7 @@ final class CryptoObject public static function install(Environment $env): void { + CryptoKeyConstructor::install($env); $crypto = new JsObject(); $crypto->defineOwnProperty( diff --git a/src/BuiltIn/DomExceptionConstructor.php b/src/BuiltIn/DomExceptionConstructor.php index 01de493a..68438b14 100644 --- a/src/BuiltIn/DomExceptionConstructor.php +++ b/src/BuiltIn/DomExceptionConstructor.php @@ -107,6 +107,7 @@ public static function install(Environment $env): void 2, ); $constructor->setConstructable(); + $env->setIntrinsic('DOMException', $constructor); // Wire prototype <-> constructor. $proto->defineOwnProperty( diff --git a/src/BuiltIn/Ed25519Crypto.php b/src/BuiltIn/Ed25519Crypto.php new file mode 100644 index 00000000..55a63a21 --- /dev/null +++ b/src/BuiltIn/Ed25519Crypto.php @@ -0,0 +1,193 @@ + $usages */ + public static function validateUsages(array $usages, string $type, bool $generated = false): void + { + $allowed = $generated ? ['sign', 'verify'] : ($type === 'private' ? ['sign'] : ['verify']); + foreach ($usages as $usage) { + if (!in_array($usage, $allowed, true)) { + self::error('SyntaxError', 'Unsupported key usage for an Ed25519 key.'); + } + } + if (($type === 'private' || $generated) && !in_array('sign', $usages, true)) { + self::error('SyntaxError', 'Usages cannot be empty when creating a private key.'); + } + } + + /** + * @param list $usages + * @return array{type: 'public'|'private', material: string} + */ + public static function import(string $format, string|JsObject $data, bool $extractable, array $usages): array + { + self::available(); + $type = 'public'; + if ($format === 'jwk' && $data instanceof JsObject) { + if ($data->get('kty')->toJsString() !== 'OKP' || $data->get('crv')->toJsString() !== 'Ed25519') { + self::error('DataError', 'Invalid Ed25519 JWK key type or curve.'); + } + $public = self::decode($data->get('x')->toJsString()); + $material = $public; + if (!$data->get('d') instanceof JsUndefined) { + $material = self::decode($data->get('d')->toJsString()); + $type = 'private'; + if (strlen($material) !== 32 || strlen($public) !== 32 || !hash_equals(self::publicKey($material), $public)) { + self::error('DataError', 'Invalid Ed25519 private key material.'); + } + } + if ($extractable && !$data->get('ext') instanceof JsUndefined && !$data->get('ext')->toBoolean()) { + self::error('DataError', 'JWK ext does not permit extraction.'); + } + if (!$data->get('use') instanceof JsUndefined && $usages !== [] && $data->get('use')->toJsString() !== 'sig') { + self::error('DataError', 'Invalid JWK use parameter.'); + } + if (!$data->get('alg') instanceof JsUndefined && $data->get('alg')->toJsString() !== 'EdDSA') { + self::error('DataError', 'Invalid JWK alg parameter.'); + } + $operations = $data->get('key_ops'); + if (!$operations instanceof JsUndefined) { + if (!$operations instanceof JsObject) { + self::error('DataError', 'JWK key_ops must be a sequence.'); + } + $allowed = []; + for ($i = 0, $length = (int) $operations->get('length')->toNumber(); $i < $length; $i++) { + $allowed[] = $operations->get((string) $i)->toJsString(); + } + if (count(array_unique($allowed)) !== count($allowed) || array_diff($usages, $allowed) !== []) { + self::error('DataError', 'JWK key_ops does not permit the requested usages.'); + } + } + } elseif (is_string($data)) { + $material = $data; + if ($format === 'spki') { + if (strlen($data) !== strlen(self::SPKI_PREFIX) + 32 || !str_starts_with($data, self::SPKI_PREFIX)) { + self::error('DataError', 'Invalid Ed25519 SubjectPublicKeyInfo.'); + } + $material = substr($data, strlen(self::SPKI_PREFIX)); + } elseif ($format === 'pkcs8') { + if (strlen($data) !== strlen(self::PKCS8_PREFIX) + 32 || !str_starts_with($data, self::PKCS8_PREFIX)) { + self::error('DataError', 'Invalid Ed25519 PrivateKeyInfo.'); + } + $material = substr($data, strlen(self::PKCS8_PREFIX)); + $type = 'private'; + } elseif ($format !== 'raw') { + self::error('NotSupportedError', 'Unsupported Ed25519 key format.'); + } + } else { + throw new TypeError('Invalid Ed25519 key data.'); + } + if (strlen($material) !== 32) { + self::error('DataError', 'Ed25519 keys must contain exactly 32 bytes.'); + } + self::validateUsages($usages, $type); + return ['type' => $type, 'material' => $material]; + } + + /** @param list $usages */ + public static function export(string $format, string $type, string $material, array $usages): string|JsValue + { + if ($format === 'raw' && $type === 'public') { + return $material; + } + if ($format === 'spki' && $type === 'public') { + return self::SPKI_PREFIX . $material; + } + if ($format === 'pkcs8' && $type === 'private') { + return self::PKCS8_PREFIX . $material; + } + if ($format === 'jwk') { + $jwk = [ + 'key_ops' => $usages, + 'ext' => true, + 'crv' => 'Ed25519', + 'x' => self::encode($type === 'private' ? self::publicKey($material) : $material), + ]; + if ($type === 'private') { + $jwk['d'] = self::encode($material); + } + $jwk['kty'] = 'OKP'; + $jwk['alg'] = 'EdDSA'; + return PhpToJs::convert($jwk); + } + self::error('InvalidAccessError', 'The requested format is not valid for this Ed25519 key type.'); + } + + /** Sign a message with a 32-byte Ed25519 private seed. */ + public static function sign(string $seed, string $message): string + { + self::available(); + return sodium_crypto_sign_detached($message, sodium_crypto_sign_secretkey(sodium_crypto_sign_seed_keypair($seed))); + } + + /** Verify a detached Ed25519 signature. */ + public static function verify(string $public, string $signature, string $message): bool + { + self::available(); + return strlen($signature) === 64 && sodium_crypto_sign_verify_detached($signature, $message, $public); + } + + /** Raise a WebCrypto DOMException without converting its rejection type. */ + public static function error(string $name, string $message): never + { + $environment = Engine::getCurrentRealm()?->getGlobalEnv(); + if ($environment === null) { + throw new TypeError($message); + } + throw new JsThrowable(DomExceptionConstructor::create($environment, $message, $name)); + } + + private static function publicKey(string $seed): string + { + return sodium_crypto_sign_publickey(sodium_crypto_sign_seed_keypair($seed)); + } + + private static function encode(string $bytes): string + { + return rtrim(strtr(base64_encode($bytes), '+/', '-_'), '='); + } + + private static function decode(string $value): string + { + if (preg_match('/^[A-Za-z0-9_-]*={0,2}$/D', $value) !== 1) { + self::error('DataError', 'Invalid base64url key material.'); + } + $decoded = base64_decode(strtr($value, '-_', '+/'), true); + if ($decoded === false) { + self::error('DataError', 'Invalid base64url key material.'); + } + return $decoded; + } + + private static function available(): void + { + if (!function_exists('sodium_crypto_sign_seed_keypair')) { + self::error('NotSupportedError', 'Ed25519 requires the PHP sodium extension.'); + } + } +} diff --git a/src/BuiltIn/EventTargetConstructor.php b/src/BuiltIn/EventTargetConstructor.php index 55b27508..efb0a521 100644 --- a/src/BuiltIn/EventTargetConstructor.php +++ b/src/BuiltIn/EventTargetConstructor.php @@ -9,6 +9,7 @@ use Phasis\Runtime\Environment; use Phasis\Spec\TypeConversion; use Phasis\Value\JsBoolean; +use Phasis\Value\JsArray; use Phasis\Value\JsFunction; use Phasis\Value\JsNull; use Phasis\Value\JsNumber; @@ -105,12 +106,15 @@ public static function install(Environment $env): void $eventProto = self::createEventPrototype(); $eventCtor = self::createEventConstructor($eventProto); $env->defineVar('Event', $eventCtor); + $env->setIntrinsic('Event', $eventCtor); // CustomEvent extends Event and adds a `detail` accessor + init. $customProto = self::createCustomEventPrototype($eventProto); $customCtor = self::createCustomEventConstructor($customProto, $eventCtor); $env->defineVar('CustomEvent', $customCtor); + $env->defineVar('MessageEvent', self::createMessageEventConstructor($eventProto, $eventCtor)); + $targetProto = self::createEventTargetPrototype(); $targetCtor = self::createEventTargetConstructor($targetProto); $env->defineVar('EventTarget', $targetCtor); @@ -171,6 +175,122 @@ static function (JsValue $_this, array $args) use ($backing, $methodName): JsVal // CustomEvent // ------------------------------------------------------------------ + private static function createMessageEventConstructor(JsObject $eventProto, JsFunction $eventCtor): JsFunction + { + $proto = new JsObject($eventProto); + foreach (['data', 'origin', 'lastEventId', 'source', 'ports'] as $name) { + $getter = JsFunction::fromCallable('get ' . $name, static function (JsValue $value) use ($name): JsValue { + if (!$value instanceof JsObject || $value->getInternalProperty('[[IsMessageEvent]]') !== true) { + throw new TypeError('MessageEvent getter called on an incompatible receiver'); + } + $stored = $value->getInternalProperty('[[MessageEvent:' . $name . ']]'); + return $stored instanceof JsValue ? $stored : JsNull::instance(); + }); + $getter->setNonConstructable(); + $proto->defineOwnProperty($name, PropertyDescriptor::accessor($getter, null, true, true)); + } + $proto->definePropertyBySymbol( + SymbolConstructor::toStringTag(), + PropertyDescriptor::data(new JsString('MessageEvent'), false, false, true), + ); + $ctor = JsFunction::fromCallable('MessageEvent', static function (JsValue $this_, array $args) use ($proto): JsValue { + if (!$this_ instanceof JsObject || !$this_->has('[[NewTarget]]')) { + throw new TypeError("Constructor MessageEvent requires 'new'"); + } + if (!isset($args[0])) { + throw new TypeError('MessageEvent requires an event type'); + } + $newTarget = $this_->get('[[NewTarget]]'); + $newProto = $newTarget instanceof JsObject ? $newTarget->get('prototype') : null; + $this_->setPrototype($newProto instanceof JsObject ? $newProto : $proto); + $type = TypeConversion::toString($args[0]); + $init = $args[1] ?? JsUndefined::instance(); + if (!$init instanceof JsObject && !$init instanceof JsNull && !$init instanceof JsUndefined) { + throw new TypeError('MessageEvent options must be a dictionary'); + } + $get = static fn (string $name): JsValue => $init instanceof JsObject + ? $init->get($name) + : JsUndefined::instance(); + $bubbles = TypeConversion::toBoolean($get('bubbles')); + $cancelable = TypeConversion::toBoolean($get('cancelable')); + $composed = TypeConversion::toBoolean($get('composed')); + $data = $get('data'); + if ($data instanceof JsUndefined) { + $data = JsNull::instance(); + } + $lastEventId = $get('lastEventId'); + $lastEventId = new JsString($lastEventId instanceof JsUndefined ? '' : TypeConversion::toString($lastEventId)); + $origin = $get('origin'); + $origin = new JsString($origin instanceof JsUndefined ? '' : TypeConversion::toString($origin)); + $portValues = $get('ports'); + $ports = []; + if (!$portValues instanceof JsUndefined) { + if (!$portValues instanceof JsObject) { + throw new TypeError('MessageEvent ports must be a sequence of MessagePort values'); + } + $iteratorMethod = $portValues->getBySymbol(SymbolConstructor::iterator()); + if (!$iteratorMethod instanceof JsFunction) { + throw new TypeError('MessageEvent ports must be iterable'); + } + $iterator = $iteratorMethod->call($portValues, []); + $next = $iterator instanceof JsObject ? $iterator->get('next') : null; + if (!$next instanceof JsFunction) { + throw new TypeError('Invalid MessageEvent ports iterator'); + } + while (true) { + $step = $next->call($iterator, []); + if (!$step instanceof JsObject) { + throw new TypeError('Invalid MessageEvent ports iterator result'); + } + if (TypeConversion::toBoolean($step->get('done'))) { + break; + } + $port = $step->get('value'); + if (!$port instanceof JsObject || $port->getInternalProperty('[[IsMessagePort]]') !== true) { + throw new TypeError('MessageEvent ports must contain MessagePort values'); + } + $ports[] = $port; + } + } + $source = $get('source'); + if ($source instanceof JsUndefined) { + $source = JsNull::instance(); + } + if ( + !$source instanceof JsNull + && !($source instanceof JsObject && $source->getInternalProperty('[[IsMessagePort]]') === true) + ) { + throw new TypeError('MessageEvent source must be a MessagePort or null'); + } + $portsArray = JsArray::fromArray($ports); + foreach ($portsArray->ordinaryOwnPropertyKeys() as $keyValue) { + if (!$keyValue instanceof JsString) { + continue; + } + $key = $keyValue->value; + $descriptor = $portsArray->getOwnPropertyDescriptor($key); + if ($descriptor !== null) { + $descriptor->configurable = false; + $descriptor->writable = false; + $portsArray->defineOwnProperty($key, $descriptor); + } + } + $portsArray->preventExtensions(); + self::initEventSlots($this_, $type, $bubbles, $cancelable, $composed); + $this_->setInternalProperty('[[IsMessageEvent]]', true); + $fields = ['data' => $data, 'origin' => $origin, 'lastEventId' => $lastEventId, 'source' => $source, 'ports' => $portsArray]; + foreach ($fields as $name => $value) { + $this_->setInternalProperty('[[MessageEvent:' . $name . ']]', $value); + } + return $this_; + }, 1); + $ctor->setConstructable(); + $ctor->setPrototype($eventCtor); + $ctor->defineOwnProperty('prototype', PropertyDescriptor::data($proto, false, false, false)); + $proto->defineOwnProperty('constructor', PropertyDescriptor::data($ctor, true, false, true)); + return $ctor; + } + private static function createCustomEventPrototype(JsObject $eventProto): JsObject { $proto = new JsObject($eventProto); diff --git a/src/BuiltIn/Fetch/BodyExtraction.php b/src/BuiltIn/Fetch/BodyExtraction.php index b45bea4e..93a36f30 100644 --- a/src/BuiltIn/Fetch/BodyExtraction.php +++ b/src/BuiltIn/Fetch/BodyExtraction.php @@ -32,12 +32,8 @@ * default and length, then populates the supplied Headers object's * `Content-Type` header if it is not already set. * - * Phasis buffers all bodies up front. The `stream` returned by the spec's - * extract-body algorithm is materialized on demand from the buffered - * bytes by `BodyMixin::installBodyMixin()` (via - * `StreamHelpers::createReadableStreamFromBytes`). Carrying the raw - * bytes through the value type avoids re-encoding round trips on every - * body method call and lets `clone()` be a cheap reference copy. + * Byte-backed sources retain their bytes until a stream is needed. + * ReadableStream sources remain live and are consumed only by body readers. * * Supported body sources, in spec order: * - Blob / File → bytes, Content-Type defaults to blob.type @@ -46,13 +42,12 @@ * - FormData → multipart/form-data with a fresh boundary * - URLSearchParams → form-urlencoded, charset=UTF-8 * - String → UTF-8 bytes, text/plain;charset=UTF-8 - * - ReadableStream → consumed eagerly into bytes (Phasis-only - * limitation; spec keeps the stream live) + * - ReadableStream → retained as the associated body stream */ final class BodyExtraction { /** - * @return array{bytes:string,contentType:?string,length:?int,sourceKind:string} + * @return array{bytes:string,contentType:?string,length:?int,sourceKind:string,stream?:JsObject} */ public static function extractBody( JsValue $source, @@ -60,7 +55,7 @@ public static function extractBody( Environment $env, bool $keepalive = false, ): array { - unset($env, $keepalive); + unset($env); if ($source instanceof JsUndefined || $source instanceof JsNull) { throw new \LogicException('extractBody called with null/undefined source'); @@ -153,30 +148,25 @@ public static function extractBody( ]; } - // ----- ReadableStream --------------------------------------------- - // Phasis fully buffers bodies; we drain the stream synchronously - // by walking its default-controller queue. Streams that have not - // already enqueued all of their chunks are consumed lazily in - // text()/json()/etc. — but for extract-body we materialize what - // is currently available so Content-Length can be computed for - // the request descriptor that fetch() builds. + // The body retains its associated stream. Reading the current queue + // loses chunks produced asynchronously and bypasses backpressure. if (ReadableStream::isReadableStream($source)) { /** @var JsObject $source */ - if (ReadableStream::isReadableStreamLocked($source)) { - throw new TypeError('Failed to construct: body stream is locked'); + if ($keepalive) { + throw new TypeError('A streaming body cannot be used with keepalive'); + } + if ( + ReadableStream::isReadableStreamLocked($source) + || $source->getInternalProperty('[[Disturbed]]') === true + ) { + throw new TypeError('Failed to construct: body stream is locked or disturbed'); } - $chunks = self::snapshotStreamChunks($source); - $bytes = self::drainStream($source); return [ - 'bytes' => $bytes, + 'bytes' => '', 'contentType' => null, - 'length' => null, // streams have indeterminate length per spec + 'length' => null, 'sourceKind' => 'stream', - // Preserve the original JS-side chunks so the host's - // `body` stream can replay them with identity - // preserved (response.clone() then structured-clones - // them for the cloned half). - 'chunks' => $chunks, + 'stream' => $source, ]; } diff --git a/src/BuiltIn/Fetch/BodyMixin.php b/src/BuiltIn/Fetch/BodyMixin.php index bea11e94..9ebc91f4 100644 --- a/src/BuiltIn/Fetch/BodyMixin.php +++ b/src/BuiltIn/Fetch/BodyMixin.php @@ -22,6 +22,7 @@ use Phasis\Value\JsObject; use Phasis\Value\JsPromise; use Phasis\Value\JsString; +use Phasis\Value\JsTypedArray; use Phasis\Value\JsUndefined; use Phasis\Value\JsValue; @@ -40,11 +41,8 @@ * by the `body` getter on first read * - [[BodyContentType]] ?string — from extract-body; used by `blob()` * - * Spec deviation: Phasis fully buffers bodies. The `body` getter returns - * a real `ReadableStream` whose single chunk is the buffered bytes, - * created on first access and cached so subsequent `.body` reads return - * the same instance (matches the spec's "associated stream" requirement - * even though the underlying source differs). + * Byte-backed bodies materialize a stream on first access. Stream-backed + * bodies retain the original stream, and consumption awaits every chunk. */ final class BodyMixin { @@ -99,13 +97,15 @@ public static function markAsBodyHost( ?string $bytes, ?string $contentType, ?array $chunks = null, + ?JsObject $stream = null, ): void { $instance->setInternalProperty('[[HasBody]]', true); $instance->setInternalProperty('[[BodyBytes]]', $bytes); $instance->setInternalProperty('[[BodyChunks]]', $chunks); $instance->setInternalProperty('[[BodyUsed]]', false); - $instance->setInternalProperty('[[BodyStream]]', null); + $instance->setInternalProperty('[[BodyStream]]', $stream); $instance->setInternalProperty('[[BodyContentType]]', $contentType); + $instance->setInternalProperty('[[BodyReplayable]]', $stream === null); } /** Read the buffered body bytes; null when no body. */ @@ -242,12 +242,13 @@ static function (JsValue $this_, array $args): JsValue { if ($err !== null) { return $err; } - $bytes = self::consume($instance); - $ab = new JsArrayBuffer(strlen($bytes)); - if ($bytes !== '') { - $ab->writeBytes(0, $bytes); - } - return JsPromise::resolved($ab); + return self::consumeConverted($instance, static function (string $bytes): JsValue { + $ab = new JsArrayBuffer(strlen($bytes)); + if ($bytes !== '') { + $ab->writeBytes(0, $bytes); + } + return $ab; + }); }, 0, ); @@ -269,15 +270,11 @@ static function (JsValue $this_, array $args): JsValue { if ($err !== null) { return $err; } - $bytes = self::consume($instance); - // Per spec, blob.type comes from the LIVE Content-Type - // header on the body host — not the extract-time MIME. - // A caller that deletes the header before calling blob() - // expects an untyped blob, even when extraction set an - // implicit Content-Type. $ct = self::contentTypeFromHeaders($instance) ?? ''; - $blob = BlobConstructor::createBlob($bytes, $ct); - return JsPromise::resolved($blob); + return self::consumeConverted( + $instance, + static fn (string $bytes): JsValue => BlobConstructor::createBlob($bytes, $ct), + ); }, 0, ); @@ -299,8 +296,10 @@ static function (JsValue $this_, array $args): JsValue { if ($err !== null) { return $err; } - $bytes = self::consume($instance); - return JsPromise::resolved(TextEncoderConstructor::makeUint8Array($bytes)); + return self::consumeConverted( + $instance, + static fn (string $bytes): JsValue => TextEncoderConstructor::makeUint8Array($bytes), + ); }, 0, ); @@ -322,12 +321,10 @@ static function (JsValue $this_, array $args): JsValue { if ($err !== null) { return $err; } - $bytes = self::consume($instance); - // UTF-8 decoding with replacement-on-error per spec. PHP - // strings carry arbitrary bytes; for v1 we pass through - // since invalid sequences are rare in fetch responses - // and the TextDecoder fallback below covers JSON callers. - return JsPromise::resolved(new JsString($bytes)); + return self::consumeConverted( + $instance, + static fn (string $bytes): JsValue => new JsString($bytes), + ); }, 0, ); @@ -349,15 +346,15 @@ static function (JsValue $this_, array $args): JsValue { if ($err !== null) { return $err; } - $bytes = self::consume($instance); - try { - $parsed = \Phasis\BuiltIn\JsonObject::parseSource($bytes); - } catch (\Throwable $e) { - return JsPromise::rejected( - StreamHelpers::createTypeError('Failed to parse JSON: ' . $e->getMessage()) - ); - } - return JsPromise::resolved($parsed); + return self::consumeConverted($instance, static function (string $bytes): JsValue { + try { + return \Phasis\BuiltIn\JsonObject::parseSource($bytes); + } catch (\Throwable $e) { + return JsPromise::rejected( + StreamHelpers::createTypeError('Failed to parse JSON: ' . $e->getMessage()), + ); + } + }); }, 0, ); @@ -390,16 +387,15 @@ static function (JsValue $this_, array $args) use ($env): JsValue { StreamHelpers::createTypeError('Failed to parse FormData: no body') ); } - $bytes = self::consume($instance); - - try { - $fd = self::parseFormDataFromBytes($bytes, $ct, $env); - } catch (\Throwable $e) { - return JsPromise::rejected( - StreamHelpers::createTypeError('Failed to parse FormData: ' . $e->getMessage()) - ); - } - return JsPromise::resolved($fd); + return self::consumeConverted($instance, static function (string $bytes) use ($ct, $env): JsValue { + try { + return self::parseFormDataFromBytes($bytes, $ct, $env); + } catch (\Throwable $e) { + return JsPromise::rejected( + StreamHelpers::createTypeError('Failed to parse FormData: ' . $e->getMessage()), + ); + } + }); }, 0, ); @@ -462,20 +458,118 @@ private static function checkConsumable(JsObject $instance): ?JsPromise } /** - * Drain + mark used. Returns the body bytes (empty string when no body). - * - * Per spec, a Response/Request with a null body (no body stream) - * does NOT flip bodyUsed when consumed — there's nothing to - * drain. Only flip the bit when a real body is present. + * Consume the associated stream, preserving asynchronous production, + * backpressure and rejection. Resolves with its complete byte string. */ - private static function consume(JsObject $instance): string + public static function consumeBytes(JsObject $instance): JsPromise { - $bytes = self::bodyBytes($instance); - if ($bytes !== null) { - self::markUsed($instance); - return $bytes; + $error = self::checkConsumable($instance); + if ($error !== null) { + return $error; + } + $stream = self::getOrCreateBodyStream($instance); + if ($stream === null) { + return JsPromise::resolved(new JsString('')); + } + self::markUsed($instance); + $reader = ReadableStream::acquireDefaultReader($stream); + $result = new JsPromise(); + $bytes = ''; + $pump = null; + $pump = static function () use ($reader, $result, $instance, &$bytes, &$pump): void { + $read = ReadableStream::defaultReaderRead($reader); + $read->addFulfillHandler(static function (JsValue $value) use ($result, $instance, &$bytes, &$pump): void { + if (!$value instanceof JsObject) { + $result->reject(StreamHelpers::createTypeError('Invalid body stream read result')); + return; + } + if (TypeConversion::toBoolean($value->get('done'))) { + $instance->setInternalProperty('[[BodyBytes]]', $bytes); + $result->resolve(new JsString($bytes)); + return; + } + $chunk = $value->get('value'); + if (!$chunk instanceof JsTypedArray || $chunk->getTypeName() !== 'Uint8Array') { + $result->reject(StreamHelpers::createTypeError('Body stream chunks must be Uint8Array values')); + return; + } + $bytes .= $chunk->getBuffer()->readBytes($chunk->getByteOffset(), $chunk->getLength()); + JsPromise::scheduleCallback($pump); + }); + $read->addRejectHandler(static function (JsValue $reason) use ($result): void { + $result->reject($reason); + }); + }; + $pump(); + return $result; + } + + /** @param \Closure(string): JsValue $convert */ + private static function consumeConverted(JsObject $instance, \Closure $convert): JsPromise + { + return self::consumeBytes($instance)->then([JsFunction::fromCallable( + '', + static function (JsValue $_this, array $args) use ($convert): JsValue { + $bytes = $args[0] ?? JsUndefined::instance(); + return $convert($bytes instanceof JsString ? $bytes->value : ''); + }, + 1, + )]); + } + + /** Clone a body by teeing its live stream, cloning chunks on the second branch. */ + public static function cloneBody(JsObject $source, JsObject $target): void + { + $stream = self::getOrCreateBodyStream($source); + self::markAsBodyHost($target, self::bodyBytes($source), self::bodyContentType($source)); + $target->setInternalProperty('[[BodyReplayable]]', $source->getInternalProperty('[[BodyReplayable]]')); + if ($stream === null) { + return; + } + $branches = \Phasis\BuiltIn\Streams\PipeOperations::tee($stream, true); + $source->setInternalProperty('[[BodyStream]]', $branches->get('0')); + $target->setInternalProperty('[[BodyStream]]', $branches->get('1')); + } + + /** Transfer a request body through a proxy stream while retaining its reader lock. */ + public static function transferBodyStream(JsObject $source, Environment $env): JsObject + { + $stream = self::getOrCreateBodyStream($source); + if ($stream === null) { + throw new \LogicException('Cannot transfer a null body'); + } + $reader = ReadableStream::acquireDefaultReader($stream); + self::markUsed($source); + $underlying = new JsObject(); + $underlying->set('pull', JsFunction::fromCallable('', static function (JsValue $_this, array $args) use ($reader): JsValue { + $controller = $args[0] ?? JsUndefined::instance(); + return ReadableStream::defaultReaderRead($reader)->then([JsFunction::fromCallable( + '', + static function (JsValue $_this, array $args) use ($controller): JsValue { + $result = $args[0] ?? JsUndefined::instance(); + if ($controller instanceof JsObject && $result instanceof JsObject) { + if (TypeConversion::toBoolean($result->get('done'))) { + ReadableStream::defaultControllerClose($controller); + } else { + ReadableStream::defaultControllerEnqueue($controller, $result->get('value')); + } + } + return JsUndefined::instance(); + }, + )]); + })); + $underlying->set('cancel', JsFunction::fromCallable('', static function (JsValue $_this, array $args) use ($stream): JsValue { + return ReadableStream::readableStreamCancel($stream, $args[0] ?? JsUndefined::instance()); + })); + $constructor = $env->get('ReadableStream'); + if (!$constructor instanceof JsFunction) { + throw new \LogicException('ReadableStream is unavailable'); + } + $proxy = $constructor->construct([$underlying]); + if (!$proxy instanceof JsObject) { + throw new \LogicException('ReadableStream constructor returned a non-object'); } - return ''; + return $proxy; } /** diff --git a/src/BuiltIn/FetchFunction.php b/src/BuiltIn/FetchFunction.php index 52502706..3c9c172a 100644 --- a/src/BuiltIn/FetchFunction.php +++ b/src/BuiltIn/FetchFunction.php @@ -87,8 +87,21 @@ private static function doFetch(JsValue $input, JsValue $init, Environment $env) return self::rejectedWithAbortReason($signal, $env); } + $realm = Engine::getCurrentRealm(); + $node = $realm?->getNodeRuntime(); + if ($node !== null && $realm->getFetchTransport() === null) { + return self::performNodeTransport($node, $request, $env); + } + // ---------- Steps 4-8: transport + redirect loop ---------- - return self::performTransport($request, $env); + return \Phasis\BuiltIn\Fetch\BodyMixin::consumeBytes($request)->then([JsFunction::fromCallable( + '', + static function (JsValue $this_, array $args) use ($request, $env): JsValue { + $bytes = $args[0] ?? JsUndefined::instance(); + $request->setInternalProperty('[[BodyBytes]]', $bytes instanceof JsString ? $bytes->value : ''); + return self::performTransport($request, $env); + }, + )]); } catch (\Phasis\Exceptions\JsThrowable $e) { // A JS-throwing operation during normalization → reject. return JsPromise::rejected($e->jsValue); @@ -99,6 +112,46 @@ private static function doFetch(JsValue $input, JsValue $init, Environment $env) } } + private static function performNodeTransport(\Phasis\Node\NodeRuntime $runtime, JsObject $request, Environment $env): JsPromise + { + $jar = Engine::getCurrentRealm()?->getCookieJar(); + $get = JsFunction::fromCallable('', static fn (JsValue $this_, array $args): JsValue => new JsString( + $jar === null ? '' : self::cookieJarGet($jar, ($args[0] ?? JsUndefined::instance())->toJsString()), + )); + $set = JsFunction::fromCallable('', static function (JsValue $this_, array $args) use ($jar): JsValue { + if ($jar !== null) { + self::cookieJarSet($jar, ($args[0] ?? JsUndefined::instance())->toJsString(), ($args[1] ?? JsUndefined::instance())->toJsString()); + } + return JsUndefined::instance(); + }); + $finish = JsFunction::fromCallable('', static function (JsValue $this_, array $args): JsValue { + $response = $args[0] ?? JsUndefined::instance(); + if (!$response instanceof JsObject || !ResponseConstructor::isResponse($response)) { + throw new TypeError('The HTTP transport returned an invalid response'); + } + $response->setInternalProperty('[[Url]]', ($args[1] ?? JsUndefined::instance())->toJsString()); + $response->setInternalProperty('[[Redirected]]', ($args[2] ?? JsUndefined::instance())->toBoolean()); + $response->setInternalProperty('[[Type]]', 'basic'); + $headers = $response->getInternalProperty('[[Headers]]'); + if ($headers instanceof JsObject) { + HeadersConstructor::setGuard($headers, 'immutable'); + } + return $response; + }); + $raw = \Phasis\BuiltIn\Fetch\BodyMixin::bodyBytes($request); + $bytes = \Phasis\Value\JsNull::instance(); + if ($raw !== null && $request->getInternalProperty('[[BodyReplayable]]') === true) { + $buffer = new \Phasis\Value\JsArrayBuffer(strlen($raw)); + $buffer->setData($raw); + $bytes = new \Phasis\Value\JsTypedArray('Uint8Array', $buffer, 0, strlen($raw)); + } + $responseConstructor = $env->getIntrinsic('Response'); + if (!$responseConstructor instanceof JsFunction) { + throw new \LogicException('Response intrinsic is not installed'); + } + return $runtime->fetch($request, $bytes, $get, $set, $finish, $responseConstructor); + } + /** * Reuse RequestConstructor to build a Request from `(input, init)`. * Always returns a fresh Request — passing through a Request the @@ -107,12 +160,9 @@ private static function doFetch(JsValue $input, JsValue $init, Environment $env) */ private static function buildRequest(JsValue $input, JsValue $init, Environment $env): JsObject { - if (!$env->has('Request')) { - throw new TypeError('Request constructor is not installed'); - } - $ctor = $env->get('Request'); + $ctor = $env->getIntrinsic('Request'); if (!$ctor instanceof JsFunction) { - throw new TypeError('Request constructor is not callable'); + throw new TypeError('Request intrinsic is not installed'); } $constructed = $ctor->construct([$input, $init]); if (!$constructed instanceof JsObject) { diff --git a/src/BuiltIn/GlobalObject.php b/src/BuiltIn/GlobalObject.php index 94d9e083..3d244ec2 100644 --- a/src/BuiltIn/GlobalObject.php +++ b/src/BuiltIn/GlobalObject.php @@ -10,6 +10,7 @@ use Phasis\Value\JsBoolean; use Phasis\Value\JsFunction; use Phasis\Value\JsNumber; +use Phasis\Value\JsProxy; use Phasis\Value\JsString; use Phasis\Value\JsUndefined; use Phasis\Value\JsValue; @@ -455,18 +456,19 @@ enumerable: false, // Per spec §19.2.3.3, Function.prototype.call passes thisArg as-is. // Sloppy-mode this-wrapping happens inside the function body, not here. $callFn = JsFunction::fromCallable('call', function (JsValue $this_, array $args): JsValue { - if (!$this_ instanceof JsFunction) { + if (!$this_ instanceof JsFunction && !($this_ instanceof JsProxy && $this_->isCallable())) { throw new \Phasis\Exceptions\TypeError('call called on non-function'); } $thisArg = $args[0] ?? JsUndefined::instance(); - return $this_->call($thisArg, array_slice($args, 1)); + $callArgs = array_slice($args, 1); + return $this_ instanceof JsProxy ? $this_->apply($thisArg, $callArgs) : $this_->call($thisArg, $callArgs); }, 1); $fnProto->defineOwnProperty( 'call', \Phasis\Object\PropertyDescriptor::data($callFn, true, false, true), ); $applyFn = JsFunction::fromCallable('apply', function (JsValue $this_, array $args): JsValue { - if (!$this_ instanceof JsFunction) { + if (!$this_ instanceof JsFunction && !($this_ instanceof JsProxy && $this_->isCallable())) { throw new \Phasis\Exceptions\TypeError('apply called on non-function'); } $thisArg = $args[0] ?? JsUndefined::instance(); @@ -508,10 +510,12 @@ enumerable: false, $callArgs = $len === count($dense) ? array_values($dense) : array_slice($dense, 0, $len); - return $this_->call($thisArg, $callArgs); + return $this_ instanceof JsProxy + ? $this_->apply($thisArg, $callArgs) + : $this_->call($thisArg, $callArgs); } } else { - return $this_->call($thisArg, []); + return $this_ instanceof JsProxy ? $this_->apply($thisArg, []) : $this_->call($thisArg, []); } } // Get length and iterate index properties. @@ -521,7 +525,7 @@ enumerable: false, $callArgs[] = $argsArr->get((string) $i); } } - return $this_->call($thisArg, $callArgs); + return $this_ instanceof JsProxy ? $this_->apply($thisArg, $callArgs) : $this_->call($thisArg, $callArgs); }, 2); $fnProto->defineOwnProperty( 'apply', diff --git a/src/BuiltIn/HeadersConstructor.php b/src/BuiltIn/HeadersConstructor.php index b6f8fbad..2cdc2adf 100644 --- a/src/BuiltIn/HeadersConstructor.php +++ b/src/BuiltIn/HeadersConstructor.php @@ -48,6 +48,9 @@ class HeadersConstructor /** Marker slot so prototype methods can authenticate the receiver. */ public const SLOT_BRAND = '[[IsHeaders]]'; + /** Server runtimes permit headers that browser network APIs restrict. */ + private const SLOT_SERVER_POLICY = '[[HeadersServerPolicy]]'; + private static ?JsObject $iteratorPrototype = null; /** Cache of Headers.prototype after install. */ @@ -79,6 +82,9 @@ public static function setGuard(JsObject $headers, string $guard): void if (!self::isHeaders($headers)) { return; } + if ($guard !== 'immutable' && $headers->getInternalProperty(self::SLOT_SERVER_POLICY) === true) { + $guard = 'none'; + } $headers->setInternalProperty(self::SLOT_GUARD, $guard); // Re-filter the existing list: drop any pair that the guard now // rejects. Pairs are validated by the *combined* per-name view, so @@ -93,6 +99,14 @@ public static function setGuard(JsObject $headers, string $guard): void self::setList($headers, $newList); } + /** Preserve a cloned request or response's header policy and mutability. */ + public static function copyGuard(JsObject $target, JsObject $source): void + { + $target->setInternalProperty(self::SLOT_SERVER_POLICY, $source->getInternalProperty(self::SLOT_SERVER_POLICY)); + $guard = $source->getInternalProperty(self::SLOT_GUARD); + self::setGuard($target, is_string($guard) ? $guard : 'none'); + } + /** * Build a fresh Headers JS object from PHP. Each `$initList` entry is * `[name, value]`; names/values pass through the same normalization @@ -129,6 +143,10 @@ public static function create(Environment $env, array $initList = []): JsObject $obj = new JsObject($proto); $obj->setInternalProperty(self::SLOT_BRAND, true); + $obj->setInternalProperty( + self::SLOT_SERVER_POLICY, + \Phasis\Engine::getCurrentRealm()?->getNodeRuntime() !== null, + ); $obj->setInternalProperty(self::SLOT_GUARD, 'none'); $obj->setInternalProperty(self::SLOT_LIST, []); @@ -231,6 +249,10 @@ function (JsValue $this_, array $args) use ($proto): JsValue { } $this_->setInternalProperty(self::SLOT_BRAND, true); + $this_->setInternalProperty( + self::SLOT_SERVER_POLICY, + \Phasis\Engine::getCurrentRealm()?->getNodeRuntime() !== null, + ); $this_->setInternalProperty(self::SLOT_GUARD, 'none'); $this_->setInternalProperty(self::SLOT_LIST, []); diff --git a/src/BuiltIn/JsonObject.php b/src/BuiltIn/JsonObject.php index c4f199fc..0e6823d6 100644 --- a/src/BuiltIn/JsonObject.php +++ b/src/BuiltIn/JsonObject.php @@ -318,10 +318,7 @@ private static function trivialJsonValue(JsValue $value, array &$stack, array &$ $integerKeys = []; $stringKeys = []; foreach (array_keys($value->properties->dataSlots) as $name) { - if ( - isset($name[0]) - && ($name[0] === '[' || ($name[0] === '_' && isset($name[1]) && $name[1] === '_')) - ) { + if (str_starts_with((string) $name, '[[') && str_ends_with((string) $name, ']]')) { continue; } // PHP stdClass treats NUL bytes / non-printable chars as @@ -891,7 +888,7 @@ private static function stringify(): \Closure } $encoded = json_encode( $php, - JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, + JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS, ); if ($encoded !== false) { if ($value instanceof JsObject) { @@ -1157,10 +1154,7 @@ private static function serializeObject( foreach ($keys as $key) { $strP = self::serializeProperty($key, $value, $replacerFn, $propertyList, $gap, $indent, $stack); if ($strP !== null) { - $encodedKey = json_encode($key, JSON_UNESCAPED_UNICODE); - if ($encodedKey === false) { - $encodedKey = '"' . $key . '"'; - } + $encodedKey = self::quoteJsonString($key); $member = $encodedKey . ':'; if ($gap !== '') { $member .= ' '; diff --git a/src/BuiltIn/RequestConstructor.php b/src/BuiltIn/RequestConstructor.php index 32c62bf5..c65cb639 100644 --- a/src/BuiltIn/RequestConstructor.php +++ b/src/BuiltIn/RequestConstructor.php @@ -124,6 +124,7 @@ static function (JsValue $this_, array $args) use ($proto, $env): JsValue { ); $env->defineVar('Request', $ctor); + $env->setIntrinsic('Request', $ctor); } /** @@ -196,18 +197,15 @@ private static function initRequest(JsObject $instance, JsValue $input, JsValue // -------- Headers ---------------------------------------------- $headers = HeadersConstructor::create($env, []); - if ($sourceRequest !== null) { + $headerInit = $initObj?->get('headers') ?? JsUndefined::instance(); + if (!$headerInit instanceof JsUndefined) { + self::fillHeadersFromValue($headers, $headerInit, $env); + } elseif ($sourceRequest !== null) { $srcHeaders = $sourceRequest->getInternalProperty('[[Headers]]'); if ($srcHeaders instanceof JsObject) { self::copyHeadersInto($headers, $srcHeaders); } } - if ($hasInit) { - $hInit = $initObj->get('headers'); - if (!$hInit instanceof JsUndefined && !$hInit instanceof JsNull) { - self::fillHeadersFromValue($headers, $hInit, $env); - } - } $instance->setInternalProperty('[[Headers]]', $headers); // -------- Mode / credentials / cache / redirect / referrer / etc ---- @@ -254,14 +252,29 @@ private static function initRequest(JsObject $instance, JsValue $input, JsValue 'follow', self::VALID_REDIRECT, )); - $instance->setInternalProperty('[[Referrer]]', self::pickString( + $referrer = self::pickString( $sourceRequest, $initObj, '[[Referrer]]', 'referrer', 'about:client', null, - )); + ); + if ($referrer !== '' && $referrer !== 'about:client') { + $referrerBase = null; + if ($env->has('__phasisRequestBaseUrl')) { + $baseValue = $env->get('__phasisRequestBaseUrl'); + if ($baseValue instanceof JsString && $baseValue->value !== '') { + $referrerBase = UrlParser::parse($baseValue->value); + } + } + $parsedReferrer = UrlParser::parse($referrer, $referrerBase); + if ($parsedReferrer === null) { + throw new TypeError("Failed to construct 'Request': Invalid referrer: '$referrer'"); + } + $referrer = UrlSerializer::serializeUrl($parsedReferrer); + } + $instance->setInternalProperty('[[Referrer]]', $referrer); $instance->setInternalProperty('[[ReferrerPolicy]]', self::pickString( $sourceRequest, $initObj, @@ -335,6 +348,8 @@ private static function initRequest(JsObject $instance, JsValue $input, JsValue // -------- Body -------------------------------------------------- $bodyBytes = null; $bodyContentType = null; + $bodyStream = null; + $bodyProvided = false; // From source Request (if no init body): clone its buffered bytes. if ($sourceRequest !== null) { @@ -351,6 +366,7 @@ private static function initRequest(JsObject $instance, JsValue $input, JsValue if ($hasInit) { $bInit = $initObj->get('body'); if (!$bInit instanceof JsUndefined && !$bInit instanceof JsNull) { + $bodyProvided = true; $methodUpper = strtoupper($method); if ($methodUpper === 'GET' || $methodUpper === 'HEAD') { throw new TypeError( @@ -360,11 +376,25 @@ private static function initRequest(JsObject $instance, JsValue $input, JsValue $extracted = BodyExtraction::extractBody($bInit, $headers, $env, $keepalive); $bodyBytes = $extracted['bytes']; $bodyContentType = $extracted['contentType']; + $bodyStream = $extracted['stream'] ?? null; BodyExtraction::maybeSetContentType($headers, $extracted); } } - BodyMixin::markAsBodyHost($instance, $bodyBytes, $bodyContentType); + if (!$bodyProvided && $sourceRequest !== null && $bodyBytes !== null) { + if (BodyMixin::isBodyUsed($sourceRequest) || BodyMixin::isStreamLockedOrDisturbed($sourceRequest)) { + throw new TypeError('Failed to construct Request: input body is unusable'); + } + if ($method === 'GET' || $method === 'HEAD') { + throw new TypeError('Request with GET/HEAD method cannot have body'); + } + $bodyStream = BodyMixin::transferBodyStream($sourceRequest, $env); + } + + BodyMixin::markAsBodyHost($instance, $bodyBytes, $bodyContentType, null, $bodyStream); + if (!$bodyProvided && $sourceRequest !== null) { + $instance->setInternalProperty('[[BodyReplayable]]', $sourceRequest->getInternalProperty('[[BodyReplayable]]')); + } } private static function copyHeadersInto(JsObject $dst, JsObject $src): void @@ -715,14 +745,10 @@ private static function cloneInto(JsObject $dst, JsObject $src, Environment $env $newHeaders = HeadersConstructor::create($env, []); if ($srcHeaders instanceof JsObject) { self::copyHeadersInto($newHeaders, $srcHeaders); + HeadersConstructor::copyGuard($newHeaders, $srcHeaders); } $dst->setInternalProperty('[[Headers]]', $newHeaders); - // Body: clone bytes verbatim. The cached stream is NOT carried - // over so the clone has its own fresh stream on first .body read - // (matches spec's "tee" semantics for the buffered case). - $bytes = BodyMixin::bodyBytes($src); - $ct = BodyMixin::bodyContentType($src); - BodyMixin::markAsBodyHost($dst, $bytes, $ct); + BodyMixin::cloneBody($src, $dst); } } diff --git a/src/BuiltIn/ResponseConstructor.php b/src/BuiltIn/ResponseConstructor.php index c6db9db2..8fca49c5 100644 --- a/src/BuiltIn/ResponseConstructor.php +++ b/src/BuiltIn/ResponseConstructor.php @@ -96,6 +96,7 @@ static function (JsValue $this_, array $args) use ($proto, $env): JsValue { self::installStatics($ctor, $proto, $env); $env->defineVar('Response', $ctor); + $env->setIntrinsic('Response', $ctor); } /** @@ -120,7 +121,9 @@ public static function createFromPhp( string $type = 'basic', bool $redirected = false, ): JsObject { - $proto = self::$prototype ?? new JsObject(); + $constructor = $env->getIntrinsic('Response'); + $prototype = $constructor instanceof JsObject ? $constructor->get('prototype') : null; + $proto = $prototype instanceof JsObject ? $prototype : self::$prototype ?? new JsObject(); $obj = new JsObject($proto); $obj->setInternalProperty('[[IsResponse]]', true); $obj->setInternalProperty('[[Status]]', $status); @@ -253,11 +256,7 @@ private static function initResponse( $extracted['contentType'] = $contentTypeOverride; } BodyExtraction::maybeSetContentType($headers, $extracted); - // Preserve original ReadableStream chunks so .body - // re-emits them with identity (response-clone teed - // structureClone WPT tests rely on this). - $bodyChunks = $extracted['chunks'] ?? null; - BodyMixin::markAsBodyHost($instance, $bodyBytes, $bodyContentType, $bodyChunks); + BodyMixin::markAsBodyHost($instance, $bodyBytes, $bodyContentType, null, $extracted['stream'] ?? null); return; } @@ -634,27 +633,11 @@ static function (JsValue $this_, array $args) use ($proto, $env): JsValue { HeadersConstructor::appendFromPhp($newHeaders, (string) $pair[0], (string) $pair[1]); } } + HeadersConstructor::copyGuard($newHeaders, $srcHeaders); } $clone->setInternalProperty('[[Headers]]', $newHeaders); - $bytes = BodyMixin::bodyBytes($this_); - $ct = BodyMixin::bodyContentType($this_); - // For ReadableStream-backed bodies, the spec clones - // the underlying stream — implemented here by - // structuredClone-ing each captured chunk so the - // cloned half reads independent (but content-equal) - // JS values. - $srcChunks = $this_->getInternalProperty('[[BodyChunks]]'); - $clonedChunks = null; - if (is_array($srcChunks) && !empty($srcChunks)) { - $clonedChunks = []; - foreach ($srcChunks as $chunk) { - if ($chunk instanceof JsValue) { - $clonedChunks[] = \Phasis\BuiltIn\StructuredCloneFunction::cloneJsValue($chunk); - } - } - } - BodyMixin::markAsBodyHost($clone, $bytes, $ct, $clonedChunks); + BodyMixin::cloneBody($this_, $clone); return $clone; }, 0, diff --git a/src/BuiltIn/Streams/ByteStream.php b/src/BuiltIn/Streams/ByteStream.php index d94bcdc8..1ed656e5 100644 --- a/src/BuiltIn/Streams/ByteStream.php +++ b/src/BuiltIn/Streams/ByteStream.php @@ -497,13 +497,16 @@ public static function setUpReadableByteStreamControllerFromUnderlyingSource( } } $startPromise = StreamHelpers::toPromise($startResult); - $startPromise->addFulfillHandler(static function (JsValue $_) use ($controller): void { - $controller->setInternalProperty('[[Started]]', true); - self::byteControllerCallPullIfNeeded($controller); - }); - $startPromise->addRejectHandler(static function (JsValue $reason) use ($controller): void { - self::byteControllerError($controller, $reason); - }); + StreamHelpers::uponPromise( + $startPromise, + static function (JsValue $_) use ($controller): void { + $controller->setInternalProperty('[[Started]]', true); + self::byteControllerCallPullIfNeeded($controller); + }, + static function (JsValue $reason) use ($controller): void { + self::byteControllerError($controller, $reason); + }, + ); } public static function byteControllerDesiredSize(JsObject $controller): ?float @@ -573,16 +576,19 @@ public static function byteControllerCallPullIfNeeded(JsObject $controller): voi return; } $p = $pullAlgo(); - $p->addFulfillHandler(static function (JsValue $_) use ($controller): void { - $controller->setInternalProperty('[[Pulling]]', false); - if ($controller->getInternalProperty('[[PullAgain]]') === true) { - $controller->setInternalProperty('[[PullAgain]]', false); - self::byteControllerCallPullIfNeeded($controller); - } - }); - $p->addRejectHandler(static function (JsValue $reason) use ($controller): void { - self::byteControllerError($controller, $reason); - }); + StreamHelpers::uponPromise( + $p, + static function (JsValue $_) use ($controller): void { + $controller->setInternalProperty('[[Pulling]]', false); + if ($controller->getInternalProperty('[[PullAgain]]') === true) { + $controller->setInternalProperty('[[PullAgain]]', false); + self::byteControllerCallPullIfNeeded($controller); + } + }, + static function (JsValue $reason) use ($controller): void { + self::byteControllerError($controller, $reason); + }, + ); } /** diff --git a/src/BuiltIn/Streams/PipeOperations.php b/src/BuiltIn/Streams/PipeOperations.php index 50490575..532072b0 100644 --- a/src/BuiltIn/Streams/PipeOperations.php +++ b/src/BuiltIn/Streams/PipeOperations.php @@ -261,7 +261,7 @@ public static function pipeThrough(JsObject $source, JsValue $transform, JsValue * * Returns a JsArray holding two ReadableStreams. */ - public static function tee(JsObject $stream): JsArray + public static function tee(JsObject $stream, bool $cloneForBranch2 = false): JsArray { $reader = \Phasis\BuiltIn\Streams\ReadableStream::acquireDefaultReader($stream); $closedOrErrored = new class () { @@ -292,14 +292,21 @@ public function __construct() public bool $value = false; }; - $pullAlgorithm = function () use ($branches, $reader, $canceled1, $canceled2, $pulling): JsPromise { + $pullAlgorithm = function () use ($branches, $reader, $canceled1, $canceled2, $pulling, $cloneForBranch2): JsPromise { if ($pulling->value) { return StreamHelpers::promiseResolved(JsUndefined::instance()); } $pulling->value = true; $readPromise = \Phasis\BuiltIn\Streams\ReadableStream::defaultReaderRead($reader); $outer = new JsPromise(); - $readPromise->addFulfillHandler(function (JsValue $result) use ($branches, $canceled1, $canceled2, $outer, $pulling): void { + $readPromise->addFulfillHandler(function (JsValue $result) use ( + $branches, + $canceled1, + $canceled2, + $outer, + $pulling, + $cloneForBranch2, + ): void { if (!$result instanceof JsObject) { $outer->reject(StreamHelpers::createTypeError('Read result not object')); $pulling->value = false; @@ -324,6 +331,25 @@ public function __construct() $pulling->value = false; return; } + $secondValue = $value; + if ($cloneForBranch2 && !$canceled2->value) { + try { + $secondValue = \Phasis\BuiltIn\StructuredCloneFunction::cloneJsValue($value); + } catch (\Throwable $error) { + $reason = $error instanceof \Phasis\Exceptions\JsThrowable + ? $error->jsValue + : StreamHelpers::createTypeError($error->getMessage()); + foreach ([$branches->b1, $branches->b2] as $branch) { + $controller = $branch?->getInternalProperty('[[Controller]]'); + if ($controller instanceof JsObject) { + \Phasis\BuiltIn\Streams\ReadableStream::defaultControllerError($controller, $reason); + } + } + $outer->reject($reason); + $pulling->value = false; + return; + } + } if (!$canceled1->value && $branches->b1 instanceof JsObject) { $c1 = $branches->b1->getInternalProperty('[[Controller]]'); if ($c1 instanceof JsObject && \Phasis\BuiltIn\Streams\ReadableStream::canCloseOrEnqueue($c1)) { @@ -333,7 +359,7 @@ public function __construct() if (!$canceled2->value && $branches->b2 instanceof JsObject) { $c2 = $branches->b2->getInternalProperty('[[Controller]]'); if ($c2 instanceof JsObject && \Phasis\BuiltIn\Streams\ReadableStream::canCloseOrEnqueue($c2)) { - \Phasis\BuiltIn\Streams\ReadableStream::defaultControllerEnqueue($c2, $value); + \Phasis\BuiltIn\Streams\ReadableStream::defaultControllerEnqueue($c2, $secondValue); } } $outer->resolve(JsUndefined::instance()); diff --git a/src/BuiltIn/Streams/ReadableStream.php b/src/BuiltIn/Streams/ReadableStream.php index f4f6e4ba..fd214271 100644 --- a/src/BuiltIn/Streams/ReadableStream.php +++ b/src/BuiltIn/Streams/ReadableStream.php @@ -657,29 +657,16 @@ public static function setUpDefaultControllerFromUnderlyingSource( } } $startPromise = StreamHelpers::toPromise($startResult); - // Per WHATWG Streams §SetUpReadableStreamDefaultController step 14 - // ("Upon fulfillment of startPromise..."): the reaction runs as a - // microtask even when the start algorithm returned synchronously. - // Our addFulfillHandler invokes immediately on already-fulfilled - // promises, so wrap the [[Started]]/pullIfNeeded transition in - // scheduleCallback to preserve spec ordering. Without this defer, - // a stream constructed without a start algorithm fires pull - // synchronously during construction, which (a) lets pull observe - // the source closure in TDZ for `const stream = new ReadableStream` - // patterns, and (b) loses the race against a synchronous cancel - // that should preempt the first pull (async-iterator return() → - // ReadableStreamCancel sets state to closed). - $startPromise->addFulfillHandler(static function (JsValue $_) use ($controller): void { - JsPromise::scheduleCallback(static function () use ($controller): void { + StreamHelpers::uponPromise( + $startPromise, + static function (JsValue $_) use ($controller): void { $controller->setInternalProperty('[[Started]]', true); self::defaultControllerCallPullIfNeeded($controller); - }); - }); - $startPromise->addRejectHandler(static function (JsValue $reason) use ($controller): void { - JsPromise::scheduleCallback(static function () use ($controller, $reason): void { + }, + static function (JsValue $reason) use ($controller): void { self::defaultControllerError($controller, $reason); - }); - }); + }, + ); } /** @@ -700,16 +687,19 @@ public static function defaultControllerCallPullIfNeeded(JsObject $controller): return; } $promise = $pullAlgorithm(); - $promise->addFulfillHandler(static function (JsValue $_) use ($controller): void { - $controller->setInternalProperty('[[Pulling]]', false); - if ($controller->getInternalProperty('[[PullAgain]]') === true) { - $controller->setInternalProperty('[[PullAgain]]', false); - self::defaultControllerCallPullIfNeeded($controller); - } - }); - $promise->addRejectHandler(static function (JsValue $reason) use ($controller): void { - self::defaultControllerError($controller, $reason); - }); + StreamHelpers::uponPromise( + $promise, + static function (JsValue $_) use ($controller): void { + $controller->setInternalProperty('[[Pulling]]', false); + if ($controller->getInternalProperty('[[PullAgain]]') === true) { + $controller->setInternalProperty('[[PullAgain]]', false); + self::defaultControllerCallPullIfNeeded($controller); + } + }, + static function (JsValue $reason) use ($controller): void { + self::defaultControllerError($controller, $reason); + }, + ); } /** diff --git a/src/BuiltIn/Streams/StreamHelpers.php b/src/BuiltIn/Streams/StreamHelpers.php index 54c56b9c..544ce2fb 100644 --- a/src/BuiltIn/Streams/StreamHelpers.php +++ b/src/BuiltIn/Streams/StreamHelpers.php @@ -110,6 +110,26 @@ public static function markPromiseHandled(JsPromise $p): void }); } + /** + * Run a stream algorithm's promise reactions in their own microtasks. + * + * @param \Closure(JsValue): void $fulfilled + * @param \Closure(JsValue): void $rejected + */ + public static function uponPromise(JsPromise $promise, \Closure $fulfilled, \Closure $rejected): void + { + $promise->then([ + JsFunction::fromCallable('', static function (JsValue $_, array $args) use ($fulfilled): JsValue { + $fulfilled($args[0] ?? JsUndefined::instance()); + return JsUndefined::instance(); + }, 1), + JsFunction::fromCallable('', static function (JsValue $_, array $args) use ($rejected): JsValue { + $rejected($args[0] ?? JsUndefined::instance()); + return JsUndefined::instance(); + }, 1), + ]); + } + /** * Set the value of the [[Resolve]] / [[Reject]] capability for a promise. * Returns [resolve, reject] closures bound to the given promise. diff --git a/src/BuiltIn/String/StringIteration.php b/src/BuiltIn/String/StringIteration.php index 917a19c3..c307c553 100644 --- a/src/BuiltIn/String/StringIteration.php +++ b/src/BuiltIn/String/StringIteration.php @@ -113,7 +113,7 @@ public static function createStringIterator(JsString $str): JsObject // Build character list using UTF-16 code units, combining valid // surrogate pairs into single code points. $chars = []; - $u16 = JsString::utf8ToUtf16LE($str->value); + $u16 = $str->utf16LE(); $u16Len = (int) (strlen($u16) / 2); $i = 0; while ($i < $u16Len) { @@ -150,19 +150,14 @@ private static function charAt(): \Closure { return function (JsValue $this_, array $args): JsValue { $str = self::extractString($this_); - // ToInteger(pos): call ToNumber first (may throw TypeError for - // objects without valueOf/toString, e.g. Object.create(null)). - $posNum = isset($args[0]) ? TypeConversion::toNumber($args[0]) : 0.0; - $index = (int) $posNum; - if (is_nan($posNum)) { - $index = 0; - } + $position = isset($args[0]) ? TypeConversion::toIntegerOrInfinity($args[0]) : 0.0; // Per spec charAt uses UTF-16 code unit indices. - $u16 = JsString::utf8ToUtf16LE($str); + $u16 = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); $len = (int) (strlen($u16) / 2); - if ($index < 0 || $index >= $len) { + if ($position < 0 || $position >= $len) { return new JsString(''); } + $index = (int) $position; $codeUnit = ord($u16[$index * 2]) | (ord($u16[$index * 2 + 1]) << 8); return new JsString(JsString::utf16CodeUnitToUtf8($codeUnit)); }; @@ -172,13 +167,14 @@ private static function charCodeAt(): \Closure { return function (JsValue $this_, array $args): JsValue { $str = self::extractString($this_); - $index = isset($args[0]) ? (int) TypeConversion::toNumber($args[0]) : 0; + $position = isset($args[0]) ? TypeConversion::toIntegerOrInfinity($args[0]) : 0.0; // Index by UTF-16 code units, not Unicode codepoints. - $u16 = JsString::utf8ToUtf16LE($str); + $u16 = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); $len = (int) (strlen($u16) / 2); - if ($index < 0 || $index >= $len) { + if ($position < 0 || $position >= $len) { return JsNumber::of(NAN); } + $index = (int) $position; $cu = ord($u16[$index * 2]) | (ord($u16[$index * 2 + 1]) << 8); return JsNumber::of((float) $cu); }; @@ -190,7 +186,7 @@ private static function slice(): \Closure $str = self::extractString($this_); // Per spec, String.prototype.slice indices are UTF-16 code unit // offsets, not code point offsets, so work on the UTF-16LE form. - $u16 = JsString::utf8ToUtf16LE($str); + $u16 = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); $len = (int) (strlen($u16) / 2); // Per spec 22.1.3.22: intStart = ToIntegerOrInfinity(start). @@ -236,7 +232,7 @@ private static function substring(): \Closure $str = self::extractString($this_); // Per spec, substring operates on UTF-16 code unit offsets, not // code point offsets. - $u16 = JsString::utf8ToUtf16LE($str); + $u16 = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); $len = (int) (strlen($u16) / 2); // Per spec: ToIntegerOrInfinity(start). NaN -> 0. @@ -308,7 +304,7 @@ private static function at(): \Closure $relative = isset($args[0]) ? TypeConversion::toIntegerOrInfinity($args[0]) : 0.0; - $u16 = JsString::utf8ToUtf16LE($str); + $u16 = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); $len = (int) (strlen($u16) / 2); $k = $relative >= 0 ? $relative : $len + $relative; if ($k < 0 || $k >= $len) { @@ -327,7 +323,7 @@ private static function codePointAt(): \Closure $pos = isset($args[0]) ? TypeConversion::toIntegerOrInfinity($args[0]) : 0.0; // Convert UTF-8 string to UTF-16 code units to match JS semantics. - $u16 = JsString::utf8ToUtf16LE($str); + $u16 = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); $size = (int) (strlen($u16) / 2); if ($pos < 0 || $pos >= $size) { diff --git a/src/BuiltIn/String/StringSearch.php b/src/BuiltIn/String/StringSearch.php index 61c6628e..8378a416 100644 --- a/src/BuiltIn/String/StringSearch.php +++ b/src/BuiltIn/String/StringSearch.php @@ -453,15 +453,37 @@ private static function split(): \Closure $sep = $separatorString ?? TypeConversion::toString($separator); if ($sep === '') { - // Split into individual characters. + $units = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); $chars = []; - $len = mb_strlen($str, 'UTF-8'); + $len = (int) (strlen($units) / 2); for ($i = 0; $i < $len && $i < $lim; $i++) { - $chars[] = new JsString(mb_substr($str, $i, 1, 'UTF-8')); + $chars[] = new JsString(JsString::utf16LEToUtf8(substr($units, $i * 2, 2))); } return JsArray::fromArray($chars); } + if (!mb_check_encoding($str, 'UTF-8') || !mb_check_encoding($sep, 'UTF-8')) { + $units = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); + $separatorUnits = JsString::utf8ToUtf16LE($sep); + $parts = []; + $cursor = 0; + $search = 0; + while (count($parts) < $lim && ($index = strpos($units, $separatorUnits, $search)) !== false) { + // UTF-16 substrings must start at a code-unit boundary. + if (($index & 1) !== 0) { + $search = $index + 1; + continue; + } + $parts[] = new JsString(JsString::utf16LEToUtf8(substr($units, $cursor, $index - $cursor))); + $cursor = $index + strlen($separatorUnits); + $search = $cursor; + } + if (count($parts) < $lim) { + $parts[] = new JsString(JsString::utf16LEToUtf8(substr($units, $cursor))); + } + return JsArray::fromArray($parts); + } + $parts = explode($sep, $str); if ($lim < count($parts)) { $parts = array_slice($parts, 0, $lim); diff --git a/src/BuiltIn/StructuredCloneFunction.php b/src/BuiltIn/StructuredCloneFunction.php index 48413a95..8487f988 100644 --- a/src/BuiltIn/StructuredCloneFunction.php +++ b/src/BuiltIn/StructuredCloneFunction.php @@ -525,12 +525,7 @@ private static function cloneRegExp(JsObject $value, \SplObjectStorage $seen): J // `new RegExp(source, flags)` runs the full // construction path and yields a JsObject with all // internal slots wired. - $newTargetMarker = new JsObject(); - $newTargetMarker->defineOwnProperty( - '[[NewTarget]]', - PropertyDescriptor::data($ctor, false, false, false), - ); - $result = $ctor->call($newTargetMarker, [ + $result = $ctor->construct([ new JsString($source), new JsString($flags), ]); @@ -725,12 +720,7 @@ private static function dataCloneError(string $message): JsThrowable $ctor = $env->get('DOMException'); if ($ctor instanceof JsFunction && $ctor->isConstructable()) { try { - $newTargetMarker = new JsObject(); - $newTargetMarker->defineOwnProperty( - '[[NewTarget]]', - PropertyDescriptor::data($ctor, false, false, false), - ); - $result = $ctor->call($newTargetMarker, [ + $result = $ctor->construct([ new JsString($message), new JsString('DataCloneError'), ]); diff --git a/src/BuiltIn/SubtleCryptoObject.php b/src/BuiltIn/SubtleCryptoObject.php index db8a731d..afe17b84 100644 --- a/src/BuiltIn/SubtleCryptoObject.php +++ b/src/BuiltIn/SubtleCryptoObject.php @@ -145,6 +145,11 @@ private static function signImpl(): \Closure $key = $args[1] ?? JsUndefined::instance(); $data = self::bufferSourceBytes($args[2] ?? JsUndefined::instance()); $algName = strtoupper(self::normalizeAlgorithmName($alg)); + if ($algName === 'ED25519') { + $cryptoKey = self::requireCryptoKey($key); + self::assertEd25519Key($cryptoKey, 'private', 'sign'); + return JsPromise::resolved(self::bufferFromBytes(Ed25519Crypto::sign(self::cryptoKeyMaterial($cryptoKey), $data))); + } if ($algName === 'HMAC') { $cryptoKey = self::requireCryptoKey($key); self::assertUsage($cryptoKey, 'sign'); @@ -195,6 +200,11 @@ private static function verifyImpl(): \Closure $signature = self::bufferSourceBytes($args[2] ?? JsUndefined::instance()); $data = self::bufferSourceBytes($args[3] ?? JsUndefined::instance()); $algName = strtoupper(self::normalizeAlgorithmName($alg)); + if ($algName === 'ED25519') { + $cryptoKey = self::requireCryptoKey($key); + self::assertEd25519Key($cryptoKey, 'public', 'verify'); + return JsPromise::resolved(JsBoolean::of(Ed25519Crypto::verify(self::cryptoKeyMaterial($cryptoKey), $signature, $data))); + } if ($algName === 'HMAC') { $cryptoKey = self::requireCryptoKey($key); self::assertUsage($cryptoKey, 'verify'); @@ -423,10 +433,25 @@ private static function generateKeyImpl(): \Closure return static function (JsValue $this_, array $args): JsValue { unset($this_); try { - $alg = self::requireObject($args[0] ?? JsUndefined::instance(), 'generateKey'); + $algorithmInput = $args[0] ?? JsUndefined::instance(); + $algName = strtoupper(self::normalizeAlgorithmName($algorithmInput)); $extractable = TypeConversion::toBoolean($args[1] ?? JsUndefined::instance()); $usages = self::collectUsages($args[2] ?? JsUndefined::instance()); - $algName = strtoupper(self::stringPropOrThrow($alg, 'name', 'generateKey')); + if ($algName === 'ED25519') { + Ed25519Crypto::validateUsages($usages, 'private', true); + [$public, $private] = Ed25519Crypto::generate(); + $algorithm = ['name' => 'Ed25519']; + $publicKey = self::makeCryptoKey('public', $algorithm, true, array_values(array_intersect($usages, ['verify'])), $public); + $privateKey = self::makeCryptoKey( + 'private', + $algorithm, + $extractable, + array_values(array_intersect($usages, ['sign'])), + $private, + ); + return JsPromise::resolved(self::makeCryptoKeyPair($publicKey, $privateKey)); + } + $alg = self::requireObject($algorithmInput, 'generateKey'); if ($algName === 'HMAC') { // Per spec, hash can be a string ('SHA-256') or an @@ -526,6 +551,18 @@ private static function importKeyImpl(): \Closure $usages = self::collectUsages($args[4] ?? JsUndefined::instance()); $algName = self::normalizeAlgorithmName($algRaw); + if (strtoupper($algName) === 'ED25519') { + $data = $format === 'jwk' ? self::requireObject($keyData, 'jwk import') : self::bufferSourceBytes($keyData); + $imported = Ed25519Crypto::import($format, $data, $extractable, $usages); + return JsPromise::resolved(self::makeCryptoKey( + $imported['type'], + ['name' => 'Ed25519'], + $extractable, + $usages, + $imported['material'], + )); + } + if ($format === 'raw') { $bytes = self::bufferSourceBytes($keyData); if (strtoupper($algName) === 'HMAC') { @@ -647,6 +684,11 @@ private static function exportKeyImpl(): \Closure $keyType = $key->getInternalProperty('[[KeyType]]'); $alg = $key->getInternalProperty('[[KeyAlgorithm]]'); $algName = is_array($alg) ? (string) ($alg['name'] ?? '') : ''; + if ($algName === 'Ed25519') { + $usages = $key->getInternalProperty('[[KeyUsages]]'); + $exported = Ed25519Crypto::export($format, (string) $keyType, $material, is_array($usages) ? $usages : []); + return JsPromise::resolved(is_string($exported) ? self::bufferFromBytes($exported) : $exported); + } $isAsym = in_array($algName, [ 'RSA-OAEP', 'RSA-PSS', @@ -1830,7 +1872,7 @@ private static function makeCryptoKey( array $usages, string $material, ): JsObject { - $key = new JsObject(); + $key = new JsObject(CryptoKeyConstructor::prototype()); $key->setInternalProperty('[[IsCryptoKey]]', true); $key->setInternalProperty('[[KeyType]]', $type); $key->setInternalProperty('[[KeyAlgorithm]]', $algorithm); @@ -1942,6 +1984,18 @@ private static function requireCryptoKey(JsValue $val): JsObject return $val; } + private static function assertEd25519Key(JsObject $key, string $type, string $usage): void + { + $algorithm = $key->getInternalProperty('[[KeyAlgorithm]]'); + $usages = $key->getInternalProperty('[[KeyUsages]]'); + if ( + !is_array($algorithm) || ($algorithm['name'] ?? '') !== 'Ed25519' + || $key->getInternalProperty('[[KeyType]]') !== $type || !is_array($usages) || !in_array($usage, $usages, true) + ) { + Ed25519Crypto::error('InvalidAccessError', 'The key cannot be used for the requested Ed25519 operation.'); + } + } + private static function cryptoKeyMaterial(JsObject $key): string { $m = $key->getInternalProperty('[[KeyMaterial]]'); @@ -2078,6 +2132,9 @@ private static function bufferFromBytes(string $bytes): JsArrayBuffer private static function rejectFromThrow(\Throwable $e): JsValue { + if ($e instanceof \Phasis\Exceptions\JsThrowable) { + return JsPromise::rejected($e->jsValue); + } // Map host exception class to the spec-correct rejection // shape. SubtleCrypto's reject conditions per spec: // - TypeError → caller passed a bad argument shape diff --git a/src/BuiltIn/TextDecoderConstructor.php b/src/BuiltIn/TextDecoderConstructor.php index 7e6a96a5..ef3593aa 100644 --- a/src/BuiltIn/TextDecoderConstructor.php +++ b/src/BuiltIn/TextDecoderConstructor.php @@ -415,37 +415,26 @@ private static function decodeUtf8( continue; } - // Check we have enough bytes left. - if ($i + $needed >= $len) { - // Incomplete tail. - if ($stream) { - // Hold over for next chunk. - $pendingOut = \substr($bytes, $i); - return $out; - } - if ($fatal) { - throw new TypeError('TextDecoder.decode: incomplete UTF-8 byte sequence'); - } - $out .= "\xEF\xBF\xBD"; - return $out; - } - - // Validate continuation bytes. $ok = true; - $secondByte = \ord($bytes[$i + 1]); - if ($secondByte < $lower || $secondByte > $upper) { - $ok = false; - } - if ($ok) { - $cp = ($cp << 6) | ($secondByte & 0x3F); - for ($k = 2; $k <= $needed; $k++) { - $nb = \ord($bytes[$i + $k]); - if ($nb < 0x80 || $nb > 0xBF) { - $ok = false; - break; + for ($consumed = 1; $consumed <= $needed; $consumed++) { + if ($i + $consumed >= $len) { + if ($stream) { + $pendingOut = \substr($bytes, $i); + return $out; } - $cp = ($cp << 6) | ($nb & 0x3F); + if ($fatal) { + throw new TypeError('TextDecoder.decode: incomplete UTF-8 byte sequence'); + } + return $out . "\xEF\xBF\xBD"; + } + $next = \ord($bytes[$i + $consumed]); + $minimum = $consumed === 1 ? $lower : 0x80; + $maximum = $consumed === 1 ? $upper : 0xBF; + if ($next < $minimum || $next > $maximum) { + $ok = false; + break; } + $cp = ($cp << 6) | ($next & 0x3F); } if (!$ok) { @@ -453,9 +442,8 @@ private static function decodeUtf8( throw new TypeError('TextDecoder.decode: invalid UTF-8 byte sequence'); } $out .= "\xEF\xBF\xBD"; - // WHATWG: advance only past the invalid leading byte; - // resume from the bad continuation. - $i += 1; + // Consumed continuation bytes belong to this error; reprocess the offending byte. + $i += $consumed; continue; } diff --git a/src/Bytecode/CompilationFailures.php b/src/Bytecode/CompilationFailures.php new file mode 100644 index 00000000..2d04967f --- /dev/null +++ b/src/Bytecode/CompilationFailures.php @@ -0,0 +1,61 @@ +> */ + private static ?\WeakMap $failures = null; + /** @var ?\WeakMap */ + private static ?\WeakMap $parameterIds = null; + private static int $nextParameterId = 0; + + /** Return a prior structural bailout without retaining any closure environment. */ + public static function get(JsFunction $function, string $compiler): ?string + { + $body = $function->getBody(); + if (!$body instanceof Node || self::$failures === null) { + return null; + } + return self::$failures[$body][self::signature($function, $compiler)] ?? null; + } + + /** Remember only syntax-based failures, never a runtime specialization failure. */ + public static function remember(JsFunction $function, string $compiler, string $reason): void + { + $body = $function->getBody(); + if (!$body instanceof Node) { + return; + } + self::$failures ??= new \WeakMap(); + $entries = self::$failures[$body] ?? []; + $entries[self::signature($function, $compiler)] = $reason; + self::$failures[$body] = $entries; + } + + /** Describe syntax and immutable function flags without retaining a closure. */ + public static function signature(JsFunction $function, string $compiler): string + { + $parameters = []; + foreach ($function->getParams() as $parameter) { + if ($parameter instanceof Node) { + self::$parameterIds ??= new \WeakMap(); + self::$parameterIds[$parameter] ??= ++self::$nextParameterId; + $parameters[] = self::$parameterIds[$parameter]; + } else { + $parameters[] = null; + } + } + return $compiler . ':' . json_encode([ + $parameters, $function->isStrict(), $function->isArrow(), $function->isGenerator(), + $function->isAsync(), $function->isClassConstructor(), $function->isDerivedConstructor(), + $function->getHomeObject() !== null, + ], JSON_THROW_ON_ERROR); + } +} diff --git a/src/Bytecode/CompilationTemplates.php b/src/Bytecode/CompilationTemplates.php new file mode 100644 index 00000000..1700f15a --- /dev/null +++ b/src/Bytecode/CompilationTemplates.php @@ -0,0 +1,39 @@ +> */ + private static ?\WeakMap $templates = null; + + /** Return an independent function cache over an immutable compiled layout. */ + public static function get(JsFunction $function): ?CompiledFunction + { + $body = $function->getBody(); + if (!$body instanceof Node || self::$templates === null) { + return null; + } + $template = self::$templates[$body][CompilationFailures::signature($function, 'bytecode')] ?? null; + return $template !== null ? clone $template : null; + } + + /** Save a freshly compiled layout before its first execution. */ + public static function remember(JsFunction $function, CompiledFunction $compiled): void + { + $body = $function->getBody(); + if (!$body instanceof Node) { + return; + } + self::$templates ??= new \WeakMap(); + $entries = self::$templates[$body] ?? []; + $entries[CompilationFailures::signature($function, 'bytecode')] = clone $compiled; + self::$templates[$body] = $entries; + } +} diff --git a/src/Bytecode/CompiledFunction.php b/src/Bytecode/CompiledFunction.php index 37706742..136bb609 100644 --- a/src/Bytecode/CompiledFunction.php +++ b/src/Bytecode/CompiledFunction.php @@ -166,6 +166,8 @@ final class CompiledFunction * executeFunction can hand the closure environment to the * Frame directly and skip the per-call createChild * allocation. + * @param bool $parametersFromEnvironment Read initialized parameter + * bindings after the interpreter applies defaults and parameter TDZ. */ public function __construct( public readonly array $code, @@ -178,6 +180,7 @@ public function __construct( public readonly bool $needsThis = true, public readonly bool $needsArgsBinding = true, public readonly bool $canSkipEnvAlloc = false, + public readonly bool $parametersFromEnvironment = false, ) { } } diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index 26fd38fc..dd2a98b5 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -90,6 +90,15 @@ final class Compiler /** @var list */ private array $paramSlots = []; + private bool $parametersFromEnvironment = false; + + private bool $tailCallsEnabled = false; + + private bool $hasTailCalls = false; + + /** @var array Captured function-scope bindings and declaration kinds. */ + private array $capturedLocals = []; + /** @var list<\Phasis\Ast\Node> */ private array $nestedFns = []; @@ -238,6 +247,26 @@ final class Compiler private bool $thisFromFrame = false; public function compile(JsFunction $fn): CompiledFunction + { + $template = CompilationTemplates::get($fn); + if ($template !== null) { + return $template; + } + $reason = CompilationFailures::get($fn, 'bytecode'); + if ($reason !== null) { + throw new CompilerBailout($reason); + } + try { + $compiled = $this->compileFunction($fn); + CompilationTemplates::remember($fn, $compiled); + return $compiled; + } catch (CompilerBailout $error) { + CompilationFailures::remember($fn, 'bytecode', $error->getMessage()); + throw $error; + } + } + + private function compileFunction(JsFunction $fn): CompiledFunction { if ($fn->isAsync() || $fn->isNative() || $fn->isClassConstructor()) { throw new CompilerBailout('non-ordinary function kind'); @@ -256,15 +285,9 @@ public function compile(JsFunction $fn): CompiledFunction } $this->inGenerator = true; } - // Strict-mode bodies that have a return-with-call shape need - // tail-call optimisation per spec. The bytecode VM emits - // CALL+RET which recurses normally and grows the PHP stack - // (test262 tco-* tests at $MAX_ITERATIONS=100000 hit - // maxCallDepth). Bail compile so the tree-walker (which - // returns TailCallThunk + callFunction trampolines) handles - // these. Mirrors the same bail in JsToPhp::compile. - if ($fn->isStrict() && self::bytecodeBailsForTailCall($fn->getBody())) { - throw new CompilerBailout('strict-mode tail-call body'); + $this->tailCallsEnabled = $fn->isStrict() && !$fn->isGenerator(); + if ($this->tailCallsEnabled) { + $this->checkTailCallShapes($fn->getBody()); } $body = $fn->getBody(); $isExpressionBody = !$body instanceof BlockStatement; @@ -283,6 +306,13 @@ public function compile(JsFunction $fn): CompiledFunction } foreach ($fn->getParams() as $param) { + if ($param instanceof AssignmentPattern && $param->left instanceof Identifier && !$fn->isGenerator()) { + if ($this->parameterInitializerCanCapture($param->right)) { + throw new CompilerBailout('parameter initializer captures bindings'); + } + $this->parametersFromEnvironment = true; + $param = $param->left; + } if (!$param instanceof Identifier) { throw new CompilerBailout('non-simple parameter'); } @@ -291,10 +321,11 @@ public function compile(JsFunction $fn): CompiledFunction } if ($isExpressionBody) { + $this->collectCapturedLocals($body); // Arrow expression body: nothing to pre-walk (no var // decls allowed), no TDZ, no statements. Compile the // single expression directly. - $this->compileExpression($body); + $this->compileReturnExpression($body); $this->emit(Op::RET); // needsThis now means "the env must carry a `this` binding": // true when the body's own bytecode walks the env for this @@ -312,8 +343,10 @@ public function compile(JsFunction $fn): CompiledFunction slotCount: max(1, count($this->localNames)), nestedFns: $this->nestedFns, needsThis: $needsEnvThis, - needsArgsBinding: false, - canSkipEnvAlloc: !$needsEnvThis, + needsArgsBinding: $this->capturedLocals !== [], + canSkipEnvAlloc: !$needsEnvThis && !$this->parametersFromEnvironment + && $this->capturedLocals === [] && !$this->hasTailCalls, + parametersFromEnvironment: $this->parametersFromEnvironment, ); $cf->callMethodDisplays = $this->callMethodDisplays; return $cf; @@ -322,6 +355,7 @@ public function compile(JsFunction $fn): CompiledFunction // Pre-walk: collect every var/let/const/function name in // the body so each is assigned a unique frame slot up front. $this->collectFunctionLocals($body->body); + $this->collectCapturedLocals($body); // TDZ guard: bail if any let/const name appears in source // BEFORE its declaration. @@ -358,8 +392,10 @@ public function compile(JsFunction $fn): CompiledFunction slotCount: max(1, count($this->localNames)), nestedFns: $this->nestedFns, needsThis: $needsEnvThis, - needsArgsBinding: false, - canSkipEnvAlloc: !$needsEnvThis, + needsArgsBinding: $this->capturedLocals !== [], + canSkipEnvAlloc: !$needsEnvThis && !$this->parametersFromEnvironment + && $this->capturedLocals === [] && $this->nestedFns === [] && !$this->hasTailCalls, + parametersFromEnvironment: $this->parametersFromEnvironment, ); $cf->handlers = $this->handlers; $cf->classNodes = $this->classNodes; @@ -367,6 +403,49 @@ public function compile(JsFunction $fn): CompiledFunction return $cf; } + private function checkTailCallShapes(Node $node): void + { + if ( + $node instanceof FunctionDeclaration + || $node instanceof \Phasis\Ast\Expression\FunctionExpression + || $node instanceof \Phasis\Ast\Expression\ArrowFunction + || $node instanceof \Phasis\Ast\Declaration\ClassDeclaration + || $node instanceof \Phasis\Ast\Expression\ClassExpression + ) { + return; + } + if ($node instanceof \Phasis\Ast\Statement\TryStatement && self::bytecodeBailsForTailCall($node)) { + throw new CompilerBailout('tail calls in try statement'); + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node) { + $this->checkTailCallShapes($child); + } + } + } + } + + private function parameterInitializerCanCapture(Node $node): bool + { + if ( + $node instanceof \Phasis\Ast\Expression\FunctionExpression + || $node instanceof \Phasis\Ast\Expression\ArrowFunction + || $node instanceof \Phasis\Ast\Expression\ClassExpression + || ($node instanceof Identifier && $node->name === 'eval') + ) { + return true; + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node && $this->parameterInitializerCanCapture($child)) { + return true; + } + } + } + return false; + } + /** * Top-level Program compile entry. Mirrors compile() but operates on a * Program node instead of a JsFunction. Returns a CompiledFunction whose diff --git a/src/Bytecode/JsToPhp.php b/src/Bytecode/JsToPhp.php index 88dbea36..f5bee971 100644 --- a/src/Bytecode/JsToPhp.php +++ b/src/Bytecode/JsToPhp.php @@ -203,6 +203,18 @@ final class JsToPhp private bool $numericMode = false; public static function compile(JsFunction $fn): ?\Closure + { + if (CompilationFailures::get($fn, 'php') !== null) { + return null; + } + $compiled = self::compileFunction($fn); + if ($compiled === null) { + CompilationFailures::remember($fn, 'php', 'unsupported syntax'); + } + return $compiled; + } + + private static function compileFunction(JsFunction $fn): ?\Closure { // Class / derived constructors and method-bound functions // (homeObject != null) carry spec semantics — `this`, `super`, diff --git a/src/Bytecode/Op.php b/src/Bytecode/Op.php index 48f28455..645b7b19 100644 --- a/src/Bytecode/Op.php +++ b/src/Bytecode/Op.php @@ -34,6 +34,7 @@ final class Op public const LOAD_TRUE = 13; // push JsBoolean(true) public const LOAD_FALSE = 14; // push JsBoolean(false) public const LOAD_THIS = 15; // push this via env chain walk (arrow lexical-this, derived-ctor TDZ, generators) + public const NEW_REGEXP = 16; // N N — create a fresh RegExp from pattern and flags strings. public const LOAD_THIS_FRAME = 111; // push frame->thisValue directly (ordinary fn bodies; receiver fixed per call) // ---- Locals --------------------------------------------------------- @@ -62,6 +63,10 @@ final class Op // VM-instantiated JsFunction value so both // the frame slot and env binding stay in // sync (closure-capture safety). + public const INITIALIZE_NAME = 33; // N: initialize a captured lexical binding, leaving TDZ. + public const ARRAY_APPEND = 34; // Append a data element to the array below it on the stack. + public const ARRAY_SPREAD = 35; // Consume an iterable into the array below it on the stack. + public const ARRAY_HOLE = 36; // Extend the array's length without defining an element. // ---- Arithmetic & comparison ---------------------------------------- public const ADD = 40; @@ -138,6 +143,8 @@ final class Op // return YieldResult to VM caller. Resume // re-enters at pc+1 with the resumed value // pushed onto the operand stack. + public const TAIL_CALL = 85; // I — CALL layout, produce a trampoline thunk for RET + public const TAIL_CALL_METHOD = 86; // I — CALL_METHOD layout, preserve the receiver in the thunk // ---- Object / array literals & member access ---------------------- public const NEW_OBJECT = 90; // push new {} (with %ObjectPrototype%) @@ -148,6 +155,8 @@ final class Op public const LOAD_COMPUTED = 95; // pop key, pop obj; push obj[key] public const STORE_MEMBER = 96; // N — pop val, pop obj; obj.name = val (writes, no push) public const STORE_COMPUTED = 97;// pop val, key, obj; obj[key] = val + public const SET_LITERAL_PROTOTYPE = 98; // pop value; initialize the remaining object's prototype if object/null. + public const TO_PROPERTY_KEY = 99; // replace the top value with its string or Symbol property key. // ---- Function expressions & arrows --------------------------------- public const MAKE_FUNCTION = 100; // I — index into CompiledFunction::$nestedFns; @@ -164,6 +173,9 @@ final class Op // ---- Throw ----------------------------------------------------------- public const THROW = 110; // pop value, raise as JsThrowable. + public const TYPEOF_NAME = 112; // N: typeof a binding, allowing unresolvable names but preserving TDZ. + public const DELETE_NAME = 113; // N: delete an environment binding without reading its value. + public const DELETE_PROPERTY = 114; // pop key and base, delete the property, push the Boolean result. public const LOOP_INIT = 120; public const LOOP_TICK = 121; @@ -212,10 +224,16 @@ public static function operandCount(int $op): int case self::RET: case self::YIELD: case self::NEW_OBJECT: + case self::ARRAY_APPEND: + case self::ARRAY_SPREAD: + case self::ARRAY_HOLE: + case self::SET_LITERAL_PROTOTYPE: + case self::TO_PROPERTY_KEY: case self::SET_COMPUTED: case self::LOAD_COMPUTED: case self::STORE_COMPUTED: case self::THROW: + case self::DELETE_PROPERTY: case self::NOP: return 0; // 1-operand opcodes @@ -227,6 +245,9 @@ public static function operandCount(int $op): int case self::LOAD_NAME: case self::STORE_NAME: case self::DEFINE_NAME: + case self::INITIALIZE_NAME: + case self::TYPEOF_NAME: + case self::DELETE_NAME: case self::JUMP: case self::JUMP_IF_TRUE: case self::JUMP_IF_FALSE: @@ -234,6 +255,8 @@ public static function operandCount(int $op): int case self::JUMP_IF_TRUTHY_KEEP: case self::JUMP_IF_FALSY_KEEP: case self::CALL: + case self::TAIL_CALL: + case self::TAIL_CALL_METHOD: case self::NEW_CALL: case self::NEW_ARRAY: case self::SET_PROP: @@ -245,6 +268,9 @@ public static function operandCount(int $op): int case self::LOOP_INIT: case self::LOOP_TICK: return 1; + // 2-operand opcodes + case self::NEW_REGEXP: + return 2; // 3-operand opcodes case self::JUMP_IF_LOCAL_GE_CONST: case self::JUMP_IF_LOCAL_GE_LOCAL: diff --git a/src/Bytecode/Parts/CompilerBailoutAnalysis.php b/src/Bytecode/Parts/CompilerBailoutAnalysis.php index 708665f2..6aa63ce0 100644 --- a/src/Bytecode/Parts/CompilerBailoutAnalysis.php +++ b/src/Bytecode/Parts/CompilerBailoutAnalysis.php @@ -465,14 +465,7 @@ private function collectLetConstOrderNode(Node $node, array &$out, int &$idx): v if ($decl->init !== null) { $this->collectLetConstOrderNode($decl->init, $out, $idx); } - if ( - $decl->id instanceof Identifier - && !isset($out[$decl->id->name]) - && !isset($this->varDeclaredNames[$decl->id->name]) - ) { - $idx++; - $out[$decl->id->name] = $idx; - } + $this->collectPatternInitializationOrder($decl->id, $out, $idx); } return; } @@ -529,7 +522,7 @@ private function checkTdzReferencesNode(Node $node, array $declOrder, int &$idx) { $idx++; $myIdx = $idx; - if ($node instanceof Identifier && isset($declOrder[$node->name])) { + if ($node instanceof Identifier && isset($declOrder[$node->name]) && !isset($this->capturedLocals[$node->name])) { if ($myIdx < $declOrder[$node->name]) { throw new CompilerBailout('let/const used before declaration: ' . $node->name); } @@ -543,12 +536,7 @@ private function checkTdzReferencesNode(Node $node, array $declOrder, int &$idx) if ($decl->init !== null) { $this->checkTdzReferencesNode($decl->init, $declOrder, $idx); } - if ($decl->id instanceof Identifier) { - $idx++; - } elseif ($decl->id instanceof Node) { - // Destructuring decl id — bailout already triggers. - $this->checkTdzReferencesNode($decl->id, $declOrder, $idx); - } + $this->checkPatternInitializationReferences($decl->id, $declOrder, $idx); } return; } @@ -559,9 +547,9 @@ private function checkTdzReferencesNode(Node $node, array $declOrder, int &$idx) || $node instanceof \Phasis\Ast\Expression\ClassExpression || $node instanceof \Phasis\Ast\Declaration\ClassDeclaration ) { - // Closures: any reference to outer let/const we haven't - // yet declared would race with slot init at call time. - $this->scanIdentifiersForTdz($node, $declOrder, $myIdx); + // Captured function-scope lexicals resolve through real TDZ records. + // The capture walk already rejects unsupported block captures and + // excludes identifiers shadowed by the nested function's bindings. return; } // MemberExpression `obj.prop`: the `property` is a name, not @@ -596,40 +584,66 @@ private function checkTdzReferencesNode(Node $node, array $declOrder, int &$idx) } } - /** - * Scan an inner closure for identifier references to outer let/ - * const bindings; if any are still pre-declaration, bail. - * - * @param array $declOrder - */ - private function scanIdentifiersForTdz(Node $node, array $declOrder, int $closurePos): void + /** @param array $order */ + private function collectPatternInitializationOrder(Node $pattern, array &$order, int &$index): void { - if ($node instanceof Identifier) { - if (isset($declOrder[$node->name]) && $closurePos < $declOrder[$node->name]) { - throw new CompilerBailout('inner closure refs let/const pre-decl: ' . $node->name); + if ($pattern instanceof Identifier) { + $index++; + if (!isset($order[$pattern->name]) && !isset($this->varDeclaredNames[$pattern->name])) { + $order[$pattern->name] = $index; + } + } elseif ($pattern instanceof AssignmentPattern) { + $this->collectLetConstOrderNode($pattern->right, $order, $index); + $this->collectPatternInitializationOrder($pattern->left, $order, $index); + } elseif ($pattern instanceof ObjectPattern) { + foreach ($pattern->properties as $property) { + if ($property instanceof \Phasis\Ast\Pattern\AssignmentProperty) { + if ($property->computed) { + $this->collectLetConstOrderNode($property->key, $order, $index); + } + $this->collectPatternInitializationOrder($property->value, $order, $index); + } elseif ($property instanceof RestElement) { + $this->collectPatternInitializationOrder($property->argument, $order, $index); + } } - return; - } - if ($node instanceof MemberExpression && !$node->computed) { - $this->scanIdentifiersForTdz($node->object, $declOrder, $closurePos); - return; - } - if ($node instanceof Property && !$node->computed) { - $this->scanIdentifiersForTdz($node->value, $declOrder, $closurePos); - return; + } elseif ($pattern instanceof ArrayPattern) { + foreach ($pattern->elements as $element) { + if ($element !== null) { + $this->collectPatternInitializationOrder($element, $order, $index); + } + } + } elseif ($pattern instanceof RestElement) { + $this->collectPatternInitializationOrder($pattern->argument, $order, $index); } - $ref = new \ReflectionObject($node); - foreach ($ref->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { - $value = $prop->getValue($node); - if ($value instanceof Node) { - $this->scanIdentifiersForTdz($value, $declOrder, $closurePos); - } elseif (is_array($value)) { - foreach ($value as $item) { - if ($item instanceof Node) { - $this->scanIdentifiersForTdz($item, $declOrder, $closurePos); + } + + /** @param array $order */ + private function checkPatternInitializationReferences(Node $pattern, array $order, int &$index): void + { + if ($pattern instanceof Identifier) { + $index++; + } elseif ($pattern instanceof AssignmentPattern) { + $this->checkTdzReferencesNode($pattern->right, $order, $index); + $this->checkPatternInitializationReferences($pattern->left, $order, $index); + } elseif ($pattern instanceof ObjectPattern) { + foreach ($pattern->properties as $property) { + if ($property instanceof \Phasis\Ast\Pattern\AssignmentProperty) { + if ($property->computed) { + $this->checkTdzReferencesNode($property->key, $order, $index); } + $this->checkPatternInitializationReferences($property->value, $order, $index); + } elseif ($property instanceof RestElement) { + $this->checkPatternInitializationReferences($property->argument, $order, $index); + } + } + } elseif ($pattern instanceof ArrayPattern) { + foreach ($pattern->elements as $element) { + if ($element !== null) { + $this->checkPatternInitializationReferences($element, $order, $index); } } + } elseif ($pattern instanceof RestElement) { + $this->checkPatternInitializationReferences($pattern->argument, $order, $index); } } @@ -775,6 +789,7 @@ private function scanForOuterCapture(?Node $node, array $shadow): bool $name = $node->name; if ( isset($this->localSlots[$name]) + && !isset($this->capturedLocals[$name]) && !isset($shadow[$name]) ) { return true; diff --git a/src/Bytecode/Parts/CompilerEmit.php b/src/Bytecode/Parts/CompilerEmit.php index 98c5d2ec..c347233e 100644 --- a/src/Bytecode/Parts/CompilerEmit.php +++ b/src/Bytecode/Parts/CompilerEmit.php @@ -68,7 +68,32 @@ private function emit(int $op, int ...$operands): void private function emitStoreLocal(int $slot): void { - $this->emit(Op::STORE_LOCAL, $slot); + $name = $this->localNames[$slot]; + if (isset($this->capturedLocals[$name])) { + $this->emit(Op::STORE_NAME, $this->internName($name)); + } else { + $this->emit(Op::STORE_LOCAL, $slot); + } + } + + private function emitLoadLocal(int $slot): void + { + $name = $this->localNames[$slot]; + if (isset($this->capturedLocals[$name])) { + $this->emit(Op::LOAD_NAME, $this->internName($name)); + } else { + $this->emit(Op::LOAD_LOCAL, $slot); + } + } + + private function emitInitializeLocal(int $slot, string $kind): void + { + $name = $this->localNames[$slot]; + if (($kind === 'let' || $kind === 'const') && isset($this->capturedLocals[$name])) { + $this->emit(Op::INITIALIZE_NAME, $this->internName($name)); + } else { + $this->emitStoreLocal($slot); + } } /** diff --git a/src/Bytecode/Parts/CompilerExpression.php b/src/Bytecode/Parts/CompilerExpression.php index 17b0162a..a10dae59 100644 --- a/src/Bytecode/Parts/CompilerExpression.php +++ b/src/Bytecode/Parts/CompilerExpression.php @@ -207,14 +207,13 @@ private function compileObjectLiteral(ObjectExpression $node): void if ($prop->method) { throw new CompilerBailout('method shorthand'); } - // Property NamedEvaluation must use the evaluated key, including - // Symbol descriptions and names visible during class evaluation. - if (self::initNeedsNamedEvaluation($prop->value)) { - throw new CompilerBailout('object property needs named evaluation'); - } if ($prop->computed) { - // [expr]: val — push key, push val, SET_COMPUTED. + if (self::initNeedsNamedEvaluation($prop->value)) { + throw new CompilerBailout('object property needs named evaluation'); + } + // Coercion of the key must finish before evaluating the value. $this->compileExpression($prop->key); + $this->emit(Op::TO_PROPERTY_KEY); $this->compileExpression($prop->value); $this->emit(Op::SET_COMPUTED); continue; @@ -230,12 +229,14 @@ private function compileObjectLiteral(ObjectExpression $node): void } else { throw new CompilerBailout('non-identifier non-literal key'); } - // `__proto__: value` is the special prototype-set sugar - // when shorthand=false (method=false has already bailed - // above); the tree-walker handles it via setPrototype rather - // than defining a property. Bail to keep spec semantics. if ($name === '__proto__' && !$prop->shorthand) { - throw new CompilerBailout('__proto__ literal'); + $this->compileExpression($prop->value); + $this->emit(Op::SET_LITERAL_PROTOTYPE); + continue; + } + // Prototype initializers do not perform property name inference. + if (self::initNeedsNamedEvaluation($prop->value)) { + throw new CompilerBailout('object property needs named evaluation'); } $this->compileExpression($prop->value); $this->emit(Op::SET_PROP, $this->internName($name)); @@ -245,8 +246,8 @@ private function compileObjectLiteral(ObjectExpression $node): void private function compileArrayLiteral(ArrayExpression $node): void { - // Use NEW_ARRAY for dense literals with no holes / - // spread. Sparse / spread arrays bail. + // Dense literals can pack their values in one instruction. Spread + // operands must finish iteration before evaluating the next element. $count = count($node->elements); $hasHoles = false; $hasSpread = false; @@ -258,7 +259,19 @@ private function compileArrayLiteral(ArrayExpression $node): void } } if ($hasHoles || $hasSpread) { - throw new CompilerBailout('array literal with hole/spread'); + $this->emit(Op::NEW_ARRAY, 0); + foreach ($node->elements as $element) { + if ($element === null) { + $this->emit(Op::ARRAY_HOLE); + } elseif ($element instanceof SpreadElement) { + $this->compileExpression($element->argument); + $this->emit(Op::ARRAY_SPREAD); + } else { + $this->compileExpression($element); + $this->emit(Op::ARRAY_APPEND); + } + } + return; } foreach ($node->elements as $el) { $this->compileExpression($el); @@ -341,7 +354,7 @@ private function tryEmitDiscardedUpdate(\Phasis\Ast\Node $expr): bool if ($name === 'eval' || $name === 'arguments' || $name === '[[NewTarget]]') { return false; } - if (!isset($this->localSlots[$name])) { + if (!isset($this->localSlots[$name]) || isset($this->capturedLocals[$name])) { return false; } $slot = $this->localSlots[$name]; @@ -366,7 +379,7 @@ private function compileUpdate(UpdateExpression $node): void if (isset($this->constSlots[$slot])) { throw new CompilerBailout('update of const'); } - $this->emit(Op::LOAD_LOCAL, $slot); + $this->emitLoadLocal($slot); // Per §13.4 (UpdateExpression) and §6.1.6.1.10 NumericAdd: // both ++x and x++ start with ToNumber(oldValue). Op::ADD // on a JsString left operand is a string-concat, so emit @@ -405,11 +418,18 @@ private function compileUnary(UnaryExpression $node): void throw new CompilerBailout('postfix unary'); } $op = $node->operator; - // `delete`, `typeof` on identifiers, `void` are easy enough, - // but the spec edge cases (delete on with-bindings, typeof - // on undeclared) are subtle. Bail to tree-walker for safety. - if ($op === 'delete' || $op === 'typeof') { - throw new CompilerBailout('delete/typeof'); + if ($op === 'typeof') { + if ($node->argument instanceof Identifier && !isset($this->localSlots[$node->argument->name])) { + $this->emit(Op::TYPEOF_NAME, $this->internName($node->argument->name)); + } else { + $this->compileExpression($node->argument); + $this->emit(Op::TYPEOF); + } + return; + } + if ($op === 'delete') { + $this->compileDelete($node->argument); + return; } if ($op === 'void') { $this->compileExpression($node->argument); @@ -436,6 +456,45 @@ private function compileUnary(UnaryExpression $node): void } } + private function compileDelete(Node $argument): void + { + if ($argument instanceof Identifier) { + if ($argument->name === '[[NewTarget]]' || $argument->name === '[[ImportMeta]]') { + $this->emit(Op::LOAD_TRUE); + } elseif (isset($this->localSlots[$argument->name])) { + // Deleting a declarative binding does not read its value or TDZ. + $this->emit(Op::LOAD_FALSE); + } else { + $this->emit(Op::DELETE_NAME, $this->internName($argument->name)); + } + return; + } + if ($argument instanceof MemberExpression) { + if ( + $argument->optional || $argument->property instanceof PrivateIdentifier + || ($argument->object instanceof Identifier && $argument->object->name === 'super') + ) { + throw new CompilerBailout('optional/private/super delete reference'); + } + $this->compileExpression($argument->object); + if ($argument->computed) { + $this->compileExpression($argument->property); + } elseif ($argument->property instanceof Identifier) { + $this->emit(Op::LOAD_CONST, $this->internConst( + new JsString($argument->property->name), + 's:' . $argument->property->name, + )); + } else { + throw new CompilerBailout('non-identifier delete property'); + } + $this->emit(Op::DELETE_PROPERTY); + return; + } + $this->compileExpression($argument); + $this->emit(Op::POP); + $this->emit(Op::LOAD_TRUE); + } + private function compileLogical(LogicalExpression $node): void { // && and ||: short-circuit by peeking. @@ -492,10 +551,12 @@ private function compileLiteral(Literal $node): void return; } if (is_string($value)) { - // RegExp literal: bail — fresh regex per evaluation, plus - // BigInt literal sharing the string slot. if (str_starts_with($node->raw, '__REGEXP__')) { - throw new CompilerBailout('regexp literal'); + if (!preg_match('#^/(.+)/([dgimsuvy]*)$#s', $value, $parts)) { + throw new CompilerBailout('invalid regexp literal'); + } + $this->emit(Op::NEW_REGEXP, $this->internName($parts[1]), $this->internName($parts[2])); + return; } if (str_starts_with($node->raw, '__BIGINT__')) { throw new CompilerBailout('bigint literal'); @@ -510,12 +571,8 @@ private function compileLiteral(Literal $node): void private function compileIdentifier(Identifier $node): void { $name = $node->name; - if ($name === 'undefined') { - $this->emit(Op::LOAD_UNDEF); - return; - } if (isset($this->localSlots[$name])) { - $this->emit(Op::LOAD_LOCAL, $this->localSlots[$name]); + $this->emitLoadLocal($this->localSlots[$name]); return; } // Free variable — let the VM walk the env via the existing @@ -728,7 +785,7 @@ private function compileAssignment(AssignmentExpression $node): void // Compound on identifier: // load lhs; compile rhs; ; DUP; STORE_* if ($isLocal) { - $this->emit(Op::LOAD_LOCAL, $this->localSlots[$name]); + $this->emitLoadLocal($this->localSlots[$name]); } else { $this->emit(Op::LOAD_NAME, $this->internName($name)); } diff --git a/src/Bytecode/Parts/CompilerScope.php b/src/Bytecode/Parts/CompilerScope.php index 14067ea5..055b7172 100644 --- a/src/Bytecode/Parts/CompilerScope.php +++ b/src/Bytecode/Parts/CompilerScope.php @@ -59,6 +59,183 @@ */ trait CompilerScope { + /** + * Captured names use the same Environment records as interpreted closures. + * Only function-scope bindings are supported. Block and iteration captures + * need distinct records and remain on the interpreter path. + */ + private function collectCapturedLocals(Node $body): void + { + $references = []; + $this->collectNestedLocalReferences($body, false, $references); + if ($references === []) { + return; + } + if ($this->inGenerator) { + throw new CompilerBailout('generator captures local bindings'); + } + $supported = []; + foreach ($this->paramSlots as $slot) { + $supported[$this->localNames[$slot]] = 'parameter'; + } + foreach ($this->varDeclaredNames as $name => $_) { + $supported[$name] = 'var'; + } + if ($body instanceof BlockStatement) { + foreach ($body->body as $statement) { + if ($statement instanceof FunctionDeclaration && $statement->id !== null) { + $supported[$statement->id->name] = 'function'; + } elseif ($statement instanceof VariableDeclaration) { + foreach ($statement->declarations as $declaration) { + $bound = []; + $this->collectPatternBoundNames($declaration->id, $bound); + foreach ($bound as $name => $_) { + $supported[$name] = $statement->kind; + } + } + } + } + } + foreach ($references as $name => $_) { + if (!isset($supported[$name])) { + throw new CompilerBailout('closure captures block binding: ' . $name); + } + $this->capturedLocals[$name] = $supported[$name]; + } + } + + /** + * @param array $references + * @param array $shadow + */ + private function collectNestedLocalReferences(Node $node, bool $nested, array &$references, array $shadow = []): void + { + if ($node instanceof Identifier) { + if ($nested && isset($this->localSlots[$node->name]) && !isset($shadow[$node->name])) { + $references[$node->name] = true; + } + return; + } + if ( + $node instanceof FunctionDeclaration + || $node instanceof \Phasis\Ast\Expression\FunctionExpression + || $node instanceof \Phasis\Ast\Expression\ArrowFunction + ) { + foreach ($node->params as $parameter) { + $this->collectPatternBoundNames($parameter, $shadow); + } + if ($node instanceof \Phasis\Ast\Expression\FunctionExpression && $node->name !== null) { + $shadow[$node->name] = true; + } + foreach ($node->params as $parameter) { + $this->collectCapturePatternInitializers($parameter, true, $references, $shadow); + } + // Body var declarations cannot shadow reads from parameter defaults. + $this->collectCaptureVarNames($node->body, $shadow); + $this->collectNestedLocalReferences($node->body, true, $references, $shadow); + return; + } + if ($nested && $node instanceof BlockStatement) { + foreach ($node->body as $statement) { + if ($statement instanceof VariableDeclaration && $statement->kind !== 'var') { + foreach ($statement->declarations as $declaration) { + $this->collectPatternBoundNames($declaration->id, $shadow); + } + } elseif ( + ($statement instanceof FunctionDeclaration || $statement instanceof \Phasis\Ast\Declaration\ClassDeclaration) + && $statement->id !== null + ) { + $shadow[$statement->id->name] = true; + } + } + } + if ($node instanceof VariableDeclaration) { + foreach ($node->declarations as $declaration) { + if ($declaration->init !== null) { + $this->collectNestedLocalReferences($declaration->init, $nested, $references, $shadow); + } + $this->collectCapturePatternInitializers($declaration->id, $nested, $references, $shadow); + } + return; + } + $nested = $nested + || $node instanceof \Phasis\Ast\Expression\ClassExpression + || $node instanceof \Phasis\Ast\Declaration\ClassDeclaration; + if ($node instanceof MemberExpression && !$node->computed) { + $this->collectNestedLocalReferences($node->object, $nested, $references, $shadow); + return; + } + if ($node instanceof Property && !$node->computed) { + $this->collectNestedLocalReferences($node->value, $nested, $references, $shadow); + return; + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node) { + $this->collectNestedLocalReferences($child, $nested, $references, $shadow); + } + } + } + } + + /** + * @param array $references + * @param array $shadow + */ + private function collectCapturePatternInitializers(Node $pattern, bool $nested, array &$references, array $shadow): void + { + if ($pattern instanceof AssignmentPattern) { + $this->collectNestedLocalReferences($pattern->right, $nested, $references, $shadow); + $this->collectCapturePatternInitializers($pattern->left, $nested, $references, $shadow); + } elseif ($pattern instanceof ObjectPattern) { + foreach ($pattern->properties as $property) { + if ($property instanceof \Phasis\Ast\Pattern\AssignmentProperty) { + if ($property->computed) { + $this->collectNestedLocalReferences($property->key, $nested, $references, $shadow); + } + $this->collectCapturePatternInitializers($property->value, $nested, $references, $shadow); + } elseif ($property instanceof RestElement) { + $this->collectCapturePatternInitializers($property->argument, $nested, $references, $shadow); + } + } + } elseif ($pattern instanceof ArrayPattern) { + foreach ($pattern->elements as $element) { + if ($element !== null) { + $this->collectCapturePatternInitializers($element, $nested, $references, $shadow); + } + } + } elseif ($pattern instanceof RestElement) { + $this->collectCapturePatternInitializers($pattern->argument, $nested, $references, $shadow); + } + } + + /** @param array $shadow */ + private function collectCaptureVarNames(Node $node, array &$shadow): void + { + if ( + $node instanceof FunctionDeclaration + || $node instanceof \Phasis\Ast\Expression\FunctionExpression + || $node instanceof \Phasis\Ast\Expression\ArrowFunction + || $node instanceof \Phasis\Ast\Expression\ClassExpression + || $node instanceof \Phasis\Ast\Declaration\ClassDeclaration + ) { + return; + } + if ($node instanceof VariableDeclaration && $node->kind === 'var') { + foreach ($node->declarations as $declaration) { + $this->collectPatternBoundNames($declaration->id, $shadow); + } + return; + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node) { + $this->collectCaptureVarNames($child, $shadow); + } + } + } + } + /** Record program var bindings while reserving only lexical temporary slots. */ private function collectProgramVarLocals(Node $stmt): void { @@ -177,16 +354,22 @@ private function collectStatementLocals(Node $stmt): void } if ($decl->id instanceof ObjectPattern) { foreach ($decl->id->properties as $prop) { + $target = $prop instanceof \Phasis\Ast\Pattern\AssignmentProperty ? $prop->value : null; + if ($target instanceof AssignmentPattern) { + $target = $target->left; + } if ( $prop instanceof \Phasis\Ast\Pattern\AssignmentProperty && !$prop->computed - && !($prop->value instanceof \Phasis\Ast\Pattern\AssignmentPattern) - && $prop->value instanceof Identifier + && $target instanceof Identifier ) { - if ($isLexical && isset($this->localSlots[$prop->value->name])) { + if ($isLexical && isset($this->localSlots[$target->name])) { throw new CompilerBailout('let/const pattern shadowing'); } - $this->declareLocal($prop->value->name); + if (!$isLexical) { + $this->varDeclaredNames[$target->name] = true; + } + $this->declareLocal($target->name); continue; } throw new CompilerBailout('complex object pattern'); @@ -295,9 +478,8 @@ private function declareLocal(string $name): int * forward references resolve. Each declaration's slot was * already reserved by collectFunctionLocals. * - * Bails if the declaration captures an outer local (its inner - * body would fail the env-walk) or is a generator / async - * function (those still need the tree-walker's full prologue). + * Captured function-scope names resolve through their shared environment. + * Unsupported captures and generator/async declarations still fall back. * * @param Node[] $statements */ @@ -345,12 +527,9 @@ private function hoistFunctionDeclarations(array $statements): void * JsFunction at runtime, capturing the current Frame's env as * the closure. * - * Capture safety: the outer function's locals live in frame - * slots, NOT in the env. A nested function that references any - * outer local would walk the env chain at call time and not - * find it. Bail when such a capture exists so the tree-walker - * keeps owning the outer function (which uses env-based - * bindings the inner closure can read). + * Captured function-scope names were assigned Environment storage by the + * capture prepass. Any remaining slot capture needs scope semantics the + * VM cannot represent and stays on the tree-walker. */ private function compileNestedFunction(Node $node): void { diff --git a/src/Bytecode/Parts/CompilerStatement.php b/src/Bytecode/Parts/CompilerStatement.php index b376840a..daf523d8 100644 --- a/src/Bytecode/Parts/CompilerStatement.php +++ b/src/Bytecode/Parts/CompilerStatement.php @@ -69,7 +69,7 @@ private function compileStatement(Node $node): void if ($node->argument === null) { $this->emit(Op::LOAD_UNDEF); } else { - $this->compileExpression($node->argument); + $this->compileReturnExpression($node->argument); } $this->emit(Op::RET); return; @@ -176,30 +176,68 @@ private function compileStatement(Node $node): void throw new CompilerBailout('unsupported statement: ' . $node->type()); } + /** Compile a return value, preserving strict tail positions recursively. */ + private function compileReturnExpression(Node $expression): void + { + if ($this->tailCallsEnabled && $expression instanceof ConditionalExpression) { + $this->compileExpression($expression->test); + $alternate = $this->emitJump(Op::JUMP_IF_FALSE); + $this->compileReturnExpression($expression->consequent); + $end = $this->emitJump(Op::JUMP); + $this->patchJumpToHere($alternate); + $this->compileReturnExpression($expression->alternate); + $this->patchJumpToHere($end); + return; + } + if ($this->tailCallsEnabled && $expression instanceof LogicalExpression) { + // The left call is not in tail position: its result is tested + // before deciding whether to evaluate the right operand. + $this->compileExpression($expression->left); + if ($expression->operator === '??') { + $right = $this->emitJump(Op::JUMP_IF_NULLISH); + $end = $this->emitJump(Op::JUMP); + $this->patchJumpToHere($right); + } else { + $end = $this->emitJump($expression->operator === '&&' + ? Op::JUMP_IF_FALSY_KEEP + : Op::JUMP_IF_TRUTHY_KEEP); + } + $this->compileReturnExpression($expression->right); + $this->patchJumpToHere($end); + return; + } + if ($this->tailCallsEnabled && $expression instanceof SequenceExpression) { + $last = count($expression->expressions) - 1; + foreach ($expression->expressions as $index => $part) { + if ($index === $last) { + $this->compileReturnExpression($part); + } else { + $this->compileExpression($part); + $this->emit(Op::POP); + } + } + return; + } + $this->compileExpression($expression); + if (!$this->tailCallsEnabled || !$expression instanceof CallExpression) { + return; + } + // compileCall preserves lookup/argument order and ends in a two-word + // CALL instruction. Return a thunk through the interpreter's existing + // trampoline instead of growing either the PHP or VM call stack. + $pc = count($this->code) - 2; + $this->code[$pc] = match ($this->code[$pc]) { + Op::CALL => Op::TAIL_CALL, + Op::CALL_METHOD => Op::TAIL_CALL_METHOD, + default => throw new CompilerBailout('unsupported tail call lowering'), + }; + $this->hasTailCalls = true; + } + /** - * Lower a TryStatement to a bytecode block plus handler-table - * entries. Three shapes are supported: - * - * - try / catch (Phase 1): one handler protecting the try body; - * on throw, the VM stores the value in the catch param slot - * and jumps to the catch body. Normal exit JUMPs past catch. - * - * - try / finally (Phase 2): the finally body is inlined twice — - * once on the normal exit path, once on the exception-rethrow - * path that runs after the handler captures the thrown value. - * - * - try / catch / finally (Phase 2): both handlers are emitted. - * Handler1 covers the try body and routes the exception - * through the catch body, then to the normal-finally inline - * (the catch already swallowed the original exception). - * Handler2 covers the catch body and routes any catch-body - * exception to the rethrow-finally inline so the catch's - * exception still surfaces after finally runs. - * - * Phase 2 enforces (via finallyLoopBoundaries / finallyDepth) that - * no return / break / continue escapes the protected blocks; those - * cases bail to the tree-walker because the inlined-finally - * approach would otherwise need to inline at every exit point. + * Lower try/catch/finally through handlers and duplicated finally bodies. + * Returns and loop exits that would escape a protected finally block bail + * to the tree-walker rather than bypassing its completion semantics. */ private function compileTryCatch(\Phasis\Ast\Statement\TryStatement $node): void { @@ -401,7 +439,7 @@ private function tryEmitFusedLoopTest(\Phasis\Ast\Node $test): int } $left = $test->left; $right = $test->right; - if (!$left instanceof Identifier || !isset($this->localSlots[$left->name])) { + if (!$left instanceof Identifier || !isset($this->localSlots[$left->name]) || isset($this->capturedLocals[$left->name])) { return -1; } $localSlot = $this->localSlots[$left->name]; @@ -422,7 +460,7 @@ private function tryEmitFusedLoopTest(\Phasis\Ast\Node $test): int $this->code[] = 0; // placeholder offset return $opcodePc; } - if ($right instanceof Identifier && isset($this->localSlots[$right->name])) { + if ($right instanceof Identifier && isset($this->localSlots[$right->name]) && !isset($this->capturedLocals[$right->name])) { $rightSlot = $this->localSlots[$right->name]; $opcodePc = count($this->code); $this->code[] = $op === '<' ? Op::JUMP_IF_LOCAL_GE_LOCAL : Op::JUMP_IF_LOCAL_GT_LOCAL; @@ -588,7 +626,8 @@ private function compileVarDecl(VariableDeclaration $node): void if ($prop->computed) { throw new CompilerBailout('computed key in pattern'); } - if (!($prop->value instanceof Identifier)) { + $target = $prop->value instanceof AssignmentPattern ? $prop->value->left : $prop->value; + if (!$target instanceof Identifier) { throw new CompilerBailout('non-identifier pattern target'); } $keyName = $prop->key instanceof Identifier @@ -600,8 +639,20 @@ private function compileVarDecl(VariableDeclaration $node): void $this->emit(Op::DUP); } $this->emit(Op::LOAD_MEMBER, $this->internName($keyName)); - $slot = $this->localSlots[$prop->value->name] ?? $this->declareLocal($prop->value->name); - $this->emitStoreLocal($slot); + if ($prop->value instanceof AssignmentPattern) { + if (self::initNeedsNamedEvaluation($prop->value->right)) { + throw new CompilerBailout('pattern initializer needs named evaluation'); + } + $this->emit(Op::DUP); + $this->emit(Op::LOAD_UNDEF); + $this->emit(Op::SEQ); + $provided = $this->emitJump(Op::JUMP_IF_FALSE); + $this->emit(Op::POP); + $this->compileExpression($prop->value->right); + $this->patchJumpToHere($provided); + } + $slot = $this->localSlots[$target->name] ?? $this->declareLocal($target->name); + $this->emitInitializeLocal($slot, $node->kind); if ($node->kind === 'const') { $this->constSlots[$slot] = true; } @@ -636,11 +687,15 @@ private function compileVarDecl(VariableDeclaration $node): void throw new CompilerBailout('var init needs named evaluation'); } $this->compileExpression($decl->init); - $this->emitStoreLocal($slot); + $this->emitInitializeLocal($slot, $node->kind); } else { if ($node->kind === 'const') { throw new CompilerBailout('const without initializer'); } + if ($node->kind === 'let' && isset($this->capturedLocals[$name])) { + $this->emit(Op::LOAD_UNDEF); + $this->emitInitializeLocal($slot, $node->kind); + } } if ($node->kind === 'const') { $this->constSlots[$slot] = true; diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 5fd34b75..4014c4f2 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -658,6 +658,9 @@ private function inlineStringSplit(JsString $receiver, array $args, int $argc): if ($sepArg->value === '') { return null; } + if (!mb_check_encoding($receiver->value, 'UTF-8') || !mb_check_encoding($sepArg->value, 'UTF-8')) { + return null; + } $parts = explode($sepArg->value, $receiver->value); $arr = new \Phasis\Value\JsArray(); foreach ($parts as $p) { @@ -804,6 +807,13 @@ public function execute( $stack[$sp++] = $consts[$code[$pc + 1]]; $pc += 2; break; + case Op::NEW_REGEXP: + $stack[$sp++] = $this->interp->createRegExpFromConstructor( + $names[$code[$pc + 1]], + $names[$code[$pc + 2]], + ); + $pc += 3; + break; case Op::LOAD_UNDEF: $stack[$sp++] = $undef; $pc++; @@ -898,6 +908,10 @@ public function execute( $env->defineVar($names[$code[$pc + 1]], $stack[--$sp]); $pc += 2; break; + case Op::INITIALIZE_NAME: + $env->initialize($names[$code[$pc + 1]], $stack[--$sp]); + $pc += 2; + break; // ---- Arithmetic ------------------------------------------ case Op::ADD: @@ -1208,6 +1222,30 @@ public function execute( $stack[$sp++] = TypeConversion::toBoolean($v) ? $false : $true; $pc++; break; + case Op::TYPEOF: + $stack[$sp - 1] = AbstractOperations::typeofOperator($stack[$sp - 1]); + $pc++; + break; + case Op::TYPEOF_NAME: + $name = $names[$code[$pc + 1]]; + $stack[$sp++] = $env->has($name) + ? AbstractOperations::typeofOperator($env->get($name)) + : new JsString('undefined'); + $pc += 2; + break; + case Op::DELETE_NAME: + if ($strict) { + throw new \Phasis\Exceptions\SyntaxError('Delete of an unqualified identifier in strict mode.'); + } + $stack[$sp++] = $env->deleteBinding($names[$code[$pc + 1]]) ? $true : $false; + $pc += 2; + break; + case Op::DELETE_PROPERTY: + $key = $stack[--$sp]; + $object = $stack[--$sp]; + $stack[$sp++] = AbstractOperations::deletePropertyReference($object, $key, $strict) ? $true : $false; + $pc++; + break; case Op::NEG: $v = $stack[--$sp]; if ($v instanceof JsNumber) { @@ -1402,6 +1440,25 @@ public function execute( break; // ---- Calls / return ------------------------------------- + case Op::TAIL_CALL: + case Op::TAIL_CALL_METHOD: + $argc = $code[$pc + 1]; + $base = $sp - $argc; + $args = $argc === 0 ? [] : array_slice($stack, $base, $argc); + $callee = $stack[$base - 1]; + $methodCall = $code[$pc] === Op::TAIL_CALL_METHOD; + $receiver = $methodCall ? $stack[$base - 2] : $undef; + $sp = $base - ($methodCall ? 2 : 1); + if ($callee instanceof JsFunction) { + $stack[$sp++] = new \Phasis\Runtime\TailCallThunk($callee, $receiver, $args); + } elseif ($callee instanceof \Phasis\Value\JsProxy && $callee->isCallable()) { + $stack[$sp++] = $callee->apply($receiver, $args); + } else { + $display = $cf->callMethodDisplays[$pc] ?? (TypeConversion::toString($callee) ?: 'value'); + throw new TypeError($display . ' is not a function'); + } + $pc += 2; + break; case Op::CALL: $argc = $code[$pc + 1]; $base = $sp - $argc; @@ -1641,6 +1698,18 @@ public function execute( $stack[$sp++] = $this->interp->vmNewObject(); $pc++; break; + case Op::SET_LITERAL_PROTOTYPE: + $prototype = $stack[--$sp]; + $object = $stack[$sp - 1]; + if ($object instanceof JsObject && ($prototype instanceof JsObject || $prototype instanceof JsNull)) { + $object->setPrototype($prototype instanceof JsObject ? $prototype : null); + } + $pc++; + break; + case Op::TO_PROPERTY_KEY: + $stack[$sp - 1] = TypeConversion::toPropertyKey($stack[$sp - 1]); + $pc++; + break; case Op::NEW_ARRAY: $count = $code[$pc + 1]; $base = $sp - $count; @@ -1662,6 +1731,31 @@ public function execute( $stack[$sp++] = \Phasis\Value\JsArray::fromArray($items); $pc += 2; break; + case Op::ARRAY_APPEND: + case Op::ARRAY_SPREAD: + $value = $stack[--$sp]; + $array = $stack[$sp - 1]; + if (!$array instanceof \Phasis\Value\JsArray) { + throw new \LogicException('Array literal stack invariant violated'); + } + if ($op === Op::ARRAY_SPREAD) { + $this->interp->vmArraySpread($array, $value); + } else { + $array->defineOwnProperty( + (string) $array->getLength(), + \Phasis\Object\PropertyDescriptor::data($value, true, true, true), + ); + } + $pc++; + break; + case Op::ARRAY_HOLE: + $array = $stack[$sp - 1]; + if (!$array instanceof \Phasis\Value\JsArray) { + throw new \LogicException('Array literal stack invariant violated'); + } + $array->setLength($array->getLength() + 1); + $pc++; + break; case Op::SET_PROP: // Stack: [obj, val] -> [obj]; effect: obj.name = val. $val = $stack[--$sp]; @@ -1680,7 +1774,7 @@ public function execute( if ($obj instanceof JsObject) { $resolved = TypeConversion::toPropertyKey($key); if ($resolved instanceof \Phasis\Value\JsSymbol) { - $obj->setBySymbol($resolved, $val); + $obj->defineOwnSymbolProperty($resolved, \Phasis\Object\PropertyDescriptor::data($val)); } else { $name = $resolved instanceof JsString ? $resolved->value diff --git a/src/Engine.php b/src/Engine.php index a264228d..48c5ba5e 100644 --- a/src/Engine.php +++ b/src/Engine.php @@ -163,7 +163,11 @@ public static function getCurrentSourceURL(): ?string private ?\Closure $cssModuleResolver = null; - public function __construct(bool $eager = false) + private ?\Phasis\Node\NodeRuntime $nodeRuntime = null; + + private ?\Phasis\Node\NodeOptions $nodeOptions = null; + + public function __construct(bool $eager = false, bool $node = false) { $this->eager = $eager; $this->jsxOptions = new \Phasis\Parser\Jsx\JsxOptions(); @@ -190,6 +194,31 @@ public function __construct(bool $eager = false) // loop also installs the hook — every microtask drain from // now on rolls into a timer-fire pass. $this->eventLoop = new EventLoop($this); + if ($node) { + $this->enableNode(); + } + } + + /** Enable Node-compatible modules, globals, and host I/O for this realm. */ + public function enableNode(?\Phasis\Node\NodeOptions $options = null): void + { + if ($this->nodeRuntime !== null) { + if ($options !== null && $options !== $this->nodeOptions) { + throw new \LogicException('Node options must be supplied when Node support is first enabled.'); + } + return; + } + $this->nodeOptions = $options ?? new \Phasis\Node\NodeOptions(); + $this->moduleOptions = $this->moduleOptions->forNode(); + $this->configureModuleLoader(); + $this->nodeRuntime = new \Phasis\Node\NodeRuntime($this, $this->nodeOptions); + $this->nodeRuntime->install(); + } + + /** The optional Node runtime owned by this engine. */ + public function getNodeRuntime(): ?\Phasis\Node\NodeRuntime + { + return $this->nodeRuntime; } private function initializeGlobalObject(): void @@ -333,7 +362,7 @@ static function ( // and re-enter this accessor when an install used // defineDeletable (which doesn't sync to the // linked global object). - $value = $env->getAtDepth($name, 0) ?? JsUndefined::instance(); + $value = $env->getInstalledBinding($name) ?? JsUndefined::instance(); // Make sure the accessor is fully gone from the // global object after install. defineVar replaces // it automatically; defineDeletable does not, so @@ -352,6 +381,24 @@ static function ( $name, PropertyDescriptor::accessor( get: $getter, + set: JsFunction::fromCallable('set ' . $name, static function ( + JsValue $receiver, + array $args, + ) use ( + $name, + $registry, + $env, + $globalObj + ): JsValue { + $registry->realize($name); + $value = $args[0] ?? JsUndefined::instance(); + if ($receiver === $globalObj) { + $env->defineVar($name, $value); + } elseif ($receiver instanceof JsObject) { + $receiver->defineOwnProperty($name, PropertyDescriptor::data($value, true, true, true)); + } + return JsUndefined::instance(); + }, 1), enumerable: false, configurable: true, ), @@ -405,6 +452,13 @@ public function pendingTaskCount(): int return $this->eventLoop->pendingTaskCount(); } + /** Release host resources and pending timers. Use reset() before starting another Node program. */ + public function close(): void + { + $this->nodeRuntime?->close(); + $this->eventLoop->clearAll(); + } + /** Internal: whether this engine eagerly installs every built-in. */ public function isEager(): bool { @@ -1332,7 +1386,7 @@ private function registerLazyBuiltins(): void // --- Fetch Pack --- $reg->register( - ['EventTarget', 'Event', 'CustomEvent'], + ['EventTarget', 'Event', 'CustomEvent', 'MessageEvent'], [], static fn () => \Phasis\BuiltIn\EventTargetConstructor::install($env), ); @@ -1687,6 +1741,7 @@ private function installStubConstructor(string $name, callable $fn, int $length $this->globalEnv->defineVar($name, $constructor); // Store prototype for internal use (e.g. Interpreter::createRegExpObject). $this->globalEnv->defineVar("__{$name}Prototype__", $proto); + $this->globalEnv->setIntrinsic($name . 'Prototype', $proto); } public function eval(string $source): mixed @@ -1767,6 +1822,16 @@ public function evalAsModule(string $source, ?string $path = null): mixed public function execFile(string $path): mixed { + if ($this->nodeRuntime !== null) { + $resolved = realpath($path); + if ($resolved === false) { + throw new \RuntimeException("Cannot read file: {$path}"); + } + $this->interpreter->setCurrentModulePath($resolved); + $this->interpreter->getModuleLoader()->requireModule($resolved, $resolved); + $this->runEventLoop(); + return null; + } // ES modules (.mjs) and JSX files go through the module loader, so // their imports resolve. Like evalAsModule(), they return null. if (str_ends_with(strtolower($path), '.mjs') || $this->jsxOptions->appliesTo($path)) { @@ -1956,6 +2021,8 @@ public function getCookieJar(): mixed public function reset(): void { + $this->nodeRuntime?->close(); + $this->nodeRuntime = null; // Detach the old event loop's post-drain hook before clearing // the microtask queue. clearMicrotasks() also nulls the hook // but doing it explicitly via the loop keeps the contract @@ -1982,6 +2049,9 @@ public function reset(): void $this->initializeGlobalObject(); $this->eventLoop = new EventLoop($this); $this->eventLoop->setTimersEnabled($this->timersEnabled); + if ($this->nodeOptions !== null) { + $this->enableNode($this->nodeOptions); + } } /** diff --git a/src/Module/CommonJsLoader.php b/src/Module/CommonJsLoader.php index 6a06c806..47a54593 100644 --- a/src/Module/CommonJsLoader.php +++ b/src/Module/CommonJsLoader.php @@ -31,6 +31,17 @@ final class CommonJsLoader private ?JsObject $process = null; + private ?JsObject $cache = null; + + /** @var array */ + private array $parents = []; + + /** @var array */ + private array $syntheticParents = []; + + private ?string $mainPath = null; + private ?JsObject $mainModule = null; + public function __construct( private readonly ModuleLoader $loader, private readonly Interpreter $interpreter, @@ -44,7 +55,10 @@ public function parse(string $source): Program $newline = strcspn($source, "\r\n"); $source = str_repeat(' ', $newline) . substr($source, $newline); } - return (new Parser(self::WRAPPER_HEAD . $source . "\n})"))->parse(); + $head = $this->loader->moduleOptions()->nodeCompatible + ? '(function (exports, require, module, __filename, __dirname) {' + : self::WRAPPER_HEAD; + return (new Parser($head . $source . "\n})"))->parse(); } /** @@ -54,13 +68,22 @@ public function parse(string $source): Program */ public function run(ModuleRecord $record, string $path, Program $program): JsObject { - $module = new JsObject(); + $module = $this->newModule($path); $exports = new JsObject(); $module->set('exports', $exports); - $module->set('id', new JsString($path)); - $module->set('filename', new JsString($path)); - $module->set('loaded', new JsBoolean(false)); $record->commonJsModule = $module; + if ($this->loader->moduleOptions()->nodeCompatible) { + $this->cache()->set($path, $module); + $parent = $this->parents[$path] ?? null; + $module->set('parent', $parent ?? \Phasis\Value\JsNull::instance()); + if ($path === $this->mainPath) { + $this->mainModule = $module; + $module->set('id', new JsString('.')); + } + if ($parent !== null) { + $this->appendChild($parent, $module); + } + } $previousStrict = $this->interpreter->isStrictMode(); $this->interpreter->setStrictMode(false); @@ -72,14 +95,17 @@ public function run(ModuleRecord $record, string $path, Program $program): JsObj if (!$wrapper instanceof JsFunction) { throw new TypeError("CommonJS wrapper for '{$path}' did not produce a function"); } - $this->interpreter->callFunction($wrapper, $exports, [ + $arguments = [ $exports, $this->makeRequire($path), $module, new JsString($path), new JsString(dirname($path)), - $this->process(), - ]); + ]; + if (!$this->loader->moduleOptions()->nodeCompatible) { + $arguments[] = $this->process(); + } + $this->interpreter->callFunction($wrapper, $exports, $arguments); $module->set('loaded', new JsBoolean(true)); return $module; } @@ -90,26 +116,30 @@ public function run(ModuleRecord $record, string $path, Program $program): JsObj * property when `__esModule` is set; every own enumerable property is * also a named export. */ - public static function populateNamespace(JsObject $namespace, JsValue $exports): void + public static function populateNamespace(JsObject $namespace, JsValue $exports, bool $nodeCompatible = false): void { $default = $exports; - if ($exports instanceof JsObject && $exports->get('__esModule')->toBoolean()) { + if (!$nodeCompatible && $exports instanceof JsObject && $exports->get('__esModule')->toBoolean()) { $default = $exports->get('default'); } $namespace->defineOwnProperty('default', PropertyDescriptor::data($default, true, true, false)); + if ($nodeCompatible) { + $namespace->defineOwnProperty('module.exports', PropertyDescriptor::data($exports, true, true, false)); + } if (!$exports instanceof JsObject) { return; } foreach ($exports->getOwnEnumerableKeys() as $key) { $key = (string) $key; - if ($key === 'default') { + if ($key === 'default' || ($nodeCompatible && $key === 'module.exports')) { continue; } $namespace->defineOwnProperty($key, PropertyDescriptor::data($exports->get($key), true, true, false)); } } - private function makeRequire(string $path): JsFunction + /** Build a require function anchored to an absolute module filename. */ + public function makeRequire(string $path): JsFunction { $loader = $this->loader; $require = JsFunction::fromCallable('require', static function (JsValue $this_, array $args) use ($loader, $path): JsValue { @@ -118,14 +148,142 @@ private function makeRequire(string $path): JsFunction }, 1); $require->set('resolve', JsFunction::fromCallable('resolve', static function (JsValue $this_, array $args) use ($loader, $path): JsValue { $specifier = ($args[0] ?? JsUndefined::instance())->toJsString(); - return new JsString($loader->resolve($specifier, $path, 'require')); + $resolved = $loader->resolve($specifier, $path, 'require'); + if ($loader->moduleOptions()->nodeCompatible && str_starts_with($resolved, ModuleResolver::BUILTIN)) { + return new JsString($specifier); + } + return new JsString($resolved); }, 1)); + if ($loader->moduleOptions()->nodeCompatible) { + $require->set('cache', $this->cache()); + $require->defineOwnProperty('main', PropertyDescriptor::accessor( + JsFunction::fromCallable('get main', fn (): JsValue => $this->mainModule ?? JsUndefined::instance()), + null, + true, + true, + )); + } return $require; } + /** Record the requiring module before a child executes, including cyclic imports. */ + public function prepareRequire(string $path, string $referrer): void + { + if (str_starts_with($path, ModuleResolver::BUILTIN)) { + return; + } + if ($path === $referrer && $this->mainPath === null && !$this->cache()->hasOwnProperty($path)) { + $this->mainPath = $path; + $this->parents[$path] = null; + return; + } + $parent = $this->cache()->get($referrer); + if (!$parent instanceof JsObject) { + $parent = $this->syntheticParents[$referrer] ??= $this->newModule($referrer); + } + if (!$this->cache()->hasOwnProperty($path)) { + $this->parents[$path] = $parent; + } + $child = $this->cache()->get($path); + if ($child instanceof JsObject) { + $this->appendChild($parent, $child); + } + } + + private function newModule(string $path): JsObject + { + $module = new JsObject(); + $module->set('id', new JsString($path)); + $module->set('filename', new JsString($path)); + $module->set('loaded', new JsBoolean(false)); + if ($this->loader->moduleOptions()->nodeCompatible) { + $module->set('path', new JsString(dirname($path))); + $module->set('children', \Phasis\Value\JsArray::fromArray([])); + $module->set('require', $this->makeRequire($path)); + $paths = []; + $directory = dirname($path); + while (true) { + if (basename($directory) !== 'node_modules') { + $paths[] = new JsString(rtrim($directory, '/') . '/node_modules'); + } + $next = dirname($directory); + if ($next === $directory) { + break; + } + $directory = $next; + } + $module->set('paths', \Phasis\Value\JsArray::fromArray($paths)); + $module->set('isPreloading', new JsBoolean(false)); + } + return $module; + } + + private function appendChild(JsObject $parent, JsObject $child): void + { + $children = $parent->get('children'); + if (!$children instanceof \Phasis\Value\JsArray) { + return; + } + for ($i = 0; $i < $children->getLength(); $i++) { + if ($children->get((string) $i) === $child) { + return; + } + } + $children->push($child); + } + + /** A failed require removes the cache entry and its edge in the parent's children array. */ + public function forgetFailedModule(string $path): void + { + $failed = $this->cache()->get($path); + $parent = $this->parents[$path] ?? null; + $children = $parent?->get('children'); + if ($children instanceof \Phasis\Value\JsArray) { + $next = 0; + $length = $children->getLength(); + for ($i = 0; $i < $length; $i++) { + $child = $children->get((string) $i); + if ($child !== $failed) { + $children->set((string) $next++, $child); + } + } + $children->setLength($next); + } + $this->cache()->forceDelete($path); + unset($this->parents[$path]); + } + + /** The shared, mutable CommonJS module cache exposed as require.cache. */ + public function cache(): JsObject + { + return $this->cache ??= JsObject::createNullPrototype(); + } + + /** Discard all module entries while preserving existing require.cache references. */ + public function resetCache(): void + { + $this->parents = []; + $this->syntheticParents = []; + $this->mainPath = null; + $this->mainModule = null; + if ($this->cache === null) { + return; + } + foreach ($this->cache->getOwnEnumerableKeys() as $key) { + $this->cache->forceDelete((string) $key); + } + } + /** The minimal `process` CommonJS modules see: only `env.NODE_ENV`. */ private function process(): JsObject { + $global = $this->interpreter->getGlobalEnv(); + if ($global->has('process')) { + $process = $global->get('process'); + if ($process instanceof JsObject) { + return $process; + } + } if ($this->process === null) { $env = new JsObject(); $env->set('NODE_ENV', new JsString($this->loader->moduleOptions()->nodeEnv)); diff --git a/src/Module/ModuleLoader.php b/src/Module/ModuleLoader.php index 7cff5ad6..b3707630 100644 --- a/src/Module/ModuleLoader.php +++ b/src/Module/ModuleLoader.php @@ -35,6 +35,9 @@ class ModuleLoader /** @var array Evaluated module cache keyed by absolute path. */ private array $modules = []; + /** @var array Module paths requested through the ES-module loader. */ + private array $namespaceRequests = []; + /** @var array Host-provided modules supporting the source import phase. */ private array $sourceModules = []; @@ -79,6 +82,9 @@ class ModuleLoader /** @var array> Built-in module export factories by specifier. */ private array $builtins = []; + /** @var array Built-ins whose require result is a CommonJS value. */ + private array $commonJsBuiltins = []; + /** @var ?\Closure(string): string */ private ?\Closure $assetResolver = null; @@ -100,7 +106,7 @@ public function __construct(Interpreter $interpreter, Environment $globalEnv) $this->globalEnv = $globalEnv; $this->resolver = new ModuleResolver( new ModuleOptions(), - fn (string $specifier): bool => isset($this->builtins[$specifier]), + fn (string $specifier): bool => isset($this->builtins[$specifier]) || isset($this->commonJsBuiltins[$specifier]), ); } @@ -125,6 +131,12 @@ public function moduleOptions(): ModuleOptions return $this->resolver->options(); } + /** Build CommonJS require for an embedded script or module.createRequire. */ + public function createRequire(string $filename): JsFunction + { + return $this->commonJs()->makeRequire($filename); + } + /** * @param array $imports */ @@ -162,6 +174,21 @@ public function registerBuiltinModule(string $specifier, \Closure $factory): voi $this->resolver->clearCache(); } + /** + * Register a native CommonJS module with an ES-module namespace view. + * + * @param \Closure(): JsValue $factory + * @param list $aliases + */ + public function registerCommonJsBuiltinModule(string $specifier, \Closure $factory, array $aliases = []): void + { + $this->commonJsBuiltins[$specifier] = $factory; + foreach ($aliases as $alias) { + $this->resolver->registerBuiltinAlias($alias, $specifier); + } + $this->resolver->clearCache(); + } + public function resolver(): ModuleResolver { return $this->resolver; @@ -194,6 +221,7 @@ public function record(string $resolved): ?ModuleRecord public function loadModule(string $specifier, ?string $referrer = null, ?string $type = null): JsObject { $resolved = $this->resolveRequest($specifier, $referrer, $type); + $this->namespaceRequests[$resolved] = true; if (isset($this->sourceModules[$specifier])) { if (!isset($this->modules[$resolved])) { $record = new ModuleRecord($resolved, JsObject::createNullPrototype()); @@ -243,6 +271,7 @@ public function loadModule(string $specifier, ?string $referrer = null, ?string throw new \Phasis\Exceptions\JsThrowable($cached->evaluationError); } } + $this->populateCommonJsNamespace($cached); return $cached->namespace; } @@ -262,11 +291,13 @@ public function loadModule(string $specifier, ?string $referrer = null, ?string public function loadModuleForDeferred(string $specifier, ?string $referrer = null): JsObject { $resolved = $this->resolve($specifier, $referrer); + $this->namespaceRequests[$resolved] = true; if (isset($this->modules[$resolved])) { // Even if the module has a cached evaluation error, return // its namespace so the deferred-namespace exotic can mirror // its export shape. The error will be re-thrown by // ensureEvaluated() when an observable trap actually fires. + $this->populateCommonJsNamespace($this->modules[$resolved]); return $this->modules[$resolved]->namespace; } return $this->loadModuleInternal($resolved, $specifier); @@ -1459,6 +1490,20 @@ public function resolve(string $specifier, ?string $referrer = null, string $kin public function requireModule(string $specifier, string $referrer): JsValue { $resolved = $this->resolve($specifier, $referrer, 'require'); + if ($this->moduleOptions()->nodeCompatible) { + $this->commonJs()->prepareRequire($resolved, $referrer); + $cache = $this->commonJs()->cache(); + $builtin = str_starts_with($resolved, ModuleResolver::BUILTIN); + $cacheKey = $builtin ? $specifier : $resolved; + $cached = $cache->get($cacheKey); + if (!str_starts_with($specifier, 'node:') && $cached instanceof JsObject) { + return $cached->get('exports'); + } + $existing = $this->modules[$resolved] ?? null; + if (!$builtin && $existing?->commonJsModule !== null && !$cache->hasOwnProperty($resolved)) { + unset($this->modules[$resolved]); + } + } $record = $this->modules[$resolved] ?? $this->linkMidEvaluation($resolved, $specifier); if ($record->commonJsProgram !== null) { $this->runCommonJs($record); @@ -1467,7 +1512,17 @@ public function requireModule(string $specifier, string $referrer): JsValue return $record->commonJsModule->get('exports'); } if (str_ends_with(strtolower($resolved), '.json')) { - return $record->namespace->get('default'); + $value = $record->namespace->get('default'); + if ($this->moduleOptions()->nodeCompatible) { + $module = new JsObject(); + $module->set('exports', $value); + $module->set('id', new JsString($resolved)); + $module->set('filename', new JsString($resolved)); + $module->set('loaded', \Phasis\Value\JsBoolean::of(true)); + $record->commonJsModule = $module; + $this->commonJs()->cache()->set($resolved, $module); + } + return $value; } if (!$record->bodyEvaluated && $record->pendingBody !== null && !$record->bodyEvaluating) { $this->evaluateModuleBodyOnDemand($record); @@ -2128,7 +2183,7 @@ private function moduleFormat(string $path): string // Application code is ES modules, as bundlers treat it. Inside // node_modules, package.json "type" decides, with Node's syntax // detection when it is absent. - if (!str_contains($path, '/node_modules/')) { + if (!str_contains($path, '/node_modules/') && !$options->nodeCompatible) { return 'esm'; } if (str_ends_with($lower, '.js')) { @@ -2144,12 +2199,14 @@ private function moduleFormat(string $path): string private function parseModule(ModuleRecord $record, string $path, string $source): \Phasis\Ast\Program { - $nodeEnv = $this->resolver->options()->nodeEnv; + $nodeEnv = $this->resolver->options()->nodeCompatible ? null : $this->resolver->options()->nodeEnv; $jsx = $this->jsxOptions !== null && $this->jsxOptions->appliesTo($path) ? $this->jsxOptions : null; $parse = static function () use ($source, $nodeEnv, $jsx): array { $parser = new Parser($source); $parser->setModuleMode(true); - $parser->setDefines(['process.env.NODE_ENV' => $nodeEnv]); + if ($nodeEnv !== null) { + $parser->setDefines(['process.env.NODE_ENV' => $nodeEnv]); + } if ($jsx !== null) { $parser->setJsxOptions($jsx); } @@ -2166,7 +2223,7 @@ private function parseCommonJs(string $source): \Phasis\Ast\Program { $cache = $this->parseCache(); $parse = fn (): \Phasis\Ast\Program => $this->commonJs()->parse($source); - return $cache === null ? $parse() : $cache->remember('commonjs', $source, [], $parse); + return $cache === null ? $parse() : $cache->remember('commonjs', $source, ['node' => $this->resolver->options()->nodeCompatible], $parse); } private function parseCache(): ?ParseCache @@ -2277,11 +2334,33 @@ private function runCommonJs(ModuleRecord $record): void $record->bodyEvaluated = true; try { $module = $this->commonJs()->run($record, $record->path, $program); - } catch (\Phasis\Exceptions\JsThrowable $e) { - $record->evaluationError = $e->jsValue; - throw $e; + } catch (\Throwable $error) { + if ($error instanceof \Phasis\Exceptions\JsThrowable) { + $record->evaluationError = $error->jsValue; + } + if ($this->moduleOptions()->nodeCompatible) { + $this->commonJs()->forgetFailedModule($record->path); + unset($this->modules[$record->path]); + } + throw $error; + } + $this->populateCommonJsNamespace($record); + } + + /** CommonJS require never reads exported getters merely to create an unused ESM view. */ + private function populateCommonJsNamespace(ModuleRecord $record): void + { + if (!$record->namespaceOpen || $record->commonJsModule === null) { + return; + } + if ($this->moduleOptions()->nodeCompatible && !isset($this->namespaceRequests[$record->path])) { + return; } - CommonJsLoader::populateNamespace($record->namespace, $module->get('exports')); + CommonJsLoader::populateNamespace( + $record->namespace, + $record->commonJsModule->get('exports'), + $this->moduleOptions()->nodeCompatible, + ); $record->namespaceOpen = false; $record->namespace->markAsModuleNamespace(); $record->namespace->preventExtensions(); @@ -2295,6 +2374,15 @@ private function linkSyntheticModule(ModuleRecord $record, string $path, string return $this->linkCommonJs($record, $path, $this->parseCommonJs($source)); case 'builtin': $specifier = substr($path, strlen(ModuleResolver::BUILTIN)); + if (isset($this->commonJsBuiltins[$specifier])) { + $value = ($this->commonJsBuiltins[$specifier])(); + $record->commonJsModule = new JsObject(); + $record->commonJsModule->set('exports', $value); + $record->namespaceOpen = true; + $namespace = $this->finishSyntheticModule($record, [], false); + $this->populateCommonJsNamespace($record); + return $namespace; + } $factory = $this->builtins[$specifier] ?? null; if ($factory === null) { throw new \Phasis\Exceptions\TypeError("Unknown built-in module '{$specifier}'"); @@ -2413,7 +2501,9 @@ private function loadTypedModule(string $specifier, ?string $referrer, string $t public function reset(): void { + $this->commonJs?->resetCache(); $this->modules = []; + $this->namespaceRequests = []; $this->evaluating = []; $this->onDemandStack = []; $this->bodyQueue = []; diff --git a/src/Module/ModuleOptions.php b/src/Module/ModuleOptions.php index 8c113665..d417e766 100644 --- a/src/Module/ModuleOptions.php +++ b/src/Module/ModuleOptions.php @@ -35,9 +35,26 @@ public function __construct( ], public ?string $parseCacheDir = null, public bool $deferSideEffectFreeModules = false, + public bool $nodeCompatible = false, ) { } + /** Preserve host resolution settings while selecting Node package semantics. */ + public function forNode(): self + { + return new self( + projectRoot: $this->projectRoot, + extensions: ['.js', '.json', '.cjs', '.mjs'], + conditions: ['node'], + nodeEnv: $this->nodeEnv, + styleExtensions: [], + assetExtensions: [], + parseCacheDir: $this->parseCacheDir, + deferSideEffectFreeModules: false, + nodeCompatible: true, + ); + } + /** * Active conditions for `import` or `require`, with the production * condition following $nodeEnv. diff --git a/src/Module/ModuleResolver.php b/src/Module/ModuleResolver.php index f4e1884e..96df11ca 100644 --- a/src/Module/ModuleResolver.php +++ b/src/Module/ModuleResolver.php @@ -28,6 +28,9 @@ final class ModuleResolver /** @var array */ private array $importMap = []; + /** @var array Aliases sharing one built-in module identity. */ + private array $builtinAliases = []; + /** @var array */ private array $cache = []; @@ -77,6 +80,13 @@ public function clearCache(): void $this->sideEffectFree = []; } + /** Register an alternate spelling of a built-in module. */ + public function registerBuiltinAlias(string $alias, string $canonical): void + { + $this->builtinAliases[$alias] = $canonical; + $this->clearCache(); + } + /** * @param 'import'|'require' $kind */ @@ -161,6 +171,9 @@ public function readPackageJson(string $dir): ?array */ private function resolveUncached(string $specifier, ?string $referrer, string $kind): string { + if (isset($this->builtinAliases[$specifier])) { + return self::BUILTIN . $this->builtinAliases[$specifier]; + } $mapped = $this->resolveImportMap($specifier); if ($mapped !== false) { if ($mapped === null) { @@ -199,7 +212,7 @@ private function resolveUncached(string $specifier, ?string $referrer, string $k } else { $path = $specifier; } - return $this->resolveFile(self::normalize($path)) ?? throw $this->notFound($specifier, $referrer); + return $this->resolveFile($path) ?? throw $this->notFound($specifier, $referrer); } $alias = $this->resolveAlias($specifier, $referrer); @@ -251,15 +264,38 @@ private function resolveImportMap(string $specifier): string|null|false */ public function resolveFile(string $path): ?string { - if (is_file($path)) { + return $this->resolvePath($path, []); + } + + /** @param array $visited */ + private function resolvePath(string $path, array $visited): ?string + { + $directoryOnly = str_ends_with($path, '/') || preg_match('~(?:^|/)\.{1,2}$~', $path) === 1; + $path = self::normalize($path); + if (isset($visited[$path])) { + return null; + } + $visited[$path] = true; + if (!$directoryOnly && is_file($path)) { return realpath($path) ?: $path; } foreach ($this->options->extensions as $extension) { - if (is_file($path . $extension)) { + if (!$directoryOnly && is_file($path . $extension)) { return realpath($path . $extension) ?: $path . $extension; } } if (is_dir($path)) { + $json = $this->readPackageJson($path); + $fields = $this->options->nodeCompatible ? ['main'] : ['module', 'main']; + foreach ($fields as $field) { + $main = $json[$field] ?? null; + if (is_string($main) && $main !== '') { + $resolved = $this->resolvePath($path . '/' . self::stripDotSlash($main), $visited); + if ($resolved !== null) { + return $resolved; + } + } + } foreach ($this->options->extensions as $extension) { $index = $path . '/index' . $extension; if (is_file($index)) { @@ -316,8 +352,9 @@ private function resolveInPackage(string $packageDir, string $subpath, string $s } return realpath($file) ?: $file; } - if ($subpath === '.') { - foreach (['module', 'main'] as $field) { + if ($subpath === '.' || $subpath === './') { + $fields = $this->options->nodeCompatible ? ['main'] : ['module', 'main']; + foreach ($fields as $field) { if (isset($json[$field]) && is_string($json[$field]) && $json[$field] !== '') { $resolved = $this->resolveFile($packageDir . '/' . self::stripDotSlash($json[$field])); if ($resolved !== null) { diff --git a/src/Node/ChildProcessBindings.php b/src/Node/ChildProcessBindings.php new file mode 100644 index 00000000..be56b726 --- /dev/null +++ b/src/Node/ChildProcessBindings.php @@ -0,0 +1,526 @@ + */ + private array $children = []; + private int $sequence = 0; + + private function __construct(private readonly Engine $engine, private readonly NodeRuntime $runtime) + { + $engine->getEventLoop()->addIoDriver( + 'child_process', + fn (int $timeout): bool => $this->poll($timeout), + fn (): bool => $this->hasReferences(), + ); + $runtime->onClose(fn () => $this->closeAll()); + } + + /** Create the realm-owned child-process host interface. */ + public static function create(Engine $engine, NodeRuntime $runtime): JsObject + { + $binding = new self($engine, $runtime); + $host = new JsObject(); + $host->set('call', JsFunction::fromCallable('call', static function (JsValue $this_, array $args) use ($binding): JsValue { + $operation = ($args[0] ?? JsUndefined::instance())->toJsString(); + return $binding->operation($operation, array_slice($args, 1)); + })); + return $host; + } + + /** @param list $args */ + private function operation(string $operation, array $args): JsValue + { + $result = new JsObject(); + try { + $value = match ($operation) { + 'spawnSync' => $this->spawnSync($this->object($args[0] ?? JsUndefined::instance())), + 'spawn' => $this->spawn($this->object($args[0] ?? JsUndefined::instance()), $this->callback($args[1] ?? JsUndefined::instance())), + 'write' => $this->write($args), + 'end' => $this->end($this->child($args[0] ?? JsUndefined::instance())), + 'pause' => $this->pause($args), + 'ref' => $this->reference($args), + 'kill' => $this->kill($args), + 'closePipe' => $this->closePipe( + $this->child($args[0] ?? JsUndefined::instance()), + (int) ($args[1] ?? JsUndefined::instance())->toNumber(), + ), + default => throw new TypeError("Unknown child-process operation '{$operation}'."), + }; + $result->set('value', $value); + } catch (\RuntimeException $error) { + $code = match ($error->getCode()) { + 2 => 'ENOENT', 13 => 'EACCES', 32 => 'EPIPE', default => 'EIO' + }; + $result->set('error', $this->error($code, $operation === 'spawnSync' ? 'spawnSync' : 'spawn', $error->getMessage())); + } + return $result; + } + + private function spawn(JsObject $options, JsFunction $callback): JsValue + { + $state = $this->open($options, $callback); + $this->children[$state->id] = $state; + return PhpToJs::convert(['id' => $state->id, 'pid' => $state->pid, 'pipes' => array_keys($state->pipes)]); + } + + private function open(JsObject $options, ?JsFunction $callback): ChildProcessState + { + $file = $options->get('file')->toJsString(); + $arguments = $options->get('args'); + $command = [$file]; + if ($arguments instanceof JsArray) { + foreach ($arguments->toList() as $argument) { + $command[] = $argument->toJsString(); + } + } + $cwd = $this->runtime->absolutePath($options->get('cwd')->toJsString()); + if (!is_dir($cwd)) { + throw new \RuntimeException($file, 2); + } + $environment = []; + $env = $options->get('env'); + if ($env instanceof JsObject) { + foreach ($env->getOwnPropertyNames() as $key) { + $environment[$key] = $env->get($key)->toJsString(); + } + } + $resolved = $this->resolveExecutable($file, $cwd, $environment['PATH'] ?? '/usr/bin:/bin'); + $command[0] = $resolved; + if ($resolved === PHP_BINARY && isset($command[1]) && preg_match('/\.(?:cjs|mjs|js)$/i', $command[1]) === 1) { + // process.execPath remains PHP. A requested JavaScript child therefore + // runs in a new Phasis realm instead of being handed to another engine. + array_splice($command, 1, 0, [__DIR__ . '/child-runtime.php']); + } + $descriptors = []; + $stdio = $options->get('stdio'); + for ($fd = 0; $fd < 3; $fd++) { + $kind = $stdio instanceof JsArray ? $stdio->get((string) $fd)->toJsString() : 'pipe'; + $descriptors[$fd] = match ($kind) { + 'pipe', 'overlapped' => ['pipe', $fd === 0 ? 'r' : 'w'], + 'ignore' => ['file', PHP_OS_FAMILY === 'Windows' ? 'NUL' : '/dev/null', $fd === 0 ? 'r' : 'w'], + '0' => STDIN, + '1' => STDOUT, + '2' => STDERR, + default => throw new TypeError('Unsupported child-process stdio descriptor.'), + }; + } + $pipes = []; + $process = @proc_open($command, $descriptors, $pipes, $cwd, $environment, ['bypass_shell' => true]); + if ($process === false) { + throw new \RuntimeException($file); + } + foreach ($pipes as $pipe) { + stream_set_blocking($pipe, false); + } + $status = proc_get_status($process); + $state = new ChildProcessState( + ++$this->sequence, + $process, + $status['pid'], + $pipes, + $callback, + AsyncContextStorage::active()->snapshot(), + ); + if (!$status['running']) { + $state->exited = true; + $state->exitCode = $status['signaled'] ? null : $status['exitcode']; + $state->signal = $status['signaled'] ? $this->signalName($status['termsig']) : null; + } + return $state; + } + + private function resolveExecutable(string $file, string $cwd, string $path): string + { + $candidates = str_contains($file, '/') ? [$file] : array_map( + static fn (string $dir): string => ($dir === '' ? '.' : $dir) . '/' . $file, + explode(PATH_SEPARATOR, $path), + ); + $denied = false; + foreach ($candidates as $candidate) { + $candidate = str_starts_with($candidate, '/') ? $candidate : $cwd . '/' . $candidate; + if (is_file($candidate)) { + if (is_executable($candidate)) { + return realpath($candidate) ?: $candidate; + } + $denied = true; + } + } + throw new \RuntimeException($file, $denied ? 13 : 2); + } + + private function spawnSync(JsObject $options): JsValue + { + $state = $this->open($options, null); + $input = $options->get('input'); + $state->input = $input instanceof JsTypedArray ? $this->bytes($input) : ''; + $state->ending = true; + $state->paused = [1 => false, 2 => false]; + $output = [1 => '', 2 => '']; + $timeout = $options->get('timeout')->toNumber(); + $deadline = $timeout > 0 ? microtime(true) + $timeout / 1000 : INF; + $maximum = $options->get('maxBuffer')->toNumber(); + $signal = (int) $options->get('killSignal')->toNumber(); + $error = null; + try { + while (!$state->exited || $state->pipes !== []) { + if ($error === null && microtime(true) >= $deadline) { + $error = $this->error('ETIMEDOUT', 'spawnSync', $options->get('file')->toJsString()); + proc_terminate($state->process, $signal); + } + $this->transfer($state, 20_000, static function (int $fd, string $bytes) use (&$output): void { + $output[$fd] .= $bytes; + }); + if ($error === null && strlen($output[1]) + strlen($output[2]) > $maximum) { + $error = $this->error('ENOBUFS', 'spawnSync', $options->get('file')->toJsString()); + proc_terminate($state->process, $signal); + } + $this->updateStatus($state); + if ($state->exited && isset($state->pipes[0])) { + $this->closePipe($state, 0); + } + } + $this->reap($state); + } finally { + $this->dispose($state); + } + $result = new JsObject(); + $result->set('pid', JsNumber::of($state->pid)); + $result->set('status', $state->exitCode === null ? JsNull::instance() : JsNumber::of($state->exitCode)); + $result->set('signal', $state->signal === null ? JsNull::instance() : new JsString($state->signal)); + $result->set('stdout', $this->buffer($output[1])); + $result->set('stderr', $this->buffer($output[2])); + if ($error !== null) { + $result->set('error', $error); + } + return $result; + } + + /** @param list $args */ + private function write(array $args): JsValue + { + $state = $this->child($args[0] ?? JsUndefined::instance()); + if (!isset($state->pipes[0])) { + throw new \RuntimeException('write EPIPE', 32); + } + $bytes = $args[1] ?? JsUndefined::instance(); + if (!$bytes instanceof JsTypedArray) { + throw new TypeError('Child input must contain bytes.'); + } + $state->input .= $this->bytes($bytes); + $state->writeCallback = $this->callback($args[2] ?? JsUndefined::instance()); + if ($state->input === '') { + $this->runtime->nextTick($state->writeCallback, []); + $state->writeCallback = null; + } + return JsUndefined::instance(); + } + + private function end(ChildProcessState $state): JsValue + { + $state->ending = true; + return JsUndefined::instance(); + } + + /** @param list $args */ + private function pause(array $args): JsValue + { + $state = $this->child($args[0] ?? JsUndefined::instance()); + $fd = (int) ($args[1] ?? JsUndefined::instance())->toNumber(); + $state->paused[$fd] = ($args[2] ?? JsUndefined::instance())->toBoolean(); + return JsUndefined::instance(); + } + + /** @param list $args */ + private function reference(array $args): JsValue + { + $state = $this->child($args[0] ?? JsUndefined::instance()); + $reference = ($args[1] ?? JsUndefined::instance())->toBoolean(); + $fd = $args[2] ?? JsUndefined::instance(); + if ($fd instanceof JsUndefined) { + $state->referenced = $reference; + } else { + $state->pipeReferences[(int) $fd->toNumber()] = $reference; + } + return JsUndefined::instance(); + } + + /** @param list $args */ + private function kill(array $args): JsValue + { + $state = $this->children[(int) ($args[0] ?? JsUndefined::instance())->toNumber()] ?? null; + $signal = (int) ($args[1] ?? JsUndefined::instance())->toNumber(); + return new JsBoolean($state !== null && !$state->exited && proc_terminate($state->process, $signal)); + } + + private function poll(int $timeout): bool + { + $progress = false; + foreach ($this->children as $state) { + if ($state->spawnPending) { + $state->spawnPending = false; + $this->emit($state, 'spawn'); + $progress = true; + } + $progress = $this->transfer($state, $progress ? 0 : $timeout * 1000, function (int $fd, string $bytes) use ($state): void { + $value = new JsObject(); + $value->set('fd', JsNumber::of($fd)); + $value->set('data', $this->buffer($bytes)); + $this->emit($state, 'data', $value); + }) || $progress; + $timeout = 0; + $this->updateStatus($state); + if ($state->exited && !$state->exitEmitted) { + $state->exitEmitted = true; + $this->emit($state, 'exit', PhpToJs::convert(['code' => $state->exitCode, 'signal' => $state->signal])); + if (isset($state->pipes[0])) { + $this->closePipe($state, 0); + } + $progress = true; + } + if ($state->exited && $state->pipes === []) { + $this->reap($state); + unset($this->children[$state->id]); + $this->emit($state, 'close', PhpToJs::convert(['code' => $state->exitCode, 'signal' => $state->signal])); + $progress = true; + } + } + return $progress; + } + + /** @param \Closure(int, string): void $receive */ + private function transfer(ChildProcessState $state, int $timeout, \Closure $receive): bool + { + if (isset($state->pipes[0]) && $state->input === '' && $state->ending) { + $this->closePipe($state, 0); + } + $read = []; + foreach ([1, 2] as $fd) { + if (isset($state->pipes[$fd]) && !$state->paused[$fd]) { + $read[] = $state->pipes[$fd]; + } + } + $write = isset($state->pipes[0]) && $state->input !== '' ? [$state->pipes[0]] : []; + if ($read === [] && $write === []) { + if ($timeout > 0) { + usleep($timeout); + } + return false; + } + $except = []; + $selected = @stream_select($read, $write, $except, 0, min($timeout, 999_999)); + if (!$selected) { + return false; + } + foreach ($write as $pipe) { + $written = @fwrite($pipe, $state->input); + if ($written === false || ($written === 0 && feof($pipe))) { + $this->completeWrite($state, $this->error('EPIPE', 'write', '')); + $this->closePipe($state, 0); + } else { + $state->input = substr($state->input, $written); + if ($state->input === '') { + $this->completeWrite($state); + if ($state->ending) { + $this->closePipe($state, 0); + } + } + } + } + foreach ([1, 2] as $fd) { + $pipe = $state->pipes[$fd] ?? null; + if ($pipe === null || !in_array($pipe, $read, true)) { + continue; + } + $bytes = fread($pipe, 65536); + if (is_string($bytes) && $bytes !== '') { + $receive($fd, $bytes); + } + if (isset($state->pipes[$fd]) && feof($pipe)) { + $this->closePipe($state, $fd); + $this->emit($state, 'end', JsNumber::of($fd)); + } + } + return true; + } + + private function updateStatus(ChildProcessState $state): void + { + if ($state->exited) { + return; + } + $status = proc_get_status($state->process); + if (!$status['running']) { + $state->exited = true; + $state->exitCode = $status['signaled'] ? null : $status['exitcode']; + if ($status['signaled']) { + $state->signal = $this->signalName($status['termsig']); + } + } + } + + private function signalName(int $signal): string + { + foreach (get_defined_constants() as $name => $value) { + if (str_starts_with($name, 'SIG') && !str_starts_with($name, 'SIG_') && $value === $signal) { + return $name; + } + } + return 'SIG' . $signal; + } + + private function closePipe(ChildProcessState $state, int $fd): JsValue + { + if (isset($state->pipes[$fd])) { + fclose($state->pipes[$fd]); + unset($state->pipes[$fd]); + } + if ($fd === 0 && $state->input !== '') { + $state->input = ''; + $this->completeWrite($state, $this->error('EPIPE', 'write', '')); + } + return JsUndefined::instance(); + } + + private function reap(ChildProcessState $state): void + { + if (!$state->closed) { + $code = proc_close($state->process); + if ($state->exitCode === null && $state->signal === null && $code >= 0) { + $state->exitCode = $code; + } + $state->closed = true; + } + } + + private function dispose(ChildProcessState $state): void + { + foreach ($state->pipes as $pipe) { + fclose($pipe); + } + $state->pipes = []; + if (!$state->closed) { + if (!$state->exited) { + proc_terminate($state->process, 9); + } + $this->reap($state); + } + } + + private function closeAll(): void + { + foreach ($this->children as $state) { + $this->dispose($state); + } + $this->children = []; + $this->engine->getEventLoop()->removeIoDriver('child_process'); + } + + private function hasReferences(): bool + { + foreach ($this->children as $state) { + if ($state->referenced && !$state->exited) { + return true; + } + foreach ($state->pipes as $fd => $pipe) { + if ($state->pipeReferences[$fd]) { + return true; + } + } + } + return false; + } + + private function emit(ChildProcessState $state, string $event, ?JsValue $value = null): void + { + if ($state->callback !== null) { + $this->invoke($state, $state->callback, [new JsString($event), $value ?? JsUndefined::instance()]); + } + } + + private function completeWrite(ChildProcessState $state, ?JsObject $error = null): void + { + $callback = $state->writeCallback; + $state->writeCallback = null; + if ($callback !== null) { + $this->invoke($state, $callback, [$error ?? JsUndefined::instance()]); + } + } + + /** @param list $args */ + private function invoke(ChildProcessState $state, JsFunction $callback, array $args): void + { + $previous = Engine::getCurrentInterpreter(); + $context = AsyncContextStorage::active()->snapshot(); + Engine::setCurrentInterpreter($this->engine->getInterpreter()); + AsyncContextStorage::active()->restore($state->context); + try { + $this->engine->getInterpreter()->callFunction($callback, JsUndefined::instance(), $args); + } finally { + AsyncContextStorage::active()->restore($context); + Engine::setCurrentInterpreter($previous); + } + } + + private function child(JsValue $id): ChildProcessState + { + return $this->children[(int) $id->toNumber()] ?? throw new \RuntimeException('Child process is closed', 32); + } + + private function object(JsValue $value): JsObject + { + return $value instanceof JsObject ? $value : throw new TypeError('Expected child-process options.'); + } + + private function callback(JsValue $value): JsFunction + { + return $value instanceof JsFunction ? $value : throw new TypeError('Expected a child-process callback.'); + } + + private function bytes(JsTypedArray $value): string + { + return $value->getBuffer()->readBytes($value->getByteOffset(), $value->getLength() * $value->getBytesPerElement()); + } + + private function buffer(string $bytes): JsTypedArray + { + $buffer = new JsArrayBuffer(strlen($bytes)); + $buffer->setData($bytes); + $constructor = $this->engine->getGlobalEnv()->get('Uint8Array'); + $prototype = $constructor instanceof JsObject ? $constructor->get('prototype') : null; + return new JsTypedArray('Uint8Array', $buffer, 0, strlen($bytes), $prototype instanceof JsObject ? $prototype : null); + } + + private function error(string $code, string $syscall, string $file): JsObject + { + $error = new JsObject(); + $error->set('message', new JsString($syscall . ($file === '' ? '' : ' ' . $file) . ' ' . $code)); + $error->set('code', new JsString($code)); + $error->set('errno', JsNumber::of(-match ($code) { + 'ENOENT' => 2, 'EACCES' => 13, 'EPIPE' => 32, 'ETIMEDOUT' => 60, 'ENOBUFS' => 55, default => 5 + })); + $error->set('syscall', new JsString($syscall . ($file === '' ? '' : ' ' . $file))); + return $error; + } +} diff --git a/src/Node/ChildProcessState.php b/src/Node/ChildProcessState.php new file mode 100644 index 00000000..4e9634a4 --- /dev/null +++ b/src/Node/ChildProcessState.php @@ -0,0 +1,43 @@ + */ + public array $paused = [1 => true, 2 => true]; + /** @var array */ + public array $pipeReferences = [0 => true, 1 => true, 2 => true]; + + /** + * @param resource $process + * @param array $pipes + * @param array{array, array} $context + */ + public function __construct( + public readonly int $id, + public mixed $process, + public readonly int $pid, + public array $pipes, + public readonly ?JsFunction $callback, + public readonly array $context, + ) { + } +} diff --git a/src/Node/CryptoBindings.php b/src/Node/CryptoBindings.php new file mode 100644 index 00000000..7141eb1a --- /dev/null +++ b/src/Node/CryptoBindings.php @@ -0,0 +1,166 @@ + PhpToJs::convert(self::hashes())); + self::method($host, 'hashLength', static fn (array $args): JsValue => JsNumber::of(strlen(hash(self::algorithm($args[0]), '', true)))); + self::method($host, 'createHash', static function (array $args): JsValue { + $algorithm = self::algorithm($args[0]); + $key = $args[1] ?? JsUndefined::instance(); + $context = $key instanceof JsUndefined + ? hash_init($algorithm) + : hash_init($algorithm, HASH_HMAC, self::bytes($key) === '' ? "\0" : self::bytes($key)); + return self::token($context); + }); + self::method($host, 'copyHash', static fn (array $args): JsValue => self::token(hash_copy(self::context($args[0])))); + self::method($host, 'updateHash', static function (array $args): JsValue { + hash_update(self::context($args[0]), self::bytes($args[1])); + return JsUndefined::instance(); + }); + self::method($host, 'digestHash', static function (array $args) use ($engine): JsValue { + $token = $args[0]; + $result = hash_final(self::context($token), true); + if ($token instanceof JsObject) { + $token->setInternalProperty('[[NodeHashContext]]', null); + } + return self::byteArray($engine, $result); + }); + self::method($host, 'randomBytes', static function (array $args) use ($engine): JsValue { + $length = (int) $args[0]->toNumber(); + return self::byteArray($engine, $length === 0 ? '' : random_bytes($length)); + }); + self::method($host, 'randomInt', static fn (array $args): JsValue => JsNumber::of(random_int( + (int) $args[0]->toNumber(), + (int) $args[1]->toNumber() - 1, + ))); + self::method($host, 'timingSafeEqual', static fn (array $args): JsValue => new JsBoolean(hash_equals( + self::bytes($args[0]), + self::bytes($args[1]), + ))); + self::method($host, 'pbkdf2', static function (array $args) use ($engine): JsValue { + $length = (int) $args[3]->toNumber(); + $result = $length === 0 ? '' : hash_pbkdf2( + self::algorithm($args[4]), + self::bytes($args[0]), + self::bytes($args[1]), + (int) $args[2]->toNumber(), + $length, + true, + ); + return self::byteArray($engine, $result); + }); + self::method($host, 'hkdf', static function (array $args) use ($engine): JsValue { + $length = (int) $args[4]->toNumber(); + $algorithm = self::algorithm($args[0]); + $key = hash_hmac($algorithm, self::bytes($args[1]), self::bytes($args[2]), true); + $info = self::bytes($args[3]); + $previous = ''; + $result = ''; + for ($block = 1; strlen($result) < $length; $block++) { + $previous = hash_hmac($algorithm, $previous . $info . chr($block), $key, true); + $result .= $previous; + } + $result = substr($result, 0, $length); + return self::byteArray($engine, $result); + }); + return $host; + } + + /** @param \Closure(list): JsValue $callback */ + private static function method(JsObject $target, string $name, \Closure $callback): void + { + $target->set($name, JsFunction::fromCallable( + $name, + static fn (JsValue $this_, array $args): JsValue => $callback($args), + )); + } + + private static function algorithm(JsValue $value): string + { + $name = strtolower($value->toJsString()); + $name = match ($name) { + 'sha-1', 'rsa-sha1' => 'sha1', + 'sha-224', 'rsa-sha224' => 'sha224', + 'sha-256', 'rsa-sha256' => 'sha256', + 'sha-384', 'rsa-sha384' => 'sha384', + 'sha-512', 'rsa-sha512' => 'sha512', + default => $name, + }; + if (!in_array($name, self::hashes(), true)) { + throw new TypeError('Digest method not supported: ' . $name); + } + return $name; + } + + /** @return list */ + private static function hashes(): array + { + $openssl = function_exists('openssl_get_md_methods') + ? openssl_get_md_methods() + : ['md4', 'md5', 'ripemd160', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512']; + return array_values(array_intersect(hash_algos(), $openssl)); + } + + private static function token(\HashContext $context): JsObject + { + $token = new JsObject(); + $token->setInternalProperty('[[NodeHashContext]]', $context); + return $token; + } + + private static function context(JsValue $value): \HashContext + { + $context = $value instanceof JsObject ? $value->getInternalProperty('[[NodeHashContext]]') : null; + if (!$context instanceof \HashContext) { + throw new TypeError('Digest already called.'); + } + return $context; + } + + private static function bytes(JsValue $value): string + { + if ($value instanceof JsTypedArray) { + $value->validateNotDetached(); + return $value->getBuffer()->readBytes($value->getByteOffset(), $value->getLength() * $value->getBytesPerElement()); + } + if ($value instanceof JsDataView) { + $value->validateNotDetached(); + return $value->getBuffer()->readBytes($value->getByteOffset(), $value->getByteLength()); + } + if ($value instanceof JsArrayBuffer && !$value->isDetached()) { + return $value->getData(); + } + throw new TypeError('Expected an ArrayBuffer or ArrayBufferView.'); + } + + private static function byteArray(Engine $engine, string $bytes): JsTypedArray + { + $constructor = $engine->getGlobalEnv()->get('Uint8Array'); + $prototype = $constructor instanceof JsObject ? $constructor->get('prototype') : null; + $array = JsTypedArray::fromLength('Uint8Array', strlen($bytes), $prototype instanceof JsObject ? $prototype : null); + $array->getBuffer()->setData($bytes); + return $array; + } +} diff --git a/src/Node/ErrorStack.php b/src/Node/ErrorStack.php new file mode 100644 index 00000000..a4ae5e07 --- /dev/null +++ b/src/Node/ErrorStack.php @@ -0,0 +1,121 @@ +getGlobalEnv()->get('Error'); + if (!$constructor instanceof JsObject) { + return; + } + $constructor->defineOwnProperty('stackTraceLimit', PropertyDescriptor::data(JsNumber::of(10), true, false, true)); + $capture = JsFunction::fromCallable('captureStackTrace', static function (JsValue $this_, array $args) use ($engine, $constructor): JsValue { + $target = $args[0] ?? JsUndefined::instance(); + if (!$target instanceof JsObject) { + throw new TypeError('Invalid argument'); + } + $exclude = $args[1] ?? null; + $frames = array_reverse($engine->getInterpreter()->getCallStack()->getFrames()); + if ($exclude instanceof JsFunction) { + $index = null; + foreach ($frames as $key => $frame) { + if ($frame->function === $exclude) { + $index = $key; + break; + } + } + $frames = $index === null ? [] : array_slice($frames, $index + 1); + } + $limit = $constructor->get('stackTraceLimit'); + $count = $limit instanceof JsNumber ? $limit->toNumber() : 0; + $frames = array_slice($frames, 0, is_infinite($count) && $count > 0 ? count($frames) : max(0, (int) $count)); + $sites = []; + foreach ($frames as $frame) { + $function = $frame->function; + $body = $function?->getBody(); + $file = $function->definingModulePath ?? Engine::getCurrentSourceURL(); + $line = $frame->line > 0 ? $frame->line : ($body instanceof Node ? $body->location->line : null); + $column = $body instanceof Node ? $body->location->column + 1 : null; + $name = $frame->name !== '' ? $frame->name : null; + $site = new JsObject(); + $values = [ + 'getFileName' => $file === null ? JsNull::instance() : new JsString($file), + 'getScriptNameOrSourceURL' => $file === null ? JsNull::instance() : new JsString($file), + 'getLineNumber' => $line === null ? JsNull::instance() : JsNumber::of($line), + 'getColumnNumber' => $column === null ? JsNull::instance() : JsNumber::of($column), + 'getFunctionName' => $name === null ? JsNull::instance() : new JsString($name), + 'getMethodName' => $name === null ? JsNull::instance() : new JsString($name), + 'getFunction' => $function !== null && !$function->isStrict() ? $function : JsUndefined::instance(), + 'getThis' => JsUndefined::instance(), + 'getTypeName' => JsNull::instance(), + 'getEvalOrigin' => JsUndefined::instance(), + 'isToplevel' => new JsBoolean(false), + 'isEval' => new JsBoolean($file === null), + 'isNative' => new JsBoolean($function?->isNative() ?? false), + 'isConstructor' => new JsBoolean($function?->isClassConstructor() ?? false), + 'isAsync' => new JsBoolean($function?->isAsync() ?? false), + 'isPromiseAll' => new JsBoolean(false), + 'getPromiseIndex' => JsNull::instance(), + ]; + foreach ($values as $method => $value) { + $site->set($method, JsFunction::fromCallable($method, static fn (): JsValue => $value)); + } + $location = $file === null ? '' : $file . ($line === null ? '' : ':' . $line . ':' . $column); + $formatted = $name === null ? $location : $name . ' (' . $location . ')'; + $site->set('toString', JsFunction::fromCallable('toString', static fn (): JsValue => new JsString($formatted))); + $sites[] = $site; + } + $cache = null; + $getter = JsFunction::fromCallable('get stack', static function () use ($target, $sites, $constructor, $engine, &$cache): JsValue { + if ($cache !== null) { + return $cache; + } + $prepare = $constructor->get('prepareStackTrace'); + if ($prepare instanceof JsFunction) { + return $cache = $engine->getInterpreter()->callFunction($prepare, $constructor, [$target, JsArray::fromArray($sites)]); + } + $name = $target->get('name'); + $message = $target->get('message'); + $header = $name instanceof JsUndefined ? 'Error' : $name->toJsString(); + if (!$message instanceof JsUndefined && $message->toJsString() !== '') { + $header .= ': ' . $message->toJsString(); + } + foreach ($sites as $site) { + $stringify = $site->get('toString'); + if ($stringify instanceof JsFunction) { + $header .= "\n at " . $stringify->call($site, [])->toJsString(); + } + } + return $cache = new JsString($header); + }); + $setter = JsFunction::fromCallable('set stack', static function (JsValue $this_, array $args) use (&$cache): JsValue { + $cache = $args[0] ?? JsUndefined::instance(); + return JsUndefined::instance(); + }); + if (!$target->defineOwnProperty('stack', PropertyDescriptor::accessor($getter, $setter, false, true))) { + throw new TypeError('Cannot define stack on target object'); + } + return JsUndefined::instance(); + }, 2); + $constructor->defineOwnProperty('captureStackTrace', PropertyDescriptor::data($capture, true, false, true)); + } +} diff --git a/src/Node/FileSystemBindings.php b/src/Node/FileSystemBindings.php new file mode 100644 index 00000000..2f0a9f83 --- /dev/null +++ b/src/Node/FileSystemBindings.php @@ -0,0 +1,470 @@ + */ + private array $descriptors = []; + + private int $nextDescriptor = 100; + + private function __construct(private readonly Engine $engine, private readonly NodeRuntime $runtime) + { + } + + /** Install the native half of fs, with cleanup on engine reset and close. */ + public static function create(Engine $engine, NodeRuntime $runtime): JsObject + { + $bindings = new self($engine, $runtime); + $runtime->onClose($bindings->closeAll(...)); + $host = new JsObject(); + $host->set('call', JsFunction::fromCallable('call', static function (JsValue $this_, array $args) use ($bindings): JsValue { + $operation = array_shift($args)?->toJsString() ?? ''; + $result = new JsObject(); + try { + $result->set('value', $bindings->dispatch($operation, $args)); + } catch (FileSystemError $error) { + $result->set('error', self::error($error)); + } + return $result; + })); + return $host; + } + + /** @param list $args */ + private function dispatch(string $operation, array $args): JsValue + { + $first = $args[0] ?? JsUndefined::instance(); + if ($operation === 'open') { + return JsNumber::of($this->open($first->toJsString(), $args[1]->toJsString(), (int) $args[2]->toNumber())); + } + if ($operation === 'close') { + $descriptor = (int) $first->toNumber(); + $entry = $this->descriptor($descriptor, 'close'); + fclose($entry['stream']); + unset($this->descriptors[$descriptor]); + return JsUndefined::instance(); + } + if ($operation === 'read' || $operation === 'write') { + return JsNumber::of($this->transfer($operation, $args)); + } + if ($operation === 'fstat') { + $entry = $this->descriptor((int) $first->toNumber(), 'fstat'); + $stat = fstat($entry['stream']); + if ($stat === false) { + throw new FileSystemError('EIO', 'fstat'); + } + return $this->statObject($stat); + } + if (in_array($operation, ['ftruncate', 'fsync', 'fdatasync'], true)) { + $entry = $this->descriptor((int) $first->toNumber(), $operation); + $success = match ($operation) { + 'ftruncate' => @ftruncate($entry['stream'], (int) $args[1]->toNumber()), + 'fsync' => @fsync($entry['stream']), + default => @fdatasync($entry['stream']), + }; + if (!$success) { + throw new FileSystemError($entry['writable'] ? 'EIO' : 'EINVAL', $operation); + } + return JsUndefined::instance(); + } + if ($operation === 'readAll') { + $entry = $this->descriptor((int) $first->toNumber(), 'read'); + if (!$entry['readable']) { + throw new FileSystemError('EBADF', 'read'); + } + if (is_dir($this->runtime->absolutePath($entry['path']))) { + throw new FileSystemError('EISDIR', 'read'); + } + $bytes = stream_get_contents($entry['stream']); + if ($bytes === false) { + throw new FileSystemError('EIO', 'read'); + } + return $this->bytes($bytes); + } + + $path = $first->toJsString(); + $absolute = $this->runtime->absolutePath($path); + clearstatcache(true, $absolute); + if ($operation === 'stat' || $operation === 'lstat') { + $stat = $operation === 'stat' ? @stat($absolute) : @lstat($absolute); + if ($stat === false) { + throw $this->pathError($operation, $path); + } + return $this->statObject($stat); + } + if ($operation === 'exists') { + return new JsBoolean(file_exists($absolute)); + } + if ($operation === 'access') { + if (!file_exists($absolute)) { + throw $this->pathError('access', $path); + } + $mode = (int) $args[1]->toNumber(); + if ((($mode & 4) && !is_readable($absolute)) || (($mode & 2) && !is_writable($absolute)) || (($mode & 1) && !is_executable($absolute))) { + throw new FileSystemError('EACCES', 'access', $path); + } + return JsUndefined::instance(); + } + if ($operation === 'readdir') { + $names = @scandir($absolute); + if ($names === false) { + throw $this->pathError('scandir', $path, is_file($absolute) ? 'ENOTDIR' : null); + } + $entries = []; + foreach ($names as $name) { + if ($name === '.' || $name === '..') { + continue; + } + $stat = @lstat($absolute . '/' . $name); + $entries[] = ['name' => $this->bytes($name), 'mode' => $stat['mode'] ?? 0]; + } + return PhpToJs::convert($entries); + } + if ($operation === 'realpath' || $operation === 'readlink') { + $value = $operation === 'realpath' ? realpath($absolute) : @readlink($absolute); + if ($value === false) { + throw $this->pathError($operation, $path, $operation === 'readlink' && file_exists($absolute) ? 'EINVAL' : null); + } + return $this->bytes($value); + } + if ($operation === 'mkdir') { + $recursive = $args[2]->toBoolean(); + if (file_exists($absolute) || is_link($absolute)) { + if ($recursive && is_dir($absolute)) { + return JsUndefined::instance(); + } + throw new FileSystemError('EEXIST', 'mkdir', $path); + } + $firstCreated = $absolute; + if ($recursive) { + while (!file_exists(dirname($firstCreated)) && dirname($firstCreated) !== $firstCreated) { + $firstCreated = dirname($firstCreated); + } + } + if (!@mkdir($absolute, (int) $args[1]->toNumber(), $recursive)) { + throw $this->pathError('mkdir', $path); + } + if (!$recursive) { + return JsUndefined::instance(); + } + $value = str_starts_with($path, '/') ? $firstCreated : substr($firstCreated, strlen($this->runtime->cwd()) + 1); + return new JsString($value); + } + if ($operation === 'mkdtemp') { + for ($attempt = 0; $attempt < 10; $attempt++) { + $suffix = ''; + $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for ($i = 0; $i < 6; $i++) { + $suffix .= $alphabet[random_int(0, 61)]; + } + if (@mkdir($absolute . $suffix, 0700)) { + return $this->bytes($path . $suffix); + } + if (!file_exists($absolute . $suffix)) { + throw $this->pathError('mkdtemp', $path . 'XXXXXX'); + } + } + throw new FileSystemError('EEXIST', 'mkdtemp', $path . 'XXXXXX'); + } + if ($operation === 'unlink' || $operation === 'rmdir') { + if ($operation === 'unlink' && is_dir($absolute) && !is_link($absolute)) { + throw new FileSystemError('EPERM', 'unlink', $path); + } + $success = $operation === 'unlink' ? @unlink($absolute) : @rmdir($absolute); + if (!$success) { + $code = $operation === 'rmdir' && is_dir($absolute) ? 'ENOTEMPTY' : null; + throw $this->pathError($operation, $path, $code); + } + return JsUndefined::instance(); + } + if (in_array($operation, ['rename', 'link', 'symlink', 'copyFile'], true)) { + return $this->twoPaths($operation, $path, $args[1]->toJsString(), $args[2] ?? JsUndefined::instance()); + } + if ($operation === 'chmod') { + if (!@chmod($absolute, (int) $args[1]->toNumber())) { + throw $this->pathError('chmod', $path); + } + return JsUndefined::instance(); + } + if ($operation === 'chown' || $operation === 'lchown') { + $uid = (int) $args[1]->toNumber(); + $gid = (int) $args[2]->toNumber(); + $link = $operation === 'lchown'; + $owner = $uid === -1 || ($link ? @lchown($absolute, $uid) : @chown($absolute, $uid)); + $group = $gid === -1 || ($link ? @lchgrp($absolute, $gid) : @chgrp($absolute, $gid)); + if (!$owner || !$group) { + throw $this->pathError($operation, $path); + } + return JsUndefined::instance(); + } + if ($operation === 'utimes') { + if (!file_exists($absolute)) { + throw $this->pathError('utime', $path); + } + if (!@touch($absolute, (int) $args[2]->toNumber(), (int) $args[1]->toNumber())) { + throw $this->pathError('utime', $path); + } + return JsUndefined::instance(); + } + throw new FileSystemError('ENOSYS', $operation, $path); + } + + private function open(string $path, string $flags, int $mode): int + { + $absolute = $this->runtime->absolutePath($path); + clearstatcache(true, $absolute); + $readable = str_contains($flags, '+') || $flags[0] === 'r'; + $writable = $flags[0] !== 'r' || str_contains($flags, '+'); + $phpMode = str_contains($flags, 'x') ? 'x' : $flags[0]; + if (str_contains($flags, '+')) { + $phpMode .= '+'; + } + $phpMode .= 'b'; + $existed = file_exists($absolute) || is_link($absolute); + if (str_contains($flags, 'x') && $existed) { + throw new FileSystemError('EEXIST', 'open', $path); + } + if ($writable && is_dir($absolute)) { + throw new FileSystemError('EISDIR', 'open', $path); + } + $stream = @fopen($absolute, $phpMode); + if ($stream === false) { + throw $this->pathError('open', $path); + } + if (!$existed && $writable) { + @chmod($absolute, $mode & ~umask()); + } + $descriptor = $this->nextDescriptor++; + $this->descriptors[$descriptor] = ['stream' => $stream, 'path' => $path, 'readable' => $readable, 'writable' => $writable]; + return $descriptor; + } + + /** @param list $args */ + private function transfer(string $operation, array $args): int + { + $entry = $this->descriptor((int) $args[0]->toNumber(), $operation); + if (!$entry[$operation === 'read' ? 'readable' : 'writable']) { + throw new FileSystemError('EBADF', $operation); + } + $view = $args[1]; + if (!$view instanceof JsTypedArray) { + throw new \Phasis\Exceptions\TypeError('Filesystem transfer requires a byte view.'); + } + $view->validateNotDetached($operation === 'read'); + $offset = (int) $args[2]->toNumber(); + $length = (int) $args[3]->toNumber(); + $position = $args[4]; + if ($length === 0) { + return 0; + } + if ($operation === 'read' && is_dir($this->runtime->absolutePath($entry['path']))) { + throw new FileSystemError('EISDIR', 'read'); + } + $stream = $entry['stream']; + $restore = null; + if (!$position instanceof JsNull && !$position instanceof JsUndefined && $position->toNumber() >= 0) { + $restore = ftell($stream); + if (fseek($stream, (int) $position->toNumber(), SEEK_SET) !== 0) { + throw new FileSystemError('ESPIPE', $operation); + } + } + try { + if ($operation === 'read') { + $bytes = @fread($stream, $length); + if ($bytes === false) { + throw new FileSystemError('EIO', 'read'); + } + $view->getBuffer()->writeBytes($view->getByteOffset() + $offset, $bytes); + return strlen($bytes); + } + $bytes = $view->getBuffer()->readBytes($view->getByteOffset() + $offset, $length); + $written = @fwrite($stream, $bytes); + if ($written === false) { + throw new FileSystemError('EIO', 'write'); + } + fflush($stream); + return $written; + } finally { + if (is_int($restore)) { + fseek($stream, $restore, SEEK_SET); + } + } + } + + private function twoPaths(string $operation, string $path, string $destination, JsValue $options): JsValue + { + $source = $this->runtime->absolutePath($path); + $target = $this->runtime->absolutePath($destination); + if ($operation === 'copyFile') { + $flags = (int) $options->toNumber(); + if (is_dir($source) || is_dir($target)) { + throw new FileSystemError('EISDIR', 'copyfile', $path, $destination); + } + if (($flags & 1) && (file_exists($target) || is_link($target))) { + throw new FileSystemError('EEXIST', 'copyfile', $path, $destination); + } + if ($flags & 4) { + throw new FileSystemError('ENOTSUP', 'copyfile', $path, $destination); + } + $sourceStat = @stat($source); + $targetStat = @stat($target); + if ( + is_array($sourceStat) && is_array($targetStat) + && $sourceStat['dev'] === $targetStat['dev'] && $sourceStat['ino'] === $targetStat['ino'] + ) { + return JsUndefined::instance(); + } + $input = @fopen($source, 'rb'); + if ($input === false) { + throw $this->pathError('copyfile', $path); + } + try { + $output = @fopen($target, ($flags & 1) ? 'xb' : 'wb'); + if ($output === false) { + throw new FileSystemError(!is_dir(dirname($target)) ? 'ENOENT' : 'EACCES', 'copyfile', $path, $destination); + } + try { + if (stream_copy_to_stream($input, $output) === false) { + throw new FileSystemError('EIO', 'copyfile', $path, $destination); + } + if (is_array($sourceStat)) { + @chmod($target, $sourceStat['mode'] & 0777); + } + } finally { + fclose($output); + } + } finally { + fclose($input); + } + return JsUndefined::instance(); + } + $success = match ($operation) { + 'rename' => @rename($source, $target), + 'link' => @link($source, $target), + default => @symlink($path, $target), + }; + if (!$success) { + $code = ($operation !== 'rename' && (file_exists($target) || is_link($target))) ? 'EEXIST' : null; + $error = $this->pathError($operation, $path, $code); + throw new FileSystemError($error->errorCode, $operation, $path, $destination); + } + return JsUndefined::instance(); + } + + /** @return array{stream: resource, path: string, readable: bool, writable: bool} */ + private function descriptor(int $descriptor, string $operation): array + { + if (!isset($this->descriptors[$descriptor])) { + throw new FileSystemError('EBADF', $operation); + } + return $this->descriptors[$descriptor]; + } + + /** @param array $stat */ + private function statObject(array $stat): JsObject + { + $result = new JsObject(); + foreach (['dev', 'mode', 'nlink', 'uid', 'gid', 'rdev', 'blksize', 'ino', 'size', 'blocks'] as $key) { + $result->set($key, JsNumber::of($stat[$key] ?? 0)); + } + foreach (['atime', 'mtime', 'ctime', 'birthtime'] as $key) { + $result->set($key . 'Ms', JsNumber::of(($stat[$key] ?? $stat['ctime']) * 1000)); + } + return $result; + } + + private function bytes(string $bytes): JsTypedArray + { + $constructor = $this->engine->getGlobalEnv()->get('Uint8Array'); + $prototype = $constructor instanceof JsObject ? $constructor->get('prototype') : null; + $view = JsTypedArray::fromLength('Uint8Array', strlen($bytes), $prototype instanceof JsObject ? $prototype : null); + $view->getBuffer()->setData($bytes); + return $view; + } + + private function pathError(string $operation, string $path, ?string $code = null): FileSystemError + { + if ($code !== null) { + return new FileSystemError($code, $operation, $path); + } + $absolute = $this->runtime->absolutePath($path); + $nameTooLong = defined('SOCKET_ENAMETOOLONG') ? constant('SOCKET_ENAMETOOLONG') : (PHP_OS_FAMILY === 'Darwin' ? 63 : 36); + // PHP's stat warning omits errno. pathconf preserves the host's path-resolution error. + if (function_exists('posix_pathconf')) { + if (@posix_pathconf($absolute, POSIX_PC_NAME_MAX) === false && posix_get_last_error() === $nameTooLong) { + return new FileSystemError('ENAMETOOLONG', $operation, $path); + } + } elseif (strlen($absolute) >= PHP_MAXPATHLEN) { + return new FileSystemError('ENAMETOOLONG', $operation, $path); + } + if (function_exists('posix_access') && !@posix_access($absolute, POSIX_F_OK) && posix_get_last_error() === $nameTooLong) { + return new FileSystemError('ENAMETOOLONG', $operation, $path); + } + $parent = dirname($absolute); + while (!file_exists($parent) && !is_link($parent) && dirname($parent) !== $parent) { + $parent = dirname($parent); + } + $code = !is_dir($parent) ? 'ENOTDIR' : (file_exists($absolute) ? 'EACCES' : 'ENOENT'); + return new FileSystemError($code, $operation, $path); + } + + private static function error(FileSystemError $error): JsObject + { + $codes = [ + 'EPERM' => [1, 'operation not permitted'], 'ENOENT' => [2, 'no such file or directory'], + 'EIO' => [5, 'i/o error'], 'EBADF' => [9, 'bad file descriptor'], + 'EACCES' => [13, 'permission denied'], 'EEXIST' => [17, 'file already exists'], + 'ENOTDIR' => [20, 'not a directory'], 'EISDIR' => [21, 'illegal operation on a directory'], + 'EINVAL' => [22, 'invalid argument'], 'EMFILE' => [24, 'too many open files'], + 'ESPIPE' => [29, 'invalid seek'], 'ENOSYS' => [PHP_OS_FAMILY === 'Darwin' ? 78 : 38, 'function not implemented'], + 'ENOTEMPTY' => [PHP_OS_FAMILY === 'Darwin' ? 66 : 39, 'directory not empty'], + 'ENAMETOOLONG' => [ + defined('SOCKET_ENAMETOOLONG') ? constant('SOCKET_ENAMETOOLONG') : (PHP_OS_FAMILY === 'Darwin' ? 63 : 36), + 'name too long', + ], + 'ENOTSUP' => [PHP_OS_FAMILY === 'Darwin' ? 45 : 95, 'operation not supported on socket'], + ]; + [$number, $description] = $codes[$error->errorCode] ?? [5, 'i/o error']; + $message = $error->errorCode . ': ' . $description . ', ' . $error->syscall; + $data = ['errno' => -$number, 'code' => $error->errorCode, 'syscall' => $error->syscall]; + if ($error->path !== null) { + $data['path'] = $error->path; + $message .= " '{$error->path}'"; + } + if ($error->destination !== null) { + $data['dest'] = $error->destination; + $message .= " -> '{$error->destination}'"; + } + $data['message'] = $message; + $value = PhpToJs::convert($data); + assert($value instanceof JsObject); + return $value; + } + + private function closeAll(): void + { + foreach ($this->descriptors as $entry) { + if (is_resource($entry['stream'])) { + fclose($entry['stream']); + } + } + $this->descriptors = []; + } +} diff --git a/src/Node/FileSystemError.php b/src/Node/FileSystemError.php new file mode 100644 index 00000000..af8554d9 --- /dev/null +++ b/src/Node/FileSystemError.php @@ -0,0 +1,18 @@ +set('fs', FileSystemBindings::create($engine, $runtime)); + $host->set('net', IoBindings::create($engine, $runtime)); + $host->set('crypto', CryptoBindings::create($engine, $runtime)); + $host->set('zlib', ZlibBindings::create($engine, $runtime)); + $host->set('vm', VmBindings::create($engine, $runtime)); + $host->set('child_process', ChildProcessBindings::create($engine, $runtime)); + $host->set('path', PathBindings::create()); + self::method($host, 'isatty', static function (array $args): JsValue { + $fd = (int) ($args[0] ?? JsUndefined::instance())->toNumber(); + $stream = match ($fd) { + 0 => STDIN, 1 => STDOUT, 2 => STDERR, default => null + }; + return new JsBoolean($stream !== null && stream_isatty($stream)); + }); + self::method($host, 'stdioWrite', static function (array $args): JsValue { + $fd = (int) ($args[0] ?? JsUndefined::instance())->toNumber(); + $stream = match ($fd) { + 1 => STDOUT, 2 => STDERR, default => null + }; + $data = $args[1] ?? JsUndefined::instance(); + if ($stream === null || !$data instanceof \Phasis\Value\JsTypedArray) { + throw new TypeError('Invalid standard stream write'); + } + $bytes = $data->getBuffer()->readBytes($data->getByteOffset(), $data->getLength()); + $written = fwrite($stream, $bytes); + if ($written === false) { + throw new \RuntimeException('Cannot write to standard stream'); + } + return JsNumber::of($written); + }); + self::method($host, 'stdioRead', static function (array $args): JsValue { + if ((int) ($args[0] ?? JsUndefined::instance())->toNumber() !== 0) { + throw new TypeError('Invalid standard input descriptor'); + } + $read = [STDIN]; + $write = $except = []; + if (stream_select($read, $write, $except, 0, 0) === 0) { + return JsUndefined::instance(); + } + $bytes = fread(STDIN, 65536); + if ($bytes === false) { + throw new \RuntimeException('Cannot read standard input'); + } + if ($bytes === '' && feof(STDIN)) { + return \Phasis\Value\JsNull::instance(); + } + $buffer = new \Phasis\Value\JsArrayBuffer(strlen($bytes)); + $buffer->setData($bytes); + return new \Phasis\Value\JsTypedArray('Uint8Array', $buffer, 0, strlen($bytes)); + }); + self::method($host, 'timer', static function (array $args) use ($engine): JsValue { + $operation = ($args[0] ?? JsUndefined::instance())->toJsString(); + $loop = $engine->getEventLoop(); + if ($operation === 'clear') { + $loop->clear((int) ($args[1] ?? JsUndefined::instance())->toNumber()); + return JsUndefined::instance(); + } + if ($operation === 'ref') { + $loop->reference((int) ($args[1] ?? JsUndefined::instance())->toNumber(), ($args[2] ?? JsUndefined::instance())->toBoolean()); + return JsUndefined::instance(); + } + $callback = self::functionArgument($args[1] ?? JsUndefined::instance()); + $delay = ($args[2] ?? JsUndefined::instance())->toNumber(); + return JsNumber::of(match ($operation) { + 'immediate' => $loop->setImmediate($callback), + 'interval' => $loop->setInterval($callback, $delay), + 'timeout' => $loop->setTimeout($callback, $delay), + default => throw new TypeError('Unknown timer operation.'), + }); + }); + $started = hrtime(true); + self::method($host, 'cwd', static fn (array $args): JsValue => new JsString($runtime->cwd())); + self::method($host, 'chdir', static function (array $args) use ($runtime): JsValue { + $runtime->chdir(($args[0] ?? JsUndefined::instance())->toJsString()); + return JsUndefined::instance(); + }); + self::method($host, 'nextTick', static function (array $args) use ($runtime): JsValue { + $callback = self::functionArgument($args[0] ?? JsUndefined::instance()); + $runtime->nextTick($callback, array_slice($args, 1)); + return JsUndefined::instance(); + }); + self::method($host, 'hrtime', static function (array $args): JsValue { + $now = hrtime(true); + return PhpToJs::convert([intdiv($now, 1_000_000_000), $now % 1_000_000_000]); + }); + self::method($host, 'hrtimeBigInt', static fn (array $args): JsValue => new \Phasis\Value\JsBigInt((string) hrtime(true))); + self::method($host, 'uptime', static fn (array $args): JsValue => JsNumber::of((hrtime(true) - $started) / 1e9)); + self::method($host, 'memoryUsage', static fn (array $args): JsValue => PhpToJs::convert([ + 'rss' => memory_get_usage(true), 'heapTotal' => memory_get_usage(true), + 'heapUsed' => memory_get_usage(), 'external' => 0, 'arrayBuffers' => 0, + ])); + self::method($host, 'pid', static fn (array $args): JsValue => JsNumber::of(getmypid() ?: 0)); + self::method($host, 'ppid', static fn (array $args): JsValue => JsNumber::of(function_exists('posix_getppid') ? posix_getppid() : 0)); + self::method($host, 'builtin', static fn (array $args): JsValue => $runtime->module(($args[0] ?? JsUndefined::instance())->toJsString())); + self::method($host, 'builtinNames', static fn (array $args): JsValue => PhpToJs::convert($runtime->builtinNames())); + self::method($host, 'createRequire', static function (array $args) use ($engine): JsValue { + $path = ($args[0] ?? JsUndefined::instance())->toJsString(); + if (str_starts_with($path, 'file:')) { + $parsed = parse_url($path); + if ( + $parsed === false || !isset($parsed['path']) + || (isset($parsed['host']) && $parsed['host'] !== '' && $parsed['host'] !== 'localhost') + ) { + throw new TypeError('createRequire expects a local file URL or absolute filename.'); + } + $path = rawurldecode($parsed['path']); + } + if (!str_starts_with($path, '/')) { + throw new TypeError('createRequire expects a file URL or absolute filename.'); + } + return $engine->getInterpreter()->getModuleLoader()->createRequire($path); + }); + self::method($host, 'eventListeners', static function (array $args): JsValue { + $target = self::objectArgument($args[0] ?? JsUndefined::instance()); + if ($target->getInternalProperty(\Phasis\BuiltIn\EventTargetConstructor::SLOT_IS_TARGET) !== true) { + throw new TypeError('Expected an EventTarget.'); + } + $type = ($args[1] ?? JsUndefined::instance())->toJsString(); + /** @var array>> $listeners */ + $listeners = $target->getInternalProperty(\Phasis\BuiltIn\EventTargetConstructor::SLOT_LISTENERS) ?? []; + $callbacks = []; + foreach ($listeners[$type] ?? [] as $listener) { + if (!empty($listener['removed'])) { + continue; + } + $signal = $listener['signal'] ?? null; + if ($signal instanceof JsObject && $signal->get('aborted')->toBoolean()) { + continue; + } + if (($listener['callback'] ?? null) instanceof JsValue) { + $callbacks[] = $listener['callback']; + } + } + return PhpToJs::convert($callbacks); + }); + self::method($host, 'contextGet', static function (array $args): JsValue { + $key = self::objectArgument($args[0] ?? JsUndefined::instance()); + return AsyncContextStorage::active()->getRaw($key) ?? JsUndefined::instance(); + }); + self::method($host, 'contextHas', static function (array $args): JsValue { + $key = self::objectArgument($args[0] ?? JsUndefined::instance()); + return new JsBoolean(AsyncContextStorage::active()->getRaw($key) !== null); + }); + self::method($host, 'contextSet', static function (array $args): JsValue { + AsyncContextStorage::active()->set(self::objectArgument($args[0] ?? JsUndefined::instance()), $args[1] ?? JsUndefined::instance()); + return JsUndefined::instance(); + }); + self::method($host, 'contextDelete', static function (array $args): JsValue { + AsyncContextStorage::active()->restoreSlot(self::objectArgument($args[0] ?? JsUndefined::instance()), null); + return JsUndefined::instance(); + }); + self::method($host, 'contextRun', static function (array $args) use ($engine): JsValue { + $key = self::objectArgument($args[0] ?? JsUndefined::instance()); + $callback = self::functionArgument($args[2] ?? JsUndefined::instance()); + $storage = AsyncContextStorage::active(); + $previous = $storage->getRaw($key); + $storage->set($key, $args[1] ?? JsUndefined::instance()); + try { + return $engine->getInterpreter()->callFunction($callback, JsUndefined::instance(), array_slice($args, 3)); + } finally { + $storage->restoreSlot($key, $previous); + } + }); + self::method($host, 'contextCapture', static function (array $args): JsValue { + $snapshot = new JsObject(); + $snapshot->setInternalProperty('[[NodeAsyncSnapshot]]', AsyncContextStorage::active()->snapshot()); + return $snapshot; + }); + self::method($host, 'contextRunSnapshot', static function (array $args) use ($engine): JsValue { + $token = self::objectArgument($args[0] ?? JsUndefined::instance()); + $snapshot = $token->getInternalProperty('[[NodeAsyncSnapshot]]'); + if (!is_array($snapshot)) { + throw new TypeError('Invalid async context snapshot.'); + } + $callback = self::functionArgument($args[1] ?? JsUndefined::instance()); + $storage = AsyncContextStorage::active(); + $previous = $storage->snapshot(); + /** @var array{0: array, 1: array} $snapshot */ + $storage->restore($snapshot); + try { + return $engine->getInterpreter()->callFunction($callback, $args[2] ?? JsUndefined::instance(), array_slice($args, 3)); + } finally { + $storage->restore($previous); + } + }); + return $host; + } + + /** @param \Closure(list): JsValue $callback */ + private static function method(JsObject $target, string $name, \Closure $callback): void + { + $target->set($name, JsFunction::fromCallable($name, static fn (JsValue $this_, array $args): JsValue => $callback($args))); + } + + private static function objectArgument(JsValue $value): JsObject + { + if (!$value instanceof JsObject) { + throw new TypeError('Expected an object.'); + } + return $value; + } + + private static function functionArgument(JsValue $value): JsFunction + { + if (!$value instanceof JsFunction) { + throw new TypeError('The callback argument must be a function.'); + } + return $value; + } +} diff --git a/src/Node/IoBindings.php b/src/Node/IoBindings.php new file mode 100644 index 00000000..2089e8da --- /dev/null +++ b/src/Node/IoBindings.php @@ -0,0 +1,636 @@ + */ + private array $sockets = []; + private int $sequence = 0; + + private function __construct(private readonly Engine $engine, private readonly NodeRuntime $runtime) + { + $engine->getEventLoop()->setIoDriver(fn (int $timeout): bool => $this->poll($timeout), fn (): bool => $this->hasReferences()); + $runtime->onClose(fn () => $this->closeAll()); + } + + public static function create(Engine $engine, NodeRuntime $runtime): JsObject + { + $io = new self($engine, $runtime); + $host = new JsObject(); + $host->set('call', JsFunction::fromCallable('call', function (JsValue $this_, array $args) use ($io): JsValue { + $operation = ($args[0] ?? JsUndefined::instance())->toJsString(); + return $io->operation($operation, array_slice($args, 1)); + })); + return $host; + } + + /** @param list $args */ + private function operation(string $operation, array $args): JsValue + { + $result = new JsObject(); + try { + $result->set('value', match ($operation) { + 'listen' => $this->listen($args), + 'connect' => $this->connect($args), + 'callback' => $this->setCallback($args), + 'write' => $this->write($args), + 'end' => $this->end($args), + 'close' => $this->close((int) ($args[0] ?? JsUndefined::instance())->toNumber()), + 'pause' => $this->pause($args), + 'ref' => $this->reference($args), + 'address' => $this->address($args), + 'startTls' => $this->startTls($args), + 'tlsInfo' => $this->tlsInfo($this->socket($args[0] ?? JsUndefined::instance())), + 'isIP' => JsNumber::of($this->ipVersion(($args[0] ?? JsUndefined::instance())->toJsString())), + 'noDelay', 'keepAlive' => $this->socketOption($operation, $args), + default => throw new TypeError("Unknown socket operation '{$operation}'"), + }); + } catch (\RuntimeException $error) { + $result->set('error', $this->error($error->getMessage(), $error->getCode(), $operation)); + } + return $result; + } + + /** @param list $args */ + private function listen(array $args): JsValue + { + $options = $this->object($args[0] ?? JsUndefined::instance()); + $callback = $this->function($args[1] ?? JsUndefined::instance()); + $path = $options->get('path'); + $host = $options->get('host'); + $host = $host instanceof JsUndefined ? '::' : $host->toJsString(); + $port = (int) $options->get('port')->toNumber(); + $address = $path instanceof JsUndefined + ? 'tcp://' . (str_contains($host, ':') ? '[' . trim($host, '[]') . ']' : $host) . ':' . $port + : 'unix://' . $this->runtime->absolutePath($path->toJsString()); + $backlog = $options->get('backlog'); + $context = stream_context_create(['socket' => [ + 'backlog' => $backlog instanceof JsUndefined ? 511 : (int) $backlog->toNumber(), + 'ipv6_v6only' => $options->get('ipv6Only')->toBoolean(), + ]]); + $errno = 0; + $message = ''; + $stream = @stream_socket_server($address, $errno, $message, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context); + if ($stream === false) { + throw new \RuntimeException($message, $errno); + } + stream_set_blocking($stream, false); + $id = ++$this->sequence; + $this->sockets[$id] = new SocketState($id, $stream, true, $callback, AsyncContextStorage::active()->snapshot()); + return JsNumber::of($id); + } + + /** @param list $args */ + private function connect(array $args): JsValue + { + $options = $this->object($args[0] ?? JsUndefined::instance()); + $callback = $this->function($args[1] ?? JsUndefined::instance()); + $path = $options->get('path'); + $host = $options->get('host'); + $host = $host instanceof JsUndefined ? 'localhost' : $host->toJsString(); + $address = $path instanceof JsUndefined + ? 'tcp://' . (str_contains($host, ':') ? '[' . trim($host, '[]') . ']' : $host) . ':' . (int) $options->get('port')->toNumber() + : 'unix://' . $this->runtime->absolutePath($path->toJsString()); + $errno = 0; + $message = ''; + $stream = @stream_socket_client( + $address, + $errno, + $message, + 0, + STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT, + stream_context_create(), + ); + if ($stream === false) { + throw new \RuntimeException($message, $errno); + } + stream_set_blocking($stream, false); + $id = ++$this->sequence; + $state = new SocketState($id, $stream, false, $callback, AsyncContextStorage::active()->snapshot()); + $state->connecting = true; + $this->sockets[$id] = $state; + return JsNumber::of($id); + } + + /** @param list $args */ + private function setCallback(array $args): JsValue + { + $this->socket($args[0] ?? JsUndefined::instance())->callback = $this->function($args[1] ?? JsUndefined::instance()); + return JsUndefined::instance(); + } + + /** @param list $args */ + private function write(array $args): JsValue + { + $socket = $this->socket($args[0] ?? JsUndefined::instance()); + $data = $args[1] ?? JsUndefined::instance(); + if (!$data instanceof JsTypedArray || $data->getTypeName() !== 'Uint8Array') { + throw new TypeError('Socket writes require Uint8Array bytes.'); + } + $socket->output .= $data->getBuffer()->readBytes($data->getByteOffset(), $data->getLength()); + $socket->writeCallback = $this->function($args[2] ?? JsUndefined::instance()); + return JsUndefined::instance(); + } + + /** @param list $args */ + private function end(array $args): JsValue + { + $socket = $this->socket($args[0] ?? JsUndefined::instance()); + $socket->ending = true; + return JsUndefined::instance(); + } + + /** @param list $args */ + private function pause(array $args): JsValue + { + $this->socket($args[0] ?? JsUndefined::instance())->paused = ($args[1] ?? JsUndefined::instance())->toBoolean(); + return JsUndefined::instance(); + } + + /** @param list $args */ + private function reference(array $args): JsValue + { + $this->socket($args[0] ?? JsUndefined::instance())->referenced = ($args[1] ?? JsUndefined::instance())->toBoolean(); + return JsUndefined::instance(); + } + + /** @param list $args */ + private function socketOption(string $operation, array $args): JsValue + { + $state = $this->socket($args[0] ?? JsUndefined::instance()); + $enabled = ($args[1] ?? JsUndefined::instance())->toBoolean(); + if (!function_exists('socket_import_stream')) { + if ($operation === 'noDelay') { + stream_context_set_option($state->stream, 'socket', 'tcp_nodelay', $enabled); + return JsUndefined::instance(); + } + throw new \RuntimeException('Socket keepalive requires the PHP sockets extension', 95); + } + $socket = @socket_import_stream($state->stream); + if ($socket === false) { + throw new \RuntimeException('Cannot access socket options', 9); + } + $ok = $operation === 'noDelay' + ? @socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $enabled) + : @socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, (int) $enabled); + if (!$ok) { + $errno = socket_last_error($socket); + throw new \RuntimeException(socket_strerror($errno), $errno); + } + return JsUndefined::instance(); + } + + /** @param list $args */ + private function address(array $args): JsValue + { + $socket = $this->socket($args[0] ?? JsUndefined::instance()); + $address = @stream_socket_get_name($socket->stream, ($args[1] ?? JsUndefined::instance())->toBoolean()); + if ($address === false) { + return \Phasis\Value\JsNull::instance(); + } + $colon = strrpos($address, ':'); + if ($colon === false) { + return new JsString($address); + } + $host = trim(substr($address, 0, $colon), '[]'); + return PhpToJs::convert([ + 'address' => $host, + 'port' => (int) substr($address, $colon + 1), + 'family' => str_contains($host, ':') ? 'IPv6' : 'IPv4', + ]); + } + + private function hasReferences(): bool + { + foreach ($this->sockets as $socket) { + if ($socket->referenced) { + return true; + } + } + return false; + } + + private function poll(int $timeout): bool + { + $read = $write = $except = $map = []; + foreach ($this->sockets as $socket) { + $map[(int) $socket->stream] = $socket; + if ($socket->tlsNegotiating || (!$socket->paused && !$socket->readEnded)) { + $read[] = $socket->stream; + } + if ( + $socket->connecting || ($socket->tlsNegotiating && !$socket->tlsHandshakeStarted) + || (!$socket->tlsNegotiating && ($socket->output !== '' || $socket->writeCallback !== null + || ($socket->ending && !$socket->writeEnded))) + ) { + $write[] = $socket->stream; + } + } + if ($read === [] && $write === []) { + if ($timeout > 0) { + usleep($timeout * 1000); + } + return false; + } + $ready = @stream_select($read, $write, $except, intdiv($timeout, 1000), ($timeout % 1000) * 1000); + if ($ready === false || $ready === 0) { + return false; + } + foreach ($write as $stream) { + $socket = $map[(int) $stream]; + if (!isset($this->sockets[$socket->id])) { + continue; + } + if ($socket->connecting) { + $socket->connecting = false; + $errno = 0; + if (function_exists('socket_import_stream')) { + $native = @socket_import_stream($stream); + if ($native !== false) { + $errno = (int) @socket_get_option($native, SOL_SOCKET, SO_ERROR); + } + } + if ($errno !== 0 || @stream_socket_get_name($stream, true) === false) { + $message = $errno !== 0 && function_exists('socket_strerror') + ? socket_strerror($errno) : 'Connection refused'; + $this->emit($socket, 'error', $this->error($message, $errno, 'connect')); + $this->close($socket->id); + continue; + } + $this->emit($socket, 'connect'); + } + if ($socket->tlsNegotiating && !$this->handshake($socket)) { + continue; + } + if (!is_resource($stream) || !isset($this->sockets[$socket->id])) { + continue; + } + if ($socket->output !== '') { + $written = @fwrite($stream, $socket->output); + if ($written === false) { + $this->emit($socket, 'error', $this->error('Broken pipe', 32, 'write')); + $this->close($socket->id); + continue; + } + $socket->output = substr($socket->output, $written); + } + if ($socket->output === '' && $socket->writeCallback !== null) { + $callback = $socket->writeCallback; + $socket->writeCallback = null; + $this->runtime->nextTick($callback); + } + if ($socket->ending && $socket->output === '' && !$socket->writeEnded) { + $socket->writeEnded = true; + @stream_socket_shutdown($stream, STREAM_SHUT_WR); + $this->emit($socket, 'shutdown'); + } + } + foreach ($read as $stream) { + if (!is_resource($stream) || !isset($map[(int) $stream])) { + continue; + } + $socket = $map[(int) $stream]; + if (!isset($this->sockets[$socket->id])) { + continue; + } + if ($socket->server) { + $connection = @stream_socket_accept($stream, 0); + if ($connection !== false) { + stream_set_blocking($connection, false); + $id = ++$this->sequence; + $accepted = new SocketState($id, $connection, false, null, $socket->context); + $this->sockets[$id] = $accepted; + $this->emit($socket, 'connection', JsNumber::of($id)); + $this->readSocket($accepted); + } + continue; + } + $this->readSocket($socket); + } + return true; + } + + private function readSocket(SocketState $socket): void + { + if (!isset($this->sockets[$socket->id]) || $socket->paused || $socket->readEnded) { + return; + } + if ($socket->tlsNegotiating && !$this->handshake($socket)) { + return; + } + $stream = $socket->stream; + if (!is_resource($stream)) { + return; + } + $data = @fread($stream, 65536); + if ($data !== false && $data !== '') { + $buffer = new JsArrayBuffer(strlen($data)); + $buffer->setData($data); + $this->emit($socket, 'data', new JsTypedArray('Uint8Array', $buffer, 0, strlen($data))); + } + if (is_resource($stream) && isset($this->sockets[$socket->id]) && feof($stream)) { + $socket->readEnded = true; + $this->emit($socket, 'end'); + } + } + + private function emit(SocketState $socket, string $event, ?JsValue $value = null): void + { + if ($socket->callback === null) { + return; + } + $previous = Engine::getCurrentInterpreter(); + $context = AsyncContextStorage::active()->snapshot(); + Engine::setCurrentInterpreter($this->engine->getInterpreter()); + AsyncContextStorage::active()->restore($socket->context); + try { + $this->engine->getInterpreter()->callFunction( + $socket->callback, + JsUndefined::instance(), + [new JsString($event), $value ?? JsUndefined::instance()], + ); + } finally { + AsyncContextStorage::active()->restore($context); + Engine::setCurrentInterpreter($previous); + } + } + + private function close(int $id): JsValue + { + $socket = $this->sockets[$id] ?? null; + if ($socket !== null) { + unset($this->sockets[$id]); + if (is_resource($socket->stream)) { + fclose($socket->stream); + } + foreach ($socket->tlsFiles as $file) { + @unlink($file); + } + $this->emit($socket, 'close'); + } + return JsUndefined::instance(); + } + + private function closeAll(): void + { + foreach ($this->sockets as $socket) { + if (is_resource($socket->stream)) { + fclose($socket->stream); + } + foreach ($socket->tlsFiles as $file) { + @unlink($file); + } + } + $this->sockets = []; + $this->engine->getEventLoop()->setIoDriver(null, null); + } + + private function socket(JsValue $id): SocketState + { + return $this->sockets[(int) $id->toNumber()] ?? throw new \RuntimeException('Socket is closed', 9); + } + + private function object(JsValue $value): JsObject + { + return $value instanceof JsObject ? $value : throw new TypeError('Expected socket options.'); + } + + private function function(JsValue $value): JsFunction + { + return $value instanceof JsFunction ? $value : throw new TypeError('Expected socket callback.'); + } + + private function ipVersion(string $host): int + { + return filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false ? 4 + : (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false ? 6 : 0); + } + + private function error(string $message, int $errno, string $syscall): JsObject + { + if ($errno === 0 && function_exists('socket_strerror')) { + foreach (['SOCKET_EADDRINUSE', 'SOCKET_ECONNREFUSED', 'SOCKET_EACCES', 'SOCKET_ENOENT', 'SOCKET_EPIPE'] as $constant) { + if (defined($constant)) { + $candidate = (int) constant($constant); + if (stripos($message, socket_strerror($candidate)) !== false) { + $errno = $candidate; + break; + } + } + } + } + $code = 'EIO'; + foreach (get_defined_constants() as $name => $value) { + if (str_starts_with($name, 'SOCKET_E') && $value === abs($errno)) { + $code = substr($name, 7); + break; + } + } + $error = new JsObject(); + $error->set('message', new JsString($code . ': ' . $message)); + $error->set('code', new JsString($code)); + $error->set('errno', JsNumber::of(-abs($errno))); + $error->set('syscall', new JsString($syscall)); + return $error; + } + + /** @param list $args */ + private function startTls(array $args): JsValue + { + if (!function_exists('stream_socket_enable_crypto')) { + throw new TypeError('TLS requires the PHP OpenSSL extension.'); + } + $socket = $this->socket($args[0] ?? JsUndefined::instance()); + $options = $this->object($args[1] ?? JsUndefined::instance()); + $socket->tlsServer = $options->get('isServer')->toBoolean(); + $reject = $options->get('rejectUnauthorized'); + $reject = $reject instanceof JsUndefined || $reject->toBoolean(); + $requestCertificate = $options->get('requestCert')->toBoolean(); + if ($socket->tlsServer && $requestCertificate && !$reject) { + throw new TypeError('Optional unverified client certificates are unavailable through PHP TLS streams.'); + } + $ssl = [ + 'verify_peer' => $socket->tlsServer ? $requestCertificate : $reject, + 'verify_peer_name' => !$socket->tlsServer && $reject && !$options->get('customIdentityCheck')->toBoolean(), + 'allow_self_signed' => false, + 'capture_peer_cert' => true, + 'capture_peer_cert_chain' => true, + 'disable_compression' => true, + 'SNI_enabled' => true, + ]; + $servername = $options->get('servername'); + $hostname = $options->get('host'); + if (!$socket->tlsServer) { + $peer = $servername instanceof JsUndefined || $servername->toJsString() === '' ? $hostname : $servername; + if (!$peer instanceof JsUndefined) { + $ssl['peer_name'] = $peer->toJsString(); + } + } + foreach (['cert' => 'local_cert', 'key' => 'local_pk', 'ca' => 'cafile'] as $name => $target) { + $value = $options->get($name); + if (!$value instanceof JsUndefined) { + $file = $this->tlsFile($socket, $this->tlsBytes($value)); + $ssl[$target] = $file; + if ($name === 'ca') { + $socket->tlsAuthorities = [$file]; + } + } + } + foreach (['passphrase' => 'passphrase', 'ciphers' => 'ciphers', 'ecdhCurve' => 'ecdh_curve'] as $name => $target) { + $value = $options->get($name); + if (!$value instanceof JsUndefined) { + $ssl[$target] = $value->toJsString(); + } + } + $alpn = $options->get('ALPNProtocols'); + if ($alpn instanceof JsObject) { + $protocols = []; + for ($i = 0, $length = (int) $alpn->get('length')->toNumber(); $i < $length; $i++) { + $protocols[] = $alpn->get((string) $i)->toJsString(); + } + $ssl['alpn_protocols'] = implode(',', $protocols); + } + $minimum = $options->get('minVersion'); + $maximum = $options->get('maxVersion'); + $minimum = $minimum instanceof JsUndefined ? 'TLSv1.2' : $minimum->toJsString(); + $maximum = $maximum instanceof JsUndefined ? 'TLSv1.3' : $maximum->toJsString(); + $versions = ['TLSv1' => 'TLSv1_0', 'TLSv1.1' => 'TLSv1_1', 'TLSv1.2' => 'TLSv1_2', 'TLSv1.3' => 'TLSv1_3']; + $include = false; + $method = 0; + foreach ($versions as $name => $constant) { + if ($name === $minimum) { + $include = true; + } + if ($include) { + $option = 'STREAM_CRYPTO_METHOD_' . $constant . ($socket->tlsServer ? '_SERVER' : '_CLIENT'); + if (defined($option)) { + $method |= (int) constant($option); + } + } + if ($name === $maximum) { + break; + } + } + if ($method === 0 || !isset($versions[$minimum], $versions[$maximum])) { + throw new TypeError('Invalid TLS version range.'); + } + foreach ($ssl as $name => $value) { + stream_context_set_option($socket->stream, 'ssl', $name, $value); + } + $socket->tlsMethod = $method; + $socket->tlsNegotiating = true; + $timeout = $options->get('handshakeTimeout'); + $socket->tlsDeadline = microtime(true) + ($timeout instanceof JsUndefined ? 120 : $timeout->toNumber() / 1000); + return JsUndefined::instance(); + } + + private function handshake(SocketState $socket): bool + { + $socket->tlsHandshakeStarted = true; + $message = ''; + set_error_handler(static function (int $number, string $text) use (&$message): bool { + $message .= ($message === '' ? '' : ' ') . $text; + return true; + }); + try { + $result = stream_socket_enable_crypto($socket->stream, true, $socket->tlsMethod); + } finally { + restore_error_handler(); + } + if ($result === true) { + $socket->tlsNegotiating = false; + $socket->tls = true; + $this->emit($socket, 'secure', $this->tlsInfo($socket)); + return is_resource($socket->stream) && isset($this->sockets[$socket->id]); + } + if ($result === false || microtime(true) > $socket->tlsDeadline) { + $socket->tlsNegotiating = false; + $error = new JsObject(); + $error->set('message', new JsString($message !== '' ? $message : 'TLS handshake timed out.')); + $code = $result === false ? 'ERR_SSL_TLSV1_ALERT_INTERNAL_ERROR' : 'ERR_TLS_HANDSHAKE_TIMEOUT'; + if (stripos($message, 'certificate verify failed') !== false) { + $code = 'CERTIFICATE_VERIFY_FAILED'; + } + $error->set('code', new JsString($code)); + $this->emit($socket, 'error', $error); + $this->close($socket->id); + } + return false; + } + + private function tlsInfo(SocketState $socket): JsValue + { + $metadata = stream_get_meta_data($socket->stream); + $context = stream_context_get_options($socket->stream); + $peer = $context['ssl']['peer_certificate'] ?? null; + $certificate = $peer instanceof \OpenSSLCertificate ? openssl_x509_parse($peer) : false; + $authorized = false; + $authorizationError = 'UNABLE_TO_GET_ISSUER_CERT'; + if ($certificate !== false && $peer instanceof \OpenSSLCertificate) { + $purpose = $socket->tlsServer ? X509_PURPOSE_SSL_CLIENT : X509_PURPOSE_SSL_SERVER; + $authorized = openssl_x509_checkpurpose($peer, $purpose, $socket->tlsAuthorities) === true; + $authorizationError = ($certificate['validTo_time_t'] ?? PHP_INT_MAX) < time() ? 'CERT_HAS_EXPIRED' : 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'; + $pem = ''; + openssl_x509_export($peer, $pem); + $certificate['rawBase64'] = preg_replace('/-----[^-]+-----|\s/', '', $pem); + $certificate['fingerprint'] = strtoupper(implode(':', str_split(openssl_x509_fingerprint($peer, 'sha1') ?: '', 2))); + $certificate['fingerprint256'] = strtoupper(implode(':', str_split(openssl_x509_fingerprint($peer, 'sha256') ?: '', 2))); + $certificate['serialNumber'] = $certificate['serialNumberHex'] ?? $certificate['serialNumber'] ?? ''; + $certificate['subjectaltname'] = $certificate['extensions']['subjectAltName'] ?? ''; + $certificate['valid_from'] = gmdate('M j H:i:s Y \G\M\T', (int) ($certificate['validFrom_time_t'] ?? 0)); + $certificate['valid_to'] = gmdate('M j H:i:s Y \G\M\T', (int) ($certificate['validTo_time_t'] ?? 0)); + } + return PhpToJs::convert([ + 'protocol' => $metadata['crypto']['protocol'] ?? null, + 'cipher' => [ + 'name' => $metadata['crypto']['cipher_name'] ?? null, + 'version' => $metadata['crypto']['cipher_version'] ?? null, + 'bits' => $metadata['crypto']['cipher_bits'] ?? null, + ], + 'alpnProtocol' => $metadata['crypto']['alpn_protocol'] ?? false, + 'authorized' => $authorized, + 'authorizationError' => $authorized ? null : $authorizationError, + 'certificate' => $certificate === false ? [] : $certificate, + ]); + } + + private function tlsFile(SocketState $socket, string $contents): string + { + $file = tempnam(sys_get_temp_dir(), 'phasis-tls-'); + if ($file === false) { + throw new TypeError('Unable to create a TLS material file.'); + } + $socket->tlsFiles[] = $file; + chmod($file, 0600); + if (file_put_contents($file, $contents) !== strlen($contents)) { + throw new TypeError('Unable to write TLS material.'); + } + return $file; + } + + private function tlsBytes(JsValue $value): string + { + if ($value instanceof JsTypedArray) { + return $value->getBuffer()->readBytes($value->getByteOffset(), $value->getLength() * $value->getBytesPerElement()); + } + return $value->toJsString(); + } +} diff --git a/src/Node/Lib/assert.cjs b/src/Node/Lib/assert.cjs new file mode 100644 index 00000000..f68c6d4a --- /dev/null +++ b/src/Node/Lib/assert.cjs @@ -0,0 +1,4629 @@ +var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; + +// scripts/node-portable/node_modules/has-symbols/shams.js +var require_shams = __commonJS({ + "scripts/node-portable/node_modules/has-symbols/shams.js"(exports2, module2) { + "use strict"; + module2.exports = function hasSymbols() { + if (typeof Symbol !== "function" || typeof Object.getOwnPropertySymbols !== "function") { + return false; + } + if (typeof Symbol.iterator === "symbol") { + return true; + } + var obj = {}; + var sym = Symbol("test"); + var symObj = Object(sym); + if (typeof sym === "string") { + return false; + } + if (Object.prototype.toString.call(sym) !== "[object Symbol]") { + return false; + } + if (Object.prototype.toString.call(symObj) !== "[object Symbol]") { + return false; + } + var symVal = 42; + obj[sym] = symVal; + for (var _ in obj) { + return false; + } + if (typeof Object.keys === "function" && Object.keys(obj).length !== 0) { + return false; + } + if (typeof Object.getOwnPropertyNames === "function" && Object.getOwnPropertyNames(obj).length !== 0) { + return false; + } + var syms = Object.getOwnPropertySymbols(obj); + if (syms.length !== 1 || syms[0] !== sym) { + return false; + } + if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { + return false; + } + if (typeof Object.getOwnPropertyDescriptor === "function") { + var descriptor = ( + /** @type {PropertyDescriptor} */ + Object.getOwnPropertyDescriptor(obj, sym) + ); + if (descriptor.value !== symVal || descriptor.enumerable !== true) { + return false; + } + } + return true; + }; + } +}); + +// scripts/node-portable/node_modules/has-tostringtag/shams.js +var require_shams2 = __commonJS({ + "scripts/node-portable/node_modules/has-tostringtag/shams.js"(exports2, module2) { + "use strict"; + var hasSymbols = require_shams(); + module2.exports = function hasToStringTagShams() { + return hasSymbols() && !!Symbol.toStringTag; + }; + } +}); + +// scripts/node-portable/node_modules/es-object-atoms/index.js +var require_es_object_atoms = __commonJS({ + "scripts/node-portable/node_modules/es-object-atoms/index.js"(exports2, module2) { + "use strict"; + module2.exports = Object; + } +}); + +// scripts/node-portable/node_modules/es-errors/index.js +var require_es_errors = __commonJS({ + "scripts/node-portable/node_modules/es-errors/index.js"(exports2, module2) { + "use strict"; + module2.exports = Error; + } +}); + +// scripts/node-portable/node_modules/es-errors/eval.js +var require_eval = __commonJS({ + "scripts/node-portable/node_modules/es-errors/eval.js"(exports2, module2) { + "use strict"; + module2.exports = EvalError; + } +}); + +// scripts/node-portable/node_modules/es-errors/range.js +var require_range = __commonJS({ + "scripts/node-portable/node_modules/es-errors/range.js"(exports2, module2) { + "use strict"; + module2.exports = RangeError; + } +}); + +// scripts/node-portable/node_modules/es-errors/ref.js +var require_ref = __commonJS({ + "scripts/node-portable/node_modules/es-errors/ref.js"(exports2, module2) { + "use strict"; + module2.exports = ReferenceError; + } +}); + +// scripts/node-portable/node_modules/es-errors/syntax.js +var require_syntax = __commonJS({ + "scripts/node-portable/node_modules/es-errors/syntax.js"(exports2, module2) { + "use strict"; + module2.exports = SyntaxError; + } +}); + +// scripts/node-portable/node_modules/es-errors/type.js +var require_type = __commonJS({ + "scripts/node-portable/node_modules/es-errors/type.js"(exports2, module2) { + "use strict"; + module2.exports = TypeError; + } +}); + +// scripts/node-portable/node_modules/es-errors/uri.js +var require_uri = __commonJS({ + "scripts/node-portable/node_modules/es-errors/uri.js"(exports2, module2) { + "use strict"; + module2.exports = URIError; + } +}); + +// scripts/node-portable/node_modules/math-intrinsics/abs.js +var require_abs = __commonJS({ + "scripts/node-portable/node_modules/math-intrinsics/abs.js"(exports2, module2) { + "use strict"; + module2.exports = Math.abs; + } +}); + +// scripts/node-portable/node_modules/math-intrinsics/floor.js +var require_floor = __commonJS({ + "scripts/node-portable/node_modules/math-intrinsics/floor.js"(exports2, module2) { + "use strict"; + module2.exports = Math.floor; + } +}); + +// scripts/node-portable/node_modules/math-intrinsics/max.js +var require_max = __commonJS({ + "scripts/node-portable/node_modules/math-intrinsics/max.js"(exports2, module2) { + "use strict"; + module2.exports = Math.max; + } +}); + +// scripts/node-portable/node_modules/math-intrinsics/min.js +var require_min = __commonJS({ + "scripts/node-portable/node_modules/math-intrinsics/min.js"(exports2, module2) { + "use strict"; + module2.exports = Math.min; + } +}); + +// scripts/node-portable/node_modules/math-intrinsics/pow.js +var require_pow = __commonJS({ + "scripts/node-portable/node_modules/math-intrinsics/pow.js"(exports2, module2) { + "use strict"; + module2.exports = Math.pow; + } +}); + +// scripts/node-portable/node_modules/math-intrinsics/round.js +var require_round = __commonJS({ + "scripts/node-portable/node_modules/math-intrinsics/round.js"(exports2, module2) { + "use strict"; + module2.exports = Math.round; + } +}); + +// scripts/node-portable/node_modules/math-intrinsics/isNaN.js +var require_isNaN = __commonJS({ + "scripts/node-portable/node_modules/math-intrinsics/isNaN.js"(exports2, module2) { + "use strict"; + module2.exports = Number.isNaN || function isNaN2(a) { + return a !== a; + }; + } +}); + +// scripts/node-portable/node_modules/math-intrinsics/sign.js +var require_sign = __commonJS({ + "scripts/node-portable/node_modules/math-intrinsics/sign.js"(exports2, module2) { + "use strict"; + var $isNaN = require_isNaN(); + module2.exports = function sign(number) { + if ($isNaN(number) || number === 0) { + return number; + } + return number < 0 ? -1 : 1; + }; + } +}); + +// scripts/node-portable/node_modules/gopd/gOPD.js +var require_gOPD = __commonJS({ + "scripts/node-portable/node_modules/gopd/gOPD.js"(exports2, module2) { + "use strict"; + module2.exports = Object.getOwnPropertyDescriptor; + } +}); + +// scripts/node-portable/node_modules/gopd/index.js +var require_gopd = __commonJS({ + "scripts/node-portable/node_modules/gopd/index.js"(exports2, module2) { + "use strict"; + var $gOPD = require_gOPD(); + if ($gOPD) { + try { + $gOPD([], "length"); + } catch (e) { + $gOPD = null; + } + } + module2.exports = $gOPD; + } +}); + +// scripts/node-portable/node_modules/es-define-property/index.js +var require_es_define_property = __commonJS({ + "scripts/node-portable/node_modules/es-define-property/index.js"(exports2, module2) { + "use strict"; + var $defineProperty = Object.defineProperty || false; + if ($defineProperty) { + try { + $defineProperty({}, "a", { value: 1 }); + } catch (e) { + $defineProperty = false; + } + } + module2.exports = $defineProperty; + } +}); + +// scripts/node-portable/node_modules/has-symbols/index.js +var require_has_symbols = __commonJS({ + "scripts/node-portable/node_modules/has-symbols/index.js"(exports2, module2) { + "use strict"; + var origSymbol = typeof Symbol !== "undefined" && Symbol; + var hasSymbolSham = require_shams(); + module2.exports = function hasNativeSymbols() { + if (typeof origSymbol !== "function") { + return false; + } + if (typeof Symbol !== "function") { + return false; + } + if (typeof origSymbol("foo") !== "symbol") { + return false; + } + if (typeof Symbol("bar") !== "symbol") { + return false; + } + return hasSymbolSham(); + }; + } +}); + +// scripts/node-portable/node_modules/get-proto/Reflect.getPrototypeOf.js +var require_Reflect_getPrototypeOf = __commonJS({ + "scripts/node-portable/node_modules/get-proto/Reflect.getPrototypeOf.js"(exports2, module2) { + "use strict"; + module2.exports = typeof Reflect !== "undefined" && Reflect.getPrototypeOf || null; + } +}); + +// scripts/node-portable/node_modules/get-proto/Object.getPrototypeOf.js +var require_Object_getPrototypeOf = __commonJS({ + "scripts/node-portable/node_modules/get-proto/Object.getPrototypeOf.js"(exports2, module2) { + "use strict"; + var $Object = require_es_object_atoms(); + module2.exports = $Object.getPrototypeOf || null; + } +}); + +// scripts/node-portable/node_modules/function-bind/implementation.js +var require_implementation = __commonJS({ + "scripts/node-portable/node_modules/function-bind/implementation.js"(exports2, module2) { + "use strict"; + var ERROR_MESSAGE = "Function.prototype.bind called on incompatible "; + var toStr = Object.prototype.toString; + var max = Math.max; + var funcType = "[object Function]"; + var concatty = function concatty2(a, b) { + var arr = []; + for (var i = 0; i < a.length; i += 1) { + arr[i] = a[i]; + } + for (var j = 0; j < b.length; j += 1) { + arr[j + a.length] = b[j]; + } + return arr; + }; + var slicy = function slicy2(arrLike, offset) { + var arr = []; + for (var i = offset || 0, j = 0; i < arrLike.length; i += 1, j += 1) { + arr[j] = arrLike[i]; + } + return arr; + }; + var joiny = function(arr, joiner) { + var str = ""; + for (var i = 0; i < arr.length; i += 1) { + str += arr[i]; + if (i + 1 < arr.length) { + str += joiner; + } + } + return str; + }; + module2.exports = function bind(that) { + var target = this; + if (typeof target !== "function" || toStr.apply(target) !== funcType) { + throw new TypeError(ERROR_MESSAGE + target); + } + var args = slicy(arguments, 1); + var bound; + var binder = function() { + if (this instanceof bound) { + var result = target.apply( + this, + concatty(args, arguments) + ); + if (Object(result) === result) { + return result; + } + return this; + } + return target.apply( + that, + concatty(args, arguments) + ); + }; + var boundLength = max(0, target.length - args.length); + var boundArgs = []; + for (var i = 0; i < boundLength; i++) { + boundArgs[i] = "$" + i; + } + bound = Function("binder", "return function (" + joiny(boundArgs, ",") + "){ return binder.apply(this,arguments); }")(binder); + if (target.prototype) { + var Empty = function Empty2() { + }; + Empty.prototype = target.prototype; + bound.prototype = new Empty(); + Empty.prototype = null; + } + return bound; + }; + } +}); + +// scripts/node-portable/node_modules/function-bind/index.js +var require_function_bind = __commonJS({ + "scripts/node-portable/node_modules/function-bind/index.js"(exports2, module2) { + "use strict"; + var implementation = require_implementation(); + module2.exports = Function.prototype.bind || implementation; + } +}); + +// scripts/node-portable/node_modules/call-bind-apply-helpers/functionCall.js +var require_functionCall = __commonJS({ + "scripts/node-portable/node_modules/call-bind-apply-helpers/functionCall.js"(exports2, module2) { + "use strict"; + module2.exports = Function.prototype.call; + } +}); + +// scripts/node-portable/node_modules/call-bind-apply-helpers/functionApply.js +var require_functionApply = __commonJS({ + "scripts/node-portable/node_modules/call-bind-apply-helpers/functionApply.js"(exports2, module2) { + "use strict"; + module2.exports = Function.prototype.apply; + } +}); + +// scripts/node-portable/node_modules/call-bind-apply-helpers/reflectApply.js +var require_reflectApply = __commonJS({ + "scripts/node-portable/node_modules/call-bind-apply-helpers/reflectApply.js"(exports2, module2) { + "use strict"; + module2.exports = typeof Reflect !== "undefined" && Reflect && Reflect.apply; + } +}); + +// scripts/node-portable/node_modules/call-bind-apply-helpers/actualApply.js +var require_actualApply = __commonJS({ + "scripts/node-portable/node_modules/call-bind-apply-helpers/actualApply.js"(exports2, module2) { + "use strict"; + var bind = require_function_bind(); + var $apply = require_functionApply(); + var $call = require_functionCall(); + var $reflectApply = require_reflectApply(); + module2.exports = $reflectApply || bind.call($call, $apply); + } +}); + +// scripts/node-portable/node_modules/call-bind-apply-helpers/index.js +var require_call_bind_apply_helpers = __commonJS({ + "scripts/node-portable/node_modules/call-bind-apply-helpers/index.js"(exports2, module2) { + "use strict"; + var bind = require_function_bind(); + var $TypeError = require_type(); + var $call = require_functionCall(); + var $actualApply = require_actualApply(); + module2.exports = function callBindBasic(args) { + if (args.length < 1 || typeof args[0] !== "function") { + throw new $TypeError("a function is required"); + } + return $actualApply(bind, $call, args); + }; + } +}); + +// scripts/node-portable/node_modules/dunder-proto/get.js +var require_get = __commonJS({ + "scripts/node-portable/node_modules/dunder-proto/get.js"(exports2, module2) { + "use strict"; + var callBind = require_call_bind_apply_helpers(); + var gOPD = require_gopd(); + var hasProtoAccessor; + try { + hasProtoAccessor = /** @type {{ __proto__?: typeof Array.prototype }} */ + [].__proto__ === Array.prototype; + } catch (e) { + if (!e || typeof e !== "object" || !("code" in e) || e.code !== "ERR_PROTO_ACCESS") { + throw e; + } + } + var desc = !!hasProtoAccessor && gOPD && gOPD( + Object.prototype, + /** @type {keyof typeof Object.prototype} */ + "__proto__" + ); + var $Object = Object; + var $getPrototypeOf = $Object.getPrototypeOf; + module2.exports = desc && typeof desc.get === "function" ? callBind([desc.get]) : typeof $getPrototypeOf === "function" ? ( + /** @type {import('./get')} */ + function getDunder(value) { + return $getPrototypeOf(value == null ? value : $Object(value)); + } + ) : false; + } +}); + +// scripts/node-portable/node_modules/get-proto/index.js +var require_get_proto = __commonJS({ + "scripts/node-portable/node_modules/get-proto/index.js"(exports2, module2) { + "use strict"; + var reflectGetProto = require_Reflect_getPrototypeOf(); + var originalGetProto = require_Object_getPrototypeOf(); + var getDunderProto = require_get(); + module2.exports = reflectGetProto ? function getProto(O) { + return reflectGetProto(O); + } : originalGetProto ? function getProto(O) { + if (!O || typeof O !== "object" && typeof O !== "function") { + throw new TypeError("getProto: not an object"); + } + return originalGetProto(O); + } : getDunderProto ? function getProto(O) { + return getDunderProto(O); + } : null; + } +}); + +// scripts/node-portable/node_modules/hasown/index.js +var require_hasown = __commonJS({ + "scripts/node-portable/node_modules/hasown/index.js"(exports2, module2) { + "use strict"; + var call = Function.prototype.call; + var $hasOwn = Object.prototype.hasOwnProperty; + var bind = require_function_bind(); + module2.exports = bind.call(call, $hasOwn); + } +}); + +// scripts/node-portable/node_modules/get-intrinsic/index.js +var require_get_intrinsic = __commonJS({ + "scripts/node-portable/node_modules/get-intrinsic/index.js"(exports2, module2) { + "use strict"; + var undefined2; + var $Object = require_es_object_atoms(); + var $Error = require_es_errors(); + var $EvalError = require_eval(); + var $RangeError = require_range(); + var $ReferenceError = require_ref(); + var $SyntaxError = require_syntax(); + var $TypeError = require_type(); + var $URIError = require_uri(); + var abs = require_abs(); + var floor = require_floor(); + var max = require_max(); + var min = require_min(); + var pow = require_pow(); + var round = require_round(); + var sign = require_sign(); + var $Function = Function; + var getEvalledConstructor = function(expressionSyntax) { + try { + return $Function('"use strict"; return (' + expressionSyntax + ").constructor;")(); + } catch (e) { + } + }; + var $gOPD = require_gopd(); + var $defineProperty = require_es_define_property(); + var throwTypeError = function() { + throw new $TypeError(); + }; + var ThrowTypeError = $gOPD ? (function() { + try { + arguments.callee; + return throwTypeError; + } catch (calleeThrows) { + try { + return $gOPD(arguments, "callee").get; + } catch (gOPDthrows) { + return throwTypeError; + } + } + })() : throwTypeError; + var hasSymbols = require_has_symbols()(); + var getProto = require_get_proto(); + var $ObjectGPO = require_Object_getPrototypeOf(); + var $ReflectGPO = require_Reflect_getPrototypeOf(); + var $apply = require_functionApply(); + var $call = require_functionCall(); + var needsEval = {}; + var TypedArray = typeof Uint8Array === "undefined" || !getProto ? undefined2 : getProto(Uint8Array); + var INTRINSICS = { + __proto__: null, + "%AggregateError%": typeof AggregateError === "undefined" ? undefined2 : AggregateError, + "%Array%": Array, + "%ArrayBuffer%": typeof ArrayBuffer === "undefined" ? undefined2 : ArrayBuffer, + "%ArrayIteratorPrototype%": hasSymbols && getProto ? getProto([][Symbol.iterator]()) : undefined2, + "%AsyncFromSyncIteratorPrototype%": undefined2, + "%AsyncFunction%": needsEval, + "%AsyncGenerator%": needsEval, + "%AsyncGeneratorFunction%": needsEval, + "%AsyncIteratorPrototype%": needsEval, + "%Atomics%": typeof Atomics === "undefined" ? undefined2 : Atomics, + "%BigInt%": typeof BigInt === "undefined" ? undefined2 : BigInt, + "%BigInt64Array%": typeof BigInt64Array === "undefined" ? undefined2 : BigInt64Array, + "%BigUint64Array%": typeof BigUint64Array === "undefined" ? undefined2 : BigUint64Array, + "%Boolean%": Boolean, + "%DataView%": typeof DataView === "undefined" ? undefined2 : DataView, + "%Date%": Date, + "%decodeURI%": decodeURI, + "%decodeURIComponent%": decodeURIComponent, + "%encodeURI%": encodeURI, + "%encodeURIComponent%": encodeURIComponent, + "%Error%": $Error, + "%eval%": eval, + // eslint-disable-line no-eval + "%EvalError%": $EvalError, + "%Float16Array%": typeof Float16Array === "undefined" ? undefined2 : Float16Array, + "%Float32Array%": typeof Float32Array === "undefined" ? undefined2 : Float32Array, + "%Float64Array%": typeof Float64Array === "undefined" ? undefined2 : Float64Array, + "%FinalizationRegistry%": typeof FinalizationRegistry === "undefined" ? undefined2 : FinalizationRegistry, + "%Function%": $Function, + "%GeneratorFunction%": needsEval, + "%Int8Array%": typeof Int8Array === "undefined" ? undefined2 : Int8Array, + "%Int16Array%": typeof Int16Array === "undefined" ? undefined2 : Int16Array, + "%Int32Array%": typeof Int32Array === "undefined" ? undefined2 : Int32Array, + "%isFinite%": isFinite, + "%isNaN%": isNaN, + "%IteratorPrototype%": hasSymbols && getProto ? getProto(getProto([][Symbol.iterator]())) : undefined2, + "%JSON%": typeof JSON === "object" ? JSON : undefined2, + "%Map%": typeof Map === "undefined" ? undefined2 : Map, + "%MapIteratorPrototype%": typeof Map === "undefined" || !hasSymbols || !getProto ? undefined2 : getProto((/* @__PURE__ */ new Map())[Symbol.iterator]()), + "%Math%": Math, + "%Number%": Number, + "%Object%": $Object, + "%Object.getOwnPropertyDescriptor%": $gOPD, + "%parseFloat%": parseFloat, + "%parseInt%": parseInt, + "%Promise%": typeof Promise === "undefined" ? undefined2 : Promise, + "%Proxy%": typeof Proxy === "undefined" ? undefined2 : Proxy, + "%RangeError%": $RangeError, + "%ReferenceError%": $ReferenceError, + "%Reflect%": typeof Reflect === "undefined" ? undefined2 : Reflect, + "%RegExp%": RegExp, + "%Set%": typeof Set === "undefined" ? undefined2 : Set, + "%SetIteratorPrototype%": typeof Set === "undefined" || !hasSymbols || !getProto ? undefined2 : getProto((/* @__PURE__ */ new Set())[Symbol.iterator]()), + "%SharedArrayBuffer%": typeof SharedArrayBuffer === "undefined" ? undefined2 : SharedArrayBuffer, + "%String%": String, + "%StringIteratorPrototype%": hasSymbols && getProto ? getProto(""[Symbol.iterator]()) : undefined2, + "%Symbol%": hasSymbols ? Symbol : undefined2, + "%SyntaxError%": $SyntaxError, + "%ThrowTypeError%": ThrowTypeError, + "%TypedArray%": TypedArray, + "%TypeError%": $TypeError, + "%Uint8Array%": typeof Uint8Array === "undefined" ? undefined2 : Uint8Array, + "%Uint8ClampedArray%": typeof Uint8ClampedArray === "undefined" ? undefined2 : Uint8ClampedArray, + "%Uint16Array%": typeof Uint16Array === "undefined" ? undefined2 : Uint16Array, + "%Uint32Array%": typeof Uint32Array === "undefined" ? undefined2 : Uint32Array, + "%URIError%": $URIError, + "%WeakMap%": typeof WeakMap === "undefined" ? undefined2 : WeakMap, + "%WeakRef%": typeof WeakRef === "undefined" ? undefined2 : WeakRef, + "%WeakSet%": typeof WeakSet === "undefined" ? undefined2 : WeakSet, + "%Function.prototype.call%": $call, + "%Function.prototype.apply%": $apply, + "%Object.defineProperty%": $defineProperty, + "%Object.getPrototypeOf%": $ObjectGPO, + "%Math.abs%": abs, + "%Math.floor%": floor, + "%Math.max%": max, + "%Math.min%": min, + "%Math.pow%": pow, + "%Math.round%": round, + "%Math.sign%": sign, + "%Reflect.getPrototypeOf%": $ReflectGPO + }; + if (getProto) { + try { + null.error; + } catch (e) { + errorProto = getProto(getProto(e)); + INTRINSICS["%Error.prototype%"] = errorProto; + } + } + var errorProto; + var doEval = function doEval2(name) { + var value; + if (name === "%AsyncFunction%") { + value = getEvalledConstructor("async function () {}"); + } else if (name === "%GeneratorFunction%") { + value = getEvalledConstructor("function* () {}"); + } else if (name === "%AsyncGeneratorFunction%") { + value = getEvalledConstructor("async function* () {}"); + } else if (name === "%AsyncGenerator%") { + var fn = doEval2("%AsyncGeneratorFunction%"); + if (fn) { + value = fn.prototype; + } + } else if (name === "%AsyncIteratorPrototype%") { + var gen = doEval2("%AsyncGenerator%"); + if (gen && getProto) { + value = getProto(gen.prototype); + } + } + INTRINSICS[name] = value; + return value; + }; + var LEGACY_ALIASES = { + __proto__: null, + "%ArrayBufferPrototype%": ["ArrayBuffer", "prototype"], + "%ArrayPrototype%": ["Array", "prototype"], + "%ArrayProto_entries%": ["Array", "prototype", "entries"], + "%ArrayProto_forEach%": ["Array", "prototype", "forEach"], + "%ArrayProto_keys%": ["Array", "prototype", "keys"], + "%ArrayProto_values%": ["Array", "prototype", "values"], + "%AsyncFunctionPrototype%": ["AsyncFunction", "prototype"], + "%AsyncGenerator%": ["AsyncGeneratorFunction", "prototype"], + "%AsyncGeneratorPrototype%": ["AsyncGeneratorFunction", "prototype", "prototype"], + "%BooleanPrototype%": ["Boolean", "prototype"], + "%DataViewPrototype%": ["DataView", "prototype"], + "%DatePrototype%": ["Date", "prototype"], + "%ErrorPrototype%": ["Error", "prototype"], + "%EvalErrorPrototype%": ["EvalError", "prototype"], + "%Float32ArrayPrototype%": ["Float32Array", "prototype"], + "%Float64ArrayPrototype%": ["Float64Array", "prototype"], + "%FunctionPrototype%": ["Function", "prototype"], + "%Generator%": ["GeneratorFunction", "prototype"], + "%GeneratorPrototype%": ["GeneratorFunction", "prototype", "prototype"], + "%Int8ArrayPrototype%": ["Int8Array", "prototype"], + "%Int16ArrayPrototype%": ["Int16Array", "prototype"], + "%Int32ArrayPrototype%": ["Int32Array", "prototype"], + "%JSONParse%": ["JSON", "parse"], + "%JSONStringify%": ["JSON", "stringify"], + "%MapPrototype%": ["Map", "prototype"], + "%NumberPrototype%": ["Number", "prototype"], + "%ObjectPrototype%": ["Object", "prototype"], + "%ObjProto_toString%": ["Object", "prototype", "toString"], + "%ObjProto_valueOf%": ["Object", "prototype", "valueOf"], + "%PromisePrototype%": ["Promise", "prototype"], + "%PromiseProto_then%": ["Promise", "prototype", "then"], + "%Promise_all%": ["Promise", "all"], + "%Promise_reject%": ["Promise", "reject"], + "%Promise_resolve%": ["Promise", "resolve"], + "%RangeErrorPrototype%": ["RangeError", "prototype"], + "%ReferenceErrorPrototype%": ["ReferenceError", "prototype"], + "%RegExpPrototype%": ["RegExp", "prototype"], + "%SetPrototype%": ["Set", "prototype"], + "%SharedArrayBufferPrototype%": ["SharedArrayBuffer", "prototype"], + "%StringPrototype%": ["String", "prototype"], + "%SymbolPrototype%": ["Symbol", "prototype"], + "%SyntaxErrorPrototype%": ["SyntaxError", "prototype"], + "%TypedArrayPrototype%": ["TypedArray", "prototype"], + "%TypeErrorPrototype%": ["TypeError", "prototype"], + "%Uint8ArrayPrototype%": ["Uint8Array", "prototype"], + "%Uint8ClampedArrayPrototype%": ["Uint8ClampedArray", "prototype"], + "%Uint16ArrayPrototype%": ["Uint16Array", "prototype"], + "%Uint32ArrayPrototype%": ["Uint32Array", "prototype"], + "%URIErrorPrototype%": ["URIError", "prototype"], + "%WeakMapPrototype%": ["WeakMap", "prototype"], + "%WeakSetPrototype%": ["WeakSet", "prototype"] + }; + var bind = require_function_bind(); + var hasOwn = require_hasown(); + var $concat = bind.call($call, Array.prototype.concat); + var $spliceApply = bind.call($apply, Array.prototype.splice); + var $replace = bind.call($call, String.prototype.replace); + var $strSlice = bind.call($call, String.prototype.slice); + var $exec = bind.call($call, RegExp.prototype.exec); + var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g; + var reEscapeChar = /\\(\\)?/g; + var stringToPath = function stringToPath2(string) { + var first = $strSlice(string, 0, 1); + var last = $strSlice(string, -1); + if (first === "%" && last !== "%") { + throw new $SyntaxError("invalid intrinsic syntax, expected closing `%`"); + } else if (last === "%" && first !== "%") { + throw new $SyntaxError("invalid intrinsic syntax, expected opening `%`"); + } + var result = []; + $replace(string, rePropName, function(match, number, quote, subString) { + result[result.length] = quote ? $replace(subString, reEscapeChar, "$1") : number || match; + }); + return result; + }; + var getBaseIntrinsic = function getBaseIntrinsic2(name, allowMissing) { + var intrinsicName = name; + var alias; + if (hasOwn(LEGACY_ALIASES, intrinsicName)) { + alias = LEGACY_ALIASES[intrinsicName]; + intrinsicName = "%" + alias[0] + "%"; + } + if (hasOwn(INTRINSICS, intrinsicName)) { + var value = INTRINSICS[intrinsicName]; + if (value === needsEval) { + value = doEval(intrinsicName); + } + if (typeof value === "undefined" && !allowMissing) { + throw new $TypeError("intrinsic " + name + " exists, but is not available. Please file an issue!"); + } + return { + alias, + name: intrinsicName, + value + }; + } + throw new $SyntaxError("intrinsic " + name + " does not exist!"); + }; + module2.exports = function GetIntrinsic(name, allowMissing) { + if (typeof name !== "string" || name.length === 0) { + throw new $TypeError("intrinsic name must be a non-empty string"); + } + if (arguments.length > 1 && typeof allowMissing !== "boolean") { + throw new $TypeError('"allowMissing" argument must be a boolean'); + } + if ($exec(/^%?[^%]*%?$/, name) === null) { + throw new $SyntaxError("`%` may not be present anywhere but at the beginning and end of the intrinsic name"); + } + var parts = stringToPath(name); + var intrinsicBaseName = parts.length > 0 ? parts[0] : ""; + var intrinsic = getBaseIntrinsic("%" + intrinsicBaseName + "%", allowMissing); + var intrinsicRealName = intrinsic.name; + var value = intrinsic.value; + var skipFurtherCaching = false; + var alias = intrinsic.alias; + if (alias) { + intrinsicBaseName = alias[0]; + $spliceApply(parts, $concat([0, 1], alias)); + } + for (var i = 1, isOwn = true; i < parts.length; i += 1) { + var part = parts[i]; + var first = $strSlice(part, 0, 1); + var last = $strSlice(part, -1); + if ((first === '"' || first === "'" || first === "`" || (last === '"' || last === "'" || last === "`")) && first !== last) { + throw new $SyntaxError("property names with quotes must have matching quotes"); + } + if (part === "constructor" || !isOwn) { + skipFurtherCaching = true; + } + intrinsicBaseName += "." + part; + intrinsicRealName = "%" + intrinsicBaseName + "%"; + if (hasOwn(INTRINSICS, intrinsicRealName)) { + value = INTRINSICS[intrinsicRealName]; + } else if (value != null) { + if (!(part in value)) { + if (!allowMissing) { + throw new $TypeError("base intrinsic for " + name + " exists, but the property is not available."); + } + return void undefined2; + } + if ($gOPD && i + 1 >= parts.length) { + var desc = $gOPD(value, part); + isOwn = !!desc; + if (isOwn && "get" in desc && !("originalValue" in desc.get)) { + value = desc.get; + } else { + value = value[part]; + } + } else { + isOwn = hasOwn(value, part); + value = value[part]; + } + if (isOwn && !skipFurtherCaching) { + INTRINSICS[intrinsicRealName] = value; + } + } + } + return value; + }; + } +}); + +// scripts/node-portable/node_modules/call-bound/index.js +var require_call_bound = __commonJS({ + "scripts/node-portable/node_modules/call-bound/index.js"(exports2, module2) { + "use strict"; + var GetIntrinsic = require_get_intrinsic(); + var callBindBasic = require_call_bind_apply_helpers(); + var $indexOf = callBindBasic([GetIntrinsic("%String.prototype.indexOf%")]); + module2.exports = function callBoundIntrinsic(name, allowMissing) { + var intrinsic = ( + /** @type {(this: unknown, ...args: unknown[]) => unknown} */ + GetIntrinsic(name, !!allowMissing) + ); + if (typeof intrinsic === "function" && $indexOf(name, ".prototype.") > -1) { + return callBindBasic( + /** @type {const} */ + [intrinsic] + ); + } + return intrinsic; + }; + } +}); + +// scripts/node-portable/node_modules/is-arguments/index.js +var require_is_arguments = __commonJS({ + "scripts/node-portable/node_modules/is-arguments/index.js"(exports2, module2) { + "use strict"; + var hasToStringTag = require_shams2()(); + var callBound = require_call_bound(); + var $toString = callBound("Object.prototype.toString"); + var isStandardArguments = function isArguments(value) { + if (hasToStringTag && value && typeof value === "object" && Symbol.toStringTag in value) { + return false; + } + return $toString(value) === "[object Arguments]"; + }; + var isLegacyArguments = function isArguments(value) { + if (isStandardArguments(value)) { + return true; + } + return value !== null && typeof value === "object" && "length" in value && typeof value.length === "number" && value.length >= 0 && $toString(value) !== "[object Array]" && "callee" in value && $toString(value.callee) === "[object Function]"; + }; + var supportsStandardArguments = (function() { + return isStandardArguments(arguments); + })(); + isStandardArguments.isLegacyArguments = isLegacyArguments; + module2.exports = supportsStandardArguments ? isStandardArguments : isLegacyArguments; + } +}); + +// scripts/node-portable/node_modules/is-regex/index.js +var require_is_regex = __commonJS({ + "scripts/node-portable/node_modules/is-regex/index.js"(exports2, module2) { + "use strict"; + var callBound = require_call_bound(); + var hasToStringTag = require_shams2()(); + var hasOwn = require_hasown(); + var gOPD = require_gopd(); + var fn; + if (hasToStringTag) { + $exec = callBound("RegExp.prototype.exec"); + isRegexMarker = {}; + throwRegexMarker = function() { + throw isRegexMarker; + }; + badStringifier = { + toString: throwRegexMarker, + valueOf: throwRegexMarker + }; + if (typeof Symbol.toPrimitive === "symbol") { + badStringifier[Symbol.toPrimitive] = throwRegexMarker; + } + fn = function isRegex(value) { + if (!value || typeof value !== "object") { + return false; + } + var descriptor = ( + /** @type {NonNullable} */ + gOPD( + /** @type {{ lastIndex?: unknown }} */ + value, + "lastIndex" + ) + ); + var hasLastIndexDataProperty = descriptor && hasOwn(descriptor, "value"); + if (!hasLastIndexDataProperty) { + return false; + } + try { + $exec( + value, + /** @type {string} */ + /** @type {unknown} */ + badStringifier + ); + } catch (e) { + return e === isRegexMarker; + } + }; + } else { + $toString = callBound("Object.prototype.toString"); + regexClass = "[object RegExp]"; + fn = function isRegex(value) { + if (!value || typeof value !== "object" && typeof value !== "function") { + return false; + } + return $toString(value) === regexClass; + }; + } + var $exec; + var isRegexMarker; + var throwRegexMarker; + var badStringifier; + var $toString; + var regexClass; + module2.exports = fn; + } +}); + +// scripts/node-portable/node_modules/safe-regex-test/index.js +var require_safe_regex_test = __commonJS({ + "scripts/node-portable/node_modules/safe-regex-test/index.js"(exports2, module2) { + "use strict"; + var callBound = require_call_bound(); + var isRegex = require_is_regex(); + var $exec = callBound("RegExp.prototype.exec"); + var $TypeError = require_type(); + module2.exports = function regexTester(regex) { + if (!isRegex(regex)) { + throw new $TypeError("`regex` must be a RegExp"); + } + return function test(s) { + return $exec(regex, s) !== null; + }; + }; + } +}); + +// scripts/node-portable/node_modules/generator-function/index.js +var require_generator_function = __commonJS({ + "scripts/node-portable/node_modules/generator-function/index.js"(exports2, module2) { + "use strict"; + var cached = ( + /** @type {GeneratorFunctionConstructor} */ + function* () { + }.constructor + ); + module2.exports = () => cached; + } +}); + +// scripts/node-portable/node_modules/is-generator-function/index.js +var require_is_generator_function = __commonJS({ + "scripts/node-portable/node_modules/is-generator-function/index.js"(exports2, module2) { + "use strict"; + var callBound = require_call_bound(); + var safeRegexTest = require_safe_regex_test(); + var isFnRegex = safeRegexTest(/^\s*(?:function)?\*/); + var hasToStringTag = require_shams2()(); + var getProto = require_get_proto(); + var toStr = callBound("Object.prototype.toString"); + var fnToStr = callBound("Function.prototype.toString"); + var getGeneratorFunction = require_generator_function(); + module2.exports = function isGeneratorFunction(fn) { + if (typeof fn !== "function") { + return false; + } + if (isFnRegex(fnToStr(fn))) { + return true; + } + if (!hasToStringTag) { + var str = toStr(fn); + return str === "[object GeneratorFunction]"; + } + if (!getProto) { + return false; + } + var GeneratorFunction = getGeneratorFunction(); + return GeneratorFunction && getProto(fn) === GeneratorFunction.prototype; + }; + } +}); + +// scripts/node-portable/node_modules/is-callable/index.js +var require_is_callable = __commonJS({ + "scripts/node-portable/node_modules/is-callable/index.js"(exports2, module2) { + "use strict"; + var fnToStr = Function.prototype.toString; + var reflectApply = typeof Reflect === "object" && Reflect !== null && Reflect.apply; + var badArrayLike; + var isCallableMarker; + if (typeof reflectApply === "function" && typeof Object.defineProperty === "function") { + try { + badArrayLike = Object.defineProperty({}, "length", { + get: function() { + throw isCallableMarker; + } + }); + isCallableMarker = {}; + reflectApply(function() { + throw 42; + }, null, badArrayLike); + } catch (_) { + if (_ !== isCallableMarker) { + reflectApply = null; + } + } + } else { + reflectApply = null; + } + var constructorRegex = /^\s*class\b/; + var isES6ClassFn = function isES6ClassFunction(value) { + try { + var fnStr = fnToStr.call(value); + return constructorRegex.test(fnStr); + } catch (e) { + return false; + } + }; + var tryFunctionObject = function tryFunctionToStr(value) { + try { + if (isES6ClassFn(value)) { + return false; + } + fnToStr.call(value); + return true; + } catch (e) { + return false; + } + }; + var toStr = Object.prototype.toString; + var objectClass = "[object Object]"; + var fnClass = "[object Function]"; + var genClass = "[object GeneratorFunction]"; + var ddaClass = "[object HTMLAllCollection]"; + var ddaClass2 = "[object HTML document.all class]"; + var ddaClass3 = "[object HTMLCollection]"; + var hasToStringTag = typeof Symbol === "function" && !!Symbol.toStringTag; + var isIE68 = !(0 in [,]); + var isDDA = function isDocumentDotAll() { + return false; + }; + if (typeof document === "object") { + all = document.all; + if (toStr.call(all) === toStr.call(document.all)) { + isDDA = function isDocumentDotAll(value) { + if ((isIE68 || !value) && (typeof value === "undefined" || typeof value === "object")) { + try { + var str = toStr.call(value); + return (str === ddaClass || str === ddaClass2 || str === ddaClass3 || str === objectClass) && value("") == null; + } catch (e) { + } + } + return false; + }; + } + } + var all; + module2.exports = reflectApply ? function isCallable(value) { + if (isDDA(value)) { + return true; + } + if (!value) { + return false; + } + if (typeof value !== "function" && typeof value !== "object") { + return false; + } + try { + reflectApply(value, null, badArrayLike); + } catch (e) { + if (e !== isCallableMarker) { + return false; + } + } + return !isES6ClassFn(value) && tryFunctionObject(value); + } : function isCallable(value) { + if (isDDA(value)) { + return true; + } + if (!value) { + return false; + } + if (typeof value !== "function" && typeof value !== "object") { + return false; + } + if (hasToStringTag) { + return tryFunctionObject(value); + } + if (isES6ClassFn(value)) { + return false; + } + var strClass = toStr.call(value); + if (strClass !== fnClass && strClass !== genClass && !/^\[object HTML/.test(strClass)) { + return false; + } + return tryFunctionObject(value); + }; + } +}); + +// scripts/node-portable/node_modules/for-each/index.js +var require_for_each = __commonJS({ + "scripts/node-portable/node_modules/for-each/index.js"(exports2, module2) { + "use strict"; + var isCallable = require_is_callable(); + var toStr = Object.prototype.toString; + var hasOwnProperty = Object.prototype.hasOwnProperty; + var forEachArray = function forEachArray2(array, iterator, receiver) { + for (var i = 0, len = array.length; i < len; i++) { + if (hasOwnProperty.call(array, i)) { + if (receiver == null) { + iterator(array[i], i, array); + } else { + iterator.call(receiver, array[i], i, array); + } + } + } + }; + var forEachString = function forEachString2(string, iterator, receiver) { + for (var i = 0, len = string.length; i < len; i++) { + if (receiver == null) { + iterator(string.charAt(i), i, string); + } else { + iterator.call(receiver, string.charAt(i), i, string); + } + } + }; + var forEachObject = function forEachObject2(object, iterator, receiver) { + for (var k in object) { + if (hasOwnProperty.call(object, k)) { + if (receiver == null) { + iterator(object[k], k, object); + } else { + iterator.call(receiver, object[k], k, object); + } + } + } + }; + function isArray(x) { + return toStr.call(x) === "[object Array]"; + } + module2.exports = function forEach(list, iterator, thisArg) { + if (!isCallable(iterator)) { + throw new TypeError("iterator must be a function"); + } + var receiver; + if (arguments.length >= 3) { + receiver = thisArg; + } + if (isArray(list)) { + forEachArray(list, iterator, receiver); + } else if (typeof list === "string") { + forEachString(list, iterator, receiver); + } else { + forEachObject(list, iterator, receiver); + } + }; + } +}); + +// scripts/node-portable/node_modules/possible-typed-array-names/index.js +var require_possible_typed_array_names = __commonJS({ + "scripts/node-portable/node_modules/possible-typed-array-names/index.js"(exports2, module2) { + "use strict"; + module2.exports = [ + "Float16Array", + "Float32Array", + "Float64Array", + "Int8Array", + "Int16Array", + "Int32Array", + "Uint8Array", + "Uint8ClampedArray", + "Uint16Array", + "Uint32Array", + "BigInt64Array", + "BigUint64Array" + ]; + } +}); + +// scripts/node-portable/node_modules/available-typed-arrays/index.js +var require_available_typed_arrays = __commonJS({ + "scripts/node-portable/node_modules/available-typed-arrays/index.js"(exports2, module2) { + "use strict"; + var possibleNames = require_possible_typed_array_names(); + var g = typeof globalThis === "undefined" ? global : globalThis; + module2.exports = function availableTypedArrays() { + var out = []; + for (var i = 0; i < possibleNames.length; i++) { + if (typeof g[possibleNames[i]] === "function") { + out[out.length] = possibleNames[i]; + } + } + return out; + }; + } +}); + +// scripts/node-portable/node_modules/define-data-property/index.js +var require_define_data_property = __commonJS({ + "scripts/node-portable/node_modules/define-data-property/index.js"(exports2, module2) { + "use strict"; + var $defineProperty = require_es_define_property(); + var $SyntaxError = require_syntax(); + var $TypeError = require_type(); + var gopd = require_gopd(); + module2.exports = function defineDataProperty(obj, property, value) { + if (!obj || typeof obj !== "object" && typeof obj !== "function") { + throw new $TypeError("`obj` must be an object or a function`"); + } + if (typeof property !== "string" && typeof property !== "symbol") { + throw new $TypeError("`property` must be a string or a symbol`"); + } + if (arguments.length > 3 && typeof arguments[3] !== "boolean" && arguments[3] !== null) { + throw new $TypeError("`nonEnumerable`, if provided, must be a boolean or null"); + } + if (arguments.length > 4 && typeof arguments[4] !== "boolean" && arguments[4] !== null) { + throw new $TypeError("`nonWritable`, if provided, must be a boolean or null"); + } + if (arguments.length > 5 && typeof arguments[5] !== "boolean" && arguments[5] !== null) { + throw new $TypeError("`nonConfigurable`, if provided, must be a boolean or null"); + } + if (arguments.length > 6 && typeof arguments[6] !== "boolean") { + throw new $TypeError("`loose`, if provided, must be a boolean"); + } + var nonEnumerable = arguments.length > 3 ? arguments[3] : null; + var nonWritable = arguments.length > 4 ? arguments[4] : null; + var nonConfigurable = arguments.length > 5 ? arguments[5] : null; + var loose = arguments.length > 6 ? arguments[6] : false; + var desc = !!gopd && gopd(obj, property); + if ($defineProperty) { + $defineProperty(obj, property, { + configurable: nonConfigurable === null && desc ? desc.configurable : !nonConfigurable, + enumerable: nonEnumerable === null && desc ? desc.enumerable : !nonEnumerable, + value, + writable: nonWritable === null && desc ? desc.writable : !nonWritable + }); + } else if (loose || !nonEnumerable && !nonWritable && !nonConfigurable) { + obj[property] = value; + } else { + throw new $SyntaxError("This environment does not support defining a property as non-configurable, non-writable, or non-enumerable."); + } + }; + } +}); + +// scripts/node-portable/node_modules/has-property-descriptors/index.js +var require_has_property_descriptors = __commonJS({ + "scripts/node-portable/node_modules/has-property-descriptors/index.js"(exports2, module2) { + "use strict"; + var $defineProperty = require_es_define_property(); + var hasPropertyDescriptors = function hasPropertyDescriptors2() { + return !!$defineProperty; + }; + hasPropertyDescriptors.hasArrayLengthDefineBug = function hasArrayLengthDefineBug() { + if (!$defineProperty) { + return null; + } + try { + return $defineProperty([], "length", { value: 1 }).length !== 1; + } catch (e) { + return true; + } + }; + module2.exports = hasPropertyDescriptors; + } +}); + +// scripts/node-portable/node_modules/set-function-length/index.js +var require_set_function_length = __commonJS({ + "scripts/node-portable/node_modules/set-function-length/index.js"(exports2, module2) { + "use strict"; + var GetIntrinsic = require_get_intrinsic(); + var define = require_define_data_property(); + var hasDescriptors = require_has_property_descriptors()(); + var gOPD = require_gopd(); + var $TypeError = require_type(); + var $floor = GetIntrinsic("%Math.floor%"); + module2.exports = function setFunctionLength(fn, length) { + if (typeof fn !== "function") { + throw new $TypeError("`fn` is not a function"); + } + if (typeof length !== "number" || length < 0 || length > 4294967295 || $floor(length) !== length) { + throw new $TypeError("`length` must be a positive 32-bit integer"); + } + var loose = arguments.length > 2 && !!arguments[2]; + var functionLengthIsConfigurable = true; + var functionLengthIsWritable = true; + if ("length" in fn && gOPD) { + var desc = gOPD(fn, "length"); + if (desc && !desc.configurable) { + functionLengthIsConfigurable = false; + } + if (desc && !desc.writable) { + functionLengthIsWritable = false; + } + } + if (functionLengthIsConfigurable || functionLengthIsWritable || !loose) { + if (hasDescriptors) { + define( + /** @type {Parameters[0]} */ + fn, + "length", + length, + true, + true + ); + } else { + define( + /** @type {Parameters[0]} */ + fn, + "length", + length + ); + } + } + return fn; + }; + } +}); + +// scripts/node-portable/node_modules/call-bind-apply-helpers/applyBind.js +var require_applyBind = __commonJS({ + "scripts/node-portable/node_modules/call-bind-apply-helpers/applyBind.js"(exports2, module2) { + "use strict"; + var bind = require_function_bind(); + var $apply = require_functionApply(); + var actualApply = require_actualApply(); + module2.exports = function applyBind() { + return actualApply(bind, $apply, arguments); + }; + } +}); + +// scripts/node-portable/node_modules/call-bind/index.js +var require_call_bind = __commonJS({ + "scripts/node-portable/node_modules/call-bind/index.js"(exports2, module2) { + "use strict"; + var setFunctionLength = require_set_function_length(); + var $defineProperty = require_es_define_property(); + var callBindBasic = require_call_bind_apply_helpers(); + var applyBind = require_applyBind(); + module2.exports = function callBind(originalFunction) { + var func = callBindBasic(arguments); + var adjustedLength = 1 + originalFunction.length - (arguments.length - 1); + return setFunctionLength( + func, + adjustedLength > 0 ? adjustedLength : 0, + true + ); + }; + if ($defineProperty) { + $defineProperty(module2.exports, "apply", { value: applyBind }); + } else { + module2.exports.apply = applyBind; + } + } +}); + +// scripts/node-portable/node_modules/which-typed-array/index.js +var require_which_typed_array = __commonJS({ + "scripts/node-portable/node_modules/which-typed-array/index.js"(exports2, module2) { + "use strict"; + var forEach = require_for_each(); + var availableTypedArrays = require_available_typed_arrays(); + var callBind = require_call_bind(); + var callBound = require_call_bound(); + var gOPD = require_gopd(); + var getProto = require_get_proto(); + var $toString = callBound("Object.prototype.toString"); + var hasToStringTag = require_shams2()(); + var g = typeof globalThis === "undefined" ? global : globalThis; + var typedArrays = availableTypedArrays(); + var $slice = callBound("String.prototype.slice"); + var $indexOf = callBound("Array.prototype.indexOf", true) || function indexOf(array, value) { + for (var i = 0; i < array.length; i += 1) { + if (array[i] === value) { + return i; + } + } + return -1; + }; + var cache = { __proto__: null }; + if (hasToStringTag && gOPD && getProto) { + forEach(typedArrays, function(typedArray) { + var arr = new g[typedArray](); + if (Symbol.toStringTag in arr && getProto) { + var proto = getProto(arr); + var descriptor = gOPD(proto, Symbol.toStringTag); + if (!descriptor && proto) { + var superProto = getProto(proto); + descriptor = gOPD(superProto, Symbol.toStringTag); + } + if (descriptor && descriptor.get) { + var bound = callBind(descriptor.get); + cache[ + /** @type {`$${TypedArrayName}`} */ + "$" + typedArray + ] = bound; + } + } + }); + } else { + forEach(typedArrays, function(typedArray) { + var arr = new g[typedArray](); + var fn = arr.slice || arr.set; + if (fn) { + var bound = ( + /** @type {typeof BoundSlice | typeof BoundSet} */ + // @ts-expect-error TODO FIXME + callBind(fn) + ); + cache[ + /** @type {`$${TypedArrayName}`} */ + "$" + typedArray + ] = bound; + } + }); + } + function tryTypedArrays(value) { + var found = false; + forEach( + /** @type {Record<`$${TypedArrayName}`, Getter>} */ + cache, + /** @param {Getter} getter @param {`$${TypedArrayName}`} typedArray */ + function(getter, typedArray) { + if (!found) { + try { + if ("$" + getter(value) === typedArray) { + found = /** @type {TypedArrayName} */ + $slice(typedArray, 1); + } + } catch (e) { + } + } + } + ); + return found; + } + function trySlices(value) { + var found = false; + forEach( + /** @type {Record<`$${TypedArrayName}`, Getter>} */ + cache, + /** @param {Getter} getter @param {`$${TypedArrayName}`} name */ + function(getter, name) { + if (!found) { + try { + getter(value); + found = /** @type {TypedArrayName} */ + $slice(name, 1); + } catch (e) { + } + } + } + ); + return found; + } + function isTATag(tag) { + return $indexOf(typedArrays, tag) > -1; + } + function whichTypedArray(value) { + if (!value || typeof value !== "object") { + return false; + } + if (!hasToStringTag) { + var tag = $slice($toString(value), 8, -1); + if (isTATag(tag)) { + return tag; + } + if (tag !== "Object") { + return false; + } + return trySlices(value); + } + if (!gOPD) { + return null; + } + return tryTypedArrays(value); + } + module2.exports = whichTypedArray; + } +}); + +// scripts/node-portable/node_modules/is-typed-array/index.js +var require_is_typed_array = __commonJS({ + "scripts/node-portable/node_modules/is-typed-array/index.js"(exports2, module2) { + "use strict"; + var whichTypedArray = require_which_typed_array(); + module2.exports = function isTypedArray(value) { + return !!whichTypedArray(value); + }; + } +}); + +// scripts/node-portable/node_modules/util/support/types.js +var require_types = __commonJS({ + "scripts/node-portable/node_modules/util/support/types.js"(exports2) { + "use strict"; + var isArgumentsObject = require_is_arguments(); + var isGeneratorFunction = require_is_generator_function(); + var whichTypedArray = require_which_typed_array(); + var isTypedArray = require_is_typed_array(); + function uncurryThis(f) { + return f.call.bind(f); + } + var BigIntSupported = typeof BigInt !== "undefined"; + var SymbolSupported = typeof Symbol !== "undefined"; + var ObjectToString = uncurryThis(Object.prototype.toString); + var numberValue = uncurryThis(Number.prototype.valueOf); + var stringValue = uncurryThis(String.prototype.valueOf); + var booleanValue = uncurryThis(Boolean.prototype.valueOf); + if (BigIntSupported) { + bigIntValue = uncurryThis(BigInt.prototype.valueOf); + } + var bigIntValue; + if (SymbolSupported) { + symbolValue = uncurryThis(Symbol.prototype.valueOf); + } + var symbolValue; + function checkBoxedPrimitive(value, prototypeValueOf) { + if (typeof value !== "object") { + return false; + } + try { + prototypeValueOf(value); + return true; + } catch (e) { + return false; + } + } + exports2.isArgumentsObject = isArgumentsObject; + exports2.isGeneratorFunction = isGeneratorFunction; + exports2.isTypedArray = isTypedArray; + function isPromise(input) { + return typeof Promise !== "undefined" && input instanceof Promise || input !== null && typeof input === "object" && typeof input.then === "function" && typeof input.catch === "function"; + } + exports2.isPromise = isPromise; + function isArrayBufferView(value) { + if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView) { + return ArrayBuffer.isView(value); + } + return isTypedArray(value) || isDataView(value); + } + exports2.isArrayBufferView = isArrayBufferView; + function isUint8Array(value) { + return whichTypedArray(value) === "Uint8Array"; + } + exports2.isUint8Array = isUint8Array; + function isUint8ClampedArray(value) { + return whichTypedArray(value) === "Uint8ClampedArray"; + } + exports2.isUint8ClampedArray = isUint8ClampedArray; + function isUint16Array(value) { + return whichTypedArray(value) === "Uint16Array"; + } + exports2.isUint16Array = isUint16Array; + function isUint32Array(value) { + return whichTypedArray(value) === "Uint32Array"; + } + exports2.isUint32Array = isUint32Array; + function isInt8Array(value) { + return whichTypedArray(value) === "Int8Array"; + } + exports2.isInt8Array = isInt8Array; + function isInt16Array(value) { + return whichTypedArray(value) === "Int16Array"; + } + exports2.isInt16Array = isInt16Array; + function isInt32Array(value) { + return whichTypedArray(value) === "Int32Array"; + } + exports2.isInt32Array = isInt32Array; + function isFloat32Array(value) { + return whichTypedArray(value) === "Float32Array"; + } + exports2.isFloat32Array = isFloat32Array; + function isFloat64Array(value) { + return whichTypedArray(value) === "Float64Array"; + } + exports2.isFloat64Array = isFloat64Array; + function isBigInt64Array(value) { + return whichTypedArray(value) === "BigInt64Array"; + } + exports2.isBigInt64Array = isBigInt64Array; + function isBigUint64Array(value) { + return whichTypedArray(value) === "BigUint64Array"; + } + exports2.isBigUint64Array = isBigUint64Array; + function isMapToString(value) { + return ObjectToString(value) === "[object Map]"; + } + isMapToString.working = typeof Map !== "undefined" && isMapToString(/* @__PURE__ */ new Map()); + function isMap(value) { + if (typeof Map === "undefined") { + return false; + } + return isMapToString.working ? isMapToString(value) : value instanceof Map; + } + exports2.isMap = isMap; + function isSetToString(value) { + return ObjectToString(value) === "[object Set]"; + } + isSetToString.working = typeof Set !== "undefined" && isSetToString(/* @__PURE__ */ new Set()); + function isSet(value) { + if (typeof Set === "undefined") { + return false; + } + return isSetToString.working ? isSetToString(value) : value instanceof Set; + } + exports2.isSet = isSet; + function isWeakMapToString(value) { + return ObjectToString(value) === "[object WeakMap]"; + } + isWeakMapToString.working = typeof WeakMap !== "undefined" && isWeakMapToString(/* @__PURE__ */ new WeakMap()); + function isWeakMap(value) { + if (typeof WeakMap === "undefined") { + return false; + } + return isWeakMapToString.working ? isWeakMapToString(value) : value instanceof WeakMap; + } + exports2.isWeakMap = isWeakMap; + function isWeakSetToString(value) { + return ObjectToString(value) === "[object WeakSet]"; + } + isWeakSetToString.working = typeof WeakSet !== "undefined" && isWeakSetToString(/* @__PURE__ */ new WeakSet()); + function isWeakSet(value) { + return isWeakSetToString(value); + } + exports2.isWeakSet = isWeakSet; + function isArrayBufferToString(value) { + return ObjectToString(value) === "[object ArrayBuffer]"; + } + isArrayBufferToString.working = typeof ArrayBuffer !== "undefined" && isArrayBufferToString(new ArrayBuffer()); + function isArrayBuffer(value) { + if (typeof ArrayBuffer === "undefined") { + return false; + } + return isArrayBufferToString.working ? isArrayBufferToString(value) : value instanceof ArrayBuffer; + } + exports2.isArrayBuffer = isArrayBuffer; + function isDataViewToString(value) { + return ObjectToString(value) === "[object DataView]"; + } + isDataViewToString.working = typeof ArrayBuffer !== "undefined" && typeof DataView !== "undefined" && isDataViewToString(new DataView(new ArrayBuffer(1), 0, 1)); + function isDataView(value) { + if (typeof DataView === "undefined") { + return false; + } + return isDataViewToString.working ? isDataViewToString(value) : value instanceof DataView; + } + exports2.isDataView = isDataView; + var SharedArrayBufferCopy = typeof SharedArrayBuffer !== "undefined" ? SharedArrayBuffer : void 0; + function isSharedArrayBufferToString(value) { + return ObjectToString(value) === "[object SharedArrayBuffer]"; + } + function isSharedArrayBuffer(value) { + if (typeof SharedArrayBufferCopy === "undefined") { + return false; + } + if (typeof isSharedArrayBufferToString.working === "undefined") { + isSharedArrayBufferToString.working = isSharedArrayBufferToString(new SharedArrayBufferCopy()); + } + return isSharedArrayBufferToString.working ? isSharedArrayBufferToString(value) : value instanceof SharedArrayBufferCopy; + } + exports2.isSharedArrayBuffer = isSharedArrayBuffer; + function isAsyncFunction(value) { + return ObjectToString(value) === "[object AsyncFunction]"; + } + exports2.isAsyncFunction = isAsyncFunction; + function isMapIterator(value) { + return ObjectToString(value) === "[object Map Iterator]"; + } + exports2.isMapIterator = isMapIterator; + function isSetIterator(value) { + return ObjectToString(value) === "[object Set Iterator]"; + } + exports2.isSetIterator = isSetIterator; + function isGeneratorObject(value) { + return ObjectToString(value) === "[object Generator]"; + } + exports2.isGeneratorObject = isGeneratorObject; + function isWebAssemblyCompiledModule(value) { + return ObjectToString(value) === "[object WebAssembly.Module]"; + } + exports2.isWebAssemblyCompiledModule = isWebAssemblyCompiledModule; + function isNumberObject(value) { + return checkBoxedPrimitive(value, numberValue); + } + exports2.isNumberObject = isNumberObject; + function isStringObject(value) { + return checkBoxedPrimitive(value, stringValue); + } + exports2.isStringObject = isStringObject; + function isBooleanObject(value) { + return checkBoxedPrimitive(value, booleanValue); + } + exports2.isBooleanObject = isBooleanObject; + function isBigIntObject(value) { + return BigIntSupported && checkBoxedPrimitive(value, bigIntValue); + } + exports2.isBigIntObject = isBigIntObject; + function isSymbolObject(value) { + return SymbolSupported && checkBoxedPrimitive(value, symbolValue); + } + exports2.isSymbolObject = isSymbolObject; + function isBoxedPrimitive(value) { + return isNumberObject(value) || isStringObject(value) || isBooleanObject(value) || isBigIntObject(value) || isSymbolObject(value); + } + exports2.isBoxedPrimitive = isBoxedPrimitive; + function isAnyArrayBuffer(value) { + return typeof Uint8Array !== "undefined" && (isArrayBuffer(value) || isSharedArrayBuffer(value)); + } + exports2.isAnyArrayBuffer = isAnyArrayBuffer; + ["isProxy", "isExternal", "isModuleNamespaceObject"].forEach(function(method) { + Object.defineProperty(exports2, method, { + enumerable: false, + value: function() { + throw new Error(method + " is not supported in userland"); + } + }); + }); + } +}); + +// scripts/node-portable/node_modules/util/support/isBuffer.js +var require_isBuffer = __commonJS({ + "scripts/node-portable/node_modules/util/support/isBuffer.js"(exports2, module2) { + module2.exports = function isBuffer(arg) { + return arg instanceof Buffer; + }; + } +}); + +// scripts/node-portable/node_modules/inherits/inherits_browser.js +var require_inherits_browser = __commonJS({ + "scripts/node-portable/node_modules/inherits/inherits_browser.js"(exports2, module2) { + if (typeof Object.create === "function") { + module2.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor; + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + } + }; + } else { + module2.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor; + var TempCtor = function() { + }; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + } + }; + } + } +}); + +// scripts/node-portable/node_modules/inherits/inherits.js +var require_inherits = __commonJS({ + "scripts/node-portable/node_modules/inherits/inherits.js"(exports2, module2) { + try { + util = require("util"); + if (typeof util.inherits !== "function") throw ""; + module2.exports = util.inherits; + } catch (e) { + module2.exports = require_inherits_browser(); + } + var util; + } +}); + +// scripts/node-portable/node_modules/util/util.js +var require_util = __commonJS({ + "scripts/node-portable/node_modules/util/util.js"(exports2) { + var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function getOwnPropertyDescriptors2(obj) { + var keys = Object.keys(obj); + var descriptors = {}; + for (var i = 0; i < keys.length; i++) { + descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj, keys[i]); + } + return descriptors; + }; + var formatRegExp = /%[sdj%]/g; + exports2.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(" "); + } + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x2) { + if (x2 === "%%") return "%"; + if (i >= len) return x2; + switch (x2) { + case "%s": + return String(args[i++]); + case "%d": + return Number(args[i++]); + case "%j": + try { + return JSON.stringify(args[i++]); + } catch (_) { + return "[Circular]"; + } + default: + return x2; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += " " + x; + } else { + str += " " + inspect(x); + } + } + return str; + }; + exports2.deprecate = function(fn, msg) { + if (typeof process !== "undefined" && process.noDeprecation === true) { + return fn; + } + if (typeof process === "undefined") { + return function() { + return exports2.deprecate(fn, msg).apply(this, arguments); + }; + } + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + return deprecated; + }; + var debugs = {}; + var debugEnvRegex = /^$/; + if (process.env.NODE_DEBUG) { + debugEnv = process.env.NODE_DEBUG; + debugEnv = debugEnv.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/\*/g, ".*").replace(/,/g, "$|^").toUpperCase(); + debugEnvRegex = new RegExp("^" + debugEnv + "$", "i"); + } + var debugEnv; + exports2.debuglog = function(set) { + set = set.toUpperCase(); + if (!debugs[set]) { + if (debugEnvRegex.test(set)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports2.format.apply(exports2, arguments); + console.error("%s %d: %s", set, pid, msg); + }; + } else { + debugs[set] = function() { + }; + } + } + return debugs[set]; + }; + function inspect(obj, opts) { + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + ctx.showHidden = opts; + } else if (opts) { + exports2._extend(ctx, opts); + } + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); + } + exports2.inspect = inspect; + inspect.colors = { + "bold": [1, 22], + "italic": [3, 23], + "underline": [4, 24], + "inverse": [7, 27], + "white": [37, 39], + "grey": [90, 39], + "black": [30, 39], + "blue": [34, 39], + "cyan": [36, 39], + "green": [32, 39], + "magenta": [35, 39], + "red": [31, 39], + "yellow": [33, 39] + }; + inspect.styles = { + "special": "cyan", + "number": "yellow", + "boolean": "yellow", + "undefined": "grey", + "null": "bold", + "string": "green", + "date": "magenta", + // "name": intentionally not styling + "regexp": "red" + }; + function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + if (style) { + return "\x1B[" + inspect.colors[style][0] + "m" + str + "\x1B[" + inspect.colors[style][1] + "m"; + } else { + return str; + } + } + function stylizeNoColor(str, styleType) { + return str; + } + function arrayToHash(array) { + var hash = {}; + array.forEach(function(val, idx) { + hash[val] = true; + }); + return hash; + } + function formatValue(ctx, value, recurseTimes) { + if (ctx.customInspect && value && isFunction(value.inspect) && // Filter out the util module, it's inspect function is special + value.inspect !== exports2.inspect && // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + if (isError(value) && (keys.indexOf("message") >= 0 || keys.indexOf("description") >= 0)) { + return formatError(value); + } + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ": " + value.name : ""; + return ctx.stylize("[Function" + name + "]", "special"); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), "regexp"); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), "date"); + } + if (isError(value)) { + return formatError(value); + } + } + var base = "", array = false, braces = ["{", "}"]; + if (isArray(value)) { + array = true; + braces = ["[", "]"]; + } + if (isFunction(value)) { + var n = value.name ? ": " + value.name : ""; + base = " [Function" + n + "]"; + } + if (isRegExp(value)) { + base = " " + RegExp.prototype.toString.call(value); + } + if (isDate(value)) { + base = " " + Date.prototype.toUTCString.call(value); + } + if (isError(value)) { + base = " " + formatError(value); + } + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), "regexp"); + } else { + return ctx.stylize("[Object]", "special"); + } + } + ctx.seen.push(value); + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + ctx.seen.pop(); + return reduceToSingleString(output, base, braces); + } + function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize("undefined", "undefined"); + if (isString(value)) { + var simple = "'" + JSON.stringify(value).replace(/^"|"$/g, "").replace(/'/g, "\\'").replace(/\\"/g, '"') + "'"; + return ctx.stylize(simple, "string"); + } + if (isNumber(value)) + return ctx.stylize("" + value, "number"); + if (isBoolean(value)) + return ctx.stylize("" + value, "boolean"); + if (isNull(value)) + return ctx.stylize("null", "null"); + } + function formatError(value) { + return "[" + Error.prototype.toString.call(value) + "]"; + } + function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty( + ctx, + value, + recurseTimes, + visibleKeys, + String(i), + true + )); + } else { + output.push(""); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty( + ctx, + value, + recurseTimes, + visibleKeys, + key, + true + )); + } + }); + return output; + } + function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize("[Getter/Setter]", "special"); + } else { + str = ctx.stylize("[Getter]", "special"); + } + } else { + if (desc.set) { + str = ctx.stylize("[Setter]", "special"); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = "[" + key + "]"; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf("\n") > -1) { + if (array) { + str = str.split("\n").map(function(line) { + return " " + line; + }).join("\n").slice(2); + } else { + str = "\n" + str.split("\n").map(function(line) { + return " " + line; + }).join("\n"); + } + } + } else { + str = ctx.stylize("[Circular]", "special"); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify("" + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.slice(1, -1); + name = ctx.stylize(name, "name"); + } else { + name = name.replace(/'/g, "\\'").replace(/\\"/g, '"').replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, "string"); + } + } + return name + ": " + str; + } + function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf("\n") >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, "").length + 1; + }, 0); + if (length > 60) { + return braces[0] + (base === "" ? "" : base + "\n ") + " " + output.join(",\n ") + " " + braces[1]; + } + return braces[0] + base + " " + output.join(", ") + " " + braces[1]; + } + exports2.types = require_types(); + function isArray(ar) { + return Array.isArray(ar); + } + exports2.isArray = isArray; + function isBoolean(arg) { + return typeof arg === "boolean"; + } + exports2.isBoolean = isBoolean; + function isNull(arg) { + return arg === null; + } + exports2.isNull = isNull; + function isNullOrUndefined(arg) { + return arg == null; + } + exports2.isNullOrUndefined = isNullOrUndefined; + function isNumber(arg) { + return typeof arg === "number"; + } + exports2.isNumber = isNumber; + function isString(arg) { + return typeof arg === "string"; + } + exports2.isString = isString; + function isSymbol(arg) { + return typeof arg === "symbol"; + } + exports2.isSymbol = isSymbol; + function isUndefined(arg) { + return arg === void 0; + } + exports2.isUndefined = isUndefined; + function isRegExp(re) { + return isObject(re) && objectToString(re) === "[object RegExp]"; + } + exports2.isRegExp = isRegExp; + exports2.types.isRegExp = isRegExp; + function isObject(arg) { + return typeof arg === "object" && arg !== null; + } + exports2.isObject = isObject; + function isDate(d) { + return isObject(d) && objectToString(d) === "[object Date]"; + } + exports2.isDate = isDate; + exports2.types.isDate = isDate; + function isError(e) { + return isObject(e) && (objectToString(e) === "[object Error]" || e instanceof Error); + } + exports2.isError = isError; + exports2.types.isNativeError = isError; + function isFunction(arg) { + return typeof arg === "function"; + } + exports2.isFunction = isFunction; + function isPrimitive(arg) { + return arg === null || typeof arg === "boolean" || typeof arg === "number" || typeof arg === "string" || typeof arg === "symbol" || // ES6 symbol + typeof arg === "undefined"; + } + exports2.isPrimitive = isPrimitive; + exports2.isBuffer = require_isBuffer(); + function objectToString(o) { + return Object.prototype.toString.call(o); + } + function pad(n) { + return n < 10 ? "0" + n.toString(10) : n.toString(10); + } + var months = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + ]; + function timestamp() { + var d = /* @__PURE__ */ new Date(); + var time = [ + pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds()) + ].join(":"); + return [d.getDate(), months[d.getMonth()], time].join(" "); + } + exports2.log = function() { + console.log("%s - %s", timestamp(), exports2.format.apply(exports2, arguments)); + }; + exports2.inherits = require_inherits(); + exports2._extend = function(origin, add) { + if (!add || !isObject(add)) return origin; + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; + }; + function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); + } + var kCustomPromisifiedSymbol = typeof Symbol !== "undefined" ? Symbol("util.promisify.custom") : void 0; + exports2.promisify = function promisify(original) { + if (typeof original !== "function") + throw new TypeError('The "original" argument must be of type Function'); + if (kCustomPromisifiedSymbol && original[kCustomPromisifiedSymbol]) { + var fn = original[kCustomPromisifiedSymbol]; + if (typeof fn !== "function") { + throw new TypeError('The "util.promisify.custom" argument must be of type Function'); + } + Object.defineProperty(fn, kCustomPromisifiedSymbol, { + value: fn, + enumerable: false, + writable: false, + configurable: true + }); + return fn; + } + function fn() { + var promiseResolve, promiseReject; + var promise = new Promise(function(resolve, reject) { + promiseResolve = resolve; + promiseReject = reject; + }); + var args = []; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + args.push(function(err, value) { + if (err) { + promiseReject(err); + } else { + promiseResolve(value); + } + }); + try { + original.apply(this, args); + } catch (err) { + promiseReject(err); + } + return promise; + } + Object.setPrototypeOf(fn, Object.getPrototypeOf(original)); + if (kCustomPromisifiedSymbol) Object.defineProperty(fn, kCustomPromisifiedSymbol, { + value: fn, + enumerable: false, + writable: false, + configurable: true + }); + return Object.defineProperties( + fn, + getOwnPropertyDescriptors(original) + ); + }; + exports2.promisify.custom = kCustomPromisifiedSymbol; + function callbackifyOnRejected(reason, cb) { + if (!reason) { + var newReason = new Error("Promise was rejected with a falsy value"); + newReason.reason = reason; + reason = newReason; + } + return cb(reason); + } + function callbackify(original) { + if (typeof original !== "function") { + throw new TypeError('The "original" argument must be of type Function'); + } + function callbackified() { + var args = []; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + var maybeCb = args.pop(); + if (typeof maybeCb !== "function") { + throw new TypeError("The last argument must be of type Function"); + } + var self = this; + var cb = function() { + return maybeCb.apply(self, arguments); + }; + original.apply(this, args).then( + function(ret) { + process.nextTick(cb.bind(null, null, ret)); + }, + function(rej) { + process.nextTick(callbackifyOnRejected.bind(null, rej, cb)); + } + ); + } + Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original)); + Object.defineProperties( + callbackified, + getOwnPropertyDescriptors(original) + ); + return callbackified; + } + exports2.callbackify = callbackify; + } +}); + +// scripts/node-portable/node_modules/assert/build/internal/errors.js +var require_errors = __commonJS({ + "scripts/node-portable/node_modules/assert/build/internal/errors.js"(exports2, module2) { + "use strict"; + function _typeof(o) { + "@babel/helpers - typeof"; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof(o); + } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); + } + } + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { writable: false }); + return Constructor; + } + function _toPropertyKey(arg) { + var key = _toPrimitive(arg, "string"); + return _typeof(key) === "symbol" ? key : String(key); + } + function _toPrimitive(input, hint) { + if (_typeof(input) !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== void 0) { + var res = prim.call(input, hint || "default"); + if (_typeof(res) !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } + subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); + Object.defineProperty(subClass, "prototype", { writable: false }); + if (superClass) _setPrototypeOf(subClass, superClass); + } + function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf2(o2, p2) { + o2.__proto__ = p2; + return o2; + }; + return _setPrototypeOf(o, p); + } + function _createSuper(Derived) { + var hasNativeReflectConstruct = _isNativeReflectConstruct(); + return function _createSuperInternal() { + var Super = _getPrototypeOf(Derived), result; + if (hasNativeReflectConstruct) { + var NewTarget = _getPrototypeOf(this).constructor; + result = Reflect.construct(Super, arguments, NewTarget); + } else { + result = Super.apply(this, arguments); + } + return _possibleConstructorReturn(this, result); + }; + } + function _possibleConstructorReturn(self, call) { + if (call && (_typeof(call) === "object" || typeof call === "function")) { + return call; + } else if (call !== void 0) { + throw new TypeError("Derived constructors may only return object or undefined"); + } + return _assertThisInitialized(self); + } + function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + return self; + } + function _isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) return false; + if (Reflect.construct.sham) return false; + if (typeof Proxy === "function") return true; + try { + Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() { + })); + return true; + } catch (e) { + return false; + } + } + function _getPrototypeOf(o) { + _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf2(o2) { + return o2.__proto__ || Object.getPrototypeOf(o2); + }; + return _getPrototypeOf(o); + } + var codes = {}; + var assert; + var util; + function createErrorType(code, message, Base) { + if (!Base) { + Base = Error; + } + function getMessage(arg1, arg2, arg3) { + if (typeof message === "string") { + return message; + } else { + return message(arg1, arg2, arg3); + } + } + var NodeError = /* @__PURE__ */ (function(_Base) { + _inherits(NodeError2, _Base); + var _super = _createSuper(NodeError2); + function NodeError2(arg1, arg2, arg3) { + var _this; + _classCallCheck(this, NodeError2); + _this = _super.call(this, getMessage(arg1, arg2, arg3)); + _this.code = code; + return _this; + } + return _createClass(NodeError2); + })(Base); + codes[code] = NodeError; + } + function oneOf(expected, thing) { + if (Array.isArray(expected)) { + var len = expected.length; + expected = expected.map(function(i) { + return String(i); + }); + if (len > 2) { + return "one of ".concat(thing, " ").concat(expected.slice(0, len - 1).join(", "), ", or ") + expected[len - 1]; + } else if (len === 2) { + return "one of ".concat(thing, " ").concat(expected[0], " or ").concat(expected[1]); + } else { + return "of ".concat(thing, " ").concat(expected[0]); + } + } else { + return "of ".concat(thing, " ").concat(String(expected)); + } + } + function startsWith(str, search, pos) { + return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; + } + function endsWith(str, search, this_len) { + if (this_len === void 0 || this_len > str.length) { + this_len = str.length; + } + return str.substring(this_len - search.length, this_len) === search; + } + function includes(str, search, start) { + if (typeof start !== "number") { + start = 0; + } + if (start + search.length > str.length) { + return false; + } else { + return str.indexOf(search, start) !== -1; + } + } + createErrorType("ERR_AMBIGUOUS_ARGUMENT", 'The "%s" argument is ambiguous. %s', TypeError); + createErrorType("ERR_INVALID_ARG_TYPE", function(name, expected, actual) { + if (assert === void 0) assert = require_assert(); + assert(typeof name === "string", "'name' must be a string"); + var determiner; + if (typeof expected === "string" && startsWith(expected, "not ")) { + determiner = "must not be"; + expected = expected.replace(/^not /, ""); + } else { + determiner = "must be"; + } + var msg; + if (endsWith(name, " argument")) { + msg = "The ".concat(name, " ").concat(determiner, " ").concat(oneOf(expected, "type")); + } else { + var type = includes(name, ".") ? "property" : "argument"; + msg = 'The "'.concat(name, '" ').concat(type, " ").concat(determiner, " ").concat(oneOf(expected, "type")); + } + msg += ". Received type ".concat(_typeof(actual)); + return msg; + }, TypeError); + createErrorType("ERR_INVALID_ARG_VALUE", function(name, value) { + var reason = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "is invalid"; + if (util === void 0) util = require_util(); + var inspected = util.inspect(value); + if (inspected.length > 128) { + inspected = "".concat(inspected.slice(0, 128), "..."); + } + return "The argument '".concat(name, "' ").concat(reason, ". Received ").concat(inspected); + }, TypeError, RangeError); + createErrorType("ERR_INVALID_RETURN_VALUE", function(input, name, value) { + var type; + if (value && value.constructor && value.constructor.name) { + type = "instance of ".concat(value.constructor.name); + } else { + type = "type ".concat(_typeof(value)); + } + return "Expected ".concat(input, ' to be returned from the "').concat(name, '"') + " function but got ".concat(type, "."); + }, TypeError); + createErrorType("ERR_MISSING_ARGS", function() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + if (assert === void 0) assert = require_assert(); + assert(args.length > 0, "At least one arg needs to be specified"); + var msg = "The "; + var len = args.length; + args = args.map(function(a) { + return '"'.concat(a, '"'); + }); + switch (len) { + case 1: + msg += "".concat(args[0], " argument"); + break; + case 2: + msg += "".concat(args[0], " and ").concat(args[1], " arguments"); + break; + default: + msg += args.slice(0, len - 1).join(", "); + msg += ", and ".concat(args[len - 1], " arguments"); + break; + } + return "".concat(msg, " must be specified"); + }, TypeError); + module2.exports.codes = codes; + } +}); + +// scripts/node-portable/node_modules/assert/build/internal/assert/assertion_error.js +var require_assertion_error = __commonJS({ + "scripts/node-portable/node_modules/assert/build/internal/assert/assertion_error.js"(exports2, module2) { + "use strict"; + function ownKeys(e, r) { + var t = Object.keys(e); + if (Object.getOwnPropertySymbols) { + var o = Object.getOwnPropertySymbols(e); + r && (o = o.filter(function(r2) { + return Object.getOwnPropertyDescriptor(e, r2).enumerable; + })), t.push.apply(t, o); + } + return t; + } + function _objectSpread(e) { + for (var r = 1; r < arguments.length; r++) { + var t = null != arguments[r] ? arguments[r] : {}; + r % 2 ? ownKeys(Object(t), true).forEach(function(r2) { + _defineProperty(e, r2, t[r2]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r2) { + Object.defineProperty(e, r2, Object.getOwnPropertyDescriptor(t, r2)); + }); + } + return e; + } + function _defineProperty(obj, key, value) { + key = _toPropertyKey(key); + if (key in obj) { + Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true }); + } else { + obj[key] = value; + } + return obj; + } + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); + } + } + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { writable: false }); + return Constructor; + } + function _toPropertyKey(arg) { + var key = _toPrimitive(arg, "string"); + return _typeof(key) === "symbol" ? key : String(key); + } + function _toPrimitive(input, hint) { + if (_typeof(input) !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== void 0) { + var res = prim.call(input, hint || "default"); + if (_typeof(res) !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } + subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); + Object.defineProperty(subClass, "prototype", { writable: false }); + if (superClass) _setPrototypeOf(subClass, superClass); + } + function _createSuper(Derived) { + var hasNativeReflectConstruct = _isNativeReflectConstruct(); + return function _createSuperInternal() { + var Super = _getPrototypeOf(Derived), result; + if (hasNativeReflectConstruct) { + var NewTarget = _getPrototypeOf(this).constructor; + result = Reflect.construct(Super, arguments, NewTarget); + } else { + result = Super.apply(this, arguments); + } + return _possibleConstructorReturn(this, result); + }; + } + function _possibleConstructorReturn(self, call) { + if (call && (_typeof(call) === "object" || typeof call === "function")) { + return call; + } else if (call !== void 0) { + throw new TypeError("Derived constructors may only return object or undefined"); + } + return _assertThisInitialized(self); + } + function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + return self; + } + function _wrapNativeSuper(Class) { + var _cache = typeof Map === "function" ? /* @__PURE__ */ new Map() : void 0; + _wrapNativeSuper = function _wrapNativeSuper2(Class2) { + if (Class2 === null || !_isNativeFunction(Class2)) return Class2; + if (typeof Class2 !== "function") { + throw new TypeError("Super expression must either be null or a function"); + } + if (typeof _cache !== "undefined") { + if (_cache.has(Class2)) return _cache.get(Class2); + _cache.set(Class2, Wrapper); + } + function Wrapper() { + return _construct(Class2, arguments, _getPrototypeOf(this).constructor); + } + Wrapper.prototype = Object.create(Class2.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); + return _setPrototypeOf(Wrapper, Class2); + }; + return _wrapNativeSuper(Class); + } + function _construct(Parent, args, Class) { + if (_isNativeReflectConstruct()) { + _construct = Reflect.construct.bind(); + } else { + _construct = function _construct2(Parent2, args2, Class2) { + var a = [null]; + a.push.apply(a, args2); + var Constructor = Function.bind.apply(Parent2, a); + var instance = new Constructor(); + if (Class2) _setPrototypeOf(instance, Class2.prototype); + return instance; + }; + } + return _construct.apply(null, arguments); + } + function _isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) return false; + if (Reflect.construct.sham) return false; + if (typeof Proxy === "function") return true; + try { + Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() { + })); + return true; + } catch (e) { + return false; + } + } + function _isNativeFunction(fn) { + return Function.toString.call(fn).indexOf("[native code]") !== -1; + } + function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf2(o2, p2) { + o2.__proto__ = p2; + return o2; + }; + return _setPrototypeOf(o, p); + } + function _getPrototypeOf(o) { + _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf2(o2) { + return o2.__proto__ || Object.getPrototypeOf(o2); + }; + return _getPrototypeOf(o); + } + function _typeof(o) { + "@babel/helpers - typeof"; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof(o); + } + var _require = require_util(); + var inspect = _require.inspect; + var _require2 = require_errors(); + var ERR_INVALID_ARG_TYPE = _require2.codes.ERR_INVALID_ARG_TYPE; + function endsWith(str, search, this_len) { + if (this_len === void 0 || this_len > str.length) { + this_len = str.length; + } + return str.substring(this_len - search.length, this_len) === search; + } + function repeat(str, count) { + count = Math.floor(count); + if (str.length == 0 || count == 0) return ""; + var maxCount = str.length * count; + count = Math.floor(Math.log(count) / Math.log(2)); + while (count) { + str += str; + count--; + } + str += str.substring(0, maxCount - str.length); + return str; + } + var blue = ""; + var green = ""; + var red = ""; + var white = ""; + var kReadableOperator = { + deepStrictEqual: "Expected values to be strictly deep-equal:", + strictEqual: "Expected values to be strictly equal:", + strictEqualObject: 'Expected "actual" to be reference-equal to "expected":', + deepEqual: "Expected values to be loosely deep-equal:", + equal: "Expected values to be loosely equal:", + notDeepStrictEqual: 'Expected "actual" not to be strictly deep-equal to:', + notStrictEqual: 'Expected "actual" to be strictly unequal to:', + notStrictEqualObject: 'Expected "actual" not to be reference-equal to "expected":', + notDeepEqual: 'Expected "actual" not to be loosely deep-equal to:', + notEqual: 'Expected "actual" to be loosely unequal to:', + notIdentical: "Values identical but not reference-equal:" + }; + var kMaxShortLength = 10; + function copyError(source) { + var keys = Object.keys(source); + var target = Object.create(Object.getPrototypeOf(source)); + keys.forEach(function(key) { + target[key] = source[key]; + }); + Object.defineProperty(target, "message", { + value: source.message + }); + return target; + } + function inspectValue(val) { + return inspect(val, { + compact: false, + customInspect: false, + depth: 1e3, + maxArrayLength: Infinity, + // Assert compares only enumerable properties (with a few exceptions). + showHidden: false, + // Having a long line as error is better than wrapping the line for + // comparison for now. + // TODO(BridgeAR): `breakLength` should be limited as soon as soon as we + // have meta information about the inspected properties (i.e., know where + // in what line the property starts and ends). + breakLength: Infinity, + // Assert does not detect proxies currently. + showProxy: false, + sorted: true, + // Inspect getters as we also check them when comparing entries. + getters: true + }); + } + function createErrDiff(actual, expected, operator) { + var other = ""; + var res = ""; + var lastPos = 0; + var end = ""; + var skipped = false; + var actualInspected = inspectValue(actual); + var actualLines = actualInspected.split("\n"); + var expectedLines = inspectValue(expected).split("\n"); + var i = 0; + var indicator = ""; + if (operator === "strictEqual" && _typeof(actual) === "object" && _typeof(expected) === "object" && actual !== null && expected !== null) { + operator = "strictEqualObject"; + } + if (actualLines.length === 1 && expectedLines.length === 1 && actualLines[0] !== expectedLines[0]) { + var inputLength = actualLines[0].length + expectedLines[0].length; + if (inputLength <= kMaxShortLength) { + if ((_typeof(actual) !== "object" || actual === null) && (_typeof(expected) !== "object" || expected === null) && (actual !== 0 || expected !== 0)) { + return "".concat(kReadableOperator[operator], "\n\n") + "".concat(actualLines[0], " !== ").concat(expectedLines[0], "\n"); + } + } else if (operator !== "strictEqualObject") { + var maxLength = process.stderr && process.stderr.isTTY ? process.stderr.columns : 80; + if (inputLength < maxLength) { + while (actualLines[0][i] === expectedLines[0][i]) { + i++; + } + if (i > 2) { + indicator = "\n ".concat(repeat(" ", i), "^"); + i = 0; + } + } + } + } + var a = actualLines[actualLines.length - 1]; + var b = expectedLines[expectedLines.length - 1]; + while (a === b) { + if (i++ < 2) { + end = "\n ".concat(a).concat(end); + } else { + other = a; + } + actualLines.pop(); + expectedLines.pop(); + if (actualLines.length === 0 || expectedLines.length === 0) break; + a = actualLines[actualLines.length - 1]; + b = expectedLines[expectedLines.length - 1]; + } + var maxLines = Math.max(actualLines.length, expectedLines.length); + if (maxLines === 0) { + var _actualLines = actualInspected.split("\n"); + if (_actualLines.length > 30) { + _actualLines[26] = "".concat(blue, "...").concat(white); + while (_actualLines.length > 27) { + _actualLines.pop(); + } + } + return "".concat(kReadableOperator.notIdentical, "\n\n").concat(_actualLines.join("\n"), "\n"); + } + if (i > 3) { + end = "\n".concat(blue, "...").concat(white).concat(end); + skipped = true; + } + if (other !== "") { + end = "\n ".concat(other).concat(end); + other = ""; + } + var printedLines = 0; + var msg = kReadableOperator[operator] + "\n".concat(green, "+ actual").concat(white, " ").concat(red, "- expected").concat(white); + var skippedMsg = " ".concat(blue, "...").concat(white, " Lines skipped"); + for (i = 0; i < maxLines; i++) { + var cur = i - lastPos; + if (actualLines.length < i + 1) { + if (cur > 1 && i > 2) { + if (cur > 4) { + res += "\n".concat(blue, "...").concat(white); + skipped = true; + } else if (cur > 3) { + res += "\n ".concat(expectedLines[i - 2]); + printedLines++; + } + res += "\n ".concat(expectedLines[i - 1]); + printedLines++; + } + lastPos = i; + other += "\n".concat(red, "-").concat(white, " ").concat(expectedLines[i]); + printedLines++; + } else if (expectedLines.length < i + 1) { + if (cur > 1 && i > 2) { + if (cur > 4) { + res += "\n".concat(blue, "...").concat(white); + skipped = true; + } else if (cur > 3) { + res += "\n ".concat(actualLines[i - 2]); + printedLines++; + } + res += "\n ".concat(actualLines[i - 1]); + printedLines++; + } + lastPos = i; + res += "\n".concat(green, "+").concat(white, " ").concat(actualLines[i]); + printedLines++; + } else { + var expectedLine = expectedLines[i]; + var actualLine = actualLines[i]; + var divergingLines = actualLine !== expectedLine && (!endsWith(actualLine, ",") || actualLine.slice(0, -1) !== expectedLine); + if (divergingLines && endsWith(expectedLine, ",") && expectedLine.slice(0, -1) === actualLine) { + divergingLines = false; + actualLine += ","; + } + if (divergingLines) { + if (cur > 1 && i > 2) { + if (cur > 4) { + res += "\n".concat(blue, "...").concat(white); + skipped = true; + } else if (cur > 3) { + res += "\n ".concat(actualLines[i - 2]); + printedLines++; + } + res += "\n ".concat(actualLines[i - 1]); + printedLines++; + } + lastPos = i; + res += "\n".concat(green, "+").concat(white, " ").concat(actualLine); + other += "\n".concat(red, "-").concat(white, " ").concat(expectedLine); + printedLines += 2; + } else { + res += other; + other = ""; + if (cur === 1 || i === 0) { + res += "\n ".concat(actualLine); + printedLines++; + } + } + } + if (printedLines > 20 && i < maxLines - 2) { + return "".concat(msg).concat(skippedMsg, "\n").concat(res, "\n").concat(blue, "...").concat(white).concat(other, "\n") + "".concat(blue, "...").concat(white); + } + } + return "".concat(msg).concat(skipped ? skippedMsg : "", "\n").concat(res).concat(other).concat(end).concat(indicator); + } + var AssertionError = /* @__PURE__ */ (function(_Error, _inspect$custom) { + _inherits(AssertionError2, _Error); + var _super = _createSuper(AssertionError2); + function AssertionError2(options) { + var _this; + _classCallCheck(this, AssertionError2); + if (_typeof(options) !== "object" || options === null) { + throw new ERR_INVALID_ARG_TYPE("options", "Object", options); + } + var message = options.message, operator = options.operator, stackStartFn = options.stackStartFn; + var actual = options.actual, expected = options.expected; + var limit = Error.stackTraceLimit; + Error.stackTraceLimit = 0; + if (message != null) { + _this = _super.call(this, String(message)); + } else { + if (process.stderr && process.stderr.isTTY) { + if (process.stderr && process.stderr.getColorDepth && process.stderr.getColorDepth() !== 1) { + blue = "\x1B[34m"; + green = "\x1B[32m"; + white = "\x1B[39m"; + red = "\x1B[31m"; + } else { + blue = ""; + green = ""; + white = ""; + red = ""; + } + } + if (_typeof(actual) === "object" && actual !== null && _typeof(expected) === "object" && expected !== null && "stack" in actual && actual instanceof Error && "stack" in expected && expected instanceof Error) { + actual = copyError(actual); + expected = copyError(expected); + } + if (operator === "deepStrictEqual" || operator === "strictEqual") { + _this = _super.call(this, createErrDiff(actual, expected, operator)); + } else if (operator === "notDeepStrictEqual" || operator === "notStrictEqual") { + var base = kReadableOperator[operator]; + var res = inspectValue(actual).split("\n"); + if (operator === "notStrictEqual" && _typeof(actual) === "object" && actual !== null) { + base = kReadableOperator.notStrictEqualObject; + } + if (res.length > 30) { + res[26] = "".concat(blue, "...").concat(white); + while (res.length > 27) { + res.pop(); + } + } + if (res.length === 1) { + _this = _super.call(this, "".concat(base, " ").concat(res[0])); + } else { + _this = _super.call(this, "".concat(base, "\n\n").concat(res.join("\n"), "\n")); + } + } else { + var _res = inspectValue(actual); + var other = ""; + var knownOperators = kReadableOperator[operator]; + if (operator === "notDeepEqual" || operator === "notEqual") { + _res = "".concat(kReadableOperator[operator], "\n\n").concat(_res); + if (_res.length > 1024) { + _res = "".concat(_res.slice(0, 1021), "..."); + } + } else { + other = "".concat(inspectValue(expected)); + if (_res.length > 512) { + _res = "".concat(_res.slice(0, 509), "..."); + } + if (other.length > 512) { + other = "".concat(other.slice(0, 509), "..."); + } + if (operator === "deepEqual" || operator === "equal") { + _res = "".concat(knownOperators, "\n\n").concat(_res, "\n\nshould equal\n\n"); + } else { + other = " ".concat(operator, " ").concat(other); + } + } + _this = _super.call(this, "".concat(_res).concat(other)); + } + } + Error.stackTraceLimit = limit; + _this.generatedMessage = !message; + Object.defineProperty(_assertThisInitialized(_this), "name", { + value: "AssertionError [ERR_ASSERTION]", + enumerable: false, + writable: true, + configurable: true + }); + _this.code = "ERR_ASSERTION"; + _this.actual = actual; + _this.expected = expected; + _this.operator = operator; + if (Error.captureStackTrace) { + Error.captureStackTrace(_assertThisInitialized(_this), stackStartFn); + } + _this.stack; + _this.name = "AssertionError"; + return _possibleConstructorReturn(_this); + } + _createClass(AssertionError2, [{ + key: "toString", + value: function toString() { + return "".concat(this.name, " [").concat(this.code, "]: ").concat(this.message); + } + }, { + key: _inspect$custom, + value: function value(recurseTimes, ctx) { + return inspect(this, _objectSpread(_objectSpread({}, ctx), {}, { + customInspect: false, + depth: 0 + })); + } + }]); + return AssertionError2; + })(/* @__PURE__ */ _wrapNativeSuper(Error), inspect.custom); + module2.exports = AssertionError; + } +}); + +// scripts/node-portable/node_modules/object-keys/isArguments.js +var require_isArguments = __commonJS({ + "scripts/node-portable/node_modules/object-keys/isArguments.js"(exports2, module2) { + "use strict"; + var toStr = Object.prototype.toString; + module2.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === "[object Arguments]"; + if (!isArgs) { + isArgs = str !== "[object Array]" && value !== null && typeof value === "object" && typeof value.length === "number" && value.length >= 0 && toStr.call(value.callee) === "[object Function]"; + } + return isArgs; + }; + } +}); + +// scripts/node-portable/node_modules/object-keys/implementation.js +var require_implementation2 = __commonJS({ + "scripts/node-portable/node_modules/object-keys/implementation.js"(exports2, module2) { + "use strict"; + var keysShim; + if (!Object.keys) { + has = Object.prototype.hasOwnProperty; + toStr = Object.prototype.toString; + isArgs = require_isArguments(); + isEnumerable = Object.prototype.propertyIsEnumerable; + hasDontEnumBug = !isEnumerable.call({ toString: null }, "toString"); + hasProtoEnumBug = isEnumerable.call(function() { + }, "prototype"); + dontEnums = [ + "toString", + "toLocaleString", + "valueOf", + "hasOwnProperty", + "isPrototypeOf", + "propertyIsEnumerable", + "constructor" + ]; + equalsConstructorPrototype = function(o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; + }; + excludedKeys = { + $applicationCache: true, + $console: true, + $external: true, + $frame: true, + $frameElement: true, + $frames: true, + $innerHeight: true, + $innerWidth: true, + $onmozfullscreenchange: true, + $onmozfullscreenerror: true, + $outerHeight: true, + $outerWidth: true, + $pageXOffset: true, + $pageYOffset: true, + $parent: true, + $scrollLeft: true, + $scrollTop: true, + $scrollX: true, + $scrollY: true, + $self: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $window: true + }; + hasAutomationEqualityBug = (function() { + if (typeof window === "undefined") { + return false; + } + for (var k in window) { + try { + if (!excludedKeys["$" + k] && has.call(window, k) && window[k] !== null && typeof window[k] === "object") { + try { + equalsConstructorPrototype(window[k]); + } catch (e) { + return true; + } + } + } catch (e) { + return true; + } + } + return false; + })(); + equalsConstructorPrototypeIfNotBuggy = function(o) { + if (typeof window === "undefined" || !hasAutomationEqualityBug) { + return equalsConstructorPrototype(o); + } + try { + return equalsConstructorPrototype(o); + } catch (e) { + return false; + } + }; + keysShim = function keys(object) { + var isObject = object !== null && typeof object === "object"; + var isFunction = toStr.call(object) === "[object Function]"; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === "[object String]"; + var theKeys = []; + if (!isObject && !isFunction && !isArguments) { + throw new TypeError("Object.keys called on a non-object"); + } + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === "prototype") && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + if (hasDontEnumBug) { + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === "constructor") && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; + }; + } + var has; + var toStr; + var isArgs; + var isEnumerable; + var hasDontEnumBug; + var hasProtoEnumBug; + var dontEnums; + var equalsConstructorPrototype; + var excludedKeys; + var hasAutomationEqualityBug; + var equalsConstructorPrototypeIfNotBuggy; + module2.exports = keysShim; + } +}); + +// scripts/node-portable/node_modules/object-keys/index.js +var require_object_keys = __commonJS({ + "scripts/node-portable/node_modules/object-keys/index.js"(exports2, module2) { + "use strict"; + var slice = Array.prototype.slice; + var isArgs = require_isArguments(); + var origKeys = Object.keys; + var keysShim = origKeys ? function keys(o) { + return origKeys(o); + } : require_implementation2(); + var originalKeys = Object.keys; + keysShim.shim = function shimObjectKeys() { + if (Object.keys) { + var keysWorksWithArguments = (function() { + var args = Object.keys(arguments); + return args && args.length === arguments.length; + })(1, 2); + if (!keysWorksWithArguments) { + Object.keys = function keys(object) { + if (isArgs(object)) { + return originalKeys(slice.call(object)); + } + return originalKeys(object); + }; + } + } else { + Object.keys = keysShim; + } + return Object.keys || keysShim; + }; + module2.exports = keysShim; + } +}); + +// scripts/node-portable/node_modules/object.assign/implementation.js +var require_implementation3 = __commonJS({ + "scripts/node-portable/node_modules/object.assign/implementation.js"(exports2, module2) { + "use strict"; + var objectKeys = require_object_keys(); + var hasSymbols = require_shams()(); + var callBound = require_call_bound(); + var $Object = require_es_object_atoms(); + var $push = callBound("Array.prototype.push"); + var $propIsEnumerable = callBound("Object.prototype.propertyIsEnumerable"); + var originalGetSymbols = hasSymbols ? $Object.getOwnPropertySymbols : null; + module2.exports = function assign(target, source1) { + if (target == null) { + throw new TypeError("target must be an object"); + } + var to = $Object(target); + if (arguments.length === 1) { + return to; + } + for (var s = 1; s < arguments.length; ++s) { + var from = $Object(arguments[s]); + var keys = objectKeys(from); + var getSymbols = hasSymbols && ($Object.getOwnPropertySymbols || originalGetSymbols); + if (getSymbols) { + var syms = getSymbols(from); + for (var j = 0; j < syms.length; ++j) { + var key = syms[j]; + if ($propIsEnumerable(from, key)) { + $push(keys, key); + } + } + } + for (var i = 0; i < keys.length; ++i) { + var nextKey = keys[i]; + if ($propIsEnumerable(from, nextKey)) { + var propValue = from[nextKey]; + to[nextKey] = propValue; + } + } + } + return to; + }; + } +}); + +// scripts/node-portable/node_modules/object.assign/polyfill.js +var require_polyfill = __commonJS({ + "scripts/node-portable/node_modules/object.assign/polyfill.js"(exports2, module2) { + "use strict"; + var implementation = require_implementation3(); + var lacksProperEnumerationOrder = function() { + if (!Object.assign) { + return false; + } + var str = "abcdefghijklmnopqrst"; + var letters = str.split(""); + var map = {}; + for (var i = 0; i < letters.length; ++i) { + map[letters[i]] = letters[i]; + } + var obj = Object.assign({}, map); + var actual = ""; + for (var k in obj) { + actual += k; + } + return str !== actual; + }; + var assignHasPendingExceptions = function() { + if (!Object.assign || !Object.preventExtensions) { + return false; + } + var thrower = Object.preventExtensions({ 1: 2 }); + try { + Object.assign(thrower, "xy"); + } catch (e) { + return thrower[1] === "y"; + } + return false; + }; + module2.exports = function getPolyfill() { + if (!Object.assign) { + return implementation; + } + if (lacksProperEnumerationOrder()) { + return implementation; + } + if (assignHasPendingExceptions()) { + return implementation; + } + return Object.assign; + }; + } +}); + +// scripts/node-portable/node_modules/object-is/implementation.js +var require_implementation4 = __commonJS({ + "scripts/node-portable/node_modules/object-is/implementation.js"(exports2, module2) { + "use strict"; + var numberIsNaN = function(value) { + return value !== value; + }; + module2.exports = function is(a, b) { + if (a === 0 && b === 0) { + return 1 / a === 1 / b; + } + if (a === b) { + return true; + } + if (numberIsNaN(a) && numberIsNaN(b)) { + return true; + } + return false; + }; + } +}); + +// scripts/node-portable/node_modules/object-is/polyfill.js +var require_polyfill2 = __commonJS({ + "scripts/node-portable/node_modules/object-is/polyfill.js"(exports2, module2) { + "use strict"; + var implementation = require_implementation4(); + module2.exports = function getPolyfill() { + return typeof Object.is === "function" ? Object.is : implementation; + }; + } +}); + +// scripts/node-portable/node_modules/call-bind/callBound.js +var require_callBound = __commonJS({ + "scripts/node-portable/node_modules/call-bind/callBound.js"(exports2, module2) { + "use strict"; + var GetIntrinsic = require_get_intrinsic(); + var callBind = require_call_bind(); + var $indexOf = callBind(GetIntrinsic("String.prototype.indexOf")); + module2.exports = function callBoundIntrinsic(name, allowMissing) { + var intrinsic = GetIntrinsic(name, !!allowMissing); + if (typeof intrinsic === "function" && $indexOf(name, ".prototype.") > -1) { + return callBind(intrinsic); + } + return intrinsic; + }; + } +}); + +// scripts/node-portable/node_modules/define-properties/index.js +var require_define_properties = __commonJS({ + "scripts/node-portable/node_modules/define-properties/index.js"(exports2, module2) { + "use strict"; + var keys = require_object_keys(); + var hasSymbols = typeof Symbol === "function" && typeof Symbol("foo") === "symbol"; + var toStr = Object.prototype.toString; + var concat = Array.prototype.concat; + var defineDataProperty = require_define_data_property(); + var isFunction = function(fn) { + return typeof fn === "function" && toStr.call(fn) === "[object Function]"; + }; + var supportsDescriptors = require_has_property_descriptors()(); + var defineProperty = function(object, name, value, predicate) { + if (name in object) { + if (predicate === true) { + if (object[name] === value) { + return; + } + } else if (!isFunction(predicate) || !predicate()) { + return; + } + } + if (supportsDescriptors) { + defineDataProperty(object, name, value, true); + } else { + defineDataProperty(object, name, value); + } + }; + var defineProperties = function(object, map) { + var predicates = arguments.length > 2 ? arguments[2] : {}; + var props = keys(map); + if (hasSymbols) { + props = concat.call(props, Object.getOwnPropertySymbols(map)); + } + for (var i = 0; i < props.length; i += 1) { + defineProperty(object, props[i], map[props[i]], predicates[props[i]]); + } + }; + defineProperties.supportsDescriptors = !!supportsDescriptors; + module2.exports = defineProperties; + } +}); + +// scripts/node-portable/node_modules/object-is/shim.js +var require_shim = __commonJS({ + "scripts/node-portable/node_modules/object-is/shim.js"(exports2, module2) { + "use strict"; + var getPolyfill = require_polyfill2(); + var define = require_define_properties(); + module2.exports = function shimObjectIs() { + var polyfill = getPolyfill(); + define(Object, { is: polyfill }, { + is: function testObjectIs() { + return Object.is !== polyfill; + } + }); + return polyfill; + }; + } +}); + +// scripts/node-portable/node_modules/object-is/index.js +var require_object_is = __commonJS({ + "scripts/node-portable/node_modules/object-is/index.js"(exports2, module2) { + "use strict"; + var define = require_define_properties(); + var callBind = require_call_bind(); + var implementation = require_implementation4(); + var getPolyfill = require_polyfill2(); + var shim = require_shim(); + var polyfill = callBind(getPolyfill(), Object); + define(polyfill, { + getPolyfill, + implementation, + shim + }); + module2.exports = polyfill; + } +}); + +// scripts/node-portable/node_modules/is-nan/implementation.js +var require_implementation5 = __commonJS({ + "scripts/node-portable/node_modules/is-nan/implementation.js"(exports2, module2) { + "use strict"; + module2.exports = function isNaN2(value) { + return value !== value; + }; + } +}); + +// scripts/node-portable/node_modules/is-nan/polyfill.js +var require_polyfill3 = __commonJS({ + "scripts/node-portable/node_modules/is-nan/polyfill.js"(exports2, module2) { + "use strict"; + var implementation = require_implementation5(); + module2.exports = function getPolyfill() { + if (Number.isNaN && Number.isNaN(NaN) && !Number.isNaN("a")) { + return Number.isNaN; + } + return implementation; + }; + } +}); + +// scripts/node-portable/node_modules/is-nan/shim.js +var require_shim2 = __commonJS({ + "scripts/node-portable/node_modules/is-nan/shim.js"(exports2, module2) { + "use strict"; + var define = require_define_properties(); + var getPolyfill = require_polyfill3(); + module2.exports = function shimNumberIsNaN() { + var polyfill = getPolyfill(); + define(Number, { isNaN: polyfill }, { + isNaN: function testIsNaN() { + return Number.isNaN !== polyfill; + } + }); + return polyfill; + }; + } +}); + +// scripts/node-portable/node_modules/is-nan/index.js +var require_is_nan = __commonJS({ + "scripts/node-portable/node_modules/is-nan/index.js"(exports2, module2) { + "use strict"; + var callBind = require_call_bind(); + var define = require_define_properties(); + var implementation = require_implementation5(); + var getPolyfill = require_polyfill3(); + var shim = require_shim2(); + var polyfill = callBind(getPolyfill(), Number); + define(polyfill, { + getPolyfill, + implementation, + shim + }); + module2.exports = polyfill; + } +}); + +// scripts/node-portable/node_modules/assert/build/internal/util/comparisons.js +var require_comparisons = __commonJS({ + "scripts/node-portable/node_modules/assert/build/internal/util/comparisons.js"(exports2, module2) { + "use strict"; + function _slicedToArray(arr, i) { + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); + } + function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _unsupportedIterableToArray(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); + } + function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + return arr2; + } + function _iterableToArrayLimit(r, l) { + var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; + if (null != t) { + var e, n, i, u, a = [], f = true, o = false; + try { + if (i = (t = t.call(r)).next, 0 === l) { + if (Object(t) !== t) return; + f = false; + } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = true) ; + } catch (r2) { + o = true, n = r2; + } finally { + try { + if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; + } finally { + if (o) throw n; + } + } + return a; + } + } + function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; + } + function _typeof(o) { + "@babel/helpers - typeof"; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof(o); + } + var regexFlagsSupported = /a/g.flags !== void 0; + var arrayFromSet = function arrayFromSet2(set) { + var array = []; + set.forEach(function(value) { + return array.push(value); + }); + return array; + }; + var arrayFromMap = function arrayFromMap2(map) { + var array = []; + map.forEach(function(value, key) { + return array.push([key, value]); + }); + return array; + }; + var objectIs = Object.is ? Object.is : require_object_is(); + var objectGetOwnPropertySymbols = Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols : function() { + return []; + }; + var numberIsNaN = Number.isNaN ? Number.isNaN : require_is_nan(); + function uncurryThis(f) { + return f.call.bind(f); + } + var hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty); + var propertyIsEnumerable = uncurryThis(Object.prototype.propertyIsEnumerable); + var objectToString = uncurryThis(Object.prototype.toString); + var _require$types = require_util().types; + var isAnyArrayBuffer = _require$types.isAnyArrayBuffer; + var isArrayBufferView = _require$types.isArrayBufferView; + var isDate = _require$types.isDate; + var isMap = _require$types.isMap; + var isRegExp = _require$types.isRegExp; + var isSet = _require$types.isSet; + var isNativeError = _require$types.isNativeError; + var isBoxedPrimitive = _require$types.isBoxedPrimitive; + var isNumberObject = _require$types.isNumberObject; + var isStringObject = _require$types.isStringObject; + var isBooleanObject = _require$types.isBooleanObject; + var isBigIntObject = _require$types.isBigIntObject; + var isSymbolObject = _require$types.isSymbolObject; + var isFloat32Array = _require$types.isFloat32Array; + var isFloat64Array = _require$types.isFloat64Array; + function isNonIndex(key) { + if (key.length === 0 || key.length > 10) return true; + for (var i = 0; i < key.length; i++) { + var code = key.charCodeAt(i); + if (code < 48 || code > 57) return true; + } + return key.length === 10 && key >= Math.pow(2, 32); + } + function getOwnNonIndexProperties(value) { + return Object.keys(value).filter(isNonIndex).concat(objectGetOwnPropertySymbols(value).filter(Object.prototype.propertyIsEnumerable.bind(value))); + } + /*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ + function compare(a, b) { + if (a === b) { + return 0; + } + var x = a.length; + var y = b.length; + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break; + } + } + if (x < y) { + return -1; + } + if (y < x) { + return 1; + } + return 0; + } + var ONLY_ENUMERABLE = void 0; + var kStrict = true; + var kLoose = false; + var kNoIterator = 0; + var kIsArray = 1; + var kIsSet = 2; + var kIsMap = 3; + function areSimilarRegExps(a, b) { + return regexFlagsSupported ? a.source === b.source && a.flags === b.flags : RegExp.prototype.toString.call(a) === RegExp.prototype.toString.call(b); + } + function areSimilarFloatArrays(a, b) { + if (a.byteLength !== b.byteLength) { + return false; + } + for (var offset = 0; offset < a.byteLength; offset++) { + if (a[offset] !== b[offset]) { + return false; + } + } + return true; + } + function areSimilarTypedArrays(a, b) { + if (a.byteLength !== b.byteLength) { + return false; + } + return compare(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength)) === 0; + } + function areEqualArrayBuffers(buf1, buf2) { + return buf1.byteLength === buf2.byteLength && compare(new Uint8Array(buf1), new Uint8Array(buf2)) === 0; + } + function isEqualBoxedPrimitive(val1, val2) { + if (isNumberObject(val1)) { + return isNumberObject(val2) && objectIs(Number.prototype.valueOf.call(val1), Number.prototype.valueOf.call(val2)); + } + if (isStringObject(val1)) { + return isStringObject(val2) && String.prototype.valueOf.call(val1) === String.prototype.valueOf.call(val2); + } + if (isBooleanObject(val1)) { + return isBooleanObject(val2) && Boolean.prototype.valueOf.call(val1) === Boolean.prototype.valueOf.call(val2); + } + if (isBigIntObject(val1)) { + return isBigIntObject(val2) && BigInt.prototype.valueOf.call(val1) === BigInt.prototype.valueOf.call(val2); + } + return isSymbolObject(val2) && Symbol.prototype.valueOf.call(val1) === Symbol.prototype.valueOf.call(val2); + } + function innerDeepEqual(val1, val2, strict, memos) { + if (val1 === val2) { + if (val1 !== 0) return true; + return strict ? objectIs(val1, val2) : true; + } + if (strict) { + if (_typeof(val1) !== "object") { + return typeof val1 === "number" && numberIsNaN(val1) && numberIsNaN(val2); + } + if (_typeof(val2) !== "object" || val1 === null || val2 === null) { + return false; + } + if (Object.getPrototypeOf(val1) !== Object.getPrototypeOf(val2)) { + return false; + } + } else { + if (val1 === null || _typeof(val1) !== "object") { + if (val2 === null || _typeof(val2) !== "object") { + return val1 == val2; + } + return false; + } + if (val2 === null || _typeof(val2) !== "object") { + return false; + } + } + var val1Tag = objectToString(val1); + var val2Tag = objectToString(val2); + if (val1Tag !== val2Tag) { + return false; + } + if (Array.isArray(val1)) { + if (val1.length !== val2.length) { + return false; + } + var keys1 = getOwnNonIndexProperties(val1, ONLY_ENUMERABLE); + var keys2 = getOwnNonIndexProperties(val2, ONLY_ENUMERABLE); + if (keys1.length !== keys2.length) { + return false; + } + return keyCheck(val1, val2, strict, memos, kIsArray, keys1); + } + if (val1Tag === "[object Object]") { + if (!isMap(val1) && isMap(val2) || !isSet(val1) && isSet(val2)) { + return false; + } + } + if (isDate(val1)) { + if (!isDate(val2) || Date.prototype.getTime.call(val1) !== Date.prototype.getTime.call(val2)) { + return false; + } + } else if (isRegExp(val1)) { + if (!isRegExp(val2) || !areSimilarRegExps(val1, val2)) { + return false; + } + } else if (isNativeError(val1) || val1 instanceof Error) { + if (val1.message !== val2.message || val1.name !== val2.name) { + return false; + } + } else if (isArrayBufferView(val1)) { + if (!strict && (isFloat32Array(val1) || isFloat64Array(val1))) { + if (!areSimilarFloatArrays(val1, val2)) { + return false; + } + } else if (!areSimilarTypedArrays(val1, val2)) { + return false; + } + var _keys = getOwnNonIndexProperties(val1, ONLY_ENUMERABLE); + var _keys2 = getOwnNonIndexProperties(val2, ONLY_ENUMERABLE); + if (_keys.length !== _keys2.length) { + return false; + } + return keyCheck(val1, val2, strict, memos, kNoIterator, _keys); + } else if (isSet(val1)) { + if (!isSet(val2) || val1.size !== val2.size) { + return false; + } + return keyCheck(val1, val2, strict, memos, kIsSet); + } else if (isMap(val1)) { + if (!isMap(val2) || val1.size !== val2.size) { + return false; + } + return keyCheck(val1, val2, strict, memos, kIsMap); + } else if (isAnyArrayBuffer(val1)) { + if (!areEqualArrayBuffers(val1, val2)) { + return false; + } + } else if (isBoxedPrimitive(val1) && !isEqualBoxedPrimitive(val1, val2)) { + return false; + } + return keyCheck(val1, val2, strict, memos, kNoIterator); + } + function getEnumerables(val, keys) { + return keys.filter(function(k) { + return propertyIsEnumerable(val, k); + }); + } + function keyCheck(val1, val2, strict, memos, iterationType, aKeys) { + if (arguments.length === 5) { + aKeys = Object.keys(val1); + var bKeys = Object.keys(val2); + if (aKeys.length !== bKeys.length) { + return false; + } + } + var i = 0; + for (; i < aKeys.length; i++) { + if (!hasOwnProperty(val2, aKeys[i])) { + return false; + } + } + if (strict && arguments.length === 5) { + var symbolKeysA = objectGetOwnPropertySymbols(val1); + if (symbolKeysA.length !== 0) { + var count = 0; + for (i = 0; i < symbolKeysA.length; i++) { + var key = symbolKeysA[i]; + if (propertyIsEnumerable(val1, key)) { + if (!propertyIsEnumerable(val2, key)) { + return false; + } + aKeys.push(key); + count++; + } else if (propertyIsEnumerable(val2, key)) { + return false; + } + } + var symbolKeysB = objectGetOwnPropertySymbols(val2); + if (symbolKeysA.length !== symbolKeysB.length && getEnumerables(val2, symbolKeysB).length !== count) { + return false; + } + } else { + var _symbolKeysB = objectGetOwnPropertySymbols(val2); + if (_symbolKeysB.length !== 0 && getEnumerables(val2, _symbolKeysB).length !== 0) { + return false; + } + } + } + if (aKeys.length === 0 && (iterationType === kNoIterator || iterationType === kIsArray && val1.length === 0 || val1.size === 0)) { + return true; + } + if (memos === void 0) { + memos = { + val1: /* @__PURE__ */ new Map(), + val2: /* @__PURE__ */ new Map(), + position: 0 + }; + } else { + var val2MemoA = memos.val1.get(val1); + if (val2MemoA !== void 0) { + var val2MemoB = memos.val2.get(val2); + if (val2MemoB !== void 0) { + return val2MemoA === val2MemoB; + } + } + memos.position++; + } + memos.val1.set(val1, memos.position); + memos.val2.set(val2, memos.position); + var areEq = objEquiv(val1, val2, strict, aKeys, memos, iterationType); + memos.val1.delete(val1); + memos.val2.delete(val2); + return areEq; + } + function setHasEqualElement(set, val1, strict, memo) { + var setValues = arrayFromSet(set); + for (var i = 0; i < setValues.length; i++) { + var val2 = setValues[i]; + if (innerDeepEqual(val1, val2, strict, memo)) { + set.delete(val2); + return true; + } + } + return false; + } + function findLooseMatchingPrimitives(prim) { + switch (_typeof(prim)) { + case "undefined": + return null; + case "object": + return void 0; + case "symbol": + return false; + case "string": + prim = +prim; + // Loose equal entries exist only if the string is possible to convert to + // a regular number and not NaN. + // Fall through + case "number": + if (numberIsNaN(prim)) { + return false; + } + } + return true; + } + function setMightHaveLoosePrim(a, b, prim) { + var altValue = findLooseMatchingPrimitives(prim); + if (altValue != null) return altValue; + return b.has(altValue) && !a.has(altValue); + } + function mapMightHaveLoosePrim(a, b, prim, item, memo) { + var altValue = findLooseMatchingPrimitives(prim); + if (altValue != null) { + return altValue; + } + var curB = b.get(altValue); + if (curB === void 0 && !b.has(altValue) || !innerDeepEqual(item, curB, false, memo)) { + return false; + } + return !a.has(altValue) && innerDeepEqual(item, curB, false, memo); + } + function setEquiv(a, b, strict, memo) { + var set = null; + var aValues = arrayFromSet(a); + for (var i = 0; i < aValues.length; i++) { + var val = aValues[i]; + if (_typeof(val) === "object" && val !== null) { + if (set === null) { + set = /* @__PURE__ */ new Set(); + } + set.add(val); + } else if (!b.has(val)) { + if (strict) return false; + if (!setMightHaveLoosePrim(a, b, val)) { + return false; + } + if (set === null) { + set = /* @__PURE__ */ new Set(); + } + set.add(val); + } + } + if (set !== null) { + var bValues = arrayFromSet(b); + for (var _i = 0; _i < bValues.length; _i++) { + var _val = bValues[_i]; + if (_typeof(_val) === "object" && _val !== null) { + if (!setHasEqualElement(set, _val, strict, memo)) return false; + } else if (!strict && !a.has(_val) && !setHasEqualElement(set, _val, strict, memo)) { + return false; + } + } + return set.size === 0; + } + return true; + } + function mapHasEqualEntry(set, map, key1, item1, strict, memo) { + var setValues = arrayFromSet(set); + for (var i = 0; i < setValues.length; i++) { + var key2 = setValues[i]; + if (innerDeepEqual(key1, key2, strict, memo) && innerDeepEqual(item1, map.get(key2), strict, memo)) { + set.delete(key2); + return true; + } + } + return false; + } + function mapEquiv(a, b, strict, memo) { + var set = null; + var aEntries = arrayFromMap(a); + for (var i = 0; i < aEntries.length; i++) { + var _aEntries$i = _slicedToArray(aEntries[i], 2), key = _aEntries$i[0], item1 = _aEntries$i[1]; + if (_typeof(key) === "object" && key !== null) { + if (set === null) { + set = /* @__PURE__ */ new Set(); + } + set.add(key); + } else { + var item2 = b.get(key); + if (item2 === void 0 && !b.has(key) || !innerDeepEqual(item1, item2, strict, memo)) { + if (strict) return false; + if (!mapMightHaveLoosePrim(a, b, key, item1, memo)) return false; + if (set === null) { + set = /* @__PURE__ */ new Set(); + } + set.add(key); + } + } + } + if (set !== null) { + var bEntries = arrayFromMap(b); + for (var _i2 = 0; _i2 < bEntries.length; _i2++) { + var _bEntries$_i = _slicedToArray(bEntries[_i2], 2), _key = _bEntries$_i[0], item = _bEntries$_i[1]; + if (_typeof(_key) === "object" && _key !== null) { + if (!mapHasEqualEntry(set, a, _key, item, strict, memo)) return false; + } else if (!strict && (!a.has(_key) || !innerDeepEqual(a.get(_key), item, false, memo)) && !mapHasEqualEntry(set, a, _key, item, false, memo)) { + return false; + } + } + return set.size === 0; + } + return true; + } + function objEquiv(a, b, strict, keys, memos, iterationType) { + var i = 0; + if (iterationType === kIsSet) { + if (!setEquiv(a, b, strict, memos)) { + return false; + } + } else if (iterationType === kIsMap) { + if (!mapEquiv(a, b, strict, memos)) { + return false; + } + } else if (iterationType === kIsArray) { + for (; i < a.length; i++) { + if (hasOwnProperty(a, i)) { + if (!hasOwnProperty(b, i) || !innerDeepEqual(a[i], b[i], strict, memos)) { + return false; + } + } else if (hasOwnProperty(b, i)) { + return false; + } else { + var keysA = Object.keys(a); + for (; i < keysA.length; i++) { + var key = keysA[i]; + if (!hasOwnProperty(b, key) || !innerDeepEqual(a[key], b[key], strict, memos)) { + return false; + } + } + if (keysA.length !== Object.keys(b).length) { + return false; + } + return true; + } + } + } + for (i = 0; i < keys.length; i++) { + var _key2 = keys[i]; + if (!innerDeepEqual(a[_key2], b[_key2], strict, memos)) { + return false; + } + } + return true; + } + function isDeepEqual(val1, val2) { + return innerDeepEqual(val1, val2, kLoose); + } + function isDeepStrictEqual(val1, val2) { + return innerDeepEqual(val1, val2, kStrict); + } + module2.exports = { + isDeepEqual, + isDeepStrictEqual + }; + } +}); + +// scripts/node-portable/node_modules/assert/build/assert.js +var require_assert = __commonJS({ + "scripts/node-portable/node_modules/assert/build/assert.js"(exports2, module2) { + "use strict"; + function _typeof(o) { + "@babel/helpers - typeof"; + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) { + return typeof o2; + } : function(o2) { + return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2; + }, _typeof(o); + } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); + } + } + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { writable: false }); + return Constructor; + } + function _toPropertyKey(arg) { + var key = _toPrimitive(arg, "string"); + return _typeof(key) === "symbol" ? key : String(key); + } + function _toPrimitive(input, hint) { + if (_typeof(input) !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== void 0) { + var res = prim.call(input, hint || "default"); + if (_typeof(res) !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + var _require = require_errors(); + var _require$codes = _require.codes; + var ERR_AMBIGUOUS_ARGUMENT = _require$codes.ERR_AMBIGUOUS_ARGUMENT; + var ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE; + var ERR_INVALID_ARG_VALUE = _require$codes.ERR_INVALID_ARG_VALUE; + var ERR_INVALID_RETURN_VALUE = _require$codes.ERR_INVALID_RETURN_VALUE; + var ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS; + var AssertionError = require_assertion_error(); + var _require2 = require_util(); + var inspect = _require2.inspect; + var _require$types = require_util().types; + var isPromise = _require$types.isPromise; + var isRegExp = _require$types.isRegExp; + var objectAssign = require_polyfill()(); + var objectIs = require_polyfill2()(); + var RegExpPrototypeTest = require_callBound()("RegExp.prototype.test"); + var isDeepEqual; + var isDeepStrictEqual; + function lazyLoadComparison() { + var comparison = require_comparisons(); + isDeepEqual = comparison.isDeepEqual; + isDeepStrictEqual = comparison.isDeepStrictEqual; + } + var warned = false; + var assert = module2.exports = ok; + var NO_EXCEPTION_SENTINEL = {}; + function innerFail(obj) { + if (obj.message instanceof Error) throw obj.message; + throw new AssertionError(obj); + } + function fail(actual, expected, message, operator, stackStartFn) { + var argsLen = arguments.length; + var internalMessage; + if (argsLen === 0) { + internalMessage = "Failed"; + } else if (argsLen === 1) { + message = actual; + actual = void 0; + } else { + if (warned === false) { + warned = true; + var warn = process.emitWarning ? process.emitWarning : console.warn.bind(console); + warn("assert.fail() with more than one argument is deprecated. Please use assert.strictEqual() instead or only pass a message.", "DeprecationWarning", "DEP0094"); + } + if (argsLen === 2) operator = "!="; + } + if (message instanceof Error) throw message; + var errArgs = { + actual, + expected, + operator: operator === void 0 ? "fail" : operator, + stackStartFn: stackStartFn || fail + }; + if (message !== void 0) { + errArgs.message = message; + } + var err = new AssertionError(errArgs); + if (internalMessage) { + err.message = internalMessage; + err.generatedMessage = true; + } + throw err; + } + assert.fail = fail; + assert.AssertionError = AssertionError; + function innerOk(fn, argLen, value, message) { + if (!value) { + var generatedMessage = false; + if (argLen === 0) { + generatedMessage = true; + message = "No value argument passed to `assert.ok()`"; + } else if (message instanceof Error) { + throw message; + } + var err = new AssertionError({ + actual: value, + expected: true, + message, + operator: "==", + stackStartFn: fn + }); + err.generatedMessage = generatedMessage; + throw err; + } + } + function ok() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + innerOk.apply(void 0, [ok, args.length].concat(args)); + } + assert.ok = ok; + assert.equal = function equal(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS("actual", "expected"); + } + if (actual != expected) { + innerFail({ + actual, + expected, + message, + operator: "==", + stackStartFn: equal + }); + } + }; + assert.notEqual = function notEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS("actual", "expected"); + } + if (actual == expected) { + innerFail({ + actual, + expected, + message, + operator: "!=", + stackStartFn: notEqual + }); + } + }; + assert.deepEqual = function deepEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS("actual", "expected"); + } + if (isDeepEqual === void 0) lazyLoadComparison(); + if (!isDeepEqual(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: "deepEqual", + stackStartFn: deepEqual + }); + } + }; + assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS("actual", "expected"); + } + if (isDeepEqual === void 0) lazyLoadComparison(); + if (isDeepEqual(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: "notDeepEqual", + stackStartFn: notDeepEqual + }); + } + }; + assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS("actual", "expected"); + } + if (isDeepEqual === void 0) lazyLoadComparison(); + if (!isDeepStrictEqual(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: "deepStrictEqual", + stackStartFn: deepStrictEqual + }); + } + }; + assert.notDeepStrictEqual = notDeepStrictEqual; + function notDeepStrictEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS("actual", "expected"); + } + if (isDeepEqual === void 0) lazyLoadComparison(); + if (isDeepStrictEqual(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: "notDeepStrictEqual", + stackStartFn: notDeepStrictEqual + }); + } + } + assert.strictEqual = function strictEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS("actual", "expected"); + } + if (!objectIs(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: "strictEqual", + stackStartFn: strictEqual + }); + } + }; + assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS("actual", "expected"); + } + if (objectIs(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: "notStrictEqual", + stackStartFn: notStrictEqual + }); + } + }; + var Comparison = /* @__PURE__ */ _createClass(function Comparison2(obj, keys, actual) { + var _this = this; + _classCallCheck(this, Comparison2); + keys.forEach(function(key) { + if (key in obj) { + if (actual !== void 0 && typeof actual[key] === "string" && isRegExp(obj[key]) && RegExpPrototypeTest(obj[key], actual[key])) { + _this[key] = actual[key]; + } else { + _this[key] = obj[key]; + } + } + }); + }); + function compareExceptionKey(actual, expected, key, message, keys, fn) { + if (!(key in actual) || !isDeepStrictEqual(actual[key], expected[key])) { + if (!message) { + var a = new Comparison(actual, keys); + var b = new Comparison(expected, keys, actual); + var err = new AssertionError({ + actual: a, + expected: b, + operator: "deepStrictEqual", + stackStartFn: fn + }); + err.actual = actual; + err.expected = expected; + err.operator = fn.name; + throw err; + } + innerFail({ + actual, + expected, + message, + operator: fn.name, + stackStartFn: fn + }); + } + } + function expectedException(actual, expected, msg, fn) { + if (typeof expected !== "function") { + if (isRegExp(expected)) return RegExpPrototypeTest(expected, actual); + if (arguments.length === 2) { + throw new ERR_INVALID_ARG_TYPE("expected", ["Function", "RegExp"], expected); + } + if (_typeof(actual) !== "object" || actual === null) { + var err = new AssertionError({ + actual, + expected, + message: msg, + operator: "deepStrictEqual", + stackStartFn: fn + }); + err.operator = fn.name; + throw err; + } + var keys = Object.keys(expected); + if (expected instanceof Error) { + keys.push("name", "message"); + } else if (keys.length === 0) { + throw new ERR_INVALID_ARG_VALUE("error", expected, "may not be an empty object"); + } + if (isDeepEqual === void 0) lazyLoadComparison(); + keys.forEach(function(key) { + if (typeof actual[key] === "string" && isRegExp(expected[key]) && RegExpPrototypeTest(expected[key], actual[key])) { + return; + } + compareExceptionKey(actual, expected, key, msg, keys, fn); + }); + return true; + } + if (expected.prototype !== void 0 && actual instanceof expected) { + return true; + } + if (Error.isPrototypeOf(expected)) { + return false; + } + return expected.call({}, actual) === true; + } + function getActual(fn) { + if (typeof fn !== "function") { + throw new ERR_INVALID_ARG_TYPE("fn", "Function", fn); + } + try { + fn(); + } catch (e) { + return e; + } + return NO_EXCEPTION_SENTINEL; + } + function checkIsPromise(obj) { + return isPromise(obj) || obj !== null && _typeof(obj) === "object" && typeof obj.then === "function" && typeof obj.catch === "function"; + } + function waitForActual(promiseFn) { + return Promise.resolve().then(function() { + var resultPromise; + if (typeof promiseFn === "function") { + resultPromise = promiseFn(); + if (!checkIsPromise(resultPromise)) { + throw new ERR_INVALID_RETURN_VALUE("instance of Promise", "promiseFn", resultPromise); + } + } else if (checkIsPromise(promiseFn)) { + resultPromise = promiseFn; + } else { + throw new ERR_INVALID_ARG_TYPE("promiseFn", ["Function", "Promise"], promiseFn); + } + return Promise.resolve().then(function() { + return resultPromise; + }).then(function() { + return NO_EXCEPTION_SENTINEL; + }).catch(function(e) { + return e; + }); + }); + } + function expectsError(stackStartFn, actual, error, message) { + if (typeof error === "string") { + if (arguments.length === 4) { + throw new ERR_INVALID_ARG_TYPE("error", ["Object", "Error", "Function", "RegExp"], error); + } + if (_typeof(actual) === "object" && actual !== null) { + if (actual.message === error) { + throw new ERR_AMBIGUOUS_ARGUMENT("error/message", 'The error message "'.concat(actual.message, '" is identical to the message.')); + } + } else if (actual === error) { + throw new ERR_AMBIGUOUS_ARGUMENT("error/message", 'The error "'.concat(actual, '" is identical to the message.')); + } + message = error; + error = void 0; + } else if (error != null && _typeof(error) !== "object" && typeof error !== "function") { + throw new ERR_INVALID_ARG_TYPE("error", ["Object", "Error", "Function", "RegExp"], error); + } + if (actual === NO_EXCEPTION_SENTINEL) { + var details = ""; + if (error && error.name) { + details += " (".concat(error.name, ")"); + } + details += message ? ": ".concat(message) : "."; + var fnType = stackStartFn.name === "rejects" ? "rejection" : "exception"; + innerFail({ + actual: void 0, + expected: error, + operator: stackStartFn.name, + message: "Missing expected ".concat(fnType).concat(details), + stackStartFn + }); + } + if (error && !expectedException(actual, error, message, stackStartFn)) { + throw actual; + } + } + function expectsNoError(stackStartFn, actual, error, message) { + if (actual === NO_EXCEPTION_SENTINEL) return; + if (typeof error === "string") { + message = error; + error = void 0; + } + if (!error || expectedException(actual, error)) { + var details = message ? ": ".concat(message) : "."; + var fnType = stackStartFn.name === "doesNotReject" ? "rejection" : "exception"; + innerFail({ + actual, + expected: error, + operator: stackStartFn.name, + message: "Got unwanted ".concat(fnType).concat(details, "\n") + 'Actual message: "'.concat(actual && actual.message, '"'), + stackStartFn + }); + } + throw actual; + } + assert.throws = function throws(promiseFn) { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + expectsError.apply(void 0, [throws, getActual(promiseFn)].concat(args)); + }; + assert.rejects = function rejects(promiseFn) { + for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { + args[_key3 - 1] = arguments[_key3]; + } + return waitForActual(promiseFn).then(function(result) { + return expectsError.apply(void 0, [rejects, result].concat(args)); + }); + }; + assert.doesNotThrow = function doesNotThrow(fn) { + for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) { + args[_key4 - 1] = arguments[_key4]; + } + expectsNoError.apply(void 0, [doesNotThrow, getActual(fn)].concat(args)); + }; + assert.doesNotReject = function doesNotReject(fn) { + for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) { + args[_key5 - 1] = arguments[_key5]; + } + return waitForActual(fn).then(function(result) { + return expectsNoError.apply(void 0, [doesNotReject, result].concat(args)); + }); + }; + assert.ifError = function ifError(err) { + if (err !== null && err !== void 0) { + var message = "ifError got unwanted exception: "; + if (_typeof(err) === "object" && typeof err.message === "string") { + if (err.message.length === 0 && err.constructor) { + message += err.constructor.name; + } else { + message += err.message; + } + } else { + message += inspect(err); + } + var newErr = new AssertionError({ + actual: err, + expected: null, + operator: "ifError", + message, + stackStartFn: ifError + }); + var origStack = err.stack; + if (typeof origStack === "string") { + var tmp2 = origStack.split("\n"); + tmp2.shift(); + var tmp1 = newErr.stack.split("\n"); + for (var i = 0; i < tmp2.length; i++) { + var pos = tmp1.indexOf(tmp2[i]); + if (pos !== -1) { + tmp1 = tmp1.slice(0, pos); + break; + } + } + newErr.stack = "".concat(tmp1.join("\n"), "\n").concat(tmp2.join("\n")); + } + throw newErr; + } + }; + function internalMatch(string, regexp, message, fn, fnName) { + if (!isRegExp(regexp)) { + throw new ERR_INVALID_ARG_TYPE("regexp", "RegExp", regexp); + } + var match = fnName === "match"; + if (typeof string !== "string" || RegExpPrototypeTest(regexp, string) !== match) { + if (message instanceof Error) { + throw message; + } + var generatedMessage = !message; + message = message || (typeof string !== "string" ? 'The "string" argument must be of type string. Received type ' + "".concat(_typeof(string), " (").concat(inspect(string), ")") : (match ? "The input did not match the regular expression " : "The input was expected to not match the regular expression ") + "".concat(inspect(regexp), ". Input:\n\n").concat(inspect(string), "\n")); + var err = new AssertionError({ + actual: string, + expected: regexp, + message, + operator: fnName, + stackStartFn: fn + }); + err.generatedMessage = generatedMessage; + throw err; + } + } + assert.match = function match(string, regexp, message) { + internalMatch(string, regexp, message, match, "match"); + }; + assert.doesNotMatch = function doesNotMatch(string, regexp, message) { + internalMatch(string, regexp, message, doesNotMatch, "doesNotMatch"); + }; + function strict() { + for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { + args[_key6] = arguments[_key6]; + } + innerOk.apply(void 0, [strict, args.length].concat(args)); + } + assert.strict = objectAssign(strict, assert, { + equal: assert.strictEqual, + deepEqual: assert.deepStrictEqual, + notEqual: assert.notStrictEqual, + notDeepEqual: assert.notDeepStrictEqual + }); + assert.strict.strict = assert.strict; + } +}); + +// scripts/node-portable/.entry-assert.cjs +module.exports = require_assert(); diff --git a/src/Node/Lib/async_hooks.cjs b/src/Node/Lib/async_hooks.cjs new file mode 100644 index 00000000..f6b3e3ba --- /dev/null +++ b/src/Node/Lib/async_hooks.cjs @@ -0,0 +1,89 @@ +'use strict'; + +const host = __phasisNodeHost; +let sequence = 1; +let activeId = 1; +let triggerId = 0; +const hooks = new Set(); + +class AsyncLocalStorage { + constructor(options = {}) { + this._key = {}; + this._defaultValue = options.defaultValue; + this._name = options.name || ''; + } + get name() { return this._name; } + getStore() { + return host.contextHas(this._key) ? host.contextGet(this._key) : this._defaultValue; + } + run(store, callback, ...args) { + return host.contextRun(this._key, store, callback, ...args); + } + exit(callback, ...args) { return this.run(undefined, callback, ...args); } + enterWith(store) { host.contextSet(this._key, store); } + disable() { + host.contextDelete(this._key); + this._key = {}; + } + static bind(callback) { + const snapshot = host.contextCapture(); + return function (...args) { return host.contextRunSnapshot(snapshot, callback, this, ...args); }; + } + static snapshot() { + const snapshot = host.contextCapture(); + return (callback, ...args) => host.contextRunSnapshot(snapshot, callback, undefined, ...args); + } +} + +function invokeHook(name, ...args) { + for (const hook of hooks) { + if (typeof hook[name] === 'function') hook[name](...args); + } +} + +class AsyncResource { + constructor(type, options = {}) { + if (typeof type !== 'string') throw new TypeError('The type argument must be a string'); + if (typeof options === 'number') options = { triggerAsyncId: options }; + this._id = ++sequence; + this._trigger = options.triggerAsyncId === undefined ? activeId : options.triggerAsyncId; + this._snapshot = host.contextCapture(); + this._destroyed = false; + invokeHook('init', this._id, type, this._trigger, this); + } + asyncId() { return this._id; } + triggerAsyncId() { return this._trigger; } + runInAsyncScope(callback, thisArg, ...args) { + const previousId = activeId; + const previousTrigger = triggerId; + activeId = this._id; + triggerId = this._trigger; + invokeHook('before', this._id); + try { return host.contextRunSnapshot(this._snapshot, callback, thisArg, ...args); } + finally { + invokeHook('after', this._id); + activeId = previousId; + triggerId = previousTrigger; + } + } + emitDestroy() { + if (!this._destroyed) { this._destroyed = true; invokeHook('destroy', this._id); } + return this; + } + bind(callback, thisArg) { + const resource = this; + return function (...args) { return resource.runInAsyncScope(callback, thisArg === undefined ? this : thisArg, ...args); }; + } + static bind(callback, type = callback.name || 'bound-anonymous-fn', thisArg) { + return new AsyncResource(type).bind(callback, thisArg); + } +} + +module.exports = { + AsyncLocalStorage, AsyncResource, + executionAsyncId: () => activeId, + triggerAsyncId: () => triggerId, + createHook(callbacks) { + return { enable() { hooks.add(callbacks); return this; }, disable() { hooks.delete(callbacks); return this; } }; + }, +}; diff --git a/src/Node/Lib/broadcast_channel.cjs b/src/Node/Lib/broadcast_channel.cjs new file mode 100644 index 00000000..a3ff2068 --- /dev/null +++ b/src/Node/Lib/broadcast_channel.cjs @@ -0,0 +1,92 @@ +'use strict'; + +const channels = new Set(); +const states = new WeakMap(); +const addListener = EventTarget.prototype.addEventListener; +const removeListener = EventTarget.prototype.removeEventListener; +const dispatch = EventTarget.prototype.dispatchEvent; +const clone = structuredClone; +const schedule = setTimeout; +const cancel = clearTimeout; + +function stateOf(channel) { + const state = states.get(channel); + if (!state) throw new TypeError('Value of this must be of type BroadcastChannel'); + return state; +} + +class BroadcastChannel extends EventTarget { + constructor(name) { + if (arguments.length === 0) throw new TypeError('BroadcastChannel requires a name'); + super(); + if (typeof name === 'symbol') throw new TypeError('Cannot convert a Symbol value to a string'); + states.set(this, { name: String(name), closed: false, referenced: true, pending: new Set(), handlers: new Map() }); + channels.add(this); + } + + get name() { return stateOf(this).name; } + + postMessage(message) { + const state = stateOf(this); + if (arguments.length === 0) throw new TypeError('BroadcastChannel.postMessage requires a message'); + if (state.closed) throw new DOMException('BroadcastChannel is closed.', 'InvalidStateError'); + const snapshot = clone(message); + for (const channel of channels) { + const recipient = stateOf(channel); + if (channel === this || recipient.closed || recipient.name !== state.name) continue; + const data = clone(snapshot); + const timer = schedule(() => { + recipient.pending.delete(timer); + if (recipient.closed) return; + dispatch.call(channel, new MessageEvent('message', { data })); + }, 0); + recipient.pending.add(timer); + if (!recipient.referenced) timer.unref(); + } + } + + close() { + const state = stateOf(this); + state.closed = true; + channels.delete(this); + for (const timer of state.pending) cancel(timer); + state.pending.clear(); + } + + ref() { + const state = stateOf(this); + state.referenced = true; + for (const timer of state.pending) timer.ref(); + return this; + } + + unref() { + const state = stateOf(this); + state.referenced = false; + for (const timer of state.pending) timer.unref(); + return this; + } +} + +for (const type of ['message', 'messageerror']) { + Object.defineProperty(BroadcastChannel.prototype, 'on' + type, { + enumerable: true, configurable: true, + get() { return stateOf(this).handlers.get(type)?.callback ?? null; }, + set(callback) { + const state = stateOf(this); + const previous = state.handlers.get(type); + if (typeof callback !== 'function') { + if (previous) removeListener.call(this, type, previous.listener); + state.handlers.delete(type); + } else if (previous) { + previous.callback = callback; + } else { + const entry = { callback, listener: event => entry.callback.call(this, event) }; + state.handlers.set(type, entry); + addListener.call(this, type, entry.listener); + } + }, + }); +} +Object.defineProperty(BroadcastChannel.prototype, Symbol.toStringTag, { value: 'BroadcastChannel', configurable: true }); +module.exports = { BroadcastChannel, closeAll() { for (const channel of channels) channel.close(); } }; diff --git a/src/Node/Lib/brotli-decoder.cjs b/src/Node/Lib/brotli-decoder.cjs new file mode 100644 index 00000000..74f66bb0 --- /dev/null +++ b/src/Node/Lib/brotli-decoder.cjs @@ -0,0 +1,3335 @@ +// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt. +"use strict"; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + try { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + } catch (e) { + throw mod = 0, e; + } +}; + +// node_modules/brotli/dec/streams.js +var require_streams = __commonJS({ + "node_modules/brotli/dec/streams.js"(exports2) { + function BrotliInput(buffer) { + this.buffer = buffer; + this.pos = 0; + } + BrotliInput.prototype.read = function(buf, i, count) { + if (this.pos + count > this.buffer.length) { + count = this.buffer.length - this.pos; + } + for (var p = 0; p < count; p++) + buf[i + p] = this.buffer[this.pos + p]; + this.pos += count; + return count; + }; + exports2.BrotliInput = BrotliInput; + function BrotliOutput(buf) { + this.buffer = buf; + this.pos = 0; + } + BrotliOutput.prototype.write = function(buf, count) { + if (this.pos + count > this.buffer.length) + throw new Error("Output buffer is not large enough"); + this.buffer.set(buf.subarray(0, count), this.pos); + this.pos += count; + return count; + }; + exports2.BrotliOutput = BrotliOutput; + } +}); + +// node_modules/brotli/dec/bit_reader.js +var require_bit_reader = __commonJS({ + "node_modules/brotli/dec/bit_reader.js"(exports2, module2) { + var BROTLI_READ_SIZE = 4096; + var BROTLI_IBUF_SIZE = 2 * BROTLI_READ_SIZE + 32; + var BROTLI_IBUF_MASK = 2 * BROTLI_READ_SIZE - 1; + var kBitMask = new Uint32Array([ + 0, + 1, + 3, + 7, + 15, + 31, + 63, + 127, + 255, + 511, + 1023, + 2047, + 4095, + 8191, + 16383, + 32767, + 65535, + 131071, + 262143, + 524287, + 1048575, + 2097151, + 4194303, + 8388607, + 16777215 + ]); + function BrotliBitReader(input) { + this.buf_ = new Uint8Array(BROTLI_IBUF_SIZE); + this.input_ = input; + this.reset(); + } + BrotliBitReader.READ_SIZE = BROTLI_READ_SIZE; + BrotliBitReader.IBUF_MASK = BROTLI_IBUF_MASK; + BrotliBitReader.prototype.reset = function() { + this.buf_ptr_ = 0; + this.val_ = 0; + this.pos_ = 0; + this.bit_pos_ = 0; + this.bit_end_pos_ = 0; + this.eos_ = 0; + this.readMoreInput(); + for (var i = 0; i < 4; i++) { + this.val_ |= this.buf_[this.pos_] << 8 * i; + ++this.pos_; + } + return this.bit_end_pos_ > 0; + }; + BrotliBitReader.prototype.readMoreInput = function() { + if (this.bit_end_pos_ > 256) { + return; + } else if (this.eos_) { + if (this.bit_pos_ > this.bit_end_pos_) + throw new Error("Unexpected end of input " + this.bit_pos_ + " " + this.bit_end_pos_); + } else { + var dst = this.buf_ptr_; + var bytes_read = this.input_.read(this.buf_, dst, BROTLI_READ_SIZE); + if (bytes_read < 0) { + throw new Error("Unexpected end of input"); + } + if (bytes_read < BROTLI_READ_SIZE) { + this.eos_ = 1; + for (var p = 0; p < 32; p++) + this.buf_[dst + bytes_read + p] = 0; + } + if (dst === 0) { + for (var p = 0; p < 32; p++) + this.buf_[(BROTLI_READ_SIZE << 1) + p] = this.buf_[p]; + this.buf_ptr_ = BROTLI_READ_SIZE; + } else { + this.buf_ptr_ = 0; + } + this.bit_end_pos_ += bytes_read << 3; + } + }; + BrotliBitReader.prototype.fillBitWindow = function() { + while (this.bit_pos_ >= 8) { + this.val_ >>>= 8; + this.val_ |= this.buf_[this.pos_ & BROTLI_IBUF_MASK] << 24; + ++this.pos_; + this.bit_pos_ = this.bit_pos_ - 8 >>> 0; + this.bit_end_pos_ = this.bit_end_pos_ - 8 >>> 0; + } + }; + BrotliBitReader.prototype.readBits = function(n_bits) { + if (32 - this.bit_pos_ < n_bits) { + this.fillBitWindow(); + } + var val = this.val_ >>> this.bit_pos_ & kBitMask[n_bits]; + this.bit_pos_ += n_bits; + return val; + }; + module2.exports = BrotliBitReader; + } +}); + +// node_modules/brotli/dec/dictionary-data.js +var require_dictionary_data = __commonJS({ + "node_modules/brotli/dec/dictionary-data.js"(exports2) { + exports2.dictionary = Uint8Array.fromBase64("dGltZWRvd25saWZlbGVmdGJhY2tjb2RlZGF0YXNob3dvbmx5c2l0ZWNpdHlvcGVuanVzdGxpa2VmcmVld29ya3RleHR5ZWFyb3ZlcmJvZHlsb3ZlZm9ybWJvb2twbGF5bGl2ZWxpbmVoZWxwaG9tZXNpZGVtb3Jld29yZGxvbmd0aGVtdmlld2ZpbmRwYWdlZGF5c2Z1bGxoZWFkdGVybWVhY2hhcmVhZnJvbXRydWVtYXJrYWJsZXVwb25oaWdoZGF0ZWxhbmRuZXdzZXZlbm5leHRjYXNlYm90aHBvc3R1c2VkbWFkZWhhbmRoZXJld2hhdG5hbWVMaW5rYmxvZ3NpemViYXNlaGVsZG1ha2VtYWludXNlcicpICtob2xkZW5kc3dpdGhOZXdzcmVhZHdlcmVzaWdudGFrZWhhdmVnYW1lc2VlbmNhbGxwYXRod2VsbHBsdXNtZW51ZmlsbXBhcnRqb2ludGhpc2xpc3Rnb29kbmVlZHdheXN3ZXN0am9ic21pbmRhbHNvbG9nb3JpY2h1c2VzbGFzdHRlYW1hcm15Zm9vZGtpbmd3aWxsZWFzdHdhcmRiZXN0ZmlyZVBhZ2Vrbm93YXdheS5wbmdtb3ZldGhhbmxvYWRnaXZlc2VsZm5vdGVtdWNoZmVlZG1hbnlyb2NraWNvbm9uY2Vsb29raGlkZWRpZWRIb21lcnVsZWhvc3RhamF4aW5mb2NsdWJsYXdzbGVzc2hhbGZzb21lc3VjaHpvbmUxMDAlb25lc2NhcmVUaW1lcmFjZWJsdWVmb3Vyd2Vla2ZhY2Vob3BlZ2F2ZWhhcmRsb3N0d2hlbnBhcmtrZXB0cGFzc3NoaXByb29tSFRNTHBsYW5UeXBlZG9uZXNhdmVrZWVwZmxhZ2xpbmtzb2xkZml2ZXRvb2tyYXRldG93bmp1bXB0aHVzZGFya2NhcmRmaWxlZmVhcnN0YXlraWxsdGhhdGZhbGxhdXRvZXZlci5jb210YWxrc2hvcHZvdGVkZWVwbW9kZXJlc3R0dXJuYm9ybmJhbmRmZWxscm9zZXVybChza2lucm9sZWNvbWVhY3RzYWdlc21lZXRnb2xkLmpwZ2l0ZW12YXJ5ZmVsdHRoZW5zZW5kZHJvcFZpZXdjb3B5MS4wIjwvYT5zdG9wZWxzZWxpZXN0b3VycGFjay5naWZwYXN0Y3NzP2dyYXltZWFuJmd0O3JpZGVzaG90bGF0ZXNhaWRyb2FkdmFyIGZlZWxqb2hucmlja3BvcnRmYXN0J1VBLWRlYWQ8L2I+cG9vcmJpbGx0eXBlVS5TLndvb2RtdXN0MnB4O0luZm9yYW5rd2lkZXdhbnR3YWxsbGVhZFswXTtwYXVsd2F2ZXN1cmUkKCcjd2FpdG1hc3Nhcm1zZ29lc2dhaW5sYW5ncGFpZCEtLSBsb2NrdW5pdHJvb3R3YWxrZmlybXdpZmV4bWwic29uZ3Rlc3QyMHB4a2luZHJvd3N0b29sZm9udG1haWxzYWZlc3Rhcm1hcHNjb3JlcmFpbmZsb3diYWJ5c3BhbnNheXM0cHg7NnB4O2FydHNmb290cmVhbHdpa2loZWF0c3RlcHRyaXBvcmcvbGFrZXdlYWt0b2xkRm9ybWNhc3RmYW5zYmFua3ZlcnlydW5zanVseXRhc2sxcHg7Z29hbGdyZXdzbG93ZWRnZWlkPSJzZXRzNXB4Oy5qcz80MHB4aWYgKHNvb25zZWF0bm9uZXR1YmV6ZXJvc2VudHJlZWRmYWN0aW50b2dpZnRoYXJtMThweGNhbWVoaWxsYm9sZHpvb212b2lkZWFzeXJpbmdmaWxscGVha2luaXRjb3N0M3B4O2phY2t0YWdzYml0c3JvbGxlZGl0a25ld25lYXI8IS0tZ3Jvd0pTT05kdXR5TmFtZXNhbGV5b3UgbG90c3BhaW5qYXp6Y29sZGV5ZXNmaXNod3d3LnJpc2t0YWJzcHJldjEwcHhyaXNlMjVweEJsdWVkaW5nMzAwLGJhbGxmb3JkZWFybndpbGRib3guZmFpcmxhY2t2ZXJzcGFpcmp1bmV0ZWNoaWYoIXBpY2tldmlsJCgiI3dhcm1sb3JkZG9lc3B1bGwsMDAwaWRlYWRyYXdodWdlc3BvdGZ1bmRidXJuaHJlZmNlbGxrZXlzdGlja2hvdXJsb3NzZnVlbDEycHhzdWl0ZGVhbFJTUyJhZ2VkZ3JleUdFVCJlYXNlYWltc2dpcmxhaWRzOHB4O25hdnlncmlkdGlwcyM5OTl3YXJzbGFkeWNhcnMpOyB9cGhwP2hlbGx0YWxsd2hvbXpoOuUqLw0KIDEwMGhhbGwuCgpBN3B4O3B1c2hjaGF0MHB4O2NyZXcqLzwvaGFzaDc1cHhmbGF0cmFyZSAmJiB0ZWxsY2FtcG9udG9sYWlkbWlzc3NraXB0ZW50ZmluZW1hbGVnZXRzcGxvdDQwMCwNCg0KY29vbGZlZXQucGhwPGJyPmVyaWNtb3N0Z3VpZGJlbGxkZXNjaGFpcm1hdGhhdG9tL2ltZyYjODJsdWNrY2VudDAwMDt0aW55Z29uZWh0bWxzZWxsZHJ1Z0ZSRUVub2Rlbmljaz9pZD1sb3NlbnVsbHZhc3R3aW5kUlNTIHdlYXJyZWx5YmVlbnNhbWVkdWtlbmFzYWNhcGV3aXNoZ3VsZlQyMzpoaXRzc2xvdGdhdGVraWNrYmx1cnRoZXkxNXB4JycpOyk7Ij5tc2lld2luc2JpcmRzb3J0YmV0YXNlZWtUMTg6b3Jkc3RyZWVtYWxsNjBweGZhcm3igJlzYm95c1swXS4nKTsiUE9TVGJlYXJraWRzKTt9fW1hcnl0ZW5kKFVLKXF1YWR6aDrmLXNpei0tLS1wcm9wJyk7DWxpZnRUMTk6dmljZWFuZHlkZWJ0PlJTU3Bvb2xuZWNrYmxvd1QxNjpkb29yZXZhbFQxNzpsZXRzZmFpbG9yYWxwb2xsbm92YWNvbHNnZW5lIOKAlHNvZnRyb21ldGlsbHJvc3M8aDM+cG91cmZhZGVwaW5rPHRyPm1pbmkpfCEobWluZXpoOuhiYXJzaGVhcjAwKTttaWxrIC0tPmlyb25mcmVkZGlza3dlbnRzb2lscHV0cy9qcy9ob2x5VDIyOklTQk5UMjA6YWRhbXNlZXM8aDI+anNvbicsICdjb250VDIxOiBSU1Nsb29wYXNpYW1vb248L3A+c291bExJTkVmb3J0Y2FydFQxNDo8aDE+ODBweCEtLTw5cHg7VDA0Om1pa2U6NDZabmljZWluY2hZb3JrcmljZXpoOuQnKSk7cHVyZW1hZ2VwYXJhdG9uZWJvbmQ6MzdaX29mXyddKTswMDAsemg653Rhbmt5YXJkYm93bGJ1c2g6NTZaSmF2YTMwcHgKfH0KJUMzJTozNFpqZWZmRVhQSWNhc2h2aXNhZ29sZnNub3d6aDrpcXVlci5jc3NzaWNrbWVhdG1pbi5iaW5kZGVsbGhpcmVwaWNzcmVudDozNlpIVFRQLTIwMWZvdG93b2xmRU5EIHhib3g6NTRaQk9EWWRpY2s7Cn0KZXhpdDozNVp2YXJzYmVhdCd9KTtkaWV0OTk5O2FubmV9fTwvW2ldLkxhbmdrbcKyd2lyZXRveXNhZGRzc2VhbGFsZXg7Cgl9ZWNob25pbmUub3JnMDA1KXRvbnlqZXdzc2FuZGxlZ3Nyb29mMDAwKSAyMDB3aW5lZ2VhcmRvZ3Nib290Z2FyeWN1dHN0eWxldGVtcHRpb24ueG1sY29ja2dhbmckKCcuNTBweFBoLkRtaXNjYWxhbmxvYW5kZXNrbWlsZXJ5YW51bml4ZGlzYyk7fQpkdXN0Y2xpcCkuCgo3MHB4LTIwMERWRHM3XT48dGFwZWRlbW9pKyspd2FnZWV1cm9waGlsb3B0c2hvbGVGQVFzYXNpbi0yNlRsYWJzcGV0c1VSTCBidWxrY29vazt9DQpIRUFEWzBdKWFiYnJqdWFuKDE5OGxlc2h0d2luPC9pPnNvbnlndXlzZnVja3BpcGV8LQohMDAyKW5kb3dbMV07W107CkxvZyBzYWx0DQoJCWJhbmd0cmltYmF0aCl7DQowMHB4Cn0pO2tvOuxmZWVzYWQ+DXM6Ly8gW107dG9sbHBsdWcoKXsKew0KIC5qcycyMDBwZHVhbGJvYXQuSlBHKTsKfXF1b3QpOwoKJyk7Cg0KfQ0yMDE0MjAxNTIwMTYyMDE3MjAxODIwMTkyMDIwMjAyMTIwMjIyMDIzMjAyNDIwMjUyMDI2MjAyNzIwMjgyMDI5MjAzMDIwMzEyMDMyMjAzMzIwMzQyMDM1MjAzNjIwMzcyMDEzMjAxMjIwMTEyMDEwMjAwOTIwMDgyMDA3MjAwNjIwMDUyMDA0MjAwMzIwMDIyMDAxMjAwMDE5OTkxOTk4MTk5NzE5OTYxOTk1MTk5NDE5OTMxOTkyMTk5MTE5OTAxOTg5MTk4ODE5ODcxOTg2MTk4NTE5ODQxOTgzMTk4MjE5ODExOTgwMTk3OTE5NzgxOTc3MTk3NjE5NzUxOTc0MTk3MzE5NzIxOTcxMTk3MDE5NjkxOTY4MTk2NzE5NjYxOTY1MTk2NDE5NjMxOTYyMTk2MTE5NjAxOTU5MTk1ODE5NTcxOTU2MTk1NTE5NTQxOTUzMTk1MjE5NTExOTUwMTAwMDEwMjQxMzk0MDAwMDk5OTljb21vbcOhc2VzdGVlc3RhcGVyb3RvZG9oYWNlY2FkYWHDsW9iaWVuZMOtYWFzw612aWRhY2Fzb290cm9mb3Jvc29sb290cmFjdWFsZGlqb3NpZG9ncmFudGlwb3RlbWFkZWJlYWxnb3F1w6llc3RvbmFkYXRyZXNwb2NvY2FzYWJham90b2Rhc2lub2FndWFwdWVzdW5vc2FudGVkaWNlbHVpc2VsbGFtYXlvem9uYWFtb3JwaXNvb2JyYWNsaWNlbGxvZGlvc2hvcmFjYXNp0LfQsNC90LDQvtC80YDQsNGA0YPRgtCw0L3QtdC/0L7QvtGC0LjQt9C90L7QtNC+0YLQvtC20LXQvtC90LjRhdCd0LDQtdC10LHRi9C80YvQktGL0YHQvtCy0YvQstC+0J3QvtC+0LHQn9C+0LvQuNC90LjQoNCk0J3QtdCc0YvRgtGL0J7QvdC40LzQtNCw0JfQsNCU0LDQndGD0J7QsdGC0LXQmNC30LXQudC90YPQvNC80KLRi9GD0LbZgdmK2KPZhtmF2KfZhdi52YPZhNij2YjYsdiv2YrYp9mB2YnZh9mI2YTZhdmE2YPYp9mI2YTZh9io2LPYp9mE2KXZhtmH2YrYo9mK2YLYr9mH2YTYq9mF2KjZh9mE2YjZhNmK2KjZhNin2YrYqNmD2LTZitin2YXYo9mF2YbYqtio2YrZhNmG2K3YqNmH2YXZhdi02YjYtGZpcnN0dmlkZW9saWdodHdvcmxkbWVkaWF3aGl0ZWNsb3NlYmxhY2tyaWdodHNtYWxsYm9va3NwbGFjZW11c2ljZmllbGRvcmRlcnBvaW50dmFsdWVsZXZlbHRhYmxlYm9hcmRob3VzZWdyb3Vwd29ya3N5ZWFyc3N0YXRldG9kYXl3YXRlcnN0YXJ0c3R5bGVkZWF0aHBvd2VycGhvbmVuaWdodGVycm9yaW5wdXRhYm91dHRlcm1zdGl0bGV0b29sc2V2ZW50bG9jYWx0aW1lc2xhcmdld29yZHNnYW1lc3Nob3J0c3BhY2Vmb2N1c2NsZWFybW9kZWxibG9ja2d1aWRlcmFkaW9zaGFyZXdvbWVuYWdhaW5tb25leWltYWdlbmFtZXN5b3VuZ2xpbmVzbGF0ZXJjb2xvcmdyZWVuZnJvbnQmYW1wO3dhdGNoZm9yY2VwcmljZXJ1bGVzYmVnaW5hZnRlcnZpc2l0aXNzdWVhcmVhc2JlbG93aW5kZXh0b3RhbGhvdXJzbGFiZWxwcmludHByZXNzYnVpbHRsaW5rc3NwZWVkc3R1ZHl0cmFkZWZvdW5kc2Vuc2V1bmRlcnNob3duZm9ybXNyYW5nZWFkZGVkc3RpbGxtb3ZlZHRha2VuYWJvdmVmbGFzaGZpeGVkb2Z0ZW5vdGhlcnZpZXdzY2hlY2tsZWdhbHJpdmVyaXRlbXNxdWlja3NoYXBlaHVtYW5leGlzdGdvaW5nbW92aWV0aGlyZGJhc2ljcGVhY2VzdGFnZXdpZHRobG9naW5pZGVhc3dyb3RlcGFnZXN1c2Vyc2RyaXZlc3RvcmVicmVha3NvdXRodm9pY2VzaXRlc21vbnRod2hlcmVidWlsZHdoaWNoZWFydGhmb3J1bXRocmVlc3BvcnRwYXJ0eUNsaWNrbG93ZXJsaXZlc2NsYXNzbGF5ZXJlbnRyeXN0b3J5dXNhZ2Vzb3VuZGNvdXJ0eW91ciBiaXJ0aHBvcHVwdHlwZXNhcHBseUltYWdlYmVpbmd1cHBlcm5vdGVzZXZlcnlzaG93c21lYW5zZXh0cmFtYXRjaHRyYWNra25vd25lYXJseWJlZ2Fuc3VwZXJwYXBlcm5vcnRobGVhcm5naXZlbm5hbWVkZW5kZWRUZXJtc3BhcnRzR3JvdXBicmFuZHVzaW5nd29tYW5mYWxzZXJlYWR5YXVkaW90YWtlc3doaWxlLmNvbS9saXZlZGNhc2VzZGFpbHljaGlsZGdyZWF0anVkZ2V0aG9zZXVuaXRzbmV2ZXJicm9hZGNvYXN0Y292ZXJhcHBsZWZpbGVzY3ljbGVzY2VuZXBsYW5zY2xpY2t3cml0ZXF1ZWVucGllY2VlbWFpbGZyYW1lb2xkZXJwaG90b2xpbWl0Y2FjaGVjaXZpbHNjYWxlZW50ZXJ0aGVtZXRoZXJldG91Y2hib3VuZHJveWFsYXNrZWR3aG9sZXNpbmNlc3RvY2sgbmFtZWZhaXRoaGVhcnRlbXB0eW9mZmVyc2NvcGVvd25lZG1pZ2h0YWxidW10aGlua2Jsb29kYXJyYXltYWpvcnRydXN0Y2Fub251bmlvbmNvdW50dmFsaWRzdG9uZVN0eWxlTG9naW5oYXBweW9jY3VybGVmdDpmcmVzaHF1aXRlZmlsbXNncmFkZW5lZWRzdXJiYW5maWdodGJhc2lzaG92ZXJhdXRvO3JvdXRlLmh0bWxtaXhlZGZpbmFsWW91ciBzbGlkZXRvcGljYnJvd25hbG9uZWRyYXduc3BsaXRyZWFjaFJpZ2h0ZGF0ZXNtYXJjaHF1b3RlZ29vZHNMaW5rc2RvdWJ0YXN5bmN0aHVtYmFsbG93Y2hpZWZ5b3V0aG5vdmVsMTBweDtzZXJ2ZXVudGlsaGFuZHNDaGVja1NwYWNlcXVlcnlqYW1lc2VxdWFsdHdpY2UwLDAwMFN0YXJ0cGFuZWxzb25nc3JvdW5kZWlnaHRzaGlmdHdvcnRocG9zdHNsZWFkc3dlZWtzYXZvaWR0aGVzZW1pbGVzcGxhbmVzbWFydGFscGhhcGxhbnRtYXJrc3JhdGVzcGxheXNjbGFpbXNhbGVzdGV4dHNzdGFyc3dyb25nPC9oMz50aGluZy5vcmcvbXVsdGloZWFyZFBvd2Vyc3RhbmR0b2tlbnNvbGlkKHRoaXNicmluZ3NoaXBzc3RhZmZ0cmllZGNhbGxzZnVsbHlmYWN0c2FnZW50VGhpcyAvLy0tPmFkbWluZWd5cHRFdmVudDE1cHg7RW1haWx0cnVlImNyb3Nzc3BlbnRibG9nc2JveCI+bm90ZWRsZWF2ZWNoaW5hc2l6ZXNndWVzdDwvaDQ+cm9ib3RoZWF2eXRydWUsc2V2ZW5ncmFuZGNyaW1lc2lnbnNhd2FyZWRhbmNlcGhhc2U+PCEtLWVuX1VTJiMzOTsyMDBweF9uYW1lbGF0aW5lbmpveWFqYXguYXRpb25zbWl0aFUuUy4gaG9sZHNwZXRlcmluZGlhbmF2Ij5jaGFpbnNjb3JlY29tZXNkb2luZ3ByaW9yU2hhcmUxOTkwc3JvbWFubGlzdHNqYXBhbmZhbGxzdHJpYWxvd25lcmFncmVlPC9oMj5hYnVzZWFsZXJ0b3BlcmEiLS8vV2NhcmRzaGlsbHN0ZWFtc1Bob3RvdHJ1dGhjbGVhbi5waHA/c2FpbnRtZXRhbGxvdWlzbWVhbnRwcm9vZmJyaWVmcm93Ij5nZW5yZXRydWNrbG9va3NWYWx1ZUZyYW1lLm5ldC8tLT4KPHRyeSB7CnZhciBtYWtlc2Nvc3RzcGxhaW5hZHVsdHF1ZXN0dHJhaW5sYWJvcmhlbHBzY2F1c2VtYWdpY21vdG9ydGhlaXIyNTBweGxlYXN0c3RlcHNDb3VudGNvdWxkZ2xhc3NzaWRlc2Z1bmRzaG90ZWxhd2FyZG1vdXRobW92ZXNwYXJpc2dpdmVzZHV0Y2h0ZXhhc2ZydWl0bnVsbCx8fFtdO3RvcCI+CjwhLS1QT1NUIm9jZWFuPGJyLz5mbG9vcnNwZWFrZGVwdGggc2l6ZWJhbmtzY2F0Y2hjaGFydDIwcHg7YWxpZ25kZWFsc3dvdWxkNTBweDt1cmw9InBhcmtzbW91c2VNb3N0IC4uLjwvYW1vbmdicmFpbmJvZHkgbm9uZTtiYXNlZGNhcnJ5ZHJhZnRyZWZlcnBhZ2VfaG9tZS5tZXRlcmRlbGF5ZHJlYW1wcm92ZWpvaW50PC90cj5kcnVnczwhLS0gYXByaWxpZGVhbGFsbGVuZXhhY3Rmb3J0aGNvZGVzbG9naWNWaWV3IHNlZW1zYmxhbmtwb3J0cyAoMjAwc2F2ZWRfbGlua2dvYWxzZ3JhbnRncmVla2hvbWVzcmluZ3NyYXRlZDMwcHg7d2hvc2VwYXJzZSgpOyIgQmxvY2tsaW51eGpvbmVzcGl4ZWwnKTsiPik7aWYoLWxlZnRkYXZpZGhvcnNlRm9jdXNyYWlzZWJveGVzVHJhY2tlbWVudDwvZW0+YmFyIj4uc3JjPXRvd2VyYWx0PSJjYWJsZWhlbnJ5MjRweDtzZXR1cGl0YWx5c2hhcnBtaW5vcnRhc3Rld2FudHN0aGlzLnJlc2V0d2hlZWxnaXJscy9jc3MvMTAwJTtjbHVic3N0dWZmYmlibGV2b3RlcyAxMDAwa29yZWF9KTsNCmJhbmRzcXVldWU9IHt9OzgwcHg7Y2tpbmd7DQoJCWFoZWFkY2xvY2tpcmlzaGxpa2UgcmF0aW9zdGF0c0Zvcm0ieWFob28pWzBdO0Fib3V0ZmluZHM8L2gxPmRlYnVndGFza3NVUkwgPWNlbGxzfSkoKTsxMnB4O3ByaW1ldGVsbHN0dXJuczB4NjAwLmpwZyJzcGFpbmJlYWNodGF4ZXNtaWNyb2FuZ2VsLS0+PC9naWZ0c3N0ZXZlLWxpbmtib2R5Ln0pOwoJbW91bnQgKDE5OUZBUTwvcm9nZXJmcmFua0NsYXNzMjhweDtmZWVkczxoMT48c2NvdHR0ZXN0czIycHg7ZHJpbmspIHx8IGxld2lzc2hhbGwjMDM5OyBmb3IgbG92ZWR3YXN0ZTAwcHg7amE644JzaW1vbjxmb250cmVwbHltZWV0c3VudGVyY2hlYXB0aWdodEJyYW5kKSAhPSBkcmVzc2NsaXBzcm9vbXNvbmtleW1vYmlsbWFpbi5OYW1lIHBsYXRlZnVubnl0cmVlc2NvbS8iMS5qcGd3bW9kZXBhcmFtU1RBUlRsZWZ0IGlkZGVuLCAyMDEpOwp9CmZvcm0udmlydXNjaGFpcnRyYW5zd29yc3RQYWdlc2l0aW9ucGF0Y2g8IS0tCm8tY2FjZmlybXN0b3VycywwMDAgYXNpYW5pKyspe2Fkb2JlJylbMF1pZD0xMGJvdGg7bWVudSAuMi5taS5wbmcia2V2aW5jb2FjaENoaWxkYnJ1Y2UyLmpwZ1VSTCkrLmpwZ3xzdWl0ZXNsaWNlaGFycnkxMjAiIHN3ZWV0dHI+DQpuYW1lPWRpZWdvcGFnZSBzd2lzcy0tPgoKI2ZmZjsiPkxvZy5jb20idHJlYXRzaGVldCkgJiYgMTRweDtzbGVlcG50ZW50ZmlsZWRqYTrjg2lkPSJjTmFtZSJ3b3JzZXNob3RzLWJveC1kZWx0YQombHQ7YmVhcnM6NDhaPGRhdGEtcnVyYWw8L2E+IHNwZW5kYmFrZXJzaG9wcz0gIiI7cGhwIj5jdGlvbjEzcHg7YnJpYW5oZWxsb3NpemU9bz0lMkYgam9pbm1heWJlPGltZyBpbWciPiwgZmpzaW1nIiAiKVswXU1Ub3BCVHlwZSJuZXdseURhbnNrY3plY2h0cmFpbGtub3dzPC9oNT5mYXEiPnpoLWNuMTApOwotMSIpO3R5cGU9Ymx1ZXN0cnVseWRhdmlzLmpzJzs+DQo8IXN0ZWVsIHlvdSBoMj4NCmZvcm0gamVzdXMxMDAlIG1lbnUuDQoJDQp3YWxlc3Jpc2tzdW1lbnRkZGluZ2ItbGlrdGVhY2hnaWYiIHZlZ2FzZGFuc2tlZXN0aXNocWlwc3VvbWlzb2JyZWRlc2RlZW50cmV0b2Rvc3B1ZWRlYcOxb3Nlc3TDoXRpZW5laGFzdGFvdHJvc3BhcnRlZG9uZGVudWV2b2hhY2VyZm9ybWFtaXNtb21lam9ybXVuZG9hcXXDrWTDrWFzc8OzbG9heXVkYWZlY2hhdG9kYXN0YW50b21lbm9zZGF0b3NvdHJhc3NpdGlvbXVjaG9haG9yYWx1Z2FybWF5b3Jlc3Rvc2hvcmFzdGVuZXJhbnRlc2ZvdG9zZXN0YXNwYcOtc251ZXZhc2FsdWRmb3Jvc21lZGlvcXVpZW5tZXNlc3BvZGVyY2hpbGVzZXLDoXZlY2VzZGVjaXJqb3PDqWVzdGFydmVudGFncnVwb2hlY2hvZWxsb3N0ZW5nb2FtaWdvY29zYXNuaXZlbGdlbnRlbWlzbWFhaXJlc2p1bGlvdGVtYXNoYWNpYWZhdm9yanVuaW9saWJyZXB1bnRvYnVlbm9hdXRvcmFicmlsYnVlbmF0ZXh0b21hcnpvc2FiZXJsaXN0YWx1ZWdvY8OzbW9lbmVyb2p1ZWdvcGVyw7poYWJlcmVzdG95bnVuY2FtdWplcnZhbG9yZnVlcmFsaWJyb2d1c3RhaWd1YWx2b3Rvc2Nhc29zZ3XDrWFwdWVkb3NvbW9zYXZpc291c3RlZGRlYmVubm9jaGVidXNjYWZhbHRhZXVyb3NzZXJpZWRpY2hvY3Vyc29jbGF2ZWNhc2FzbGXDs25wbGF6b2xhcmdvb2JyYXN2aXN0YWFwb3lvanVudG90cmF0YXZpc3RvY3JlYXJjYW1wb2hlbW9zY2luY29jYXJnb3Bpc29zb3JkZW5oYWNlbsOhcmVhZGlzY29wZWRyb2NlcmNhcHVlZGFwYXBlbG1lbm9yw7p0aWxjbGFyb2pvcmdlY2FsbGVwb25lcnRhcmRlbmFkaWVtYXJjYXNpZ3VlZWxsYXNzaWdsb2NvY2hlbW90b3NtYWRyZWNsYXNlcmVzdG9uacOxb3F1ZWRhcGFzYXJiYW5jb2hpam9zdmlhamVwYWJsb8Opc3RldmllbmVyZWlub2RlamFyZm9uZG9jYW5hbG5vcnRlbGV0cmFjYXVzYXRvbWFybWFub3NsdW5lc2F1dG9zdmlsbGF2ZW5kb3Blc2FydGlwb3N0ZW5nYW1hcmNvbGxldmFwYWRyZXVuaWRvdmFtb3N6b25hc2FtYm9zYmFuZGFtYXJpYWFidXNvbXVjaGFzdWJpcnJpb2phdml2aXJncmFkb2NoaWNhYWxsw61qb3ZlbmRpY2hhZXN0YW50YWxlc3NhbGlyc3VlbG9wZXNvc2ZpbmVzbGxhbWFidXNjb8Opc3RhbGxlZ2FuZWdyb3BsYXphaHVtb3JwYWdhcmp1bnRhZG9ibGVpc2xhc2JvbHNhYmHDsW9oYWJsYWx1Y2hhw4FyZWFkaWNlbmp1Z2Fybm90YXN2YWxsZWFsbMOhY2FyZ2Fkb2xvcmFiYWpvZXN0w6lndXN0b21lbnRlbWFyaW9maXJtYWNvc3RvZmljaGFwbGF0YWhvZ2FyYXJ0ZXNsZXllc2FxdWVsbXVzZW9iYXNlc3BvY29zbWl0YWRjaWVsb2NoaWNvbWllZG9nYW5hcnNhbnRvZXRhcGFkZWJlc3BsYXlhcmVkZXNzaWV0ZWNvcnRlY29yZWFkdWRhc2Rlc2Vvdmllam9kZXNlYWFndWFzJnF1b3Q7ZG9tYWluY29tbW9uc3RhdHVzZXZlbnRzbWFzdGVyc3lzdGVtYWN0aW9uYmFubmVycmVtb3Zlc2Nyb2xsdXBkYXRlZ2xvYmFsbWVkaXVtZmlsdGVybnVtYmVyY2hhbmdlcmVzdWx0cHVibGljc2NyZWVuY2hvb3Nlbm9ybWFsdHJhdmVsaXNzdWVzc291cmNldGFyZ2V0c3ByaW5nbW9kdWxlbW9iaWxlc3dpdGNocGhvdG9zYm9yZGVycmVnaW9uaXRzZWxmc29jaWFsYWN0aXZlY29sdW1ucmVjb3JkZm9sbG93dGl0bGU+ZWl0aGVybGVuZ3RoZmFtaWx5ZnJpZW5kbGF5b3V0YXV0aG9yY3JlYXRlcmV2aWV3c3VtbWVyc2VydmVycGxheWVkcGxheWVyZXhwYW5kcG9saWN5Zm9ybWF0ZG91YmxlcG9pbnRzc2VyaWVzcGVyc29ubGl2aW5nZGVzaWdubW9udGhzZm9yY2VzdW5pcXVld2VpZ2h0cGVvcGxlZW5lcmd5bmF0dXJlc2VhcmNoZmlndXJlaGF2aW5nY3VzdG9tb2Zmc2V0bGV0dGVyd2luZG93c3VibWl0cmVuZGVyZ3JvdXBzdXBsb2FkaGVhbHRobWV0aG9kdmlkZW9zc2Nob29sZnV0dXJlc2hhZG93ZGViYXRldmFsdWVzT2JqZWN0b3RoZXJzcmlnaHRzbGVhZ3VlY2hyb21lc2ltcGxlbm90aWNlc2hhcmVkZW5kaW5nc2Vhc29ucmVwb3J0b25saW5lc3F1YXJlYnV0dG9uaW1hZ2VzZW5hYmxlbW92aW5nbGF0ZXN0d2ludGVyRnJhbmNlcGVyaW9kc3Ryb25ncmVwZWF0TG9uZG9uZGV0YWlsZm9ybWVkZGVtYW5kc2VjdXJlcGFzc2VkdG9nZ2xlcGxhY2VzZGV2aWNlc3RhdGljY2l0aWVzc3RyZWFteWVsbG93YXR0YWNrc3RyZWV0ZmxpZ2h0aGlkZGVuaW5mbyI+b3BlbmVkdXNlZnVsdmFsbGV5Y2F1c2VzbGVhZGVyc2VjcmV0c2Vjb25kZGFtYWdlc3BvcnRzZXhjZXB0cmF0aW5nc2lnbmVkdGhpbmdzZWZmZWN0ZmllbGRzc3RhdGVzb2ZmaWNldmlzdWFsZWRpdG9ydm9sdW1lUmVwb3J0bXVzZXVtbW92aWVzcGFyZW50YWNjZXNzbW9zdGx5bW90aGVyIiBpZD0ibWFya2V0Z3JvdW5kY2hhbmNlc3VydmV5YmVmb3Jlc3ltYm9sbW9tZW50c3BlZWNobW90aW9uaW5zaWRlbWF0dGVyQ2VudGVyb2JqZWN0ZXhpc3RzbWlkZGxlRXVyb3BlZ3Jvd3RobGVnYWN5bWFubmVyZW5vdWdoY2FyZWVyYW5zd2Vyb3JpZ2lucG9ydGFsY2xpZW50c2VsZWN0cmFuZG9tY2xvc2VkdG9waWNzY29taW5nZmF0aGVyb3B0aW9uc2ltcGx5cmFpc2VkZXNjYXBlY2hvc2VuY2h1cmNoZGVmaW5lcmVhc29uY29ybmVyb3V0cHV0bWVtb3J5aWZyYW1lcG9saWNlbW9kZWxzTnVtYmVyZHVyaW5nb2ZmZXJzc3R5bGVza2lsbGVkbGlzdGVkY2FsbGVkc2lsdmVybWFyZ2luZGVsZXRlYmV0dGVyYnJvd3NlbGltaXRzR2xvYmFsc2luZ2xld2lkZ2V0Y2VudGVyYnVkZ2V0bm93cmFwY3JlZGl0Y2xhaW1zZW5naW5lc2FmZXR5Y2hvaWNlc3Bpcml0LXN0eWxlc3ByZWFkbWFraW5nbmVlZGVkcnVzc2lhcGxlYXNlZXh0ZW50U2NyaXB0YnJva2VuYWxsb3dzY2hhcmdlZGl2aWRlZmFjdG9ybWVtYmVyLWJhc2VkdGhlb3J5Y29uZmlnYXJvdW5kd29ya2VkaGVscGVkQ2h1cmNoaW1wYWN0c2hvdWxkYWx3YXlzbG9nbyIgYm90dG9tbGlzdCI+KXt2YXIgcHJlZml4b3JhbmdlSGVhZGVyLnB1c2goY291cGxlZ2FyZGVuYnJpZGdlbGF1bmNoUmV2aWV3dGFraW5ndmlzaW9ubGl0dGxlZGF0aW5nQnV0dG9uYmVhdXR5dGhlbWVzZm9yZ290U2VhcmNoYW5jaG9yYWxtb3N0bG9hZGVkQ2hhbmdlcmV0dXJuc3RyaW5ncmVsb2FkTW9iaWxlaW5jb21lc3VwcGx5U291cmNlb3JkZXJzdmlld2VkJm5ic3A7Y291cnNlQWJvdXQgaXNsYW5kPGh0bWwgY29va2llbmFtZT0iYW1hem9ubW9kZXJuYWR2aWNlaW48L2E+OiBUaGUgZGlhbG9naG91c2VzQkVHSU4gTWV4aWNvc3RhcnRzY2VudHJlaGVpZ2h0YWRkaW5nSXNsYW5kYXNzZXRzRW1waXJlU2Nob29sZWZmb3J0ZGlyZWN0bmVhcmx5bWFudWFsU2VsZWN0LgoKT25lam9pbmVkbWVudSI+UGhpbGlwYXdhcmRzaGFuZGxlaW1wb3J0T2ZmaWNlcmVnYXJkc2tpbGxzbmF0aW9uU3BvcnRzZGVncmVld2Vla2x5IChlLmcuYmVoaW5kZG9jdG9ybG9nZ2VkdW5pdGVkPC9iPjwvYmVnaW5zcGxhbnRzYXNzaXN0YXJ0aXN0aXNzdWVkMzAwcHh8Y2FuYWRhYWdlbmN5c2NoZW1lcmVtYWluQnJhemlsc2FtcGxlbG9nbyI+YmV5b25kLXNjYWxlYWNjZXB0c2VydmVkbWFyaW5lRm9vdGVyY2FtZXJhPC9oMT4KX2Zvcm0ibGVhdmVzc3RyZXNzIiAvPg0KLmdpZiIgb25sb2FkbG9hZGVyT3hmb3Jkc2lzdGVyc3Vydml2bGlzdGVuZmVtYWxlRGVzaWduc2l6ZT0iYXBwZWFsdGV4dCI+bGV2ZWxzdGhhbmtzaGlnaGVyZm9yY2VkYW5pbWFsYW55b25lQWZyaWNhYWdyZWVkcmVjZW50UGVvcGxlPGJyIC8+d29uZGVycHJpY2VzdHVybmVkfHwge307bWFpbiI+aW5saW5lc3VuZGF5d3JhcCI+ZmFpbGVkY2Vuc3VzbWludXRlYmVhY29ucXVvdGVzMTUwcHh8ZXN0YXRlcmVtb3RlZW1haWwibGlua2VkcmlnaHQ7c2lnbmFsZm9ybWFsMS5odG1sc2lnbnVwcHJpbmNlZmxvYXQ6LnBuZyIgZm9ydW0uQWNjZXNzcGFwZXJzc291bmRzZXh0ZW5kSGVpZ2h0c2xpZGVyVVRGLTgiJmFtcDsgQmVmb3JlLiBXaXRoc3R1ZGlvb3duZXJzbWFuYWdlcHJvZml0alF1ZXJ5YW5udWFscGFyYW1zYm91Z2h0ZmFtb3VzZ29vZ2xlbG9uZ2VyaSsrKSB7aXNyYWVsc2F5aW5nZGVjaWRlaG9tZSI+aGVhZGVyZW5zdXJlYnJhbmNocGllY2VzYmxvY2s7c3RhdGVkdG9wIj48cmFjaW5ncmVzaXplLS0mZ3Q7cGFjaXR5c2V4dWFsYnVyZWF1LmpwZyIgMTAsMDAwb2J0YWludGl0bGVzYW1vdW50LCBJbmMuY29tZWR5bWVudSIgbHlyaWNzdG9kYXkuaW5kZWVkY291bnR5X2xvZ28uRmFtaWx5bG9va2VkTWFya2V0bHNlIGlmUGxheWVydHVya2V5KTt2YXIgZm9yZXN0Z2l2aW5nZXJyb3JzRG9tYWlufWVsc2V7aW5zZXJ0QmxvZzwvZm9vdGVybG9naW4uZmFzdGVyYWdlbnRzPGJvZHkgMTBweCAwcHJhZ21hZnJpZGF5anVuaW9yZG9sbGFycGxhY2VkY292ZXJzcGx1Z2luNSwwMDAgcGFnZSI+Ym9zdG9uLnRlc3QoYXZhdGFydGVzdGVkX2NvdW50Zm9ydW1zc2NoZW1haW5kZXgsZmlsbGVkc2hhcmVzcmVhZGVyYWxlcnQoYXBwZWFyU3VibWl0bGluZSI+Ym9keSI+CiogVGhlVGhvdWdoc2VlaW5namVyc2V5TmV3czwvdmVyaWZ5ZXhwZXJ0aW5qdXJ5d2lkdGg9Q29va2llU1RBUlQgYWNyb3NzX2ltYWdldGhyZWFkbmF0aXZlcG9ja2V0Ym94Ij4KU3lzdGVtIERhdmlkY2FuY2VydGFibGVzcHJvdmVkQXByaWwgcmVhbGx5ZHJpdmVyaXRlbSI+bW9yZSI+Ym9hcmRzY29sb3JzY2FtcHVzZmlyc3QgfHwgW107bWVkaWEuZ3VpdGFyZmluaXNod2lkdGg6c2hvd2VkT3RoZXIgLnBocCIgYXNzdW1lbGF5ZXJzd2lsc29uc3RvcmVzcmVsaWVmc3dlZGVuQ3VzdG9tZWFzaWx5IHlvdXIgU3RyaW5nCgpXaGlsdGF5bG9yY2xlYXI6cmVzb3J0ZnJlbmNodGhvdWdoIikgKyAiPGJvZHk+YnV5aW5nYnJhbmRzTWVtYmVybmFtZSI+b3BwaW5nc2VjdG9yNXB4OyI+dnNwYWNlcG9zdGVybWFqb3IgY29mZmVlbWFydGlubWF0dXJlaGFwcGVuPC9uYXY+a2Fuc2FzbGluayI+SW1hZ2VzPWZhbHNld2hpbGUgaHNwYWNlMCZhbXA7IAoKSW4gIHBvd2VyUG9sc2tpLWNvbG9yam9yZGFuQm90dG9tU3RhcnQgLWNvdW50Mi5odG1sbmV3cyI+MDEuanBnT25saW5lLXJpZ2h0bWlsbGVyc2VuaW9ySVNCTiAwMCwwMDAgZ3VpZGVzdmFsdWUpZWN0aW9ucmVwYWlyLnhtbCIgIHJpZ2h0cy5odG1sLWJsb2NrcmVnRXhwOmhvdmVyd2l0aGludmlyZ2lucGhvbmVzPC90cj4NdXNpbmcgCgl2YXIgPicpOwoJPC90ZD4KPC90cj4KYmFoYXNhYnJhc2lsZ2FsZWdvbWFneWFycG9sc2tpc3Jwc2tp2LHYr9mI5Lit5paH566A5L2T57mB6auU5L+h5oGv5Lit5Zu95oiR5Lus5LiA5Liq5YWs5Y+4566h55CG6K665Z2b5Y+v5Lul5pyN5Yqh5pe26Ze05Liq5Lq65Lqn5ZOB6Ieq5bex5LyB5Lia5p+l55yL5bel5L2c6IGU57O75rKh5pyJ572R56uZ5omA5pyJ6K+E6K665Lit5b+D5paH56ug55So5oi36aaW6aG15L2c6ICF5oqA5pyv6Zeu6aKY55u45YWz5LiL6L295pCc57Si5L2/55So6L2v5Lu25Zyo57q/5Li76aKY6LWE5paZ6KeG6aKR5Zue5aSN5rOo5YaM572R57uc5pS26JeP5YaF5a655o6o6I2Q5biC5Zy65raI5oGv56m66Ze05Y+R5biD5LuA5LmI5aW95Y+L55Sf5rS75Zu+54mH5Y+R5bGV5aaC5p6c5omL5py65paw6Ze75pyA5paw5pa55byP5YyX5Lqs5o+Q5L6b5YWz5LqO5pu05aSa6L+Z5Liq57O757uf55+l6YGT5ri45oiP5bm/5ZGK5YW25LuW5Y+R6KGo5a6J5YWo56ys5LiA5Lya5ZGY6L+b6KGM54K55Ye754mI5p2D55S15a2Q5LiW55WM6K6+6K6h5YWN6LS55pWZ6IKy5Yqg5YWl5rS75Yqo5LuW5Lus5ZWG5ZOB5Y2a5a6i546w5Zyo5LiK5rW35aaC5L2V5bey57uP55WZ6KiA6K+m57uG56S+5Yy655m75b2V5pys56uZ6ZyA6KaB5Lu35qC85pSv5oyB5Zu96ZmF6ZO+5o6l5Zu95a625bu66K6+5pyL5Y+L6ZiF6K+75rOV5b6L5L2N572u57uP5rWO6YCJ5oup6L+Z5qC35b2T5YmN5YiG57G75o6S6KGM5Zug5Li65Lqk5piT5pyA5ZCO6Z+z5LmQ5LiN6IO96YCa6L+H6KGM5Lia56eR5oqA5Y+v6IO96K6+5aSH5ZCI5L2c5aSn5a6256S+5Lya56CU56m25LiT5Lia5YWo6YOo6aG555uu6L+Z6YeM6L+Y5piv5byA5aeL5oOF5Ya155S16ISR5paH5Lu25ZOB54mM5biu5Yqp5paH5YyW6LWE5rqQ5aSn5a2m5a2m5Lmg5Zyw5Z2A5rWP6KeI5oqV6LWE5bel56iL6KaB5rGC5oCO5LmI5pe25YCZ5Yqf6IO95Li76KaB55uu5YmN6LWE6K6v5Z+O5biC5pa55rOV55S15b2x5oub6IGY5aOw5piO5Lu75L2V5YGl5bq35pWw5o2u576O5Zu95rG96L2m5LuL57uN5L2G5piv5Lqk5rWB55Sf5Lqn5omA5Lul55S16K+d5pi+56S65LiA5Lqb5Y2V5L2N5Lq65ZGY5YiG5p6Q5Zyw5Zu+5peF5ri45bel5YW35a2m55Sf57O75YiX572R5Y+L5biW5a2Q5a+G56CB6aKR6YGT5o6n5Yi25Zyw5Yy65Z+65pys5YWo5Zu9572R5LiK6YeN6KaB56ys5LqM5Zac5qyi6L+b5YWl5Y+L5oOF6L+Z5Lqb6ICD6K+V5Y+R546w5Z+56K6t5Lul5LiK5pS/5bqc5oiQ5Li6546v5aKD6aaZ5riv5ZCM5pe25aix5LmQ5Y+R6YCB5LiA5a6a5byA5Y+R5L2c5ZOB5qCH5YeG5qyi6L+O6Kej5Yaz5Zyw5pa55LiA5LiL5Lul5Y+K6LSj5Lu75oiW6ICF5a6i5oi35Luj6KGo56ev5YiG5aWz5Lq65pWw56CB6ZSA5ZSu5Ye6546w56a757q/5bqU55So5YiX6KGo5LiN5ZCM57yW6L6R57uf6K6h5p+l6K+i5LiN6KaB5pyJ5YWz5py65p6E5b6I5aSa5pKt5pS+57uE57uH5pS/562W55u05o6l6IO95Yqb5p2l5rqQ5pmC6ZaT55yL5Yiw54Ot6Zeo5YWz6ZSu5LiT5Yy66Z2e5bi46Iux6K+t55m+5bqm5biM5pyb576O5aWz5q+U6L6D55+l6K+G6KeE5a6a5bu66K6u6YOo6Zeo5oSP6KeB57K+5b2p5pel5pys5o+Q6auY5Y+R6KiA5pa56Z2i5Z+66YeR5aSE55CG5p2D6ZmQ5b2x54mH6ZO26KGM6L+Y5pyJ5YiG5Lqr54mp5ZOB57uP6JCl5re75Yqg5LiT5a626L+Z56eN6K+d6aKY6LW35p2l5Lia5Yqh5YWs5ZGK6K6w5b2V566A5LuL6LSo6YeP55S35Lq65b2x5ZON5byV55So5oql5ZGK6YOo5YiG5b+r6YCf5ZKo6K+i5pe25bCa5rOo5oSP55Sz6K+35a2m5qCh5bqU6K+l5Y6G5Y+y5Y+q5piv6L+U5Zue6LSt5Lmw5ZCN56ew5Li65LqG5oiQ5Yqf6K+05piO5L6b5bqU5a2p5a2Q5LiT6aKY56iL5bqP5LiA6Iis5pyD5ZOh5Y+q5pyJ5YW25a6D5L+d5oqk6ICM5LiU5LuK5aSp56qX5Y+j5Yqo5oCB54q25oCB54m55Yir6K6k5Li65b+F6aG75pu05paw5bCP6K+05oiR5YCR5L2c5Li65aqS5L2T5YyF5ous6YKj5LmI5LiA5qC35Zu95YaF5piv5ZCm5qC55o2u55S16KeG5a2m6Zmi5YW35pyJ6L+H56iL55Sx5LqO5Lq65omN5Ye65p2l5LiN6L+H5q2j5Zyo5piO5pif5pWF5LqL5YWz57O75qCH6aKY5ZWG5Yqh6L6T5YWl5LiA55u05Z+656GA5pWZ5a2m5LqG6Kej5bu6562R57uT5p6c5YWo55CD6YCa55+l6K6h5YiS5a+55LqO6Im65pyv55u45YaM5Y+R55Sf55yf55qE5bu656uL562J57qn57G75Z6L57uP6aqM5a6e546w5Yi25L2c5p2l6Ieq5qCH562+5Lul5LiL5Y6f5Yib5peg5rOV5YW25Lit5YCL5Lq65LiA5YiH5oyH5Y2X5YWz6Zet6ZuG5Zui56ys5LiJ5YWz5rOo5Zug5q2k54Wn54mH5rex5Zyz5ZWG5Lia5bm/5bee5pel5pyf6auY57qn5pyA6L+R57u85ZCI6KGo56S65LiT6L6R6KGM5Li65Lqk6YCa6K+E5Lu36KeJ5b6X57K+5Y2O5a625bqt5a6M5oiQ5oSf6KeJ5a6J6KOF5b6X5Yiw6YKu5Lu25Yi25bqm6aOf5ZOB6Jm954S26L2s6L295oql5Lu36K6w6ICF5pa55qGI6KGM5pS/5Lq65rCR55So5ZOB5Lic6KW/5o+Q5Ye66YWS5bqX54S25ZCO5LuY5qy+54Ot54K55Lul5YmN5a6M5YWo5Y+R5biW6K6+572u6aKG5a+85bel5Lia5Yy76Zmi55yL55yL57uP5YW45Y6f5Zug5bmz5Y+w5ZCE56eN5aKe5Yqg5p2Q5paZ5paw5aKe5LmL5ZCO6IGM5Lia5pWI5p6c5LuK5bm06K665paH5oiR5Zu95ZGK6K+J54mI5Li75L+u5pS55Y+C5LiO5omT5Y2w5b+r5LmQ5py65qKw6KeC54K55a2Y5Zyo57K+56We6I635b6X5Yip55So57un57ut5L2g5Lus6L+Z5LmI5qih5byP6K+t6KiA6IO95aSf6ZuF6JmO5pON5L2c6aOO5qC85LiA6LW356eR5a2m5L2T6IKy55+t5L+h5p2h5Lu25rK755aX6L+Q5Yqo5Lqn5Lia5Lya6K6u5a+86Iiq5YWI55Sf6IGU55uf5Y+v5piv5ZWP6aGM57uT5p6E5L2c55So6LCD5p+l6LOH5paZ6Ieq5Yqo6LSf6LSj5Yac5Lia6K6/6Zeu5a6e5pa95o6l5Y+X6K6o6K666YKj5Liq5Y+N6aaI5Yqg5by65aWz5oCn6IyD5Zu05pyN5YuZ5LyR6Zey5LuK5pel5a6i5pyN6KeA55yL5Y+C5Yqg55qE6K+d5LiA54K55L+d6K+B5Zu+5Lmm5pyJ5pWI5rWL6K+V56e75Yqo5omN6IO95Yaz5a6a6IKh56Wo5LiN5pat6ZyA5rGC5LiN5b6X5Yqe5rOV5LmL6Ze06YeH55So6JCl6ZSA5oqV6K+J55uu5qCH54ix5oOF5pGE5b2x5pyJ5Lqb6KSH6KO95paH5a2m5py65Lya5pWw5a2X6KOF5L+u6LSt54mp5Yac5p2R5YWo6Z2i57K+5ZOB5YW25a6e5LqL5oOF5rC05bmz5o+Q56S65LiK5biC6LCi6LCi5pmu6YCa5pWZ5biI5LiK5Lyg57G75Yir5q2M5puy5oul5pyJ5Yib5paw6YWN5Lu25Y+q6KaB5pe25Luj6LOH6KiK6L6+5Yiw5Lq655Sf6K6i6ZiF6ICB5biI5bGV56S65b+D55CG6LS05a2Q57ay56uZ5Li76aGM6Ieq54S257qn5Yir566A5Y2V5pS56Z2p6YKj5Lqb5p2l6K+05omT5byA5Luj56CB5Yig6Zmk6K+B5Yi46IqC55uu6YeN54K55qyh5pW45aSa5bCR6KeE5YiS6LWE6YeR5om+5Yiw5Lul5ZCO5aSn5YWo5Li76aG15pyA5L2z5Zue562U5aSp5LiL5L+d6Zqc546w5Luj5qOA5p+l5oqV56Wo5bCP5pe25rKS5pyJ5q2j5bi455Sa6Iez5Luj55CG55uu5b2V5YWs5byA5aSN5Yi26YeR6J6N5bm456aP54mI5pys5b2i5oiQ5YeG5aSH6KGM5oOF5Zue5Yiw5oCd5oOz5oCO5qC35Y2P6K6u6K6k6K+B5pyA5aW95Lqn55Sf5oyJ54Wn5pyN6KOF5bm/5Lic5Yqo5ryr6YeH6LSt5paw5omL57uE5Zu+6Z2i5p2/5Y+C6ICD5pS/5rK75a655piT5aSp5Zyw5Yqq5Yqb5Lq65Lus5Y2H57qn6YCf5bqm5Lq654mp6LCD5pW05rWB6KGM6YCg5oiQ5paH5a2X6Z+p5Zu96LS45piT5byA5bGV55u46Zec6KGo546w5b2x6KeG5aaC5q2k576O5a655aSn5bCP5oql6YGT5p2h5qy+5b+D5oOF6K645aSa5rOV6KeE5a625bGF5Lmm5bqX6L+e5o6l56uL5Y2z5Li+5oql5oqA5ben5aWl6L+Q55m75YWl5Lul5p2l55CG6K665LqL5Lu26Ieq55Sx5Lit5Y2O5Yqe5YWs5aaI5aaI55yf5q2j5LiN6ZSZ5YWo5paH5ZCI5ZCM5Lu35YC85Yir5Lq655uR552j5YW35L2T5LiW57qq5Zui6Zif5Yib5Lia5om/5ouF5aKe6ZW/5pyJ5Lq65L+d5oyB5ZWG5a6257u05L+u5Y+w5rm+5bem5Y+z6IKh5Lu9562U5qGI5a6e6ZmF55S15L+h57uP55CG55Sf5ZG95a6j5Lyg5Lu75Yqh5q2j5byP54m56Imy5LiL5p2l5Y2P5Lya5Y+q6IO95b2T54S26YeN5paw5YWn5a655oyH5a+86L+Q6KGM5pel5b+X6LOj5a626LaF6L+H5Zyf5Zyw5rWZ5rGf5pSv5LuY5o6o5Ye656uZ6ZW/5p2t5bee5omn6KGM5Yi26YCg5LmL5LiA5o6o5bm/546w5Zy65o+P6L+w5Y+Y5YyW5Lyg57uf5q2M5omL5L+d6Zmp6K++56iL5Yy755aX57uP6L+H6L+H5Y675LmL5YmN5pS25YWl5bm05bqm5p2C5b+X576O5Li95pyA6auY55m76ZmG5pyq5p2l5Yqg5bel5YWN6LSj5pWZ56iL54mI5Z2X6Lqr5L2T6YeN5bqG5Ye65ZSu5oiQ5pys5b2i5byP5Zyf6LGG5Ye65YO55Lic5pa56YKu566x5Y2X5Lqs5rGC6IGM5Y+W5b6X6IGM5L2N55u45L+h6aG16Z2i5YiG6ZKf572R6aG156Gu5a6a5Zu+5L6L572R5Z2A56ev5p6B6ZSZ6K+v55uu55qE5a6d6LSd5py65YWz6aOO6Zmp5o6I5p2D55eF5q+S5a6g54mp6Zmk5LqG6KmV6KuW55a+55eF5Y+K5pe25rGC6LSt56uZ54K55YS/56ul5q+P5aSp5Lit5aSu6K6k6K+G5q+P5Liq5aSp5rSl5a2X5L2T5Y+w54Gj57u05oqk5pys6aG15Liq5oCn5a6Y5pa55bi46KeB55u45py65oiY55Wl5bqU5b2T5b6L5biI5pa55L6/5qCh5Zut6IKh5biC5oi/5bGL5qCP55uu5ZGY5bel5a+86Ie056qB54S26YGT5YW35pys572R57uT5ZCI5qGj5qGI5Yqz5Yqo5Y+m5aSW576O5YWD5byV6LW35pS55Y+Y56ys5Zub5Lya6K6h6Kqq5piO6ZqQ56eB5a6d5a6d6KeE6IyD5raI6LS55YWx5ZCM5b+Y6K6w5L2T57O75bim5p2l5ZCN5a2X55m86KGo5byA5pS+5Yqg55uf5Y+X5Yiw5LqM5omL5aSn6YeP5oiQ5Lq65pWw6YeP5YWx5Lqr5Yy65Z+f5aWz5a2p5Y6f5YiZ5omA5Zyo57uT5p2f6YCa5L+h6LaF57qn6YWN572u5b2T5pe25LyY56eA5oCn5oSf5oi/5Lqn6YGK5oiy5Ye65Y+j5o+Q5Lqk5bCx5Lia5L+d5YGl56iL5bqm5Y+C5pWw5LqL5Lia5pW05Liq5bGx5Lic5oOF5oSf54m55q6K5YiG6aGe5pCc5bCL5bGe5LqO6Zeo5oi36LSi5Yqh5aOw6Z+z5Y+K5YW26LSi57uP5Z2a5oyB5bmy6YOo5oiQ56uL5Yip55uK6ICD6JmR5oiQ6YO95YyF6KOF55So5oi25q+U6LWb5paH5piO5oub5ZWG5a6M5pW055yf5piv55y8552b5LyZ5Ly05aiB5pyb6aKG5Z+f5Y2r55Sf5LyY5oOg6KuW5aOH5YWs5YWx6Imv5aW95YWF5YiG56ym5ZCI6ZmE5Lu254m554K55LiN5Y+v6Iux5paH6LWE5Lqn5qC55pys5piO5pi+5a+G56K85YWs5LyX5rCR5peP5pu05Yqg5Lqr5Y+X5ZCM5a2m5ZCv5Yqo6YCC5ZCI5Y6f5p2l6Zeu562U5pys5paH576O6aOf57u/6Imy56iz5a6a57uI5LqO55Sf54mp5L6b5rGC5pCc54uQ5Yqb6YeP5Lil6YeN5rC46L+c5YaZ55yf5pyJ6ZmQ56ue5LqJ5a+56LGh6LS555So5LiN5aW957ud5a+55Y2B5YiG5L+D6L+b54K56K+E5b2x6Z+z5LyY5Yq/5LiN5bCR5qyj6LWP5bm25LiU5pyJ54K55pa55ZCR5YWo5paw5L+h55So6K6+5pa95b2i6LGh6LWE5qC856qB56C06ZqP552A6YeN5aSn5LqO5piv5q+V5Lia5pm66IO95YyW5bel5a6M576O5ZWG5Z+O57uf5LiA5Ye654mI5omT6YCg55Si5ZOB5qaC5Ya155So5LqO5L+d55WZ5Zug57Sg5Lit5ZyL5a2Y5YKo6LS05Zu+5pyA5oSb6ZW/5pyf5Y+j5Lu355CG6LSi5Z+65Zyw5a6J5o6S5q2m5rGJ6YeM6Z2i5Yib5bu65aSp56m66aaW5YWI5a6M5ZaE6amx5Yqo5LiL6Z2i5LiN5YaN6K+a5L+h5oSP5LmJ6Ziz5YWJ6Iux5Zu95ryC5Lqu5Yab5LqL546p5a62576k5LyX5Yac5rCR5Y2z5Y+v5ZCN56ix5a625YW35Yqo55S75oOz5Yiw5rOo5piO5bCP5a2m5oCn6IO96ICD56CU56Gs5Lu26KeC55yL5riF5qWa5pCe56yR6aaW6aCB6buE6YeR6YCC55So5rGf6IuP55yf5a6e5Li7566h6Zi25q616Ki75YaK57+76K+R5p2D5Yip5YGa5aW95Ly85LmO6YCa6K6v5pa95bel54uA5oWL5Lmf6K64546v5L+d5Z+55YW75qaC5b+15aSn5Z6L5py656Wo55CG6Kej5Yy/5ZCNY3VhbmRvZW52aWFybWFkcmlkYnVzY2FyaW5pY2lvdGllbXBvcG9ycXVlY3VlbnRhZXN0YWRvcHVlZGVuanVlZ29zY29udHJhZXN0w6Fubm9tYnJldGllbmVucGVyZmlsbWFuZXJhYW1pZ29zY2l1ZGFkY2VudHJvYXVucXVlcHVlZGVzZGVudHJvcHJpbWVycHJlY2lvc2Vnw7puYnVlbm9zdm9sdmVycHVudG9zc2VtYW5haGFiw61hYWdvc3RvbnVldm9zdW5pZG9zY2FybG9zZXF1aXBvbmnDsW9zbXVjaG9zYWxndW5hY29ycmVvaW1hZ2VucGFydGlyYXJyaWJhbWFyw61haG9tYnJlZW1wbGVvdmVyZGFkY2FtYmlvbXVjaGFzZnVlcm9ucGFzYWRvbMOtbmVhcGFyZWNlbnVldmFzY3Vyc29zZXN0YWJhcXVpZXJvbGlicm9zY3VhbnRvYWNjZXNvbWlndWVsdmFyaW9zY3VhdHJvdGllbmVzZ3J1cG9zc2Vyw6FuZXVyb3BhbWVkaW9zZnJlbnRlYWNlcmNhZGVtw6Fzb2ZlcnRhY29jaGVzbW9kZWxvaXRhbGlhbGV0cmFzYWxnw7puY29tcHJhY3VhbGVzZXhpc3RlY3VlcnBvc2llbmRvcHJlbnNhbGxlZ2FydmlhamVzZGluZXJvbXVyY2lhcG9kcsOhcHVlc3RvZGlhcmlvcHVlYmxvcXVpZXJlbWFudWVscHJvcGlvY3Jpc2lzY2llcnRvc2VndXJvbXVlcnRlZnVlbnRlY2VycmFyZ3JhbmRlZWZlY3RvcGFydGVzbWVkaWRhcHJvcGlhb2ZyZWNldGllcnJhZS1tYWlsdmFyaWFzZm9ybWFzZnV0dXJvb2JqZXRvc2VndWlycmllc2dvbm9ybWFzbWlzbW9zw7puaWNvY2FtaW5vc2l0aW9zcmF6w7NuZGViaWRvcHJ1ZWJhdG9sZWRvdGVuw61hamVzw7pzZXNwZXJvY29jaW5hb3JpZ2VudGllbmRhY2llbnRvY8OhZGl6aGFibGFyc2Vyw61hbGF0aW5hZnVlcnphZXN0aWxvZ3VlcnJhZW50cmFyw6l4aXRvbMOzcGV6YWdlbmRhdsOtZGVvZXZpdGFycGFnaW5hbWV0cm9zamF2aWVycGFkcmVzZsOhY2lsY2FiZXphw6FyZWFzc2FsaWRhZW52w61vamFww7NuYWJ1c29zYmllbmVzdGV4dG9zbGxldmFycHVlZGFuZnVlcnRlY29tw7puY2xhc2VzaHVtYW5vdGVuaWRvYmlsYmFvdW5pZGFkZXN0w6FzZWRpdGFyY3JlYWRv0LTQu9GP0YfRgtC+0LrQsNC60LjQu9C40Y3RgtC+0LLRgdC10LXQs9C+0L/RgNC40YLQsNC60LXRidC10YPQttC10JrQsNC60LHQtdC30LHRi9C70L7QvdC40JLRgdC10L/QvtC00K3RgtC+0YLQvtC80YfQtdC80L3QtdGC0LvQtdGC0YDQsNC30L7QvdCw0LPQtNC10LzQvdC10JTQu9GP0J/RgNC40L3QsNGB0L3QuNGF0YLQtdC80LrRgtC+0LPQvtC00LLQvtGC0YLQsNC80KHQqNCQ0LzQsNGP0KfRgtC+0LLQsNGB0LLQsNC80LXQvNGD0KLQsNC60LTQstCw0L3QsNC80Y3RgtC40Y3RgtGD0JLQsNC80YLQtdGF0L/RgNC+0YLRg9GC0L3QsNC00LTQvdGP0JLQvtGC0YLRgNC40L3QtdC50JLQsNGB0L3QuNC80YHQsNC80YLQvtGC0YDRg9Cx0J7QvdC40LzQuNGA0L3QtdC10J7QntCe0LvQuNGG0Y3RgtCw0J7QvdCw0L3QtdC80LTQvtC80LzQvtC50LTQstC10L7QvdC+0YHRg9C04KSV4KWH4KS54KWI4KSV4KWA4KS44KWH4KSV4KS+4KSV4KWL4KSU4KSw4KSq4KSw4KSo4KWH4KSP4KSV4KSV4KS/4KSt4KWA4KSH4KS44KSV4KSw4KSk4KWL4KS54KWL4KSG4KSq4KS54KWA4KSv4KS54KSv4KS+4KSk4KSV4KSl4KS+amFncmFu4KSG4KSc4KSc4KWL4KSF4KSs4KSm4KWL4KSX4KSI4KSc4KS+4KSX4KSP4KS54KSu4KSH4KSo4KS14KS54KSv4KWH4KSl4KWH4KSl4KWA4KSY4KSw4KSc4KSs4KSm4KWA4KSV4KSI4KSc4KWA4KS14KWH4KSo4KSI4KSo4KSP4KS54KSw4KSJ4KS44KSu4KWH4KSV4KSu4KS14KWL4KSy4KWH4KS44KSs4KSu4KSI4KSm4KWH4KST4KSw4KSG4KSu4KSs4KS44KSt4KSw4KSs4KSo4KSa4KSy4KSu4KSo4KSG4KSX4KS44KWA4KSy4KWA2LnZhNmJ2KXZhNmJ2YfYsNin2KLYrtix2LnYr9iv2KfZhNmJ2YfYsNmH2LXZiNix2LrZitix2YPYp9mG2YjZhNin2KjZitmG2LnYsdi22LDZhNmD2YfZhtin2YrZiNmF2YLYp9mE2LnZhNmK2KfZhtin2YTZg9mG2K3YqtmJ2YLYqNmE2YjYrdip2KfYrtix2YHZgti32LnYqNiv2LHZg9mG2KXYsNin2YPZhdin2KfYrdiv2KXZhNin2YHZitmH2KjYudi22YPZitmB2KjYrdir2YjZhdmG2YjZh9mI2KPZhtin2KzYr9in2YTZh9in2LPZhNmF2LnZhtiv2YTZitiz2LnYqNix2LXZhNmJ2YXZhtiw2KjZh9in2KPZhtmH2YXYq9mE2YPZhtiq2KfZhNin2K3Zitir2YXYtdix2LTYsdit2K3ZiNmE2YjZgdmK2KfYsNin2YTZg9mE2YXYsdip2KfZhtiq2KfZhNmB2KPYqNmI2K7Yp9i12KPZhtiq2KfZhtmH2KfZhNmK2LnYttmI2YjZgtiv2KfYqNmG2K7Zitix2KjZhtiq2YTZg9mF2LTYp9ih2YjZh9mK2KfYqNmI2YLYtdi12YjZhdin2LHZgtmF2KPYrdiv2YbYrdmG2LnYr9mF2LHYo9mK2KfYrdip2YPYqtio2K/ZiNmG2YrYrNio2YXZhtmH2KrYrdiq2KzZh9ip2LPZhtip2YrYqtmF2YPYsdip2LrYstip2YbZgdiz2KjZitiq2YTZhNmH2YTZhtin2KrZhNmD2YLZhNio2YTZhdin2LnZhtmH2KPZiNmE2LTZitih2YbZiNix2KPZhdin2YHZitmD2KjZg9mE2LDYp9iq2LHYqtio2KjYo9mG2YfZhdiz2KfZhtmD2KjZiti52YHZgtiv2K3Ys9mG2YTZh9mF2LTYudix2KPZh9mE2LTZh9ix2YLYt9ix2LfZhNiocHJvZmlsZXNlcnZpY2VkZWZhdWx0aGltc2VsZmRldGFpbHNjb250ZW50c3VwcG9ydHN0YXJ0ZWRtZXNzYWdlc3VjY2Vzc2Zhc2hpb248dGl0bGU+Y291bnRyeWFjY291bnRjcmVhdGVkc3Rvcmllc3Jlc3VsdHNydW5uaW5ncHJvY2Vzc3dyaXRpbmdvYmplY3RzdmlzaWJsZXdlbGNvbWVhcnRpY2xldW5rbm93bm5ldHdvcmtjb21wYW55ZHluYW1pY2Jyb3dzZXJwcml2YWN5cHJvYmxlbVNlcnZpY2VyZXNwZWN0ZGlzcGxheXJlcXVlc3RyZXNlcnZld2Vic2l0ZWhpc3RvcnlmcmllbmRzb3B0aW9uc3dvcmtpbmd2ZXJzaW9ubWlsbGlvbmNoYW5uZWx3aW5kb3cuYWRkcmVzc3Zpc2l0ZWR3ZWF0aGVyY29ycmVjdHByb2R1Y3RlZGlyZWN0Zm9yd2FyZHlvdSBjYW5yZW1vdmVkc3ViamVjdGNvbnRyb2xhcmNoaXZlY3VycmVudHJlYWRpbmdsaWJyYXJ5bGltaXRlZG1hbmFnZXJmdXJ0aGVyc3VtbWFyeW1hY2hpbmVtaW51dGVzcHJpdmF0ZWNvbnRleHRwcm9ncmFtc29jaWV0eW51bWJlcnN3cml0dGVuZW5hYmxlZHRyaWdnZXJzb3VyY2VzbG9hZGluZ2VsZW1lbnRwYXJ0bmVyZmluYWxseXBlcmZlY3RtZWFuaW5nc3lzdGVtc2tlZXBpbmdjdWx0dXJlJnF1b3Q7LGpvdXJuYWxwcm9qZWN0c3VyZmFjZXMmcXVvdDtleHBpcmVzcmV2aWV3c2JhbGFuY2VFbmdsaXNoQ29udGVudHRocm91Z2hQbGVhc2Ugb3BpbmlvbmNvbnRhY3RhdmVyYWdlcHJpbWFyeXZpbGxhZ2VTcGFuaXNoZ2FsbGVyeWRlY2xpbmVtZWV0aW5nbWlzc2lvbnBvcHVsYXJxdWFsaXR5bWVhc3VyZWdlbmVyYWxzcGVjaWVzc2Vzc2lvbnNlY3Rpb253cml0ZXJzY291bnRlcmluaXRpYWxyZXBvcnRzZmlndXJlc21lbWJlcnNob2xkaW5nZGlzcHV0ZWVhcmxpZXJleHByZXNzZGlnaXRhbHBpY3R1cmVBbm90aGVybWFycmllZHRyYWZmaWNsZWFkaW5nY2hhbmdlZGNlbnRyYWx2aWN0b3J5aW1hZ2VzL3JlYXNvbnNzdHVkaWVzZmVhdHVyZWxpc3RpbmdtdXN0IGJlc2Nob29sc1ZlcnNpb251c3VhbGx5ZXBpc29kZXBsYXlpbmdncm93aW5nb2J2aW91c292ZXJsYXlwcmVzZW50YWN0aW9uczwvdWw+DQp3cmFwcGVyYWxyZWFkeWNlcnRhaW5yZWFsaXR5c3RvcmFnZWFub3RoZXJkZXNrdG9wb2ZmZXJlZHBhdHRlcm51bnVzdWFsRGlnaXRhbGNhcGl0YWxXZWJzaXRlZmFpbHVyZWNvbm5lY3RyZWR1Y2VkQW5kcm9pZGRlY2FkZXNyZWd1bGFyICZhbXA7IGFuaW1hbHNyZWxlYXNlQXV0b21hdGdldHRpbmdtZXRob2Rzbm90aGluZ1BvcHVsYXJjYXB0aW9ubGV0dGVyc2NhcHR1cmVzY2llbmNlbGljZW5zZWNoYW5nZXNFbmdsYW5kPTEmYW1wO0hpc3RvcnkgPSBuZXcgQ2VudHJhbHVwZGF0ZWRTcGVjaWFsTmV0d29ya3JlcXVpcmVjb21tZW50d2FybmluZ0NvbGxlZ2V0b29sYmFycmVtYWluc2JlY2F1c2VlbGVjdGVkRGV1dHNjaGZpbmFuY2V3b3JrZXJzcXVpY2tseWJldHdlZW5leGFjdGx5c2V0dGluZ2Rpc2Vhc2VTb2NpZXR5d2VhcG9uc2V4aGliaXQmbHQ7IS0tQ29udHJvbGNsYXNzZXNjb3ZlcmVkb3V0bGluZWF0dGFja3NkZXZpY2VzKHdpbmRvd3B1cnBvc2V0aXRsZT0iTW9iaWxlIGtpbGxpbmdzaG93aW5nSXRhbGlhbmRyb3BwZWRoZWF2aWx5ZWZmZWN0cy0xJ10pOwpjb25maXJtQ3VycmVudGFkdmFuY2VzaGFyaW5nb3BlbmluZ2RyYXdpbmdiaWxsaW9ub3JkZXJlZEdlcm1hbnlyZWxhdGVkPC9mb3JtPmluY2x1ZGV3aGV0aGVyZGVmaW5lZFNjaWVuY2VjYXRhbG9nQXJ0aWNsZWJ1dHRvbnNsYXJnZXN0dW5pZm9ybWpvdXJuZXlzaWRlYmFyQ2hpY2Fnb2hvbGlkYXlHZW5lcmFscGFzc2FnZSwmcXVvdDthbmltYXRlZmVlbGluZ2Fycml2ZWRwYXNzaW5nbmF0dXJhbHJvdWdobHkuCgpUaGUgYnV0IG5vdGRlbnNpdHlCcml0YWluQ2hpbmVzZWxhY2sgb2Z0cmlidXRlSXJlbGFuZCIgZGF0YS1mYWN0b3JzcmVjZWl2ZXRoYXQgaXNMaWJyYXJ5aHVzYmFuZGluIGZhY3RhZmZhaXJzQ2hhcmxlc3JhZGljYWxicm91Z2h0ZmluZGluZ2xhbmRpbmc6bGFuZz0icmV0dXJuIGxlYWRlcnNwbGFubmVkcHJlbWl1bXBhY2thZ2VBbWVyaWNhRWRpdGlvbl0mcXVvdDtNZXNzYWdlbmVlZCB0b3ZhbHVlPSJjb21wbGV4bG9va2luZ3N0YXRpb25iZWxpZXZlc21hbGxlci1tb2JpbGVyZWNvcmRzd2FudCB0b2tpbmQgb2ZGaXJlZm94eW91IGFyZXNpbWlsYXJzdHVkaWVkbWF4aW11bWhlYWRpbmdyYXBpZGx5Y2xpbWF0ZWtpbmdkb21lbWVyZ2VkYW1vdW50c2ZvdW5kZWRwaW9uZWVyZm9ybXVsYWR5bmFzdHlob3cgdG8gU3VwcG9ydHJldmVudWVlY29ub215UmVzdWx0c2Jyb3RoZXJzb2xkaWVybGFyZ2VseWNhbGxpbmcuJnF1b3Q7QWNjb3VudEVkd2FyZCBzZWdtZW50Um9iZXJ0IGVmZm9ydHNQYWNpZmljbGVhcm5lZHVwIHdpdGhoZWlnaHQ6d2UgaGF2ZUFuZ2VsZXNuYXRpb25zX3NlYXJjaGFwcGxpZWRhY3F1aXJlbWFzc2l2ZWdyYW50ZWQ6IGZhbHNldHJlYXRlZGJpZ2dlc3RiZW5lZml0ZHJpdmluZ1N0dWRpZXNtaW5pbXVtcGVyaGFwc21vcm5pbmdzZWxsaW5naXMgdXNlZHJldmVyc2V2YXJpYW50IHJvbGU9Im1pc3NpbmdhY2hpZXZlcHJvbW90ZXN0dWRlbnRzb21lb25lZXh0cmVtZXJlc3RvcmVib3R0b206ZXZvbHZlZGFsbCB0aGVzaXRlbWFwZW5nbGlzaHdheSB0byAgQXVndXN0c3ltYm9sc0NvbXBhbnltYXR0ZXJzbXVzaWNhbGFnYWluc3RzZXJ2aW5nfSkoKTsNCnBheW1lbnR0cm91YmxlY29uY2VwdGNvbXBhcmVwYXJlbnRzcGxheWVyc3JlZ2lvbnNtb25pdG9yICcnVGhlIHdpbm5pbmdleHBsb3JlYWRhcHRlZEdhbGxlcnlwcm9kdWNlYWJpbGl0eWVuaGFuY2VjYXJlZXJzKS4gVGhlIGNvbGxlY3RTZWFyY2ggYW5jaWVudGV4aXN0ZWRmb290ZXIgaGFuZGxlcnByaW50ZWRjb25zb2xlRWFzdGVybmV4cG9ydHN3aW5kb3dzQ2hhbm5lbGlsbGVnYWxuZXV0cmFsc3VnZ2VzdF9oZWFkZXJzaWduaW5nLmh0bWwiPnNldHRsZWR3ZXN0ZXJuY2F1c2luZy13ZWJraXRjbGFpbWVkSnVzdGljZWNoYXB0ZXJ2aWN0aW1zVGhvbWFzIG1vemlsbGFwcm9taXNlcGFydGllc2VkaXRpb25vdXRzaWRlOmZhbHNlLGh1bmRyZWRPbHltcGljX2J1dHRvbmF1dGhvcnNyZWFjaGVkY2hyb25pY2RlbWFuZHNzZWNvbmRzcHJvdGVjdGFkb3B0ZWRwcmVwYXJlbmVpdGhlcmdyZWF0bHlncmVhdGVyb3ZlcmFsbGltcHJvdmVjb21tYW5kc3BlY2lhbHNlYXJjaC53b3JzaGlwZnVuZGluZ3Rob3VnaHRoaWdoZXN0aW5zdGVhZHV0aWxpdHlxdWFydGVyQ3VsdHVyZXRlc3RpbmdjbGVhcmx5ZXhwb3NlZEJyb3dzZXJsaWJlcmFsfSBjYXRjaFByb2plY3RleGFtcGxlaGlkZSgpO0Zsb3JpZGFhbnN3ZXJzYWxsb3dlZEVtcGVyb3JkZWZlbnNlc2VyaW91c2ZyZWVkb21TZXZlcmFsLWJ1dHRvbkZ1cnRoZXJvdXQgb2YgIT0gbnVsbHRyYWluZWREZW5tYXJrdm9pZCgwKS9hbGwuanNwcmV2ZW50UmVxdWVzdFN0ZXBoZW4KCldoZW4gb2JzZXJ2ZTwvaDI+DQpNb2Rlcm4gcHJvdmlkZSIgYWx0PSJib3JkZXJzLgoKRm9yIAoKTWFueSBhcnRpc3RzcG93ZXJlZHBlcmZvcm1maWN0aW9udHlwZSBvZm1lZGljYWx0aWNrZXRzb3Bwb3NlZENvdW5jaWx3aXRuZXNzanVzdGljZUdlb3JnZSBCZWxnaXVtLi4uPC9hPnR3aXR0ZXJub3RhYmx5d2FpdGluZ3dhcmZhcmUgT3RoZXIgcmFua2luZ3BocmFzZXNtZW50aW9uc3Vydml2ZXNjaG9sYXI8L3A+DQogQ291bnRyeWlnbm9yZWRsb3NzIG9manVzdCBhc0dlb3JnaWFzdHJhbmdlPGhlYWQ+PHN0b3BwZWQxJ10pOw0KaXNsYW5kc25vdGFibGVib3JkZXI6bGlzdCBvZmNhcnJpZWQxMDAsMDAwPC9oMz4KIHNldmVyYWxiZWNvbWVzc2VsZWN0IHdlZGRpbmcwMC5odG1sbW9uYXJjaG9mZiB0aGV0ZWFjaGVyaGlnaGx5IGJpb2xvZ3lsaWZlIG9mb3IgZXZlbnJpc2Ugb2YmcmFxdW87cGx1c29uZWh1bnRpbmcodGhvdWdoRG91Z2xhc2pvaW5pbmdjaXJjbGVzRm9yIHRoZUFuY2llbnRWaWV0bmFtdmVoaWNsZXN1Y2ggYXNjcnlzdGFsdmFsdWUgPVdpbmRvd3NlbmpveWVkYSBzbWFsbGFzc3VtZWQ8YSBpZD0iZm9yZWlnbiBBbGwgcmlob3cgdGhlRGlzcGxheXJldGlyZWRob3dldmVyaGlkZGVuO2JhdHRsZXNzZWVraW5nY2FiaW5ldHdhcyBub3Rsb29rIGF0Y29uZHVjdGdldCB0aGVKYW51YXJ5aGFwcGVuc3R1cm5pbmdhOmhvdmVyT25saW5lIEZyZW5jaCBsYWNraW5ndHlwaWNhbGV4dHJhY3RlbmVtaWVzZXZlbiBpZmdlbmVyYXRkZWNpZGVkYXJlIG5vdC9zZWFyY2hiZWxpZWZzLWltYWdlOmxvY2F0ZWRzdGF0aWMubG9naW4iPmNvbnZlcnR2aW9sZW50ZW50ZXJlZGZpcnN0Ij5jaXJjdWl0RmlubGFuZGNoZW1pc3RzaGUgd2FzMTBweDsiPmFzIHN1Y2hkaXZpZGVkPC9zcGFuPndpbGwgYmVsaW5lIG9mYSBncmVhdG15c3RlcnkvaW5kZXguZmFsbGluZ2R1ZSB0byByYWlsd2F5Y29sbGVnZW1vbnN0ZXJkZXNjZW50aXQgd2l0aG51Y2xlYXJKZXdpc2ggcHJvdGVzdEJyaXRpc2hmbG93ZXJzcHJlZGljdHJlZm9ybXNidXR0b24gd2hvIHdhc2xlY3R1cmVpbnN0YW50c3VpY2lkZWdlbmVyaWNwZXJpb2RzbWFya2V0c1NvY2lhbCBmaXNoaW5nY29tYmluZWdyYXBoaWN3aW5uZXJzPGJyIC8+PGJ5IHRoZSBOYXR1cmFsUHJpdmFjeWNvb2tpZXNvdXRjb21lcmVzb2x2ZVN3ZWRpc2hicmllZmx5UGVyc2lhbnNvIG11Y2hDZW50dXJ5ZGVwaWN0c2NvbHVtbnNob3VzaW5nc2NyaXB0c25leHQgdG9iZWFyaW5nbWFwcGluZ3JldmlzZWRqUXVlcnkoLXdpZHRoOnRpdGxlIj50b29sdGlwU2VjdGlvbmRlc2lnbnNUdXJraXNoeW91bmdlci5tYXRjaCh9KSgpOwoKYnVybmluZ29wZXJhdGVkZWdyZWVzc291cmNlPVJpY2hhcmRjbG9zZWx5cGxhc3RpY2VudHJpZXM8L3RyPg0KY29sb3I6I3VsIGlkPSJwb3NzZXNzcm9sbGluZ3BoeXNpY3NmYWlsaW5nZXhlY3V0ZWNvbnRlc3RsaW5rIHRvRGVmYXVsdDxiciAvPgo6IHRydWUsY2hhcnRlcnRvdXJpc21jbGFzc2ljcHJvY2VlZGV4cGxhaW48L2gxPg0Kb25saW5lLj94bWwgdmVoZWxwaW5nZGlhbW9uZHVzZSB0aGVhaXJsaW5lZW5kIC0tPikuYXR0cihyZWFkZXJzaG9zdGluZyNmZmZmZmZyZWFsaXplVmluY2VudHNpZ25hbHMgc3JjPSIvUHJvZHVjdGRlc3BpdGVkaXZlcnNldGVsbGluZ1B1YmxpYyBoZWxkIGluSm9zZXBoIHRoZWF0cmVhZmZlY3RzPHN0eWxlPmEgbGFyZ2Vkb2Vzbid0bGF0ZXIsIEVsZW1lbnRmYXZpY29uY3JlYXRvckh1bmdhcnlBaXJwb3J0c2VlIHRoZXNvIHRoYXRNaWNoYWVsU3lzdGVtc1Byb2dyYW1zLCBhbmQgIHdpZHRoPWUmcXVvdDt0cmFkaW5nbGVmdCI+CnBlcnNvbnNHb2xkZW4gQWZmYWlyc2dyYW1tYXJmb3JtaW5nZGVzdHJveWlkZWEgb2ZjYXNlIG9mb2xkZXN0IHRoaXMgaXMuc3JjID0gY2FydG9vbnJlZ2lzdHJDb21tb25zTXVzbGltc1doYXQgaXNpbiBtYW55bWFya2luZ3JldmVhbHNJbmRlZWQsZXF1YWxseS9zaG93X2FvdXRkb29yZXNjYXBlKEF1c3RyaWFnZW5ldGljc3lzdGVtLEluIHRoZSBzaXR0aW5nSGUgYWxzb0lzbGFuZHNBY2FkZW15CgkJPCEtLURhbmllbCBiaW5kaW5nYmxvY2siPmltcG9zZWR1dGlsaXplQWJyYWhhbShleGNlcHR7d2lkdGg6cHV0dGluZykuaHRtbCh8fCBbXTsKREFUQVsgKmtpdGNoZW5tb3VudGVkYWN0dWFsIGRpYWxlY3RtYWlubHkgX2JsYW5rJ2luc3RhbGxleHBlcnRzaWYodHlwZUl0IGFsc28mY29weTsgIj5UZXJtc2Jvcm4gaW5PcHRpb25zZWFzdGVybnRhbGtpbmdjb25jZXJuZ2FpbmVkIG9uZ29pbmdqdXN0aWZ5Y3JpdGljc2ZhY3RvcnlpdHMgb3duYXNzYXVsdGludml0ZWRsYXN0aW5naGlzIG93bmhyZWY9Ii8iIHJlbD0iZGV2ZWxvcGNvbmNlcnRkaWFncmFtZG9sbGFyc2NsdXN0ZXJwaHA/aWQ9YWxjb2hvbCk7fSkoKTt1c2luZyBhPjxzcGFuPnZlc3NlbHNyZXZpdmFsQWRkcmVzc2FtYXRldXJhbmRyb2lkYWxsZWdlZGlsbG5lc3N3YWxraW5nY2VudGVyc3F1YWxpZnltYXRjaGVzdW5pZmllZGV4dGluY3REZWZlbnNlZGllZCBpbgoJPCEtLSBjdXN0b21zbGlua2luZ0xpdHRsZSBCb29rIG9mZXZlbmluZ21pbi5qcz9hcmUgdGhla29udGFrdHRvZGF5J3MuaHRtbCIgdGFyZ2V0PXdlYXJpbmdBbGwgUmlnOwp9KSgpO3JhaXNpbmcgQWxzbywgY3J1Y2lhbGFib3V0Ij5kZWNsYXJlLS0+CjxzY2ZpcmVmb3hhcyBtdWNoYXBwbGllc2luZGV4LCBzLCBidXQgdHlwZSA9IAoNCjwhLS10b3dhcmRzUmVjb3Jkc1ByaXZhdGVGb3JlaWduUHJlbWllcmNob2ljZXNWaXJ0dWFscmV0dXJuc0NvbW1lbnRQb3dlcmVkaW5saW5lO3BvdmVydHljaGFtYmVyTGl2aW5nIHZvbHVtZXNBbnRob255bG9naW4iIFJlbGF0ZWRFY29ub215cmVhY2hlc2N1dHRpbmdncmF2aXR5bGlmZSBpbkNoYXB0ZXItc2hhZG93Tm90YWJsZTwvdGQ+DQogcmV0dXJuc3RhZGl1bXdpZGdldHN2YXJ5aW5ndHJhdmVsc2hlbGQgYnl3aG8gYXJld29yayBpbmZhY3VsdHlhbmd1bGFyd2hvIGhhZGFpcnBvcnR0b3duIG9mCgpTb21lICdjbGljaydjaGFyZ2Vza2V5d29yZGl0IHdpbGxjaXR5IG9mKHRoaXMpO0FuZHJldyB1bmlxdWUgY2hlY2tlZG9yIG1vcmUzMDBweDsgcmV0dXJuO3JzaW9uPSJwbHVnaW5zd2l0aGluIGhlcnNlbGZTdGF0aW9uRmVkZXJhbHZlbnR1cmVwdWJsaXNoc2VudCB0b3RlbnNpb25hY3RyZXNzY29tZSB0b2ZpbmdlcnNEdWtlIG9mcGVvcGxlLGV4cGxvaXR3aGF0IGlzaGFybW9ueWEgbWFqb3IiOiJodHRwaW4gaGlzIG1lbnUiPgptb250aGx5b2ZmaWNlcmNvdW5jaWxnYWluaW5nZXZlbiBpblN1bW1hcnlkYXRlIG9mbG95YWx0eWZpdG5lc3NhbmQgd2FzZW1wZXJvcnN1cHJlbWVTZWNvbmQgaGVhcmluZ1J1c3NpYW5sb25nZXN0QWxiZXJ0YWxhdGVyYWxzZXQgb2Ygc21hbGwiPi5hcHBlbmRkbyB3aXRoZmVkZXJhbGJhbmsgb2ZiZW5lYXRoRGVzcGl0ZUNhcGl0YWxncm91bmRzKSwgYW5kIHBlcmNlbnRpdCBmcm9tY2xvc2luZ2NvbnRhaW5JbnN0ZWFkZmlmdGVlbmFzIHdlbGwueWFob28ucmVzcG9uZGZpZ2h0ZXJvYnNjdXJlcmVmbGVjdG9yZ2FuaWM9IE1hdGguZWRpdGluZ29ubGluZSBwYWRkaW5nYSB3aG9sZW9uZXJyb3J5ZWFyIG9mZW5kIG9mIGJhcnJpZXJ3aGVuIGl0aGVhZGVyIGhvbWUgb2ZyZXN1bWVkcmVuYW1lZHN0cm9uZz5oZWF0aW5ncmV0YWluc2Nsb3VkZnJ3YXkgb2YgTWFyY2ggMWtub3dpbmdpbiBwYXJ0QmV0d2Vlbmxlc3NvbnNjbG9zZXN0dmlydHVhbGxpbmtzIj5jcm9zc2VkRU5EIC0tPmZhbW91cyBhd2FyZGVkTGljZW5zZUhlYWx0aCBmYWlybHkgd2VhbHRoeW1pbmltYWxBZnJpY2FuY29tcGV0ZWxhYmVsIj5zaW5naW5nZmFybWVyc0JyYXNpbClkaXNjdXNzcmVwbGFjZUdyZWdvcnlmb250IGNvcHVyc3VlZGFwcGVhcnNtYWtlIHVwcm91bmRlZGJvdGggb2ZibG9ja2Vkc2F3IHRoZW9mZmljZXNjb2xvdXJzaWYoZG9jdXdoZW4gaGVlbmZvcmNlcHVzaChmdUF1Z3VzdCBVVEYtOCI+RmFudGFzeWluIG1vc3Rpbmp1cmVkVXN1YWxseWZhcm1pbmdjbG9zdXJlb2JqZWN0IGRlZmVuY2V1c2Ugb2YgTWVkaWNhbDxib2R5PgpldmlkZW50YmUgdXNlZGtleUNvZGVzaXh0ZWVuSXNsYW1pYyMwMDAwMDBlbnRpcmUgd2lkZWx5IGFjdGl2ZSAodHlwZW9mb25lIGNhbmNvbG9yID1zcGVha2VyZXh0ZW5kc1BoeXNpY3N0ZXJyYWluPHRib2R5PmZ1bmVyYWx2aWV3aW5nbWlkZGxlIGNyaWNrZXRwcm9waGV0c2hpZnRlZGRvY3RvcnNSdXNzZWxsIHRhcmdldGNvbXBhY3RhbGdlYnJhc29jaWFsLWJ1bGsgb2ZtYW4gYW5kPC90ZD4KIGhlIGxlZnQpLnZhbCgpZmFsc2UpO2xvZ2ljYWxiYW5raW5naG9tZSB0b25hbWluZyBBcml6b25hY3JlZGl0cyk7Cn0pOwpmb3VuZGVyaW4gdHVybkNvbGxpbnNiZWZvcmUgQnV0IHRoZWNoYXJnZWRUaXRsZSI+Q2FwdGFpbnNwZWxsZWRnb2RkZXNzVGFnIC0tPkFkZGluZzpidXQgd2FzUmVjZW50IHBhdGllbnRiYWNrIGluPWZhbHNlJkxpbmNvbG53ZSBrbm93Q291bnRlckp1ZGFpc21zY3JpcHQgYWx0ZXJlZCddKTsKICBoYXMgdGhldW5jbGVhckV2ZW50Jyxib3RoIGlubm90IGFsbAoKPCEtLSBwbGFjaW5naGFyZCB0byBjZW50ZXJzb3J0IG9mY2xpZW50c3N0cmVldHNCZXJuYXJkYXNzZXJ0c3RlbmQgdG9mYW50YXN5ZG93biBpbmhhcmJvdXJGcmVlZG9tamV3ZWxyeS9hYm91dC4uc2VhcmNobGVnZW5kc2lzIG1hZGVtb2Rlcm4gb25seSBvbm9ubHkgdG9pbWFnZSIgbGluZWFyIHBhaW50ZXJhbmQgbm90cmFyZWx5IGFjcm9ueW1kZWxpdmVyc2hvcnRlcjAwJmFtcDthcyBtYW55d2lkdGg9Ii8qIDwhW0N0aXRsZSA9b2YgdGhlIGxvd2VzdCBwaWNrZWQgZXNjYXBlZHVzZXMgb2ZwZW9wbGVzIFB1YmxpY01hdHRoZXd0YWN0aWNzZGFtYWdlZHdheSBmb3JsYXdzIG9mZWFzeSB0byB3aW5kb3dzdHJvbmcgIHNpbXBsZX1jYXRjaChzZXZlbnRoaW5mb2JveHdlbnQgdG9wYWludGVkY2l0aXplbkkgZG9uJ3RyZXRyZWF0LiBTb21lIHd3LiIpOwpib21iaW5nbWFpbHRvOm1hZGUgaW4uIE1hbnkgY2Fycmllc3x8e307d2l3b3JrIG9mc3lub255bWRlZmVhdHNmYXZvcmVkb3B0aWNhbHBhZ2VUcmF1bmxlc3Mgc2VuZGluZ2xlZnQiPjxjb21TY29yQWxsIHRoZWpRdWVyeS50b3VyaXN0Q2xhc3NpY2ZhbHNlIiBXaWxoZWxtc3VidXJic2dlbnVpbmViaXNob3BzLnNwbGl0KGdsb2JhbCBmb2xsb3dzYm9keSBvZm5vbWluYWxDb250YWN0c2VjdWxhcmxlZnQgdG9jaGllZmx5LWhpZGRlbi1iYW5uZXI8L2xpPgoKLiBXaGVuIGluIGJvdGhkaXNtaXNzRXhwbG9yZWFsd2F5cyB2aWEgdGhlc3Bhw7FvbHdlbGZhcmVydWxpbmcgYXJyYW5nZWNhcHRhaW5oaXMgc29ucnVsZSBvZmhlIHRvb2tpdHNlbGYsPTAmYW1wOyhjYWxsZWRzYW1wbGVzdG8gbWFrZWNvbS9wYWdNYXJ0aW4gS2VubmVkeWFjY2VwdHNmdWxsIG9maGFuZGxlZEJlc2lkZXMvLy0tPjwvYWJsZSB0b3RhcmdldHNlc3NlbmNlaGltIHRvIGl0cyBieSBjb21tb24ubWluZXJhbHRvIHRha2V3YXlzIHRvcy5vcmcvbGFkdmlzZWRwZW5hbHR5c2ltcGxlOmlmIHRoZXlMZXR0ZXJzYSBzaG9ydEhlcmJlcnRzdHJpa2VzIGdyb3Vwcy5sZW5ndGhmbGlnaHRzb3ZlcmxhcHNsb3dseSBsZXNzZXIgc29jaWFsIDwvcD4KCQlpdCBpbnRvcmFua2VkIHJhdGUgb2Z1bD4NCiAgYXR0ZW1wdHBhaXIgb2ZtYWtlIGl0S29udGFrdEFudG9uaW9oYXZpbmcgcmF0aW5ncyBhY3RpdmVzdHJlYW1zdHJhcHBlZCIpLmNzcyhob3N0aWxlbGVhZCB0b2xpdHRsZSBncm91cHMsUGljdHVyZS0tPg0KDQogcm93cz0iIG9iamVjdGludmVyc2U8Zm9vdGVyQ3VzdG9tVj48XC9zY3Jzb2x2aW5nQ2hhbWJlcnNsYXZlcnl3b3VuZGVkd2hlcmVhcyE9ICd1bmRmb3IgYWxscGFydGx5IC1yaWdodDpBcmFiaWFuYmFja2VkIGNlbnR1cnl1bml0IG9mbW9iaWxlLUV1cm9wZSxpcyBob21lcmlzayBvZmRlc2lyZWRDbGludG9uY29zdCBvZmFnZSBvZiBiZWNvbWUgbm9uZSBvZnAmcXVvdDtNaWRkbGUgZWFkJylbMENyaXRpY3NzdHVkaW9zPiZjb3B5O2dyb3VwIj5hc3NlbWJsbWFraW5nIHByZXNzZWR3aWRnZXQucHM6IiA/IHJlYnVpbHRieSBzb21lRm9ybWVyIGVkaXRvcnNkZWxheWVkQ2Fub25pY2hhZCB0aGVwdXNoaW5nY2xhc3M9ImJ1dCBhcmVwYXJ0aWFsQmFieWxvbmJvdHRvbSBjYXJyaWVyQ29tbWFuZGl0cyB1c2VBcyB3aXRoY291cnNlc2EgdGhpcmRkZW5vdGVzYWxzbyBpbkhvdXN0b24yMHB4OyI+YWNjdXNlZGRvdWJsZSBnb2FsIG9mRmFtb3VzICkuYmluZChwcmllc3RzIE9ubGluZWluIEp1bHlzdCArICJnY29uc3VsdGRlY2ltYWxoZWxwZnVscmV2aXZlZGlzIHZlcnlyJysnaXB0bG9zaW5nIGZlbWFsZXNpcyBhbHNvc3RyaW5nc2RheXMgb2ZhcnJpdmFsZnV0dXJlIDxvYmplY3Rmb3JjaW5nU3RyaW5nKCIgLz4KCQloZXJlIGlzZW5jb2RlZC4gIFRoZSBiYWxsb29uZG9uZSBieS9jb21tb25iZ2NvbG9ybGF3IG9mIEluZGlhbmFhdm9pZGVkYnV0IHRoZTJweCAzcHhqcXVlcnkuYWZ0ZXIgYXBvbGljeS5tZW4gYW5kZm9vdGVyLT0gdHJ1ZTtmb3IgdXNlc2NyZWVuLkluZGlhbiBpbWFnZSA9ZmFtaWx5LGh0dHA6Ly8gJm5ic3A7ZHJpdmVyc2V0ZXJuYWxzYW1lIGFzbm90aWNlZHZpZXdlcnN9KSgpOwogaXMgbW9yZXNlYXNvbnNmb3JtZXIgdGhlIG5ld2lzIGp1c3Rjb25zZW50IFNlYXJjaHdhcyB0aGV3aHkgdGhlc2hpcHBlZGJyPjxicj53aWR0aDogaGVpZ2h0PW1hZGUgb2ZjdWlzaW5laXMgdGhhdGEgdmVyeSBBZG1pcmFsIGZpeGVkO25vcm1hbCBNaXNzaW9uUHJlc3MsIG9udGFyaW9jaGFyc2V0dHJ5IHRvIGludmFkZWQ9InRydWUic3BhY2luZ2lzIG1vc3RhIG1vcmUgdG90YWxseWZhbGwgb2Z9KTsNCiAgaW1tZW5zZXRpbWUgaW5zZXQgb3V0c2F0aXNmeXRvIGZpbmRkb3duIHRvbG90IG9mIFBsYXllcnNpbiBKdW5lcXVhbnR1bW5vdCB0aGV0aW1lIHRvZGlzdGFudEZpbm5pc2hzcmMgPSAoc2luZ2xlIGhlbHAgb2ZHZXJtYW4gbGF3IGFuZGxhYmVsZWRmb3Jlc3RzY29va2luZ3NwYWNlIj5oZWFkZXItd2VsbCBhc1N0YW5sZXlicmlkZ2VzL2dsb2JhbENyb2F0aWEgQWJvdXQgWzBdOwogIGl0LCBhbmRncm91cGVkYmVpbmcgYSl7dGhyb3doZSBtYWRlbGlnaHRlcmV0aGljYWxGRkZGRkYiYm90dG9tImxpa2UgYSBlbXBsb3lzbGl2ZSBpbmFzIHNlZW5wcmludGVybW9zdCBvZnViLWxpbmtyZWplY3RzYW5kIHVzZWltYWdlIj5zdWNjZWVkZmVlZGluZ051Y2xlYXJpbmZvcm1hdG8gaGVscFdvbWVuJ3NOZWl0aGVyTWV4aWNhbnByb3RlaW48dGFibGUgYnkgbWFueWhlYWx0aHlsYXdzdWl0ZGV2aXNlZC5wdXNoKHtzZWxsZXJzc2ltcGx5IFRocm91Z2guY29va2llIEltYWdlKG9sZGVyIj51cy5qcyI+IFNpbmNlIHVuaXZlcnNsYXJnZXIgb3BlbiB0byEtLSBlbmRsaWVzIGluJ10pOw0KICBtYXJrZXR3aG8gaXMgKCJET01Db21hbmFnZWRvbmUgZm9ydHlwZW9mIEtpbmdkb21wcm9maXRzcHJvcG9zZXRvIHNob3djZW50ZXI7bWFkZSBpdGRyZXNzZWR3ZXJlIGlubWl4dHVyZXByZWNpc2VhcmlzaW5nc3JjID0gJ21ha2UgYSBzZWN1cmVkQmFwdGlzdHZvdGluZyAKCQl2YXIgTWFyY2ggMmdyZXcgdXBDbGltYXRlLnJlbW92ZXNraWxsZWR3YXkgdGhlPC9oZWFkPmZhY2Ugb2ZhY3RpbmcgcmlnaHQiPnRvIHdvcmtyZWR1Y2VzaGFzIGhhZGVyZWN0ZWRzaG93KCk7YWN0aW9uPWJvb2sgb2ZhbiBhcmVhPT0gImh0dDxoZWFkZXIKPGh0bWw+Y29uZm9ybWZhY2luZyBjb29raWUucmVseSBvbmhvc3RlZCAuY3VzdG9taGUgd2VudGJ1dCBmb3JzcHJlYWQgRmFtaWx5IGEgbWVhbnNvdXQgdGhlZm9ydW1zLmZvb3RhZ2UiPk1vYmlsQ2xlbWVudHMiIGlkPSJhcyBoaWdoaW50ZW5zZS0tPjwhLS1mZW1hbGUgaXMgc2VlbmltcGxpZWRzZXQgdGhlYSBzdGF0ZWFuZCBoaXNmYXN0ZXN0YmVzaWRlc2J1dHRvbl9ib3VuZGVkIj48aW1nIEluZm9ib3hldmVudHMsYSB5b3VuZ2FuZCBhcmVOYXRpdmUgY2hlYXBlclRpbWVvdXRhbmQgaGFzZW5naW5lc3dvbiB0aGUobW9zdGx5cmlnaHQ6IGZpbmQgYSAtYm90dG9tUHJpbmNlIGFyZWEgb2Ztb3JlIG9mc2VhcmNoX25hdHVyZSxsZWdhbGx5cGVyaW9kLGxhbmQgb2ZvciB3aXRoaW5kdWNlZHByb3ZpbmdtaXNzaWxlbG9jYWxseUFnYWluc3R0aGUgd2F5ayZxdW90O3B4OyI+DQpwdXNoZWQgYWJhbmRvbm51bWVyYWxDZXJ0YWluSW4gdGhpc21vcmUgaW5vciBzb21lbmFtZSBpc2FuZCwgaW5jcm93bmVkSVNCTiAwLWNyZWF0ZXNPY3RvYmVybWF5IG5vdGNlbnRlciBsYXRlIGluRGVmZW5jZWVuYWN0ZWR3aXNoIHRvYnJvYWRseWNvb2xpbmdvbmxvYWQ9aXQuIFRoZXJlY292ZXJNZW1iZXJzaGVpZ2h0IGFzc3VtZXM8aHRtbD4KcGVvcGxlLmluIG9uZSA9d2luZG93Zm9vdGVyX2EgZ29vZCByZWtsYW1hb3RoZXJzLHRvIHRoaXNfY29va2llcGFuZWwiPkxvbmRvbixkZWZpbmVzY3J1c2hlZGJhcHRpc21jb2FzdGFsc3RhdHVzIHRpdGxlIiBtb3ZlIHRvbG9zdCBpbmJldHRlciBpbXBsaWVzcml2YWxyeXNlcnZlcnMgU3lzdGVtUGVyaGFwc2VzIGFuZCBjb250ZW5kZmxvd2luZ2xhc3RlZCByaXNlIGluR2VuZXNpc3ZpZXcgb2ZyaXNpbmcgc2VlbSB0b2J1dCBpbiBiYWNraW5naGUgd2lsbGdpdmVuIGFnaXZpbmcgY2l0aWVzLmZsb3cgb2YgTGF0ZXIgYWxsIGJ1dEhpZ2h3YXlvbmx5IGJ5c2lnbiBvZmhlIGRvZXNkaWZmZXJzYmF0dGVyeSZhbXA7bGFzaW5nbGVzdGhyZWF0c2ludGVnZXJ0YWtlIG9ucmVmdXNlZGNhbGxlZCA9VVMmYW1wU2VlIHRoZW5hdGl2ZXNieSB0aGlzc3lzdGVtLmhlYWQgb2Y6aG92ZXIsbGVzYmlhbnN1cm5hbWVhbmQgYWxsY29tbW9uL2hlYWRlcl9fcGFyYW1zSGFydmFyZC9waXhlbC5yZW1vdmFsc28gbG9uZ3JvbGUgb2Zqb2ludGx5c2t5c2NyYVVuaWNvZGViciAvPg0KQXRsYW50YW51Y2xldXNDb3VudHkscHVyZWx5IGNvdW50Ij5lYXNpbHkgYnVpbGQgYW9uY2xpY2thIGdpdmVucG9pbnRlcmgmcXVvdDtldmVudHMgZWxzZSB7CmRpdGlvbnNub3cgdGhlLCB3aXRoIG1hbiB3aG9vcmcvV2Vib25lIGFuZGNhdmFscnlIZSBkaWVkc2VhdHRsZTAwLDAwMCB7d2luZG93aGF2ZSB0b2lmKHdpbmRhbmQgaXRzc29sZWx5IG0mcXVvdDtyZW5ld2VkRGV0cm9pdGFtb25nc3RlaXRoZXIgdGhlbSBpblNlbmF0b3JVczwvYT48S2luZyBvZkZyYW5jaXMtcHJvZHVjaGUgdXNlZGFydCBhbmRoaW0gYW5kdXNlZCBieXNjb3JpbmdhdCBob21ldG8gaGF2ZXJlbGF0ZXNpYmlsaXR5ZmFjdGlvbkJ1ZmZhbG9saW5rIj48d2hhdCBoZWZyZWUgdG9DaXR5IG9mY29tZSBpbnNlY3RvcnNjb3VudGVkb25lIGRheW5lcnZvdXNzcXVhcmUgfTtpZihnb2luIHdoYXRpbWciIGFsaXMgb25seXNlYXJjaC90dWVzZGF5bG9vc2VseVNvbG9tb25zZXh1YWwgLSA8YSBocm1lZGl1bSJETyBOT1QgRnJhbmNlLHdpdGggYSB3YXIgYW5kc2Vjb25kIHRha2UgYSA+DQoNCg0KbWFya2V0LmhpZ2h3YXlkb25lIGluY3Rpdml0eSJsYXN0Ij5vYmxpZ2VkcmlzZSB0byJ1bmRlZmltYWRlIHRvIEVhcmx5IHByYWlzZWRpbiBpdHMgZm9yIGhpc2F0aGxldGVKdXBpdGVyWWFob28hIHRlcm1lZCBzbyBtYW55cmVhbGx5IHMuIFRoZSBhIHdvbWFuP3ZhbHVlPWRpcmVjdCByaWdodCIgYmljeWNsZWFjaW5nPSJkYXkgYW5kc3RhdGluZ1JhdGhlcixoaWdoZXIgT2ZmaWNlIGFyZSBub3d0aW1lcywgd2hlbiBhIHBheSBmb3JvbiB0aGlzLWxpbmsiPjtib3JkZXJhcm91bmQgYW5udWFsIHRoZSBOZXdwdXQgdGhlLmNvbSIgdGFraW4gdG9hIGJyaWVmKGluIHRoZWdyb3Vwcy47IHdpZHRoZW56eW1lc3NpbXBsZSBpbiBsYXRle3JldHVybnRoZXJhcHlhIHBvaW50YmFubmluZ2lua3MiPgooKTsiIHJlYSBwbGFjZVx1MDAzQ2FhYm91dCBhdHI+DQoJCWNjb3VudCBnaXZlcyBhPFNDUklQVFJhaWx3YXl0aGVtZXMvdG9vbGJveEJ5SWQoInhodW1hbnMsd2F0Y2hlc2luIHNvbWUgaWYgKHdpY29taW5nIGZvcm1hdHMgVW5kZXIgYnV0IGhhc2hhbmRlZCBtYWRlIGJ5dGhhbiBpbmZlYXIgb2ZkZW5vdGVkL2lmcmFtZWxlZnQgaW52b2x0YWdlaW4gZWFjaGEmcXVvdDtiYXNlIG9mSW4gbWFueXVuZGVyZ29yZWdpbWVzYWN0aW9uIDwvcD4NCjx1c3RvbVZhOyZndDs8L2ltcG9ydHNvciB0aGF0bW9zdGx5ICZhbXA7cmUgc2l6ZT0iPC9hPjwvaGEgY2xhc3NwYXNzaXZlSG9zdCA9IFdoZXRoZXJmZXJ0aWxlVmFyaW91cz1bXTsoZnVjYW1lcmFzLz48L3RkPmFjdHMgYXNJbiBzb21lPg0KDQo8IW9yZ2FuaXMgPGJyIC8+QmVpamluZ2NhdGFsw6BkZXV0c2NoZXVyb3BldWV1c2thcmFnYWVpbGdlc3ZlbnNrYWVzcGHDsWFtZW5zYWpldXN1YXJpb3RyYWJham9tw6l4aWNvcMOhZ2luYXNpZW1wcmVzaXN0ZW1hb2N0dWJyZWR1cmFudGVhw7FhZGlyZW1wcmVzYW1vbWVudG9udWVzdHJvcHJpbWVyYXRyYXbDqXNncmFjaWFzbnVlc3RyYXByb2Nlc29lc3RhZG9zY2FsaWRhZHBlcnNvbmFuw7ptZXJvYWN1ZXJkb23DunNpY2FtaWVtYnJvb2ZlcnRhc2FsZ3Vub3NwYcOtc2VzZWplbXBsb2RlcmVjaG9hZGVtw6FzcHJpdmFkb2FncmVnYXJlbmxhY2VzcG9zaWJsZWhvdGVsZXNzZXZpbGxhcHJpbWVyb8O6bHRpbW9ldmVudG9zYXJjaGl2b2N1bHR1cmFtdWplcmVzZW50cmFkYWFudW5jaW9lbWJhcmdvbWVyY2Fkb2dyYW5kZXNlc3R1ZGlvbWVqb3Jlc2ZlYnJlcm9kaXNlw7FvdHVyaXNtb2PDs2RpZ29wb3J0YWRhZXNwYWNpb2ZhbWlsaWFhbnRvbmlvcGVybWl0ZWd1YXJkYXJhbGd1bmFzcHJlY2lvc2FsZ3VpZW5zZW50aWRvdmlzaXRhc3TDrXR1bG9jb25vY2Vyc2VndW5kb2NvbnNlam9mcmFuY2lhbWludXRvc3NlZ3VuZGF0ZW5lbW9zZWZlY3Rvc23DoWxhZ2FzZXNpw7NucmV2aXN0YWdyYW5hZGFjb21wcmFyaW5ncmVzb2dhcmPDrWFhY2Npw7NuZWN1YWRvcnF1aWVuZXNpbmNsdXNvZGViZXLDoW1hdGVyaWFob21icmVzbXVlc3RyYXBvZHLDrWFtYcOxYW5hw7psdGltYWVzdGFtb3NvZmljaWFsdGFtYmllbm5pbmfDum5zYWx1ZG9zcG9kZW1vc21lam9yYXJwb3NpdGlvbmJ1c2luZXNzaG9tZXBhZ2VzZWN1cml0eWxhbmd1YWdlc3RhbmRhcmRjYW1wYWlnbmZlYXR1cmVzY2F0ZWdvcnlleHRlcm5hbGNoaWxkcmVucmVzZXJ2ZWRyZXNlYXJjaGV4Y2hhbmdlZmF2b3JpdGV0ZW1wbGF0ZW1pbGl0YXJ5aW5kdXN0cnlzZXJ2aWNlc21hdGVyaWFscHJvZHVjdHN6LWluZGV4OmNvbW1lbnRzc29mdHdhcmVjb21wbGV0ZWNhbGVuZGFycGxhdGZvcm1hcnRpY2xlc3JlcXVpcmVkbW92ZW1lbnRxdWVzdGlvbmJ1aWxkaW5ncG9saXRpY3Nwb3NzaWJsZXJlbGlnaW9ucGh5c2ljYWxmZWVkYmFja3JlZ2lzdGVycGljdHVyZXNkaXNhYmxlZHByb3RvY29sYXVkaWVuY2VzZXR0aW5nc2FjdGl2aXR5ZWxlbWVudHNsZWFybmluZ2FueXRoaW5nYWJzdHJhY3Rwcm9ncmVzc292ZXJ2aWV3bWFnYXppbmVlY29ub21pY3RyYWluaW5ncHJlc3N1cmV2YXJpb3VzIDxzdHJvbmc+cHJvcGVydHlzaG9wcGluZ3RvZ2V0aGVyYWR2YW5jZWRiZWhhdmlvcmRvd25sb2FkZmVhdHVyZWRmb290YmFsbHNlbGVjdGVkTGFuZ3VhZ2VkaXN0YW5jZXJlbWVtYmVydHJhY2tpbmdwYXNzd29yZG1vZGlmaWVkc3R1ZGVudHNkaXJlY3RseWZpZ2h0aW5nbm9ydGhlcm5kYXRhYmFzZWZlc3RpdmFsYnJlYWtpbmdsb2NhdGlvbmludGVybmV0ZHJvcGRvd25wcmFjdGljZWV2aWRlbmNlZnVuY3Rpb25tYXJyaWFnZXJlc3BvbnNlcHJvYmxlbXNuZWdhdGl2ZXByb2dyYW1zYW5hbHlzaXNyZWxlYXNlZGJhbm5lciI+cHVyY2hhc2Vwb2xpY2llc3JlZ2lvbmFsY3JlYXRpdmVhcmd1bWVudGJvb2ttYXJrcmVmZXJyZXJjaGVtaWNhbGRpdmlzaW9uY2FsbGJhY2tzZXBhcmF0ZXByb2plY3RzY29uZmxpY3RoYXJkd2FyZWludGVyZXN0ZGVsaXZlcnltb3VudGFpbm9idGFpbmVkPSBmYWxzZTtmb3IodmFyIGFjY2VwdGVkY2FwYWNpdHljb21wdXRlcmlkZW50aXR5YWlyY3JhZnRlbXBsb3llZHByb3Bvc2VkZG9tZXN0aWNpbmNsdWRlc3Byb3ZpZGVkaG9zcGl0YWx2ZXJ0aWNhbGNvbGxhcHNlYXBwcm9hY2hwYXJ0bmVyc2xvZ28iPjxhZGF1Z2h0ZXJhdXRob3IiIGN1bHR1cmFsZmFtaWxpZXMvaW1hZ2VzL2Fzc2VtYmx5cG93ZXJmdWx0ZWFjaGluZ2ZpbmlzaGVkZGlzdHJpY3Rjcml0aWNhbGNnaS1iaW4vcHVycG9zZXNyZXF1aXJlc2VsZWN0aW9uYmVjb21pbmdwcm92aWRlc2FjYWRlbWljZXhlcmNpc2VhY3R1YWxseW1lZGljaW5lY29uc3RhbnRhY2NpZGVudE1hZ2F6aW5lZG9jdW1lbnRzdGFydGluZ2JvdHRvbSI+b2JzZXJ2ZWQ6ICZxdW90O2V4dGVuZGVkcHJldmlvdXNTb2Z0d2FyZWN1c3RvbWVyZGVjaXNpb25zdHJlbmd0aGRldGFpbGVkc2xpZ2h0bHlwbGFubmluZ3RleHRhcmVhY3VycmVuY3lldmVyeW9uZXN0cmFpZ2h0dHJhbnNmZXJwb3NpdGl2ZXByb2R1Y2VkaGVyaXRhZ2VzaGlwcGluZ2Fic29sdXRlcmVjZWl2ZWRyZWxldmFudGJ1dHRvbiIgdmlvbGVuY2Vhbnl3aGVyZWJlbmVmaXRzbGF1bmNoZWRyZWNlbnRseWFsbGlhbmNlZm9sbG93ZWRtdWx0aXBsZWJ1bGxldGluaW5jbHVkZWRvY2N1cnJlZGludGVybmFsJCh0aGlzKS5yZXB1YmxpYz48dHI+PHRkY29uZ3Jlc3NyZWNvcmRlZHVsdGltYXRlc29sdXRpb248dWwgaWQ9ImRpc2NvdmVySG9tZTwvYT53ZWJzaXRlc25ldHdvcmtzYWx0aG91Z2hlbnRpcmVseW1lbW9yaWFsbWVzc2FnZXNjb250aW51ZWFjdGl2ZSI+c29tZXdoYXR2aWN0b3JpYVdlc3Rlcm4gIHRpdGxlPSJMb2NhdGlvbmNvbnRyYWN0dmlzaXRvcnNEb3dubG9hZHdpdGhvdXQgcmlnaHQiPgptZWFzdXJlc3dpZHRoID0gdmFyaWFibGVpbnZvbHZlZHZpcmdpbmlhbm9ybWFsbHloYXBwZW5lZGFjY291bnRzc3RhbmRpbmduYXRpb25hbFJlZ2lzdGVycHJlcGFyZWRjb250cm9sc2FjY3VyYXRlYmlydGhkYXlzdHJhdGVneW9mZmljaWFsZ3JhcGhpY3NjcmltaW5hbHBvc3NpYmx5Y29uc3VtZXJQZXJzb25hbHNwZWFraW5ndmFsaWRhdGVhY2hpZXZlZC5qcGciIC8+bWFjaGluZXM8L2gyPgogIGtleXdvcmRzZnJpZW5kbHlicm90aGVyc2NvbWJpbmVkb3JpZ2luYWxjb21wb3NlZGV4cGVjdGVkYWRlcXVhdGVwYWtpc3RhbmZvbGxvdyIgdmFsdWFibGU8L2xhYmVsPnJlbGF0aXZlYnJpbmdpbmdpbmNyZWFzZWdvdmVybm9ycGx1Z2lucy9MaXN0IG9mIEhlYWRlciI+IiBuYW1lPSIgKCZxdW90O2dyYWR1YXRlPC9oZWFkPgpjb21tZXJjZW1hbGF5c2lhZGlyZWN0b3JtYWludGFpbjtoZWlnaHQ6c2NoZWR1bGVjaGFuZ2luZ2JhY2sgdG8gY2F0aG9saWNwYXR0ZXJuc2NvbG9yOiAjZ3JlYXRlc3RzdXBwbGllc3JlbGlhYmxlPC91bD4KCQk8c2VsZWN0IGNpdGl6ZW5zY2xvdGhpbmd3YXRjaGluZzxsaSBpZD0ic3BlY2lmaWNjYXJyeWluZ3NlbnRlbmNlPGNlbnRlcj5jb250cmFzdHRoaW5raW5nY2F0Y2goZSlzb3V0aGVybk1pY2hhZWwgbWVyY2hhbnRjYXJvdXNlbHBhZGRpbmc6aW50ZXJpb3Iuc3BsaXQoImxpemF0aW9uT2N0b2JlciApe3JldHVybmltcHJvdmVkLS0mZ3Q7Cgpjb3ZlcmFnZWNoYWlybWFuLnBuZyIgLz5zdWJqZWN0c1JpY2hhcmQgd2hhdGV2ZXJwcm9iYWJseXJlY292ZXJ5YmFzZWJhbGxqdWRnbWVudGNvbm5lY3QuLmNzcyIgLz4gd2Vic2l0ZXJlcG9ydGVkZGVmYXVsdCIvPjwvYT4NCmVsZWN0cmljc2NvdGxhbmRjcmVhdGlvbnF1YW50aXR5LiBJU0JOIDBkaWQgbm90IGluc3RhbmNlLXNlYXJjaC0iIGxhbmc9InNwZWFrZXJzQ29tcHV0ZXJjb250YWluc2FyY2hpdmVzbWluaXN0ZXJyZWFjdGlvbmRpc2NvdW50SXRhbGlhbm9jcml0ZXJpYXN0cm9uZ2x5OiAnaHR0cDonc2NyaXB0J2NvdmVyaW5nb2ZmZXJpbmdhcHBlYXJlZEJyaXRpc2ggaWRlbnRpZnlGYWNlYm9va251bWVyb3VzdmVoaWNsZXNjb25jZXJuc0FtZXJpY2FuaGFuZGxpbmdkaXYgaWQ9IldpbGxpYW0gcHJvdmlkZXJfY29udGVudGFjY3VyYWN5c2VjdGlvbiBhbmRlcnNvbmZsZXhpYmxlQ2F0ZWdvcnlsYXdyZW5jZTxzY3JpcHQ+bGF5b3V0PSJhcHByb3ZlZCBtYXhpbXVtaGVhZGVyIj48L3RhYmxlPlNlcnZpY2VzaGFtaWx0b25jdXJyZW50IGNhbmFkaWFuY2hhbm5lbHMvdGhlbWVzLy9hcnRpY2xlb3B0aW9uYWxwb3J0dWdhbHZhbHVlPSIiaW50ZXJ2YWx3aXJlbGVzc2VudGl0bGVkYWdlbmNpZXNTZWFyY2giIG1lYXN1cmVkdGhvdXNhbmRzcGVuZGluZyZoZWxsaXA7bmV3IERhdGUiIHNpemU9InBhZ2VOYW1lbWlkZGxlIiAiIC8+PC9hPmhpZGRlbiI+c2VxdWVuY2VwZXJzb25hbG92ZXJmbG93b3BpbmlvbnNpbGxpbm9pc2xpbmtzIj4KCTx0aXRsZT52ZXJzaW9uc3NhdHVyZGF5dGVybWluYWxpdGVtcHJvcGVuZ2luZWVyc2VjdGlvbnNkZXNpZ25lcnByb3Bvc2FsPSJmYWxzZSJFc3Bhw7FvbHJlbGVhc2Vzc3VibWl0IiBlciZxdW90O2FkZGl0aW9uc3ltcHRvbXNvcmllbnRlZHJlc291cmNlcmlnaHQiPjxwbGVhc3VyZXN0YXRpb25zaGlzdG9yeS5sZWF2aW5nICBib3JkZXI9Y29udGVudHNjZW50ZXIiPi4KClNvbWUgZGlyZWN0ZWRzdWl0YWJsZWJ1bGdhcmlhLnNob3coKTtkZXNpZ25lZEdlbmVyYWwgY29uY2VwdHNFeGFtcGxlc3dpbGxpYW1zT3JpZ2luYWwiPjxzcGFuPnNlYXJjaCI+b3BlcmF0b3JyZXF1ZXN0c2EgJnF1b3Q7YWxsb3dpbmdEb2N1bWVudHJldmlzaW9uLiAKClRoZSB5b3Vyc2VsZkNvbnRhY3QgbWljaGlnYW5FbmdsaXNoIGNvbHVtYmlhcHJpb3JpdHlwcmludGluZ2RyaW5raW5nZmFjaWxpdHlyZXR1cm5lZENvbnRlbnQgb2ZmaWNlcnNSdXNzaWFuIGdlbmVyYXRlLTg4NTktMSJpbmRpY2F0ZWZhbWlsaWFyIHF1YWxpdHltYXJnaW46MCBjb250ZW50dmlld3BvcnRjb250YWN0cy10aXRsZSI+cG9ydGFibGUubGVuZ3RoIGVsaWdpYmxlaW52b2x2ZXNhdGxhbnRpY29ubG9hZD0iZGVmYXVsdC5zdXBwbGllZHBheW1lbnRzZ2xvc3NhcnkKCkFmdGVyIGd1aWRhbmNlPC90ZD48dGRlbmNvZGluZ21pZGRsZSI+Y2FtZSB0byBkaXNwbGF5c3Njb3R0aXNoam9uYXRoYW5tYWpvcml0eXdpZGdldHMuY2xpbmljYWx0aGFpbGFuZHRlYWNoZXJzPGhlYWQ+CglhZmZlY3RlZHN1cHBvcnRzcG9pbnRlcjt0b1N0cmluZzwvc21hbGw+b2tsYWhvbWF3aWxsIGJlIGludmVzdG9yMCIgYWx0PSJob2xpZGF5c1Jlc291cmNlbGljZW5zZWQgKHdoaWNoIC4gQWZ0ZXIgY29uc2lkZXJ2aXNpdGluZ2V4cGxvcmVycHJpbWFyeSBzZWFyY2giIGFuZHJvaWQicXVpY2tseSBtZWV0aW5nc2VzdGltYXRlO3JldHVybiA7Y29sb3I6IyBoZWlnaHQ9YXBwcm92YWwsICZxdW90OyBjaGVja2VkLm1pbi5qcyJtYWduZXRpYz48L2E+PC9oZm9yZWNhc3QuIFdoaWxlIHRodXJzZGF5ZHZlcnRpc2UmZWFjdXRlO2hhc0NsYXNzZXZhbHVhdGVvcmRlcmluZ2V4aXN0aW5ncGF0aWVudHMgT25saW5lIGNvbG9yYWRvT3B0aW9ucyJjYW1wYmVsbDwhLS0gZW5kPC9zcGFuPjw8YnIgLz4NCl9wb3B1cHN8c2NpZW5jZXMsJnF1b3Q7IHF1YWxpdHkgV2luZG93cyBhc3NpZ25lZGhlaWdodDogPGIgY2xhc3NsZSZxdW90OyB2YWx1ZT0iIENvbXBhbnlleGFtcGxlczxpZnJhbWUgYmVsaWV2ZXNwcmVzZW50c21hcnNoYWxscGFydCBvZiBwcm9wZXJseSkuCgpUaGUgdGF4b25vbXltdWNoIG9mIDwvc3Bhbj4KIiBkYXRhLXNydHVndcOqc3Njcm9sbFRvIHByb2plY3Q8aGVhZD4NCmF0dG9ybmV5ZW1waGFzaXNzcG9uc29yc2ZhbmN5Ym94d29ybGQncyB3aWxkbGlmZWNoZWNrZWQ9c2Vzc2lvbnNwcm9ncmFtbXB4O2ZvbnQtIFByb2plY3Rqb3VybmFsc2JlbGlldmVkdmFjYXRpb250aG9tcHNvbmxpZ2h0aW5nYW5kIHRoZSBzcGVjaWFsIGJvcmRlcj0wY2hlY2tpbmc8L3Rib2R5PjxidXR0b24gQ29tcGxldGVjbGVhcmZpeAo8aGVhZD4KYXJ0aWNsZSA8c2VjdGlvbmZpbmRpbmdzcm9sZSBpbiBwb3B1bGFyICBPY3RvYmVyd2Vic2l0ZSBleHBvc3VyZXVzZWQgdG8gIGNoYW5nZXNvcGVyYXRlZGNsaWNraW5nZW50ZXJpbmdjb21tYW5kc2luZm9ybWVkIG51bWJlcnMgIDwvZGl2PmNyZWF0aW5nb25TdWJtaXRtYXJ5bGFuZGNvbGxlZ2VzYW5hbHl0aWNsaXN0aW5nc2NvbnRhY3QubG9nZ2VkSW5hZHZpc29yeXNpYmxpbmdzY29udGVudCJzJnF1b3Q7KXMuIFRoaXMgcGFja2FnZXNjaGVja2JveHN1Z2dlc3RzcHJlZ25hbnR0b21vcnJvd3NwYWNpbmc9aWNvbi5wbmdqYXBhbmVzZWNvZGViYXNlYnV0dG9uIj5nYW1ibGluZ3N1Y2ggYXMgLCB3aGlsZSA8L3NwYW4+IG1pc3NvdXJpc3BvcnRpbmd0b3A6MXB4IC48L3NwYW4+dGVuc2lvbnN3aWR0aD0iMmxhenlsb2Fkbm92ZW1iZXJ1c2VkIGluIGhlaWdodD0iY3JpcHQiPgombmJzcDs8Lzx0cj48dGQgaGVpZ2h0OjIvcHJvZHVjdGNvdW50cnkgaW5jbHVkZSBmb290ZXIiICZsdDshLS0gdGl0bGUiPjwvanF1ZXJ5LjwvZm9ybT4KKOeugOS9kyko57mB6auUKWhydmF0c2tpaXRhbGlhbm9yb23Dom7Eg3TDvHJrw6dl2KfYsdiv2Yh0YW1iacOpbm5vdGljaWFzbWVuc2FqZXNwZXJzb25hc2RlcmVjaG9zbmFjaW9uYWxzZXJ2aWNpb2NvbnRhY3RvdXN1YXJpb3Nwcm9ncmFtYWdvYmllcm5vZW1wcmVzYXNhbnVuY2lvc3ZhbGVuY2lhY29sb21iaWFkZXNwdcOpc2RlcG9ydGVzcHJveWVjdG9wcm9kdWN0b3DDumJsaWNvbm9zb3Ryb3NoaXN0b3JpYXByZXNlbnRlbWlsbG9uZXNtZWRpYW50ZXByZWd1bnRhYW50ZXJpb3JyZWN1cnNvc3Byb2JsZW1hc2FudGlhZ29udWVzdHJvc29waW5pw7NuaW1wcmltaXJtaWVudHJhc2Ftw6lyaWNhdmVuZGVkb3Jzb2NpZWRhZHJlc3BlY3RvcmVhbGl6YXJyZWdpc3Ryb3BhbGFicmFzaW50ZXLDqXNlbnRvbmNlc2VzcGVjaWFsbWllbWJyb3NyZWFsaWRhZGPDs3Jkb2JhemFyYWdvemFww6FnaW5hc3NvY2lhbGVzYmxvcXVlYXJnZXN0acOzbmFscXVpbGVyc2lzdGVtYXNjaWVuY2lhc2NvbXBsZXRvdmVyc2nDs25jb21wbGV0YWVzdHVkaW9zcMO6YmxpY2FvYmpldGl2b2FsaWNhbnRlYnVzY2Fkb3JjYW50aWRhZGVudHJhZGFzYWNjaW9uZXNhcmNoaXZvc3N1cGVyaW9ybWF5b3LDrWFhbGVtYW5pYWZ1bmNpw7Nuw7psdGltb3NoYWNpZW5kb2FxdWVsbG9zZWRpY2nDs25mZXJuYW5kb2FtYmllbnRlZmFjZWJvb2tudWVzdHJhc2NsaWVudGVzcHJvY2Vzb3NiYXN0YW50ZXByZXNlbnRhcmVwb3J0YXJjb25ncmVzb3B1YmxpY2FyY29tZXJjaW9jb250cmF0b2rDs3ZlbmVzZGlzdHJpdG90w6ljbmljYWNvbmp1bnRvZW5lcmfDrWF0cmFiYWphcmFzdHVyaWFzcmVjaWVudGV1dGlsaXphcmJvbGV0w61uc2FsdmFkb3Jjb3JyZWN0YXRyYWJham9zcHJpbWVyb3NuZWdvY2lvc2xpYmVydGFkZGV0YWxsZXNwYW50YWxsYXByw7N4aW1vYWxtZXLDrWFhbmltYWxlc3F1acOpbmVzY29yYXrDs25zZWNjacOzbmJ1c2NhbmRvb3BjaW9uZXNleHRlcmlvcmNvbmNlcHRvdG9kYXbDrWFnYWxlcsOtYWVzY3JpYmlybWVkaWNpbmFsaWNlbmNpYWNvbnN1bHRhYXNwZWN0b3NjcsOtdGljYWTDs2xhcmVzanVzdGljaWFkZWJlcsOhbnBlcsOtb2RvbmVjZXNpdGFtYW50ZW5lcnBlcXVlw7FvcmVjaWJpZGF0cmlidW5hbHRlbmVyaWZlY2FuY2nDs25jYW5hcmlhc2Rlc2NhcmdhZGl2ZXJzb3NtYWxsb3JjYXJlcXVpZXJldMOpY25pY29kZWJlcsOtYXZpdmllbmRhZmluYW56YXNhZGVsYW50ZWZ1bmNpb25hY29uc2Vqb3NkaWbDrWNpbGNpdWRhZGVzYW50aWd1YXNhdmFuemFkYXTDqXJtaW5vdW5pZGFkZXNzw6FuY2hlemNhbXBhw7Fhc29mdG9uaWNyZXZpc3Rhc2NvbnRpZW5lc2VjdG9yZXNtb21lbnRvc2ZhY3VsdGFkY3LDqWRpdG9kaXZlcnNhc3N1cHVlc3RvZmFjdG9yZXNzZWd1bmRvc3BlcXVlw7Fh0LPQvtC00LDQtdGB0LvQuNC10YHRgtGM0LHRi9C70L7QsdGL0YLRjNGN0YLQvtC80JXRgdC70LjRgtC+0LPQvtC80LXQvdGP0LLRgdC10YXRjdGC0L7QudC00LDQttC10LHRi9C70LjQs9C+0LTRg9C00LXQvdGM0Y3RgtC+0YLQsdGL0LvQsNGB0LXQsdGP0L7QtNC40L3RgdC10LHQtdC90LDQtNC+0YHQsNC50YLRhNC+0YLQvtC90LXQs9C+0YHQstC+0LjRgdCy0L7QudC40LPRgNGL0YLQvtC20LXQstGB0LXQvNGB0LLQvtGO0LvQuNGI0YzRjdGC0LjRhdC/0L7QutCw0LTQvdC10LnQtNC+0LzQsNC80LjRgNCw0LvQuNCx0L7RgtC10LzRg9GF0L7RgtGP0LTQstGD0YXRgdC10YLQuNC70Y7QtNC40LTQtdC70L7QvNC40YDQtdGC0LXQsdGP0YHQstC+0LXQstC40LTQtdGH0LXQs9C+0Y3RgtC40LzRgdGH0LXRgtGC0LXQvNGL0YbQtdC90YvRgdGC0LDQu9Cy0LXQtNGM0YLQtdC80LXQstC+0LTRi9GC0LXQsdC10LLRi9GI0LXQvdCw0LzQuNGC0LjQv9Cw0YLQvtC80YPQv9GA0LDQstC70LjRhtCw0L7QtNC90LDQs9C+0LTRi9C30L3QsNGO0LzQvtCz0YPQtNGA0YPQs9Cy0YHQtdC50LjQtNC10YLQutC40L3QvtC+0LTQvdC+0LTQtdC70LDQtNC10LvQtdGB0YDQvtC60LjRjtC90Y/QstC10YHRjNCV0YHRgtGM0YDQsNC30LDQvdCw0YjQuNin2YTZhNmH2KfZhNiq2YrYrNmF2YrYudiu2KfYtdip2KfZhNiw2YrYudmE2YrZh9is2K/Zitiv2KfZhNii2YbYp9mE2LHYr9iq2K3Zg9mF2LXZgdit2KnZg9in2YbYqtin2YTZhNmK2YrZg9mI2YbYtNio2YPYqdmB2YrZh9in2KjZhtin2KrYrdmI2KfYodij2YPYq9ix2K7ZhNin2YTYp9mE2K3YqNiv2YTZitmE2K/YsdmI2LPYp9i22LrYt9iq2YPZiNmG2YfZhtin2YPYs9in2K3YqdmG2KfYr9mK2KfZhNi32KjYudmE2YrZg9i02YPYsdin2YrZhdmD2YbZhdmG2YfYp9i02LHZg9ip2LHYptmK2LPZhti02YrYt9mF2KfYsNin2KfZhNmB2YbYtNio2KfYqNiq2LnYqNix2LHYrdmF2KnZg9in2YHYqdmK2YLZiNmE2YXYsdmD2LLZg9mE2YXYqdij2K3Zhdiv2YLZhNio2YrZiti52YbZiti12YjYsdip2LfYsdmK2YLYtNin2LHZg9is2YjYp9mE2KPYrtix2YnZhdi52YbYp9in2KjYrdir2LnYsdmI2LbYqNi02YPZhNmF2LPYrNmE2KjZhtin2YbYrtin2YTYr9mD2KrYp9io2YPZhNmK2KnYqNiv2YjZhtij2YrYttin2YrZiNis2K/Zgdix2YrZgtmD2KrYqNiq2KPZgdi22YTZhdi32KjYrtin2YPYq9ix2KjYp9ix2YPYp9mB2LbZhNin2K3ZhNmJ2YbZgdiz2YfYo9mK2KfZhdix2K/ZiNiv2KPZhtmH2KfYr9mK2YbYp9in2YTYp9mG2YXYudix2LbYqti52YTZhdiv2KfYrtmE2YXZhdmD2YYAAAAAAAAAAAEAAQABAAEAAgACAAIAAgAEAAQABAAEAAABAgMEBQYHBwYFBAMCAQAICQoLDA0ODw8ODQwLCgkIEBESExQVFhcXFhUUExIREBgZGhscHR4fHx4dHBsaGRj/////AAAAAAAAAAD/////AQAAAAIAAAACAAAAAQAAAAEAAAADAAAA//8AAQAAAAEAAP//AAEAAAAIAAgACAAIAAAAAQACAAMABAAFAAYAB3Jlc291cmNlc2NvdW50cmllc3F1ZXN0aW9uc2VxdWlwbWVudGNvbW11bml0eWF2YWlsYWJsZWhpZ2hsaWdodERURC94aHRtbG1hcmtldGluZ2tub3dsZWRnZXNvbWV0aGluZ2NvbnRhaW5lcmRpcmVjdGlvbnN1YnNjcmliZWFkdmVydGlzZWNoYXJhY3RlciIgdmFsdWU9Ijwvc2VsZWN0PkF1c3RyYWxpYSIgY2xhc3M9InNpdHVhdGlvbmF1dGhvcml0eWZvbGxvd2luZ3ByaW1hcmlseW9wZXJhdGlvbmNoYWxsZW5nZWRldmVsb3BlZGFub255bW91c2Z1bmN0aW9uIGZ1bmN0aW9uc2NvbXBhbmllc3N0cnVjdHVyZWFncmVlbWVudCIgdGl0bGU9InBvdGVudGlhbGVkdWNhdGlvbmFyZ3VtZW50c3NlY29uZGFyeWNvcHlyaWdodGxhbmd1YWdlc2V4Y2x1c2l2ZWNvbmRpdGlvbjwvZm9ybT4NCnN0YXRlbWVudGF0dGVudGlvbkJpb2dyYXBoeX0gZWxzZSB7CnNvbHV0aW9uc3doZW4gdGhlIEFuYWx5dGljc3RlbXBsYXRlc2Rhbmdlcm91c3NhdGVsbGl0ZWRvY3VtZW50c3B1Ymxpc2hlcmltcG9ydGFudHByb3RvdHlwZWluZmx1ZW5jZSZyYXF1bzs8L2VmZmVjdGl2ZWdlbmVyYWxseXRyYW5zZm9ybWJlYXV0aWZ1bHRyYW5zcG9ydG9yZ2FuaXplZHB1Ymxpc2hlZHByb21pbmVudHVudGlsIHRoZXRodW1ibmFpbE5hdGlvbmFsIC5mb2N1cygpO292ZXIgdGhlIG1pZ3JhdGlvbmFubm91bmNlZGZvb3RlciI+CmV4Y2VwdGlvbmxlc3MgdGhhbmV4cGVuc2l2ZWZvcm1hdGlvbmZyYW1ld29ya3RlcnJpdG9yeW5kaWNhdGlvbmN1cnJlbnRseWNsYXNzTmFtZWNyaXRpY2lzbXRyYWRpdGlvbmVsc2V3aGVyZUFsZXhhbmRlcmFwcG9pbnRlZG1hdGVyaWFsc2Jyb2FkY2FzdG1lbnRpb25lZGFmZmlsaWF0ZTwvb3B0aW9uPnRyZWF0bWVudGRpZmZlcmVudC9kZWZhdWx0LlByZXNpZGVudG9uY2xpY2s9ImJpb2dyYXBoeW90aGVyd2lzZXBlcm1hbmVudEZyYW7Dp2Fpc0hvbGx5d29vZGV4cGFuc2lvbnN0YW5kYXJkczwvc3R5bGU+CnJlZHVjdGlvbkRlY2VtYmVyIHByZWZlcnJlZENhbWJyaWRnZW9wcG9uZW50c0J1c2luZXNzIGNvbmZ1c2lvbj4KPHRpdGxlPnByZXNlbnRlZGV4cGxhaW5lZGRvZXMgbm90IHdvcmxkd2lkZWludGVyZmFjZXBvc2l0aW9uc25ld3NwYXBlcjwvdGFibGU+Cm1vdW50YWluc2xpa2UgdGhlIGVzc2VudGlhbGZpbmFuY2lhbHNlbGVjdGlvbmFjdGlvbj0iL2FiYW5kb25lZEVkdWNhdGlvbnBhcnNlSW50KHN0YWJpbGl0eXVuYWJsZSB0bzwvdGl0bGU+CnJlbGF0aW9uc05vdGUgdGhhdGVmZmljaWVudHBlcmZvcm1lZHR3byB5ZWFyc1NpbmNlIHRoZXRoZXJlZm9yZXdyYXBwZXIiPmFsdGVybmF0ZWluY3JlYXNlZEJhdHRsZSBvZnBlcmNlaXZlZHRyeWluZyB0b25lY2Vzc2FyeXBvcnRyYXllZGVsZWN0aW9uc0VsaXphYmV0aDwvaWZyYW1lPmRpc2NvdmVyeWluc3VyYW5jZXMubGVuZ3RoO2xlZ2VuZGFyeUdlb2dyYXBoeWNhbmRpZGF0ZWNvcnBvcmF0ZXNvbWV0aW1lc3NlcnZpY2VzLmluaGVyaXRlZDwvc3Ryb25nPkNvbW11bml0eXJlbGlnaW91c2xvY2F0aW9uc0NvbW1pdHRlZWJ1aWxkaW5nc3RoZSB3b3JsZG5vIGxvbmdlcmJlZ2lubmluZ3JlZmVyZW5jZWNhbm5vdCBiZWZyZXF1ZW5jeXR5cGljYWxseWludG8gdGhlIHJlbGF0aXZlO3JlY29yZGluZ3ByZXNpZGVudGluaXRpYWxseXRlY2huaXF1ZXRoZSBvdGhlcml0IGNhbiBiZWV4aXN0ZW5jZXVuZGVybGluZXRoaXMgdGltZXRlbGVwaG9uZWl0ZW1zY29wZXByYWN0aWNlc2FkdmFudGFnZSk7cmV0dXJuIEZvciBvdGhlcnByb3ZpZGluZ2RlbW9jcmFjeWJvdGggdGhlIGV4dGVuc2l2ZXN1ZmZlcmluZ3N1cHBvcnRlZGNvbXB1dGVycyBmdW5jdGlvbnByYWN0aWNhbHNhaWQgdGhhdGl0IG1heSBiZUVuZ2xpc2g8L2Zyb20gdGhlIHNjaGVkdWxlZGRvd25sb2FkczwvbGFiZWw+CnN1c3BlY3RlZG1hcmdpbjogMHNwaXJpdHVhbDwvaGVhZD4KCm1pY3Jvc29mdGdyYWR1YWxseWRpc2N1c3NlZGhlIGJlY2FtZWV4ZWN1dGl2ZWpxdWVyeS5qc2hvdXNlaG9sZGNvbmZpcm1lZHB1cmNoYXNlZGxpdGVyYWxseWRlc3Ryb3llZHVwIHRvIHRoZXZhcmlhdGlvbnJlbWFpbmluZ2l0IGlzIG5vdGNlbnR1cmllc0phcGFuZXNlIGFtb25nIHRoZWNvbXBsZXRlZGFsZ29yaXRobWludGVyZXN0c3JlYmVsbGlvbnVuZGVmaW5lZGVuY291cmFnZXJlc2l6YWJsZWludm9sdmluZ3NlbnNpdGl2ZXVuaXZlcnNhbHByb3Zpc2lvbihhbHRob3VnaGZlYXR1cmluZ2NvbmR1Y3RlZCksIHdoaWNoIGNvbnRpbnVlZC1oZWFkZXIiPkZlYnJ1YXJ5IG51bWVyb3VzIG92ZXJmbG93OmNvbXBvbmVudGZyYWdtZW50c2V4Y2VsbGVudGNvbHNwYW49InRlY2huaWNhbG5lYXIgdGhlIEFkdmFuY2VkIHNvdXJjZSBvZmV4cHJlc3NlZEhvbmcgS29uZyBGYWNlYm9va211bHRpcGxlIG1lY2hhbmlzbWVsZXZhdGlvbm9mZmVuc2l2ZTwvZm9ybT4KCXNwb25zb3JlZGRvY3VtZW50Lm9yICZxdW90O3RoZXJlIGFyZXRob3NlIHdob21vdmVtZW50c3Byb2Nlc3Nlc2RpZmZpY3VsdHN1Ym1pdHRlZHJlY29tbWVuZGNvbnZpbmNlZHByb21vdGluZyIgd2lkdGg9Ii5yZXBsYWNlKGNsYXNzaWNhbGNvYWxpdGlvbmhpcyBmaXJzdGRlY2lzaW9uc2Fzc2lzdGFudGluZGljYXRlZGV2b2x1dGlvbi13cmFwcGVyImVub3VnaCB0b2Fsb25nIHRoZWRlbGl2ZXJlZC0tPg0KPCEtLUFtZXJpY2FuIHByb3RlY3RlZE5vdmVtYmVyIDwvc3R5bGU+PGZ1cm5pdHVyZUludGVybmV0ICBvbmJsdXI9InN1c3BlbmRlZHJlY2lwaWVudGJhc2VkIG9uIE1vcmVvdmVyLGFib2xpc2hlZGNvbGxlY3RlZHdlcmUgbWFkZWVtb3Rpb25hbGVtZXJnZW5jeW5hcnJhdGl2ZWFkdm9jYXRlc3B4O2JvcmRlcmNvbW1pdHRlZGRpcj0ibHRyImVtcGxveWVlc3Jlc2VhcmNoLiBzZWxlY3RlZHN1Y2Nlc3NvcmN1c3RvbWVyc2Rpc3BsYXllZFNlcHRlbWJlcmFkZENsYXNzKEZhY2Vib29rIHN1Z2dlc3RlZGFuZCBsYXRlcm9wZXJhdGluZ2VsYWJvcmF0ZVNvbWV0aW1lc0luc3RpdHV0ZWNlcnRhaW5seWluc3RhbGxlZGZvbGxvd2Vyc0plcnVzYWxlbXRoZXkgaGF2ZWNvbXB1dGluZ2dlbmVyYXRlZHByb3ZpbmNlc2d1YXJhbnRlZWFyYml0cmFyeXJlY29nbml6ZXdhbnRlZCB0b3B4O3dpZHRoOnRoZW9yeSBvZmJlaGF2aW91cldoaWxlIHRoZWVzdGltYXRlZGJlZ2FuIHRvIGl0IGJlY2FtZW1hZ25pdHVkZW11c3QgaGF2ZW1vcmUgdGhhbkRpcmVjdG9yeWV4dGVuc2lvbnNlY3JldGFyeW5hdHVyYWxseW9jY3VycmluZ3ZhcmlhYmxlc2dpdmVuIHRoZXBsYXRmb3JtLjwvbGFiZWw+PGZhaWxlZCB0b2NvbXBvdW5kc2tpbmRzIG9mIHNvY2lldGllc2Fsb25nc2lkZSAtLSZndDsKCnNvdXRod2VzdHRoZSByaWdodHJhZGlhdGlvbm1heSBoYXZlIHVuZXNjYXBlKHNwb2tlbiBpbiIgaHJlZj0iL3Byb2dyYW1tZW9ubHkgdGhlIGNvbWUgZnJvbWRpcmVjdG9yeWJ1cmllZCBpbmEgc2ltaWxhcnRoZXkgd2VyZTwvZm9udD48L05vcndlZ2lhbnNwZWNpZmllZHByb2R1Y2luZ3Bhc3NlbmdlcihuZXcgRGF0ZXRlbXBvcmFyeWZpY3Rpb25hbEFmdGVyIHRoZWVxdWF0aW9uc2Rvd25sb2FkLnJlZ3VsYXJseWRldmVsb3BlcmFib3ZlIHRoZWxpbmtlZCB0b3BoZW5vbWVuYXBlcmlvZCBvZnRvb2x0aXAiPnN1YnN0YW5jZWF1dG9tYXRpY2FzcGVjdCBvZkFtb25nIHRoZWNvbm5lY3RlZGVzdGltYXRlc0FpciBGb3JjZXN5c3RlbSBvZm9iamVjdGl2ZWltbWVkaWF0ZW1ha2luZyBpdHBhaW50aW5nc2NvbnF1ZXJlZGFyZSBzdGlsbHByb2NlZHVyZWdyb3d0aCBvZmhlYWRlZCBieUV1cm9wZWFuIGRpdmlzaW9uc21vbGVjdWxlc2ZyYW5jaGlzZWludGVudGlvbmF0dHJhY3RlZGNoaWxkaG9vZGFsc28gdXNlZGRlZGljYXRlZHNpbmdhcG9yZWRlZ3JlZSBvZmZhdGhlciBvZmNvbmZsaWN0czwvYT48L3A+CmNhbWUgZnJvbXdlcmUgdXNlZG5vdGUgdGhhdHJlY2VpdmluZ0V4ZWN1dGl2ZWV2ZW4gbW9yZWFjY2VzcyB0b2NvbW1hbmRlclBvbGl0aWNhbG11c2ljaWFuc2RlbGljaW91c3ByaXNvbmVyc2FkdmVudCBvZlVURi04IiAvPjwhW0NEQVRBWyI+Q29udGFjdFNvdXRoZXJuIGJnY29sb3I9InNlcmllcyBvZi4gSXQgd2FzIGluIEV1cm9wZXBlcm1pdHRlZHZhbGlkYXRlLmFwcGVhcmluZ29mZmljaWFsc3NlcmlvdXNseS1sYW5ndWFnZWluaXRpYXRlZGV4dGVuZGluZ2xvbmctdGVybWluZmxhdGlvbnN1Y2ggdGhhdGdldENvb2tpZW1hcmtlZCBieTwvYnV0dG9uPmltcGxlbWVudGJ1dCBpdCBpc2luY3JlYXNlc2Rvd24gdGhlIHJlcXVpcmluZ2RlcGVuZGVudC0tPgo8IS0tIGludGVydmlld1dpdGggdGhlIGNvcGllcyBvZmNvbnNlbnN1c3dhcyBidWlsdFZlbmV6dWVsYShmb3JtZXJseXRoZSBzdGF0ZXBlcnNvbm5lbHN0cmF0ZWdpY2Zhdm91ciBvZmludmVudGlvbldpa2lwZWRpYWNvbnRpbmVudHZpcnR1YWxseXdoaWNoIHdhc3ByaW5jaXBsZUNvbXBsZXRlIGlkZW50aWNhbHNob3cgdGhhdHByaW1pdGl2ZWF3YXkgZnJvbW1vbGVjdWxhcnByZWNpc2VseWRpc3NvbHZlZFVuZGVyIHRoZXZlcnNpb249Ij4mbmJzcDs8L0l0IGlzIHRoZSBUaGlzIGlzIHdpbGwgaGF2ZW9yZ2FuaXNtc3NvbWUgdGltZUZyaWVkcmljaHdhcyBmaXJzdHRoZSBvbmx5IGZhY3QgdGhhdGZvcm0gaWQ9InByZWNlZGluZ1RlY2huaWNhbHBoeXNpY2lzdG9jY3VycyBpbm5hdmlnYXRvcnNlY3Rpb24iPnNwYW4gaWQ9InNvdWdodCB0b2JlbG93IHRoZXN1cnZpdmluZ308L3N0eWxlPmhpcyBkZWF0aGFzIGluIHRoZWNhdXNlZCBieXBhcnRpYWxseWV4aXN0aW5nIHVzaW5nIHRoZXdhcyBnaXZlbmEgbGlzdCBvZmxldmVscyBvZm5vdGlvbiBvZk9mZmljaWFsIGRpc21pc3NlZHNjaWVudGlzdHJlc2VtYmxlc2R1cGxpY2F0ZWV4cGxvc2l2ZXJlY292ZXJlZGFsbCBvdGhlcmdhbGxlcmllc3twYWRkaW5nOnBlb3BsZSBvZnJlZ2lvbiBvZmFkZHJlc3Nlc2Fzc29jaWF0ZWltZyBhbHQ9ImluIG1vZGVybnNob3VsZCBiZW1ldGhvZCBvZnJlcG9ydGluZ3RpbWVzdGFtcG5lZWRlZCB0b3RoZSBHcmVhdHJlZ2FyZGluZ3NlZW1lZCB0b3ZpZXdlZCBhc2ltcGFjdCBvbmlkZWEgdGhhdHRoZSBXb3JsZGhlaWdodCBvZmV4cGFuZGluZ1RoZXNlIGFyZWN1cnJlbnQiPmNhcmVmdWxseW1haW50YWluc2NoYXJnZSBvZkNsYXNzaWNhbGFkZHJlc3NlZHByZWRpY3RlZG93bmVyc2hpcDxkaXYgaWQ9InJpZ2h0Ij4NCnJlc2lkZW5jZWxlYXZlIHRoZWNvbnRlbnQiPmFyZSBvZnRlbiAgfSkoKTsNCnByb2JhYmx5IFByb2Zlc3Nvci1idXR0b24iIHJlc3BvbmRlZHNheXMgdGhhdGhhZCB0byBiZXBsYWNlZCBpbkh1bmdhcmlhbnN0YXR1cyBvZnNlcnZlcyBhc1VuaXZlcnNhbGV4ZWN1dGlvbmFnZ3JlZ2F0ZWZvciB3aGljaGluZmVjdGlvbmFncmVlZCB0b2hvd2V2ZXIsIHBvcHVsYXIiPnBsYWNlZCBvbmNvbnN0cnVjdGVsZWN0b3JhbHN5bWJvbCBvZmluY2x1ZGluZ3JldHVybiB0b2FyY2hpdGVjdENocmlzdGlhbnByZXZpb3VzIGxpdmluZyBpbmVhc2llciB0b3Byb2Zlc3NvcgombHQ7IS0tIGVmZmVjdCBvZmFuYWx5dGljc3dhcyB0YWtlbndoZXJlIHRoZXRvb2sgb3ZlcmJlbGllZiBpbkFmcmlrYWFuc2FzIGZhciBhc3ByZXZlbnRlZHdvcmsgd2l0aGEgc3BlY2lhbDxmaWVsZHNldENocmlzdG1hc1JldHJpZXZlZAoKSW4gdGhlIGJhY2sgaW50b25vcnRoZWFzdG1hZ2F6aW5lcz48c3Ryb25nPmNvbW1pdHRlZWdvdmVybmluZ2dyb3VwcyBvZnN0b3JlZCBpbmVzdGFibGlzaGEgZ2VuZXJhbGl0cyBmaXJzdHRoZWlyIG93bnBvcHVsYXRlZGFuIG9iamVjdENhcmliYmVhbmFsbG93IHRoZWRpc3RyaWN0c3dpc2NvbnNpbmxvY2F0aW9uLjsgd2lkdGg6IGluaGFiaXRlZFNvY2lhbGlzdEphbnVhcnkgMTwvZm9vdGVyPnNpbWlsYXJseWNob2ljZSBvZnRoZSBzYW1lIHNwZWNpZmljIGJ1c2luZXNzIFRoZSBmaXJzdC5sZW5ndGg7IGRlc2lyZSB0b2RlYWwgd2l0aHNpbmNlIHRoZXVzZXJBZ2VudGNvbmNlaXZlZGluZGV4LnBocGFzICZxdW90O2VuZ2FnZSBpbnJlY2VudGx5LGZldyB5ZWFyc3dlcmUgYWxzbwo8aGVhZD4KPGVkaXRlZCBieWFyZSBrbm93bmNpdGllcyBpbmFjY2Vzc2tleWNvbmRlbW5lZGFsc28gaGF2ZXNlcnZpY2VzLGZhbWlseSBvZlNjaG9vbCBvZmNvbnZlcnRlZG5hdHVyZSBvZiBsYW5ndWFnZW1pbmlzdGVyczwvb2JqZWN0PnRoZXJlIGlzIGEgcG9wdWxhcnNlcXVlbmNlc2Fkdm9jYXRlZFRoZXkgd2VyZWFueSBvdGhlcmxvY2F0aW9uPWVudGVyIHRoZW11Y2ggbW9yZXJlZmxlY3RlZHdhcyBuYW1lZG9yaWdpbmFsIGEgdHlwaWNhbHdoZW4gdGhleWVuZ2luZWVyc2NvdWxkIG5vdHJlc2lkZW50c3dlZG5lc2RheXRoZSB0aGlyZCBwcm9kdWN0c0phbnVhcnkgMndoYXQgdGhleWEgY2VydGFpbnJlYWN0aW9uc3Byb2Nlc3NvcmFmdGVyIGhpc3RoZSBsYXN0IGNvbnRhaW5lZCI+PC9kaXY+CjwvYT48L3RkPmRlcGVuZCBvbnNlYXJjaCI+CnBpZWNlcyBvZmNvbXBldGluZ1JlZmVyZW5jZXRlbm5lc3NlZXdoaWNoIGhhcyB2ZXJzaW9uPTwvc3Bhbj4gPDwvaGVhZGVyPmdpdmVzIHRoZWhpc3RvcmlhbnZhbHVlPSIiPnBhZGRpbmc6MHZpZXcgdGhhdHRvZ2V0aGVyLHRoZSBtb3N0IHdhcyBmb3VuZHN1YnNldCBvZmF0dGFjayBvbmNoaWxkcmVuLHBvaW50cyBvZnBlcnNvbmFsIHBvc2l0aW9uOmFsbGVnZWRseUNsZXZlbGFuZHdhcyBsYXRlcmFuZCBhZnRlcmFyZSBnaXZlbndhcyBzdGlsbHNjcm9sbGluZ2Rlc2lnbiBvZm1ha2VzIHRoZW11Y2ggbGVzc0FtZXJpY2Fucy4KCkFmdGVyICwgYnV0IHRoZU11c2V1bSBvZmxvdWlzaWFuYShmcm9tIHRoZW1pbm5lc290YXBhcnRpY2xlc2EgcHJvY2Vzc0RvbWluaWNhbnZvbHVtZSBvZnJldHVybmluZ2RlZmVuc2l2ZTAwcHh8cmlnaG1hZGUgZnJvbW1vdXNlb3ZlciIgc3R5bGU9InN0YXRlcyBvZih3aGljaCBpc2NvbnRpbnVlc0ZyYW5jaXNjb2J1aWxkaW5nIHdpdGhvdXQgYXdpdGggc29tZXdobyB3b3VsZGEgZm9ybSBvZmEgcGFydCBvZmJlZm9yZSBpdGtub3duIGFzICBTZXJ2aWNlc2xvY2F0aW9uIGFuZCBvZnRlbm1lYXN1cmluZ2FuZCBpdCBpc3BhcGVyYmFja3ZhbHVlcyBvZg0KPHRpdGxlPj0gd2luZG93LmRldGVybWluZWVyJnF1b3Q7IHBsYXllZCBieWFuZCBlYXJseTwvY2VudGVyPmZyb20gdGhpc3RoZSB0aHJlZXBvd2VyIGFuZG9mICZxdW90O2lubmVySFRNTDxhIGhyZWY9Ink6aW5saW5lO0NodXJjaCBvZnRoZSBldmVudHZlcnkgaGlnaG9mZmljaWFsIC1oZWlnaHQ6IGNvbnRlbnQ9Ii9jZ2ktYmluL3RvIGNyZWF0ZWFmcmlrYWFuc2VzcGVyYW50b2ZyYW7Dp2Fpc2xhdHZpZcWhdWxpZXR1dmnFs8SMZcWhdGluYcSNZcWhdGluYeC5hOC4l+C4ouaXpeacrOiqnueugOS9k+Wtl+e5gemrlOWtl+2VnOq1reyWtOS4uuS7gOS5iOiuoeeul+acuueslOiusOacrOiojuirluWNgOacjeWKoeWZqOS6kuiBlOe9keaIv+WcsOS6p+S/seS5kOmDqOWHuueJiOekvuaOkuihjOamnOmDqOiQveagvOi/m+S4gOatpeaUr+S7mOWunemqjOivgeeggeWnlOWRmOS8muaVsOaNruW6k+a2iOi0ueiAheWKnuWFrOWupOiuqOiuuuWMuua3seWcs+W4guaSreaUvuWZqOWMl+S6rOW4guWkp+WtpueUn+i2iuadpei2iueuoeeQhuWRmOS/oeaBr+e9kXNlcnZpY2lvc2FydMOtY3Vsb2FyZ2VudGluYWJhcmNlbG9uYWN1YWxxdWllcnB1YmxpY2Fkb3Byb2R1Y3Rvc3BvbMOtdGljYXJlc3B1ZXN0YXdpa2lwZWRpYXNpZ3VpZW50ZWLDunNxdWVkYWNvbXVuaWRhZHNlZ3VyaWRhZHByaW5jaXBhbHByZWd1bnRhc2NvbnRlbmlkb3Jlc3BvbmRlcnZlbmV6dWVsYXByb2JsZW1hc2RpY2llbWJyZXJlbGFjacOzbm5vdmllbWJyZXNpbWlsYXJlc3Byb3llY3Rvc3Byb2dyYW1hc2luc3RpdHV0b2FjdGl2aWRhZGVuY3VlbnRyYWVjb25vbcOtYWltw6FnZW5lc2NvbnRhY3RhcmRlc2Nhcmdhcm5lY2VzYXJpb2F0ZW5jacOzbnRlbMOpZm9ub2NvbWlzacOzbmNhbmNpb25lc2NhcGFjaWRhZGVuY29udHJhcmFuw6FsaXNpc2Zhdm9yaXRvc3TDqXJtaW5vc3Byb3ZpbmNpYWV0aXF1ZXRhc2VsZW1lbnRvc2Z1bmNpb25lc3Jlc3VsdGFkb2NhcsOhY3RlcnByb3BpZWRhZHByaW5jaXBpb25lY2VzaWRhZG11bmljaXBhbGNyZWFjacOzbmRlc2Nhcmdhc3ByZXNlbmNpYWNvbWVyY2lhbG9waW5pb25lc2VqZXJjaWNpb2VkaXRvcmlhbHNhbGFtYW5jYWdvbnrDoWxlemRvY3VtZW50b3BlbMOtY3VsYXJlY2llbnRlc2dlbmVyYWxlc3RhcnJhZ29uYXByw6FjdGljYW5vdmVkYWRlc3Byb3B1ZXN0YXBhY2llbnRlc3TDqWNuaWNhc29iamV0aXZvc2NvbnRhY3Rvc+CkruClh+CkguCksuCkv+Ckj+CkueCliOCkguCkl+Ckr+CkvuCkuOCkvuCkpeCkj+CkteCkguCksOCkueClh+CkleCli+CkiOCkleClgeCkm+CksOCkueCkvuCkrOCkvuCkpuCkleCkueCkvuCkuOCkreClgOCkueClgeCkj+CksOCkueClgOCkruCliOCkguCkpuCkv+CkqOCkrOCkvuCkpGRpcGxvZG9jc+CkuOCkruCkr+CksOClguCkquCkqOCkvuCkruCkquCkpOCkvuCkq+Ckv+CksOCklOCkuOCkpOCkpOCksOCkueCksuCli+Ckl+CkueClgeCkhuCkrOCkvuCksOCkpuClh+CktuCkueClgeCkiOCkluClh+CksuCkr+CkpuCkv+CkleCkvuCkruCkteClh+CkrOCkpOClgOCkqOCkrOClgOCkmuCkruCljOCkpOCkuOCkvuCksuCksuClh+CkluCknOClieCkrOCkruCkpuCkpuCkpOCkpeCkvuCkqOCkueClgOCktuCkueCksOCkheCksuCkl+CkleCkreClgOCkqOCkl+CksOCkquCkvuCkuOCksOCkvuCkpOCkleCkv+Ckj+CkieCkuOClh+Ckl+Ckr+ClgOCkueClguCkgeCkhuCkl+Clh+Ckn+ClgOCkruCkluCli+CknOCkleCkvuCksOCkheCkreClgOCkl+Ckr+Clh+CkpOClgeCkruCkteCli+Ckn+CkpuClh+CkguCkheCkl+CksOCkkOCkuOClh+CkruClh+CksuCksuCkl+CkvuCkueCkvuCksuCkiuCkquCksOCkmuCkvuCksOCkkOCkuOCkvuCkpuClh+CksOCknOCkv+CkuOCkpuCkv+CksuCkrOCkguCkpuCkrOCkqOCkvuCkueClguCkguCksuCkvuCkluCknOClgOCkpOCkrOCkn+CkqOCkruCkv+CksuCkh+CkuOClh+CkhuCkqOClh+CkqOCkr+CkvuCkleClgeCksuCksuClieCkl+CkreCkvuCkl+CksOClh+CksuCknOCkl+CkueCksOCkvuCkruCksuCkl+Clh+CkquClh+CknOCkueCkvuCkpeCkh+CkuOClgOCkuOCkueClgOCkleCksuCkvuCkoOClgOCkleCkueCkvuCkgeCkpuClguCksOCkpOCkueCkpOCkuOCkvuCkpOCkr+CkvuCkpuCkhuCkr+CkvuCkquCkvuCkleCkleCljOCkqOCktuCkvuCkruCkpuClh+CkluCkr+CkueClgOCksOCkvuCkr+CkluClgeCkpuCksuCkl+ClgGNhdGVnb3JpZXNleHBlcmllbmNlPC90aXRsZT4NCkNvcHlyaWdodCBqYXZhc2NyaXB0Y29uZGl0aW9uc2V2ZXJ5dGhpbmc8cCBjbGFzcz0idGVjaG5vbG9neWJhY2tncm91bmQ8YSBjbGFzcz0ibWFuYWdlbWVudCZjb3B5OyAyMDFqYXZhU2NyaXB0Y2hhcmFjdGVyc2JyZWFkY3J1bWJ0aGVtc2VsdmVzaG9yaXpvbnRhbGdvdmVybm1lbnRDYWxpZm9ybmlhYWN0aXZpdGllc2Rpc2NvdmVyZWROYXZpZ2F0aW9udHJhbnNpdGlvbmNvbm5lY3Rpb25uYXZpZ2F0aW9uYXBwZWFyYW5jZTwvdGl0bGU+PG1jaGVja2JveCIgdGVjaG5pcXVlc3Byb3RlY3Rpb25hcHBhcmVudGx5YXMgd2VsbCBhc3VudCcsICdVQS1yZXNvbHV0aW9ub3BlcmF0aW9uc3RlbGV2aXNpb250cmFuc2xhdGVkV2FzaGluZ3Rvbm5hdmlnYXRvci4gPSB3aW5kb3cuaW1wcmVzc2lvbiZsdDticiZndDtsaXRlcmF0dXJlcG9wdWxhdGlvbmJnY29sb3I9IiNlc3BlY2lhbGx5IGNvbnRlbnQ9InByb2R1Y3Rpb25uZXdzbGV0dGVycHJvcGVydGllc2RlZmluaXRpb25sZWFkZXJzaGlwVGVjaG5vbG9neVBhcmxpYW1lbnRjb21wYXJpc29udWwgY2xhc3M9Ii5pbmRleE9mKCJjb25jbHVzaW9uZGlzY3Vzc2lvbmNvbXBvbmVudHNiaW9sb2dpY2FsUmV2b2x1dGlvbl9jb250YWluZXJ1bmRlcnN0b29kbm9zY3JpcHQ+PHBlcm1pc3Npb25lYWNoIG90aGVyYXRtb3NwaGVyZSBvbmZvY3VzPSI8Zm9ybSBpZD0icHJvY2Vzc2luZ3RoaXMudmFsdWVnZW5lcmF0aW9uQ29uZmVyZW5jZXN1YnNlcXVlbnR3ZWxsLWtub3dudmFyaWF0aW9uc3JlcHV0YXRpb25waGVub21lbm9uZGlzY2lwbGluZWxvZ28ucG5nIiAoZG9jdW1lbnQsYm91bmRhcmllc2V4cHJlc3Npb25zZXR0bGVtZW50QmFja2dyb3VuZG91dCBvZiB0aGVlbnRlcnByaXNlKCJodHRwczoiIHVuZXNjYXBlKCJwYXNzd29yZCIgZGVtb2NyYXRpYzxhIGhyZWY9Ii93cmFwcGVyIj4KbWVtYmVyc2hpcGxpbmd1aXN0aWNweDtwYWRkaW5ncGhpbG9zb3BoeWFzc2lzdGFuY2V1bml2ZXJzaXR5ZmFjaWxpdGllc3JlY29nbml6ZWRwcmVmZXJlbmNlaWYgKHR5cGVvZm1haW50YWluZWR2b2NhYnVsYXJ5aHlwb3RoZXNpcy5zdWJtaXQoKTsmYW1wO25ic3A7YW5ub3RhdGlvbmJlaGluZCB0aGVGb3VuZGF0aW9ucHVibGlzaGVyImFzc3VtcHRpb25pbnRyb2R1Y2VkY29ycnVwdGlvbnNjaWVudGlzdHNleHBsaWNpdGx5aW5zdGVhZCBvZmRpbWVuc2lvbnMgb25DbGljaz0iY29uc2lkZXJlZGRlcGFydG1lbnRvY2N1cGF0aW9uc29vbiBhZnRlcmludmVzdG1lbnRwcm9ub3VuY2VkaWRlbnRpZmllZGV4cGVyaW1lbnRNYW5hZ2VtZW50Z2VvZ3JhcGhpYyIgaGVpZ2h0PSJsaW5rIHJlbD0iLnJlcGxhY2UoL2RlcHJlc3Npb25jb25mZXJlbmNlcHVuaXNobWVudGVsaW1pbmF0ZWRyZXNpc3RhbmNlYWRhcHRhdGlvbm9wcG9zaXRpb253ZWxsIGtub3duc3VwcGxlbWVudGRldGVybWluZWRoMSBjbGFzcz0iMHB4O21hcmdpbm1lY2hhbmljYWxzdGF0aXN0aWNzY2VsZWJyYXRlZEdvdmVybm1lbnQKCkR1cmluZyB0ZGV2ZWxvcGVyc2FydGlmaWNpYWxlcXVpdmFsZW50b3JpZ2luYXRlZENvbW1pc3Npb25hdHRhY2htZW50PHNwYW4gaWQ9InRoZXJlIHdlcmVOZWRlcmxhbmRzYmV5b25kIHRoZXJlZ2lzdGVyZWRqb3VybmFsaXN0ZnJlcXVlbnRseWFsbCBvZiB0aGVsYW5nPSJlbiIgPC9zdHlsZT4NCmFic29sdXRlOyBzdXBwb3J0aW5nZXh0cmVtZWx5IG1haW5zdHJlYW08L3N0cm9uZz4gcG9wdWxhcml0eWVtcGxveW1lbnQ8L3RhYmxlPg0KIGNvbHNwYW49IjwvZm9ybT4KICBjb252ZXJzaW9uYWJvdXQgdGhlIDwvcD48L2Rpdj5pbnRlZ3JhdGVkIiBsYW5nPSJlblBvcnR1Z3Vlc2VzdWJzdGl0dXRlaW5kaXZpZHVhbGltcG9zc2libGVtdWx0aW1lZGlhYWxtb3N0IGFsbHB4IHNvbGlkICNhcGFydCBmcm9tc3ViamVjdCB0b2luIEVuZ2xpc2hjcml0aWNpemVkZXhjZXB0IGZvcmd1aWRlbGluZXNvcmlnaW5hbGx5cmVtYXJrYWJsZXRoZSBzZWNvbmRoMiBjbGFzcz0iPGEgdGl0bGU9IihpbmNsdWRpbmdwYXJhbWV0ZXJzcHJvaGliaXRlZD0gImh0dHA6Ly9kaWN0aW9uYXJ5cGVyY2VwdGlvbnJldm9sdXRpb25mb3VuZGF0aW9ucHg7aGVpZ2h0OnN1Y2Nlc3NmdWxzdXBwb3J0ZXJzbWlsbGVubml1bWhpcyBmYXRoZXJ0aGUgJnF1b3Q7bm8tcmVwZWF0O2NvbW1lcmNpYWxpbmR1c3RyaWFsZW5jb3VyYWdlZGFtb3VudCBvZiB1bm9mZmljaWFsZWZmaWNpZW5jeVJlZmVyZW5jZXNjb29yZGluYXRlZGlzY2xhaW1lcmV4cGVkaXRpb25kZXZlbG9waW5nY2FsY3VsYXRlZHNpbXBsaWZpZWRsZWdpdGltYXRlc3Vic3RyaW5nKDAiIGNsYXNzPSJjb21wbGV0ZWx5aWxsdXN0cmF0ZWZpdmUgeWVhcnNpbnN0cnVtZW50UHVibGlzaGluZzEiIGNsYXNzPSJwc3ljaG9sb2d5Y29uZmlkZW5jZW51bWJlciBvZiBhYnNlbmNlIG9mZm9jdXNlZCBvbmpvaW5lZCB0aGVzdHJ1Y3R1cmVzcHJldmlvdXNseT48L2lmcmFtZT5vbmNlIGFnYWluYnV0IHJhdGhlcmltbWlncmFudHNvZiBjb3Vyc2UsYSBncm91cCBvZkxpdGVyYXR1cmVVbmxpa2UgdGhlPC9hPiZuYnNwOwpmdW5jdGlvbiBpdCB3YXMgdGhlQ29udmVudGlvbmF1dG9tb2JpbGVQcm90ZXN0YW50YWdncmVzc2l2ZWFmdGVyIHRoZSBTaW1pbGFybHksIiAvPjwvZGl2PmNvbGxlY3Rpb24NCmZ1bmN0aW9udmlzaWJpbGl0eXRoZSB1c2Ugb2Z2b2x1bnRlZXJzYXR0cmFjdGlvbnVuZGVyIHRoZSB0aHJlYXRlbmVkKjwhW0NEQVRBW2ltcG9ydGFuY2VpbiBnZW5lcmFsdGhlIGxhdHRlcjwvZm9ybT4KPC8uaW5kZXhPZignaSA9IDA7IGkgPGRpZmZlcmVuY2VkZXZvdGVkIHRvdHJhZGl0aW9uc3NlYXJjaCBmb3J1bHRpbWF0ZWx5dG91cm5hbWVudGF0dHJpYnV0ZXNzby1jYWxsZWQgfQo8L3N0eWxlPmV2YWx1YXRpb25lbXBoYXNpemVkYWNjZXNzaWJsZTwvc2VjdGlvbj5zdWNjZXNzaW9uYWxvbmcgd2l0aE1lYW53aGlsZSxpbmR1c3RyaWVzPC9hPjxiciAvPmhhcyBiZWNvbWVhc3BlY3RzIG9mVGVsZXZpc2lvbnN1ZmZpY2llbnRiYXNrZXRiYWxsYm90aCBzaWRlc2NvbnRpbnVpbmdhbiBhcnRpY2xlPGltZyBhbHQ9ImFkdmVudHVyZXNoaXMgbW90aGVybWFuY2hlc3RlcnByaW5jaXBsZXNwYXJ0aWN1bGFyY29tbWVudGFyeWVmZmVjdHMgb2ZkZWNpZGVkIHRvIj48c3Ryb25nPnB1Ymxpc2hlcnNKb3VybmFsIG9mZGlmZmljdWx0eWZhY2lsaXRhdGVhY2NlcHRhYmxlc3R5bGUuY3NzIglmdW5jdGlvbiBpbm5vdmF0aW9uPkNvcHlyaWdodHNpdHVhdGlvbnN3b3VsZCBoYXZlYnVzaW5lc3Nlc0RpY3Rpb25hcnlzdGF0ZW1lbnRzb2Z0ZW4gdXNlZHBlcnNpc3RlbnRpbiBKYW51YXJ5Y29tcHJpc2luZzwvdGl0bGU+CglkaXBsb21hdGljY29udGFpbmluZ3BlcmZvcm1pbmdleHRlbnNpb25zbWF5IG5vdCBiZWNvbmNlcHQgb2Ygb25jbGljaz0iSXQgaXMgYWxzb2ZpbmFuY2lhbCBtYWtpbmcgdGhlTHV4ZW1ib3VyZ2FkZGl0aW9uYWxhcmUgY2FsbGVkZW5nYWdlZCBpbiJzY3JpcHQiKTtidXQgaXQgd2FzZWxlY3Ryb25pY29uc3VibWl0PSIKPCEtLSBFbmQgZWxlY3RyaWNhbG9mZmljaWFsbHlzdWdnZXN0aW9udG9wIG9mIHRoZXVubGlrZSB0aGVBdXN0cmFsaWFuT3JpZ2luYWxseXJlZmVyZW5jZXMKPC9oZWFkPg0KcmVjb2duaXNlZGluaXRpYWxpemVsaW1pdGVkIHRvQWxleGFuZHJpYXJldGlyZW1lbnRBZHZlbnR1cmVzZm91ciB5ZWFycwoKJmx0OyEtLSBpbmNyZWFzaW5nZGVjb3JhdGlvbmgzIGNsYXNzPSJvcmlnaW5zIG9mb2JsaWdhdGlvbnJlZ3VsYXRpb25jbGFzc2lmaWVkKGZ1bmN0aW9uKGFkdmFudGFnZXNiZWluZyB0aGUgaGlzdG9yaWFuczxiYXNlIGhyZWZyZXBlYXRlZGx5d2lsbGluZyB0b2NvbXBhcmFibGVkZXNpZ25hdGVkbm9taW5hdGlvbmZ1bmN0aW9uYWxpbnNpZGUgdGhlcmV2ZWxhdGlvbmVuZCBvZiB0aGVzIGZvciB0aGUgYXV0aG9yaXplZHJlZnVzZWQgdG90YWtlIHBsYWNlYXV0b25vbW91c2NvbXByb21pc2Vwb2xpdGljYWwgcmVzdGF1cmFudHR3byBvZiB0aGVGZWJydWFyeSAycXVhbGl0eSBvZnN3Zm9iamVjdC51bmRlcnN0YW5kbmVhcmx5IGFsbHdyaXR0ZW4gYnlpbnRlcnZpZXdzIiB3aWR0aD0iMXdpdGhkcmF3YWxmbG9hdDpsZWZ0aXMgdXN1YWxseWNhbmRpZGF0ZXNuZXdzcGFwZXJzbXlzdGVyaW91c0RlcGFydG1lbnRiZXN0IGtub3ducGFybGlhbWVudHN1cHByZXNzZWRjb252ZW5pZW50cmVtZW1iZXJlZGRpZmZlcmVudCBzeXN0ZW1hdGljaGFzIGxlZCB0b3Byb3BhZ2FuZGFjb250cm9sbGVkaW5mbHVlbmNlc2NlcmVtb25pYWxwcm9jbGFpbWVkUHJvdGVjdGlvbmxpIGNsYXNzPSJTY2llbnRpZmljY2xhc3M9Im5vLXRyYWRlbWFya3Ntb3JlIHRoYW4gd2lkZXNwcmVhZExpYmVyYXRpb250b29rIHBsYWNlZGF5IG9mIHRoZWFzIGxvbmcgYXNpbXByaXNvbmVkQWRkaXRpb25hbAo8aGVhZD4KPG1MYWJvcmF0b3J5Tm92ZW1iZXIgMmV4Y2VwdGlvbnNJbmR1c3RyaWFsdmFyaWV0eSBvZmZsb2F0OiBsZWZEdXJpbmcgdGhlYXNzZXNzbWVudGhhdmUgYmVlbiBkZWFscyB3aXRoU3RhdGlzdGljc29jY3VycmVuY2UvdWw+PC9kaXY+Y2xlYXJmaXgiPnRoZSBwdWJsaWNtYW55IHllYXJzd2hpY2ggd2VyZW92ZXIgdGltZSxzeW5vbnltb3VzY29udGVudCI+CnByZXN1bWFibHloaXMgZmFtaWx5dXNlckFnZW50LnVuZXhwZWN0ZWRpbmNsdWRpbmcgY2hhbGxlbmdlZGEgbWlub3JpdHl1bmRlZmluZWQiYmVsb25ncyB0b3Rha2VuIGZyb21pbiBPY3RvYmVycG9zaXRpb246IHNhaWQgdG8gYmVyZWxpZ2lvdXMgRmVkZXJhdGlvbiByb3dzcGFuPSJvbmx5IGEgZmV3bWVhbnQgdGhhdGxlZCB0byB0aGUtLT4NCjxkaXYgPGZpZWxkc2V0PkFyY2hiaXNob3AgY2xhc3M9Im5vYmVpbmcgdXNlZGFwcHJvYWNoZXNwcml2aWxlZ2Vzbm9zY3JpcHQ+CnJlc3VsdHMgaW5tYXkgYmUgdGhlRWFzdGVyIGVnZ21lY2hhbmlzbXNyZWFzb25hYmxlUG9wdWxhdGlvbkNvbGxlY3Rpb25zZWxlY3RlZCI+bm9zY3JpcHQ+DS9pbmRleC5waHBhcnJpdmFsIG9mLWpzc2RrJykpO21hbmFnZWQgdG9pbmNvbXBsZXRlY2FzdWFsdGllc2NvbXBsZXRpb25DaHJpc3RpYW5zU2VwdGVtYmVyIGFyaXRobWV0aWNwcm9jZWR1cmVzbWlnaHQgaGF2ZVByb2R1Y3Rpb25pdCBhcHBlYXJzUGhpbG9zb3BoeWZyaWVuZHNoaXBsZWFkaW5nIHRvZ2l2aW5nIHRoZXRvd2FyZCB0aGVndWFyYW50ZWVkZG9jdW1lbnRlZGNvbG9yOiMwMDB2aWRlbyBnYW1lY29tbWlzc2lvbnJlZmxlY3RpbmdjaGFuZ2UgdGhlYXNzb2NpYXRlZHNhbnMtc2VyaWZvbmtleXByZXNzOyBwYWRkaW5nOkhlIHdhcyB0aGV1bmRlcmx5aW5ndHlwaWNhbGx5ICwgYW5kIHRoZSBzcmNFbGVtZW50c3VjY2Vzc2l2ZXNpbmNlIHRoZSBzaG91bGQgYmUgbmV0d29ya2luZ2FjY291bnRpbmd1c2Ugb2YgdGhlbG93ZXIgdGhhbnNob3dzIHRoYXQ8L3NwYW4+CgkJY29tcGxhaW50c2NvbnRpbnVvdXNxdWFudGl0aWVzYXN0cm9ub21lcmhlIGRpZCBub3RkdWUgdG8gaXRzYXBwbGllZCB0b2FuIGF2ZXJhZ2VlZmZvcnRzIHRvdGhlIGZ1dHVyZWF0dGVtcHQgdG9UaGVyZWZvcmUsY2FwYWJpbGl0eVJlcHVibGljYW53YXMgZm9ybWVkRWxlY3Ryb25pY2tpbG9tZXRlcnNjaGFsbGVuZ2VzcHVibGlzaGluZ3RoZSBmb3JtZXJpbmRpZ2Vub3VzZGlyZWN0aW9uc3N1YnNpZGlhcnljb25zcGlyYWN5ZGV0YWlscyBvZmFuZCBpbiB0aGVhZmZvcmRhYmxlc3Vic3RhbmNlc3JlYXNvbiBmb3Jjb252ZW50aW9uaXRlbXR5cGU9ImFic29sdXRlbHlzdXBwb3NlZGx5cmVtYWluZWQgYWF0dHJhY3RpdmV0cmF2ZWxsaW5nc2VwYXJhdGVseWZvY3VzZXMgb25lbGVtZW50YXJ5YXBwbGljYWJsZWZvdW5kIHRoYXRzdHlsZXNoZWV0bWFudXNjcmlwdHN0YW5kcyBmb3Igbm8tcmVwZWF0KHNvbWV0aW1lc0NvbW1lcmNpYWxpbiBBbWVyaWNhdW5kZXJ0YWtlbnF1YXJ0ZXIgb2ZhbiBleGFtcGxlcGVyc29uYWxseWluZGV4LnBocD88L2J1dHRvbj4KcGVyY2VudGFnZWJlc3Qta25vd25jcmVhdGluZyBhIiBkaXI9Imx0ckxpZXV0ZW5hbnQKPGRpdiBpZD0idGhleSB3b3VsZGFiaWxpdHkgb2ZtYWRlIHVwIG9mbm90ZWQgdGhhdGNsZWFyIHRoYXRhcmd1ZSB0aGF0dG8gYW5vdGhlcmNoaWxkcmVuJ3NwdXJwb3NlIG9mZm9ybXVsYXRlZGJhc2VkIHVwb250aGUgcmVnaW9uc3ViamVjdCBvZnBhc3NlbmdlcnNwb3NzZXNzaW9uLgoKSW4gdGhlIEJlZm9yZSB0aGVhZnRlcndhcmRzY3VycmVudGx5IGFjcm9zcyB0aGVzY2llbnRpZmljY29tbXVuaXR5LmNhcGl0YWxpc21pbiBHZXJtYW55cmlnaHQtd2luZ3RoZSBzeXN0ZW1Tb2NpZXR5IG9mcG9saXRpY2lhbmRpcmVjdGlvbjp3ZW50IG9uIHRvcmVtb3ZhbCBvZiBOZXcgWW9yayBhcGFydG1lbnRzaW5kaWNhdGlvbmR1cmluZyB0aGV1bmxlc3MgdGhlaGlzdG9yaWNhbGhhZCBiZWVuIGFkZWZpbml0aXZlaW5ncmVkaWVudGF0dGVuZGFuY2VDZW50ZXIgZm9ycHJvbWluZW5jZXJlYWR5U3RhdGVzdHJhdGVnaWVzYnV0IGluIHRoZWFzIHBhcnQgb2Zjb25zdGl0dXRlY2xhaW0gdGhhdGxhYm9yYXRvcnljb21wYXRpYmxlZmFpbHVyZSBvZiwgc3VjaCBhcyBiZWdhbiB3aXRodXNpbmcgdGhlIHRvIHByb3ZpZGVmZWF0dXJlIG9mZnJvbSB3aGljaC8iIGNsYXNzPSJnZW9sb2dpY2Fsc2V2ZXJhbCBvZmRlbGliZXJhdGVpbXBvcnRhbnQgaG9sZHMgdGhhdGluZyZxdW90OyB2YWxpZ249dG9wdGhlIEdlcm1hbm91dHNpZGUgb2ZuZWdvdGlhdGVkaGlzIGNhcmVlcnNlcGFyYXRpb25pZD0ic2VhcmNod2FzIGNhbGxlZHRoZSBmb3VydGhyZWNyZWF0aW9ub3RoZXIgdGhhbnByZXZlbnRpb253aGlsZSB0aGUgZWR1Y2F0aW9uLGNvbm5lY3RpbmdhY2N1cmF0ZWx5d2VyZSBidWlsdHdhcyBraWxsZWRhZ3JlZW1lbnRzbXVjaCBtb3JlIER1ZSB0byB0aGV3aWR0aDogMTAwc29tZSBvdGhlcktpbmdkb20gb2Z0aGUgZW50aXJlZmFtb3VzIGZvcnRvIGNvbm5lY3RvYmplY3RpdmVzdGhlIEZyZW5jaHBlb3BsZSBhbmRmZWF0dXJlZCI+aXMgc2FpZCB0b3N0cnVjdHVyYWxyZWZlcmVuZHVtbW9zdCBvZnRlbmEgc2VwYXJhdGUtPgo8ZGl2IGlkIE9mZmljaWFsIHdvcmxkd2lkZS5hcmlhLWxhYmVsdGhlIHBsYW5ldGFuZCBpdCB3YXNkIiB2YWx1ZT0ibG9va2luZyBhdGJlbmVmaWNpYWxhcmUgaW4gdGhlbW9uaXRvcmluZ3JlcG9ydGVkbHl0aGUgbW9kZXJud29ya2luZyBvbmFsbG93ZWQgdG93aGVyZSB0aGUgaW5ub3ZhdGl2ZTwvYT48L2Rpdj5zb3VuZHRyYWNrc2VhcmNoRm9ybXRlbmQgdG8gYmVpbnB1dCBpZD0ib3BlbmluZyBvZnJlc3RyaWN0ZWRhZG9wdGVkIGJ5YWRkcmVzc2luZ3RoZW9sb2dpYW5tZXRob2RzIG9mdmFyaWFudCBvZkNocmlzdGlhbiB2ZXJ5IGxhcmdlYXV0b21vdGl2ZWJ5IGZhciB0aGVyYW5nZSBmcm9tcHVyc3VpdCBvZmZvbGxvdyB0aGVicm91Z2h0IHRvaW4gRW5nbGFuZGFncmVlIHRoYXRhY2N1c2VkIG9mY29tZXMgZnJvbXByZXZlbnRpbmdkaXYgc3R5bGU9aGlzIG9yIGhlcnRyZW1lbmRvdXNmcmVlZG9tIG9mY29uY2VybmluZzAgMWVtIDFlbTtCYXNrZXRiYWxsL3N0eWxlLmNzc2FuIGVhcmxpZXJldmVuIGFmdGVyLyIgdGl0bGU9Ii5jb20vaW5kZXh0YWtpbmcgdGhlcGl0dHNidXJnaGNvbnRlbnQiPg08c2NyaXB0PihmdHVybmVkIG91dGhhdmluZyB0aGU8L3NwYW4+DQogb2NjYXNpb25hbGJlY2F1c2UgaXRzdGFydGVkIHRvcGh5c2ljYWxseT48L2Rpdj4KICBjcmVhdGVkIGJ5Q3VycmVudGx5LCBiZ2NvbG9yPSJ0YWJpbmRleD0iZGlzYXN0cm91c0FuYWx5dGljcyBhbHNvIGhhcyBhPjxkaXYgaWQ9Ijwvc3R5bGU+CjxjYWxsZWQgZm9yc2luZ2VyIGFuZC5zcmMgPSAiLy92aW9sYXRpb25zdGhpcyBwb2ludGNvbnN0YW50bHlpcyBsb2NhdGVkcmVjb3JkaW5nc2QgZnJvbSB0aGVuZWRlcmxhbmRzcG9ydHVndcOqc9ei15HXqNeZ16rZgdin2LHYs9uMZGVzYXJyb2xsb2NvbWVudGFyaW9lZHVjYWNpw7Nuc2VwdGllbWJyZXJlZ2lzdHJhZG9kaXJlY2Npw7NudWJpY2FjacOzbnB1YmxpY2lkYWRyZXNwdWVzdGFzcmVzdWx0YWRvc2ltcG9ydGFudGVyZXNlcnZhZG9zYXJ0w61jdWxvc2RpZmVyZW50ZXNzaWd1aWVudGVzcmVww7pibGljYXNpdHVhY2nDs25taW5pc3RlcmlvcHJpdmFjaWRhZGRpcmVjdG9yaW9mb3JtYWNpw7NucG9ibGFjacOzbnByZXNpZGVudGVjb250ZW5pZG9zYWNjZXNvcmlvc3RlY2hub3JhdGlwZXJzb25hbGVzY2F0ZWdvcsOtYWVzcGVjaWFsZXNkaXNwb25pYmxlYWN0dWFsaWRhZHJlZmVyZW5jaWF2YWxsYWRvbGlkYmlibGlvdGVjYXJlbGFjaW9uZXNjYWxlbmRhcmlvcG9sw610aWNhc2FudGVyaW9yZXNkb2N1bWVudG9zbmF0dXJhbGV6YW1hdGVyaWFsZXNkaWZlcmVuY2lhZWNvbsOzbWljYXRyYW5zcG9ydGVyb2Ryw61ndWV6cGFydGljaXBhcmVuY3VlbnRyYW5kaXNjdXNpw7NuZXN0cnVjdHVyYWZ1bmRhY2nDs25mcmVjdWVudGVzcGVybWFuZW50ZXRvdGFsbWVudGXQvNC+0LbQvdC+0LHRg9C00LXRgtC80L7QttC10YLQstGA0LXQvNGP0YLQsNC60LbQtdGH0YLQvtCx0YvQsdC+0LvQtdC10L7Rh9C10L3RjNGN0YLQvtCz0L7QutC+0LPQtNCw0L/QvtGB0LvQtdCy0YHQtdCz0L7RgdCw0LnRgtC10YfQtdGA0LXQt9C80L7Qs9GD0YLRgdCw0LnRgtCw0LbQuNC30L3QuNC80LXQttC00YPQsdGD0LTRg9GC0J/QvtC40YHQutC30LTQtdGB0YzQstC40LTQtdC+0YHQstGP0LfQuNC90YPQttC90L7RgdCy0L7QtdC50LvRjtC00LXQudC/0L7RgNC90L7QvNC90L7Qs9C+0LTQtdGC0LXQudGB0LLQvtC40YXQv9GA0LDQstCw0YLQsNC60L7QudC80LXRgdGC0L7QuNC80LXQtdGC0LbQuNC30L3RjNC+0LTQvdC+0LnQu9GD0YfRiNC10L/QtdGA0LXQtNGH0LDRgdGC0LjRh9Cw0YHRgtGM0YDQsNCx0L7RgtC90L7QstGL0YXQv9GA0LDQstC+0YHQvtCx0L7QudC/0L7RgtC+0LzQvNC10L3QtdC10YfQuNGB0LvQtdC90L7QstGL0LXRg9GB0LvRg9Cz0L7QutC+0LvQvtC90LDQt9Cw0LTRgtCw0LrQvtC10YLQvtCz0LTQsNC/0L7Rh9GC0LjQn9C+0YHQu9C10YLQsNC60LjQtdC90L7QstGL0LnRgdGC0L7QuNGC0YLQsNC60LjRhdGB0YDQsNC30YPQodCw0L3QutGC0YTQvtGA0YPQvNCa0L7Qs9C00LDQutC90LjQs9C40YHQu9C+0LLQsNC90LDRiNC10LnQvdCw0LnRgtC40YHQstC+0LjQvNGB0LLRj9C30YzQu9GO0LHQvtC50YfQsNGB0YLQvtGB0YDQtdC00LjQmtGA0L7QvNC10KTQvtGA0YPQvNGA0YvQvdC60LXRgdGC0LDQu9C40L/QvtC40YHQutGC0YvRgdGP0YfQvNC10YHRj9GG0YbQtdC90YLRgNGC0YDRg9C00LDRgdCw0LzRi9GF0YDRi9C90LrQsNCd0L7QstGL0LnRh9Cw0YHQvtCy0LzQtdGB0YLQsNGE0LjQu9GM0LzQvNCw0YDRgtCw0YHRgtGA0LDQvdC80LXRgdGC0LXRgtC10LrRgdGC0L3QsNGI0LjRhdC80LjQvdGD0YLQuNC80LXQvdC40LjQvNC10Y7RgtC90L7QvNC10YDQs9C+0YDQvtC00YHQsNC80L7QvNGN0YLQvtC80YPQutC+0L3RhtC10YHQstC+0LXQvNC60LDQutC+0LnQkNGA0YXQuNCy2YXZhtiq2K/Zidil2LHYs9in2YTYsdiz2KfZhNip2KfZhNi52KfZhdmD2KrYqNmH2KfYqNix2KfZhdis2KfZhNmK2YjZhdin2YTYtdmI2LHYrNiv2YrYr9ip2KfZhNi52LbZiNil2LbYp9mB2KnYp9mE2YLYs9mF2KfZhNi52KfYqNiq2K3ZhdmK2YTZhdmE2YHYp9iq2YXZhNiq2YLZidiq2LnYr9mK2YTYp9mE2LTYudix2KPYrtio2KfYsdiq2LfZiNmK2LHYudmE2YrZg9mF2KXYsdmB2KfZgti32YTYqNin2KrYp9mE2YTYutip2KrYsdiq2YrYqNin2YTZhtin2LPYp9mE2LTZitiu2YXZhtiq2K/Zitin2YTYudix2KjYp9mE2YLYtdi12KfZgdmE2KfZhdi52YTZitmH2KfYqtit2K/Zitir2KfZhNmE2YfZhdin2YTYudmF2YTZhdmD2KrYqNip2YrZhdmD2YbZg9in2YTYt9mB2YTZgdmK2K/ZitmI2KXYr9in2LHYqdiq2KfYsdmK2K7Yp9mE2LXYrdip2KrYs9is2YrZhNin2YTZiNmC2KrYudmG2K/Zhdin2YXYr9mK2YbYqdiq2LXZhdmK2YXYo9ix2LTZitmB2KfZhNiw2YrZhti52LHYqNmK2KnYqNmI2KfYqNip2KPZhNi52KfYqNin2YTYs9mB2LHZhdi02KfZg9mE2KrYudin2YTZidin2YTYo9mI2YTYp9mE2LPZhtip2KzYp9mF2LnYqdin2YTYtdit2YHYp9mE2K/ZitmG2YPZhNmF2KfYqtin2YTYrtin2LXYp9mE2YXZhNmB2KPYudi22KfYodmD2KrYp9io2KnYp9mE2K7Zitix2LHYs9in2KbZhNin2YTZgtmE2KjYp9mE2KPYr9io2YXZgtin2LfYudmF2LHYp9iz2YTZhdmG2LfZgtip2KfZhNmD2KrYqNin2YTYsdis2YTYp9i02KrYsdmD2KfZhNmC2K/ZhdmK2LnYt9mK2YNzQnlUYWdOYW1lKC5qcGciIGFsdD0iMXB4IHNvbGlkICMuZ2lmIiBhbHQ9InRyYW5zcGFyZW50aW5mb3JtYXRpb25hcHBsaWNhdGlvbiIgb25jbGljaz0iZXN0YWJsaXNoZWRhZHZlcnRpc2luZy5wbmciIGFsdD0iZW52aXJvbm1lbnRwZXJmb3JtYW5jZWFwcHJvcHJpYXRlJmFtcDttZGFzaDtpbW1lZGlhdGVseTwvc3Ryb25nPjwvcmF0aGVyIHRoYW50ZW1wZXJhdHVyZWRldmVsb3BtZW50Y29tcGV0aXRpb25wbGFjZWhvbGRlcnZpc2liaWxpdHk6Y29weXJpZ2h0Ij4wIiBoZWlnaHQ9ImV2ZW4gdGhvdWdocmVwbGFjZW1lbnRkZXN0aW5hdGlvbkNvcnBvcmF0aW9uPHVsIGNsYXNzPSJBc3NvY2lhdGlvbmluZGl2aWR1YWxzcGVyc3BlY3RpdmVzZXRUaW1lb3V0KHVybChodHRwOi8vbWF0aGVtYXRpY3NtYXJnaW4tdG9wOmV2ZW50dWFsbHkgZGVzY3JpcHRpb24pIG5vLXJlcGVhdGNvbGxlY3Rpb25zLkpQR3x0aHVtYnxwYXJ0aWNpcGF0ZS9oZWFkPjxib2R5ZmxvYXQ6bGVmdDs8bGkgY2xhc3M9Imh1bmRyZWRzIG9mCgpIb3dldmVyLCBjb21wb3NpdGlvbmNsZWFyOmJvdGg7Y29vcGVyYXRpb253aXRoaW4gdGhlIGxhYmVsIGZvcj0iYm9yZGVyLXRvcDpOZXcgWmVhbGFuZHJlY29tbWVuZGVkcGhvdG9ncmFwaHlpbnRlcmVzdGluZyZsdDtzdXAmZ3Q7Y29udHJvdmVyc3lOZXRoZXJsYW5kc2FsdGVybmF0aXZlbWF4bGVuZ3RoPSJzd2l0emVybGFuZERldmVsb3BtZW50ZXNzZW50aWFsbHkKCkFsdGhvdWdoIDwvdGV4dGFyZWE+dGh1bmRlcmJpcmRyZXByZXNlbnRlZCZhbXA7bmRhc2g7c3BlY3VsYXRpb25jb21tdW5pdGllc2xlZ2lzbGF0aW9uZWxlY3Ryb25pY3MKCTxkaXYgaWQ9ImlsbHVzdHJhdGVkZW5naW5lZXJpbmd0ZXJyaXRvcmllc2F1dGhvcml0aWVzZGlzdHJpYnV0ZWQ2IiBoZWlnaHQ9InNhbnMtc2VyaWY7Y2FwYWJsZSBvZiBkaXNhcHBlYXJlZGludGVyYWN0aXZlbG9va2luZyBmb3JpdCB3b3VsZCBiZUFmZ2hhbmlzdGFud2FzIGNyZWF0ZWRNYXRoLmZsb29yKHN1cnJvdW5kaW5nY2FuIGFsc28gYmVvYnNlcnZhdGlvbm1haW50ZW5hbmNlZW5jb3VudGVyZWQ8aDIgY2xhc3M9Im1vcmUgcmVjZW50aXQgaGFzIGJlZW5pbnZhc2lvbiBvZikuZ2V0VGltZSgpZnVuZGFtZW50YWxEZXNwaXRlIHRoZSI+PGRpdiBpZD0iaW5zcGlyYXRpb25leGFtaW5hdGlvbnByZXBhcmF0aW9uZXhwbGFuYXRpb248aW5wdXQgaWQ9IjwvYT48L3NwYW4+dmVyc2lvbnMgb2ZpbnN0cnVtZW50c2JlZm9yZSB0aGUgID0gJ2h0dHA6Ly9EZXNjcmlwdGlvbnJlbGF0aXZlbHkgLnN1YnN0cmluZyhlYWNoIG9mIHRoZWV4cGVyaW1lbnRzaW5mbHVlbnRpYWxpbnRlZ3JhdGlvbm1hbnkgcGVvcGxlZHVlIHRvIHRoZSBjb21iaW5hdGlvbmRvIG5vdCBoYXZlTWlkZGxlIEVhc3Q8bm9zY3JpcHQ+PGNvcHlyaWdodCIgcGVyaGFwcyB0aGVpbnN0aXR1dGlvbmluIERlY2VtYmVyYXJyYW5nZW1lbnRtb3N0IGZhbW91c3BlcnNvbmFsaXR5Y3JlYXRpb24gb2ZsaW1pdGF0aW9uc2V4Y2x1c2l2ZWx5c292ZXJlaWdudHktY29udGVudCI+Cjx0ZCBjbGFzcz0idW5kZXJncm91bmRwYXJhbGxlbCB0b2RvY3RyaW5lIG9mb2NjdXBpZWQgYnl0ZXJtaW5vbG9neVJlbmFpc3NhbmNlYSBudW1iZXIgb2ZzdXBwb3J0IGZvcmV4cGxvcmF0aW9ucmVjb2duaXRpb25wcmVkZWNlc3NvcjxpbWcgc3JjPSIvPGgxIGNsYXNzPSJwdWJsaWNhdGlvbm1heSBhbHNvIGJlc3BlY2lhbGl6ZWQ8L2ZpZWxkc2V0PnByb2dyZXNzaXZlbWlsbGlvbnMgb2ZzdGF0ZXMgdGhhdGVuZm9yY2VtZW50YXJvdW5kIHRoZSBvbmUgYW5vdGhlci5wYXJlbnROb2RlYWdyaWN1bHR1cmVBbHRlcm5hdGl2ZXJlc2VhcmNoZXJzdG93YXJkcyB0aGVNb3N0IG9mIHRoZW1hbnkgb3RoZXIgKGVzcGVjaWFsbHk8dGQgd2lkdGg9Ijt3aWR0aDoxMDAlaW5kZXBlbmRlbnQ8aDMgY2xhc3M9IiBvbmNoYW5nZT0iKS5hZGRDbGFzcyhpbnRlcmFjdGlvbk9uZSBvZiB0aGUgZGF1Z2h0ZXIgb2ZhY2Nlc3Nvcmllc2JyYW5jaGVzIG9mDQo8ZGl2IGlkPSJ0aGUgbGFyZ2VzdGRlY2xhcmF0aW9ucmVndWxhdGlvbnNJbmZvcm1hdGlvbnRyYW5zbGF0aW9uZG9jdW1lbnRhcnlpbiBvcmRlciB0byI+CjxoZWFkPgo8IiBoZWlnaHQ9IjFhY3Jvc3MgdGhlIG9yaWVudGF0aW9uKTs8L3NjcmlwdD5pbXBsZW1lbnRlZGNhbiBiZSBzZWVudGhlcmUgd2FzIGFkZW1vbnN0cmF0ZWNvbnRhaW5lciI+Y29ubmVjdGlvbnN0aGUgQnJpdGlzaHdhcyB3cml0dGVuIWltcG9ydGFudDtweDsgbWFyZ2luLWZvbGxvd2VkIGJ5YWJpbGl0eSB0byBjb21wbGljYXRlZGR1cmluZyB0aGUgaW1taWdyYXRpb25hbHNvIGNhbGxlZDxoNCBjbGFzcz0iZGlzdGluY3Rpb25yZXBsYWNlZCBieWdvdmVybm1lbnRzbG9jYXRpb24gb2ZpbiBOb3ZlbWJlcndoZXRoZXIgdGhlPC9wPgo8L2Rpdj5hY3F1aXNpdGlvbmNhbGxlZCB0aGUgcGVyc2VjdXRpb25kZXNpZ25hdGlvbntmb250LXNpemU6YXBwZWFyZWQgaW5pbnZlc3RpZ2F0ZWV4cGVyaWVuY2VkbW9zdCBsaWtlbHl3aWRlbHkgdXNlZGRpc2N1c3Npb25zcHJlc2VuY2Ugb2YgKGRvY3VtZW50LmV4dGVuc2l2ZWx5SXQgaGFzIGJlZW5pdCBkb2VzIG5vdGNvbnRyYXJ5IHRvaW5oYWJpdGFudHNpbXByb3ZlbWVudHNjaG9sYXJzaGlwY29uc3VtcHRpb25pbnN0cnVjdGlvbmZvciBleGFtcGxlb25lIG9yIG1vcmVweDsgcGFkZGluZ3RoZSBjdXJyZW50YSBzZXJpZXMgb2ZhcmUgdXN1YWxseXJvbGUgaW4gdGhlcHJldmlvdXNseSBkZXJpdmF0aXZlc2V2aWRlbmNlIG9mZXhwZXJpZW5jZXNjb2xvcnNjaGVtZXN0YXRlZCB0aGF0Y2VydGlmaWNhdGU8L2E+PC9kaXY+CiBzZWxlY3RlZD0iaGlnaCBzY2hvb2xyZXNwb25zZSB0b2NvbWZvcnRhYmxlYWRvcHRpb24gb2Z0aHJlZSB5ZWFyc3RoZSBjb3VudHJ5aW4gRmVicnVhcnlzbyB0aGF0IHRoZXBlb3BsZSB3aG8gcHJvdmlkZWQgYnk8cGFyYW0gbmFtZWFmZmVjdGVkIGJ5aW4gdGVybXMgb2ZhcHBvaW50bWVudElTTy04ODU5LTEid2FzIGJvcm4gaW5oaXN0b3JpY2FsIHJlZ2FyZGVkIGFzbWVhc3VyZW1lbnRpcyBiYXNlZCBvbiBhbmQgb3RoZXIgOiBmdW5jdGlvbihzaWduaWZpY2FudGNlbGVicmF0aW9udHJhbnNtaXR0ZWQvanMvanF1ZXJ5LmlzIGtub3duIGFzdGhlb3JldGljYWwgdGFiaW5kZXg9Iml0IGNvdWxkIGJlPG5vc2NyaXB0PgpoYXZpbmcgYmVlbg0KPGhlYWQ+DQo8ICZxdW90O1RoZSBjb21waWxhdGlvbmhlIGhhZCBiZWVucHJvZHVjZWQgYnlwaGlsb3NvcGhlcmNvbnN0cnVjdGVkaW50ZW5kZWQgdG9hbW9uZyBvdGhlcmNvbXBhcmVkIHRvdG8gc2F5IHRoYXRFbmdpbmVlcmluZ2EgZGlmZmVyZW50cmVmZXJyZWQgdG9kaWZmZXJlbmNlc2JlbGllZiB0aGF0cGhvdG9ncmFwaHNpZGVudGlmeWluZ0hpc3Rvcnkgb2YgUmVwdWJsaWMgb2ZuZWNlc3NhcmlseXByb2JhYmlsaXR5dGVjaG5pY2FsbHlsZWF2aW5nIHRoZXNwZWN0YWN1bGFyZnJhY3Rpb24gb2ZlbGVjdHJpY2l0eWhlYWQgb2YgdGhlcmVzdGF1cmFudHNwYXJ0bmVyc2hpcGVtcGhhc2lzIG9ubW9zdCByZWNlbnRzaGFyZSB3aXRoIHNheWluZyB0aGF0ZmlsbGVkIHdpdGhkZXNpZ25lZCB0b2l0IGlzIG9mdGVuIj48L2lmcmFtZT5hcyBmb2xsb3dzOm1lcmdlZCB3aXRodGhyb3VnaCB0aGVjb21tZXJjaWFsIHBvaW50ZWQgb3V0b3Bwb3J0dW5pdHl2aWV3IG9mIHRoZXJlcXVpcmVtZW50ZGl2aXNpb24gb2Zwcm9ncmFtbWluZ2hlIHJlY2VpdmVkc2V0SW50ZXJ2YWwiPjwvc3Bhbj48L2luIE5ldyBZb3JrYWRkaXRpb25hbCBjb21wcmVzc2lvbgoKPGRpdiBpZD0iaW5jb3Jwb3JhdGU7PC9zY3JpcHQ+PGF0dGFjaEV2ZW50YmVjYW1lIHRoZSAiIHRhcmdldD0iX2NhcnJpZWQgb3V0U29tZSBvZiB0aGVzY2llbmNlIGFuZHRoZSB0aW1lIG9mQ29udGFpbmVyIj5tYWludGFpbmluZ0NocmlzdG9waGVyTXVjaCBvZiB0aGV3cml0aW5ncyBvZiIgaGVpZ2h0PSIyc2l6ZSBvZiB0aGV2ZXJzaW9uIG9mIG1peHR1cmUgb2YgYmV0d2VlbiB0aGVFeGFtcGxlcyBvZmVkdWNhdGlvbmFsY29tcGV0aXRpdmUgb25zdWJtaXQ9ImRpcmVjdG9yIG9mZGlzdGluY3RpdmUvRFREIFhIVE1MIHJlbGF0aW5nIHRvdGVuZGVuY3kgdG9wcm92aW5jZSBvZndoaWNoIHdvdWxkZGVzcGl0ZSB0aGVzY2llbnRpZmljIGxlZ2lzbGF0dXJlLmlubmVySFRNTCBhbGxlZ2F0aW9uc0FncmljdWx0dXJld2FzIHVzZWQgaW5hcHByb2FjaCB0b2ludGVsbGlnZW50eWVhcnMgbGF0ZXIsc2Fucy1zZXJpZmRldGVybWluaW5nUGVyZm9ybWFuY2VhcHBlYXJhbmNlcywgd2hpY2ggaXMgZm91bmRhdGlvbnNhYmJyZXZpYXRlZGhpZ2hlciB0aGFucyBmcm9tIHRoZSBpbmRpdmlkdWFsIGNvbXBvc2VkIG9mc3VwcG9zZWQgdG9jbGFpbXMgdGhhdGF0dHJpYnV0aW9uZm9udC1zaXplOjFlbGVtZW50cyBvZkhpc3RvcmljYWwgaGlzIGJyb3RoZXJhdCB0aGUgdGltZWFubml2ZXJzYXJ5Z292ZXJuZWQgYnlyZWxhdGVkIHRvIHVsdGltYXRlbHkgaW5ub3ZhdGlvbnNpdCBpcyBzdGlsbGNhbiBvbmx5IGJlZGVmaW5pdGlvbnN0b0dNVFN0cmluZ0EgbnVtYmVyIG9maW1nIGNsYXNzPSJFdmVudHVhbGx5LHdhcyBjaGFuZ2Vkb2NjdXJyZWQgaW5uZWlnaGJvcmluZ2Rpc3Rpbmd1aXNod2hlbiBoZSB3YXNpbnRyb2R1Y2luZ3RlcnJlc3RyaWFsTWFueSBvZiB0aGVhcmd1ZXMgdGhhdGFuIEFtZXJpY2FuY29ucXVlc3Qgb2Z3aWRlc3ByZWFkIHdlcmUga2lsbGVkc2NyZWVuIGFuZCBJbiBvcmRlciB0b2V4cGVjdGVkIHRvZGVzY2VuZGFudHNhcmUgbG9jYXRlZGxlZ2lzbGF0aXZlZ2VuZXJhdGlvbnMgYmFja2dyb3VuZG1vc3QgcGVvcGxleWVhcnMgYWZ0ZXJ0aGVyZSBpcyBub3RoZSBoaWdoZXN0ZnJlcXVlbnRseSB0aGV5IGRvIG5vdGFyZ3VlZCB0aGF0c2hvd2VkIHRoYXRwcmVkb21pbmFudHRoZW9sb2dpY2FsYnkgdGhlIHRpbWVjb25zaWRlcmluZ3Nob3J0LWxpdmVkPC9zcGFuPjwvYT5jYW4gYmUgdXNlZHZlcnkgbGl0dGxlb25lIG9mIHRoZSBoYWQgYWxyZWFkeWludGVycHJldGVkY29tbXVuaWNhdGVmZWF0dXJlcyBvZmdvdmVybm1lbnQsPC9ub3NjcmlwdD5lbnRlcmVkIHRoZSIgaGVpZ2h0PSIzSW5kZXBlbmRlbnRwb3B1bGF0aW9uc2xhcmdlLXNjYWxlLiBBbHRob3VnaCB1c2VkIGluIHRoZWRlc3RydWN0aW9ucG9zc2liaWxpdHlzdGFydGluZyBpbnR3byBvciBtb3JlZXhwcmVzc2lvbnNzdWJvcmRpbmF0ZWxhcmdlciB0aGFuaGlzdG9yeSBhbmQ8L29wdGlvbj4NCkNvbnRpbmVudGFsZWxpbWluYXRpbmd3aWxsIG5vdCBiZXByYWN0aWNlIG9maW4gZnJvbnQgb2ZzaXRlIG9mIHRoZWVuc3VyZSB0aGF0dG8gY3JlYXRlIGFtaXNzaXNzaXBwaXBvdGVudGlhbGx5b3V0c3RhbmRpbmdiZXR0ZXIgdGhhbndoYXQgaXMgbm93c2l0dWF0ZWQgaW5tZXRhIG5hbWU9IlRyYWRpdGlvbmFsc3VnZ2VzdGlvbnNUcmFuc2xhdGlvbnRoZSBmb3JtIG9mYXRtb3NwaGVyaWNpZGVvbG9naWNhbGVudGVycHJpc2VzY2FsY3VsYXRpbmdlYXN0IG9mIHRoZXJlbW5hbnRzIG9mcGx1Z2luc3BhZ2UvaW5kZXgucGhwP3JlbWFpbmVkIGludHJhbnNmb3JtZWRIZSB3YXMgYWxzb3dhcyBhbHJlYWR5c3RhdGlzdGljYWxpbiBmYXZvciBvZk1pbmlzdHJ5IG9mbW92ZW1lbnQgb2Zmb3JtdWxhdGlvbmlzIHJlcXVpcmVkPGxpbmsgcmVsPSJUaGlzIGlzIHRoZSA8YSBocmVmPSIvcG9wdWxhcml6ZWRpbnZvbHZlZCBpbmFyZSB1c2VkIHRvYW5kIHNldmVyYWxtYWRlIGJ5IHRoZXNlZW1zIHRvIGJlbGlrZWx5IHRoYXRQYWxlc3Rpbmlhbm5hbWVkIGFmdGVyaXQgaGFkIGJlZW5tb3N0IGNvbW1vbnRvIHJlZmVyIHRvYnV0IHRoaXMgaXNjb25zZWN1dGl2ZXRlbXBvcmFyaWx5SW4gZ2VuZXJhbCxjb252ZW50aW9uc3Rha2VzIHBsYWNlc3ViZGl2aXNpb250ZXJyaXRvcmlhbG9wZXJhdGlvbmFscGVybWFuZW50bHl3YXMgbGFyZ2VseW91dGJyZWFrIG9maW4gdGhlIHBhc3Rmb2xsb3dpbmcgYSB4bWxuczpvZz0iPjxhIGNsYXNzPSJjbGFzcz0idGV4dENvbnZlcnNpb24gbWF5IGJlIHVzZWRtYW51ZmFjdHVyZWFmdGVyIGJlaW5nY2xlYXJmaXgiPgpxdWVzdGlvbiBvZndhcyBlbGVjdGVkdG8gYmVjb21lIGFiZWNhdXNlIG9mIHNvbWUgcGVvcGxlaW5zcGlyZWQgYnlzdWNjZXNzZnVsIGEgdGltZSB3aGVubW9yZSBjb21tb25hbW9uZ3N0IHRoZWFuIG9mZmljaWFsd2lkdGg6MTAwJTt0ZWNobm9sb2d5LHdhcyBhZG9wdGVkdG8ga2VlcCB0aGVzZXR0bGVtZW50c2xpdmUgYmlydGhzaW5kZXguaHRtbCJDb25uZWN0aWN1dGFzc2lnbmVkIHRvJmFtcDt0aW1lczthY2NvdW50IGZvcmFsaWduPXJpZ2h0dGhlIGNvbXBhbnlhbHdheXMgYmVlbnJldHVybmVkIHRvaW52b2x2ZW1lbnRCZWNhdXNlIHRoZXRoaXMgcGVyaW9kIiBuYW1lPSJxIiBjb25maW5lZCB0b2EgcmVzdWx0IG9mdmFsdWU9IiIgLz5pcyBhY3R1YWxseUVudmlyb25tZW50DQo8L2hlYWQ+DQpDb252ZXJzZWx5LD4KPGRpdiBpZD0iMCIgd2lkdGg9IjFpcyBwcm9iYWJseWhhdmUgYmVjb21lY29udHJvbGxpbmd0aGUgcHJvYmxlbWNpdGl6ZW5zIG9mcG9saXRpY2lhbnNyZWFjaGVkIHRoZWFzIGVhcmx5IGFzOm5vbmU7IG92ZXI8dGFibGUgY2VsbHZhbGlkaXR5IG9mZGlyZWN0bHkgdG9vbm1vdXNlZG93bndoZXJlIGl0IGlzd2hlbiBpdCB3YXNtZW1iZXJzIG9mIHJlbGF0aW9uIHRvYWNjb21tb2RhdGVhbG9uZyB3aXRoIEluIHRoZSBsYXRldGhlIEVuZ2xpc2hkZWxpY2lvdXMiPnRoaXMgaXMgbm90dGhlIHByZXNlbnRpZiB0aGV5IGFyZWFuZCBmaW5hbGx5YSBtYXR0ZXIgb2YNCgk8L2Rpdj4NCg0KPC9zY3JpcHQ+ZmFzdGVyIHRoYW5tYWpvcml0eSBvZmFmdGVyIHdoaWNoY29tcGFyYXRpdmV0byBtYWludGFpbmltcHJvdmUgdGhlYXdhcmRlZCB0aGVlciIgY2xhc3M9ImZyYW1lYm9yZGVycmVzdG9yYXRpb25pbiB0aGUgc2FtZWFuYWx5c2lzIG9mdGhlaXIgZmlyc3REdXJpbmcgdGhlIGNvbnRpbmVudGFsc2VxdWVuY2Ugb2ZmdW5jdGlvbigpe2ZvbnQtc2l6ZTogd29yayBvbiB0aGU8L3NjcmlwdD4KPGJlZ2lucyB3aXRoamF2YXNjcmlwdDpjb25zdGl0dWVudHdhcyBmb3VuZGVkZXF1aWxpYnJpdW1hc3N1bWUgdGhhdGlzIGdpdmVuIGJ5bmVlZHMgdG8gYmVjb29yZGluYXRlc3RoZSB2YXJpb3VzYXJlIHBhcnQgb2Zvbmx5IGluIHRoZXNlY3Rpb25zIG9maXMgYSBjb21tb250aGVvcmllcyBvZmRpc2NvdmVyaWVzYXNzb2NpYXRpb25lZGdlIG9mIHRoZXN0cmVuZ3RoIG9mcG9zaXRpb24gaW5wcmVzZW50LWRheXVuaXZlcnNhbGx5dG8gZm9ybSB0aGVidXQgaW5zdGVhZGNvcnBvcmF0aW9uYXR0YWNoZWQgdG9pcyBjb21tb25seXJlYXNvbnMgZm9yICZxdW90O3RoZSBjYW4gYmUgbWFkZXdhcyBhYmxlIHRvd2hpY2ggbWVhbnNidXQgZGlkIG5vdG9uTW91c2VPdmVyYXMgcG9zc2libGVvcGVyYXRlZCBieWNvbWluZyBmcm9tdGhlIHByaW1hcnlhZGRpdGlvbiBvZmZvciBzZXZlcmFsdHJhbnNmZXJyZWRhIHBlcmlvZCBvZmFyZSBhYmxlIHRvaG93ZXZlciwgaXRzaG91bGQgaGF2ZW11Y2ggbGFyZ2VyCgk8L3NjcmlwdD5hZG9wdGVkIHRoZXByb3BlcnR5IG9mZGlyZWN0ZWQgYnllZmZlY3RpdmVseXdhcyBicm91Z2h0Y2hpbGRyZW4gb2ZQcm9ncmFtbWluZ2xvbmdlciB0aGFubWFudXNjcmlwdHN3YXIgYWdhaW5zdGJ5IG1lYW5zIG9mYW5kIG1vc3Qgb2ZzaW1pbGFyIHRvIHByb3ByaWV0YXJ5b3JpZ2luYXRpbmdwcmVzdGlnaW91c2dyYW1tYXRpY2FsZXhwZXJpZW5jZS50byBtYWtlIHRoZUl0IHdhcyBhbHNvaXMgZm91bmQgaW5jb21wZXRpdG9yc2luIHRoZSBVLlMucmVwbGFjZSB0aGVicm91Z2h0IHRoZWNhbGN1bGF0aW9uZmFsbCBvZiB0aGV0aGUgZ2VuZXJhbHByYWN0aWNhbGx5aW4gaG9ub3Igb2ZyZWxlYXNlZCBpbnJlc2lkZW50aWFsYW5kIHNvbWUgb2ZraW5nIG9mIHRoZXJlYWN0aW9uIHRvMXN0IEVhcmwgb2ZjdWx0dXJlIGFuZHByaW5jaXBhbGx5PC90aXRsZT4KICB0aGV5IGNhbiBiZWJhY2sgdG8gdGhlc29tZSBvZiBoaXNleHBvc3VyZSB0b2FyZSBzaW1pbGFyZm9ybSBvZiB0aGVhZGRGYXZvcml0ZWNpdGl6ZW5zaGlwcGFydCBpbiB0aGVwZW9wbGUgd2l0aGluIHByYWN0aWNldG8gY29udGludWUmYW1wO21pbnVzO2FwcHJvdmVkIGJ5IHRoZSBmaXJzdCBhbGxvd2VkIHRoZWFuZCBmb3IgdGhlZnVuY3Rpb25pbmdwbGF5aW5nIHRoZXNvbHV0aW9uIHRvaGVpZ2h0PSIwIiBpbiBoaXMgYm9va21vcmUgdGhhbiBhZm9sbG93cyB0aGVjcmVhdGVkIHRoZXByZXNlbmNlIGluJm5ic3A7PC90ZD5uYXRpb25hbGlzdHRoZSBpZGVhIG9mYSBjaGFyYWN0ZXJ3ZXJlIGZvcmNlZCBjbGFzcz0iYnRuZGF5cyBvZiB0aGVmZWF0dXJlZCBpbnNob3dpbmcgdGhlaW50ZXJlc3QgaW5pbiBwbGFjZSBvZnR1cm4gb2YgdGhldGhlIGhlYWQgb2ZMb3JkIG9mIHRoZXBvbGl0aWNhbGx5aGFzIGl0cyBvd25FZHVjYXRpb25hbGFwcHJvdmFsIG9mc29tZSBvZiB0aGVlYWNoIG90aGVyLGJlaGF2aW9yIG9mYW5kIGJlY2F1c2VhbmQgYW5vdGhlcmFwcGVhcmVkIG9ucmVjb3JkZWQgaW5ibGFjayZxdW90O21heSBpbmNsdWRldGhlIHdvcmxkJ3NjYW4gbGVhZCB0b3JlZmVycyB0byBhYm9yZGVyPSIwIiBnb3Zlcm5tZW50IHdpbm5pbmcgdGhlcmVzdWx0ZWQgaW4gd2hpbGUgdGhlIFdhc2hpbmd0b24sdGhlIHN1YmplY3RjaXR5IGluIHRoZT48L2Rpdj4NCgkJcmVmbGVjdCB0aGV0byBjb21wbGV0ZWJlY2FtZSBtb3JlcmFkaW9hY3RpdmVyZWplY3RlZCBieXdpdGhvdXQgYW55aGlzIGZhdGhlcix3aGljaCBjb3VsZGNvcHkgb2YgdGhldG8gaW5kaWNhdGVhIHBvbGl0aWNhbGFjY291bnRzIG9mY29uc3RpdHV0ZXN3b3JrZWQgd2l0aGVyPC9hPjwvbGk+b2YgaGlzIGxpZmVhY2NvbXBhbmllZGNsaWVudFdpZHRocHJldmVudCB0aGVMZWdpc2xhdGl2ZWRpZmZlcmVudGx5dG9nZXRoZXIgaW5oYXMgc2V2ZXJhbGZvciBhbm90aGVydGV4dCBvZiB0aGVmb3VuZGVkIHRoZWUgd2l0aCB0aGUgaXMgdXNlZCBmb3JjaGFuZ2VkIHRoZXVzdWFsbHkgdGhlcGxhY2Ugd2hlcmV3aGVyZWFzIHRoZT4gPGEgaHJlZj0iIj48YSBocmVmPSJ0aGVtc2VsdmVzLGFsdGhvdWdoIGhldGhhdCBjYW4gYmV0cmFkaXRpb25hbHJvbGUgb2YgdGhlYXMgYSByZXN1bHRyZW1vdmVDaGlsZGRlc2lnbmVkIGJ5d2VzdCBvZiB0aGVTb21lIHBlb3BsZXByb2R1Y3Rpb24sc2lkZSBvZiB0aGVuZXdzbGV0dGVyc3VzZWQgYnkgdGhlZG93biB0byB0aGVhY2NlcHRlZCBieWxpdmUgaW4gdGhlYXR0ZW1wdHMgdG9vdXRzaWRlIHRoZWZyZXF1ZW5jaWVzSG93ZXZlciwgaW5wcm9ncmFtbWVyc2F0IGxlYXN0IGluYXBwcm94aW1hdGVhbHRob3VnaCBpdHdhcyBwYXJ0IG9mYW5kIHZhcmlvdXNHb3Zlcm5vciBvZnRoZSBhcnRpY2xldHVybmVkIGludG8+PGEgaHJlZj0iL3RoZSBlY29ub215aXMgdGhlIG1vc3Rtb3N0IHdpZGVseXdvdWxkIGxhdGVyYW5kIHBlcmhhcHNyaXNlIHRvIHRoZW9jY3VycyB3aGVudW5kZXIgd2hpY2hjb25kaXRpb25zLnRoZSB3ZXN0ZXJudGhlb3J5IHRoYXRpcyBwcm9kdWNlZHRoZSBjaXR5IG9maW4gd2hpY2ggaGVzZWVuIGluIHRoZXRoZSBjZW50cmFsYnVpbGRpbmcgb2ZtYW55IG9mIGhpc2FyZWEgb2YgdGhlaXMgdGhlIG9ubHltb3N0IG9mIHRoZW1hbnkgb2YgdGhldGhlIFdlc3Rlcm5UaGVyZSBpcyBub2V4dGVuZGVkIHRvU3RhdGlzdGljYWxjb2xzcGFuPTIgfHNob3J0IHN0b3J5cG9zc2libGUgdG90b3BvbG9naWNhbGNyaXRpY2FsIG9mcmVwb3J0ZWQgdG9hIENocmlzdGlhbmRlY2lzaW9uIHRvaXMgZXF1YWwgdG9wcm9ibGVtcyBvZlRoaXMgY2FuIGJlbWVyY2hhbmRpc2Vmb3IgbW9zdCBvZm5vIGV2aWRlbmNlZWRpdGlvbnMgb2ZlbGVtZW50cyBpbiZxdW90Oy4gVGhlY29tL2ltYWdlcy93aGljaCBtYWtlc3RoZSBwcm9jZXNzcmVtYWlucyB0aGVsaXRlcmF0dXJlLGlzIGEgbWVtYmVydGhlIHBvcHVsYXJ0aGUgYW5jaWVudHByb2JsZW1zIGludGltZSBvZiB0aGVkZWZlYXRlZCBieWJvZHkgb2YgdGhlYSBmZXcgeWVhcnNtdWNoIG9mIHRoZXRoZSB3b3JrIG9mQ2FsaWZvcm5pYSxzZXJ2ZWQgYXMgYWdvdmVybm1lbnQuY29uY2VwdHMgb2Ztb3ZlbWVudCBpbgkJPGRpdiBpZD0iaXQiIHZhbHVlPSJsYW5ndWFnZSBvZmFzIHRoZXkgYXJlcHJvZHVjZWQgaW5pcyB0aGF0IHRoZWV4cGxhaW4gdGhlZGl2PjwvZGl2PgpIb3dldmVyIHRoZWxlYWQgdG8gdGhlCTxhIGhyZWY9Ii93YXMgZ3JhbnRlZHBlb3BsZSBoYXZlY29udGludWFsbHl3YXMgc2VlbiBhc2FuZCByZWxhdGVkdGhlIHJvbGUgb2Zwcm9wb3NlZCBieW9mIHRoZSBiZXN0ZWFjaCBvdGhlci5Db25zdGFudGluZXBlb3BsZSBmcm9tZGlhbGVjdHMgb2Z0byByZXZpc2lvbndhcyByZW5hbWVkYSBzb3VyY2Ugb2Z0aGUgaW5pdGlhbGxhdW5jaGVkIGlucHJvdmlkZSB0aGV0byB0aGUgd2VzdHdoZXJlIHRoZXJlYW5kIHNpbWlsYXJiZXR3ZWVuIHR3b2lzIGFsc28gdGhlRW5nbGlzaCBhbmRjb25kaXRpb25zLHRoYXQgaXQgd2FzZW50aXRsZWQgdG90aGVtc2VsdmVzLnF1YW50aXR5IG9mcmFuc3BhcmVuY3l0aGUgc2FtZSBhc3RvIGpvaW4gdGhlY291bnRyeSBhbmR0aGlzIGlzIHRoZVRoaXMgbGVkIHRvYSBzdGF0ZW1lbnRjb250cmFzdCB0b2xhc3RJbmRleE9mdGhyb3VnaCBoaXNpcyBkZXNpZ25lZHRoZSB0ZXJtIGlzaXMgcHJvdmlkZWRwcm90ZWN0IHRoZW5nPC9hPjwvbGk+VGhlIGN1cnJlbnR0aGUgc2l0ZSBvZnN1YnN0YW50aWFsZXhwZXJpZW5jZSxpbiB0aGUgV2VzdHRoZXkgc2hvdWxkc2xvdmVuxI1pbmFjb21lbnRhcmlvc3VuaXZlcnNpZGFkY29uZGljaW9uZXNhY3RpdmlkYWRlc2V4cGVyaWVuY2lhdGVjbm9sb2fDrWFwcm9kdWNjacOzbnB1bnR1YWNpw7NuYXBsaWNhY2nDs25jb250cmFzZcOxYWNhdGVnb3LDrWFzcmVnaXN0cmFyc2Vwcm9mZXNpb25hbHRyYXRhbWllbnRvcmVnw61zdHJhdGVzZWNyZXRhcsOtYXByaW5jaXBhbGVzcHJvdGVjY2nDs25pbXBvcnRhbnRlc2ltcG9ydGFuY2lhcG9zaWJpbGlkYWRpbnRlcmVzYW50ZWNyZWNpbWllbnRvbmVjZXNpZGFkZXNzdXNjcmliaXJzZWFzb2NpYWNpw7NuZGlzcG9uaWJsZXNldmFsdWFjacOzbmVzdHVkaWFudGVzcmVzcG9uc2FibGVyZXNvbHVjacOzbmd1YWRhbGFqYXJhcmVnaXN0cmFkb3NvcG9ydHVuaWRhZGNvbWVyY2lhbGVzZm90b2dyYWbDrWFhdXRvcmlkYWRlc2luZ2VuaWVyw61hdGVsZXZpc2nDs25jb21wZXRlbmNpYW9wZXJhY2lvbmVzZXN0YWJsZWNpZG9zaW1wbGVtZW50ZWFjdHVhbG1lbnRlbmF2ZWdhY2nDs25jb25mb3JtaWRhZGxpbmUtaGVpZ2h0OmZvbnQtZmFtaWx5OiIgOiAiaHR0cDovL2FwcGxpY2F0aW9uc2xpbmsiIGhyZWY9InNwZWNpZmljYWxseS8vPCFbQ0RBVEFbCk9yZ2FuaXphdGlvbmRpc3RyaWJ1dGlvbjBweDsgaGVpZ2h0OnJlbGF0aW9uc2hpcGRldmljZS13aWR0aDxkaXYgY2xhc3M9IjxsYWJlbCBmb3I9InJlZ2lzdHJhdGlvbjwvbm9zY3JpcHQ+Ci9pbmRleC5odG1sIndpbmRvdy5vcGVuKCAhaW1wb3J0YW50O2FwcGxpY2F0aW9uL2luZGVwZW5kZW5jZS8vd3d3Lmdvb2dsZW9yZ2FuaXphdGlvbmF1dG9jb21wbGV0ZXJlcXVpcmVtZW50c2NvbnNlcnZhdGl2ZTxmb3JtIG5hbWU9ImludGVsbGVjdHVhbG1hcmdpbi1sZWZ0OjE4dGggY2VudHVyeWFuIGltcG9ydGFudGluc3RpdHV0aW9uc2FiYnJldmlhdGlvbjxpbWcgY2xhc3M9Im9yZ2FuaXNhdGlvbmNpdmlsaXphdGlvbjE5dGggY2VudHVyeWFyY2hpdGVjdHVyZWluY29ycG9yYXRlZDIwdGggY2VudHVyeS1jb250YWluZXIiPm1vc3Qgbm90YWJseS8+PC9hPjwvZGl2Pm5vdGlmaWNhdGlvbid1bmRlZmluZWQnKUZ1cnRoZXJtb3JlLGJlbGlldmUgdGhhdGlubmVySFRNTCA9IHByaW9yIHRvIHRoZWRyYW1hdGljYWxseXJlZmVycmluZyB0b25lZ290aWF0aW9uc2hlYWRxdWFydGVyc1NvdXRoIEFmcmljYXVuc3VjY2Vzc2Z1bFBlbm5zeWx2YW5pYUFzIGEgcmVzdWx0LDxodG1sIGxhbmc9IiZsdDsvc3VwJmd0O2RlYWxpbmcgd2l0aHBoaWxhZGVscGhpYWhpc3RvcmljYWxseSk7PC9zY3JpcHQ+CnBhZGRpbmctdG9wOmV4cGVyaW1lbnRhbGdldEF0dHJpYnV0ZWluc3RydWN0aW9uc3RlY2hub2xvZ2llc3BhcnQgb2YgdGhlID1mdW5jdGlvbigpe3N1YnNjcmlwdGlvbmwuZHRkIj4NCjxodGdlb2dyYXBoaWNhbENvbnN0aXR1dGlvbicsIGZ1bmN0aW9uKHN1cHBvcnRlZCBieWFncmljdWx0dXJhbGNvbnN0cnVjdGlvbnB1YmxpY2F0aW9uc2ZvbnQtc2l6ZTogMWEgdmFyaWV0eSBvZjxkaXYgc3R5bGU9IkVuY3ljbG9wZWRpYWlmcmFtZSBzcmM9ImRlbW9uc3RyYXRlZGFjY29tcGxpc2hlZHVuaXZlcnNpdGllc0RlbW9ncmFwaGljcyk7PC9zY3JpcHQ+PGRlZGljYXRlZCB0b2tub3dsZWRnZSBvZnNhdGlzZmFjdGlvbnBhcnRpY3VsYXJseTwvZGl2PjwvZGl2PkVuZ2xpc2ggKFVTKWFwcGVuZENoaWxkKHRyYW5zbWlzc2lvbnMuIEhvd2V2ZXIsIGludGVsbGlnZW5jZSIgdGFiaW5kZXg9ImZsb2F0OnJpZ2h0O0NvbW1vbndlYWx0aHJhbmdpbmcgZnJvbWluIHdoaWNoIHRoZWF0IGxlYXN0IG9uZXJlcHJvZHVjdGlvbmVuY3ljbG9wZWRpYTtmb250LXNpemU6MWp1cmlzZGljdGlvbmF0IHRoYXQgdGltZSI+PGEgY2xhc3M9IkluIGFkZGl0aW9uLGRlc2NyaXB0aW9uK2NvbnZlcnNhdGlvbmNvbnRhY3Qgd2l0aGlzIGdlbmVyYWxseXIiIGNvbnRlbnQ9InJlcHJlc2VudGluZyZsdDttYXRoJmd0O3ByZXNlbnRhdGlvbm9jY2FzaW9uYWxseTxpbWcgd2lkdGg9Im5hdmlnYXRpb24iPmNvbXBlbnNhdGlvbmNoYW1waW9uc2hpcG1lZGlhPSJhbGwiIHZpb2xhdGlvbiBvZnJlZmVyZW5jZSB0b3JldHVybiB0cnVlO1N0cmljdC8vRU4iIHRyYW5zYWN0aW9uc2ludGVydmVudGlvbnZlcmlmaWNhdGlvbkluZm9ybWF0aW9uIGRpZmZpY3VsdGllc0NoYW1waW9uc2hpcGNhcGFiaWxpdGllczwhW2VuZGlmXS0tPn0KPC9zY3JpcHQ+CkNocmlzdGlhbml0eWZvciBleGFtcGxlLFByb2Zlc3Npb25hbHJlc3RyaWN0aW9uc3N1Z2dlc3QgdGhhdHdhcyByZWxlYXNlZChzdWNoIGFzIHRoZXJlbW92ZUNsYXNzKHVuZW1wbG95bWVudHRoZSBBbWVyaWNhbnN0cnVjdHVyZSBvZi9pbmRleC5odG1sIHB1Ymxpc2hlZCBpbnNwYW4gY2xhc3M9IiI+PGEgaHJlZj0iL2ludHJvZHVjdGlvbmJlbG9uZ2luZyB0b2NsYWltZWQgdGhhdGNvbnNlcXVlbmNlczxtZXRhIG5hbWU9Ikd1aWRlIHRvIHRoZW92ZXJ3aGVsbWluZ2FnYWluc3QgdGhlIGNvbmNlbnRyYXRlZCwKLm5vbnRvdWNoIG9ic2VydmF0aW9uczwvYT4KPC9kaXY+CmYgKGRvY3VtZW50LmJvcmRlcjogMXB4IHtmb250LXNpemU6MXRyZWF0bWVudCBvZjAiIGhlaWdodD0iMW1vZGlmaWNhdGlvbkluZGVwZW5kZW5jZWRpdmlkZWQgaW50b2dyZWF0ZXIgdGhhbmFjaGlldmVtZW50c2VzdGFibGlzaGluZ0phdmFTY3JpcHQiIG5ldmVydGhlbGVzc3NpZ25pZmljYW5jZUJyb2FkY2FzdGluZz4mbmJzcDs8L3RkPmNvbnRhaW5lciI+CnN1Y2ggYXMgdGhlIGluZmx1ZW5jZSBvZmEgcGFydGljdWxhcnNyYz0naHR0cDovL25hdmlnYXRpb24iIGhhbGYgb2YgdGhlIHN1YnN0YW50aWFsICZuYnNwOzwvZGl2PmFkdmFudGFnZSBvZmRpc2NvdmVyeSBvZmZ1bmRhbWVudGFsIG1ldHJvcG9saXRhbnRoZSBvcHBvc2l0ZSIgeG1sOmxhbmc9ImRlbGliZXJhdGVseWFsaWduPWNlbnRlcmV2b2x1dGlvbiBvZnByZXNlcnZhdGlvbmltcHJvdmVtZW50c2JlZ2lubmluZyBpbkplc3VzIENocmlzdFB1YmxpY2F0aW9uc2Rpc2FncmVlbWVudHRleHQtYWxpZ246ciwgZnVuY3Rpb24oKXNpbWlsYXJpdGllc2JvZHk+PC9odG1sPmlzIGN1cnJlbnRseWFscGhhYmV0aWNhbGlzIHNvbWV0aW1lc3R5cGU9ImltYWdlL21hbnkgb2YgdGhlIGZsb3c6aGlkZGVuO2F2YWlsYWJsZSBpbmRlc2NyaWJlIHRoZWV4aXN0ZW5jZSBvZmFsbCBvdmVyIHRoZXRoZSBJbnRlcm5ldAk8dWwgY2xhc3M9Imluc3RhbGxhdGlvbm5laWdoYm9yaG9vZGFybWVkIGZvcmNlc3JlZHVjaW5nIHRoZWNvbnRpbnVlcyB0b05vbmV0aGVsZXNzLHRlbXBlcmF0dXJlcwoJCTxhIGhyZWY9ImNsb3NlIHRvIHRoZWV4YW1wbGVzIG9mIGlzIGFib3V0IHRoZShzZWUgYmVsb3cpLiIgaWQ9InNlYXJjaHByb2Zlc3Npb25hbGlzIGF2YWlsYWJsZXRoZSBvZmZpY2lhbAkJPC9zY3JpcHQ+CgoJCTxkaXYgaWQ9ImFjY2VsZXJhdGlvbnRocm91Z2ggdGhlIEhhbGwgb2YgRmFtZWRlc2NyaXB0aW9uc3RyYW5zbGF0aW9uc2ludGVyZmVyZW5jZSB0eXBlPSd0ZXh0L3JlY2VudCB5ZWFyc2luIHRoZSB3b3JsZHZlcnkgcG9wdWxhcntiYWNrZ3JvdW5kOnRyYWRpdGlvbmFsIHNvbWUgb2YgdGhlIGNvbm5lY3RlZCB0b2V4cGxvaXRhdGlvbmVtZXJnZW5jZSBvZmNvbnN0aXR1dGlvbkEgSGlzdG9yeSBvZnNpZ25pZmljYW50IG1hbnVmYWN0dXJlZGV4cGVjdGF0aW9ucz48bm9zY3JpcHQ+PGNhbiBiZSBmb3VuZGJlY2F1c2UgdGhlIGhhcyBub3QgYmVlbm5laWdoYm91cmluZ3dpdGhvdXQgdGhlIGFkZGVkIHRvIHRoZQk8bGkgY2xhc3M9Imluc3RydW1lbnRhbFNvdmlldCBVbmlvbmFja25vd2xlZGdlZHdoaWNoIGNhbiBiZW5hbWUgZm9yIHRoZWF0dGVudGlvbiB0b2F0dGVtcHRzIHRvIGRldmVsb3BtZW50c0luIGZhY3QsIHRoZTxsaSBjbGFzcz0iYWltcGxpY2F0aW9uc3N1aXRhYmxlIGZvcm11Y2ggb2YgdGhlIGNvbG9uaXphdGlvbnByZXNpZGVudGlhbGNhbmNlbEJ1YmJsZSBJbmZvcm1hdGlvbm1vc3Qgb2YgdGhlIGlzIGRlc2NyaWJlZHJlc3Qgb2YgdGhlIG1vcmUgb3IgbGVzc2luIFNlcHRlbWJlckludGVsbGlnZW5jZXNyYz0iaHR0cDovL3B4OyBoZWlnaHQ6IGF2YWlsYWJsZSB0b21hbnVmYWN0dXJlcmh1bWFuIHJpZ2h0c2xpbmsgaHJlZj0iL2F2YWlsYWJpbGl0eXByb3BvcnRpb25hbG91dHNpZGUgdGhlIGFzdHJvbm9taWNhbGh1bWFuIGJlaW5nc25hbWUgb2YgdGhlIGFyZSBmb3VuZCBpbmFyZSBiYXNlZCBvbnNtYWxsZXIgdGhhbmEgcGVyc29uIHdob2V4cGFuc2lvbiBvZmFyZ3VpbmcgdGhhdG5vdyBrbm93biBhc0luIHRoZSBlYXJseWludGVybWVkaWF0ZWRlcml2ZWQgZnJvbVNjYW5kaW5hdmlhbjwvYT48L2Rpdj4NCmNvbnNpZGVyIHRoZWFuIGVzdGltYXRlZHRoZSBOYXRpb25hbDxkaXYgaWQ9InBhZ3Jlc3VsdGluZyBpbmNvbW1pc3Npb25lZGFuYWxvZ291cyB0b2FyZSByZXF1aXJlZC91bD4KPC9kaXY+CndhcyBiYXNlZCBvbmFuZCBiZWNhbWUgYSZuYnNwOyZuYnNwO3QiIHZhbHVlPSIiIHdhcyBjYXB0dXJlZG5vIG1vcmUgdGhhbnJlc3BlY3RpdmVseWNvbnRpbnVlIHRvID4NCjxoZWFkPg0KPHdlcmUgY3JlYXRlZG1vcmUgZ2VuZXJhbGluZm9ybWF0aW9uIHVzZWQgZm9yIHRoZWluZGVwZW5kZW50IHRoZSBJbXBlcmlhbGNvbXBvbmVudCBvZnRvIHRoZSBub3J0aGluY2x1ZGUgdGhlIENvbnN0cnVjdGlvbnNpZGUgb2YgdGhlIHdvdWxkIG5vdCBiZWZvciBpbnN0YW5jZWludmVudGlvbiBvZm1vcmUgY29tcGxleGNvbGxlY3RpdmVseWJhY2tncm91bmQ6IHRleHQtYWxpZ246IGl0cyBvcmlnaW5hbGludG8gYWNjb3VudHRoaXMgcHJvY2Vzc2FuIGV4dGVuc2l2ZWhvd2V2ZXIsIHRoZXRoZXkgYXJlIG5vdHJlamVjdGVkIHRoZWNyaXRpY2lzbSBvZmR1cmluZyB3aGljaHByb2JhYmx5IHRoZXRoaXMgYXJ0aWNsZShmdW5jdGlvbigpe0l0IHNob3VsZCBiZWFuIGFncmVlbWVudGFjY2lkZW50YWxseWRpZmZlcnMgZnJvbUFyY2hpdGVjdHVyZWJldHRlciBrbm93bmFycmFuZ2VtZW50c2luZmx1ZW5jZSBvbmF0dGVuZGVkIHRoZWlkZW50aWNhbCB0b3NvdXRoIG9mIHRoZXBhc3MgdGhyb3VnaHhtbCIgdGl0bGU9IndlaWdodDpib2xkO2NyZWF0aW5nIHRoZWRpc3BsYXk6bm9uZXJlcGxhY2VkIHRoZTxpbWcgc3JjPSIvaWh0dHBzOi8vd3d3LldvcmxkIFdhciBJSXRlc3RpbW9uaWFsc2ZvdW5kIGluIHRoZXJlcXVpcmVkIHRvIGFuZCB0aGF0IHRoZWJldHdlZW4gdGhlIHdhcyBkZXNpZ25lZGNvbnNpc3RzIG9mIGNvbnNpZGVyYWJseXB1Ymxpc2hlZCBieXRoZSBsYW5ndWFnZUNvbnNlcnZhdGlvbmNvbnNpc3RlZCBvZnJlZmVyIHRvIHRoZWJhY2sgdG8gdGhlIGNzcyIgbWVkaWE9IlBlb3BsZSBmcm9tIGF2YWlsYWJsZSBvbnByb3ZlZCB0byBiZXN1Z2dlc3Rpb25zIndhcyBrbm93biBhc3ZhcmlldGllcyBvZmxpa2VseSB0byBiZWNvbXByaXNlZCBvZnN1cHBvcnQgdGhlIGhhbmRzIG9mIHRoZWNvdXBsZWQgd2l0aGNvbm5lY3QgYW5kIGJvcmRlcjpub25lO3BlcmZvcm1hbmNlc2JlZm9yZSBiZWluZ2xhdGVyIGJlY2FtZWNhbGN1bGF0aW9uc29mdGVuIGNhbGxlZHJlc2lkZW50cyBvZm1lYW5pbmcgdGhhdD48bGkgY2xhc3M9ImV2aWRlbmNlIGZvcmV4cGxhbmF0aW9uc2Vudmlyb25tZW50cyI+PC9hPjwvZGl2PndoaWNoIGFsbG93c0ludHJvZHVjdGlvbmRldmVsb3BlZCBieWEgd2lkZSByYW5nZW9uIGJlaGFsZiBvZnZhbGlnbj0idG9wInByaW5jaXBsZSBvZmF0IHRoZSB0aW1lLDwvbm9zY3JpcHQ+DXNhaWQgdG8gaGF2ZWluIHRoZSBmaXJzdHdoaWxlIG90aGVyc2h5cG90aGV0aWNhbHBoaWxvc29waGVyc3Bvd2VyIG9mIHRoZWNvbnRhaW5lZCBpbnBlcmZvcm1lZCBieWluYWJpbGl0eSB0b3dlcmUgd3JpdHRlbnNwYW4gc3R5bGU9ImlucHV0IG5hbWU9InRoZSBxdWVzdGlvbmludGVuZGVkIGZvcnJlamVjdGlvbiBvZmltcGxpZXMgdGhhdGludmVudGVkIHRoZXRoZSBzdGFuZGFyZHdhcyBwcm9iYWJseWxpbmsgYmV0d2VlbnByb2Zlc3NvciBvZmludGVyYWN0aW9uc2NoYW5naW5nIHRoZUluZGlhbiBPY2VhbiBjbGFzcz0ibGFzdHdvcmtpbmcgd2l0aCdodHRwOi8vd3d3LnllYXJzIGJlZm9yZVRoaXMgd2FzIHRoZXJlY3JlYXRpb25hbGVudGVyaW5nIHRoZW1lYXN1cmVtZW50c2FuIGV4dHJlbWVseXZhbHVlIG9mIHRoZXN0YXJ0IG9mIHRoZQo8L3NjcmlwdD4KCmFuIGVmZm9ydCB0b2luY3JlYXNlIHRoZXRvIHRoZSBzb3V0aHNwYWNpbmc9IjAiPnN1ZmZpY2llbnRseXRoZSBFdXJvcGVhbmNvbnZlcnRlZCB0b2NsZWFyVGltZW91dGRpZCBub3QgaGF2ZWNvbnNlcXVlbnRseWZvciB0aGUgbmV4dGV4dGVuc2lvbiBvZmVjb25vbWljIGFuZGFsdGhvdWdoIHRoZWFyZSBwcm9kdWNlZGFuZCB3aXRoIHRoZWluc3VmZmljaWVudGdpdmVuIGJ5IHRoZXN0YXRpbmcgdGhhdGV4cGVuZGl0dXJlczwvc3Bhbj48L2E+CnRob3VnaHQgdGhhdG9uIHRoZSBiYXNpc2NlbGxwYWRkaW5nPWltYWdlIG9mIHRoZXJldHVybmluZyB0b2luZm9ybWF0aW9uLHNlcGFyYXRlZCBieWFzc2Fzc2luYXRlZHMiIGNvbnRlbnQ9ImF1dGhvcml0eSBvZm5vcnRod2VzdGVybjwvZGl2Pgo8ZGl2ICI+PC9kaXY+DQogIGNvbnN1bHRhdGlvbmNvbW11bml0eSBvZnRoZSBuYXRpb25hbGl0IHNob3VsZCBiZXBhcnRpY2lwYW50cyBhbGlnbj0ibGVmdHRoZSBncmVhdGVzdHNlbGVjdGlvbiBvZnN1cGVybmF0dXJhbGRlcGVuZGVudCBvbmlzIG1lbnRpb25lZGFsbG93aW5nIHRoZXdhcyBpbnZlbnRlZGFjY29tcGFueWluZ2hpcyBwZXJzb25hbGF2YWlsYWJsZSBhdHN0dWR5IG9mIHRoZW9uIHRoZSBvdGhlcmV4ZWN1dGlvbiBvZkh1bWFuIFJpZ2h0c3Rlcm1zIG9mIHRoZWFzc29jaWF0aW9uc3Jlc2VhcmNoIGFuZHN1Y2NlZWRlZCBieWRlZmVhdGVkIHRoZWFuZCBmcm9tIHRoZWJ1dCB0aGV5IGFyZWNvbW1hbmRlciBvZnN0YXRlIG9mIHRoZXllYXJzIG9mIGFnZXRoZSBzdHVkeSBvZjx1bCBjbGFzcz0ic3BsYWNlIGluIHRoZXdoZXJlIGhlIHdhczxsaSBjbGFzcz0iZnRoZXJlIGFyZSBub3doaWNoIGJlY2FtZWhlIHB1Ymxpc2hlZGV4cHJlc3NlZCBpbnRvIHdoaWNoIHRoZWNvbW1pc3Npb25lcmZvbnQtd2VpZ2h0OnRlcnJpdG9yeSBvZmV4dGVuc2lvbnMiPlJvbWFuIEVtcGlyZWVxdWFsIHRvIHRoZUluIGNvbnRyYXN0LGhvd2V2ZXIsIGFuZGlzIHR5cGljYWxseWFuZCBoaXMgd2lmZShhbHNvIGNhbGxlZD48dWwgY2xhc3M9ImVmZmVjdGl2ZWx5IGV2b2x2ZWQgaW50b3NlZW0gdG8gaGF2ZXdoaWNoIGlzIHRoZXRoZXJlIHdhcyBub2FuIGV4Y2VsbGVudGFsbCBvZiB0aGVzZWRlc2NyaWJlZCBieUluIHByYWN0aWNlLGJyb2FkY2FzdGluZ2NoYXJnZWQgd2l0aHJlZmxlY3RlZCBpbnN1YmplY3RlZCB0b21pbGl0YXJ5IGFuZHRvIHRoZSBwb2ludGVjb25vbWljYWxseXNldFRhcmdldGluZ2FyZSBhY3R1YWxseXZpY3Rvcnkgb3ZlcigpOzwvc2NyaXB0PmNvbnRpbnVvdXNseXJlcXVpcmVkIGZvcmV2b2x1dGlvbmFyeWFuIGVmZmVjdGl2ZW5vcnRoIG9mIHRoZSwgd2hpY2ggd2FzIGZyb250IG9mIHRoZW9yIG90aGVyd2lzZXNvbWUgZm9ybSBvZmhhZCBub3QgYmVlbmdlbmVyYXRlZCBieWluZm9ybWF0aW9uLnBlcm1pdHRlZCB0b2luY2x1ZGVzIHRoZWRldmVsb3BtZW50LGVudGVyZWQgaW50b3RoZSBwcmV2aW91c2NvbnNpc3RlbnRseWFyZSBrbm93biBhc3RoZSBmaWVsZCBvZnRoaXMgdHlwZSBvZmdpdmVuIHRvIHRoZXRoZSB0aXRsZSBvZmNvbnRhaW5zIHRoZWluc3RhbmNlcyBvZmluIHRoZSBub3J0aGR1ZSB0byB0aGVpcmFyZSBkZXNpZ25lZGNvcnBvcmF0aW9uc3dhcyB0aGF0IHRoZW9uZSBvZiB0aGVzZW1vcmUgcG9wdWxhcnN1Y2NlZWRlZCBpbnN1cHBvcnQgZnJvbWluIGRpZmZlcmVudGRvbWluYXRlZCBieWRlc2lnbmVkIGZvcm93bmVyc2hpcCBvZmFuZCBwb3NzaWJseXN0YW5kYXJkaXplZHJlc3BvbnNlVGV4dHdhcyBpbnRlbmRlZHJlY2VpdmVkIHRoZWFzc3VtZWQgdGhhdGFyZWFzIG9mIHRoZXByaW1hcmlseSBpbnRoZSBiYXNpcyBvZmluIHRoZSBzZW5zZWFjY291bnRzIGZvcmRlc3Ryb3llZCBieWF0IGxlYXN0IHR3b3dhcyBkZWNsYXJlZGNvdWxkIG5vdCBiZVNlY3JldGFyeSBvZmFwcGVhciB0byBiZW1hcmdpbi10b3A6MS9eXHMrfFxzKyQvZ2Upe3Rocm93IGV9O3RoZSBzdGFydCBvZnR3byBzZXBhcmF0ZWxhbmd1YWdlIGFuZHdobyBoYWQgYmVlbm9wZXJhdGlvbiBvZmRlYXRoIG9mIHRoZXJlYWwgbnVtYmVycwk8bGluayByZWw9InByb3ZpZGVkIHRoZXRoZSBzdG9yeSBvZmNvbXBldGl0aW9uc2VuZ2xpc2ggKFVLKWVuZ2xpc2ggKFVTKdCc0L7QvdCz0L7Qu9Ch0YDQv9GB0LrQuNGB0YDQv9GB0LrQuNGB0YDQv9GB0LrQvtmE2LnYsdio2YrYqeato+mrlOS4reaWh+eugOS9k+S4reaWh+e5geS9k+S4reaWh+aciemZkOWFrOWPuOS6uuawkeaUv+W6nOmYv+mHjOW3tOW3tOekvuS8muS4u+S5ieaTjeS9nOezu+e7n+aUv+etluazleinhGluZm9ybWFjacOzbmhlcnJhbWllbnRhc2VsZWN0csOzbmljb2Rlc2NyaXBjacOzbmNsYXNpZmljYWRvc2Nvbm9jaW1pZW50b3B1YmxpY2FjacOzbnJlbGFjaW9uYWRhc2luZm9ybcOhdGljYXJlbGFjaW9uYWRvc2RlcGFydGFtZW50b3RyYWJhamFkb3Jlc2RpcmVjdGFtZW50ZWF5dW50YW1pZW50b21lcmNhZG9MaWJyZWNvbnTDoWN0ZW5vc2hhYml0YWNpb25lc2N1bXBsaW1pZW50b3Jlc3RhdXJhbnRlc2Rpc3Bvc2ljacOzbmNvbnNlY3VlbmNpYWVsZWN0csOzbmljYWFwbGljYWNpb25lc2Rlc2NvbmVjdGFkb2luc3RhbGFjacOzbnJlYWxpemFjacOzbnV0aWxpemFjacOzbmVuY2ljbG9wZWRpYWVuZmVybWVkYWRlc2luc3RydW1lbnRvc2V4cGVyaWVuY2lhc2luc3RpdHVjacOzbnBhcnRpY3VsYXJlc3N1YmNhdGVnb3JpYdGC0L7Qu9GM0LrQvtCg0L7RgdGB0LjQuNGA0LDQsdC+0YLRi9Cx0L7Qu9GM0YjQtdC/0YDQvtGB0YLQvtC80L7QttC10YLQtdC00YDRg9Cz0LjRhdGB0LvRg9GH0LDQtdGB0LXQudGH0LDRgdCy0YHQtdCz0LTQsNCg0L7RgdGB0LjRj9Cc0L7RgdC60LLQtdC00YDRg9Cz0LjQtdCz0L7RgNC+0LTQsNCy0L7Qv9GA0L7RgdC00LDQvdC90YvRhdC00L7Qu9C20L3Ri9C40LzQtdC90L3QvtCc0L7RgdC60LLRi9GA0YPQsdC70LXQudCc0L7RgdC60LLQsNGB0YLRgNCw0L3Ri9C90LjRh9C10LPQvtGA0LDQsdC+0YLQtdC00L7Qu9C20LXQvdGD0YHQu9GD0LPQuNGC0LXQv9C10YDRjNCe0LTQvdCw0LrQvtC/0L7RgtC+0LzRg9GA0LDQsdC+0YLRg9Cw0L/RgNC10LvRj9Cy0L7QvtCx0YnQtdC+0LTQvdC+0LPQvtGB0LLQvtC10LPQvtGB0YLQsNGC0YzQuNC00YDRg9Cz0L7QudGE0L7RgNGD0LzQtdGF0L7RgNC+0YjQvtC/0YDQvtGC0LjQstGB0YHRi9C70LrQsNC60LDQttC00YvQudCy0LvQsNGB0YLQuNCz0YDRg9C/0L/Ri9Cy0LzQtdGB0YLQtdGA0LDQsdC+0YLQsNGB0LrQsNC30LDQu9C/0LXRgNCy0YvQudC00LXQu9Cw0YLRjNC00LXQvdGM0LPQuNC/0LXRgNC40L7QtNCx0LjQt9C90LXRgdC+0YHQvdC+0LLQtdC80L7QvNC10L3RgtC60YPQv9C40YLRjNC00L7Qu9C20L3QsNGA0LDQvNC60LDRhdC90LDRh9Cw0LvQvtCg0LDQsdC+0YLQsNCi0L7Qu9GM0LrQvtGB0L7QstGB0LXQvNCy0YLQvtGA0L7QudC90LDRh9Cw0LvQsNGB0L/QuNGB0L7QutGB0LvRg9C20LHRi9GB0LjRgdGC0LXQvNC/0LXRh9Cw0YLQuNC90L7QstC+0LPQvtC/0L7QvNC+0YnQuNGB0LDQudGC0L7QstC/0L7Rh9C10LzRg9C/0L7QvNC+0YnRjNC00L7Qu9C20L3QvtGB0YHRi9C70LrQuNCx0YvRgdGC0YDQvtC00LDQvdC90YvQtdC80L3QvtCz0LjQtdC/0YDQvtC10LrRgtCh0LXQudGH0LDRgdC80L7QtNC10LvQuNGC0LDQutC+0LPQvtC+0L3Qu9Cw0LnQvdCz0L7RgNC+0LTQtdCy0LXRgNGB0LjRj9GB0YLRgNCw0L3QtdGE0LjQu9GM0LzRi9GD0YDQvtCy0L3Rj9GA0LDQt9C90YvRhdC40YHQutCw0YLRjNC90LXQtNC10LvRjtGP0L3QstCw0YDRj9C80LXQvdGM0YjQtdC80L3QvtCz0LjRhdC00LDQvdC90L7QudC30L3QsNGH0LjRgtC90LXQu9GM0LfRj9GE0L7RgNGD0LzQsNCi0LXQv9C10YDRjNC80LXRgdGP0YbQsNC30LDRidC40YLRi9Cb0YPRh9GI0LjQteCkqOCkueClgOCkguCkleCksOCkqOClh+CkheCkquCkqOClh+CkleCkv+Ckr+CkvuCkleCksOClh+CkguCkheCkqOCljeCkr+CkleCljeCkr+CkvuCkl+CkvuCkh+CkoeCkrOCkvuCksOClh+CkleCkv+CkuOClgOCkpuCkv+Ckr+CkvuCkquCkueCksuClh+CkuOCkv+CkguCkueCkreCkvuCksOCkpOCkheCkquCkqOClgOCkteCkvuCksuClh+CkuOClh+CkteCkvuCkleCksOCkpOClh+CkruClh+CksOClh+CkueCli+CkqOClh+CkuOCkleCkpOClh+CkrOCkueClgeCkpOCkuOCkvuCkh+Ckn+CkueCli+Ckl+CkvuCknOCkvuCkqOClh+CkruCkv+CkqOCkn+CkleCksOCkpOCkvuCkleCksOCkqOCkvuCkieCkqOCkleClh+Ckr+CkueCkvuCkgeCkuOCkrOCkuOClh+CkreCkvuCkt+CkvuCkhuCkquCkleClh+CksuCkv+Ckr+Clh+CktuClgeCksOClguCkh+CkuOCkleClh+CkmOCkguCkn+Clh+CkruClh+CksOClgOCkuOCkleCkpOCkvuCkruClh+CksOCkvuCksuClh+CkleCksOCkheCkp+Ckv+CkleCkheCkquCkqOCkvuCkuOCkruCkvuCknOCkruClgeCkneClh+CkleCkvuCksOCko+CkueCli+CkpOCkvuCkleCkoeCkvOClgOCkr+CkueCkvuCkguCkueCli+Ckn+CksuCktuCkrOCljeCkpuCksuCkv+Ckr+CkvuCknOClgOCkteCkqOCknOCkvuCkpOCkvuCkleCliOCkuOClh+CkhuCkquCkleCkvuCkteCkvuCksuClgOCkpuClh+CkqOClh+CkquClguCksOClgOCkquCkvuCkqOClgOCkieCkuOCkleClh+CkueCli+Ckl+ClgOCkrOCliOCkoOCkleCkhuCkquCkleClgOCkteCksOCljeCkt+Ckl+CkvuCkguCkteCkhuCkquCkleCli+CknOCkv+CksuCkvuCknOCkvuCkqOCkvuCkuOCkueCkruCkpOCkueCkruClh+CkguCkieCkqOCkleClgOCkr+CkvuCkueClguCkpuCksOCljeCknOCkuOClguCkmuClgOCkquCkuOCkguCkpuCkuOCkteCkvuCksuCkueCli+CkqOCkvuCkueCli+CkpOClgOCknOCliOCkuOClh+CkteCkvuCkquCkuOCknOCkqOCkpOCkvuCkqOClh+CkpOCkvuCknOCkvuCksOClgOCkmOCkvuCkr+CksuCknOCkv+CksuClh+CkqOClgOCkmuClh+CknOCkvuCkguCkmuCkquCkpOCljeCksOCkl+ClguCkl+CksuCknOCkvuCkpOClh+CkrOCkvuCkueCksOCkhuCkquCkqOClh+CkteCkvuCkueCkqOCkh+CkuOCkleCkvuCkuOClgeCkrOCkueCksOCkueCkqOClh+Ckh+CkuOCkuOClh+CkuOCkueCkv+CkpOCkrOCkoeCkvOClh+CkmOCkn+CkqOCkvuCkpOCksuCkvuCktuCkquCkvuCkguCkmuCktuCljeCksOClgOCkrOCkoeCkvOClgOCkueCli+CkpOClh+CkuOCkvuCkiOCkn+CktuCkvuCkr+CkpuCkuOCkleCkpOClgOCknOCkvuCkpOClgOCkteCkvuCksuCkvuCkueCknOCkvuCksOCkquCkn+CkqOCkvuCksOCkluCkqOClh+CkuOCkoeCkvOCkleCkruCkv+CksuCkvuCkieCkuOCkleClgOCkleClh+CkteCksuCksuCkl+CkpOCkvuCkluCkvuCkqOCkvuCkheCksOCljeCkpeCknOCkueCkvuCkguCkpuClh+CkluCkvuCkquCkueCksuClgOCkqOCkv+Ckr+CkruCkrOCkv+CkqOCkvuCkrOCliOCkguCkleCkleCkueClgOCkguCkleCkueCkqOCkvuCkpuClh+CkpOCkvuCkueCkruCksuClh+CkleCkvuCkq+ClgOCknOCkrOCkleCkv+CkpOClgeCksOCkpOCkruCkvuCkguCkl+CkteCkueClgOCkguCksOCli+CknOCkvOCkruCkv+CksuClgOCkhuCksOCli+CkquCkuOClh+CkqOCkvuCkr+CkvuCkpuCkteCksuClh+CkqOClh+CkluCkvuCkpOCkvuCkleCksOClgOCkrOCkieCkqOCkleCkvuCknOCkteCkvuCkrOCkquClguCksOCkvuCkrOCkoeCkvOCkvuCkuOCljOCkpuCkvuCktuClh+Ckr+CksOCkleCkv+Ckr+Clh+CkleCkueCkvuCkguCkheCkleCkuOCksOCkrOCkqOCkvuCkj+CkteCkueCkvuCkguCkuOCljeCkpeCksuCkruCkv+CksuClh+CksuClh+CkluCkleCkteCkv+Ckt+Ckr+CkleCljeCksOCkguCkuOCkruClguCkueCkpeCkvuCkqOCkvtiq2LPYqti32YrYudmF2LTYp9ix2YPYqdio2YjYp9iz2LfYqdin2YTYtdmB2K3YqdmF2YjYp9i22YrYudin2YTYrtin2LXYqdin2YTZhdiy2YrYr9in2YTYudin2YXYqdin2YTZg9in2KrYqNin2YTYsdiv2YjYr9io2LHZhtin2YXYrNin2YTYr9mI2YTYqdin2YTYudin2YTZhdin2YTZhdmI2YLYudin2YTYudix2KjZitin2YTYs9ix2YrYudin2YTYrNmI2KfZhNin2YTYsNmH2KfYqNin2YTYrdmK2KfYqdin2YTYrdmC2YjZgtin2YTZg9ix2YrZhdin2YTYudix2KfZgtmF2K3ZgdmI2LjYqdin2YTYq9in2YbZitmF2LTYp9mH2K/Yqdin2YTZhdix2KPYqdin2YTZgtix2KLZhtin2YTYtNio2KfYqNin2YTYrdmI2KfYsdin2YTYrNiv2YrYr9in2YTYo9iz2LHYqdin2YTYudmE2YjZhdmF2KzZhdmI2LnYqdin2YTYsdit2YXZhtin2YTZhtmC2KfYt9mB2YTYs9i32YrZhtin2YTZg9mI2YrYqtin2YTYr9mG2YrYp9io2LHZg9in2KrZh9in2YTYsdmK2KfYttiq2K3Zitin2KrZitio2KrZiNmC2YrYqtin2YTYo9mI2YTZidin2YTYqNix2YrYr9in2YTZg9mE2KfZhdin2YTYsdin2KjYt9in2YTYtNiu2LXZitiz2YrYp9ix2KfYqtin2YTYq9in2YTYq9in2YTYtdmE2KfYqdin2YTYrdiv2YrYq9in2YTYstmI2KfYsdin2YTYrtmE2YrYrNin2YTYrNmF2YrYudin2YTYudin2YXZh9in2YTYrNmF2KfZhNin2YTYs9in2LnYqdmF2LTYp9mH2K/Zh9in2YTYsdim2YrYs9in2YTYr9iu2YjZhNin2YTZgdmG2YrYqdin2YTZg9iq2KfYqNin2YTYr9mI2LHZitin2YTYr9ix2YjYs9in2LPYqti62LHZgtiq2LXYp9mF2YrZhdin2YTYqNmG2KfYqtin2YTYudi42YrZhWVudGVydGFpbm1lbnR1bmRlcnN0YW5kaW5nID0gZnVuY3Rpb24oKS5qcGciIHdpZHRoPSJjb25maWd1cmF0aW9uLnBuZyIgd2lkdGg9Ijxib2R5IGNsYXNzPSJNYXRoLnJhbmRvbSgpY29udGVtcG9yYXJ5IFVuaXRlZCBTdGF0ZXNjaXJjdW1zdGFuY2VzLmFwcGVuZENoaWxkKG9yZ2FuaXphdGlvbnM8c3BhbiBjbGFzcz0iIj48aW1nIHNyYz0iL2Rpc3Rpbmd1aXNoZWR0aG91c2FuZHMgb2YgY29tbXVuaWNhdGlvbmNsZWFyIj48L2Rpdj5pbnZlc3RpZ2F0aW9uZmF2aWNvbi5pY28iIG1hcmdpbi1yaWdodDpiYXNlZCBvbiB0aGUgTWFzc2FjaHVzZXR0c3RhYmxlIGJvcmRlcj1pbnRlcm5hdGlvbmFsYWxzbyBrbm93biBhc3Byb251bmNpYXRpb25iYWNrZ3JvdW5kOiNmcGFkZGluZy1sZWZ0OkZvciBleGFtcGxlLCBtaXNjZWxsYW5lb3VzJmx0Oy9tYXRoJmd0O3BzeWNob2xvZ2ljYWxpbiBwYXJ0aWN1bGFyZWFyY2giIHR5cGU9ImZvcm0gbWV0aG9kPSJhcyBvcHBvc2VkIHRvU3VwcmVtZSBDb3VydG9jY2FzaW9uYWxseSBBZGRpdGlvbmFsbHksTm9ydGggQW1lcmljYXB4O2JhY2tncm91bmRvcHBvcnR1bml0aWVzRW50ZXJ0YWlubWVudC50b0xvd2VyQ2FzZShtYW51ZmFjdHVyaW5ncHJvZmVzc2lvbmFsIGNvbWJpbmVkIHdpdGhGb3IgaW5zdGFuY2UsY29uc2lzdGluZyBvZiIgbWF4bGVuZ3RoPSJyZXR1cm4gZmFsc2U7Y29uc2Npb3VzbmVzc01lZGl0ZXJyYW5lYW5leHRyYW9yZGluYXJ5YXNzYXNzaW5hdGlvbnN1YnNlcXVlbnRseSBidXR0b24gdHlwZT0idGhlIG51bWJlciBvZnRoZSBvcmlnaW5hbCBjb21wcmVoZW5zaXZlcmVmZXJzIHRvIHRoZTwvdWw+CjwvZGl2PgpwaGlsb3NvcGhpY2FsbG9jYXRpb24uaHJlZndhcyBwdWJsaXNoZWRTYW4gRnJhbmNpc2NvKGZ1bmN0aW9uKCl7CjxkaXYgaWQ9Im1haW5zb3BoaXN0aWNhdGVkbWF0aGVtYXRpY2FsIC9oZWFkPg0KPGJvZHlzdWdnZXN0cyB0aGF0ZG9jdW1lbnRhdGlvbmNvbmNlbnRyYXRpb25yZWxhdGlvbnNoaXBzbWF5IGhhdmUgYmVlbihmb3IgZXhhbXBsZSxUaGlzIGFydGljbGUgaW4gc29tZSBjYXNlc3BhcnRzIG9mIHRoZSBkZWZpbml0aW9uIG9mR3JlYXQgQnJpdGFpbiBjZWxscGFkZGluZz1lcXVpdmFsZW50IHRvcGxhY2Vob2xkZXI9IjsgZm9udC1zaXplOiBqdXN0aWZpY2F0aW9uYmVsaWV2ZWQgdGhhdHN1ZmZlcmVkIGZyb21hdHRlbXB0ZWQgdG8gbGVhZGVyIG9mIHRoZWNyaXB0IiBzcmM9Ii8oZnVuY3Rpb24oKSB7YXJlIGF2YWlsYWJsZQoJPGxpbmsgcmVsPSIgc3JjPSdodHRwOi8vaW50ZXJlc3RlZCBpbmNvbnZlbnRpb25hbCAiIGFsdD0iIiAvPjwvYXJlIGdlbmVyYWxseWhhcyBhbHNvIGJlZW5tb3N0IHBvcHVsYXIgY29ycmVzcG9uZGluZ2NyZWRpdGVkIHdpdGh0eWxlPSJib3JkZXI6PC9hPjwvc3Bhbj48Ly5naWYiIHdpZHRoPSI8aWZyYW1lIHNyYz0idGFibGUgY2xhc3M9ImlubGluZS1ibG9jazthY2NvcmRpbmcgdG8gdG9nZXRoZXIgd2l0aGFwcHJveGltYXRlbHlwYXJsaWFtZW50YXJ5bW9yZSBhbmQgbW9yZWRpc3BsYXk6bm9uZTt0cmFkaXRpb25hbGx5cHJlZG9taW5hbnRseSZuYnNwO3wmbmJzcDsmbmJzcDs8L3NwYW4+IGNlbGxzcGFjaW5nPTxpbnB1dCBuYW1lPSJvciIgY29udGVudD0iY29udHJvdmVyc2lhbHByb3BlcnR5PSJvZzoveC1zaG9ja3dhdmUtZGVtb25zdHJhdGlvbnN1cnJvdW5kZWQgYnlOZXZlcnRoZWxlc3Msd2FzIHRoZSBmaXJzdGNvbnNpZGVyYWJsZSBBbHRob3VnaCB0aGUgY29sbGFib3JhdGlvbnNob3VsZCBub3QgYmVwcm9wb3J0aW9uIG9mPHNwYW4gc3R5bGU9Imtub3duIGFzIHRoZSBzaG9ydGx5IGFmdGVyZm9yIGluc3RhbmNlLGRlc2NyaWJlZCBhcyAvaGVhZD4KPGJvZHkgc3RhcnRpbmcgd2l0aGluY3JlYXNpbmdseSB0aGUgZmFjdCB0aGF0ZGlzY3Vzc2lvbiBvZm1pZGRsZSBvZiB0aGVhbiBpbmRpdmlkdWFsZGlmZmljdWx0IHRvIHBvaW50IG9mIHZpZXdob21vc2V4dWFsaXR5YWNjZXB0YW5jZSBvZjwvc3Bhbj48L2Rpdj5tYW51ZmFjdHVyZXJzb3JpZ2luIG9mIHRoZWNvbW1vbmx5IHVzZWRpbXBvcnRhbmNlIG9mZGVub21pbmF0aW9uc2JhY2tncm91bmQ6ICNsZW5ndGggb2YgdGhlZGV0ZXJtaW5hdGlvbmEgc2lnbmlmaWNhbnQiIGJvcmRlcj0iMCI+cmV2b2x1dGlvbmFyeXByaW5jaXBsZXMgb2ZpcyBjb25zaWRlcmVkd2FzIGRldmVsb3BlZEluZG8tRXVyb3BlYW52dWxuZXJhYmxlIHRvcHJvcG9uZW50cyBvZmFyZSBzb21ldGltZXNjbG9zZXIgdG8gdGhlTmV3IFlvcmsgQ2l0eSBuYW1lPSJzZWFyY2hhdHRyaWJ1dGVkIHRvY291cnNlIG9mIHRoZW1hdGhlbWF0aWNpYW5ieSB0aGUgZW5kIG9mYXQgdGhlIGVuZCBvZiIgYm9yZGVyPSIwIiB0ZWNobm9sb2dpY2FsLnJlbW92ZUNsYXNzKGJyYW5jaCBvZiB0aGVldmlkZW5jZSB0aGF0IVtlbmRpZl0tLT4NCkluc3RpdHV0ZSBvZiBpbnRvIGEgc2luZ2xlcmVzcGVjdGl2ZWx5LmFuZCB0aGVyZWZvcmVwcm9wZXJ0aWVzIG9maXMgbG9jYXRlZCBpbnNvbWUgb2Ygd2hpY2hUaGVyZSBpcyBhbHNvY29udGludWVkIHRvIGFwcGVhcmFuY2Ugb2YgJmFtcDtuZGFzaDsgZGVzY3JpYmVzIHRoZWNvbnNpZGVyYXRpb25hdXRob3Igb2YgdGhlaW5kZXBlbmRlbnRseWVxdWlwcGVkIHdpdGhkb2VzIG5vdCBoYXZlPC9hPjxhIGhyZWY9ImNvbmZ1c2VkIHdpdGg8bGluayBocmVmPSIvYXQgdGhlIGFnZSBvZmFwcGVhciBpbiB0aGVUaGVzZSBpbmNsdWRlcmVnYXJkbGVzcyBvZmNvdWxkIGJlIHVzZWQgc3R5bGU9JnF1b3Q7c2V2ZXJhbCB0aW1lc3JlcHJlc2VudCB0aGVib2R5Pgo8L2h0bWw+dGhvdWdodCB0byBiZXBvcHVsYXRpb24gb2Zwb3NzaWJpbGl0aWVzcGVyY2VudGFnZSBvZmFjY2VzcyB0byB0aGVhbiBhdHRlbXB0IHRvcHJvZHVjdGlvbiBvZmpxdWVyeS9qcXVlcnl0d28gZGlmZmVyZW50YmVsb25nIHRvIHRoZWVzdGFibGlzaG1lbnRyZXBsYWNpbmcgdGhlZGVzY3JpcHRpb24iIGRldGVybWluZSB0aGVhdmFpbGFibGUgZm9yQWNjb3JkaW5nIHRvIHdpZGUgcmFuZ2Ugb2YJPGRpdiBjbGFzcz0ibW9yZSBjb21tb25seW9yZ2FuaXNhdGlvbnNmdW5jdGlvbmFsaXR5d2FzIGNvbXBsZXRlZCAmYW1wO21kYXNoOyBwYXJ0aWNpcGF0aW9udGhlIGNoYXJhY3RlcmFuIGFkZGl0aW9uYWxhcHBlYXJzIHRvIGJlZmFjdCB0aGF0IHRoZWFuIGV4YW1wbGUgb2ZzaWduaWZpY2FudGx5b25tb3VzZW92ZXI9ImJlY2F1c2UgdGhleSBhc3luYyA9IHRydWU7cHJvYmxlbXMgd2l0aHNlZW1zIHRvIGhhdmV0aGUgcmVzdWx0IG9mIHNyYz0iaHR0cDovL2ZhbWlsaWFyIHdpdGhwb3NzZXNzaW9uIG9mZnVuY3Rpb24gKCkge3Rvb2sgcGxhY2UgaW5hbmQgc29tZXRpbWVzc3Vic3RhbnRpYWxseTxzcGFuPjwvc3Bhbj5pcyBvZnRlbiB1c2VkaW4gYW4gYXR0ZW1wdGdyZWF0IGRlYWwgb2ZFbnZpcm9ubWVudGFsc3VjY2Vzc2Z1bGx5IHZpcnR1YWxseSBhbGwyMHRoIGNlbnR1cnkscHJvZmVzc2lvbmFsc25lY2Vzc2FyeSB0byBkZXRlcm1pbmVkIGJ5Y29tcGF0aWJpbGl0eWJlY2F1c2UgaXQgaXNEaWN0aW9uYXJ5IG9mbW9kaWZpY2F0aW9uc1RoZSBmb2xsb3dpbmdtYXkgcmVmZXIgdG86Q29uc2VxdWVudGx5LEludGVybmF0aW9uYWxhbHRob3VnaCBzb21ldGhhdCB3b3VsZCBiZXdvcmxkJ3MgZmlyc3RjbGFzc2lmaWVkIGFzYm90dG9tIG9mIHRoZShwYXJ0aWN1bGFybHlhbGlnbj0ibGVmdCIgbW9zdCBjb21tb25seWJhc2lzIGZvciB0aGVmb3VuZGF0aW9uIG9mY29udHJpYnV0aW9uc3BvcHVsYXJpdHkgb2ZjZW50ZXIgb2YgdGhldG8gcmVkdWNlIHRoZWp1cmlzZGljdGlvbnNhcHByb3hpbWF0aW9uIG9ubW91c2VvdXQ9Ik5ldyBUZXN0YW1lbnRjb2xsZWN0aW9uIG9mPC9zcGFuPjwvYT48L2luIHRoZSBVbml0ZWRmaWxtIGRpcmVjdG9yLXN0cmljdC5kdGQiPmhhcyBiZWVuIHVzZWRyZXR1cm4gdG8gdGhlYWx0aG91Z2ggdGhpc2NoYW5nZSBpbiB0aGVzZXZlcmFsIG90aGVyYnV0IHRoZXJlIGFyZXVucHJlY2VkZW50ZWRpcyBzaW1pbGFyIHRvZXNwZWNpYWxseSBpbndlaWdodDogYm9sZDtpcyBjYWxsZWQgdGhlY29tcHV0YXRpb25hbGluZGljYXRlIHRoYXRyZXN0cmljdGVkIHRvCTxtZXRhIG5hbWU9ImFyZSB0eXBpY2FsbHljb25mbGljdCB3aXRoSG93ZXZlciwgdGhlIEFuIGV4YW1wbGUgb2Zjb21wYXJlZCB3aXRocXVhbnRpdGllcyBvZnJhdGhlciB0aGFuIGFjb25zdGVsbGF0aW9ubmVjZXNzYXJ5IGZvcnJlcG9ydGVkIHRoYXRzcGVjaWZpY2F0aW9ucG9saXRpY2FsIGFuZCZuYnNwOyZuYnNwOzxyZWZlcmVuY2VzIHRvdGhlIHNhbWUgeWVhckdvdmVybm1lbnQgb2ZnZW5lcmF0aW9uIG9maGF2ZSBub3QgYmVlbnNldmVyYWwgeWVhcnNjb21taXRtZW50IHRvCQk8dWwgY2xhc3M9InZpc3VhbGl6YXRpb24xOXRoIGNlbnR1cnkscHJhY3RpdGlvbmVyc3RoYXQgaGUgd291bGRhbmQgY29udGludWVkb2NjdXBhdGlvbiBvZmlzIGRlZmluZWQgYXNjZW50cmUgb2YgdGhldGhlIGFtb3VudCBvZj48ZGl2IHN0eWxlPSJlcXVpdmFsZW50IG9mZGlmZmVyZW50aWF0ZWJyb3VnaHQgYWJvdXRtYXJnaW4tbGVmdDogYXV0b21hdGljYWxseXRob3VnaHQgb2YgYXNTb21lIG9mIHRoZXNlCjxkaXYgY2xhc3M9ImlucHV0IGNsYXNzPSJyZXBsYWNlZCB3aXRoaXMgb25lIG9mIHRoZWVkdWNhdGlvbiBhbmRpbmZsdWVuY2VkIGJ5cmVwdXRhdGlvbiBhcwo8bWV0YSBuYW1lPSJhY2NvbW1vZGF0aW9uPC9kaXY+CjwvZGl2PmxhcmdlIHBhcnQgb2ZJbnN0aXR1dGUgZm9ydGhlIHNvLWNhbGxlZCBhZ2FpbnN0IHRoZSBJbiB0aGlzIGNhc2Usd2FzIGFwcG9pbnRlZGNsYWltZWQgdG8gYmVIb3dldmVyLCB0aGlzRGVwYXJ0bWVudCBvZnRoZSByZW1haW5pbmdlZmZlY3Qgb24gdGhlcGFydGljdWxhcmx5IGRlYWwgd2l0aCB0aGUKPGRpdiBzdHlsZT0iYWxtb3N0IGFsd2F5c2FyZSBjdXJyZW50bHlleHByZXNzaW9uIG9mcGhpbG9zb3BoeSBvZmZvciBtb3JlIHRoYW5jaXZpbGl6YXRpb25zb24gdGhlIGlzbGFuZHNlbGVjdGVkSW5kZXhjYW4gcmVzdWx0IGluIiB2YWx1ZT0iIiAvPnRoZSBzdHJ1Y3R1cmUgLz48L2E+PC9kaXY+TWFueSBvZiB0aGVzZWNhdXNlZCBieSB0aGVvZiB0aGUgVW5pdGVkc3BhbiBjbGFzcz0ibWNhbiBiZSB0cmFjZWRpcyByZWxhdGVkIHRvYmVjYW1lIG9uZSBvZmlzIGZyZXF1ZW50bHlsaXZpbmcgaW4gdGhldGhlb3JldGljYWxseUZvbGxvd2luZyB0aGVSZXZvbHV0aW9uYXJ5Z292ZXJubWVudCBpbmlzIGRldGVybWluZWR0aGUgcG9saXRpY2FsaW50cm9kdWNlZCBpbnN1ZmZpY2llbnQgdG9kZXNjcmlwdGlvbiI+c2hvcnQgc3Rvcmllc3NlcGFyYXRpb24gb2ZhcyB0byB3aGV0aGVya25vd24gZm9yIGl0c3dhcyBpbml0aWFsbHlkaXNwbGF5OmJsb2NraXMgYW4gZXhhbXBsZXRoZSBwcmluY2lwYWxjb25zaXN0cyBvZiBhcmVjb2duaXplZCBhcy9ib2R5PjwvaHRtbD5hIHN1YnN0YW50aWFscmVjb25zdHJ1Y3RlZGhlYWQgb2Ygc3RhdGVyZXNpc3RhbmNlIHRvdW5kZXJncmFkdWF0ZVRoZXJlIGFyZSB0d29ncmF2aXRhdGlvbmFsYXJlIGRlc2NyaWJlZGludGVudGlvbmFsbHlzZXJ2ZWQgYXMgdGhlY2xhc3M9ImhlYWRlcm9wcG9zaXRpb24gdG9mdW5kYW1lbnRhbGx5ZG9taW5hdGVkIHRoZWFuZCB0aGUgb3RoZXJhbGxpYW5jZSB3aXRod2FzIGZvcmNlZCB0b3Jlc3BlY3RpdmVseSxhbmQgcG9saXRpY2FsaW4gc3VwcG9ydCBvZnBlb3BsZSBpbiB0aGUyMHRoIGNlbnR1cnkuYW5kIHB1Ymxpc2hlZGxvYWRDaGFydGJlYXR0byB1bmRlcnN0YW5kbWVtYmVyIHN0YXRlc2Vudmlyb25tZW50YWxmaXJzdCBoYWxmIG9mY291bnRyaWVzIGFuZGFyY2hpdGVjdHVyYWxiZSBjb25zaWRlcmVkY2hhcmFjdGVyaXplZGNsZWFySW50ZXJ2YWxhdXRob3JpdGF0aXZlRmVkZXJhdGlvbiBvZndhcyBzdWNjZWVkZWRhbmQgdGhlcmUgYXJlYSBjb25zZXF1ZW5jZXRoZSBQcmVzaWRlbnRhbHNvIGluY2x1ZGVkZnJlZSBzb2Z0d2FyZXN1Y2Nlc3Npb24gb2ZkZXZlbG9wZWQgdGhld2FzIGRlc3Ryb3llZGF3YXkgZnJvbSB0aGU7Cjwvc2NyaXB0Pgo8YWx0aG91Z2ggdGhleWZvbGxvd2VkIGJ5IGFtb3JlIHBvd2VyZnVscmVzdWx0ZWQgaW4gYVVuaXZlcnNpdHkgb2ZIb3dldmVyLCBtYW55dGhlIHByZXNpZGVudEhvd2V2ZXIsIHNvbWVpcyB0aG91Z2h0IHRvdW50aWwgdGhlIGVuZHdhcyBhbm5vdW5jZWRhcmUgaW1wb3J0YW50YWxzbyBpbmNsdWRlcz48aW5wdXQgdHlwZT10aGUgY2VudGVyIG9mIERPIE5PVCBBTFRFUnVzZWQgdG8gcmVmZXJ0aGVtZXMvP3NvcnQ9dGhhdCBoYWQgYmVlbnRoZSBiYXNpcyBmb3JoYXMgZGV2ZWxvcGVkaW4gdGhlIHN1bW1lcmNvbXBhcmF0aXZlbHlkZXNjcmliZWQgdGhlc3VjaCBhcyB0aG9zZXRoZSByZXN1bHRpbmdpcyBpbXBvc3NpYmxldmFyaW91cyBvdGhlclNvdXRoIEFmcmljYW5oYXZlIHRoZSBzYW1lZWZmZWN0aXZlbmVzc2luIHdoaWNoIGNhc2U7IHRleHQtYWxpZ246c3RydWN0dXJlIGFuZDsgYmFja2dyb3VuZDpyZWdhcmRpbmcgdGhlc3VwcG9ydGVkIHRoZWlzIGFsc28ga25vd25zdHlsZT0ibWFyZ2luaW5jbHVkaW5nIHRoZWJhaGFzYSBNZWxheXVub3JzayBib2ttw6Vsbm9yc2sgbnlub3Jza3Nsb3ZlbsWhxI1pbmFpbnRlcm5hY2lvbmFsY2FsaWZpY2FjacOzbmNvbXVuaWNhY2nDs25jb25zdHJ1Y2Npw7NuIj48ZGl2IGNsYXNzPSJkaXNhbWJpZ3VhdGlvbkRvbWFpbk5hbWUnLCAnYWRtaW5pc3RyYXRpb25zaW11bHRhbmVvdXNseXRyYW5zcG9ydGF0aW9uSW50ZXJuYXRpb25hbCBtYXJnaW4tYm90dG9tOnJlc3BvbnNpYmlsaXR5PCFbZW5kaWZdLS0+CjwvPjxtZXRhIG5hbWU9ImltcGxlbWVudGF0aW9uaW5mcmFzdHJ1Y3R1cmVyZXByZXNlbnRhdGlvbmJvcmRlci1ib3R0b206PC9oZWFkPgo8Ym9keT49aHR0cCUzQSUyRiUyRjxmb3JtIG1ldGhvZD0ibWV0aG9kPSJwb3N0IiAvZmF2aWNvbi5pY28iIH0pOwo8L3NjcmlwdD4KLnNldEF0dHJpYnV0ZShBZG1pbmlzdHJhdGlvbj0gbmV3IEFycmF5KCk7PCFbZW5kaWZdLS0+DQpkaXNwbGF5OmJsb2NrO1VuZm9ydHVuYXRlbHksIj4mbmJzcDs8L2Rpdj4vZmF2aWNvbi5pY28iPj0nc3R5bGVzaGVldCcgaWRlbnRpZmljYXRpb24sIGZvciBleGFtcGxlLDxsaT48YSBocmVmPSIvYW4gYWx0ZXJuYXRpdmVhcyBhIHJlc3VsdCBvZnB0Ij48L3NjcmlwdD4KdHlwZT0ic3VibWl0IiAKKGZ1bmN0aW9uKCkge3JlY29tbWVuZGF0aW9uZm9ybSBhY3Rpb249Ii90cmFuc2Zvcm1hdGlvbnJlY29uc3RydWN0aW9uLnN0eWxlLmRpc3BsYXkgQWNjb3JkaW5nIHRvIGhpZGRlbiIgbmFtZT0iYWxvbmcgd2l0aCB0aGVkb2N1bWVudC5ib2R5LmFwcHJveGltYXRlbHkgQ29tbXVuaWNhdGlvbnNwb3N0IiBhY3Rpb249Im1lYW5pbmcgJnF1b3Q7LS08IVtlbmRpZl0tLT5QcmltZSBNaW5pc3RlcmNoYXJhY3RlcmlzdGljPC9hPiA8YSBjbGFzcz10aGUgaGlzdG9yeSBvZiBvbm1vdXNlb3Zlcj0idGhlIGdvdmVybm1lbnRocmVmPSJodHRwczovL3dhcyBvcmlnaW5hbGx5d2FzIGludHJvZHVjZWRjbGFzc2lmaWNhdGlvbnJlcHJlc2VudGF0aXZlYXJlIGNvbnNpZGVyZWQ8IVtlbmRpZl0tLT4KCmRlcGVuZHMgb24gdGhlVW5pdmVyc2l0eSBvZiBpbiBjb250cmFzdCB0byBwbGFjZWhvbGRlcj0iaW4gdGhlIGNhc2Ugb2ZpbnRlcm5hdGlvbmFsIGNvbnN0aXR1dGlvbmFsc3R5bGU9ImJvcmRlci06IGZ1bmN0aW9uKCkge0JlY2F1c2Ugb2YgdGhlLXN0cmljdC5kdGQiPgo8dGFibGUgY2xhc3M9ImFjY29tcGFuaWVkIGJ5YWNjb3VudCBvZiB0aGU8c2NyaXB0IHNyYz0iL25hdHVyZSBvZiB0aGUgdGhlIHBlb3BsZSBpbiBpbiBhZGRpdGlvbiB0b3MpOyBqcy5pZCA9IGlkIiB3aWR0aD0iMTAwJSJyZWdhcmRpbmcgdGhlIFJvbWFuIENhdGhvbGljYW4gaW5kZXBlbmRlbnRmb2xsb3dpbmcgdGhlIC5naWYiIHdpZHRoPSIxdGhlIGZvbGxvd2luZyBkaXNjcmltaW5hdGlvbmFyY2hhZW9sb2dpY2FscHJpbWUgbWluaXN0ZXIuanMiPjwvc2NyaXB0PmNvbWJpbmF0aW9uIG9mIG1hcmdpbndpZHRoPSJjcmVhdGVFbGVtZW50KHcuYXR0YWNoRXZlbnQoPC9hPjwvdGQ+PC90cj5zcmM9Imh0dHBzOi8vYUluIHBhcnRpY3VsYXIsIGFsaWduPSJsZWZ0IiBDemVjaCBSZXB1YmxpY1VuaXRlZCBLaW5nZG9tY29ycmVzcG9uZGVuY2Vjb25jbHVkZWQgdGhhdC5odG1sIiB0aXRsZT0iKGZ1bmN0aW9uICgpIHtjb21lcyBmcm9tIHRoZWFwcGxpY2F0aW9uIG9mPHNwYW4gY2xhc3M9InNiZWxpZXZlZCB0byBiZWVtZW50KCdzY3JpcHQnPC9hPgo8L2xpPgo8bGl2ZXJ5IGRpZmZlcmVudD48c3BhbiBjbGFzcz0ib3B0aW9uIHZhbHVlPSIoYWxzbyBrbm93biBhcwk8bGk+PGEgaHJlZj0iPjxpbnB1dCBuYW1lPSJzZXBhcmF0ZWQgZnJvbXJlZmVycmVkIHRvIGFzIHZhbGlnbj0idG9wIj5mb3VuZGVyIG9mIHRoZWF0dGVtcHRpbmcgdG8gY2FyYm9uIGRpb3hpZGUKCjxkaXYgY2xhc3M9ImNsYXNzPSJzZWFyY2gtL2JvZHk+CjwvaHRtbD5vcHBvcnR1bml0eSB0b2NvbW11bmljYXRpb25zPC9oZWFkPg0KPGJvZHkgc3R5bGU9IndpZHRoOlRp4bq/bmcgVmnhu4d0Y2hhbmdlcyBpbiB0aGVib3JkZXItY29sb3I6IzAiIGJvcmRlcj0iMCIgPC9zcGFuPjwvZGl2Pjx3YXMgZGlzY292ZXJlZCIgdHlwZT0idGV4dCIgKTsKPC9zY3JpcHQ+CgpEZXBhcnRtZW50IG9mIGVjY2xlc2lhc3RpY2FsdGhlcmUgaGFzIGJlZW5yZXN1bHRpbmcgZnJvbTwvYm9keT48L2h0bWw+aGFzIG5ldmVyIGJlZW50aGUgZmlyc3QgdGltZWluIHJlc3BvbnNlIHRvYXV0b21hdGljYWxseSA8L2Rpdj4KCjxkaXYgaXdhcyBjb25zaWRlcmVkcGVyY2VudCBvZiB0aGUiIC8+PC9hPjwvZGl2PmNvbGxlY3Rpb24gb2YgZGVzY2VuZGVkIGZyb21zZWN0aW9uIG9mIHRoZWFjY2VwdC1jaGFyc2V0dG8gYmUgY29uZnVzZWRtZW1iZXIgb2YgdGhlIHBhZGRpbmctcmlnaHQ6dHJhbnNsYXRpb24gb2ZpbnRlcnByZXRhdGlvbiBocmVmPSdodHRwOi8vd2hldGhlciBvciBub3RUaGVyZSBhcmUgYWxzb3RoZXJlIGFyZSBtYW55YSBzbWFsbCBudW1iZXJvdGhlciBwYXJ0cyBvZmltcG9zc2libGUgdG8gIGNsYXNzPSJidXR0b25sb2NhdGVkIGluIHRoZS4gSG93ZXZlciwgdGhlYW5kIGV2ZW50dWFsbHlBdCB0aGUgZW5kIG9mIGJlY2F1c2Ugb2YgaXRzcmVwcmVzZW50cyB0aGU8Zm9ybSBhY3Rpb249IiBtZXRob2Q9InBvc3QiaXQgaXMgcG9zc2libGVtb3JlIGxpa2VseSB0b2FuIGluY3JlYXNlIGluaGF2ZSBhbHNvIGJlZW5jb3JyZXNwb25kcyB0b2Fubm91bmNlZCB0aGF0YWxpZ249InJpZ2h0Ij5tYW55IGNvdW50cmllc2ZvciBtYW55IHllYXJzZWFybGllc3Qga25vd25iZWNhdXNlIGl0IHdhc3B0Ij48L3NjcmlwdD4NIHZhbGlnbj0idG9wIiBpbmhhYml0YW50cyBvZmZvbGxvd2luZyB5ZWFyDQo8ZGl2IGNsYXNzPSJtaWxsaW9uIHBlb3BsZWNvbnRyb3ZlcnNpYWwgY29uY2VybmluZyB0aGVhcmd1ZSB0aGF0IHRoZWdvdmVybm1lbnQgYW5kYSByZWZlcmVuY2UgdG90cmFuc2ZlcnJlZCB0b2Rlc2NyaWJpbmcgdGhlIHN0eWxlPSJjb2xvcjphbHRob3VnaCB0aGVyZWJlc3Qga25vd24gZm9yc3VibWl0IiBuYW1lPSJtdWx0aXBsaWNhdGlvbm1vcmUgdGhhbiBvbmUgcmVjb2duaXRpb24gb2ZDb3VuY2lsIG9mIHRoZWVkaXRpb24gb2YgdGhlICA8bWV0YSBuYW1lPSJFbnRlcnRhaW5tZW50IGF3YXkgZnJvbSB0aGUgO21hcmdpbi1yaWdodDphdCB0aGUgdGltZSBvZmludmVzdGlnYXRpb25zY29ubmVjdGVkIHdpdGhhbmQgbWFueSBvdGhlcmFsdGhvdWdoIGl0IGlzYmVnaW5uaW5nIHdpdGggPHNwYW4gY2xhc3M9ImRlc2NlbmRhbnRzIG9mPHNwYW4gY2xhc3M9ImkgYWxpZ249InJpZ2h0IjwvaGVhZD4KPGJvZHkgYXNwZWN0cyBvZiB0aGVoYXMgc2luY2UgYmVlbkV1cm9wZWFuIFVuaW9ucmVtaW5pc2NlbnQgb2Ztb3JlIGRpZmZpY3VsdFZpY2UgUHJlc2lkZW50Y29tcG9zaXRpb24gb2ZwYXNzZWQgdGhyb3VnaG1vcmUgaW1wb3J0YW50Zm9udC1zaXplOjExcHhleHBsYW5hdGlvbiBvZnRoZSBjb25jZXB0IG9md3JpdHRlbiBpbiB0aGUJPHNwYW4gY2xhc3M9ImlzIG9uZSBvZiB0aGUgcmVzZW1ibGFuY2UgdG9vbiB0aGUgZ3JvdW5kc3doaWNoIGNvbnRhaW5zaW5jbHVkaW5nIHRoZSBkZWZpbmVkIGJ5IHRoZXB1YmxpY2F0aW9uIG9mbWVhbnMgdGhhdCB0aGVvdXRzaWRlIG9mIHRoZXN1cHBvcnQgb2YgdGhlPGlucHV0IGNsYXNzPSI8c3BhbiBjbGFzcz0idChNYXRoLnJhbmRvbSgpbW9zdCBwcm9taW5lbnRkZXNjcmlwdGlvbiBvZkNvbnN0YW50aW5vcGxld2VyZSBwdWJsaXNoZWQ8ZGl2IGNsYXNzPSJzZWFwcGVhcnMgaW4gdGhlMSIgaGVpZ2h0PSIxIiBtb3N0IGltcG9ydGFudHdoaWNoIGluY2x1ZGVzd2hpY2ggaGFkIGJlZW5kZXN0cnVjdGlvbiBvZnRoZSBwb3B1bGF0aW9uCgk8ZGl2IGNsYXNzPSJwb3NzaWJpbGl0eSBvZnNvbWV0aW1lcyB1c2VkYXBwZWFyIHRvIGhhdmVzdWNjZXNzIG9mIHRoZWludGVuZGVkIHRvIGJlcHJlc2VudCBpbiB0aGVzdHlsZT0iY2xlYXI6Yg0KPC9zY3JpcHQ+DQo8d2FzIGZvdW5kZWQgaW5pbnRlcnZpZXcgd2l0aF9pZCIgY29udGVudD0iY2FwaXRhbCBvZiB0aGUNCjxsaW5rIHJlbD0ic3JlbGVhc2Ugb2YgdGhlcG9pbnQgb3V0IHRoYXR4TUxIdHRwUmVxdWVzdGFuZCBzdWJzZXF1ZW50c2Vjb25kIGxhcmdlc3R2ZXJ5IGltcG9ydGFudHNwZWNpZmljYXRpb25zc3VyZmFjZSBvZiB0aGVhcHBsaWVkIHRvIHRoZWZvcmVpZ24gcG9saWN5X3NldERvbWFpbk5hbWVlc3RhYmxpc2hlZCBpbmlzIGJlbGlldmVkIHRvSW4gYWRkaXRpb24gdG9tZWFuaW5nIG9mIHRoZWlzIG5hbWVkIGFmdGVydG8gcHJvdGVjdCB0aGVpcyByZXByZXNlbnRlZERlY2xhcmF0aW9uIG9mbW9yZSBlZmZpY2llbnRDbGFzc2lmaWNhdGlvbm90aGVyIGZvcm1zIG9maGUgcmV0dXJuZWQgdG88c3BhbiBjbGFzcz0iY3BlcmZvcm1hbmNlIG9mKGZ1bmN0aW9uKCkgew1pZiBhbmQgb25seSBpZnJlZ2lvbnMgb2YgdGhlbGVhZGluZyB0byB0aGVyZWxhdGlvbnMgd2l0aFVuaXRlZCBOYXRpb25zc3R5bGU9ImhlaWdodDpvdGhlciB0aGFuIHRoZXlwZSIgY29udGVudD0iQXNzb2NpYXRpb24gb2YKPC9oZWFkPgo8Ym9keWxvY2F0ZWQgb24gdGhlaXMgcmVmZXJyZWQgdG8oaW5jbHVkaW5nIHRoZWNvbmNlbnRyYXRpb25zdGhlIGluZGl2aWR1YWxhbW9uZyB0aGUgbW9zdHRoYW4gYW55IG90aGVyLz4KPGxpbmsgcmVsPSIgcmV0dXJuIGZhbHNlO3RoZSBwdXJwb3NlIG9mdGhlIGFiaWxpdHkgdG87Y29sb3I6I2ZmZn0KLgo8c3BhbiBjbGFzcz0idGhlIHN1YmplY3Qgb2ZkZWZpbml0aW9ucyBvZj4NCjxsaW5rIHJlbD0iY2xhaW0gdGhhdCB0aGVoYXZlIGRldmVsb3BlZDx0YWJsZSB3aWR0aD0iY2VsZWJyYXRpb24gb2ZGb2xsb3dpbmcgdGhlIHRvIGRpc3Rpbmd1aXNoPHNwYW4gY2xhc3M9ImJ0YWtlcyBwbGFjZSBpbnVuZGVyIHRoZSBuYW1lbm90ZWQgdGhhdCB0aGU+PCFbZW5kaWZdLS0+CnN0eWxlPSJtYXJnaW4taW5zdGVhZCBvZiB0aGVpbnRyb2R1Y2VkIHRoZXRoZSBwcm9jZXNzIG9maW5jcmVhc2luZyB0aGVkaWZmZXJlbmNlcyBpbmVzdGltYXRlZCB0aGF0ZXNwZWNpYWxseSB0aGUvZGl2PjxkaXYgaWQ9IndhcyBldmVudHVhbGx5dGhyb3VnaG91dCBoaXN0aGUgZGlmZmVyZW5jZXNvbWV0aGluZyB0aGF0c3Bhbj48L3NwYW4+PC9zaWduaWZpY2FudGx5ID48L3NjcmlwdD4NCg0KZW52aXJvbm1lbnRhbCB0byBwcmV2ZW50IHRoZWhhdmUgYmVlbiB1c2VkZXNwZWNpYWxseSBmb3J1bmRlcnN0YW5kIHRoZWlzIGVzc2VudGlhbGx5d2VyZSB0aGUgZmlyc3RpcyB0aGUgbGFyZ2VzdGhhdmUgYmVlbiBtYWRlIiBzcmM9Imh0dHA6Ly9pbnRlcnByZXRlZCBhc3NlY29uZCBoYWxmIG9mY3JvbGxpbmc9Im5vIiBpcyBjb21wb3NlZCBvZklJLCBIb2x5IFJvbWFuaXMgZXhwZWN0ZWQgdG9oYXZlIHRoZWlyIG93bmRlZmluZWQgYXMgdGhldHJhZGl0aW9uYWxseSBoYXZlIGRpZmZlcmVudGFyZSBvZnRlbiB1c2VkdG8gZW5zdXJlIHRoYXRhZ3JlZW1lbnQgd2l0aGNvbnRhaW5pbmcgdGhlYXJlIGZyZXF1ZW50bHlpbmZvcm1hdGlvbiBvbmV4YW1wbGUgaXMgdGhlcmVzdWx0aW5nIGluIGE8L2E+PC9saT48L3VsPiBjbGFzcz0iZm9vdGVyYW5kIGVzcGVjaWFsbHl0eXBlPSJidXR0b24iIDwvc3Bhbj48L3NwYW4+d2hpY2ggaW5jbHVkZWQ+CjxtZXRhIG5hbWU9ImNvbnNpZGVyZWQgdGhlY2FycmllZCBvdXQgYnlIb3dldmVyLCBpdCBpc2JlY2FtZSBwYXJ0IG9maW4gcmVsYXRpb24gdG9wb3B1bGFyIGluIHRoZXRoZSBjYXBpdGFsIG9md2FzIG9mZmljaWFsbHl3aGljaCBoYXMgYmVlbnRoZSBIaXN0b3J5IG9mYWx0ZXJuYXRpdmUgdG9kaWZmZXJlbnQgZnJvbXRvIHN1cHBvcnQgdGhlc3VnZ2VzdGVkIHRoYXRpbiB0aGUgcHJvY2VzcyAgPGRpdiBjbGFzcz0idGhlIGZvdW5kYXRpb25iZWNhdXNlIG9mIGhpc2NvbmNlcm5lZCB3aXRodGhlIHVuaXZlcnNpdHlvcHBvc2VkIHRvIHRoZXRoZSBjb250ZXh0IG9mPHNwYW4gY2xhc3M9InB0ZXh0IiBuYW1lPSJxIgkJPGRpdiBjbGFzcz0idGhlIHNjaWVudGlmaWNyZXByZXNlbnRlZCBieW1hdGhlbWF0aWNpYW5zZWxlY3RlZCBieSB0aGV0aGF0IGhhdmUgYmVlbj48ZGl2IGNsYXNzPSJjZGl2IGlkPSJoZWFkZXJpbiBwYXJ0aWN1bGFyLGNvbnZlcnRlZCBpbnRvKTsKPC9zY3JpcHQ+CjxwaGlsb3NvcGhpY2FsIHNycHNrb2hydmF0c2tpdGnhur9uZyBWaeG7h3TQoNGD0YHRgdC60LjQudGA0YPRgdGB0LrQuNC5aW52ZXN0aWdhY2nDs25wYXJ0aWNpcGFjacOzbtC60L7RgtC+0YDRi9C10L7QsdC70LDRgdGC0LjQutC+0YLQvtGA0YvQudGH0LXQu9C+0LLQtdC60YHQuNGB0YLQtdC80YvQndC+0LLQvtGB0YLQuNC60L7RgtC+0YDRi9GF0L7QsdC70LDRgdGC0YzQstGA0LXQvNC10L3QuNC60L7RgtC+0YDQsNGP0YHQtdCz0L7QtNC90Y/RgdC60LDRh9Cw0YLRjNC90L7QstC+0YHRgtC40KPQutGA0LDQuNC90YvQstC+0L/RgNC+0YHRi9C60L7RgtC+0YDQvtC50YHQtNC10LvQsNGC0YzQv9C+0LzQvtGJ0YzRjtGB0YDQtdC00YHRgtCy0L7QsdGA0LDQt9C+0LzRgdGC0L7RgNC+0L3Ri9GD0YfQsNGB0YLQuNC10YLQtdGH0LXQvdC40LXQk9C70LDQstC90LDRj9C40YHRgtC+0YDQuNC40YHQuNGB0YLQtdC80LDRgNC10YjQtdC90LjRj9Ch0LrQsNGH0LDRgtGM0L/QvtGN0YLQvtC80YPRgdC70LXQtNGD0LXRgtGB0LrQsNC30LDRgtGM0YLQvtCy0LDRgNC+0LLQutC+0L3QtdGH0L3QvtGA0LXRiNC10L3QuNC10LrQvtGC0L7RgNC+0LXQvtGA0LPQsNC90L7QstC60L7RgtC+0YDQvtC80KDQtdC60LvQsNC80LDYp9mE2YXZhtiq2K/ZidmF2YbYqtiv2YrYp9iq2KfZhNmF2YjYttmI2LnYp9mE2KjYsdin2YXYrNin2YTZhdmI2KfZgti52KfZhNix2LPYp9im2YTZhdi02KfYsdmD2KfYqtin2YTYo9i52LbYp9ih2KfZhNix2YrYp9i22KnYp9mE2KrYtdmF2YrZhdin2YTYp9i52LbYp9ih2KfZhNmG2KrYp9im2KzYp9mE2KPZhNi52KfYqNin2YTYqtiz2KzZitmE2KfZhNij2YLYs9in2YXYp9mE2LbYuti32KfYqtin2YTZgdmK2K/ZitmI2KfZhNiq2LHYrdmK2KjYp9mE2KzYr9mK2K/Yqdin2YTYqti52YTZitmF2KfZhNij2K7YqNin2LHYp9mE2KfZgdmE2KfZhdin2YTYo9mB2YTYp9mF2KfZhNiq2KfYsdmK2K7Yp9mE2KrZgtmG2YrYqdin2YTYp9mE2LnYp9io2KfZhNiu2YjYp9i32LHYp9mE2YXYrNiq2YXYudin2YTYr9mK2YPZiNix2KfZhNiz2YrYp9it2KnYudio2K/Yp9mE2YTZh9in2YTYqtix2KjZitip2KfZhNix2YjYp9io2LfYp9mE2KPYr9io2YrYqdin2YTYp9iu2KjYp9ix2KfZhNmF2KrYrdiv2KnYp9mE2KfYutin2YbZimN1cnNvcjpwb2ludGVyOzwvdGl0bGU+CjxtZXRhICIgaHJlZj0iaHR0cDovLyI+PHNwYW4gY2xhc3M9Im1lbWJlcnMgb2YgdGhlIHdpbmRvdy5sb2NhdGlvbnZlcnRpY2FsLWFsaWduOi9hPiB8IDxhIGhyZWY9IjwhZG9jdHlwZSBodG1sPm1lZGlhPSJzY3JlZW4iIDxvcHRpb24gdmFsdWU9ImZhdmljb24uaWNvIiAvPgoJCTxkaXYgY2xhc3M9ImNoYXJhY3RlcmlzdGljcyIgbWV0aG9kPSJnZXQiIC9ib2R5Pgo8L2h0bWw+CnNob3J0Y3V0IGljb24iIGRvY3VtZW50LndyaXRlKHBhZGRpbmctYm90dG9tOnJlcHJlc2VudGF0aXZlc3N1Ym1pdCIgdmFsdWU9ImFsaWduPSJjZW50ZXIiIHRocm91Z2hvdXQgdGhlIHNjaWVuY2UgZmljdGlvbgogIDxkaXYgY2xhc3M9InN1Ym1pdCIgY2xhc3M9Im9uZSBvZiB0aGUgbW9zdCB2YWxpZ249InRvcCI+PHdhcyBlc3RhYmxpc2hlZCk7DQo8L3NjcmlwdD4NCnJldHVybiBmYWxzZTsiPikuc3R5bGUuZGlzcGxheWJlY2F1c2Ugb2YgdGhlIGRvY3VtZW50LmNvb2tpZTxmb3JtIGFjdGlvbj0iL31ib2R5e21hcmdpbjowO0VuY3ljbG9wZWRpYSBvZnZlcnNpb24gb2YgdGhlIC5jcmVhdGVFbGVtZW50KG5hbWUiIGNvbnRlbnQ9IjwvZGl2Pgo8L2Rpdj4KCmFkbWluaXN0cmF0aXZlIDwvYm9keT4KPC9odG1sPmhpc3Rvcnkgb2YgdGhlICI+PGlucHV0IHR5cGU9InBvcnRpb24gb2YgdGhlIGFzIHBhcnQgb2YgdGhlICZuYnNwOzxhIGhyZWY9Im90aGVyIGNvdW50cmllcyI+CjxkaXYgY2xhc3M9Ijwvc3Bhbj48L3NwYW4+PEluIG90aGVyIHdvcmRzLGRpc3BsYXk6IGJsb2NrO2NvbnRyb2wgb2YgdGhlIGludHJvZHVjdGlvbiBvZi8+CjxtZXRhIG5hbWU9ImFzIHdlbGwgYXMgdGhlIGluIHJlY2VudCB5ZWFycw0KCTxkaXYgY2xhc3M9IjwvZGl2PgoJPC9kaXY+Cmluc3BpcmVkIGJ5IHRoZXRoZSBlbmQgb2YgdGhlIGNvbXBhdGlibGUgd2l0aGJlY2FtZSBrbm93biBhcyBzdHlsZT0ibWFyZ2luOi5qcyI+PC9zY3JpcHQ+PCBJbnRlcm5hdGlvbmFsIHRoZXJlIGhhdmUgYmVlbkdlcm1hbiBsYW5ndWFnZSBzdHlsZT0iY29sb3I6I0NvbW11bmlzdCBQYXJ0eWNvbnNpc3RlbnQgd2l0aGJvcmRlcj0iMCIgY2VsbCBtYXJnaW5oZWlnaHQ9InRoZSBtYWpvcml0eSBvZiIgYWxpZ249ImNlbnRlcnJlbGF0ZWQgdG8gdGhlIG1hbnkgZGlmZmVyZW50IE9ydGhvZG94IENodXJjaHNpbWlsYXIgdG8gdGhlIC8+CjxsaW5rIHJlbD0ic3dhcyBvbmUgb2YgdGhlIHVudGlsIGhpcyBkZWF0aH0pKCk7Cjwvc2NyaXB0Pm90aGVyIGxhbmd1YWdlc2NvbXBhcmVkIHRvIHRoZXBvcnRpb25zIG9mIHRoZXRoZSBOZXRoZXJsYW5kc3RoZSBtb3N0IGNvbW1vbmJhY2tncm91bmQ6dXJsKGFyZ3VlZCB0aGF0IHRoZXNjcm9sbGluZz0ibm8iIGluY2x1ZGVkIGluIHRoZU5vcnRoIEFtZXJpY2FuIHRoZSBuYW1lIG9mIHRoZWludGVycHJldGF0aW9uc3RoZSB0cmFkaXRpb25hbGRldmVsb3BtZW50IG9mIGZyZXF1ZW50bHkgdXNlZGEgY29sbGVjdGlvbiBvZnZlcnkgc2ltaWxhciB0b3N1cnJvdW5kaW5nIHRoZWV4YW1wbGUgb2YgdGhpc2FsaWduPSJjZW50ZXIiPndvdWxkIGhhdmUgYmVlbmltYWdlX2NhcHRpb24gPWF0dGFjaGVkIHRvIHRoZXN1Z2dlc3RpbmcgdGhhdGluIHRoZSBmb3JtIG9mIGludm9sdmVkIGluIHRoZWlzIGRlcml2ZWQgZnJvbW5hbWVkIGFmdGVyIHRoZUludHJvZHVjdGlvbiB0b3Jlc3RyaWN0aW9ucyBvbiBzdHlsZT0id2lkdGg6IGNhbiBiZSB1c2VkIHRvIHRoZSBjcmVhdGlvbiBvZm1vc3QgaW1wb3J0YW50IGluZm9ybWF0aW9uIGFuZHJlc3VsdGVkIGluIHRoZWNvbGxhcHNlIG9mIHRoZVRoaXMgbWVhbnMgdGhhdGVsZW1lbnRzIG9mIHRoZXdhcyByZXBsYWNlZCBieWFuYWx5c2lzIG9mIHRoZWluc3BpcmF0aW9uIGZvcnJlZ2FyZGVkIGFzIHRoZW1vc3Qgc3VjY2Vzc2Z1bGtub3duIGFzICZxdW90O2EgY29tcHJlaGVuc2l2ZUhpc3Rvcnkgb2YgdGhlIHdlcmUgY29uc2lkZXJlZHJldHVybmVkIHRvIHRoZWFyZSByZWZlcnJlZCB0b1Vuc291cmNlZCBpbWFnZT4KCTxkaXYgY2xhc3M9ImNvbnNpc3RzIG9mIHRoZXN0b3BQcm9wYWdhdGlvbmludGVyZXN0IGluIHRoZWF2YWlsYWJpbGl0eSBvZmFwcGVhcnMgdG8gaGF2ZWVsZWN0cm9tYWduZXRpY2VuYWJsZVNlcnZpY2VzKGZ1bmN0aW9uIG9mIHRoZUl0IGlzIGltcG9ydGFudDwvc2NyaXB0PjwvZGl2PmZ1bmN0aW9uKCl7dmFyIHJlbGF0aXZlIHRvIHRoZWFzIGEgcmVzdWx0IG9mIHRoZSBwb3NpdGlvbiBvZkZvciBleGFtcGxlLCBpbiBtZXRob2Q9InBvc3QiIHdhcyBmb2xsb3dlZCBieSZhbXA7bWRhc2g7IHRoZXRoZSBhcHBsaWNhdGlvbmpzIj48L3NjcmlwdD4NCnVsPjwvZGl2PjwvZGl2PmFmdGVyIHRoZSBkZWF0aHdpdGggcmVzcGVjdCB0b3N0eWxlPSJwYWRkaW5nOmlzIHBhcnRpY3VsYXJseWRpc3BsYXk6aW5saW5lOyB0eXBlPSJzdWJtaXQiIGlzIGRpdmlkZWQgaW50b+S4reaWhyAo566A5L2TKXJlc3BvbnNhYmlsaWRhZGFkbWluaXN0cmFjacOzbmludGVybmFjaW9uYWxlc2NvcnJlc3BvbmRpZW50ZeCkieCkquCkr+Cli+Ckl+CkquClguCksOCljeCkteCkueCkruCkvuCksOClh+CksuCli+Ckl+Cli+CkguCkmuClgeCkqOCkvuCkteCksuClh+CkleCkv+CkqOCkuOCksOCkleCkvuCksOCkquClgeCksuCkv+CkuOCkluCli+CknOClh+CkguCkmuCkvuCkueCkv+Ckj+CkreClh+CknOClh+CkguCktuCkvuCkruCkv+CksuCkueCkruCkvuCksOClgOCknOCkvuCkl+CksOCko+CkrOCkqOCkvuCkqOClh+CkleClgeCkruCkvuCksOCkrOCljeCksuClieCkl+CkruCkvuCksuCkv+CkleCkruCkueCkv+CksuCkvuCkquClg+Ckt+CljeCkoOCkrOCkouCkvOCkpOClh+CkreCkvuCknOCkquCkvuCkleCljeCksuCkv+CkleCkn+CljeCksOClh+CkqOCkluCkv+CksuCkvuCkq+CkpuCljOCksOCkvuCkqOCkruCkvuCkruCksuClh+CkruCkpOCkpuCkvuCkqOCkrOCkvuCknOCkvuCksOCkteCkv+CkleCkvuCkuOCkleCljeCkr+Cli+CkguCkmuCkvuCkueCkpOClh+CkquCkueClgeCkgeCkmuCkrOCkpOCkvuCkr+CkvuCkuOCkguCkteCkvuCkpuCkpuClh+CkluCkqOClh+CkquCkv+Ckm+CksuClh+CkteCkv+CktuClh+Ckt+CksOCkvuCknOCljeCkr+CkieCkpOCljeCkpOCksOCkruClgeCkguCkrOCkiOCkpuCli+CkqOCli+CkguCkieCkquCkleCksOCko+CkquCkouCkvOClh+CkguCkuOCljeCkpeCkv+CkpOCkq+Ckv+CksuCljeCkruCkruClgeCkluCljeCkr+CkheCkmuCljeCkm+CkvuCkm+ClguCkn+CkpOClgOCkuOCkguCkl+ClgOCkpOCknOCkvuCkj+Ckl+CkvuCkteCkv+CkreCkvuCkl+CkmOCko+CljeCkn+Clh+CkpuClguCkuOCksOClh+CkpuCkv+CkqOCli+CkguCkueCkpOCljeCkr+CkvuCkuOClh+CkleCljeCkuOCkl+CkvuCkguCkp+ClgOCkteCkv+CktuCljeCkteCksOCkvuCkpOClh+CkguCkpuCliOCkn+CljeCkuOCkqOCkleCljeCktuCkvuCkuOCkvuCkruCkqOClh+CkheCkpuCkvuCksuCkpOCkrOCkv+CknOCksuClgOCkquClgeCksOClguCkt+CkueCkv+CkguCkpuClgOCkruCkv+CkpOCljeCksOCkleCkteCkv+CkpOCkvuCksOClgeCkquCkr+Clh+CkuOCljeCkpeCkvuCkqOCkleCksOCli+CkoeCkvOCkruClgeCkleCljeCkpOCkr+Cli+CknOCkqOCkvuCkleClg+CkquCkr+CkvuCkquCli+CkuOCljeCkn+CkmOCksOClh+CksuClguCkleCkvuCksOCljeCkr+CkteCkv+CkmuCkvuCksOCkuOClguCkmuCkqOCkvuCkruClguCksuCljeCkr+CkpuClh+CkluClh+CkguCkueCkruClh+CktuCkvuCkuOCljeCkleClguCksuCkruCliOCkguCkqOClh+CkpOCliOCkr+CkvuCksOCknOCkv+CkuOCkleClh3Jzcyt4bWwiIHRpdGxlPSItdHlwZSIgY29udGVudD0idGl0bGUiIGNvbnRlbnQ9ImF0IHRoZSBzYW1lIHRpbWUuanMiPjwvc2NyaXB0Pgo8IiBtZXRob2Q9InBvc3QiIDwvc3Bhbj48L2E+PC9saT52ZXJ0aWNhbC1hbGlnbjp0L2pxdWVyeS5taW4uanMiPi5jbGljayhmdW5jdGlvbiggc3R5bGU9InBhZGRpbmctfSkoKTsKPC9zY3JpcHQ+Cjwvc3Bhbj48YSBocmVmPSI8YSBocmVmPSJodHRwOi8vKTsgcmV0dXJuIGZhbHNlO3RleHQtZGVjb3JhdGlvbjogc2Nyb2xsaW5nPSJubyIgYm9yZGVyLWNvbGxhcHNlOmFzc29jaWF0ZWQgd2l0aCBCYWhhc2EgSW5kb25lc2lhRW5nbGlzaCBsYW5ndWFnZTx0ZXh0IHhtbDpzcGFjZT0uZ2lmIiBib3JkZXI9IjAiPC9ib2R5Pgo8L2h0bWw+Cm92ZXJmbG93OmhpZGRlbjtpbWcgc3JjPSJodHRwOi8vYWRkRXZlbnRMaXN0ZW5lcnJlc3BvbnNpYmxlIGZvciBzLmpzIj48L3NjcmlwdD4KL2Zhdmljb24uaWNvIiAvPm9wZXJhdGluZyBzeXN0ZW0iIHN0eWxlPSJ3aWR0aDoxdGFyZ2V0PSJfYmxhbmsiPlN0YXRlIFVuaXZlcnNpdHl0ZXh0LWFsaWduOmxlZnQ7CmRvY3VtZW50LndyaXRlKCwgaW5jbHVkaW5nIHRoZSBhcm91bmQgdGhlIHdvcmxkKTsNCjwvc2NyaXB0Pg0KPCIgc3R5bGU9ImhlaWdodDo7b3ZlcmZsb3c6aGlkZGVubW9yZSBpbmZvcm1hdGlvbmFuIGludGVybmF0aW9uYWxhIG1lbWJlciBvZiB0aGUgb25lIG9mIHRoZSBmaXJzdGNhbiBiZSBmb3VuZCBpbiA8L2Rpdj4KCQk8L2Rpdj4KZGlzcGxheTogbm9uZTsiPiIgLz4KPGxpbmsgcmVsPSIKICAoZnVuY3Rpb24oKSB7dGhlIDE1dGggY2VudHVyeS5wcmV2ZW50RGVmYXVsdChsYXJnZSBudW1iZXIgb2YgQnl6YW50aW5lIEVtcGlyZS5qcGd8dGh1bWJ8bGVmdHx2YXN0IG1ham9yaXR5IG9mbWFqb3JpdHkgb2YgdGhlICBhbGlnbj0iY2VudGVyIj5Vbml2ZXJzaXR5IFByZXNzZG9taW5hdGVkIGJ5IHRoZVNlY29uZCBXb3JsZCBXYXJkaXN0cmlidXRpb24gb2Ygc3R5bGU9InBvc2l0aW9uOnRoZSByZXN0IG9mIHRoZSBjaGFyYWN0ZXJpemVkIGJ5IHJlbD0ibm9mb2xsb3ciPmRlcml2ZXMgZnJvbSB0aGVyYXRoZXIgdGhhbiB0aGUgYSBjb21iaW5hdGlvbiBvZnN0eWxlPSJ3aWR0aDoxMDBFbmdsaXNoLXNwZWFraW5nY29tcHV0ZXIgc2NpZW5jZWJvcmRlcj0iMCIgYWx0PSJ0aGUgZXhpc3RlbmNlIG9mRGVtb2NyYXRpYyBQYXJ0eSIgc3R5bGU9Im1hcmdpbi1Gb3IgdGhpcyByZWFzb24sLmpzIj48L3NjcmlwdD4KCXNCeVRhZ05hbWUocylbMF1qcyI+PC9zY3JpcHQ+DQo8LmpzIj48L3NjcmlwdD4NCmxpbmsgcmVsPSJpY29uIiAnIGFsdD0nJyBjbGFzcz0nZm9ybWF0aW9uIG9mIHRoZXZlcnNpb25zIG9mIHRoZSA8L2E+PC9kaXY+PC9kaXY+L3BhZ2U+CiAgPHBhZ2U+CjxkaXYgY2xhc3M9ImNvbnRiZWNhbWUgdGhlIGZpcnN0YmFoYXNhIEluZG9uZXNpYWVuZ2xpc2ggKHNpbXBsZSnOlc67zrvOt869zrnOus6s0YXRgNCy0LDRgtGB0LrQuNC60L7QvNC/0LDQvdC40LjRj9Cy0LvRj9C10YLRgdGP0JTQvtCx0LDQstC40YLRjNGH0LXQu9C+0LLQtdC60LDRgNCw0LfQstC40YLQuNGP0JjQvdGC0LXRgNC90LXRgtCe0YLQstC10YLQuNGC0YzQvdCw0L/RgNC40LzQtdGA0LjQvdGC0LXRgNC90LXRgtC60L7RgtC+0YDQvtCz0L7RgdGC0YDQsNC90LjRhtGL0LrQsNGH0LXRgdGC0LLQtdGD0YHQu9C+0LLQuNGP0YXQv9GA0L7QsdC70LXQvNGL0L/QvtC70YPRh9C40YLRjNGP0LLQu9GP0Y7RgtGB0Y/QvdCw0LjQsdC+0LvQtdC10LrQvtC80L/QsNC90LjRj9Cy0L3QuNC80LDQvdC40LXRgdGA0LXQtNGB0YLQstCw2KfZhNmF2YjYp9i22YrYudin2YTYsdim2YrYs9mK2KnYp9mE2KfZhtiq2YLYp9mE2YXYtNin2LHZg9in2KrZg9in2YTYs9mK2KfYsdin2KrYp9mE2YXZg9iq2YjYqNip2KfZhNiz2LnZiNiv2YrYqdin2K3Ytdin2KbZitin2KrYp9mE2LnYp9mE2YXZitip2KfZhNi12YjYqtmK2KfYqtin2YTYp9mG2KrYsdmG2KrYp9mE2KrYtdin2YXZitmF2KfZhNil2LPZhNin2YXZitin2YTZhdi02KfYsdmD2KnYp9mE2YXYsdim2YrYp9iqcm9ib3RzIiBjb250ZW50PSI8ZGl2IGlkPSJmb290ZXIiPnRoZSBVbml0ZWQgU3RhdGVzPGltZyBzcmM9Imh0dHA6Ly8uanBnfHJpZ2h0fHRodW1ifC5qcyI+PC9zY3JpcHQ+DQo8bG9jYXRpb24ucHJvdG9jb2xmcmFtZWJvcmRlcj0iMCIgcyIgLz4KPG1ldGEgbmFtZT0iPC9hPjwvZGl2PjwvZGl2Pjxmb250LXdlaWdodDpib2xkOyZxdW90OyBhbmQgJnF1b3Q7ZGVwZW5kaW5nIG9uIHRoZSBtYXJnaW46MDtwYWRkaW5nOiIgcmVsPSJub2ZvbGxvdyIgUHJlc2lkZW50IG9mIHRoZSB0d2VudGlldGggY2VudHVyeWV2aXNpb24+CiAgPC9wYWdlSW50ZXJuZXQgRXhwbG9yZXJhLmFzeW5jID0gdHJ1ZTsNCmluZm9ybWF0aW9uIGFib3V0PGRpdiBpZD0iaGVhZGVyIj4iIGFjdGlvbj0iaHR0cDovLzxhIGhyZWY9Imh0dHBzOi8vPGRpdiBpZD0iY29udGVudCI8L2Rpdj4NCjwvZGl2Pg0KPGRlcml2ZWQgZnJvbSB0aGUgPGltZyBzcmM9J2h0dHA6Ly9hY2NvcmRpbmcgdG8gdGhlIAo8L2JvZHk+CjwvaHRtbD4Kc3R5bGU9ImZvbnQtc2l6ZTpzY3JpcHQgbGFuZ3VhZ2U9IkFyaWFsLCBIZWx2ZXRpY2EsPC9hPjxzcGFuIGNsYXNzPSI8L3NjcmlwdD48c2NyaXB0IHBvbGl0aWNhbCBwYXJ0aWVzdGQ+PC90cj48L3RhYmxlPjxocmVmPSJodHRwOi8vd3d3LmludGVycHJldGF0aW9uIG9mcmVsPSJzdHlsZXNoZWV0IiBkb2N1bWVudC53cml0ZSgnPGNoYXJzZXQ9InV0Zi04Ij4KYmVnaW5uaW5nIG9mIHRoZSByZXZlYWxlZCB0aGF0IHRoZXRlbGV2aXNpb24gc2VyaWVzIiByZWw9Im5vZm9sbG93Ij4gdGFyZ2V0PSJfYmxhbmsiPmNsYWltaW5nIHRoYXQgdGhlaHR0cCUzQSUyRiUyRnd3dy5tYW5pZmVzdGF0aW9ucyBvZlByaW1lIE1pbmlzdGVyIG9maW5mbHVlbmNlZCBieSB0aGVjbGFzcz0iY2xlYXJmaXgiPi9kaXY+DQo8L2Rpdj4NCg0KdGhyZWUtZGltZW5zaW9uYWxDaHVyY2ggb2YgRW5nbGFuZG9mIE5vcnRoIENhcm9saW5hc3F1YXJlIGtpbG9tZXRyZXMuYWRkRXZlbnRMaXN0ZW5lcmRpc3RpbmN0IGZyb20gdGhlY29tbW9ubHkga25vd24gYXNQaG9uZXRpYyBBbHBoYWJldGRlY2xhcmVkIHRoYXQgdGhlY29udHJvbGxlZCBieSB0aGVCZW5qYW1pbiBGcmFua2xpbnJvbGUtcGxheWluZyBnYW1ldGhlIFVuaXZlcnNpdHkgb2ZpbiBXZXN0ZXJuIEV1cm9wZXBlcnNvbmFsIGNvbXB1dGVyUHJvamVjdCBHdXRlbmJlcmdyZWdhcmRsZXNzIG9mIHRoZWhhcyBiZWVuIHByb3Bvc2VkdG9nZXRoZXIgd2l0aCB0aGU+PC9saT48bGkgY2xhc3M9ImluIHNvbWUgY291bnRyaWVzbWluLmpzIj48L3NjcmlwdD5vZiB0aGUgcG9wdWxhdGlvbm9mZmljaWFsIGxhbmd1YWdlPGltZyBzcmM9ImltYWdlcy9pZGVudGlmaWVkIGJ5IHRoZW5hdHVyYWwgcmVzb3VyY2VzY2xhc3NpZmljYXRpb24gb2ZjYW4gYmUgY29uc2lkZXJlZHF1YW50dW0gbWVjaGFuaWNzTmV2ZXJ0aGVsZXNzLCB0aGVtaWxsaW9uIHllYXJzIGFnbzwvYm9keT4NCjwvaHRtbD4NzpXOu867zrfOvc65zrrOrAp0YWtlIGFkdmFudGFnZSBvZmFuZCwgYWNjb3JkaW5nIHRvYXR0cmlidXRlZCB0byB0aGVNaWNyb3NvZnQgV2luZG93c3RoZSBmaXJzdCBjZW50dXJ5dW5kZXIgdGhlIGNvbnRyb2xkaXYgY2xhc3M9ImhlYWRlcnNob3J0bHkgYWZ0ZXIgdGhlbm90YWJsZSBleGNlcHRpb250ZW5zIG9mIHRob3VzYW5kc3NldmVyYWwgZGlmZmVyZW50YXJvdW5kIHRoZSB3b3JsZC5yZWFjaGluZyBtaWxpdGFyeWlzb2xhdGVkIGZyb20gdGhlb3Bwb3NpdGlvbiB0byB0aGV0aGUgT2xkIFRlc3RhbWVudEFmcmljYW4gQW1lcmljYW5zaW5zZXJ0ZWQgaW50byB0aGVzZXBhcmF0ZSBmcm9tIHRoZW1ldHJvcG9saXRhbiBhcmVhbWFrZXMgaXQgcG9zc2libGVhY2tub3dsZWRnZWQgdGhhdGFyZ3VhYmx5IHRoZSBtb3N0dHlwZT0idGV4dC9jc3MiPgp0aGUgSW50ZXJuYXRpb25hbEFjY29yZGluZyB0byB0aGUgcGU9InRleHQvY3NzIiAvPgpjb2luY2lkZSB3aXRoIHRoZXR3by10aGlyZHMgb2YgdGhlRHVyaW5nIHRoaXMgdGltZSxkdXJpbmcgdGhlIHBlcmlvZGFubm91bmNlZCB0aGF0IGhldGhlIGludGVybmF0aW9uYWxhbmQgbW9yZSByZWNlbnRseWJlbGlldmVkIHRoYXQgdGhlY29uc2Npb3VzbmVzcyBhbmRmb3JtZXJseSBrbm93biBhc3N1cnJvdW5kZWQgYnkgdGhlZmlyc3QgYXBwZWFyZWQgaW5vY2Nhc2lvbmFsbHkgdXNlZHBvc2l0aW9uOmFic29sdXRlOyIgdGFyZ2V0PSJfYmxhbmsiIHBvc2l0aW9uOnJlbGF0aXZlO3RleHQtYWxpZ246Y2VudGVyO2pheC9saWJzL2pxdWVyeS8xLmJhY2tncm91bmQtY29sb3I6I3R5cGU9ImFwcGxpY2F0aW9uL2FuZ3VhZ2UiIGNvbnRlbnQ9IjxtZXRhIGh0dHAtZXF1aXY9IlByaXZhY3kgUG9saWN5PC9hPmUoIiUzQ3NjcmlwdCBzcmM9JyIgdGFyZ2V0PSJfYmxhbmsiPk9uIHRoZSBvdGhlciBoYW5kLC5qcGd8dGh1bWJ8cmlnaHR8MjwvZGl2PjxkaXYgY2xhc3M9IjxkaXYgc3R5bGU9ImZsb2F0Om5pbmV0ZWVudGggY2VudHVyeTwvYm9keT4NCjwvaHRtbD4NCjxpbWcgc3JjPSJodHRwOi8vczt0ZXh0LWFsaWduOmNlbnRlcmZvbnQtd2VpZ2h0OiBib2xkOyBBY2NvcmRpbmcgdG8gdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiIgZnJhbWVib3JkZXI9IjAiICIgc3R5bGU9InBvc2l0aW9uOmxpbmsgaHJlZj0iaHR0cDovL2h0bWw0L2xvb3NlLmR0ZCI+CmR1cmluZyB0aGlzIHBlcmlvZDwvdGQ+PC90cj48L3RhYmxlPmNsb3NlbHkgcmVsYXRlZCB0b2ZvciB0aGUgZmlyc3QgdGltZTtmb250LXdlaWdodDpib2xkO2lucHV0IHR5cGU9InRleHQiIDxzcGFuIHN0eWxlPSJmb250LW9ucmVhZHlzdGF0ZWNoYW5nZQk8ZGl2IGNsYXNzPSJjbGVhcmRvY3VtZW50LmxvY2F0aW9uLiBGb3IgZXhhbXBsZSwgdGhlIGEgd2lkZSB2YXJpZXR5IG9mIDwhRE9DVFlQRSBodG1sPg0KPCZuYnNwOyZuYnNwOyZuYnNwOyI+PGEgaHJlZj0iaHR0cDovL3N0eWxlPSJmbG9hdDpsZWZ0O2NvbmNlcm5lZCB3aXRoIHRoZT1odHRwJTNBJTJGJTJGd3d3LmluIHBvcHVsYXIgY3VsdHVyZXR5cGU9InRleHQvY3NzIiAvPml0IGlzIHBvc3NpYmxlIHRvIEhhcnZhcmQgVW5pdmVyc2l0eXR5bGVzaGVldCIgaHJlZj0iL3RoZSBtYWluIGNoYXJhY3Rlck94Zm9yZCBVbml2ZXJzaXR5ICBuYW1lPSJrZXl3b3JkcyIgY3N0eWxlPSJ0ZXh0LWFsaWduOnRoZSBVbml0ZWQgS2luZ2RvbWZlZGVyYWwgZ292ZXJubWVudDxkaXYgc3R5bGU9Im1hcmdpbiBkZXBlbmRpbmcgb24gdGhlIGRlc2NyaXB0aW9uIG9mIHRoZTxkaXYgY2xhc3M9ImhlYWRlci5taW4uanMiPjwvc2NyaXB0PmRlc3RydWN0aW9uIG9mIHRoZXNsaWdodGx5IGRpZmZlcmVudGluIGFjY29yZGFuY2Ugd2l0aHRlbGVjb21tdW5pY2F0aW9uc2luZGljYXRlcyB0aGF0IHRoZXNob3J0bHkgdGhlcmVhZnRlcmVzcGVjaWFsbHkgaW4gdGhlIEV1cm9wZWFuIGNvdW50cmllc0hvd2V2ZXIsIHRoZXJlIGFyZXNyYz0iaHR0cDovL3N0YXRpY3N1Z2dlc3RlZCB0aGF0IHRoZSIgc3JjPSJodHRwOi8vd3d3LmEgbGFyZ2UgbnVtYmVyIG9mIFRlbGVjb21tdW5pY2F0aW9ucyIgcmVsPSJub2ZvbGxvdyIgdEhvbHkgUm9tYW4gRW1wZXJvcmFsbW9zdCBleGNsdXNpdmVseSIgYm9yZGVyPSIwIiBhbHQ9IlNlY3JldGFyeSBvZiBTdGF0ZWN1bG1pbmF0aW5nIGluIHRoZUNJQSBXb3JsZCBGYWN0Ym9va3RoZSBtb3N0IGltcG9ydGFudGFubml2ZXJzYXJ5IG9mIHRoZXN0eWxlPSJiYWNrZ3JvdW5kLTxsaT48ZW0+PGEgaHJlZj0iL3RoZSBBdGxhbnRpYyBPY2VhbnN0cmljdGx5IHNwZWFraW5nLHNob3J0bHkgYmVmb3JlIHRoZWRpZmZlcmVudCB0eXBlcyBvZnRoZSBPdHRvbWFuIEVtcGlyZT48aW1nIHNyYz0iaHR0cDovL0FuIEludHJvZHVjdGlvbiB0b2NvbnNlcXVlbmNlIG9mIHRoZWRlcGFydHVyZSBmcm9tIHRoZUNvbmZlZGVyYXRlIFN0YXRlc2luZGlnZW5vdXMgcGVvcGxlc1Byb2NlZWRpbmdzIG9mIHRoZWluZm9ybWF0aW9uIG9uIHRoZXRoZW9yaWVzIGhhdmUgYmVlbmludm9sdmVtZW50IGluIHRoZWRpdmlkZWQgaW50byB0aHJlZWFkamFjZW50IGNvdW50cmllc2lzIHJlc3BvbnNpYmxlIGZvcmRpc3NvbHV0aW9uIG9mIHRoZWNvbGxhYm9yYXRpb24gd2l0aHdpZGVseSByZWdhcmRlZCBhc2hpcyBjb250ZW1wb3Jhcmllc2ZvdW5kaW5nIG1lbWJlciBvZkRvbWluaWNhbiBSZXB1YmxpY2dlbmVyYWxseSBhY2NlcHRlZHRoZSBwb3NzaWJpbGl0eSBvZmFyZSBhbHNvIGF2YWlsYWJsZXVuZGVyIGNvbnN0cnVjdGlvbnJlc3RvcmF0aW9uIG9mIHRoZXRoZSBnZW5lcmFsIHB1YmxpY2lzIGFsbW9zdCBlbnRpcmVseXBhc3NlcyB0aHJvdWdoIHRoZWhhcyBiZWVuIHN1Z2dlc3RlZGNvbXB1dGVyIGFuZCB2aWRlb0dlcm1hbmljIGxhbmd1YWdlcyBhY2NvcmRpbmcgdG8gdGhlIGRpZmZlcmVudCBmcm9tIHRoZXNob3J0bHkgYWZ0ZXJ3YXJkc2hyZWY9Imh0dHBzOi8vd3d3LnJlY2VudCBkZXZlbG9wbWVudEJvYXJkIG9mIERpcmVjdG9yczxkaXYgY2xhc3M9InNlYXJjaHwgPGEgaHJlZj0iaHR0cDovL0luIHBhcnRpY3VsYXIsIHRoZU11bHRpcGxlIGZvb3Rub3Rlc29yIG90aGVyIHN1YnN0YW5jZXRob3VzYW5kcyBvZiB5ZWFyc3RyYW5zbGF0aW9uIG9mIHRoZTwvZGl2Pg0KPC9kaXY+DQoNCjxhIGhyZWY9ImluZGV4LnBocHdhcyBlc3RhYmxpc2hlZCBpbm1pbi5qcyI+PC9zY3JpcHQ+CnBhcnRpY2lwYXRlIGluIHRoZWEgc3Ryb25nIGluZmx1ZW5jZXN0eWxlPSJtYXJnaW4tdG9wOnJlcHJlc2VudGVkIGJ5IHRoZWdyYWR1YXRlZCBmcm9tIHRoZVRyYWRpdGlvbmFsbHksIHRoZUVsZW1lbnQoInNjcmlwdCIpO0hvd2V2ZXIsIHNpbmNlIHRoZS9kaXY+CjwvZGl2Pgo8ZGl2IGxlZnQ7IG1hcmdpbi1sZWZ0OnByb3RlY3Rpb24gYWdhaW5zdDA7IHZlcnRpY2FsLWFsaWduOlVuZm9ydHVuYXRlbHksIHRoZXR5cGU9ImltYWdlL3gtaWNvbi9kaXY+CjxkaXYgY2xhc3M9IiBjbGFzcz0iY2xlYXJmaXgiPjxkaXYgY2xhc3M9ImZvb3RlcgkJPC9kaXY+CgkJPC9kaXY+CnRoZSBtb3Rpb24gcGljdHVyZdCR0YrQu9Cz0LDRgNGB0LrQuNCx0YrQu9Cz0LDRgNGB0LrQuNCk0LXQtNC10YDQsNGG0LjQuNC90LXRgdC60L7Qu9GM0LrQvtGB0L7QvtCx0YnQtdC90LjQtdGB0L7QvtCx0YnQtdC90LjRj9C/0YDQvtCz0YDQsNC80LzRi9Ce0YLQv9GA0LDQstC40YLRjNCx0LXRgdC/0LvQsNGC0L3QvtC80LDRgtC10YDQuNCw0LvRi9C/0L7Qt9Cy0L7Qu9GP0LXRgtC/0L7RgdC70LXQtNC90LjQtdGA0LDQt9C70LjRh9C90YvRhdC/0YDQvtC00YPQutGG0LjQuNC/0YDQvtCz0YDQsNC80LzQsNC/0L7Qu9C90L7RgdGC0YzRjtC90LDRhdC+0LTQuNGC0YHRj9C40LfQsdGA0LDQvdC90L7QtdC90LDRgdC10LvQtdC90LjRj9C40LfQvNC10L3QtdC90LjRj9C60LDRgtC10LPQvtGA0LjQuNCQ0LvQtdC60YHQsNC90LTRgOCkpuCljeCkteCkvuCksOCkvuCkruCliOCkqOClgeCkheCksuCkquCljeCksOCkpuCkvuCkqOCkreCkvuCksOCkpOClgOCkr+CkheCkqOClgeCkpuClh+CktuCkueCkv+CkqOCljeCkpuClgOCkh+CkguCkoeCkv+Ckr+CkvuCkpuCkv+CksuCljeCksuClgOCkheCkp+Ckv+CkleCkvuCksOCkteClgOCkoeCkv+Ckr+Cli+CkmuCkv+Ckn+CljeCkoOClh+CkuOCkruCkvuCkmuCkvuCksOCknOCkguCkleCljeCktuCkqOCkpuClgeCkqOCkv+Ckr+CkvuCkquCljeCksOCkr+Cli+Ckl+CkheCkqOClgeCkuOCkvuCksOCkkeCkqOCksuCkvuCkh+CkqOCkquCkvuCksOCljeCkn+ClgOCktuCksOCljeCkpOCli+CkguCksuCli+CkleCkuOCkreCkvuCkq+CkvOCljeCksuCliOCktuCktuCksOCljeCkpOClh+CkguCkquCljeCksOCkpuClh+CktuCkquCljeCksuClh+Ckr+CksOCkleClh+CkguCkpuCljeCksOCkuOCljeCkpeCkv+CkpOCkv+CkieCkpOCljeCkquCkvuCkpuCkieCkqOCljeCkueClh+CkguCkmuCkv+Ckn+CljeCkoOCkvuCkr+CkvuCkpOCljeCksOCkvuCknOCljeCkr+CkvuCkpuCkvuCkquClgeCksOCkvuCkqOClh+CknOCli+CkoeCkvOClh+CkguCkheCkqOClgeCkteCkvuCkpuCktuCljeCksOClh+Cko+ClgOCktuCkv+CkleCljeCkt+CkvuCkuOCksOCkleCkvuCksOClgOCkuOCkguCkl+CljeCksOCkueCkquCksOCkv+Cko+CkvuCkruCkrOCljeCksOCkvuCkguCkoeCkrOCkmuCljeCkmuCli+CkguCkieCkquCksuCkrOCljeCkp+CkruCkguCkpOCljeCksOClgOCkuOCkguCkquCksOCljeCkleCkieCkruCljeCkruClgOCkpuCkruCkvuCkp+CljeCkr+CkruCkuOCkueCkvuCkr+CkpOCkvuCktuCkrOCljeCkpuCli+CkguCkruClgOCkoeCkv+Ckr+CkvuCkhuCkiOCkquClgOCkj+CksuCkruCli+CkrOCkvuCkh+CksuCkuOCkguCkluCljeCkr+CkvuCkhuCkquCksOClh+CktuCkqOCkheCkqOClgeCkrOCkguCkp+CkrOCkvuCknOCkvOCkvuCksOCkqOCkteClgOCkqOCkpOCkruCkquCljeCksOCkruClgeCkluCkquCljeCksOCktuCljeCkqOCkquCksOCkv+CkteCkvuCksOCkqOClgeCkleCkuOCkvuCkqOCkuOCkruCksOCljeCkpeCkqOCkhuCkr+Cli+CknOCkv+CkpOCkuOCli+CkruCkteCkvuCksNin2YTZhdi02KfYsdmD2KfYqtin2YTZhdmG2KrYr9mK2KfYqtin2YTZg9mF2KjZitmI2KrYsdin2YTZhdi02KfZh9iv2KfYqti52K/Yr9in2YTYstmI2KfYsdi52K/Yr9in2YTYsdiv2YjYr9in2YTYpdiz2YTYp9mF2YrYqdin2YTZgdmI2KrZiNi02YjYqNin2YTZhdiz2KfYqNmC2KfYqtin2YTZhdi52YTZiNmF2KfYqtin2YTZhdiz2YTYs9mE2KfYqtin2YTYrNix2KfZgdmK2YPYs9in2YTYp9iz2YTYp9mF2YrYqdin2YTYp9iq2LXYp9mE2KfYqmtleXdvcmRzIiBjb250ZW50PSJ3My5vcmcvMTk5OS94aHRtbCI+PGEgdGFyZ2V0PSJfYmxhbmsiIHRleHQvaHRtbDsgY2hhcnNldD0iIHRhcmdldD0iX2JsYW5rIj48dGFibGUgY2VsbHBhZGRpbmc9ImF1dG9jb21wbGV0ZT0ib2ZmIiB0ZXh0LWFsaWduOiBjZW50ZXI7dG8gbGFzdCB2ZXJzaW9uIGJ5IGJhY2tncm91bmQtY29sb3I6ICMiIGhyZWY9Imh0dHA6Ly93d3cuL2Rpdj48L2Rpdj48ZGl2IGlkPTxhIGhyZWY9IiMiIGNsYXNzPSIiPjxpbWcgc3JjPSJodHRwOi8vY3JpcHQiIHNyYz0iaHR0cDovLwo8c2NyaXB0IGxhbmd1YWdlPSIvL0VOIiAiaHR0cDovL3d3dy53ZW5jb2RlVVJJQ29tcG9uZW50KCIgaHJlZj0iamF2YXNjcmlwdDo8ZGl2IGNsYXNzPSJjb250ZW50ZG9jdW1lbnQud3JpdGUoJzxzY3Bvc2l0aW9uOiBhYnNvbHV0ZTtzY3JpcHQgc3JjPSJodHRwOi8vIHN0eWxlPSJtYXJnaW4tdG9wOi5taW4uanMiPjwvc2NyaXB0Pgo8L2Rpdj4KPGRpdiBjbGFzcz0idzMub3JnLzE5OTkveGh0bWwiIAoNCjwvYm9keT4NCjwvaHRtbD5kaXN0aW5jdGlvbiBiZXR3ZWVuLyIgdGFyZ2V0PSJfYmxhbmsiPjxsaW5rIGhyZWY9Imh0dHA6Ly9lbmNvZGluZz0idXRmLTgiPz4Kdy5hZGRFdmVudExpc3RlbmVyP2FjdGlvbj0iaHR0cDovL3d3dy5pY29uIiBocmVmPSJodHRwOi8vIHN0eWxlPSJiYWNrZ3JvdW5kOnR5cGU9InRleHQvY3NzIiAvPgptZXRhIHByb3BlcnR5PSJvZzp0PGlucHV0IHR5cGU9InRleHQiICBzdHlsZT0idGV4dC1hbGlnbjp0aGUgZGV2ZWxvcG1lbnQgb2YgdHlsZXNoZWV0IiB0eXBlPSJ0ZWh0bWw7IGNoYXJzZXQ9dXRmLThpcyBjb25zaWRlcmVkIHRvIGJldGFibGUgd2lkdGg9IjEwMCUiIEluIGFkZGl0aW9uIHRvIHRoZSBjb250cmlidXRlZCB0byB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbmRldmVsb3BtZW50IG9mIHRoZSBJdCBpcyBpbXBvcnRhbnQgdG8gPC9zY3JpcHQ+Cgo8c2NyaXB0ICBzdHlsZT0iZm9udC1zaXplOjE+PC9zcGFuPjxzcGFuIGlkPWdiTGlicmFyeSBvZiBDb25ncmVzczxpbWcgc3JjPSJodHRwOi8vaW1FbmdsaXNoIHRyYW5zbGF0aW9uQWNhZGVteSBvZiBTY2llbmNlc2RpdiBzdHlsZT0iZGlzcGxheTpjb25zdHJ1Y3Rpb24gb2YgdGhlLmdldEVsZW1lbnRCeUlkKGlkKWluIGNvbmp1bmN0aW9uIHdpdGhFbGVtZW50KCdzY3JpcHQnKTsgPG1ldGEgcHJvcGVydHk9Im9nOtCR0YrQu9Cz0LDRgNGB0LrQuAogdHlwZT0idGV4dCIgbmFtZT0iPlByaXZhY3kgUG9saWN5PC9hPmFkbWluaXN0ZXJlZCBieSB0aGVlbmFibGVTaW5nbGVSZXF1ZXN0c3R5bGU9JnF1b3Q7bWFyZ2luOjwvZGl2PjwvZGl2PjwvZGl2Pjw+PGltZyBzcmM9Imh0dHA6Ly9pIHN0eWxlPSZxdW90O2Zsb2F0OnJlZmVycmVkIHRvIGFzIHRoZSB0b3RhbCBwb3B1bGF0aW9uIG9maW4gV2FzaGluZ3RvbiwgRC5DLiBzdHlsZT0iYmFja2dyb3VuZC1hbW9uZyBvdGhlciB0aGluZ3Msb3JnYW5pemF0aW9uIG9mIHRoZXBhcnRpY2lwYXRlZCBpbiB0aGV0aGUgaW50cm9kdWN0aW9uIG9maWRlbnRpZmllZCB3aXRoIHRoZWZpY3Rpb25hbCBjaGFyYWN0ZXIgT3hmb3JkIFVuaXZlcnNpdHkgbWlzdW5kZXJzdGFuZGluZyBvZlRoZXJlIGFyZSwgaG93ZXZlcixzdHlsZXNoZWV0IiBocmVmPSIvQ29sdW1iaWEgVW5pdmVyc2l0eWV4cGFuZGVkIHRvIGluY2x1ZGV1c3VhbGx5IHJlZmVycmVkIHRvaW5kaWNhdGluZyB0aGF0IHRoZWhhdmUgc3VnZ2VzdGVkIHRoYXRhZmZpbGlhdGVkIHdpdGggdGhlY29ycmVsYXRpb24gYmV0d2Vlbm51bWJlciBvZiBkaWZmZXJlbnQ+PC90ZD48L3RyPjwvdGFibGU+UmVwdWJsaWMgb2YgSXJlbGFuZAo8L3NjcmlwdD4KPHNjcmlwdCB1bmRlciB0aGUgaW5mbHVlbmNlY29udHJpYnV0aW9uIHRvIHRoZU9mZmljaWFsIHdlYnNpdGUgb2ZoZWFkcXVhcnRlcnMgb2YgdGhlY2VudGVyZWQgYXJvdW5kIHRoZWltcGxpY2F0aW9ucyBvZiB0aGVoYXZlIGJlZW4gZGV2ZWxvcGVkRmVkZXJhbCBSZXB1YmxpYyBvZmJlY2FtZSBpbmNyZWFzaW5nbHljb250aW51YXRpb24gb2YgdGhlTm90ZSwgaG93ZXZlciwgdGhhdHNpbWlsYXIgdG8gdGhhdCBvZiBjYXBhYmlsaXRpZXMgb2YgdGhlYWNjb3JkYW5jZSB3aXRoIHRoZXBhcnRpY2lwYW50cyBpbiB0aGVmdXJ0aGVyIGRldmVsb3BtZW50dW5kZXIgdGhlIGRpcmVjdGlvbmlzIG9mdGVuIGNvbnNpZGVyZWRoaXMgeW91bmdlciBicm90aGVyPC90ZD48L3RyPjwvdGFibGU+PGEgaHR0cC1lcXVpdj0iWC1VQS1waHlzaWNhbCBwcm9wZXJ0aWVzb2YgQnJpdGlzaCBDb2x1bWJpYWhhcyBiZWVuIGNyaXRpY2l6ZWQod2l0aCB0aGUgZXhjZXB0aW9ucXVlc3Rpb25zIGFib3V0IHRoZXBhc3NpbmcgdGhyb3VnaCB0aGUwIiBjZWxscGFkZGluZz0iMCIgdGhvdXNhbmRzIG9mIHBlb3BsZXJlZGlyZWN0cyBoZXJlLiBGb3JoYXZlIGNoaWxkcmVuIHVuZGVyJTNFJTNDL3NjcmlwdCUzRSIpKTs8YSBocmVmPSJodHRwOi8vd3d3LjxsaT48YSBocmVmPSJodHRwOi8vc2l0ZV9uYW1lIiBjb250ZW50PSJ0ZXh0LWRlY29yYXRpb246bm9uZXN0eWxlPSJkaXNwbGF5OiBub25lPG1ldGEgaHR0cC1lcXVpdj0iWC1uZXcgRGF0ZSgpLmdldFRpbWUoKSB0eXBlPSJpbWFnZS94LWljb24iPC9zcGFuPjxzcGFuIGNsYXNzPSJsYW5ndWFnZT0iamF2YXNjcmlwdHdpbmRvdy5sb2NhdGlvbi5ocmVmPGEgaHJlZj0iamF2YXNjcmlwdDotLT4NCjxzY3JpcHQgdHlwZT0idDxhIGhyZWY9J2h0dHA6Ly93d3cuaG9ydGN1dCBpY29uIiBocmVmPSI8L2Rpdj4NCjxkaXYgY2xhc3M9IjxzY3JpcHQgc3JjPSJodHRwOi8vIiByZWw9InN0eWxlc2hlZXQiIHQ8L2Rpdj4KPHNjcmlwdCB0eXBlPS9hPiA8YSBocmVmPSJodHRwOi8vIGFsbG93VHJhbnNwYXJlbmN5PSJYLVVBLUNvbXBhdGlibGUiIGNvbnJlbGF0aW9uc2hpcCBiZXR3ZWVuCjwvc2NyaXB0Pg0KPHNjcmlwdCA8L2E+PC9saT48L3VsPjwvZGl2PmFzc29jaWF0ZWQgd2l0aCB0aGUgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2U8L2E+PGEgaHJlZj0iaHR0cDovLzwvYT48L2xpPjxsaSBjbGFzcz0iZm9ybSBhY3Rpb249Imh0dHA6Ly88ZGl2IHN0eWxlPSJkaXNwbGF5OnR5cGU9InRleHQiIG5hbWU9InEiPHRhYmxlIHdpZHRoPSIxMDAlIiBiYWNrZ3JvdW5kLXBvc2l0aW9uOiIgYm9yZGVyPSIwIiB3aWR0aD0icmVsPSJzaG9ydGN1dCBpY29uIiBoNj48dWw+PGxpPjxhIGhyZWY9IiAgPG1ldGEgaHR0cC1lcXVpdj0iY3NzIiBtZWRpYT0ic2NyZWVuIiByZXNwb25zaWJsZSBmb3IgdGhlICIgdHlwZT0iYXBwbGljYXRpb24vIiBzdHlsZT0iYmFja2dyb3VuZC1odG1sOyBjaGFyc2V0PXV0Zi04IiBhbGxvd3RyYW5zcGFyZW5jeT0ic3R5bGVzaGVldCIgdHlwZT0idGUNCjxtZXRhIGh0dHAtZXF1aXY9Ij48L3NwYW4+PHNwYW4gY2xhc3M9IjAiIGNlbGxzcGFjaW5nPSIwIj47Cjwvc2NyaXB0Pgo8c2NyaXB0IHNvbWV0aW1lcyBjYWxsZWQgdGhlZG9lcyBub3QgbmVjZXNzYXJpbHlGb3IgbW9yZSBpbmZvcm1hdGlvbmF0IHRoZSBiZWdpbm5pbmcgb2YgPCFET0NUWVBFIGh0bWw+PGh0bWxwYXJ0aWN1bGFybHkgaW4gdGhlIHR5cGU9ImhpZGRlbiIgbmFtZT0iamF2YXNjcmlwdDp2b2lkKDApOyJlZmZlY3RpdmVuZXNzIG9mIHRoZSBhdXRvY29tcGxldGU9Im9mZiIgZ2VuZXJhbGx5IGNvbnNpZGVyZWQ+PGlucHV0IHR5cGU9InRleHQiICI+PC9zY3JpcHQ+DQo8c2NyaXB0dGhyb3VnaG91dCB0aGUgd29ybGRjb21tb24gbWlzY29uY2VwdGlvbmFzc29jaWF0aW9uIHdpdGggdGhlPC9kaXY+CjwvZGl2Pgo8ZGl2IGNkdXJpbmcgaGlzIGxpZmV0aW1lLGNvcnJlc3BvbmRpbmcgdG8gdGhldHlwZT0iaW1hZ2UveC1pY29uIiBhbiBpbmNyZWFzaW5nIG51bWJlcmRpcGxvbWF0aWMgcmVsYXRpb25zYXJlIG9mdGVuIGNvbnNpZGVyZWRtZXRhIGNoYXJzZXQ9InV0Zi04IiA8aW5wdXQgdHlwZT0idGV4dCIgZXhhbXBsZXMgaW5jbHVkZSB0aGUiPjxpbWcgc3JjPSJodHRwOi8vaXBhcnRpY2lwYXRpb24gaW4gdGhldGhlIGVzdGFibGlzaG1lbnQgb2YKPC9kaXY+CjxkaXYgY2xhc3M9IiZhbXA7bmJzcDsmYW1wO25ic3A7dG8gZGV0ZXJtaW5lIHdoZXRoZXJxdWl0ZSBkaWZmZXJlbnQgZnJvbW1hcmtlZCB0aGUgYmVnaW5uaW5nZGlzdGFuY2UgYmV0d2VlbiB0aGVjb250cmlidXRpb25zIHRvIHRoZWNvbmZsaWN0IGJldHdlZW4gdGhld2lkZWx5IGNvbnNpZGVyZWQgdG93YXMgb25lIG9mIHRoZSBmaXJzdHdpdGggdmFyeWluZyBkZWdyZWVzaGF2ZSBzcGVjdWxhdGVkIHRoYXQoZG9jdW1lbnQuZ2V0RWxlbWVudHBhcnRpY2lwYXRpbmcgaW4gdGhlb3JpZ2luYWxseSBkZXZlbG9wZWRldGEgY2hhcnNldD0idXRmLTgiPiB0eXBlPSJ0ZXh0L2NzcyIgLz4KaW50ZXJjaGFuZ2VhYmx5IHdpdGhtb3JlIGNsb3NlbHkgcmVsYXRlZHNvY2lhbCBhbmQgcG9saXRpY2FsdGhhdCB3b3VsZCBvdGhlcndpc2VwZXJwZW5kaWN1bGFyIHRvIHRoZXN0eWxlIHR5cGU9InRleHQvY3NzdHlwZT0ic3VibWl0IiBuYW1lPSJmYW1pbGllcyByZXNpZGluZyBpbmRldmVsb3BpbmcgY291bnRyaWVzY29tcHV0ZXIgcHJvZ3JhbW1pbmdlY29ub21pYyBkZXZlbG9wbWVudGRldGVybWluYXRpb24gb2YgdGhlZm9yIG1vcmUgaW5mb3JtYXRpb25vbiBzZXZlcmFsIG9jY2FzaW9uc3BvcnR1Z3XDqnMgKEV1cm9wZXUp0KPQutGA0LDRl9C90YHRjNC60LDRg9C60YDQsNGX0L3RgdGM0LrQsNCg0L7RgdGB0LjQudGB0LrQvtC50LzQsNGC0LXRgNC40LDQu9C+0LLQuNC90YTQvtGA0LzQsNGG0LjQuNGD0L/RgNCw0LLQu9C10L3QuNGP0L3QtdC+0LHRhdC+0LTQuNC80L7QuNC90YTQvtGA0LzQsNGG0LjRj9CY0L3RhNC+0YDQvNCw0YbQuNGP0KDQtdGB0L/Rg9Cx0LvQuNC60LjQutC+0LvQuNGH0LXRgdGC0LLQvtC40L3RhNC+0YDQvNCw0YbQuNGO0YLQtdGA0YDQuNGC0L7RgNC40LjQtNC+0YHRgtCw0YLQvtGH0L3Qvtin2YTZhdiq2YjYp9is2K/ZiNmG2KfZhNin2LTYqtix2KfZg9in2KrYp9mE2KfZgtiq2LHYp9it2KfYqmh0bWw7IGNoYXJzZXQ9VVRGLTgiIHNldFRpbWVvdXQoZnVuY3Rpb24oKWRpc3BsYXk6aW5saW5lLWJsb2NrOzxpbnB1dCB0eXBlPSJzdWJtaXQiIHR5cGUgPSAndGV4dC9qYXZhc2NyaTxpbWcgc3JjPSJodHRwOi8vd3d3LiIgImh0dHA6Ly93d3cudzMub3JnL3Nob3J0Y3V0IGljb24iIGhyZWY9IiIgYXV0b2NvbXBsZXRlPSJvZmYiIDwvYT48L2Rpdj48ZGl2IGNsYXNzPTwvYT48L2xpPgo8bGkgY2xhc3M9ImNzcyIgdHlwZT0idGV4dC9jc3MiIDxmb3JtIGFjdGlvbj0iaHR0cDovL3h0L2NzcyIgaHJlZj0iaHR0cDovL2xpbmsgcmVsPSJhbHRlcm5hdGUiIA0KPHNjcmlwdCB0eXBlPSJ0ZXh0LyBvbmNsaWNrPSJqYXZhc2NyaXB0OihuZXcgRGF0ZSkuZ2V0VGltZSgpfWhlaWdodD0iMSIgd2lkdGg9IjEiIFBlb3BsZSdzIFJlcHVibGljIG9mICA8YSBocmVmPSJodHRwOi8vd3d3LnRleHQtZGVjb3JhdGlvbjp1bmRlcnRoZSBiZWdpbm5pbmcgb2YgdGhlIDwvZGl2Pgo8L2Rpdj4KPC9kaXY+CmVzdGFibGlzaG1lbnQgb2YgdGhlIDwvZGl2PjwvZGl2PjwvZGl2PjwvZCN2aWV3cG9ydHttaW4taGVpZ2h0Ogo8c2NyaXB0IHNyYz0iaHR0cDovL29wdGlvbj48b3B0aW9uIHZhbHVlPW9mdGVuIHJlZmVycmVkIHRvIGFzIC9vcHRpb24+CjxvcHRpb24gdmFsdTwhRE9DVFlQRSBodG1sPgo8IS0tW0ludGVybmF0aW9uYWwgQWlycG9ydD4KPGEgaHJlZj0iaHR0cDovL3d3dzwvYT48YSBocmVmPSJodHRwOi8vd+C4oOC4suC4qeC4suC5hOC4l+C4ouGDpeGDkOGDoOGDl+GDo+GDmuGDmOato+mrlOS4reaWhyAo57mB6auUKeCkqOCkv+CksOCljeCkpuClh+CktuCkoeCkvuCkieCkqOCksuCli+CkoeCkleCljeCkt+Clh+CkpOCljeCksOCknOCkvuCkqOCkleCkvuCksOClgOCkuOCkguCkrOCkguCkp+Ckv+CkpOCkuOCljeCkpeCkvuCkquCkqOCkvuCkuOCljeCkteClgOCkleCkvuCksOCkuOCkguCkuOCljeCkleCksOCko+CkuOCkvuCkruCkl+CljeCksOClgOCkmuCkv+Ckn+CljeCkoOCli+CkguCkteCkv+CknOCljeCknuCkvuCkqOCkheCkruClh+CksOCkv+CkleCkvuCkteCkv+CkreCkv+CkqOCljeCkqOCkl+CkvuCkoeCkv+Ckr+CkvuCkgeCkleCljeCkr+Cli+CkguCkleCkv+CkuOClgeCksOCkleCljeCkt+CkvuCkquCkueClgeCkgeCkmuCkpOClgOCkquCljeCksOCkrOCkguCkp+CkqOCkn+Ckv+CkquCljeCkquCko+ClgOCkleCljeCksOCkv+CkleClh+Ckn+CkquCljeCksOCkvuCksOCkguCkreCkquCljeCksOCkvuCkquCljeCkpOCkruCkvuCksuCkv+CkleCli+CkguCksOCkq+CkvOCljeCkpOCkvuCksOCkqOCkv+CksOCljeCkruCkvuCko+CksuCkv+CkruCkv+Ckn+Clh+CkoWRlc2NyaXB0aW9uIiBjb250ZW50PSJkb2N1bWVudC5sb2NhdGlvbi5wcm90LmdldEVsZW1lbnRzQnlUYWdOYW1lKDwhRE9DVFlQRSBodG1sPgo8aHRtbCA8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+OnVybCIgY29udGVudD0iaHR0cDovLy5jc3MiIHJlbD0ic3R5bGVzaGVldCJzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+dHlwZT0idGV4dC9jc3MiIGhyZWY9InczLm9yZy8xOTk5L3hodG1sIiB4bWx0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiIG1ldGhvZD0iZ2V0IiBhY3Rpb249ImxpbmsgcmVsPSJzdHlsZXNoZWV0IiAgPSBkb2N1bWVudC5nZXRFbGVtZW50dHlwZT0iaW1hZ2UveC1pY29uIiAvPmNlbGxwYWRkaW5nPSIwIiBjZWxsc3AuY3NzIiB0eXBlPSJ0ZXh0L2NzcyIgPC9hPjwvbGk+PGxpPjxhIGhyZWY9IiIgd2lkdGg9IjEiIGhlaWdodD0iMSIiPjxhIGhyZWY9Imh0dHA6Ly93d3cuc3R5bGU9ImRpc3BsYXk6bm9uZTsiPmFsdGVybmF0ZSIgdHlwZT0iYXBwbGktLy9XM0MvL0RURCBYSFRNTCAxLjAgZWxsc3BhY2luZz0iMCIgY2VsbHBhZCB0eXBlPSJoaWRkZW4iIHZhbHVlPSIvYT4mbmJzcDs8c3BhbiByb2xlPSJzCjxpbnB1dCB0eXBlPSJoaWRkZW4iIGxhbmd1YWdlPSJKYXZhU2NyaXB0IiAgZG9jdW1lbnQuZ2V0RWxlbWVudHNCZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHlwZT0idGV4dC9jc3MiIG1lZGlhPSJ0eXBlPSd0ZXh0L2phdmFzY3JpcHQnd2l0aCB0aGUgZXhjZXB0aW9uIG9mIHlwZT0idGV4dC9jc3MiIHJlbD0ic3QgaGVpZ2h0PSIxIiB3aWR0aD0iMSIgPScrZW5jb2RlVVJJQ29tcG9uZW50KDxsaW5rIHJlbD0iYWx0ZXJuYXRlIiAKYm9keSwgdHIsIGlucHV0LCB0ZXh0bWV0YSBuYW1lPSJyb2JvdHMiIGNvbm1ldGhvZD0icG9zdCIgYWN0aW9uPSI+CjxhIGhyZWY9Imh0dHA6Ly93d3cuY3NzIiByZWw9InN0eWxlc2hlZXQiIDwvZGl2PjwvZGl2PjxkaXYgY2xhc3NsYW5ndWFnZT0iamF2YXNjcmlwdCI+YXJpYS1oaWRkZW49InRydWUiPsK3PHJpcHQiIHR5cGU9InRleHQvamF2YXNsPTA7fSkoKTsKKGZ1bmN0aW9uKCl7YmFja2dyb3VuZC1pbWFnZTogdXJsKC9hPjwvbGk+PGxpPjxhIGhyZWY9ImgJCTxsaT48YSBocmVmPSJodHRwOi8vYXRvciIgYXJpYS1oaWRkZW49InRydT4gPGEgaHJlZj0iaHR0cDovL3d3dy5sYW5ndWFnZT0iamF2YXNjcmlwdCIgL29wdGlvbj4KPG9wdGlvbiB2YWx1ZS9kaXY+PC9kaXY+PGRpdiBjbGFzcz1yYXRvciIgYXJpYS1oaWRkZW49InRyZT0obmV3IERhdGUpLmdldFRpbWUoKXBvcnR1Z3XDqnMgKGRvIEJyYXNpbCnQvtGA0LPQsNC90LjQt9Cw0YbQuNC40LLQvtC30LzQvtC20L3QvtGB0YLRjNC+0LHRgNCw0LfQvtCy0LDQvdC40Y/RgNC10LPQuNGB0YLRgNCw0YbQuNC40LLQvtC30LzQvtC20L3QvtGB0YLQuNC+0LHRj9C30LDRgtC10LvRjNC90LA8IURPQ1RZUEUgaHRtbCBQVUJMSUMgIm50LVR5cGUiIGNvbnRlbnQ9InRleHQvPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVyYW5zaXRpb25hbC8vRU4iICJodHRwOjxodG1sIHhtbG5zPSJodHRwOi8vd3d3LS8vVzNDLy9EVEQgWEhUTUwgMS4wIFREVEQveGh0bWwxLXRyYW5zaXRpb25hbC8vd3d3LnczLm9yZy9UUi94aHRtbDEvcGUgPSAndGV4dC9qYXZhc2NyaXB0Jzs8bWV0YSBuYW1lPSJkZXNjcmlwdGlvbnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlPGlucHV0IHR5cGU9ImhpZGRlbiIgbmFqcyIgdHlwZT0idGV4dC9qYXZhc2NyaShkb2N1bWVudCkucmVhZHkoZnVuY3Rpc2NyaXB0IHR5cGU9InRleHQvamF2YXNpbWFnZSIgY29udGVudD0iaHR0cDovL1VBLUNvbXBhdGlibGUiIGNvbnRlbnQ9dG1sOyBjaGFyc2V0PXV0Zi04IiAvPgpsaW5rIHJlbD0ic2hvcnRjdXQgaWNvbjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgPC9zY3JpcHQ+CjxzY3JpcHQgdHlwZT09IGRvY3VtZW50LmNyZWF0ZUVsZW1lbjxhIHRhcmdldD0iX2JsYW5rIiBocmVmPSBkb2N1bWVudC5nZXRFbGVtZW50c0JpbnB1dCB0eXBlPSJ0ZXh0IiBuYW1lPWEudHlwZSA9ICd0ZXh0L2phdmFzY3JpbnB1dCB0eXBlPSJoaWRkZW4iIG5hbWVodG1sOyBjaGFyc2V0PXV0Zi04IiAvPmR0ZCI+CjxodG1sIHhtbG5zPSJodHRwLS8vVzNDLy9EVEQgSFRNTCA0LjAxIFRlbnRzQnlUYWdOYW1lKCdzY3JpcHQnKWlucHV0IHR5cGU9ImhpZGRlbiIgbmFtPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzIiBzdHlsZT0iZGlzcGxheTpub25lOyI+ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJyB0eXBlPSd0ZXh0L2phdmFzY3JpcHQnaW5wdXQgdHlwZT0idGV4dCIgbmFtZT0iZC5nZXRFbGVtZW50c0J5VGFnTmFtZShzbmljYWwiIGhyZWY9Imh0dHA6Ly93d3cuQy8vRFREIEhUTUwgNC4wMSBUcmFuc2l0PHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+aW9uYWwuZHRkIj4KPGh0bWwgeG1sbnM9aHR0cC1lcXVpdj0iQ29udGVudC1UeXBlZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KIHN0eWxlPSJkaXNwbGF5Om5vbmU7Ij48PGxpPjxhIGhyZWY9Imh0dHA6Ly93d3cuIHR5cGU9J3RleHQvamF2YXNjcmlwdCc+0LTQtdGP0YLQtdC70YzQvdC+0YHRgtC40YHQvtC+0YLQstC10YLRgdGC0LLQuNC40L/RgNC+0LjQt9Cy0L7QtNGB0YLQstCw0LHQtdC30L7Qv9Cw0YHQvdC+0YHRgtC44KSq4KWB4KS44KWN4KSk4KS/4KSV4KS+4KSV4KS+4KSC4KSX4KWN4KSw4KWH4KS44KSJ4KSo4KWN4KS54KWL4KSC4KSo4KWH4KS14KS/4KSn4KS+4KSo4KS44KSt4KS+4KSr4KS/4KSV4KWN4KS44KS/4KSC4KSX4KS44KWB4KSw4KSV4KWN4KS34KS/4KSk4KSV4KWJ4KSq4KWA4KSw4KS+4KSH4KSf4KS14KS/4KSc4KWN4KSe4KS+4KSq4KSo4KSV4KS+4KSw4KWN4KSw4KS14KS+4KSI4KS44KSV4KWN4KSw4KS/4KSv4KSk4KS+"); + exports2.init = function() { + return exports2.dictionary; + }; + } +}); + +// node_modules/brotli/dec/dictionary.js +var require_dictionary = __commonJS({ + "node_modules/brotli/dec/dictionary.js"(exports2) { + var data = require_dictionary_data(); + exports2.init = function() { + exports2.dictionary = data.init(); + }; + exports2.offsetsByLength = new Uint32Array([ + 0, + 0, + 0, + 0, + 0, + 4096, + 9216, + 21504, + 35840, + 44032, + 53248, + 63488, + 74752, + 87040, + 93696, + 100864, + 104704, + 106752, + 108928, + 113536, + 115968, + 118528, + 119872, + 121280, + 122016 + ]); + exports2.sizeBitsByLength = new Uint8Array([ + 0, + 0, + 0, + 0, + 10, + 10, + 11, + 11, + 10, + 10, + 10, + 10, + 10, + 9, + 9, + 8, + 7, + 7, + 8, + 7, + 7, + 6, + 6, + 5, + 5 + ]); + exports2.minDictionaryWordLength = 4; + exports2.maxDictionaryWordLength = 24; + } +}); + +// node_modules/brotli/dec/huffman.js +var require_huffman = __commonJS({ + "node_modules/brotli/dec/huffman.js"(exports2) { + function HuffmanCode(bits, value) { + this.bits = bits; + this.value = value; + } + exports2.HuffmanCode = HuffmanCode; + var MAX_LENGTH = 15; + function GetNextKey(key, len) { + var step = 1 << len - 1; + while (key & step) { + step >>= 1; + } + return (key & step - 1) + step; + } + function ReplicateValue(table, i, step, end, code) { + do { + end -= step; + table[i + end] = new HuffmanCode(code.bits, code.value); + } while (end > 0); + } + function NextTableBitSize(count, len, root_bits) { + var left = 1 << len - root_bits; + while (len < MAX_LENGTH) { + left -= count[len]; + if (left <= 0) break; + ++len; + left <<= 1; + } + return len - root_bits; + } + exports2.BrotliBuildHuffmanTable = function(root_table, table, root_bits, code_lengths, code_lengths_size) { + var start_table = table; + var code; + var len; + var symbol; + var key; + var step; + var low; + var mask; + var table_bits; + var table_size; + var total_size; + var sorted; + var count = new Int32Array(MAX_LENGTH + 1); + var offset = new Int32Array(MAX_LENGTH + 1); + sorted = new Int32Array(code_lengths_size); + for (symbol = 0; symbol < code_lengths_size; symbol++) { + count[code_lengths[symbol]]++; + } + offset[1] = 0; + for (len = 1; len < MAX_LENGTH; len++) { + offset[len + 1] = offset[len] + count[len]; + } + for (symbol = 0; symbol < code_lengths_size; symbol++) { + if (code_lengths[symbol] !== 0) { + sorted[offset[code_lengths[symbol]]++] = symbol; + } + } + table_bits = root_bits; + table_size = 1 << table_bits; + total_size = table_size; + if (offset[MAX_LENGTH] === 1) { + for (key = 0; key < total_size; ++key) { + root_table[table + key] = new HuffmanCode(0, sorted[0] & 65535); + } + return total_size; + } + key = 0; + symbol = 0; + for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) { + for (; count[len] > 0; --count[len]) { + code = new HuffmanCode(len & 255, sorted[symbol++] & 65535); + ReplicateValue(root_table, table + key, step, table_size, code); + key = GetNextKey(key, len); + } + } + mask = total_size - 1; + low = -1; + for (len = root_bits + 1, step = 2; len <= MAX_LENGTH; ++len, step <<= 1) { + for (; count[len] > 0; --count[len]) { + if ((key & mask) !== low) { + table += table_size; + table_bits = NextTableBitSize(count, len, root_bits); + table_size = 1 << table_bits; + total_size += table_size; + low = key & mask; + root_table[start_table + low] = new HuffmanCode(table_bits + root_bits & 255, table - start_table - low & 65535); + } + code = new HuffmanCode(len - root_bits & 255, sorted[symbol++] & 65535); + ReplicateValue(root_table, table + (key >> root_bits), step, table_size, code); + key = GetNextKey(key, len); + } + } + return total_size; + }; + } +}); + +// node_modules/brotli/dec/context.js +var require_context = __commonJS({ + "node_modules/brotli/dec/context.js"(exports2) { + exports2.lookup = new Uint8Array([ + /* CONTEXT_UTF8, last byte. */ + /* ASCII range. */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4, + 4, + 0, + 0, + 4, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 8, + 12, + 16, + 12, + 12, + 20, + 12, + 16, + 24, + 28, + 12, + 12, + 32, + 12, + 36, + 12, + 44, + 44, + 44, + 44, + 44, + 44, + 44, + 44, + 44, + 44, + 32, + 32, + 24, + 40, + 28, + 12, + 12, + 48, + 52, + 52, + 52, + 48, + 52, + 52, + 52, + 48, + 52, + 52, + 52, + 52, + 52, + 48, + 52, + 52, + 52, + 52, + 52, + 48, + 52, + 52, + 52, + 52, + 52, + 24, + 12, + 28, + 12, + 12, + 12, + 56, + 60, + 60, + 60, + 56, + 60, + 60, + 60, + 56, + 60, + 60, + 60, + 60, + 60, + 56, + 60, + 60, + 60, + 60, + 60, + 56, + 60, + 60, + 60, + 60, + 60, + 24, + 12, + 28, + 12, + 0, + /* UTF8 continuation byte range. */ + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + /* UTF8 lead byte range. */ + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + 2, + 3, + /* CONTEXT_UTF8 second last byte. */ + /* ASCII range. */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 1, + 1, + 1, + 0, + /* UTF8 continuation byte range. */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* UTF8 lead byte range. */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + /* CONTEXT_SIGNED, second last byte. */ + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 7, + /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */ + 0, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 16, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 40, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 56, + /* CONTEXT_LSB6, last byte. */ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + /* CONTEXT_MSB6, last byte. */ + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 6, + 6, + 6, + 6, + 7, + 7, + 7, + 7, + 8, + 8, + 8, + 8, + 9, + 9, + 9, + 9, + 10, + 10, + 10, + 10, + 11, + 11, + 11, + 11, + 12, + 12, + 12, + 12, + 13, + 13, + 13, + 13, + 14, + 14, + 14, + 14, + 15, + 15, + 15, + 15, + 16, + 16, + 16, + 16, + 17, + 17, + 17, + 17, + 18, + 18, + 18, + 18, + 19, + 19, + 19, + 19, + 20, + 20, + 20, + 20, + 21, + 21, + 21, + 21, + 22, + 22, + 22, + 22, + 23, + 23, + 23, + 23, + 24, + 24, + 24, + 24, + 25, + 25, + 25, + 25, + 26, + 26, + 26, + 26, + 27, + 27, + 27, + 27, + 28, + 28, + 28, + 28, + 29, + 29, + 29, + 29, + 30, + 30, + 30, + 30, + 31, + 31, + 31, + 31, + 32, + 32, + 32, + 32, + 33, + 33, + 33, + 33, + 34, + 34, + 34, + 34, + 35, + 35, + 35, + 35, + 36, + 36, + 36, + 36, + 37, + 37, + 37, + 37, + 38, + 38, + 38, + 38, + 39, + 39, + 39, + 39, + 40, + 40, + 40, + 40, + 41, + 41, + 41, + 41, + 42, + 42, + 42, + 42, + 43, + 43, + 43, + 43, + 44, + 44, + 44, + 44, + 45, + 45, + 45, + 45, + 46, + 46, + 46, + 46, + 47, + 47, + 47, + 47, + 48, + 48, + 48, + 48, + 49, + 49, + 49, + 49, + 50, + 50, + 50, + 50, + 51, + 51, + 51, + 51, + 52, + 52, + 52, + 52, + 53, + 53, + 53, + 53, + 54, + 54, + 54, + 54, + 55, + 55, + 55, + 55, + 56, + 56, + 56, + 56, + 57, + 57, + 57, + 57, + 58, + 58, + 58, + 58, + 59, + 59, + 59, + 59, + 60, + 60, + 60, + 60, + 61, + 61, + 61, + 61, + 62, + 62, + 62, + 62, + 63, + 63, + 63, + 63, + /* CONTEXT_{M,L}SB6, second last byte, */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ]); + exports2.lookupOffsets = new Uint16Array([ + /* CONTEXT_LSB6 */ + 1024, + 1536, + /* CONTEXT_MSB6 */ + 1280, + 1536, + /* CONTEXT_UTF8 */ + 0, + 256, + /* CONTEXT_SIGNED */ + 768, + 512 + ]); + } +}); + +// node_modules/brotli/dec/prefix.js +var require_prefix = __commonJS({ + "node_modules/brotli/dec/prefix.js"(exports2) { + function PrefixCodeRange(offset, nbits) { + this.offset = offset; + this.nbits = nbits; + } + exports2.kBlockLengthPrefixCode = [ + new PrefixCodeRange(1, 2), + new PrefixCodeRange(5, 2), + new PrefixCodeRange(9, 2), + new PrefixCodeRange(13, 2), + new PrefixCodeRange(17, 3), + new PrefixCodeRange(25, 3), + new PrefixCodeRange(33, 3), + new PrefixCodeRange(41, 3), + new PrefixCodeRange(49, 4), + new PrefixCodeRange(65, 4), + new PrefixCodeRange(81, 4), + new PrefixCodeRange(97, 4), + new PrefixCodeRange(113, 5), + new PrefixCodeRange(145, 5), + new PrefixCodeRange(177, 5), + new PrefixCodeRange(209, 5), + new PrefixCodeRange(241, 6), + new PrefixCodeRange(305, 6), + new PrefixCodeRange(369, 7), + new PrefixCodeRange(497, 8), + new PrefixCodeRange(753, 9), + new PrefixCodeRange(1265, 10), + new PrefixCodeRange(2289, 11), + new PrefixCodeRange(4337, 12), + new PrefixCodeRange(8433, 13), + new PrefixCodeRange(16625, 24) + ]; + exports2.kInsertLengthPrefixCode = [ + new PrefixCodeRange(0, 0), + new PrefixCodeRange(1, 0), + new PrefixCodeRange(2, 0), + new PrefixCodeRange(3, 0), + new PrefixCodeRange(4, 0), + new PrefixCodeRange(5, 0), + new PrefixCodeRange(6, 1), + new PrefixCodeRange(8, 1), + new PrefixCodeRange(10, 2), + new PrefixCodeRange(14, 2), + new PrefixCodeRange(18, 3), + new PrefixCodeRange(26, 3), + new PrefixCodeRange(34, 4), + new PrefixCodeRange(50, 4), + new PrefixCodeRange(66, 5), + new PrefixCodeRange(98, 5), + new PrefixCodeRange(130, 6), + new PrefixCodeRange(194, 7), + new PrefixCodeRange(322, 8), + new PrefixCodeRange(578, 9), + new PrefixCodeRange(1090, 10), + new PrefixCodeRange(2114, 12), + new PrefixCodeRange(6210, 14), + new PrefixCodeRange(22594, 24) + ]; + exports2.kCopyLengthPrefixCode = [ + new PrefixCodeRange(2, 0), + new PrefixCodeRange(3, 0), + new PrefixCodeRange(4, 0), + new PrefixCodeRange(5, 0), + new PrefixCodeRange(6, 0), + new PrefixCodeRange(7, 0), + new PrefixCodeRange(8, 0), + new PrefixCodeRange(9, 0), + new PrefixCodeRange(10, 1), + new PrefixCodeRange(12, 1), + new PrefixCodeRange(14, 2), + new PrefixCodeRange(18, 2), + new PrefixCodeRange(22, 3), + new PrefixCodeRange(30, 3), + new PrefixCodeRange(38, 4), + new PrefixCodeRange(54, 4), + new PrefixCodeRange(70, 5), + new PrefixCodeRange(102, 5), + new PrefixCodeRange(134, 6), + new PrefixCodeRange(198, 7), + new PrefixCodeRange(326, 8), + new PrefixCodeRange(582, 9), + new PrefixCodeRange(1094, 10), + new PrefixCodeRange(2118, 24) + ]; + exports2.kInsertRangeLut = [ + 0, + 0, + 8, + 8, + 0, + 16, + 8, + 16, + 16 + ]; + exports2.kCopyRangeLut = [ + 0, + 8, + 0, + 8, + 16, + 0, + 16, + 8, + 16 + ]; + } +}); + +// node_modules/brotli/dec/transform.js +var require_transform = __commonJS({ + "node_modules/brotli/dec/transform.js"(exports2) { + var BrotliDictionary = require_dictionary(); + var kIdentity = 0; + var kOmitLast1 = 1; + var kOmitLast2 = 2; + var kOmitLast3 = 3; + var kOmitLast4 = 4; + var kOmitLast5 = 5; + var kOmitLast6 = 6; + var kOmitLast7 = 7; + var kOmitLast8 = 8; + var kOmitLast9 = 9; + var kUppercaseFirst = 10; + var kUppercaseAll = 11; + var kOmitFirst1 = 12; + var kOmitFirst2 = 13; + var kOmitFirst3 = 14; + var kOmitFirst4 = 15; + var kOmitFirst5 = 16; + var kOmitFirst6 = 17; + var kOmitFirst7 = 18; + var kOmitFirst9 = 20; + function Transform(prefix, transform, suffix) { + this.prefix = new Uint8Array(prefix.length); + this.transform = transform; + this.suffix = new Uint8Array(suffix.length); + for (var i = 0; i < prefix.length; i++) + this.prefix[i] = prefix.charCodeAt(i); + for (var i = 0; i < suffix.length; i++) + this.suffix[i] = suffix.charCodeAt(i); + } + var kTransforms = [ + new Transform("", kIdentity, ""), + new Transform("", kIdentity, " "), + new Transform(" ", kIdentity, " "), + new Transform("", kOmitFirst1, ""), + new Transform("", kUppercaseFirst, " "), + new Transform("", kIdentity, " the "), + new Transform(" ", kIdentity, ""), + new Transform("s ", kIdentity, " "), + new Transform("", kIdentity, " of "), + new Transform("", kUppercaseFirst, ""), + new Transform("", kIdentity, " and "), + new Transform("", kOmitFirst2, ""), + new Transform("", kOmitLast1, ""), + new Transform(", ", kIdentity, " "), + new Transform("", kIdentity, ", "), + new Transform(" ", kUppercaseFirst, " "), + new Transform("", kIdentity, " in "), + new Transform("", kIdentity, " to "), + new Transform("e ", kIdentity, " "), + new Transform("", kIdentity, '"'), + new Transform("", kIdentity, "."), + new Transform("", kIdentity, '">'), + new Transform("", kIdentity, "\n"), + new Transform("", kOmitLast3, ""), + new Transform("", kIdentity, "]"), + new Transform("", kIdentity, " for "), + new Transform("", kOmitFirst3, ""), + new Transform("", kOmitLast2, ""), + new Transform("", kIdentity, " a "), + new Transform("", kIdentity, " that "), + new Transform(" ", kUppercaseFirst, ""), + new Transform("", kIdentity, ". "), + new Transform(".", kIdentity, ""), + new Transform(" ", kIdentity, ", "), + new Transform("", kOmitFirst4, ""), + new Transform("", kIdentity, " with "), + new Transform("", kIdentity, "'"), + new Transform("", kIdentity, " from "), + new Transform("", kIdentity, " by "), + new Transform("", kOmitFirst5, ""), + new Transform("", kOmitFirst6, ""), + new Transform(" the ", kIdentity, ""), + new Transform("", kOmitLast4, ""), + new Transform("", kIdentity, ". The "), + new Transform("", kUppercaseAll, ""), + new Transform("", kIdentity, " on "), + new Transform("", kIdentity, " as "), + new Transform("", kIdentity, " is "), + new Transform("", kOmitLast7, ""), + new Transform("", kOmitLast1, "ing "), + new Transform("", kIdentity, "\n "), + new Transform("", kIdentity, ":"), + new Transform(" ", kIdentity, ". "), + new Transform("", kIdentity, "ed "), + new Transform("", kOmitFirst9, ""), + new Transform("", kOmitFirst7, ""), + new Transform("", kOmitLast6, ""), + new Transform("", kIdentity, "("), + new Transform("", kUppercaseFirst, ", "), + new Transform("", kOmitLast8, ""), + new Transform("", kIdentity, " at "), + new Transform("", kIdentity, "ly "), + new Transform(" the ", kIdentity, " of "), + new Transform("", kOmitLast5, ""), + new Transform("", kOmitLast9, ""), + new Transform(" ", kUppercaseFirst, ", "), + new Transform("", kUppercaseFirst, '"'), + new Transform(".", kIdentity, "("), + new Transform("", kUppercaseAll, " "), + new Transform("", kUppercaseFirst, '">'), + new Transform("", kIdentity, '="'), + new Transform(" ", kIdentity, "."), + new Transform(".com/", kIdentity, ""), + new Transform(" the ", kIdentity, " of the "), + new Transform("", kUppercaseFirst, "'"), + new Transform("", kIdentity, ". This "), + new Transform("", kIdentity, ","), + new Transform(".", kIdentity, " "), + new Transform("", kUppercaseFirst, "("), + new Transform("", kUppercaseFirst, "."), + new Transform("", kIdentity, " not "), + new Transform(" ", kIdentity, '="'), + new Transform("", kIdentity, "er "), + new Transform(" ", kUppercaseAll, " "), + new Transform("", kIdentity, "al "), + new Transform(" ", kUppercaseAll, ""), + new Transform("", kIdentity, "='"), + new Transform("", kUppercaseAll, '"'), + new Transform("", kUppercaseFirst, ". "), + new Transform(" ", kIdentity, "("), + new Transform("", kIdentity, "ful "), + new Transform(" ", kUppercaseFirst, ". "), + new Transform("", kIdentity, "ive "), + new Transform("", kIdentity, "less "), + new Transform("", kUppercaseAll, "'"), + new Transform("", kIdentity, "est "), + new Transform(" ", kUppercaseFirst, "."), + new Transform("", kUppercaseAll, '">'), + new Transform(" ", kIdentity, "='"), + new Transform("", kUppercaseFirst, ","), + new Transform("", kIdentity, "ize "), + new Transform("", kUppercaseAll, "."), + new Transform("\xC2\xA0", kIdentity, ""), + new Transform(" ", kIdentity, ","), + new Transform("", kUppercaseFirst, '="'), + new Transform("", kUppercaseAll, '="'), + new Transform("", kIdentity, "ous "), + new Transform("", kUppercaseAll, ", "), + new Transform("", kUppercaseFirst, "='"), + new Transform(" ", kUppercaseFirst, ","), + new Transform(" ", kUppercaseAll, '="'), + new Transform(" ", kUppercaseAll, ", "), + new Transform("", kUppercaseAll, ","), + new Transform("", kUppercaseAll, "("), + new Transform("", kUppercaseAll, ". "), + new Transform(" ", kUppercaseAll, "."), + new Transform("", kUppercaseAll, "='"), + new Transform(" ", kUppercaseAll, ". "), + new Transform(" ", kUppercaseFirst, '="'), + new Transform(" ", kUppercaseAll, "='"), + new Transform(" ", kUppercaseFirst, "='") + ]; + exports2.kTransforms = kTransforms; + exports2.kNumTransforms = kTransforms.length; + function ToUpperCase(p, i) { + if (p[i] < 192) { + if (p[i] >= 97 && p[i] <= 122) { + p[i] ^= 32; + } + return 1; + } + if (p[i] < 224) { + p[i + 1] ^= 32; + return 2; + } + p[i + 2] ^= 5; + return 3; + } + exports2.transformDictionaryWord = function(dst, idx, word, len, transform) { + var prefix = kTransforms[transform].prefix; + var suffix = kTransforms[transform].suffix; + var t = kTransforms[transform].transform; + var skip = t < kOmitFirst1 ? 0 : t - (kOmitFirst1 - 1); + var i = 0; + var start_idx = idx; + var uppercase; + if (skip > len) { + skip = len; + } + var prefix_pos = 0; + while (prefix_pos < prefix.length) { + dst[idx++] = prefix[prefix_pos++]; + } + word += skip; + len -= skip; + if (t <= kOmitLast9) { + len -= t; + } + for (i = 0; i < len; i++) { + dst[idx++] = BrotliDictionary.dictionary[word + i]; + } + uppercase = idx - len; + if (t === kUppercaseFirst) { + ToUpperCase(dst, uppercase); + } else if (t === kUppercaseAll) { + while (len > 0) { + var step = ToUpperCase(dst, uppercase); + uppercase += step; + len -= step; + } + } + var suffix_pos = 0; + while (suffix_pos < suffix.length) { + dst[idx++] = suffix[suffix_pos++]; + } + return idx - start_idx; + }; + } +}); + +// node_modules/brotli/dec/decode.js +var require_decode = __commonJS({ + "node_modules/brotli/dec/decode.js"(exports2) { + var BrotliInput = require_streams().BrotliInput; + var BrotliOutput = require_streams().BrotliOutput; + var BrotliBitReader = require_bit_reader(); + var BrotliDictionary = require_dictionary(); + var HuffmanCode = require_huffman().HuffmanCode; + var BrotliBuildHuffmanTable = require_huffman().BrotliBuildHuffmanTable; + var Context = require_context(); + var Prefix = require_prefix(); + var Transform = require_transform(); + var kDefaultCodeLength = 8; + var kCodeLengthRepeatCode = 16; + var kNumLiteralCodes = 256; + var kNumInsertAndCopyCodes = 704; + var kNumBlockLengthCodes = 26; + var kLiteralContextBits = 6; + var kDistanceContextBits = 2; + var HUFFMAN_TABLE_BITS = 8; + var HUFFMAN_TABLE_MASK = 255; + var HUFFMAN_MAX_TABLE_SIZE = 1080; + var CODE_LENGTH_CODES = 18; + var kCodeLengthCodeOrder = new Uint8Array([ + 1, + 2, + 3, + 4, + 0, + 5, + 17, + 6, + 16, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ]); + var NUM_DISTANCE_SHORT_CODES = 16; + var kDistanceShortCodeIndexOffset = new Uint8Array([ + 3, + 2, + 1, + 0, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2 + ]); + var kDistanceShortCodeValueOffset = new Int8Array([ + 0, + 0, + 0, + 0, + -1, + 1, + -2, + 2, + -3, + 3, + -1, + 1, + -2, + 2, + -3, + 3 + ]); + var kMaxHuffmanTableSize = new Uint16Array([ + 256, + 402, + 436, + 468, + 500, + 534, + 566, + 598, + 630, + 662, + 694, + 726, + 758, + 790, + 822, + 854, + 886, + 920, + 952, + 984, + 1016, + 1048, + 1080 + ]); + function DecodeWindowBits(br) { + var n; + if (br.readBits(1) === 0) { + return 16; + } + n = br.readBits(3); + if (n > 0) { + return 17 + n; + } + n = br.readBits(3); + if (n > 0) { + return 8 + n; + } + return 17; + } + function DecodeVarLenUint8(br) { + if (br.readBits(1)) { + var nbits = br.readBits(3); + if (nbits === 0) { + return 1; + } else { + return br.readBits(nbits) + (1 << nbits); + } + } + return 0; + } + function MetaBlockLength() { + this.meta_block_length = 0; + this.input_end = 0; + this.is_uncompressed = 0; + this.is_metadata = false; + } + function DecodeMetaBlockLength(br) { + var out = new MetaBlockLength(); + var size_nibbles; + var size_bytes; + var i; + out.input_end = br.readBits(1); + if (out.input_end && br.readBits(1)) { + return out; + } + size_nibbles = br.readBits(2) + 4; + if (size_nibbles === 7) { + out.is_metadata = true; + if (br.readBits(1) !== 0) + throw new Error("Invalid reserved bit"); + size_bytes = br.readBits(2); + if (size_bytes === 0) + return out; + for (i = 0; i < size_bytes; i++) { + var next_byte = br.readBits(8); + if (i + 1 === size_bytes && size_bytes > 1 && next_byte === 0) + throw new Error("Invalid size byte"); + out.meta_block_length |= next_byte << i * 8; + } + } else { + for (i = 0; i < size_nibbles; ++i) { + var next_nibble = br.readBits(4); + if (i + 1 === size_nibbles && size_nibbles > 4 && next_nibble === 0) + throw new Error("Invalid size nibble"); + out.meta_block_length |= next_nibble << i * 4; + } + } + ++out.meta_block_length; + if (!out.input_end && !out.is_metadata) { + out.is_uncompressed = br.readBits(1); + } + return out; + } + function ReadSymbol(table, index, br) { + var start_index = index; + var nbits; + br.fillBitWindow(); + index += br.val_ >>> br.bit_pos_ & HUFFMAN_TABLE_MASK; + nbits = table[index].bits - HUFFMAN_TABLE_BITS; + if (nbits > 0) { + br.bit_pos_ += HUFFMAN_TABLE_BITS; + index += table[index].value; + index += br.val_ >>> br.bit_pos_ & (1 << nbits) - 1; + } + br.bit_pos_ += table[index].bits; + return table[index].value; + } + function ReadHuffmanCodeLengths(code_length_code_lengths, num_symbols, code_lengths, br) { + var symbol = 0; + var prev_code_len = kDefaultCodeLength; + var repeat = 0; + var repeat_code_len = 0; + var space = 32768; + var table = []; + for (var i = 0; i < 32; i++) + table.push(new HuffmanCode(0, 0)); + BrotliBuildHuffmanTable(table, 0, 5, code_length_code_lengths, CODE_LENGTH_CODES); + while (symbol < num_symbols && space > 0) { + var p = 0; + var code_len; + br.readMoreInput(); + br.fillBitWindow(); + p += br.val_ >>> br.bit_pos_ & 31; + br.bit_pos_ += table[p].bits; + code_len = table[p].value & 255; + if (code_len < kCodeLengthRepeatCode) { + repeat = 0; + code_lengths[symbol++] = code_len; + if (code_len !== 0) { + prev_code_len = code_len; + space -= 32768 >> code_len; + } + } else { + var extra_bits = code_len - 14; + var old_repeat; + var repeat_delta; + var new_len = 0; + if (code_len === kCodeLengthRepeatCode) { + new_len = prev_code_len; + } + if (repeat_code_len !== new_len) { + repeat = 0; + repeat_code_len = new_len; + } + old_repeat = repeat; + if (repeat > 0) { + repeat -= 2; + repeat <<= extra_bits; + } + repeat += br.readBits(extra_bits) + 3; + repeat_delta = repeat - old_repeat; + if (symbol + repeat_delta > num_symbols) { + throw new Error("[ReadHuffmanCodeLengths] symbol + repeat_delta > num_symbols"); + } + for (var x = 0; x < repeat_delta; x++) + code_lengths[symbol + x] = repeat_code_len; + symbol += repeat_delta; + if (repeat_code_len !== 0) { + space -= repeat_delta << 15 - repeat_code_len; + } + } + } + if (space !== 0) { + throw new Error("[ReadHuffmanCodeLengths] space = " + space); + } + for (; symbol < num_symbols; symbol++) + code_lengths[symbol] = 0; + } + function ReadHuffmanCode(alphabet_size, tables, table, br) { + var table_size = 0; + var simple_code_or_skip; + var code_lengths = new Uint8Array(alphabet_size); + br.readMoreInput(); + simple_code_or_skip = br.readBits(2); + if (simple_code_or_skip === 1) { + var i; + var max_bits_counter = alphabet_size - 1; + var max_bits = 0; + var symbols = new Int32Array(4); + var num_symbols = br.readBits(2) + 1; + while (max_bits_counter) { + max_bits_counter >>= 1; + ++max_bits; + } + for (i = 0; i < num_symbols; ++i) { + symbols[i] = br.readBits(max_bits) % alphabet_size; + code_lengths[symbols[i]] = 2; + } + code_lengths[symbols[0]] = 1; + switch (num_symbols) { + case 1: + break; + case 3: + if (symbols[0] === symbols[1] || symbols[0] === symbols[2] || symbols[1] === symbols[2]) { + throw new Error("[ReadHuffmanCode] invalid symbols"); + } + break; + case 2: + if (symbols[0] === symbols[1]) { + throw new Error("[ReadHuffmanCode] invalid symbols"); + } + code_lengths[symbols[1]] = 1; + break; + case 4: + if (symbols[0] === symbols[1] || symbols[0] === symbols[2] || symbols[0] === symbols[3] || symbols[1] === symbols[2] || symbols[1] === symbols[3] || symbols[2] === symbols[3]) { + throw new Error("[ReadHuffmanCode] invalid symbols"); + } + if (br.readBits(1)) { + code_lengths[symbols[2]] = 3; + code_lengths[symbols[3]] = 3; + } else { + code_lengths[symbols[0]] = 2; + } + break; + } + } else { + var i; + var code_length_code_lengths = new Uint8Array(CODE_LENGTH_CODES); + var space = 32; + var num_codes = 0; + var huff = [ + new HuffmanCode(2, 0), + new HuffmanCode(2, 4), + new HuffmanCode(2, 3), + new HuffmanCode(3, 2), + new HuffmanCode(2, 0), + new HuffmanCode(2, 4), + new HuffmanCode(2, 3), + new HuffmanCode(4, 1), + new HuffmanCode(2, 0), + new HuffmanCode(2, 4), + new HuffmanCode(2, 3), + new HuffmanCode(3, 2), + new HuffmanCode(2, 0), + new HuffmanCode(2, 4), + new HuffmanCode(2, 3), + new HuffmanCode(4, 5) + ]; + for (i = simple_code_or_skip; i < CODE_LENGTH_CODES && space > 0; ++i) { + var code_len_idx = kCodeLengthCodeOrder[i]; + var p = 0; + var v; + br.fillBitWindow(); + p += br.val_ >>> br.bit_pos_ & 15; + br.bit_pos_ += huff[p].bits; + v = huff[p].value; + code_length_code_lengths[code_len_idx] = v; + if (v !== 0) { + space -= 32 >> v; + ++num_codes; + } + } + if (!(num_codes === 1 || space === 0)) + throw new Error("[ReadHuffmanCode] invalid num_codes or space"); + ReadHuffmanCodeLengths(code_length_code_lengths, alphabet_size, code_lengths, br); + } + table_size = BrotliBuildHuffmanTable(tables, table, HUFFMAN_TABLE_BITS, code_lengths, alphabet_size); + if (table_size === 0) { + throw new Error("[ReadHuffmanCode] BuildHuffmanTable failed: "); + } + return table_size; + } + function ReadBlockLength(table, index, br) { + var code; + var nbits; + code = ReadSymbol(table, index, br); + nbits = Prefix.kBlockLengthPrefixCode[code].nbits; + return Prefix.kBlockLengthPrefixCode[code].offset + br.readBits(nbits); + } + function TranslateShortCodes(code, ringbuffer, index) { + var val; + if (code < NUM_DISTANCE_SHORT_CODES) { + index += kDistanceShortCodeIndexOffset[code]; + index &= 3; + val = ringbuffer[index] + kDistanceShortCodeValueOffset[code]; + } else { + val = code - NUM_DISTANCE_SHORT_CODES + 1; + } + return val; + } + function MoveToFront(v, index) { + var value = v[index]; + var i = index; + for (; i; --i) v[i] = v[i - 1]; + v[0] = value; + } + function InverseMoveToFrontTransform(v, v_len) { + var mtf = new Uint8Array(256); + var i; + for (i = 0; i < 256; ++i) { + mtf[i] = i; + } + for (i = 0; i < v_len; ++i) { + var index = v[i]; + v[i] = mtf[index]; + if (index) MoveToFront(mtf, index); + } + } + function HuffmanTreeGroup(alphabet_size, num_htrees) { + this.alphabet_size = alphabet_size; + this.num_htrees = num_htrees; + this.codes = new Array(num_htrees + num_htrees * kMaxHuffmanTableSize[alphabet_size + 31 >>> 5]); + this.htrees = new Uint32Array(num_htrees); + } + HuffmanTreeGroup.prototype.decode = function(br) { + var i; + var table_size; + var next = 0; + for (i = 0; i < this.num_htrees; ++i) { + this.htrees[i] = next; + table_size = ReadHuffmanCode(this.alphabet_size, this.codes, next, br); + next += table_size; + } + }; + function DecodeContextMap(context_map_size, br) { + var out = { num_htrees: null, context_map: null }; + var use_rle_for_zeros; + var max_run_length_prefix = 0; + var table; + var i; + br.readMoreInput(); + var num_htrees = out.num_htrees = DecodeVarLenUint8(br) + 1; + var context_map = out.context_map = new Uint8Array(context_map_size); + if (num_htrees <= 1) { + return out; + } + use_rle_for_zeros = br.readBits(1); + if (use_rle_for_zeros) { + max_run_length_prefix = br.readBits(4) + 1; + } + table = []; + for (i = 0; i < HUFFMAN_MAX_TABLE_SIZE; i++) { + table[i] = new HuffmanCode(0, 0); + } + ReadHuffmanCode(num_htrees + max_run_length_prefix, table, 0, br); + for (i = 0; i < context_map_size; ) { + var code; + br.readMoreInput(); + code = ReadSymbol(table, 0, br); + if (code === 0) { + context_map[i] = 0; + ++i; + } else if (code <= max_run_length_prefix) { + var reps = 1 + (1 << code) + br.readBits(code); + while (--reps) { + if (i >= context_map_size) { + throw new Error("[DecodeContextMap] i >= context_map_size"); + } + context_map[i] = 0; + ++i; + } + } else { + context_map[i] = code - max_run_length_prefix; + ++i; + } + } + if (br.readBits(1)) { + InverseMoveToFrontTransform(context_map, context_map_size); + } + return out; + } + function DecodeBlockType(max_block_type, trees, tree_type, block_types, ringbuffers, indexes, br) { + var ringbuffer = tree_type * 2; + var index = tree_type; + var type_code = ReadSymbol(trees, tree_type * HUFFMAN_MAX_TABLE_SIZE, br); + var block_type; + if (type_code === 0) { + block_type = ringbuffers[ringbuffer + (indexes[index] & 1)]; + } else if (type_code === 1) { + block_type = ringbuffers[ringbuffer + (indexes[index] - 1 & 1)] + 1; + } else { + block_type = type_code - 2; + } + if (block_type >= max_block_type) { + block_type -= max_block_type; + } + block_types[tree_type] = block_type; + ringbuffers[ringbuffer + (indexes[index] & 1)] = block_type; + ++indexes[index]; + } + function CopyUncompressedBlockToOutput(output, len, pos, ringbuffer, ringbuffer_mask, br) { + var rb_size = ringbuffer_mask + 1; + var rb_pos = pos & ringbuffer_mask; + var br_pos = br.pos_ & BrotliBitReader.IBUF_MASK; + var nbytes; + if (len < 8 || br.bit_pos_ + (len << 3) < br.bit_end_pos_) { + while (len-- > 0) { + br.readMoreInput(); + ringbuffer[rb_pos++] = br.readBits(8); + if (rb_pos === rb_size) { + output.write(ringbuffer, rb_size); + rb_pos = 0; + } + } + return; + } + if (br.bit_end_pos_ < 32) { + throw new Error("[CopyUncompressedBlockToOutput] br.bit_end_pos_ < 32"); + } + while (br.bit_pos_ < 32) { + ringbuffer[rb_pos] = br.val_ >>> br.bit_pos_; + br.bit_pos_ += 8; + ++rb_pos; + --len; + } + nbytes = br.bit_end_pos_ - br.bit_pos_ >> 3; + if (br_pos + nbytes > BrotliBitReader.IBUF_MASK) { + var tail = BrotliBitReader.IBUF_MASK + 1 - br_pos; + for (var x = 0; x < tail; x++) + ringbuffer[rb_pos + x] = br.buf_[br_pos + x]; + nbytes -= tail; + rb_pos += tail; + len -= tail; + br_pos = 0; + } + for (var x = 0; x < nbytes; x++) + ringbuffer[rb_pos + x] = br.buf_[br_pos + x]; + rb_pos += nbytes; + len -= nbytes; + if (rb_pos >= rb_size) { + output.write(ringbuffer, rb_size); + rb_pos -= rb_size; + for (var x = 0; x < rb_pos; x++) + ringbuffer[x] = ringbuffer[rb_size + x]; + } + while (rb_pos + len >= rb_size) { + nbytes = rb_size - rb_pos; + if (br.input_.read(ringbuffer, rb_pos, nbytes) < nbytes) { + throw new Error("[CopyUncompressedBlockToOutput] not enough bytes"); + } + output.write(ringbuffer, rb_size); + len -= nbytes; + rb_pos = 0; + } + if (br.input_.read(ringbuffer, rb_pos, len) < len) { + throw new Error("[CopyUncompressedBlockToOutput] not enough bytes"); + } + br.reset(); + } + function JumpToByteBoundary(br) { + var new_bit_pos = br.bit_pos_ + 7 & ~7; + var pad_bits = br.readBits(new_bit_pos - br.bit_pos_); + return pad_bits == 0; + } + function BrotliDecompressedSize(buffer) { + var input = new BrotliInput(buffer); + var br = new BrotliBitReader(input); + DecodeWindowBits(br); + var out = DecodeMetaBlockLength(br); + return out.meta_block_length; + } + exports2.BrotliDecompressedSize = BrotliDecompressedSize; + function BrotliDecompressBuffer(buffer, output_size) { + var input = new BrotliInput(buffer); + if (output_size == null) { + output_size = BrotliDecompressedSize(buffer); + } + var output_buffer = new Uint8Array(output_size); + var output = new BrotliOutput(output_buffer); + BrotliDecompress(input, output); + if (output.pos < output.buffer.length) { + output.buffer = output.buffer.subarray(0, output.pos); + } + return output.buffer; + } + exports2.BrotliDecompressBuffer = BrotliDecompressBuffer; + function BrotliDecompress(input, output) { + var i; + var pos = 0; + var input_end = 0; + var window_bits = 0; + var max_backward_distance; + var max_distance = 0; + var ringbuffer_size; + var ringbuffer_mask; + var ringbuffer; + var ringbuffer_end; + var dist_rb = [16, 15, 11, 4]; + var dist_rb_idx = 0; + var prev_byte1 = 0; + var prev_byte2 = 0; + var hgroup = [new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0)]; + var block_type_trees; + var block_len_trees; + var br; + var kRingBufferWriteAheadSlack = 128 + BrotliBitReader.READ_SIZE; + br = new BrotliBitReader(input); + window_bits = DecodeWindowBits(br); + max_backward_distance = (1 << window_bits) - 16; + ringbuffer_size = 1 << window_bits; + ringbuffer_mask = ringbuffer_size - 1; + ringbuffer = new Uint8Array(ringbuffer_size + kRingBufferWriteAheadSlack + BrotliDictionary.maxDictionaryWordLength); + ringbuffer_end = ringbuffer_size; + block_type_trees = []; + block_len_trees = []; + for (var x = 0; x < 3 * HUFFMAN_MAX_TABLE_SIZE; x++) { + block_type_trees[x] = new HuffmanCode(0, 0); + block_len_trees[x] = new HuffmanCode(0, 0); + } + while (!input_end) { + var meta_block_remaining_len = 0; + var is_uncompressed; + var block_length = [1 << 28, 1 << 28, 1 << 28]; + var block_type = [0]; + var num_block_types = [1, 1, 1]; + var block_type_rb = [0, 1, 0, 1, 0, 1]; + var block_type_rb_index = [0]; + var distance_postfix_bits; + var num_direct_distance_codes; + var distance_postfix_mask; + var num_distance_codes; + var context_map = null; + var context_modes = null; + var num_literal_htrees; + var dist_context_map = null; + var num_dist_htrees; + var context_offset = 0; + var context_map_slice = null; + var literal_htree_index = 0; + var dist_context_offset = 0; + var dist_context_map_slice = null; + var dist_htree_index = 0; + var context_lookup_offset1 = 0; + var context_lookup_offset2 = 0; + var context_mode; + var htree_command; + for (i = 0; i < 3; ++i) { + hgroup[i].codes = null; + hgroup[i].htrees = null; + } + br.readMoreInput(); + var _out = DecodeMetaBlockLength(br); + meta_block_remaining_len = _out.meta_block_length; + if (pos + meta_block_remaining_len > output.buffer.length) { + var tmp = new Uint8Array(pos + meta_block_remaining_len); + tmp.set(output.buffer); + output.buffer = tmp; + } + input_end = _out.input_end; + is_uncompressed = _out.is_uncompressed; + if (_out.is_metadata) { + JumpToByteBoundary(br); + for (; meta_block_remaining_len > 0; --meta_block_remaining_len) { + br.readMoreInput(); + br.readBits(8); + } + continue; + } + if (meta_block_remaining_len === 0) { + continue; + } + if (is_uncompressed) { + br.bit_pos_ = br.bit_pos_ + 7 & ~7; + CopyUncompressedBlockToOutput( + output, + meta_block_remaining_len, + pos, + ringbuffer, + ringbuffer_mask, + br + ); + pos += meta_block_remaining_len; + continue; + } + for (i = 0; i < 3; ++i) { + num_block_types[i] = DecodeVarLenUint8(br) + 1; + if (num_block_types[i] >= 2) { + ReadHuffmanCode(num_block_types[i] + 2, block_type_trees, i * HUFFMAN_MAX_TABLE_SIZE, br); + ReadHuffmanCode(kNumBlockLengthCodes, block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br); + block_length[i] = ReadBlockLength(block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br); + block_type_rb_index[i] = 1; + } + } + br.readMoreInput(); + distance_postfix_bits = br.readBits(2); + num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES + (br.readBits(4) << distance_postfix_bits); + distance_postfix_mask = (1 << distance_postfix_bits) - 1; + num_distance_codes = num_direct_distance_codes + (48 << distance_postfix_bits); + context_modes = new Uint8Array(num_block_types[0]); + for (i = 0; i < num_block_types[0]; ++i) { + br.readMoreInput(); + context_modes[i] = br.readBits(2) << 1; + } + var _o1 = DecodeContextMap(num_block_types[0] << kLiteralContextBits, br); + num_literal_htrees = _o1.num_htrees; + context_map = _o1.context_map; + var _o2 = DecodeContextMap(num_block_types[2] << kDistanceContextBits, br); + num_dist_htrees = _o2.num_htrees; + dist_context_map = _o2.context_map; + hgroup[0] = new HuffmanTreeGroup(kNumLiteralCodes, num_literal_htrees); + hgroup[1] = new HuffmanTreeGroup(kNumInsertAndCopyCodes, num_block_types[1]); + hgroup[2] = new HuffmanTreeGroup(num_distance_codes, num_dist_htrees); + for (i = 0; i < 3; ++i) { + hgroup[i].decode(br); + } + context_map_slice = 0; + dist_context_map_slice = 0; + context_mode = context_modes[block_type[0]]; + context_lookup_offset1 = Context.lookupOffsets[context_mode]; + context_lookup_offset2 = Context.lookupOffsets[context_mode + 1]; + htree_command = hgroup[1].htrees[0]; + while (meta_block_remaining_len > 0) { + var cmd_code; + var range_idx; + var insert_code; + var copy_code; + var insert_length; + var copy_length; + var distance_code; + var distance; + var context; + var j; + var copy_dst; + br.readMoreInput(); + if (block_length[1] === 0) { + DecodeBlockType( + num_block_types[1], + block_type_trees, + 1, + block_type, + block_type_rb, + block_type_rb_index, + br + ); + block_length[1] = ReadBlockLength(block_len_trees, HUFFMAN_MAX_TABLE_SIZE, br); + htree_command = hgroup[1].htrees[block_type[1]]; + } + --block_length[1]; + cmd_code = ReadSymbol(hgroup[1].codes, htree_command, br); + range_idx = cmd_code >> 6; + if (range_idx >= 2) { + range_idx -= 2; + distance_code = -1; + } else { + distance_code = 0; + } + insert_code = Prefix.kInsertRangeLut[range_idx] + (cmd_code >> 3 & 7); + copy_code = Prefix.kCopyRangeLut[range_idx] + (cmd_code & 7); + insert_length = Prefix.kInsertLengthPrefixCode[insert_code].offset + br.readBits(Prefix.kInsertLengthPrefixCode[insert_code].nbits); + copy_length = Prefix.kCopyLengthPrefixCode[copy_code].offset + br.readBits(Prefix.kCopyLengthPrefixCode[copy_code].nbits); + prev_byte1 = ringbuffer[pos - 1 & ringbuffer_mask]; + prev_byte2 = ringbuffer[pos - 2 & ringbuffer_mask]; + for (j = 0; j < insert_length; ++j) { + br.readMoreInput(); + if (block_length[0] === 0) { + DecodeBlockType( + num_block_types[0], + block_type_trees, + 0, + block_type, + block_type_rb, + block_type_rb_index, + br + ); + block_length[0] = ReadBlockLength(block_len_trees, 0, br); + context_offset = block_type[0] << kLiteralContextBits; + context_map_slice = context_offset; + context_mode = context_modes[block_type[0]]; + context_lookup_offset1 = Context.lookupOffsets[context_mode]; + context_lookup_offset2 = Context.lookupOffsets[context_mode + 1]; + } + context = Context.lookup[context_lookup_offset1 + prev_byte1] | Context.lookup[context_lookup_offset2 + prev_byte2]; + literal_htree_index = context_map[context_map_slice + context]; + --block_length[0]; + prev_byte2 = prev_byte1; + prev_byte1 = ReadSymbol(hgroup[0].codes, hgroup[0].htrees[literal_htree_index], br); + ringbuffer[pos & ringbuffer_mask] = prev_byte1; + if ((pos & ringbuffer_mask) === ringbuffer_mask) { + output.write(ringbuffer, ringbuffer_size); + } + ++pos; + } + meta_block_remaining_len -= insert_length; + if (meta_block_remaining_len <= 0) break; + if (distance_code < 0) { + var context; + br.readMoreInput(); + if (block_length[2] === 0) { + DecodeBlockType( + num_block_types[2], + block_type_trees, + 2, + block_type, + block_type_rb, + block_type_rb_index, + br + ); + block_length[2] = ReadBlockLength(block_len_trees, 2 * HUFFMAN_MAX_TABLE_SIZE, br); + dist_context_offset = block_type[2] << kDistanceContextBits; + dist_context_map_slice = dist_context_offset; + } + --block_length[2]; + context = (copy_length > 4 ? 3 : copy_length - 2) & 255; + dist_htree_index = dist_context_map[dist_context_map_slice + context]; + distance_code = ReadSymbol(hgroup[2].codes, hgroup[2].htrees[dist_htree_index], br); + if (distance_code >= num_direct_distance_codes) { + var nbits; + var postfix; + var offset; + distance_code -= num_direct_distance_codes; + postfix = distance_code & distance_postfix_mask; + distance_code >>= distance_postfix_bits; + nbits = (distance_code >> 1) + 1; + offset = (2 + (distance_code & 1) << nbits) - 4; + distance_code = num_direct_distance_codes + (offset + br.readBits(nbits) << distance_postfix_bits) + postfix; + } + } + distance = TranslateShortCodes(distance_code, dist_rb, dist_rb_idx); + if (distance < 0) { + throw new Error("[BrotliDecompress] invalid distance"); + } + if (pos < max_backward_distance && max_distance !== max_backward_distance) { + max_distance = pos; + } else { + max_distance = max_backward_distance; + } + copy_dst = pos & ringbuffer_mask; + if (distance > max_distance) { + if (copy_length >= BrotliDictionary.minDictionaryWordLength && copy_length <= BrotliDictionary.maxDictionaryWordLength) { + var offset = BrotliDictionary.offsetsByLength[copy_length]; + var word_id = distance - max_distance - 1; + var shift = BrotliDictionary.sizeBitsByLength[copy_length]; + var mask = (1 << shift) - 1; + var word_idx = word_id & mask; + var transform_idx = word_id >> shift; + offset += word_idx * copy_length; + if (transform_idx < Transform.kNumTransforms) { + var len = Transform.transformDictionaryWord(ringbuffer, copy_dst, offset, copy_length, transform_idx); + copy_dst += len; + pos += len; + meta_block_remaining_len -= len; + if (copy_dst >= ringbuffer_end) { + output.write(ringbuffer, ringbuffer_size); + for (var _x = 0; _x < copy_dst - ringbuffer_end; _x++) + ringbuffer[_x] = ringbuffer[ringbuffer_end + _x]; + } + } else { + throw new Error("Invalid backward reference. pos: " + pos + " distance: " + distance + " len: " + copy_length + " bytes left: " + meta_block_remaining_len); + } + } else { + throw new Error("Invalid backward reference. pos: " + pos + " distance: " + distance + " len: " + copy_length + " bytes left: " + meta_block_remaining_len); + } + } else { + if (distance_code > 0) { + dist_rb[dist_rb_idx & 3] = distance; + ++dist_rb_idx; + } + if (copy_length > meta_block_remaining_len) { + throw new Error("Invalid backward reference. pos: " + pos + " distance: " + distance + " len: " + copy_length + " bytes left: " + meta_block_remaining_len); + } + for (j = 0; j < copy_length; ++j) { + ringbuffer[pos & ringbuffer_mask] = ringbuffer[pos - distance & ringbuffer_mask]; + if ((pos & ringbuffer_mask) === ringbuffer_mask) { + output.write(ringbuffer, ringbuffer_size); + } + ++pos; + --meta_block_remaining_len; + } + } + prev_byte1 = ringbuffer[pos - 1 & ringbuffer_mask]; + prev_byte2 = ringbuffer[pos - 2 & ringbuffer_mask]; + } + pos &= 1073741823; + } + output.write(ringbuffer, pos & ringbuffer_mask); + } + exports2.BrotliDecompress = BrotliDecompress; + BrotliDictionary.init(); + } +}); + +// node_modules/brotli/decompress.js +var require_decompress = __commonJS({ + "node_modules/brotli/decompress.js"(exports2, module2) { + module2.exports = require_decode().BrotliDecompressBuffer; + } +}); + +// brotli-decoder-entry.cjs +module.exports = require_decompress(); diff --git a/src/Node/Lib/brotli-encoder.cjs b/src/Node/Lib/brotli-encoder.cjs new file mode 100644 index 00000000..fd610ae1 --- /dev/null +++ b/src/Node/Lib/brotli-encoder.cjs @@ -0,0 +1,30266 @@ +// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt. +"use strict"; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + try { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + } catch (e) { + throw mod = 0, e; + } +}; + +// node_modules/brotli/build/encode.js +var require_encode = __commonJS({ + "node_modules/brotli/build/encode.js"(exports, module) { + var b = { TOTAL_MEMORY: 67108864 }; + b.readBinary = function() { + return Uint8Array.fromBase64("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AAAAAMuyLAAAAAAAy7JsAAAAAADLsqwAAAAAAMuy7AAAAAAAy7ItAAAAAADLsm0AAAAAAMuyrQAAAAAAy7LtAAAAAADLsi4AAAAAAMuybgAAAAAAy7KuAAAAAADLsu4AAAAAAMuyLwAAAAAAy7JvAAAAAADLsq8AAAAAAMuy7wAAAAAAy7YsAAAAAADLtmwAAAAAAMu2rAAAAAAAy7bsAAAAAADLti0AAAAAAMu2bQAAAAAAy7atAAAAAADLtu0AAAAAAMu2LgAAAAAAy7ZuAAAAAADLtq4AAAAAAMu27gAAAAAAy7YvAAAAAADLtm8AAAAAAMu2rwAAAAAAy7bvAAAAAADLuiwAAAAAAMu6bAAAAAAAy7qsAAAAAADLuuwAAAAAAMu6LQAAAAAAy7ptAAAAAADLuq0AAAAAAMu67QAAAAAAy7ouAAAAAADLum4AAAAAAMu6rgAAAAAAy7ruAAAAAADLui8AAAAAAMu6bwAAAAAAy7qvAAAAAADLuu8AAAAAAMu+LAAAAAAAy75sAAAAAADLvqwAAAAAAMu+7AAAAAAAy74tAAAAAADLvm0AAAAAAMu+rQAAAAAAy77tAAAAAADLvi4AAAAAAMu+bgAAAAAAy76uAAAAAADLvu4AAAAAAMu+LwAAAAAAy75vAAAAAADLvq8AAAAAAMu+7wAAAAAA27IsAAAAAADbsmwAAAAAANuyrAAAAAAA27LsAAAAAADbsi0AAAAAANuybQAAAAAA27KtAAAAAADbsu0AAAAAANuyLgAAAAAA27JuAAAAAADbsq4AAAAAANuy7gAAAAAA27IvAAAAAADbsm8AAAAAANuyrwAAAAAA27LvAAAAAADbtiwAAAAAANu2bAAAAAAA27asAAAAAADbtuwAAAAAANu2LQAAAAAA27ZtAAAAAADbtq0AAAAAANu27QAAAAAA27YuAAAAAADbtm4AAAAAANu2rgAAAAAA27buAAAAAADbti8AAAAAANu2bwAAAAAA27avAAAAAADbtu8AAAAAANu6LAAAAAAA27psAAAAAADbuqwAAAAAANu67AAAAAAA27otAAAAAADbum0AAAAAANu6rQAAAAAA27rtAAAAAADbui4AAAAAANu6bgAAAAAA27quAAAAAADbuu4AAAAAANu6LwAAAAAA27pvAAAAAADbuq8AAAAAANu67wAAAAAA274sAAAAAADbvmwAAAAAANu+rAAAAAAA277sAAAAAADbvi0AAAAAANu+bQAAAAAA276tAAAAAADbvu0AAAAAANu+LgAAAAAA275uAAAAAADbvq4AAAAAANu+7gAAAAAA274vAAAAAADbvm8AAAAAANu+rwAAAAAA277vAAAAAADrsiwAAAAAAOuybAAAAAAA67KsAAAAAADrsuwAAAAAAOuyLQAAAAAA67JtAAAAAADrsq0AAAAAAOuy7QAAAAAA67IuAAAAAADrsm4AAAAAAOuyrgAAAAAA67LuAAAAAADrsi8AAAAAAOuybwAAAAAA67KvAAAAAADrsu8AAAAAAOu2LAAAAAAA67ZsAAAAAADrtqwAAAAAAOu27AAAAAAA67YtAAAAAADrtm0AAAAAAOu2rQAAAAAA67btAAAAAADrti4AAAAAAOu2bgAAAAAA67auAAAAAADrtu4AAAAAAOu2LwAAAAAA67ZvAAAAAADrtq8AAAAAAOu27wAAAAAA67osAAAAAADrumwAAAAAAOu6rAAAAAAA67rsAAAAAADrui0AAAAAAOu6bQAAAAAA67qtAAAAAADruu0AAAAAAOu6LgAAAAAA67puAAAAAADruq4AAAAAAOu67gAAAAAA67ovAAAAAADrum8AAAAAAOu6rwAAAAAA67rvAAAAAADrviwAAAAAAOu+bAAAAAAA676sAAAAAADrvuwAAAAAAOu+LQAAAAAA675tAAAAAADrvq0AAAAAAOu+7QAAAAAA674uAAAAAADrvm4AAAAAAOu+rgAAAAAA677uAAAAAADrvi8AAAAAAOu+bwAAAAAA676vAAAAAADrvu8AAAAAAPuyLAAAAAAA+7JsAAAAAAD7sqwAAAAAAPuy7AAAAAAA+7ItAAAAAAD7sm0AAAAAAPuyrQAAAAAA+7LtAAAAAAD7si4AAAAAAPuybgAAAAAA+7KuAAAAAAD7su4AAAAAAPuyLwAAAAAA+7JvAAAAAAD7sq8AAAAAAPuy7wAAAAAA+7YsAAAAAAD7tmwAAAAAAPu2rAAAAAAA+7bsAAAAAAD7ti0AAAAAAPu2bQAAAAAA+7atAAAAAAD7tu0AAAAAAPu2LgAAAAAA+7ZuAAAAAAD7tq4AAAAAAPu27gAAAAAA+7YvAAAAAAD7tm8AAAAAAPu2rwAAAAAA+7bvAAAAAAD7uiwA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27IvKwAAAADbsi87AAAAANuybwsAAAAA27JvGwAAAADbsm8rAAAAANuybzsAAAAA27KvCwAAAADbsq8bAAAAANuyrysAAAAA27KvOwAAAADbsu8LAAAAANuy7xsAAAAA27LvKwAAAADbsu87AAAAANu2LAsAAAAA27YsGwAAAADbtiwrAAAAANu2LDsAAAAA27ZsCwAAAADbtmwbAAAAANu2bCsAAAAA27ZsOwAAAADbtqwLAAAAANu2rBsAAAAA27asKwAAAADbtqw7AAAAANu27AsAAAAA27bsGwAAAADbtuwrAAAAANu27DsAAAAA27YtCwAAAADbti0bAAAAANu2LSsAAAAA27YtOwAAAADbtm0LAAAAANu2bRsAAAAA27ZtKwAAAADbtm07AAAAANu2rQsAAAAA27atGwAAAADbtq0rAAAAANu2rTsAAAAA27btCwAAAADbtu0bAAAAANu27SsAAAAA27btOwAAAADbti4LAAAAANu2LhsAAAAA27YuKwAAAADbti47AAAAANu2bgsAAAAA27ZuGwAAAADbtm4rAAAAANu2bjsAAAAA27auCwAAAADbtq4bAAAAANu2risAAAAA27auOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAJAAAAFQAAACMAAAArAAAANAAAAD4AAAAJAEAAFQBAABuAQAAigEAAJkBAAChAQCAqQEAgLsBAADFAQAAzwEAQNQBAMDZAQCg3AEAAAAAAAEAAAACAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAD/////AQAAAP7///8CAAAA/f///wMAAAD/////AQAAAP7///8CAAAA/f///wMAAAA8DwAAoQ4AAIsOAACBDgAAow4AAKMOAACgDgAAoA4AAJ0OAACdDgAAlw4AAJcOAACNDgAAjQ4AAIMOAACDDgAAAAAAAAQAAAAIAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAALAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAAAAAACAAAAAQAAAAMAAAAAgAAAAoAAAAGAAAADgAAAAEAAAAJAAAABQAAAA0AAAADAAAADwAAAB8AAAAAAAAACwAAAAcAAAAGAAAABgAAAAYAAAAGAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAASAAAAEgAAABIAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAB4AAAAeAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAwAAAAOAAAAGAAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAwAAAAOAAAAEgAAABYAAAAeAAAAJgAAADYAAABGAAAAZgAAAIYAAADGAAAARgEAAEYCAABGBAAARggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAACAAAAAgAAAAMAAAADAAAABAAAAAQAAAAFAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAAGAAAAAEAAAACAAAABQAAAAIAAAAJAAAAAgAAAA0AAAACAAAAEQAAAAMAAAAZAAAAAwAAACEAAAADAAAAKQAAAAMAAAAxAAAABAAAAEEAAAAEAAAAUQAAAAQAAABhAAAABAAAAHEAAAAFAAAAkQAAAAUAAACxAAAABQAAANEAAAAFAAAA8QAAAAYAAAAxAQAABgAAAHEBAAAHAAAA8QEAAAgAAADxAgAACQAAAPEEAAAKAAAA8QgAAAsAAADxEAAADAAAAPEgAAANAAAA8UAAABgAAAAAAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAwAAAAOAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAACAAAAAgAAAAMAAAADAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAACAAAAAgAAAAMAAAADAAAABAAAAAQAAAAFAAAABQAAAAYAAAAGAAAABwAAAAcAAAAIAAAACAAAAAkAAAAJAAAACgAAAAoAAAALAAAACwAAAAwAAAAMAAAADQAAAA0AAAAOAAAADgAAAA8AAAAPAAAAEAAAABAAAAARAAAAEQAAABIAAAASAAAAEwAAABMAAAAUAAAAFAAAABUAAAAVAAAAFgAAABYAAAAXAAAAFwAAABgAAAAYAAAAAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAgAAAAKAAAADgAAABIAAAAaAAAAIgAAADIAAABCAAAAYgAAAIIAAADCAAAAQgEAAEICAABCBAAAQggAAEIYAABCWAAABAAAAAsAAAAPAAAAEAAAAAAAAAAAAAAAAQAAAAIAAAAAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQAAAA5AAAAFwAAAAoAAAAEAAAAAQAAAAAAAAAIAAAABAAAAAwAAAACAAAACgAAAAYAAAAOAAAAAQAAAAkAAAAFAAAADQAAAAMAAAALAAAABwAAAA8AAAAAAAAAAAAAAAAAgD8N4Mo/AAAAQHiaFEAHcCVAtKszQAAAQEAN4EpAeJpUQFRnXUAHcGVAAdRsQLSrc0B/CnpAAACAQH/MgkAHcIVABu+HQDxNikDdjYxAqrOOQAXBkEADuJJAeJqUQAFqlkAKKJhA2tWZQJV0m0A/BZ1Ax4ieQAAAoECta6FAf8yiQBYjpEAHcKVA2LOmQAbvp0AEIqlAPE2qQBFxq0DdjaxA9qOtQKqzrkBDva9ABcGwQDG/sUADuLJAtKuzQHiatECChLVAAWq2QCBLt0AKKLhA5gC5QNrVuUAJp7pAlXS7QJ0+vEA/Bb1Amsi9QMeIvkDhRb9AAADAQD23wECta8FAZx3CQH/MwkAIecNAFiPEQLrKxEAHcMVACxPGQNizxkB8UsdABu/HQISJyEAEIslAkrjJQDxNykAN4MpAEXHLQFMAzEDdjcxAuxnNQPajzUCYLM5AqrPOQDU5z0BDvc9A2z/QQAXB0EDKQNFAMb/RQEI80kADuNJAfDLTQLSr00CwI9RAeJrUQBIQ1UCChNVA0PfVQAFq1kAZ29ZAIEvXQBm610AKKNhA95TYQOYA2UDba9lA2tXZQOg+2kAJp9pAQQ7bQJV020AH2ttAnT7cQFmi3EA/Bd1AVGfdQJrI3UAUKd5Ax4jeQLTn3kDhRd9ATqPfQAAA4ED5W+BAPbfgQM0R4UCta+FA4MThQGcd4kBGdeJAf8ziQBQj40AIeeNAXs7jQBYj5EA0d+RAusrkQKod5UAHcOVA0cHlQAsT5kC3Y+ZA2LPmQG4D50B8UudAA6HnQAbv50CFPOhAhInoQAPW6EAEIulAiG3pQJK46UAjA+pAPE3qQN+W6kAN4OpAyCjrQBFx60DpuOtAUwDsQE5H7EDdjexAAdTsQLsZ7UAMX+1A9qPtQHno7UCYLO5AUnDuQKqz7kCg9u5ANTnvQGt770BDve9Avf7vQNs/8ECdgPBABcHwQBQB8UDKQPFAKYDxQDG/8UDk/fFAQjzyQEx68kADuPJAaPXyQHwy80BAb/NAtKvzQNnn80CwI/RAO1/0QHia9EBq1fRAEhD1QG9K9UCChPVATb71QND39UAMMfZAAWr2QLCi9kAZ2/ZAPxP3QCBL90C+gvdAGbr3QDLx90AKKPhAoV74QPeU+EAOy/hA5gD5QH82+UDba/lA+aD5QNrV+UB/CvpA6D76QBZz+kAJp/pAwtr6QEEO+0CHQftAlXT7QGqn+0AH2vtAbQz8QJ0+/ECWcPxAWaL8QOfT/EA/Bf1AZDb9QFRn/UAQmP1Amsj9QPD4/UAUKf5ABln+QMeI/kBWuP5AtOf+QOMW/0DhRf9Ar3T/QE6j/0C+0f9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEh9AAAAAAAAAAAAAAAAAAAAAGRVAAAAAAAAAAAAAAAAAAAmngAAAAAAAAAAAADmsgAAAAAAAAAAAAAAAAwFAAAAAAAAAABkExYBpVwAAAROAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATgjmPgAAAAAAAGU4AAAAAAAAAAAAAAAAAABnaM0IAAAAAGRDAAAAAAAAAAAAAAAAAAAAAAAAJg4AAAAAAAAAAMhZAAAAAAAAAAAAAAAAB0EAAMeFAAAAAAAAAAAAAGa9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM8JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATEwAAAAAxF0AAAAAAABkJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIV4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5nwAAAAAAAAAAAAAAAAAAAAAqlBkCQAAJVGNBkcjAAAEGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp8oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaRomHAAAAADoVcdZAAAAAMkNAABIBwAAAAAAAAAAAAAAACYrAAAAAKklAAAAAAAAaxkAAAAARpBIVKfzAAAAAAAAAAAAAAAAAAAAAAAAZiAAAAAAAAAAAAAAAAAAAGefAAAAAAAA5pnIHwAAAAAAAAAAAAAAAAAAqyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR8AAAAACWQAAAAAAACoA4QOjQxHPQAAAAAAAAAAAAAnzQAA5UMAAAAAAAAAACgFpRYAACVSAAAAAEgZJwMAAAAAAAAAAAAAAAAAAAAAAAAAAOk0AAAAAAAAKA4AAAAAAADqc2R4AAAFegAAxBkAAAAAAAAAAAAAAAAAAAAAAABG+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGVwAARpIAAAAAAAAAAEgcpwEAACRgyVTkRAAAAAAAAAAAAAAAACkHAAAAAAAASAGFFwAAAAAAAAZOAAAAAAAAAAAAAAAAAAAAAAAAp/JSEAAAAAAAAAAARC+pIQAAAAAEQgAARo8AAAAAAAAmigAABsoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGUgAAhvIAAAAAAAAAAAAAphUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJTnIKkdlAAAAAAAAAACJTQAAAAAAAAAAAAAAAAAA6HjmC+o3xjIAAAAAAACkOwAAhp4IdqbyAAAAAAAApE4AAAAAAAAAAAAA5S4AAAAAAACGzAAAAAAAAAAAymAAACwAR4EAAAAAAAAAAAAABGcAAAAAAAAAAAAAxQ4AAAAACEYHJQAAAAAAAAAAAAAAAAAAAAApfsVvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGuMstAAAAAAAAAAAAAAAAAAAAAAAA6Aln1wAAAAAKGQAAAAAAAAAAAAAAAAAAAADm24ouAAARAgAA6HUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFIAAAAACIcOblaVjFAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh/oAAAAASwFkDgAARQYAAAAAAAAAAAAAAAAAAAAAAAAAAApBJQAAAEZcSAxFPAAAAAAAAAAAAAAAAAAAAAAAAAAAq1dFAAAAAAAAAAAAAAAAAAAAAACoRQAAAAAAAAAAAAAAAAAAAAAAAGkrAAAAAAAAAACFRwAAAAAAAAAAAAAAAAAAAAAAAAZoAAAAAKhjJ2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUIAAAAAAACmawAAAADKJAAAAAAAALQNAAAAAAAAAAAAAAAAAAAAAGaUSSRFIQAAAAAAAAAAKgZEBohdAAAAAEQ67TEAAAAAAAAAAAAAAAAAAEkvAADpQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRT6CvGcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIwWAAAAAKRsAAAAAAAAAAAAAAAAAACEIAAAAAAAAAAAAAAAAAAAAAAAAAAAbEGFBAAAAABqScQ/KmWnA40gAAAAAAAAAAAAAAAAAAAAAEZHAACmRgAABrcAAAAAAAAAAAAAAABTAQAAAABkYuwxhi8JGQAAAAAAAAAAhEAAAIRp624AAAAAAAAAAAAAAAAAAIwFAAAAAAAAKCbnzgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABLYkQBAAAAAAAAAAAAAAAAAAAAAAAA5v0AAAAAAAAAAAAAhVUAAAAAAAAAAAAABrkAAAAAAABmAwAAAAAAAGYxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkZeg/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQcAAAAAAADJGQY+AAAAAAAAAAAAAKRxAABkbwAAAAAAAAAAAAAAAAAAAAAAAORVAAAAAAAAxqcAAAAAAAAAAAAAAAAAAAAAAAAAAA0UJgUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxtZIYQAAAAAAAAAAAAAAAAAAAAAAAAAARskAAAAAAAAAAAAAZQ4AAAAAAAAAAE4nxCQAAAAAAADkekwWJRgAAAAAAAAAAAAAAAAAAAAAAADHFQAAAAAAAAAAAAAAAAAAAAAAAAAACGqG4AAAAAAAAAAAAAAAAKwbAADpVYbPAAAAAAAAAADNIAAAAABlFgAAAAAAAAAAAABECAAApmAAAAcsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtBAAACRMAAAAAppUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMRgAAAACFRgAAAAAAAKZjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhkUAAGZmAAAAAAAAAAAAAAAAAAAAAOhZB0SoT6QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKcMAAAntAAAAAAAAKRvAAAAAAAAAAAAAAAAAAAAAAAAxR0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGogAAAAAoeSbYSCeEBwAAAAAAAAAAAAAGjwAAZ48AAAAAAAAAAAAAAAAAAAAAAAAAAKo2p+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFZwAABxYAAAAAAAAAAAAAAABJNuUEAAAAAAAAAAAAAOcTAAAAAAAAxXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxiEAAAAAAAAAAClkhEUAAAAAAAAAAAAAAAAAAAQ0bAKlGCsuAAAAAAAAAAAAAAAAAAAAAAAAiANHBAAApV4AAAAASHAnwgAAJVoAAAAAAAAAAIh+AAAAAAAAAADHiQAARHDqFgAAAAAAAAAAAAAAAAAACREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7R6lIgAAAAAAAGQ2AAAAAAAAAAAAAOajAAAAAAAAAAAAAAAAbhqlNgAAAAAAAIcDAAAAAMpdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIb7AADEVwAABWUAAAAAAAAAAGhcxRQAAAAAAAAAAAAAAADpWUUViT4AAAAAAAAAAAAAAAAAAAAAhrvpKAAAAABEOAAAAAAAAMekAAAAAAAARsgAAAAAailEXgAAAAAAAAAAAAAGqwAAAACqRQAAAAAAAOhjRWoAAAAAAAAAAAAAAAAAAAAAinEAAAAAAAAAAAAAcgLEB2w5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARuEAAAAAAAAAAAAAAAAAAAAAAACmrgAAAAAAAAAACA/HHQAAAAAAAAAAAAAAAAAAAAAAAAAAAACGpQAAAAAAAAAAAAAAAAAAAABISyQZAAAAAIgUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOVMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnmwAAAAAAAAAACHkAAAAAAAAAAAAAAABGbgAAAAAAAGRxKimFDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFkgDJwEAAAAAKCEGIAAAAAAAAAAAAAAAAAAAAAAAAGRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6g9GTAAAAAAAAAAAqHkm+gAAAAAAAAAAAAAAAExBAAAAAAAAAAAAAAAAAAAAAAAAAAAAACpFAAAAAAAAAAAAAAAAxsUAAEfFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZjAAAAAAAABzYAAAAAAAAAAAAAAACICscPAAAAAAAAAADIYgAALC8GCAAAJr8AAAAAAAAAAElCJ+hrQweKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3oAAAAAAABJBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA0cDAAAAAMpyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgWZi8AAAAAAAAAAAAAAAAAAAVjAAAAAAAAAAAAAAAAAAAAAAAAB/AAAAAAAAAAAAAAAAAAAAAAAABmYAAAAAAAAGf3AACkcM4fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI4RAAAAAAAAAAAAAAg3pAQAAIQ/AAAAAAAAJUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAEAAAAApEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMXgVzAAAHgwAAJRMAAAAA6jAAAAAAB/QAAAAAAAAAAAAAAAAAAAAAAAAAAM4PAAAAAAAAAAAGUAAAZDypCAfKAAAAAAAAAAAAAMdbAAAAAAAAAAAAAAAACjwAAOk9AAAJOwAAAAAAAAAAAAAAAAAAAABEbakcAAAAAAAAAACGdgAAAAAAAAAAAAAAAAAAAAArfoRdAABmRQAAAAAAAAAAAAAAACgYAACoUQAAAAAAAAAAAAAAAAAAAAAAAAAABHsAAAAAAACFFQAAAAAAAAAAAAAAAAAAAABtCgbEAAAAAAswAAAAAAAAAAAAAAAAAACJFAduAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOYtMg8AAAAAhGcAAAAAAAAAAAAAAAAAAKbAAAAAAAAAAAAAAAAAAADlKgAAAAAAAAAAAAAAAAAAAAApRicHAAAAAAAAAAAAAAAAAADGcwAAAAAAAAAAaWcAAEgYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMcCAAAAAAAAAAAAAAAAAAAAAAAAAAALcCecAAAAAAAAAAAAAMbJAAAAAAAAh2sAAAAAAAAAAAAAAAAAAAAAi3jEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZHAAACRHAAAAAAAAAABoY6b/AAAAAAAAAAAAAAAACQ2GBgAAAAAAAAAAAACESwAAAAAAAAAAaGEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATBAAAAAAAAAAAxj0AAKZUAAAAAAAAAAAAAAAAAACHPwAAAAAAAAAAAAAAAAAAAAAAAMZ+AACmdwAAAADKTsYmAAAAAAAAR0cAAAAAKDgAAAgIJ0MAAAAAAAAAAAAAAAAAAIQeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMpXRs40BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEkqAAAAAAAAAADmnwAAAAAAAAAAAAAAAAAABXAAAAAAUhYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAll5lYAAAAAAAAAAGhDp4sAAAAAAAAAAAAAAAAAAAAALCAAAGx9AAAAAAAAKwAGOAAAhUAAAAAADHgAAKwPhQAAAIeeywOGXQAAAACLagAAAAAAAMwAAAAAAARqjB0nrchrZuIAAAAAAAAAAEhXZWQAAAAAAAAAAAAAAAAAAERMC3wAAAAAxm0AAOfmAAAAAAAAAAAAAAAAAADlLwAAhq8AAAAAAAAAAEh7AABqKwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJSodHAABnsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHSwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApuQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACLV4ddAAAAAAAAAAAAAAAAqi0AAAAA5Q8AAAAAbArGGAAAAAAAAAAAAAAAAAps5gYAAAAAAAAAAMhaBtsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEeFAACFXwAAAAAAAAAAa1UAAMpEpiYAAAAASG2GlwAAAAAAAIaqAABHe6ovZloAAAAAAACnxAAAAAAAAAAAAAAmgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA58IAAAAAAAAAAKo9pxAAAAAAAAAAAIoS5g4AAAAAAAAAAAAAAAAoQ8UBq0MAAGhPxA8AAAAAAADkPQAAAAAAAAAAqWvEfCh+AAAAAAAAAAAAAAAAAADrLAYuAAAAAAAAAAAKJifFAAAAAAAAAAAAAGaKAAAAAAAAAAAAACZ0AAAAAAAAx44AAAAAAAAAACkk5hUAAAU2AABnGwAAAAAAAAAAAAAnYgAAAABrSgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAoAAAAAAAAAAAAAAABldAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZqUAAAAAAAAAAE0kAADoReba7Q8AAAAAAADLdOeRAABneAAAhiAAAAAAAACmRwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIlIJtMAAAAAAAAAAAAAAAAAAAAAAACGkQAAAADJekbwAADmBwAAAAAAAAAAAAAlYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZQjJYgAAAAAAAAAAAAAAAAAAAAAAAAAA5DBpNwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOQhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIaOAAAAAAAAAACJKoclAAAncAAAAAAAAAAAAAAAAAAAAAAAAAAASm8AAAAAAAAAAEVmKyilBgAAAAAAAAAAAAAAAAAAAAAAAIQ6AABnHgAAxmwAAAAAAACm3DQPAAAAAAAAihbHQAAAxWZuNERPAAAAAAAAAAAAAAAAAAAAAAAARnAAAAAAAAAAAMg4hgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGpQAABA0AAAAAAAAAAAAAAAAAAAAAAACHIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMlDpwUAAAAA6yCGvU8FAAAAAAAAAAAAAIo6AACofQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOJOcKAAAAAAAAAAAAAAAAAAAAAMk+h3utEAAAAAAAAAAAAAAAAKcRAAAAAAhtRuYAAAAAAAAAAAAAAAAAAAAAqSBkTQAAAAAAAAAAqBfFHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoI2UEAACkQAAAAAAAAAAAAAAAAAAAAAAAAAAAjEPGGmhTAABMCQAAAACnDwAAAAAAAAAAAAAlX2oQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHp84LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJTgAAMVQ6AzHCipQh/0AAAAAAAAmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmbPIKpiKuDucEAAAAAAAAAAAAAAAAAAAAAEt1JiUAAAAAAAAAAMhFBzoAAAAAAAAAAAAAAAAAAAAAAAAAAGxbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbJAAAAAAAAAAAAAAAAAACmsgAAAACrW0d+AAAAAEoqB88AAAAAAADGgWh6RvsAAAAAAAAAAAAAAAAAAKZ9AAAAADMPAAAAAAAAaRuFAgAAAAAAAAAAAAAAAAttB7QAAAAAAABnVQAAxoUAAAAAS0EAAAAAAAAAAOQ2qFMAAAAAAAAAAAAAAAAAAAAAppsAAAAAAAAAAAAARpgAAAAAaEQkHQAAAAAAAAAAAAAAAAAAAAAAAEQ8AAAAAAAAAAAAAAAAAADEbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZWMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZy4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMdNAAAnTgAAAAAAAGcqrwMAAAAARSoAAAAAAAAAAEoQAAAAAAAAAAAAAAAAAAAAAAAAbCYAAAAAAAAAAAAAAAAAAAAAAAAAAIf/AAAAAAAAAAAAAAAAAAAAAIkmRmAAAAAAAAAAAAAAR54AAAAAAAAAAAAAAAAAAAAAAAAEMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS1ZnXAAAAAAAAAAAAAAAAAAAxnsAAAAAAADn5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGVfAADEbQAAAAAAACR6AACEDAAAAAAAAAAAAAAAAAAAAAAAAOY5AAAAAAAAAADrTcYnAAAAAAgl5TkuEQAAAADEOAAAAAAAAOe+UQcAAAAAAAAAAAAAAAAAAE0CBQYAAAAAAAAAAAAAJVsAAAAAAABFNwAAAAAAAAAAEAUmOAAApGoAAAAAAAAAAAAAAABsHAAAAAAAAAAAAAAAAGa6AAAAAAAAAAAAAAAAAAAAAAAAAAAsFOUGAABFOAAAxpLKBwAA7BkAAAAAAAAAAAAAAAAAAAAAp2wAAAAAAAAAAAgKpBoAAAAAAAAAAAAAAAAAAAAAAAAAAEgsh2YAAAAAaF0AAAAAAABIdwAAAAAmhgAAh0UAAAAAAACFVgAA5hcAAIRkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6GdGFAAAAAB2BAAAAAAAAAAAAAAAAAAAAABnmgAAAAAAAAAAAABGmgAAAAAAAAAAAAAAAAAAAAAAAAAADQwAAAAAAAAAAAAAAAAAALISAAAAAAAAyXCEGQAAAAAoaAAA6SPHLQAAAAAAAAAAAAAAAAh8hvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhSwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYgAAAADpRsdOAAAAAAAAZkMAAAAAbgMAAAAAAAAAAAAAAAAAAAAAAAAAAGZeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAy2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGh7AAAAAOcfKl9EGAAAxocAAAAAAAAAAAAAAAAIfwAAAACHrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARUbpISZyAAAAAAAAAAAAAAAAAAAAAAsoJhOsBWc7AAAAAAAAAAAAAAAAAAAmWQAA5SgAAAAAAAAAAAAAAACJSwZFawDmLAAAAAAAAAAAqWoFCgAAAAAAAAAAAAAAAAAABvzIAOVuAAAAAAAAAADoeQAAKngAAAAAAAAAAAAAiXJm7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACJDKUMyjCHWAAAAAAAAGVJ6HoHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmUAAAAAAAAGZqAAAAAAAAAAAAAEQ+iBEnGwAAAAAAAAa1AAAAAAAAAAAAAAAAAAAAAAAAJXEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaFAnDQAABmMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWBwAAAAAAAAAAAAAAAAAAAAAAAAAA5UIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH2gAAAAAAAAAAAABFXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHELAAAAAKbDAABmCwxjZHVzAEYuAAAAAAAAAADwCwAAAAAAAAAA50TvAGdNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMaPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADnUwAAAAAAAAAAAAAEbwoupBIAAAAAKA3HjQAA53oAAAAASTnkAwAAZlAAAAAAAAAEJwAAhVwAAAAAAABHzQAAAAAAAAAAAAAAAAAAhB0AAAAAAAAAAAAAAAAAAGcHiggAAAAAAAAAAAAAa2xnYwAAAAAAAAAATHkm9wAAAAAAAAAAAAAAAAAAho8AAORgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASHkAAAAAAAAAAAAAAAAAAAAAAAAqU+QIAAAAAAAAAABrZwAAAAAAAAAAAAAAAAAAAAAAAAAA5DsAAAAAAAAAAAAAAAAAAAAAaAznSwAAAAAAAAAAAAAAAAAABvUAAAAAAAAkYwAAAADrbCQFAAAAACwexwsAAAAAAAAAACkaAAAAACa7AAAAAAAAAAAAAAAAAAAAAAAARQwAAAAAAADkOQAAAAAAAAAAbiQAAAAAAAAAAAAAAAAAAAAAAAAAAAV7AAAAAAAAAAAAAKYZAAAAAAAAAAAAAAAAqRlEBQAAJmQAAAAAAAAAAAAAZE8AAAAAq0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZC4AAEagAAAAAAAAJWcAAAAAAAAAAAAAAAAAAAAAAACnLOltZjoAAKcnAAAAAAAAAAAAAAAAAACGcwAAAAAAAAAAKGpm4AAAAAAAAAAA6m/m4GsFAAAAAAAAAAAAAAAAAAAAAAAAAACH4wAAAAAAAAAAAAAAAAAApUEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGDQAApT0AAMQVKDQAAAAAAAAAAAAA6UinWwAAAAAAAAAAAAAAAC085RoAAAAAAAAAAKg7AAAAAAAAAAAAAAAAAAAAAIUmAAAAAAAAAAAAAAAAAAAAACglxQ8AAAAAKy3nwQAAAAAAAAAAAAAAAOhs5uEAAAAAAAAAAAAAZ6MAAKRVAAAAAAAAAAAAAAAAAAClYwAARmsAAKVGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASjaEH0lnAAAAAAAAAAAAAAAA5GIAAAAAAAAAAKo/5RxKFidLAAAAAAAAAAAAAAAAAAAAAHAF58YAAAAAAAAAAAAAZ9IAAAAAAAAAAKsFAAAAAAAAAAAAAAAAAAAAAAAAAAAHjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIlFxT0AAMQxAAAAAAAAx4AAAAAAAAAAAAAAAAANFQAAAAAAAAAAAAAAAAAAAAAAAAAAp3kAAERQAAAAAAAAAAAAAAAAAAAAAAAA5skAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABNL0dKAACniAAA5FQQDgAAAAAAAAAAhrqIQ8erSVnHuQAAAAAAAAAAKGfmvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABncAAAAACFzlEQAAhFcAAIbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACnwgAAAAAAAIVry3sHAAAAAADrZAAAAAAAAAAAAABpEGVAAADEUAAAAAAAAAAAqQ4HW4g/Jg8AAAAAAAAAAAAAAACqLAAAAAAAAAAAAAAAAKUdAAAAAAAAAAAAAAAAAAAAAAAAB98AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJFmKKwbAAABHXAAAAAAAAAAAAAAAAAAARTYAAAAAAAAAAAAAAADKLafq6gQAAAAAAAAAAAAAAACESAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApbQAAAAAAAAAAZxUAACZOyERnDewq5HUAAAAAAAAAAAAAAAAAAAVgDgAAAAAAAAAAAAAAAADkYwAAAAAAAMRvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACfRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIaDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiIAACQ3AAAAAHQAJAEAAAAAAADHkwAARqgAAAAAAAAAAAAAAAAAAAAASFUAAAAAhn0PAwAAAAAGeQAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALBcAAAAAAABJSEc7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4ORUIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFRQAAAAAAAAAAAAAAAAgCpqQAAAAAMgwAAAAAAADqVwAAAAAAAAAAAAAAAAAAAACGbwAAAAAAAGbEAAAAAEk1RhcAAKaJAAAAAAAAAAAAAAAAAAAAACl1JEkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAItQZyQAAAAAAAAAAKldAABJFAAAAACkLwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGXwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIlOpQIAAAAAAAAAAAAAAAAAAAAA63IAAAAAAAAAAAAAAAAAAAAAAAAqTwAAAAAAAAAAhykAAAAAAAAAAAAAAAAAAAAAAAAnugAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGjIMQAAqFAAAAAAAACwAQAAAAAAAAAAAAAAAAAAAAAAAAAAhgIAAARkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAm+QAAAAAAAAAAKGAAAAAAAAArUwAAAAAAAAAAAAAAAAAAAAAAAAAARrIAAAAAAAAAAIsHAAAAAAAAKVBH6gAAhlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACn2wAAAAAAAAAAAAAndQAAh84AAMZRAAAAAAAAAAAAAAAAAADnQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARRwAAAAAAAAAAAAAxrkAAAAAAAAAAAAAAAAAAAAAAAAAAAAApigAAAAAAAAAAAAAAAAAACaoAAAAAHILAACIMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKV5AAAAAAAAAAAAAAAAAAAHkwAApEQAAAAAAAAAAAAAAAAAAAAAAAAAAAh6AAAAAAAAAAAAALACAAAAAAAAAAAAAHAGAAAAAAAAAABHJwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkgAAAAAAAAAAAAAAAAAAAAAAAADJGMcAAACmiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB94AAAAAAAAAAAAABr8AAGQ0AAAAAAAAAAAAAAAAAAAAAIkJRBEAAAAAAAAAAMxPpQMAAAAAAAAAAAAAAAAAAEexAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxtUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMQuUCAAAAAAAAAAAAAAAAAADFawAAAABKdgZKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyAgAAAAAAAAAAAAAAAAAAAAAAACJZQAAAAAAAIsJAAAAAIZ7AABGNwAAAAAAAAdwAAAAAAAAAAAAAAAAaDwAAAAAAAAAAKbVAAAAAAAAAAAAAAAA8w4AAAAAAACsDgAAqSYAAAAAAAAAAAAAikoHegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEYAAAAAAAAAAAAAAAAAAAAAAAAMRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOlrAAAAAAAAEAMnEox/AAAAAAb4AAAAAAAAAAAAAAAAAABGUgAAAAAAAAAAAAAAAAAAAAAAAAAATA1m5AAARX4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMpI5QoAAAAAAAAAAAAAAAAAAGQhAAAAAAAA5VcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACT4AAAAAAAAAACeMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKh8kRgAAAAAAAAAAAAAAAAAABF8AAAAASRMAAAAAAADoHwAAbDRkKAAAAAAAAAAAAAAELgAAAAAAAAAAAAAAAAAAAAAAAAAASEEAAAAAAAAAAAAAAAAAAOhER0YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiQsAAAAAAAAAAAAAAAAAAIwjpkEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMt3AAAAAEVKAAAAAAAAAAAAAAAAzQDmOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxBwAAAAAAAAAAAAAAAAAAiGYmzQAAhsIAAAAAAAAAAAAAAAAAAMQlAAAAAAAAAAAAAIYSAAAAAIlUAAAAAAAAAAAAAAAARtEAAAAAAAAAAAAAAABLFgAAAAAAAAAAAAAAAAAAygumMAAAAAAAAAAAaAsGAQAAAAAAAAAAAAAAAAAAAAAAAAAACQ4AAAAAAAAAAAAAAAAAAAAAAAAAAGZdAAAAAAAAAAAAAAAAAABH2gAAAAAAAAAAAAAHAwAABqnKE0e/AAAAAMpZRRALIyavAAAAAAAAAAAAAEfzEAEAAAAAAAAAAObIAAAAAAAAAAAAAAAASm4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJTQAAAAAAACnxylPJTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJAkYdAAAAAAAAAAAAAAAAAAAAAAhVx/MAAAAAAAAAACsfpgAAAAAAAAAAAAAAAAAAAAAAAAAGmAAApt0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqD+HFgAAAAAAAAAAAAAAAAAARH0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGR0AAAAAAAAAAAAAAAAAAAAAGxd53UAAKflAAAAAAAAAAAAAAAAAAAmUAAAAAAAAAAACSMAAAAAAAC3AAAAAAAAAAAAAAAKCSVEAAAAAAAAAAAAAAAAAAAAAAAAxFwAAAAAyx/nEgptAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJnMAAAAAqEAnaAAAB9IAAAAAiDZnHwhJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4DhT4AAAAAAAAAAAAAAAAAAAAAchjm3UhApzAAAAAAAAAAAAAAAAAAAORcAAAAAAAAAAAAAAAAiyQAAAAAAABpHGegzGCm4QAAAAAAAAAAAAAAAAAAAAAAAAAA7A4lCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApcsbuAAAAAAAAR+RLPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEaRiFfHAwAAAAAAACZa6mgAAAAAAAApTQAAAAAAAAAAAAAAAAAAAAAAACgVhjUAAAAAAAAAAAAABs6qT6eWAAAAAAAAh8cAAAAAiABEIQAAAAAAAAAAAAAAAAAAAAAAAAAAAADEawAAAAAAAAAAAAAAAAAAAAAAAAAAEwIAAAAAAAAAAAAAAAAAAAAAAADoIqcT6DCGSwAAAAArWSd2qm2keQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABpa+RGiE7H5gAAAAAAAAAAAAAAAAAAAAAAAEVfAAAAAO0XAAAAAAAAAABFJQAAAADpX6dxAAAAAAAAAAAAAAAAAABkYwAAAACrJQAAAABH9gAAAAAAAAAAAAAAAAAAAAAAAIaaAAAAAAAAAAAAAAAAjFAnLvMBAAAIFOYIAAAAAAAAAAAAAOa0AAAAAAAAAAAAAAAAAAAAAOpb5pyICQAAAAAAAAAAAAAAAAAAAAAAAAAARjsAAAAAAAAAAAAAAAAAAAAAAAAAACppAAAAAAAAAAAAAAAAAAAAAAAAAACGaAAAAAAAAAAAAADHygAAAADsWwAAAAAAAAAAJsiJZMatTjEAAAAAAAAAAAAAAAAGDAAAJSQAAAAAaAQHVgAAAAAAAGZTAAAkQAAAAAAAAAAAAAAAAAAARv4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEWAAAhr4AAMeGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARSYAAAAAAAAAAAAAAAAAAOU1AACHlQAAAADKBgAA6QEHtQAARrEAAAAAAAAAAAAAAAAAAAAAAABmcQAAAAAAAAAAAAAAAEwY5twAAAAAAAAAAAAABWkAAIZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIazAAAAAAAAAABJUAfDAAAAAAAAAAAAAAAAywtGMAAAAAAAAAAAAAAAAAAAAAAAAAAAy2cHNAAAAACNAmdbAAAAAAAAAAAAAAAAAAAAACxXAAAAAMRSAAAAAAAAAAAAAAAAAAAAAAAApGsAAAAAAAAAAAAAAAAAAOZs61MFbAAABXTtAAAAiCkAAAAAAAAAAOaDAAAAAAAAAAAAAAAAS3sAAAAAAAAAAAAAiAWHCQAAAAAAAAAAAAAAAAAAAAAAAAAAiyUAAAAAAAAAAAAAAAAAAOsVxUDpZ4aKAAAAAAAAhGgAAIfnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaGmG4QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyh4AAAAAAABITEUZAAAAAIkEAAAAAAAACB7HUakBAAAAAAAAAAAAAAAAAAAAAOcwAABmMgAAAAAAAAAAAAAAAAAAAAAAAAAAawkAAM0t5mUAAAAA6U4AAAAAAAAAAAAAAAAAAAAAJSsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHdwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlVHUExlIAAOQjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALgARQQAAAAAAAAAAAAAAAAAAAAA6hIAAGg1AAAAAMYvAAAAAAAAJCkAAAAA6SIAAAAAAAAAAAAAAAAAAAAAAAAAAERxAAAAAMgtZmkAAGa0AACHqwp8AACIBGQPAAAkUQAAAAAAAAAAAADlXwAARn8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZXwAAAAAAAAAAAAAAAAAAAYJDC4AAAAAJ6gAAAAAAAClSQAAAAAAAAAAAAAAAAAAAAAAAIb4AAAAAIgbpkMAAAAAAADFVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8EhxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKUvAAAAAAAAAAAAAAAAAAAAAAAAhrUAAAAAGAAHTQAAAAAAAAAAAAAAAAAAAAAAAKeZAAAAAAAAAAAAAAAAAAAAAAAAAABpUwYPAAAAAAAAAAAAAAAAAABHjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAELAAAAAAAAAAAAACmJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5nQAAEaDAABkEgwLAAAAAGdzAAAAAAAAAAAAAMV0AAAAAAAAAAAAAAAAAAAAAE8OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqCrHGwAAAAAAAAAAAAAAAAAAAAAAAAAAqCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkTwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOaQAAAAAAAA5mkAAAAAAAAAAAAAAABpVQAAaWwGdgAAAAAAAAAAAAAn4gAAAAAAAAAAAAAAAAAAAAAAAAAAaDFGFQAAAAAAAAAAAAAAAAAAAAAAAAAASE3kQgAAJ8sAAAAAAAAAAAAAAAAAAAAA9gIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEYQAAAAAAAAAAAADEBQAAB/4AAAAAtQRHtgAAR3VpLUYEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEonAAAAAAAAAAAAAAAAJ28AAAAAAAAAAAAAAAAAAAAAAAAAAAAAxDkAAAAAAAAAAKhBAAAAAOYCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIRUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASD6nWgAAAAAAAAAA9wAAAAAAAAAAAKdgAAAAAAAAhBQAAAAAAAAAAAAAAAAAAAAACXXkSGtSx7YAAIUbAAAAAAAAAABrZAAAAAAERPQOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKsWBRYAAAeVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx+oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUDAAAAAAAAAAAAAAAAB3YAAAAAAAAAAAAAAAAAACUiAAAAAAAAAAAAAOZqAAAAAAAAAACrAOYPAAAAAAAAAAAAAAAAAAAAAAlexhwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACICEUUAADEUQkGhBMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKkYAAAAAAAAAAAAAAAAAABqeAAAAAAAAAAAAAAAAAAAAAAAAAAAR2sAAAAAAAAAAAAAAAAAAAAAAAAAAIhUR/cAAAAAywyHeQAAAAAAAAAAAAAAAAAAJC0AAKQ5AAAAAAAABDsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAal0mcQAAAAAAAGUTAAAAAAAAAAAAAAAAAAAAAAAAAADoJ2cUAAAAAAAAAAAAAAAAAAAAAAAABmoAAAAAlQTmTgAAAAAAAAAAAAAm3QAAAAAAAAAAAAAEEgAAAAAAAAAAAAAAAAAAAAAAAAAALi4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABpReYeAAAAAIh8AAAAAKcXAAAAAAAAAAAAAAAAAAAAAAAAAAAKIwAAAAAAAAAAAAAAAAAAAAAAAAAAAADIQUddAAAAACsrAAAAAAAAKH8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqUYU1AAAAAAAAR5HNHOcoSkQEYwAAAAAAAGaWAAAAAAAAAAAAAAAAAAAAAAAABVSqFwAAAAAAAAAAAAAAAGUMAAAAAAAARyUAAAAAAAAAAAAAAABoRaQxAAAAAAAAAAAAAKaQAAAAAAAAAAAAAAAAAAAAAAAAAADMMWe+AADGLQAAAABqYgAAAAAAAEkjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKQTAACmdQAAAAAAAAAAAAAHpwAAAACIDgAAAAAAAAAAAAAAAGZiAAAAAAAAAAAAAAAAAAAAAAAAAABKFQUUAADm4gAAAAAAAAAAAABEbAAAAAAAAAAAAAAAAAAAAAAAACRWAAAAAAAAAACJZgAASz6EDQAAAAAAAOaLAAAAAAAAhR4sTKd9AAClSAAAAAAAAAAAAADkbwAAAAAAAEftAAAAAAAAAAAAAMRzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEQw0+xiSqJQAAAAAAAFECAAAAAKReAAAAAAAAAAAAAOadAACEZgAARVoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIb9AAAAAAAAAACLD2fqAAAAAAAAJ24AAAAAAACGqAAAAAAAAAAAAAAAAAAA5nEAAER3AAAAAAAAAADIMwAAAAAAAAAApUAAAAAAAAAAAAAABGYAAAAAAAAAAAAAAAAAAAAAKVkAAAAAAAAAAAAAAAAAACkEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKUrFEgAAAAAAAAAAAAAmRQAAAAAAAAAAAAAAAAAAAAAAAAAAjA0AAAAAAAAAAIc0AAAAAAAAAAAAAAAAAAAAAAAAAAAAACfeAAAAAPAGpD0AAAAAKwoAACgohnoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASC0HDgAARAkAAAAAAAAAAAAAAAAAACROAAAAAAAAAAAAAAAAKC8GAgAAAACoBycjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoc54AAAAAAAAAAAAAAAABpBgAAAAAAAAAAAAAAAAAAbBqlJuoBpQ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKpipRUAAOU2MgEHUQAAAADOJAAAAAAAAAAAAAAAAAAAyS4EAQAAZ4kAAAAAAAAAAAAAAAAAAOVHAAAAAAAAxkAAAAAAAADGVwAAAAAAAAAAAAAAAOgKAAAAAAAAyjYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjpFDwAAAAAAAEfhAAAAAAAAAAAAAAAAaz4AAAAAAADqCoc7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGluIwAAAAAAAAAAhsoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK0wHkQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFS24ohi4AAAAAAAAAAOs6RFoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKo7B6MAAMbdAAAAAAkLAADJNoUBAAAAAAAAAAAAAAAAAAAAAOpTpnwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6E/GAgAAAADIYSVVAAAAAAAAAAAAAAAAAAAAAAAAAACrfgRTAADGdQAApqgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACLLAAAAAAFBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7BokJAAA5vaoDUY4AAAAAAAAAAAAAAAAAAAAAAAAAAAoWAAAAAAFUwAAAAAAAAAAAAAAAAAAx5oAAAAAzScAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl4BuoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6QwAAAAAAAAAAAAAAAAAAAAAAADsHSdhAABGAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO0uxDMAACcCAAAAAAAAx6gAAGd3AAAAAAAAAAAAAAAAAAAAAOpuBHgAAAAAAAAAAAAAAAAAAAAAAAAAAIlYxVgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5nIAAAAAAAAAAMo+BiP1AKUFAAAAAAAAAAAoYQAAAAAAAAAARDMAAMeKAAAAAAAAAAAAAAAAyzOlKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2IAAAAAAACENgAAAAAAAAAAAAAAAAAAZ9WpTCYvCwwAAAAAAAAAAGQ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGVQAAZzyKcgAAAAAAAAAAAAAAACZ1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGVcAAAAAAAAAAAAAAAAAAAAAFMKAAAAAOdSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIQAAAAAAAAAAAAAAAAAAAAAOaHAAAAAAAAAAAAAAAAAADnPgAAAAAAAAAAAAAAACkBJA4KDYQoAACHOQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADkdMlXRzapPMd+qnbkNAAAh3AAAAAAAAAAAAAAAAAAAEb8zEcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGlgAAAAAAAAAAAAAAAAAAAADUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGfwAAAAAAAAAA7hEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKf9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaEEAAAAAAAAAAAAAAAAlTgAAAAAoNacEAAAAAAAA5/IAAAAAAAAAAAAApF8AAAAAAAAAAAAAAAAAAAAAAAAAAOtEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBUAAAAASH4AAAAARvkAAAAAAABnCwAAAAAAAAAAikIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh+sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKHuYBAAAAAAAAZpkAAMa/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA51FJRmcxAAAAAAAApD5ofwAAAAAAAAAApj9rIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZokAAAAAAAAAAAAAAACKdgAAAAAAAAAAAAAAAAAAzTlEDgAAAABMIIYyAACm1gAAAAAAAAAASAqnhAAAh1oAAAAAAAAAAAAApo0AAAAAAAAAAAAAAACsfyZpAACkfwAAAAAAAAAAAAAAAAAAAAAAAAAACT2nLrYEAAAAAAAAAACERgAAAAAAAAAAAAAmQAAAAAAAACRnAAAAAGlwAAAAAEZhAAAAAJgBJ7EAAIeLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEoOJkQAAKUAAAAAAAAAAAAAAAAAAAAHGAAAAABoXwAAAAAAAAAAAAAAAAAAal7lXgAAAAAAAAAAAAAAAAAAAAAAAEcuAACnmgAAAAAAAAAAAAAAAE0l5AoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPIDAAAAAAAAAAAAAAAAx2XsewAAqV4kBwAAAAAAAAAAAAAAAAAAAAAAAIRDAAAAAAAAAAAITAAAAAAAAAAAAAAAAAAAAADEfgAAAAAAAMdwAAAAAAAAAAAoRYfQAAAAAAAAAAAAAAAAAAAAAAAA5EWSBwAAAAAAAAAAAADqPwAAAABlVAAAAACLEwAAAAAAAAAAAAAAAKVYAABGVwAAAAAAACbaAAAAAAAAAAAAAAAAAAAAAAAARVkAAAAAAAAAAAAAAAAAAAAAyBkHAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEYQAAAAAAAAAAAAAAAAAAAAAAAAefAAAAAAAAAAAAAGaEAAAAAAAAAAAAAAAAyDIAAAAAAAAAAAAAAAAAAAAAAAAAAGR2AAAAAAAAAAAAAAAAChUAAAAAAAAAAAAAAADEbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATEUAAAAAAAAAAAViiHEAAAAAAAAAAAAAAAAAAIgxxiwAAAAAAAAAAAAAAAAAAAAAVACHHAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkackBAACMWYbjSEoAAC4Kh7IAACUUAADEYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARCAAAAAAAAAAAAADKfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGaCAAAGuwAAAAAAAAAAAAAAAAAAAACsYQAAAAAAAAAAAAAAAAAAKWZGiwAAx+LMdwAAAAAAAAAAhGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaBEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiB1nUAAAAAAAAAAAAAAAAAAAAAAAAIaSAAAAAAAAAAAAAAAAAAAAAAAARqcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxQYAAAAAAAAEIAAAAADpKwAAbHem6wAApToAAAAAAADGngAABF0AACYnAAAAAAAAAAAAAAAAAAAAAEoyJ3kAAAAAAAAAAAAAAABIBgAAAAAAAAAAhEcAAAAAAAAAAOppAAAAAAAAAAAAAAAAAAAIH2YFAAAlLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxV8AAGUtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMZUAAAAACwzRiBUCiUfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQQlMQAAhWIAAAAAAAAmoK0/B/YAAAAAAAAAAO8EZiQAAAAAAACmSQAAAADNBmeEAAAAAAAAAAAAAAAACWcAAAAAAAAAAAAAAAAAAAAAAAAAAKV9AADHxwAAAAAAAAAAAADkcgAAAAAAAAAAAAAAAAAAAACKBoYQAAAAAAAAAAAAAAYpAAAAAAAAAACpFQAAAAAAAAAAAAAzCGawAAAAAAAAAAAAAAAAAAAAAAAAAABNNwAAS2kAAAAAAAAAAAAAAAAAAAAAAADIQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqmlGGgAAAAAAAAAAAAAAAAAAAACKbwAAAADmGwAAAAAAAAAAKEIAAAAAAADpZAAALxFEGwAAhrQAAAAAAAAAAAAAhimsUgAAAAAAAAAAAAAAAAAAjgmnvQAAAAAAAAAAAAAAAAAAAAAAAAAAAABFNAAAAAAAAAAAAAAAAAAAAAAoPGcvAAAAAAAAAAAAAKYSSgIAAAAAAAAAAAAAAAAAAAAAx1wIJsQRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6WOnc2oYZQYAAAAAAAAAAAhWAAAAAAAAAAAkVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACaS7F0AAAAAAACKOCd0AAClGwAAprMAAAAAAAAAAGh3Z5wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGGAAAhBAAAAAAAAAAAAAAJ2wAAAAAAAAAAAAAAAAAAORfCVRGBQAAAAAAAEeDAAAAAAAAAAAAAAAAAAAAAAguhgUAAAAAAAAAAAAAAAAAAERHrAMAAAAAAAAAAAAAAABmHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEVBAAAAAAAAAAAAAAAAAAAnvwAAAAAAAAAAAAAAAGxcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGbQAAAAAAAAAAAAAAAAjBDmPwAARhEJGoR/AAAAAOgCpEYAAAYrAAAAAAAAAAAAAERzAAAAAAAAAAAAAAAAAAAGHgAAAADpM2YVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgyAAAAAEZe7QOEWQAAxXpoWwAAAAAAAAAAAAAAAAAACG8AAAAAAABqZOVpAAAAAOlmAAAAAAAAAAAAAAAAJmIAAAAAWAAAAAAAAAAAAAAAAAAAAIhCAAAAACdVAAAAAEwnAAAIMIRVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKVHnNwAARuPofQAAKigAAEkIBy0AAAAAAAAlMAAAAAAAAAAAAAAAAAAAhHAoCcUfAAAAAAAAAABoVef0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADTCgAAAACkWgAAAAAAAAAAAACGGAAAAAAAAAAAAADlZwAAAAAAAAAAaFoAAAAAAAAAAAAASHxmTgAAAAAAAAAAAAAAAAAAAAAAAAAAiF9GCAAAAAAAAAAAqhmEBAAAAAAAAAAAAAAAAAAAxnYAAAAAAADkbvQNAAAAAOdnijCmFAAAAAAAAAAAAABnEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKYWdeAAAAAAAAAABJcEYSAAAAAAAAAAAAAAAAAACkBewAAAAAAAAAAAAAAAAAAAAAAORLAAAAAAAAAAAAAAAALAgAAAAAAAAAAAAAAAAAAAAAAAALCwAAAAAAAAAAAACpTQRLAADlLQAAAAAAAAAAAAAAAAAAJkYAAOZFAAAmSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADmIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlSpEwAAAAAAAAAAR1kAAAAAAAAAAAAABjkAAKVzAAAAAAAAAAAAAAAAAAAAAGkCAAAAAAAAAAAmuAAAAAAAAAAAAAAAAAAAAAAAAAAAKw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALEI5zkAAAAATQomGE4A5joAAAAAAAAAAChPAAAAAAAAAAAAAAAAh48sEAeuyENnZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMg2AAAAAAAAAAAAAAAAZG0AAAAAAAAAAAAApB0AAAAAAAAAAAAAAAAAACcIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbEYAAAAAAAAsAYQ3AAAAAGoFh50AAAAAAAAAAAAAAABqeQAAAABmVwAAAAAAAAAAAACGiwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKRnTB4AAAAAJkoAAAAAAAAAAAAAAAAAAAAAKBmHBAwcAAAAAAAAAAAAAAAAxrIAAMbhAABkQQAAAACSGibsAAAAAAAAZmcAAAAAAAAAAAAAZv8KEUYeAAAAAAAAAAAAAAAAiCOHEk4BAAAAAAAAAAAAAAAAJpwAAAAAAADkZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANMLAAAAAAAAyD0AAAAAAAAAAAAAAAAAAAAAx7wAAAAAAAAAAAAAAAAAAAAAAAAAACg/R6MAAAAAil+FIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADn1AAAAAAAAAAA6ROEeOhIAAAAAAAAAAAAAAAAZEAAAAAAyWoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmjAAAAAAAAAAAAAAAAAAABBEAAAAAAAAAAAAAxt4AAAAAiQXnoAAAAAAAAAAAAACFWwAAAAAAAAAAKCfnVAAAAACOJwAAAAAAAAAAZkoAAAAAAAAAAAAAAAApXmYSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKhEAAAAAAAAAAMUzAABH3AAAAAAAAAAAAAAAAAAAAAAAAAAAAADmSgAAAAAAAAAAAAAAAAAAAAAAAKbaAAAAAAAAZssAAAQ9AAAAAAAAAAAAAGQKAAAAAAAAAACMVAAAAADnzAAAAAAAAAAAAAAAAAAAAAAAAMYiAAAAAAAAAAAAAAAALAwAANABpocAAAAAAAAAAAAAAACrYYcwAAAkamgHpxwAAAAAAAAAAAAAZosAAAAAAAAAAJANAAAAAAAAAACGVwAAAAAAAAAAAAAAAAAAAAAAAMawAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEUipcZ4EAAAAAAAAAAAAAAAAsQUdWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACiIAAAAAAAAAAAAAAAAAAAAAAAAAAAbaAAAAAAAAAAAAAAAADRCkWwAAAACqIgAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIdab3FgUAAAAAAAAAAAAAAAAAAAAA5mAAAAAAAAAAAAAAAAAAAAAAAABHJgAAAAAAAAAAAAAAAAAAZXoAAAAAAAAAAAAAZUwAAAAAAAAAAAAARRYAAAAAAAAm9gAAAAAAAAAAAAAAAAAABlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEMAAAAAAAAMa8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKc9AAAAALIEAAAAAAAAAACGWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgwnwAAAAAALFSU7AAAAAAAAJQ0AAAAAAAAAAGxOxTYAAAAAAAAAAAAAAAAAAAAAAAAAAHgBBp0AAAAAAABHywAAZGEAAAAAAAAAACgDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQmAAAAAAAAAAAAAKdcAADkUwAAAAAAAAAAKFHHEgAAAABpDCZBAAAAAG4AZSoAAAAAAADmQwAAAAAAAAAAAAAAAAAAAAAAAMapAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMHWYTAAAAAAAAAAAAAAAAAACGywAAxF8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKdnAAAAAAAAp7QAAAAAAADFPAAAAAAAAAAATABnzAAAAAAAAAAAykUAAAAAAAAAAAAAAAAAAAAAAAAAAKa2AAAAAAAAAAAAAOVKAAAAAAAAAAAAAAAAAAAAAAAABqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACpCwAAAAAAAAAAAAAAAOY3AAAAAE0IB7MAAAAAAAAAAAAAAABuJgAAqzMkTAAAAAAAAER0AAAAAAAAAACuAmV1AAAAAAAAAAAAAEV4iwBlUQAAAAAAAAAA9gFlSAAAAAAAAAAAAACnSgAAAAAAAAAAAACkegAAAAAAACREAAAAAAAAAAAAAAAAAADGwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZCYCAAAAADECAABqcQAAAAAAAMgNAAAAAAAAswZFORIA5/cAAAAAAAAAAAAAAAAAAAAAAAAAAGo3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIpzhuYAAAaaAAAAAAAAAADKCORAAAAkfAAAAAAAAAAAAAAAAM4BR0IAAGVxAAAAAAAAAAAAAKZbAAAAAAAAAAAAAAAAAAAAAOgGAACJF2ZCDAcAAAAAptMAAAAAAAAAAAAAAAAAAAAALDcAAAoYBnQAAAAAAAAAAAAAJB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKe+AABkIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAtFwAACTpnyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAni4kjB1oAAAAASFoAAAAAAAAAAAAAtgEAAAAAAAAAAAAAAAAAAJcAJiRuBQAAAAAAAAAAAAAAAMfTAAAAAAAAAAArGAAAAAAAAAAAJzMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKJgAAAADm6AAAAAAAAAAAAAAAAAAAAAAAAMZiAAAAAChdRX0AAAAAAAAAAAAAAAAAAAAAAAAnJIsIpju1AQAAAAAAAAAAAAAAAAAAAAAAAAAAJUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5C0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZCAAAAAAAAAAAAAAAAAAAAAAAAxFZJB4dEAAAAAAAAAAAAAAAA7FUAAAAAAAAAAKfaAAAAAAAAAAAAAAAAAAAAAIp9pFIAAAAAAAAAAAAAAACpNwAAAAAAAFQJAAAAAAAAAACnGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARmgAAAAAqxcH0QAAAAAAAAAAAAAAAAAAhsEPGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADATkXQAAxQkAAAAAAAAAAAAAAAALREfIMQ0mOwAAAAAAAAAAAAAAAI8TpvMAAGfeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZfAAAAAAAAAAAAAAAAAAAAAK4DAAAAAAAAAAAAAAAAAAAAAAAAAABnbgAAAAAAAAAAAAAAAAAABj0AACVNAAAAAEsGAADLVse9KWIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREQAAAAAAAAAAAAAAAAAAAAAAAAAANECAAAAAAAAAAAGfwAAAAAAACVIAAAAAAAAAAAAAAAACBfndEkOBloAAAAAjgwAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAAAAAADoC8cBAAAkeQAAAAAAAAAAAAAAAAAA5loAAKV/AAAAAAAAAAAAAMaUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkEwAAAAAAAAAAAAAAAAAAAAAAAMVjAABkSQAAAADoVkcFAAAm8awRpXcAACc68gCHcQAAAABIOIUSAAAAAAAAxpEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqHwAAa30AAAAAAAAAAAAAAAAAAAAAAAAAAAAAyQUAAAAA5G0AAMZkAACH6QAAAAAAAAAAAADG5gAAAAAAAEZbAAAAAAAAAAAAAAAAAACneAAAAAAAAAAASD8AAAAAAABPAQAAAAAAAMoCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKeAYlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZJAAAAAAAAAACXAgAAAAAAAAoEx3oAAAAAAAAAAAAAAAAAAAAAAAAAAKh1AAAAAAAAAABlNgAAAAAAAAAAAAAAAOgIZjQAAAAAAAAAAAAAAAAMVodcyQsnKwAAAADqVMZIAAAAAAAAAAAAAAAAAAAmdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGlDAACIVSf5AAAAAAAAZlIAAOZIAABkZAAABVgAAAAAAAAAAAAAxRioFmcrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJzyqMmUZAAAAAGsMRmcAAAAAAAAAAAAAAAAAAIY9AAAGMwAAAAAAAAAAAAAAAAAAAAAAAAAAjgAAAAAAAAAAACRTqSsnEQAAAAAAAAAAi0zHngAAAAAAAAAAAABlLgAAAAAAAEdnAAAAAAAAAAC3Aua/S2vELgAAAAAAAAAAAAAAAOkmAAAAAAAA6nsG9gAAAAAAAAAAyT3mzQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJmAAAAAAAAAAAAAARlAAAAAAqhNmDwAAAAAAAGezAAAAAAAAAAAAAAAAAAAAAAAAAAD0CQAAAAAAAAAAAAAAACayAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABNDSYxyzxH0wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIpeBRcAAAAAAADGrAAAAAAAAOUVAACmugAA5n0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAZhsAAAAAAAAAAGhAZwwAAGVqAAAAAAAAAAAAAMafAAAAAAAAAAAAAAAAAAAEfcp6AABIXwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADKcWbjAAAAAAAAAAAAAAAASnEAAAAAAAAAAAAAAAAAAAAAAAAAAEbYAAAAAAAAAAAAAAAAAAAAAAAAAAAAACaUAAAAAAAAAAAAAAAAAAAAAAoFAAAAAAAAaRIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAExRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwfGAwAAJEUAAAAAjgKlSgAAx8kAAAAAAAAAAAAA5igwBgAAAAAAAAAAAAAAAAAAygkAAAAAR2LPEAAAAAAAAIsBBz4AAAAAAAAAAAAAAAAAAAAAAAAAAEgFhxkAAMRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAByEuUeAAAAAAAAAADIdQAAAADm/AAAAAAAAAAAAAAAAGkIpSMAAAAAFwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApqMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAWGQgAAAAAAAAAAAAAAAAAAh9MAAAAAAAAAAO8GB9UAAAAAAAAAAIh7AAAAAAAA7hsAAAAAAAAAAAAAAAAAADAHZ4wAAAAAAAAAAAAAh9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5vsAAAAAAADmxwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwABj+rTQecKSgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp64AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC03ZwkAAAAAAAAAAAAAAAAAAAAAAAAAAClpAAAAAAAAAAAAAKxWAABKUUUnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJHIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACm4AAGg7AAAAAAV/aBZHS+oNJikAAAAAAAAH6QAAAAAAAAAAzGkG7AAAAACJYQAAAAAAAEwKAAAAAAAAAAClZgAAAAAAAAAAAAAAAAAAAAAAAAAAAACEdwoOAAAAAAAAqiDlOAAAAAAAAAAAAAAAACkqJjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEhcm6QAAAAApWgUCAADEPAAAAAAAACYhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKVNAAAAAAAAAAAAAAAAAAAAAEkdAAAAAOVlAAAAAOhcZ/ioGaYYAAAAAAAAAAAAAAAAAAAAAAAARicAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAahuGOKpJAAAJFqQpAAAAAAAAAAAAAAAAAADGiusFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhsAAAAAIYlAACmmgAAAAAAAAAAAAAAAAAAAAAAAAAAAACm0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6ADnEGkxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOdOAAAAAAAAAAAAAAAAamgAAAAAAADIS2c5AABmegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIVMAAAAAAAAAAAAAAAAAAAAAMgThC4AAMVqAAAAAAAAAAAAAAAAAACHugAAAAAAACZoAAAAAAAAAAAAAAAAAABn2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGUYAAAAAAAAAAAAAAAAAAAAAEhbp/kAAAAAAAAAAAAAAAAAAAAAtgcAAAAAAAAAAAAAAAAAAEgh5V0AAAAAAAAAAAAAAAAAAKdmAAAAAAAAZlkAAAAAAACGbAAA5ncAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp4MAAAAAAADFdgAAJocAAGfHAAAAAAAAAAB0BwAAAAAAAAAAAAAAAAAAAAAAAAAA5wWJVQAAAAAAAAAAAAAAAMbIAAAmYQAAh38AAAAAAADHiAAAAAAAAAAAAAAAAAAAxCsAAAAAAAAAAAAAAABOHofiAAAAAAAA5XgAAAAAFgAkO8ojAAAAAAAAAAAAAAAAxGOoTsQbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK0AlKk0mAAAAAAAAAAAAAAAAAAAAAAAASBIAAAAAx80AAAAAAAAAAAAAJDoAAAAAAACkQQAAAAAAAAAAAAAAAGolpxQAAAAAAAAAAAAAAAAAAAaFAAAAAAAAAAAAAIRKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMsdp9kAACeabjgG5AAAAAAAAAAAqVvlPQAAAAAAAAAAAACGlgAAAAAAAOVFqioAAAgcpgIAAAAAAAAAAAAAAAAAAAAAKQzHtAAAAAAAAAAAAAAAAAAAJlsAAAAAqEbkWgAAhvMAAAAAAADlQAAAAAAAAAAAAAAAAAAAAAAAACaVAAAAAAAAAAAAAAAAzGIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaChHAC4ZAAAAAGUHAAAAAFIEAAAIcCR4AACmoAAAAADUBQAA7TsAAAAAAAAAAKdEAADkUgAAAAAAAAAAAADkYSgIRFUAAAAAAAAAAAAAZgEAAAAAAAAAAAAAREEAAAAAAACEBgAAAAAAAAAAAADkLwAAAAAAAAAAAAAAAAAAAADuDwAAAAAAAAAAAACpMUcYAAAAAGlPAAAAAAAAAAAAAAAAAAAAAAAAAADkeQAAAAAAAAAAAAAAAAAAAAAAAAAAlA4AAG4GAAAAAERrAABmhuhCBTgAAAAAAAAAAAAAR0wAAAAAAAAAAAAAAAAAAAAAAAAAAOgXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGchKlTkJ8wLhwsAAOZEAAAAAEkbx6+qCAUgAAAAAAh3hvcAACRoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8QQAAAAAAAAAAAAAAAAAADIKAAAAAAAADixHTwAAAAAAAAAAAABETQAAAAAAAAAAAAAAADEJZCoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALRXkXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ4YAAAAAAAAAAAAAAABIPCZRAAAAAAAAAAAAAAAAAAAAAEgwBSoAAAAAAABmgQAAAAAAAAAAAAAAAAAAAAAAAAAAAACFcwAAJwkAAAAAAAAAAAAAZ/YAAAAAAAAAAAAAAAAAAAAAAAAHqAAApj4AAAAAAAAAAAAAAAAAAAAAyAXlYwAAAAAAAAAAAAAAAAAAhyIAAAAAAAAAAAAAAAAAAEVgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHEwAAAAAAAAAAAAAGswAAAAAAAAAAAAAAAAAAAAAAAAAANwMAAAAAJ/oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMQ7AAAAAAAAAAAAAAAAbAuntmgaREsAAAAAAAAAAAAAAAAAAAAAAACGhQAAAACJD+VGAAAAAAAAx30AAAAAAAAAAAAAAAAAAAAAAADkW4plAAAAAGcoAAAAAAAABSYAAAAAAAAAAAAAAAAAAAAAAACEEgAAAAAAAAAAAAAAAAAAAAAAAGVBAAAAABISR1sAAAAAqHoAAAAA5Q0AAAAAihAAAAAAAAAAAAAAAABGbwAAAAAAAAAAAACFNwAAZ98AAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAm/4h0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJXUAAGZ8AAAAAOofAAAAAEUR6mukeAAAAADsTgAAAAAAAAAARq4WAoRRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmcAAAJSgAAAAAAAAAAAAAR3MAAGVNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIxpAAAAAAAAAAAAAAAAZs8AAIeJAAAAAAAAppIAAEbxiCFlHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMgw5VgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZdAAAAAAAAAAAAAAAAAAAAAAAABU4AAAAAAADH+QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApowAAAAAAABESgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhCEAAAAAAAAAAAAAAAAAAGVGAAAAAAAAAAAAAAAAAAAAAFAA5gQAAAAAAACGpgAAAAAAAAAAAAAAAAAAhj8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwIh2MAAAAAAAAAAOlBAAAAAAAAAABGDAAAAAALSAAAAAAAAAAAAABNDwAAiSKmBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAClUAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEJAAAAABKX4ehAAAAAAAAZ6QAAGb0AAAAAAAAAAAAAAAAAAAAAAAAAABIGmcQAAAAAAAAAACrYwAAzwQAAHYBBz0AAAR1AAAmNwAAAAAAAAAAAABnSgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOZ7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKRRAABnQQAAAAAAAOZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgoAAAAAAAAAAAAAAAAAAAAAAAAONgAAAABEJwAAAAAAAAAACB0Hq8lCAAAAAAAAAAAAAGkDAAAAAAAAjgEAAAAAAAAAAAAAAAAAAAAAAAALIQdcAAAmzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKaLAADnDwAAAAAAAAaXAADGoQAAAAAAAAAAiC0AAAAAAAAAAAAAqw/HpgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJYwAAAAAAAAAAAAAAAAAAKWpkVwAAAAAAAAAAAAAEeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxrSID6cxAAAAAAAAAAAAAAAAAAAAAAAAAAAAACVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6A9GKwAAAACpQGUJAAAAAAAAAAAAAAAAAAAAAG4KAAAAAAAAAAAAAAAA5oAAAAAAAAAAAAAAAAAAAMa3AABFdwAAAAAqKwYmSTMAAAAAAAAAAMZbAAAAAAAAAAAAAMbjAAAAAAAAx+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMYBAAAAAAAAAAAAAAAAKxQn6awIAAAAAAAAAAAAAAAARnMAAAAAAAAAAAAAAAAAAAAAAAAAAAAApEMAAGVOAAAAAAAAAAAAAAAAAAAAAAAAxxQAAAAAAAAAAAAAAAAAAAAAAAAmagAAAAAAAAAAAAAAAAAApVkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEsAAAAAAAAAAAAAAADFUQAAAACKFyYiAAAAAAAA5EMAAEcz7QoAAAAApHUAAAAASxdEHwAAJt8AAAAAAAAAAAAAZqfIOSd4AACEYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlQgAAAAAAAAAAAAAAAEg7h58AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAOFdgAAAAAAAAAALFImXgAAAAAAAAAAq3UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFWCt7pWgAAKfoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgkp3QAAAAAAAAAAAAAAAAAAAAAAADnXwAAAAAAAAAAAAAAAAAAJFAAAAAAAAAmmlEOAABpbgAASiIG+wAARuCsIwAAAABkRwAAAAAAAAAAAAAAAAAAAAAAAAAA6GYFeAwCJ00AAOQ1AAAAAAAAAAAAAAAAAAAAAAAAAADrRgAAKTIAAEoApmELNSUEAADH+gAAAABIIgAAAABH6wAARGMAAAAAAAAH5wAAAAAAAAAAAAAAAAg45gUAAAAAAADmlQAAAAAAAAAAAAAAAAAAAAApNAAAAAAAAAAAAAAAAAAAAAAAAAAA5iQAAAAAAAAAAAAAAAAAAGV/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACETQAAAAAAAAAACzoAAAAAAAAAAAYaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASjcAAEp0AAAAAAAAAAAAAIhAhggAAAAAAAAAAAAABo0MDQAAAAAAAAAAAAAAAAAAAABlYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaD0AAAAAAAAAAAAAAADmWAAAAAAwAQAAqwwlNwAAAAAAAAAAAAAAAAAAAAAAAAAAChSHMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOVUySgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHjQAAAAAAAAAAAAAmXAAAh+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIKsRHAAAAAAAAAAAAAAaJaj2nMgAAAAAAAAAAAAAnhwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh9EAAOaWAAAAAAAAAAAAAAAAKXlFLAAAAAAAAAAAyEoAACklAAAAAAAAAAAAAAAAAAAAAIfd6l0AAK0EAAAAAIbkAAAAAAAAAAAAAAAAAAAAAAAAJiDpF8RIAAAAAAAAAAAAAAAAymIAAAAAAAAAAAAA6gUAAAAAAAAAAAAAAAAAACo4RiZrfgAAAAAAAAAAAABpJQAAAAAAAAAAAAAAAKRoAAAAAAAAAAAAAAAASgElKQAAAAAAAAAAAAAGpQAAAAAAAAAAAAAAANITJFIAAOeUAAAAAAAAAAAAAAAA+AAAAMh5ZvIAACfQAAAAAAAAAAAPAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCRFCAAAAAAAAAAAyj3nFQAAZs0AAAAAAAAAAAAAAAAAAAAASEfFXepZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACrAQAAAADmmwAAAACoG4csAAAAAAAAAAAAAAAAAAAAAAAAAADMVibiAAAAAAAAAAAAAAAAAABkMwAAhQXvAwAAAAAAAAAAp1MAACdUAAAAAAAAAAAAAAAAAAAAAAAA5qIKWGUlAAAAAAAAZiIAAAAACBsn3AAAAAAAAAAAAAAAAAAAAAAAAAAAAADnpAAAAACMNQAAAAAAAAAAAAAAAAAAAAAAAAAARUAAAAAAAAAAAAAAAAAuBuQG0gwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhS0AAAAAAAAAAGsvAAAqc2R5iQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEadAAAAAAAARoQAAAAAAAAAAAAABFIAAAAAAAAAAAAABxIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp6tNAadLAAAAAAAAAAAAAAAAAADFaAAAhX4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBOnLQAAAAAAAAAAAAAAAAAAAAAAAIUqAAAAAAAAAAAAAEZlAAAAAAAAAAAAAAAA6z0AAAAAAAAAAAAAAAAAAAAAAACoIAAA6kIGHwAAxCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADmRqg3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZXAAAAAAAABqcAAAAAAAAAAAAAAAAAAAAAqnLGFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOQrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEIwAAAAAJB8c2AAAAAAAAAAAAAMbzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARFwAAAAAAAAAAAAAAAAAAAAAAAAAACp55v8AAAAAAAAAAAAAAAAAAEZmAAAAAAAAAAAAAAAAAABFbAAAAAAAAAAAAAAAAAAAZrcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIR5AABmLAAAAAAAAIUOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaCGmFwsNAAAAAAAAAACmyQAAAAAAAAAAAAAAAAAAhg4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGbgAAxAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC2BQAAAADmawAAAAAAAAAAAAAAAAAAJvRKOKfdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACuLwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMaOAACmlAAAAAAAAOVSAAAAAAAAAAAAAAAAAADFaQAAAAAKQgAAKzFFLwAAAAAAAAAAAAAAAK4oZ3AJVQfrAABG3QAAAAAAAAAAAAAEUQAAAAAAAAAAAAAAACsX5xQAAMb/AAAAAAAAAAAAAAAAKR+nzQAABBMAAAAAAACn2AAAAAAAAAAAAADFfQAAAAAAAAAAAACFNAAAAAAAAAdoAAAAAAAAAAAAAOUrAAAAAAAAAADRAAUFAAAAAIgHAAAAAAAAAABGqSldhFoAAAAAAAAAAAAAAAAAAAAAiGDn82sihw3pTwAAAAAAAAAAAAAAAAAAAAAAAIg+x9sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxuvpWKUZAAAAAKh4JmwAAAAAAADFQgAAAAAAAAAAaVYAAAAAAACpHWY3AADHbQAAAAAAAAAAAABGsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAERIAAAAAAAAAAAqbgAAAAAAAAAAAAAAAAAAAADEZgAAZXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIRzAAAAAAAAJVMAAAAAAAAAAAAAp+0AAAAAAAAAAAAAx3ZNPqULAAAAAAAAZ7UAAAAAAAAAAAAAZ12JZ4ZiCzIHFwAAxxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR3wAAAAAAAAAAAAAAAAAAAAA6EwFKAAAAAAAAEV6aWkkcQAAAAAAAAAAAAAAAAAAAABIasR5AAAAAAAAAADYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApD8AAAAAAAAAAAAAJyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYZAAAAAAAAJ4IAAAAAAAAGggAAAAAAAAAAAAAAAAAAAAAAAKVWSx3GYAAABCoAAOeu1AIAAKhkRWQpYeUUqWIAAAAAJtUAAAAAAAAAAAAAAAAAAAAAAAAAAAAARwG3AWUBAAAAAIgZBCEAAAAACgcAAAAApu8AAMU6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMeVAAAAAAAAAAAAAAAAAAAAAAAAAADrfgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZVkAAAAASX0AAAAAAABKJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGwAAAAAiFoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHYAAAAAAAAAAAAABGhQAAAAAAAAAAbggAANIVhHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIRfAAAAAAAAAABpCSYRAACEXgAAAAAAAAAAAAAAAAh+RGlrUAAAAAAAAGsIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgQpGYAAAAAAAAAAAAAAAAAAAAADFwAAKowZywAAAAASmIAAAAAAAAAAAAAAACG/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMaAAAAAAAAAZocAAAAAAAAAAAAARpkAAAAAAAAAAIgs5icKAaQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFOwAAAAAAAGQ1AACmMwAARFsAAAAAAAAAAAAApS4AAAAAAAAAAAAAAAAAAAAAAADnYwAAAAAAACfgAAAAAAAARCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADELRyRLAAAAAAAAAAAAAAAAAAAAAAAAAAAABFRsV4boAAAAAAAAJVwAAAAAAACGyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlEowPh24AAAAAAAAAAAAAZDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5lQAAMdEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ6MAAAAAAAAAAAAAAAAAAARIAAAAAAAAAAAAAAAAAADGVQAA5ksAAAAAtAQAAAAAAAAAAAAAAAAAAAAAAACoDMfXAAAAAAAAAAAAAMR3AAAAAAAA5XAAAAAAAAAAAGwSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOotAAAAAAAAAABGVgAAJFgtIgAAAADnbgAAAAAAAAAAAAAAAAAAAAAAAAAAAABGCwAAAAAAAAAAAAAAAAAAhnEAAAAAAAAAAAAAAAAAAKadAAAAACw+ZpoAAKc1AAAAAAAAAAAKcQAAlwGmDwAAAAAAACRpAAAAAAAAAAAAAIZrSHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApgAABJYAYUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOwhAAAAAAAAAAAAAAAAAADrWQAAaVenSAAAAAAAAAAAAAAAAAAAAAAAAAAAyWsHJgAA5E4AAAAAAAAAAAhuJ70AAAAAAAAAAAAAp3oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABENgAAAAAAAAAAAADGRAAAAACKO0d0CmclRQAAAACIOAAA6BIAAAAAAAAAAAAAAACEYAAAhSTqEAAAAAAAAAAAAAAAAAAACT8AAAAAJogAAAAAAAAAAAAAAAAAAAAAAAAAAAAA52EAAAAAAAAAAAAAAADLGScxAAAAAAAAAAAAAAAAAAAAAAkdBHIAAAAAAAAAAAAAJnoAAAAAiFlHDAAAAAAAAAAAAAClWwAAAAAAAAAAAAAAAAAAAABqAgAAAAAAAAAAhVMAAAQtAAAAAAAAAAAAAAAADFIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AcdaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQkAAAAApp4AAAAA6TkAAAAAAAAAAAAAAADHtQAA5qCtHgAAqHsAAAAAAAAAAAAAAAAAAAAAAABpDYcUAAAAAAAAAAAAAAAAAACmhAAAAAAAAAAASACFPAAAAAAAAAAAAAAAAAAA5owAAAAAAAAAAAAAAAAAAIQ5AAAAAAAAAAAAAIR0AAAAAAAAAAAAAAAAAACGSShOAAAAAAAAAACGCYgLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkXwAAxE0AAAAAAAClHwAAR0QAAAAAyg0AAAogh3IAAAAAbASFGgAAAABJXQAAAAAAAMoSAAAAAEa3AAAAAAAAZqIAAAAAAAAAAAAAAAAAAAAAAADGvQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAppkAAAAAAAAFZgAAAAAAAAAAAAAAAOwTAAAAAAAAAAAAAMhbpWzND4bWAAAAAAAAAAAAAAAASRkEHQAAAAAAAAAAiBoAAAAAAAAAAAAA6A1nfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1gAAAAAOGwAAAAAAAAAAhkAAAAAAAAAAAAAARlEAAAAAAAAAADEHZgwAAAAAAAAAAIwlxkcAAAAAAAAAAOh/AAAAAMclAADn6QAABFuJHwAAAACmOQAAAAAAAGYoAAAAAAAAAAAAAAAA6GCnOQAAAAAAAAAAAAAAAIsVAAAAAAQ6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADIJ51oAAOR/AAAAAAAAAAAAAAAAAAAAAAAAAAAoSAAAAAAAAAAAAAAAAAAAAACmgQAAAAAAAAAAAAAAAAAAAAAMI6VUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOZjAAAAAAAAAADoEwAAyzdH2AAAAAAAAAAAAAAAAAAAAAAAAGQxAAAAAAAAAAArEgAAAAAAAAAAAAAAAAAAlQIAAAAARjUKTAAAAAAAAAAAAAApegAASh8AAAAAAAAAAAAAiwwAAAAAAAAAAMb3AAAAAAAAAAAAAIU7AAAAAAAAAAAAAAAASkqFCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOg3AAAAAAAAAADEQQAAAADXAYeMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhxcAAAAAAAAAAAAAAAAAAAAASS2nJQAAAAAAAOfZAABEFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARtAADmZwAAAAALGkYZAAAAAAAAAAAAAAAAAABG9AAAAAAAAAAAikAHbQAAAAApJwQcAAAAAAsDAABoAUVEAAAAAAAAJ/JIHiUe1gUAAAAAAADJZyafAAAAAAAAAAAAAAAAAAAmZ+ooxH0AAAAAAAAAAAAAh8WJQMQtAAAAAAAAAAAAAAbZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAObxAABEZwAAAAAAAAAAaxFmKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHJAAAhnIAAAAAAAAAAAAAB+wAAAAAAAAAAAAAAAAAAOa3AABGxAAARDEAAAAAAAAAAAAAAAAAAGfxAADn1gAARFKNHAAAAAAAAAAAAADILgAAAAAAAAAA51sAAAAAAAAAAAAAAABrKEY+AADnhAAAAAAAAAAAaRMAAAAAAAAAAAAAAAAAAAAARXEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGaOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIoNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAETchwAAAAAAAAAAAAAIhWAAAAAAAAAAAAAAAA5mYAAAAAAAAkJgAAAAAAAAAAAAAAAAAAJlUAAAAAAAAAAA0AxRqIfQAAAAAAAAAAAAAAAAAA7gIAAAAA5tQAAAAAAAAAAAAAAAAAAAAAAABntAAAAABxAkZZAAAAAAAAAAANCCRcAAAAACkrxtsAAAAAakjlBQAAAABqQ2URAAAAAAAAAACNMAAAAAAAAAAAph8AAAAAAAAAAAAAAACKHwAALF0AAAAAAAAAAAAAAAAAAAAAAAAAAAAACD9kDQAA5GwAAAAAAACkHAAAAAAAAAAAAADkcAAAAADsCAAAAAClRMkA5AUAAAAAAAAAAAAAAAAAAAAAAACFeihsJVgAAAAAAAAnFAAAAAAAAAAA6BFnpgAAAAAAAIatLASFWgAAAAAAAGUCAAAAAAAAZTEAAAAAAAAAAAAAxGlMGgAAAAAAAEkPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAORWKHUnPgAAAAAAAAAAAADGWQAAAAAAAAAAAAAAAAAApsUAAAAAAAAAAAAAAAApFCYGAAAAAAAAAAAAAAAAAAAAAAAApEoAAAAAAADGiAAAAAAAAGRli3EAAAAAAAAAAAAAAAAAAAAAAAAAAOe3AAAAAAAAAAAAAAAAAAAAAAAAAABMBefxAAAAAAAAx/tKCOf6AAAAAEtJAAAAAAAAAAAAAAAAAAAAAAAAiwOnhgAAAAAAAKaYAAAAAMsHAAAAAAAAAAAAAAAAAAAAAAAAAADG3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYDAABqPoetAAAAACgMRQEAAAAAAAAAAAAAJTwAAAAAAAAAAAAAAAAAAAAAAAAAAKkExhBoE8c8AABGtAAAAAAAAAAAAADlSQAAAAAAAAAAAAAAAMgmp5IAAAAAAAAAACkzh5AAAAAAAABGPAAAAADoIMdzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ54AAOQzAACFKwAAAAAAAIR+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyFGbhAAAAAAAAAAAAAAAAAAAEMwAAAAAAAAAAAAAAACkgJqUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGjgAAAAAAACQfAAAAAAAABUgAAAAAAAAAAO4cAAAAAAAACSQAAAAAAAAAAAAAAAAAAAAAAAApNue5LEfH0QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7AoAAAAAAAAAAAAAbGFHQwAAAAAAAKUzAAAAAAAAAAAAAAAAAAAAAAAAAADoPQAAAAAAAAAAAADqF8cGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASELnRgAAAAAAAAAAAACGuQAAAAAAAAAAAAAAAOllJkwAAAAAAAAAAAAAhjwAAAAAAAAAAAAAAAAAAAAAAAAAAIlwAAAAAAAAAADnpgAAhtcAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5uQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQ7AAAAAAAAAAAAAAAAAAAAAAAA5okAAAe87FFGgQAAAAAAAAAAAAAlJgAAAAAAAAAAAAAAAAAAAAAAAIeaAAAAAKg1JhsAAAAAAAAAAGpcxyIAAAAAAAAAAAAAAAAAAIZYAAAAAAAAAAAAAAbmLB0AAAAAAAAAAAAAAAAAAAAAJvwAAAAAAAAAAAAABroAAAAAAADGxgAAAAAAAAAAAAAG4ZADAAAAAAAAAAAAAAAAAAAAAAAAqQUAAJEEAADOAke0SC8AAAAAAAAAAAAAAABmvAAAAAAAAAAAAAAAAAAAAAAAAAAA6wQAAAAAxoOoWmf0AACG/gAAAAAAAAAAAAAAAAAAAAAAAAAADHDm6QAAAAAAAAAAAAAAAAAAAAAAAAAAqWQAAAAAAAAAAMf/AAAAAAAAAAArAgVZAAAkTekGBijoIQAAAAAAAAAAAAAAAAAAAAAAAKo3AAALF+cMAAAAAAAAAAAAAAAAAAAAAGlSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArKgAAAAAAAEw/AAAAAAAAAAAAAGpppQkAAEQ5AAAAAAAAAAAAAIexyi+mDcsRRikAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxCgAAAAAAAIs9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5poAAAAAAAAAAAAAAABrGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACaDAAAnKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACf4AAAAAEgPAAAAAEQdAAAAAAAARokAAAAAAAAAAAAAAACoRKcfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJQWYQAAAAAK4SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ/AAAAAAAAAABpZcZOAAAAAAAA5CoAAAAAAAAAAAAABDjqSec4AACnrAAAAAAAAAAAAAAAAAAA5kcAAAAAAAAAAAAA5pIAAAAAAAAAAAAAAAAAAAAAAACmUQAAAAAAACbcAADGlQAAAAAAAAAAKiXnjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMRUAAAAAJIUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbgQAAK0FAAAAAAAAAAAAACoPAAAAAAAAAAAAAAAAAAAAAKQPAAAAAAAAxsoAAAAAAAAAAAAAJFooEgAAAAAAAEt5B2MAAAAAAABkWQAAAAAAAAAAAADn+QAAAABICWVCAAAAADAIAAAAAAAALQ2GGwAAAAAAAAAAAAAAAAAABngAAAAAAAAAABQAAACLNWYCAAAAACgyBwwAAAAAAAAAAAAAZseRDgAAqH8AAAAAAAAAAAAAyF0n9QAAAACJEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbgkAAAAA5qwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaWEAAAAAAAAAAAAAAAAAAAAAxEoAAAc1AAAAAAAAAAAAAAAAAADGmAAAAAAAAIRtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKUQAAAAAAAAAABoFwAACAEAAAAAAAAAAAAAAAAAAKs1AACoVQAAAAAAAAAAAAAAAAAAAAAAAAAAAACIEAY7AAAAAAAAAAAAAAAAAAAAAAAARnUAAAAASW0AAAAAAAAAAAAAyGAAAAAAAAAAAAAAkgsAAAAAAAAAAAAAAADEZ6lXAAAAAAAAAAAAAEg1xSsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaUtmBwAAAAAAAAAAAAAAAAAAAAAAAAAArSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJzdoFIcAAAAAAAAAAAAAAAAAAAAAAAAAxGQAAAAAAAAAAAAAAAAuHQAAAAAAAAAAR/kAAGbZAAAAACgxAAD0BceBAAAAAAAApyYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgtAAAAAAAA7hUAAAAAAAAAAAAAAAAAAEhTAAAAAGfRAAAGyAAAAAAAAAdlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQjzAYAAAAAAAAAAAAAAAAAAAAApDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACcfAAAAAOoMxh8AAMUgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZkAAAAAAAAAAAAAAAAAAAAAAAAxssAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOVTiHmkewAAAAAAAAAAAAAAAAAAJG8AAAAAAADHrAAAAAAAAAAAAAAAAAAA5WAAAAAAAAAAAAAAAAAAAAAAAAAAAIwwRxkAAAAAAAAAAA0CBkYAAAAAAAAnaQAAAADIRgAAAAAAAEh1AAAAAAAAAAAAAAAAAAAAAAAAAAAFcgAAAAAAACeqAAAAAAAAAAAAAAAAS02FHQAAxucAAAAAyCfFFwAAB6wAAAAAAAAAAAAAAAAAAKcrAAAAAAAAAADodob2AAAAAAAAAAAAAAAACSsAAAAAAAAAAAAAAAAAAAAARGoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABuAgAAahSnCgAA5DwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoSAABzCgAAAACkfgAAAAAAAEfwAAAAACsVpUVLCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnlVAKAAAKLMU4MgcAAAAAp6aJMWYNAABFLgAAAAAAAAAAAAAAAAAAAAAAAIUZAAAAAAAAAAAAAEbVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASDGHlgAAAAAAAAAAAADlfQAAAAAAAAfUAADmvQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACpegAAAAAAAAAABoYAAAAAAAAEWQAApssAAAAAAAAAAAAAAAAAAAZbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADmngAAAAAAAAfJFwIAAAAAAAAAAKU8AAAAAAAAAAAAAAAAKBNlAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOb4AAAAAAAAAAAAAAAAAAAAAI4GAAC0AgAAAAAAAAAAAAAAAAAAAAAAAGhmAAAAAAAAAAAAAKtyAAAAAAAAAAAHYgAAAAAAAAAA7xAAAAAAAAAAAAAAyjgAAAAAAAAAAAAAAAAAAAAAAACJaubWAAAAAAAAAAAAAIdqAAAAAAAAAAAAAAR3AAAAAAAAAAAKRwAAAAAAAAAAAAAJOAAAAAAAAGgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEbkKlIAACtbRlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkUwAAAAAAAAAAAAAAAAAARTIAAAAACxMAAAAAAAAAAAdyAAAAAAAAAAAAAAAAaAYHKAAApDcAAAAAAAAAAIsmAAAAAAAAAAAAAEswAAAAAOUdAAAAAEgQZwoAAOQRAACHKwAAAAAAAAAAAAAAAAAAxncAAAAAAAAAAAAARBoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxDUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqAKUaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACdkAAAAAAAAAAAAAAAAAAAAAAAABnUAAIUNAAAAAAAAAAAAAAAAAAAAAAAApG5rSWUbyjGHLQAAp5EAAAAAySomHuklAAAAAAAAAAAAAAAAAAAAAAAAAADGtQAAAAAAAAAAAAAAAAAAAAAAAAAAyR9ERgAARGIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoPQYbAAAAAAAAAABrG6cqAAAAAAAAAAAAAAAAAAAAAAAAAABLEMfYTBMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqFeFSwAAAADobQAAaRhFUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAptAAAAAAAADm3wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh5kAAAAAAAAAAAAA5E0AAAAAAAAAAAAAAAAAAMdjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAigpHDwAAAAAAAKZoAAAAAAAAAAAAAAAAqH4AAAAAJkgAAAAAAACGOYp0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgDZRAAAAAAAACmSwAAAAAAAMabAAAAAAAAAACJCMUiqBRlJqhhAAAAAAAAAAAAAAAAJgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACaLAAAAAAhaJ/RqGQAAAAAAAAAAAAAAAAAAKTXGKAAAAAAAAAAAAAAAAAAAAAAAAAAAKx6HpAAAAAAAAAAAAAAFNAAAAAAAAIaiAADnaQAAAADKUsUsAAAAAAAAAADoaObjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMxRRr4AAAAAAAAAAAAAAABrFAAAAAAAAAAAAABNJ0R6AAAAAAAAJEsAAAAAAAAAAAAARXZINgAAAAAAAEwyZzMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsAWe3TjMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADJCAAAAAAAAAAAp68AAAAAAAAAAAAAAACJDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkYQAAAAAAAAAAAABlXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJD8AAMUoAAAAAI8Uhk7KUQAAAAAAAKgEBgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiVMGEwAAAAAAAAAAAAAAAAAAAAAAAAAAAACkSAAAAAAAAAAAjgXGDyoLAAAAAAAAAAAAAAAAAAAAAGa/AAAAAAAAAAAAAAAAAAAAAGwZ5pEAAAAAAAAAAAAAAAAAAAAAaUIHmgAAAAAAAAAAAADmdQAAxVPrHARuAAAmygAAAAAAAKf0AAAAAAAAAAAAAAAAAADmeQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHHgAAAAAAAAAAAAAAAAAAAAAAAKU0AAAAAMgBRWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqOgAAAAAAAAAAAABJaAZWqTPkagAAAAAAAMRJAAAAAAAAAAAAAAAAAAAAAEsOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgFJRUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxBgAAAAAq0YlSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZlYAAAAAAAAlSgAAAAAAAAAAAAAAAAAAAAAAACdyjA4AAAAAAAAAAAaqAAAAAAAARGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAClUhiYAAKRYyX3m7AAAhBwAAAAAAAAH5gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEwAAAAAAAAAAAAAAAAAAAAAAACmxAAA5/4IEYZDAAAAAAAAAAAAAAAAAAAkcAAAAABJdcbqAAAAAAAAAAAAAAAAAAAAAAAAprcAAOV8AABkJQAAAAAAAAAAAAAAAAAARUgAAAAAAAAAAAAABTkAAAAAAADn0WwUp1YAAAAAAAAAAAAAAAASBmReAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASyoAAAAAAAAAAGaIAAAAAAAAAADsVgAAAAAHtwAAAAAAAAAAAADneQAAAADtKQAAAABm9wAAAAAAAAAAqCHHw8lOhjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOfiSk8FAAAAAADIeAAAAAAAAAAAAAAAAAAAKAGGMwAAx3cAAAAAaEjELwAAhBoAAAAAAAAAAKp4JFUAAAAADgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlUQAAAAAAAAAAcQgAAAAAAAAAAAAAAADmXQAAAAAAAAAA6DTmHAAAAAAKf4UlAAAAAAAAAACIDKYdAAAAAAAARqsAAAAAAAAHlwAAAAAAAAAAAABmmC4QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOUYAAAAAGw1AAAAAAAAAACmdihTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1kAAAAAAAAAAAAARpQAAAAAAAAAAAAAAAAAAAAAAAAAAOwkBicAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6RIAAAAAAAAAAIRJmAAAAAAAAAAAAAAAzDMGDQAAAACqXuYgAAAlRgAAAAAAAAQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQcAAAAAAAAAACxBCdmAADFeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARv1rEGUdCQIAAMhJp5AAAAAAAAAAAAAAAAAAAAAAqhsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIoRxzAAAAAAAAAAAAAAAAAAAAePAAAAAAAABjoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACLGeUy6CVHmAAAAAAAAAAAqAClKAAAAAAAAAAAigEHZAAA594AAAAAAAAAAAAAAAAAAAAAAAAAAA0/pk0AAAAAAAAAAAAAAAAAAAAAAAAGcwAABC8AAAAAAAAAAAAARhuMSAAACGDHOAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAIpUAAAAAAAAAAAAAAAAhhQAAAAAAAAAAAAAAAAAAAAAVgYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0PpiMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEkc5ioAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtgMAAAAAhuIAAAAAFQEAAAAAAAC2AqeMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5qUAAAAAAAAAAOlHxscAAAAAAAAAAAAAAAAAAAAAAADmbwAAAAAAAOV3AAAAAAAAAAAAAOfbqBUAAAAAAAAAAEYhriAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGayAAAAAIglJoEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkkAAAAAAAAAAIgGxVsAAAAAKxvnHQAAJo0AAAAAAAAAAAAAAAAAAAAAiFuHAgAAAAAAAAAAAAAAAAAAAAAAAAAAAABGNAAAAAAAAKVMAAAAAAAAAAAAAAAAAAAAAAAABE8AAAAAqAoHewAAAAAAAAAAqHHFVusAp4oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADkFAAAAAAAAAAACCPFBwAAAAAqBAAAAADkLE0Xh3oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ0kAAAAAAABlGgAAAAANKiYSAABGjQAAJ20AAAAACGnkIAAAAAAAAAAAAAAAAAAAAAAAAIRyAAAAAAAAAAAAAAAAAAAAAAAAAABvEwAAAAAAAKo5JwwAAAAAAAAAAAAAh6kAAAAAAAAAAAAAAAAAACRKAAAAAAAAAAAAAAauAAAAAAAAAADTDwAAAAAAAAAAZpMAAAAAAAAAAAAARBQAAAAAAAAAAAAApl8AAGUXAADHoAAAAAAAAAAAAAAAAAAAAAAAAGZPAAAAAOsC5BoAAAAAAABGowAAAAAtDIdZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChSAAAAAAAAAAAAAAAAAAAAAGYlAAAAAAAAAAAAAAAAzhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATFJGhwAAAAAAAAAAAABH+gAAAAAAAAAAAAAAACtoBx8AAAAAAAAAAAAAxs4AAAAAakIAAAAAAAAAAAAAAABGTwAAAAAAAAAAAAAAAAAAAAAAAKVqq0cmHwAAAAAAAAAAAAAAAAAAAADqQQAAAAAAAAAAZrEAAAAAAAAAAAAAAACIAicGAAAAAAAABXwAAAAAAAAFWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACg+Z8UAAAAAAAAAAMkHhiEAAAAAAAAAAAAAAAAAACaWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6j0nGAAAAAAAAAAASg0AAAAAZmsAAAAA7QIAAAAAAAAAAAAAAAAAAKllpnMAAAAA6BumTCh3AAAAAAAAAAAAAAAAAAAAAERTAAAAAAAAAAAAAAAAAAAAAAAAxFMAAAAACQUHGwAAAAAAAAAAAAAAAGsgAAAAAAAACjdHiwAAAAAAAAAAAAAAAAAAAABJCWY7AAAAAIwXZBEAAKRjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhsQAAAAAAAAAAPUEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARscAAAAAAAAAAAAAAAAAAEYkAAAFHQAAAADpbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKEHEAQAAAAAAAAAAAACmXAAAAAAAAAZ8AAAAAAAAAAAAAAAAAAAAAPANAAAAACQ1AAAAAAAAAAAAAKdiAAAAAAAAJscAAAbdAAAAACsdAAAAAAAAAADldQAAAAAAAAAAAAAAAAAAZHcoHKUeAAAAAAAAAAAAAAAALh4AAAAAAAAAAObyAAAAAAAAhqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp1gAAAAAAAAAAAAAAABIRQAAAAAAAAAAAAAAAAAAAACGwwAAAAAAAGQ3AAAAAAAAAAAAAAAADiMAAAAAAAAAAAAAAAAAAAAAJFsAAAAAAACEKwAAAAAAAAAAAAAAAAAAxl4JakQlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKlnxrGuFycPAAAAAAlPh2UAAAAAi0UAAAAAAAAAAAAAijaEFUtChWkNHQZ7AAAAAAAAAAAAAAAAAAAAAAAAAABqEgAAAAAAAAAAAAAAAAAAAAAlQwAAAAAAAAAAAABkawAAAABJaQAAAAAAAAAAAAAAAAAAAAAAAAAAZ6EAAAAAAAAAAAAAAAAAAAAAAAAAAAAARrmMTAUxAAAAAAAAxiDuAwAAAAAAAAAAAAAAAAAAAAAAAAAAJF6pRAQAAAAAAAAAAAAAAAVXAAAAAAAAAAAAAAAAAABEaAAAAAAAAAAAAABkYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJXMAAAAAAABFVAAAAAAAAAAAAAAAAAAAAAAAAAAAiCaGNwAAAAAAAAAAAAAAAKtkhhYAAAAAzSLnIQAAAADNGiY/AADnlwAAAAAAAAAAAAAAAGgw5iEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmzUoFhgsAAGQ5AAAAAEwppsIAAAAAAAAAAAAAAAAAAAAAKg5GAgAAAAAAAMbZAAAAAAAApXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMYWAAAAACoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApnkAAAAAAAAAAAAABykAAAAAiUkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARt8AAAAASHgm+AAAAAAAAIcmiz8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhJAAAAAAAAAAAAAAAAxUwsYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATCQAAAAAAAAAAAAAAAAAAAAAAAAAAAaOAAAAAAAAAAAAAAAAAAAAAAAAAACIY+dZAAAAAMgoRRoAAAAAAACkV8leBTsAAAAAAABn88oi5oYAAAAAAAAAAAAAAAApPicFAAAAAEhPxQUoeAAASGWEQQAAAAAtBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIVCAAClfAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARqIAAOZTAAAAAAAARCYAAAAAAAAAAAAAAAAAAAAAAAAAAKtW5+MAAAAAAADnXgAAAAAAAAAAAACH8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARC8UWAAAAAAAAh/UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRBAAAAAAAAAAAAAAAACTUnawAAAAAAAAAA6FMFKQAAJEIAAAAAAAAAAAAAhlkAAKa8DgpmCAAAAAAAAAAAaQemEQAAAAAAAAAAAAAAAOhhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEa7AAAAAAAAAADuKsc1aWTnk6hUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApqmwBgAAAAAAAAAAxkkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACcpAAAAAAAAAAAAAAAAAACkOgAAAAAAAAAAAAAAAAAAAAAAAAAAjjkAAAAA5tkAAAAAaHiGKgAAAAAAAAAAAABmyAAAAABMHwAAAAAAAAAAAADIUEUbAABH4AsAAAAAAGVHAADkOAAAAAAAAIZ+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqUomFAAApCsAAIZBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASygGNgAAAAAAAAAAAAAAAKoo5RsAAAAAAAAAAAAAxEYAAAAAAABHris8hjYAAAQGKDlFTIleRU0AAAAAAABlXgAAJ5gAAAAAAAAAAAAApBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACESFPW4NxzMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5H0AAAAAAAAAALAAAAAAAIbFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGbmAAAAAAAAAAAAAAAAAAAAAAAApBQAAAAAAAAAAAAAAAApZaZuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJPgAAAAAAAEwmJQEAAAAAAAAAAAAAAAAAAKQ2KlpFEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmFgAAAAAAAAAAAAAAAAAAJqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFGQAA5HcAAAAAAAAG8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmswAAJjwAAAAAAAAAAAAAAADKEYQKAAAAAAAAAAAAAOV+AAAAAAAAZCcAAAAAAAAAAAAAAADpXgAAAAAAAAAAAAAAAAAAAAAGWQAAAAAAAEbXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyBsAACp7x7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnn0pDR1gAAAAAAAAAAAAAAAAAAAAAbw4AAAAAAAAAAAAAAAAAAAAAAAAAAKfeAAAAAAAAAAAAAOc1KgwnU0kFpx0AAAAAAAAHIQAAAACoGgAAAAAAAAAAAAAAAAAA6TgAAAAAAABIcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtOAADIRwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQsAAAAAAAAx8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjwhnHWxapuIAAAAAAACndwAAxWcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyAgAAAAAFPgAAAAAAAAAAAAAAAAAAZkTpHQULAAAAAAAAAAAAAAAAAAAAAAAAx6MAAAAAAAAAAAAAAAAAAAAACQqHhgAAAADODgAAAAAAAOs7RyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJD4AAAAAq1OnIAAAAAAAAAAAqAEAAAAAAAAAAAAAAADmYkgfR1AAAAAAAACnsmp1pHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAERmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMh6RykAAAAAAAAAACpEAAAAAAAAAAAAAAAAZnYAAIaUAAAAAAAAAAAAAARxAAAAAAAAAAAAAIarAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkVisvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOdWAAAAACpZRzAAAAAAAAAAAAkQ58QAAAAAAAAAAAAAAAANNadvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhxAAAAAAAAAAAAAAlFRigAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIkDBuIsBgAAAAAAAAAABuUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKc0AAAAAEk35jMAAAAAKyQAAAAAAAAAAAAAzhnEDQAAAAAAAAAAAACnGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHcCZ8AAAAAAAAAAAAAAhqcAAEeVAAAAAAAAAAAAAAAAAAAAAKxEAAAAAAAAAAAAAAAAAAAAAAbXAAAAAAAAAAAAAAAAAAAAAAAA5ScAAAAAAAAAABQOh5MAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5ngAAAAAAAAAAAAAAAAAAAAAAACH8gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOhbAAAAAAAAAAAAAAAAAAAAAAAAK3CFEAAAAAAAAAAAAAAAAAAAAAAAAAAAygTEaAAAAAAAAGUvSBsFAYpSJH8AAAAAAAAAAAAAAADtDWYw6VCnbQAAAACqBsdiAAAAAAAAAAAAAAAAAAAAAE45AAAAAAAAAAAAAAAARncAAAAAAABHMQAA5qoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEbgAAAAAAAAAAAAAAAAAAJ7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMgEhw/KKucYAAAAAAAAAAAAAAAAAAAAAAAAAACMWoROAAAAAAAAAACIZEchAAAAAAAAAAAAAAcaAADmCQAAAAAAAAAAAAAAAAAAAACoXAAAAAAAAAAAAAAAAAAAAAAAAAAAxksAAMa6qWYmwgAAAADsEKUyAAAAAEgWhgwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQ8AAAAAAAARqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOViKARnmSlrAABoOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5DcAAAAAAAAAAAAAAADLCgQQAAAAAAAAAAAAAAAAaEkAAAAAAACKVkd/AABkGAAAAAAAAAAAAAAAAAAARsEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhlUAAAAAKCsAAAAAAAAAAAAAAAClLQAAZtIAAAAACjsAAC42AAAAAAAAAAAAAAAAAACXAwAAAAAAAKx8AAAqWGUAAAAAAAAAAAAAAAAAAAAAAAAApRwAAAAAAAAAAMgMAAAAAAAAAABGbMh/AAAAAAAAAAAAAAAAAAAAAAAA9gYAAGgOAAAAAAAAAACmdAAAAAAAAAAAAAAAAAAAxVcAAAAAAAAAAAAAAAAAAAbYUgOEPAAAAAAAACcXSk0mNAAAZmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxp0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADnO8ogAAAAAAAAAAAAAAAAxmcAAAAAAAAAAEsDxQgAAAAAAAAAAAAAAAAAAAAALxsAAAhQZgYAAAAADS1HxgAAAAAAAAAAAACHUQAAAAAAAAAAAADHXwAAAAAAAAAASCUnXAAAAAAAAAAAAAAAAAAAAAAAAAAA6VHFG0lxAAAAAKZ+6Hsm+wAAAAAAAAAA6j4AAAAAAAASG0UTAAAAAAAAhVkAAIdpAAAAAAAAAACoTYYfAAAAAAAAAACJXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7gwAAFcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdIAAAAAAAABlEAAAAAAABlKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxPAAAAAAAAyEBlDQAAAAAAAAAAAAAAAAAAAABpagAAAAAAAAAABD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD0AGVuAAAAAAAAAAAAAAAAAABFcwAAAAAAAAAAAAAAAAAAAABpCyV8AAAAAAAAAAAAAAAACBlkEFgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACpLSezAAAAAAAAAACKA+UMAAAAAMhjpX4AAAAAAAAAAAAAAAAAAAAA7ASn8AAApmoAAAAA6iHmQAAAAAAAAAAATioAAAAAhCXJOmU0AAAAAAAAAAAAAAAAiWgAAAAAAAAAAAAAAAAm8gAAAAAAAAAAAAAkMQAAAACoLAAAAAAAAAAAAADrVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZTAAAAAAAAAAAAAAAABoCYVYqzjnqAAA5CUAAAAAimAAAAAAAAAAAAAAAAAAAAAApF0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACaFAAAAAKtZRhwAAAAAAAAAAAAARW/uNUZOAAAAAAAAAABKWAAAAAAAAG0GRFcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhmcAAAAAKgIAAAAAAAAAACfxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIYKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMD52xMPgAAqgwm4AAAAAAAAAAAAAAAAGo2AAAAAAAAAAAAAMp4AAApEIfNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACnfMg+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5GYAAOfwAAAAAAAAAABJDIfbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAEAAAsUx4IAAIc9AAAAAAAAAAAAAAAAKBCmBQAAAAAAAAAAAAAAACgsx0UAAAAAAAAAAAAAJWIAAAAAAAAmj6kXAAAAAAAAVwMlLAAAAAAAAAAAAAAG/QAAAAAAAMVLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQBOdqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABm+wAAAACyAIQAAAAAAKs5h18AAAAAAAAmtQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKa0AAAAAAAABpIAAAAAAAAmHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADmHwAAAAAJGwAAAAAAAMsjAAAAAAAAdwAAAAAAAABqWgRDAAAAAAAAAAAAAKcjAAAAAAAAB0YAAAAAAAAAAAAARFYAAAAAAAAAAAAAx5sAAAAA8wcAACsEAAAAAAAAAAAAAAxBx+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADLTgAAAAAAAAAARUUAAAAAAAAAAAAAJX0AAAAAAAAAAAAAxTcAAAAAAAAAAAAAAAAAACakAAAAAKlohk8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMsiAAAAAAAAAAAAAAAAAAAAAIRsAAAAAAAAAABKfgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA55kAAAQmAABHPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVgMAAKgLB7BKY2RpC1gAAK0jRQ6oPEdwKRIAAGgCZ/4AAAAAAACn8QAAAAAAAAAAAAAAAAAAB9gAAAAAAAAAAAAAAAAAAAAASF0AAAAAAAAAAAAAAAAAAGh8hvUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxsEAAEZtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARH8AAAAAAADEZcsPAAAAAAaeAAAAAMhlZXcAAAAAAAAAAAAAAAAAAKZ6AAAAAAAAAAAAAAAAAAAAAGhyBQcAAAAAlAwAAAAAAAAAAAAAAAAAAAAAAADLTwAAAAAAAAAARVwAAAAAAAAAAAAAAAAAAAAAAADFXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHiwAAAADOGgAAAAAAAKkQAACNGAcVAAAAAAAAAAAAAAaQAACnmwAAAABIQyYV6mwG4wAAAACoM6YQAAAAAAAARnoAAAAAbAWmC2kuAAAAAAAAAAAAAAAAxUEpAwAATF7kKQAAAAAAAAAAyxYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6AQlSwAAAAAAAAAAAAAAAAAApBZILgAAAACGzsgsAAAAAAAAAAAAAAAAAAAAAAAADRbGIwAAh2IAAAAAAAAAAAAA5piIYccfaH0GcAAAAAAAAOe0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADF0AAAAAAAAAAAAA0g8AACsFhGIAAAAAAAClTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAClJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACENK4Ehu0AAAAAAAAAAMxDR8SodwAAAAAAAAAAAAAAAAAAqC7nAwAAAAAAAAAAqg+kKAAAAAAAAAAAAAAAAGooAAAAAGbBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHmAAAAAAAAAAAAAAAAM8YJu6pTucBAAAAAAAAAAAAAAAAjwJmCetDJ6kAAAAAAACnQgAAAADVAAAAAAAAAAAAAAAAAEVDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQqAAAAAAAAAABxAQYAAAAAAIojZVIAAKV7AAAAAAAAAAAAAAAAAAAAAAAAB2oAAAAAaj8AAAAAAAAAAAAAAAAAAAAAhBfre4VuAAAAAAAAAACQB+d3AAAAAAAAAAAAAKbOAAAAAEhzJyoAAMRPAAAAAIo+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARzQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIXwAAAAAAAAAAAAAAAKafAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEhgAAAAAAAAAAAAAAAAAABqHiQLAAAAAAAAAAAAAAAAAAAAAAAAhq4AAAVGAAAAAGkARs8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEpJAAAAAOeeAAAAAAAAJT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApk8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZvMqBac3AAAAAAAAAAAAAAAAAAAAACgHpBcAAAAAai4AAAAAAAAAAARFAABmbgAAZnMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ20AAAAAAACH3zEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKpSAAAAACfzAAAAAAAAAAAAAEZjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOaNAAAAAAAAJV0AAAAAAAAAAAAAAAAAAIUKAAAAAAAAAAAAAAAAAABFMwAABHoAAAAAAAAAAAAA5lcAAAAAAAAAAAAAAABqF0UoAAAAAAAAZRwAAAAAAAAAAAlGAADzA2euAAAAAAAAAAAAAEc6AAAAAAAAAABqUOYUAAAAAAAAhrIAAIUzAAAAAAAAAAAAAAAAAAAAAAAAxotIRgAAAAAAAAAAAAALIAAAAAAAAAAAAAAAAGbdAAAAAAAAAAAAAMeUiRAAAE8IAAAAAAAAAAAAAAAAAAAAAAAAAACkJwAAAAAAAOUHAAAAAAAAAAAAAAAAAABmuAAAAAAAAAAAAAAAAAAABCQAAAAAAAAAAAlMAAAAAAAAAAAAAAAAAAAAACaZAACnlAAAAAAAAAAAAAAAAAAAhrcAAAAAAAAAAAAAJlYKDwAAAAAAAAAAAAAAAAAANwAAAC4pAAAAAAAAAABHHAAAAAAAAAAAAADn5wAAAACpOQAAAAAAAAAAR6gAAAAAAAAAAAAApgoAAAAAbiUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZpIAAAAAAACEegAAAAAAAAAAAAAAAAAAAACpT+UiAAAAAAAAAAAAAKQkAAAAAAAAAAAJQiUCAAAAAAAAAAC2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgYAAAAAAAAAAAAAAAAAACpLAAAAAAAAAAAAAAAAZWEAAIQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARqUrXAReAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhzMOGAcKAAAAAAwBx7cAAAAAAAAAAAAAAAAAAAAAAAAkbQAAAAAAAAAAAABmaAAAAAAAAAAACCDGBEp7AAAAAAAAAAAAAAAAAAAAAAAAagsnIMgi5XEAAAAAAAAAAAAAAAAAAAAAqF3kEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKp7AAAAAMV7AAAAAEkLRRgAAAAAAAAAAAAAJTUAAAAAAAAAAAAAxGAAAAAAAAAAAAAAAAAAAAAAAAAAAMxQZGcLXgAAAAAAAMlSAADLAqcCAAAAAAAAAAAAAAAA6gvmHQAAAAAAAOY1AAAAAAAAAAAPAEVtAAAAACshJggAAAAAAADGqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5+sAAAAAAAAAAAAAAAAAACRlAAAEVwAARoYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMVOAAAAAEhkAAAAAAAAEwcHYQAARHkAAAAAqWMAAAAAAAAAAAAACjIAAAAA5vMAAAAALQUAAGwBxg4AAAAAAAAAAAAAAAAAAAAAah/nTAAAAAAAAIeCAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQuAAAAAAAAAAANDQcGKhoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEZ0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMagAADmXgAABA8pMAAAAAAAAKo1AAAAAAAAAAAAAAAAAAAAAIVmAAAAAAAAAAAAAAAA6hgAAFcB5hIAAAAAAAAmX6gtAAAAAAAAAAAAAAAAAAAAAAAA0QXHhwAAAAAAAAAAawEGy1YHBSsAAAAACX6G6QAAAAAAAAVvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5FgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJcibvAADFdwAAp24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAORpiyIAAMklJAgAAAAAAADHPwAAR70AAAAAAAAAAAAAAAAME2QkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASyOkSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARBAAAAAA6zlFBQAAAAAAAAAAAACFLgAAAAAAAAAAAAAAAAAAAAAAAAVVAAAAAAAAAAAAAAAAAAAAACh6pvkAAAAAAABEZQAAAAAAAAAAAAAAAAAAAAAAAMetAAAAAAAAhFAAAAAAamzEegAAAAAAAAAAAAAAAAAAh0MAAGcPAAAAAAAARvcAAAAAAAAAAKhi5k0AAGbXAACGmAAAAAAAAAAAAAAAAAAABzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAABm8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoJWf5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKYmYWAAAAAAAAAAAAAAAA6TWFEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKar9gQGCowYAAAAAGY/AAAAAAAAxlAAAAAAAAAAAAAAx5cAAAAAAAAAAMtzAAAAAAAAKQBHDgAAAAAAAAAAAADENwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGPQAAAAAAAGY9AAAGxgAAAABoP0cfAAAAAAAAxBNJAUctMwAAAAAAAAAAAAAAAAAAAAAAAAAJM4YcimsGPAAAZmEAAAAAAACkRQAAAADIEacYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEa6cAFHL4onJoQAAAAAVwJmSGslR8EAACQWAAAAAAAAAAAAAAAAAAAAAAAAZTMAAAAAAAAAAOpa5zYAAAAAAAAAAAAAB78AAAAAAAAAAAAAAABPBwAASjwAAAAAAAAuPwb0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEUeAAAAAAAAAAAAAAAAAAAldwAAAAAAAAAAS2QAAAAAAAAAAAAAAAAAAAAAAAAAAEUkAAAAAOtihQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA4AAAAAAAAAAAAAhoAAAAAAShEAAAAAAAAAAGfiAAAAAAAAAAAAAAAAynSm4wAAAAAAAAAAaC7EBAAAAAAAAAeiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZVoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEamAAAAAAAAAAAAAAAAAADnnAwlpQ0AAAAAAAAAAAAAhlIAAAAAAAAAAMkh5kkAAAAAAAAAAAAAAAAAAEaIKQoAAAAAAAAAAOYwAAAAAAAAAAAoH0coAAAAAAAAAAAAAAAAAACGsAAAAAAAAAAAAAAAAAAAAAAAAAAAykEFTwAAAAAAAAAAAAAAAGgdBhIAAAAAAAAAAAAAhnUAAAAAAACHBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoJoUYAAAAAAAAAAAAAAfvAABHoQAAxFUAAAAAKk4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAizMAAAAAAAAAAGUFAAAAAAAAAABtAed4zF4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhBsAAAAAAAAAAAAAAAAAAAAAAAAAAChtZwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHbwAAAABNAAAAAAAAAAAAAAAAAAAAAADH3Sox5SAAAAAAAAAAAAAAAABJZgc5AAAAAGgfRhYpMSUMAAAAAAAAAAAAAEZUDBUAAAAAAAAAAAAAAAAAAPIT5swAAAAAAAAAAAAAAAAAAAAAcwfHdAAA5BcAAAAAAAAAAEkrpRQAAKVtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAJ6IAAAAAAAAAAAAAAACOFAAAAAAAAPcBhxAoHieGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiByGKLYGAAAAAMdxAAAAAAAAAAAAAAAAAAAAAMlbJ1goGyQJAAAAAAAAAAAAAAAAAAAAAIhPpTAAACawAAAAAAAAAAAAAKZvAAAAAAAAAACoAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALFoAAAAAAADodwAAAAAAAAAAJrMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMFaUXAAAAAAAAAAAAAAAAAAAAAAAAAADIAkYAAAAAAOtlRywAAAAAAAAAACw1AABoM4YHswFnyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxriLSgAAAADGMQAARwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALGOeQAAAAAAAAAAAAAARK6hsAAAAAAAAAAAAAAAAAAKgeBwgAAAAAAAAAAM4iAACISwAAAADGuyohAAAAAAAAAAAAAAAAAADMJmfcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUQAAAAAAAAAAAAAAAAAAAAAAAAhqkAAAAAAAAAAAAAAAAAAAAALT8AAAAAAAAAAAAAAAAAAAt9AAAAAMZ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5mgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKVPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMlJAAAAAAAAAAAFIwAAAAAAAEatAAAAAAAAJSMAAAeFAAAAAAAAAAAAAKZyAAAAAPUBZ0UAAAAAyX5m6wAAAAAAAKZ4AAAAAK0OJwQAAAAAAAAlZAAAAAAAAAAAAACkbQAABmcAAAAAAAAAAAAAAAAAAAAAAAAAAAAApC0AAAAAAAAAAAAAAADLYOUAAADGNQAAAADqHAUtAAAAAAAAAAAAAAAAAAAAAMlmhlwAAAAAKHSnuQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhGoAAAAAAAAAACkCAAAAAAAAAAAAAAAAJn0AAAAAAAAAAG8E5GcAAAAADDAnOQAAAAAAAOaoAABnAwAAAAAIewAACSEFRQAAJDIAAAAAAADGWAAAZpcAAAAAdwGkGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKoAZ0gAAKRZAAAAAGh+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKRkAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQ9AAAAAAAABoAAAAAAAAAAAAAAAAAAAAAAAACHbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACk7AAAAAAAAbFIGbAAAAAAAAAAAAAAAAAoTZ2YAAGcGAAAAAAAAAAAAAAAAAAAAAAAAAABJEAAAAAAAAAAAAACoHAAAAAAAAAAARFQAAAAAAAAAAAAAAAAAAAAAAABEYIsG5QkAAAAAAABG0AAAJjMAAAAAAAAAAAAAAAAAAGYYAAAEVgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlb8gVBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZtAADGcihHhyEAAAAAAAAGmQAAJqoAAAAAAAAAAAAAAAAAAAAAAADFLgAAAAAAAAAAAABlWwAAAAAAAAAAyxcAAAAAAAAAAAAAAAAAAEoZRT+JNwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoaAAANwLHvgAAAAAAAAAAAACnOwAAAABKfMarkgkAAAAAAAAAAAAAAAAAAGgs5yMAAKatAAAAAAAAAAAAAAAA6DgFMAAAAAAAAAUhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKH0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGAwAAAAAAAGRq7BXnLAAAAAAAAAAAAAAAAAAAAADqI4RcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmawAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABpZkavAAAAAAAAAAAAAAAAzRUFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnzgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOhRpEcAAAAAAAAAAAAAAAAAAAAACxDnKwAAAAAAAAAAAAAAAAAAAAAAAAAAAADFcgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5lUAAAAAAAAAAAAAAAAAAAAAAACmvgAAAAAAACR+AAAAAAAAAAAAAAAAAACEKgAAAAAAAAAAAAAAAAAAAAAAAAAAqmsAAAsWAAAAAAAAAAAAAAAAAAAAAAAAEQwlewAA5EwAAAAAAAAAAAAAAAAAAOfvAAAAAAAAAAAAAGaNAAAAAAAAAAAAAAAAAADkHgAAAAAAAAAAaAPnAgAAAAAAAAAAAAAAAAAAAADNBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADkfgAAAAAAAAAAAAAGiAAAAAAAAAAAAAAmxgAAAAAAAAAAahwAAAAAAADIOwYtAAAAAAAA5wsAAAAAAAAAAAAAAABoVwAAAAAAAE4DAAAAAAAAAADniwAAAAAAAGRcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACpXGQIAAAAAAAAAAAAAAAACDoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOBQAACgwAAAAAAABQA8UqAAAAAAAAAAAAAAAAaBkAAAAAJDgAAAAAAAAAAAAAAAAAAAAAAAAAAAkg5iYAAAAAAAAAAAAAAADKXgAAAAAAAAAAAAAAAAAAAABlZwAAAAAAAAAArEgFCAAA54IAAAAAAAAAAAAABiQAAAAAAAAAAAAA5qsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp6MAAAAAAAAAAAAAAAAAAAAADC+GAQAAAAAAAAAAAABHEwAABr4AACbb7AvGPgAAAAAAAAAAAAAAAAAApCFoJKeVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPQBAAAAAAAAAACmpwAAJn8AAAAAAAAAAAAAAAAAAAAAKmtG4qhCAAAAAKa1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhoZBoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHACAACIEwAAAAAAAAAAJX4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIZmAAAAAAAAAAAAAAAAAAAAABcAhRwAAAAAAABnjQAAhp8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqagbgAAAAAKkwZSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKpBAAAAAAAArjgAAAAAAAAAAEdTAAAAAAAAxDQRAGUsAAAAAAAAAACrFAAAiSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACVsAAAAAAAAAAAAAAAAAAAmywAAAAAAAEUdAADnrAAAAAAAAAAAAAAAAAAAAABIJgAAAAAAAExkJvAAAAAAAAAAAAAAAACNFgAAAAAAAAAAB6TJZQAAAAAAAAAAAAAAAAAAAAAAAAAAZVgAAAAAAACnumoBpwesWwAAAAAAAKkqAAAAAAAATgwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyH4AAAAAAAAAAAAAAAAAAM8RxgwAAAAA1wMAAAAA52YAAKaCAAAAAAAAR/EAAAa9AAAAAAAAAAAAAAAAAADmCgAAZpupHgAAAAAAAAAAAAAAAAAACAaHCAAAAAAAAAAAAAAAAAAAAADID6cJKU5EdQAAAADqKwAAAAAAAMoVhtAAAGdYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGUyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1wAAAAAARiMAAAAAAAAAAAAAAAAJAYQFAAAAAGotZw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApRCdfAAAAAGloxpwAAAAAAAAAAEh0BvIAAAAAAAAAAAAAAAAAAAAArFEAAAAAAAAAAAAACCsAAAAAZrkrVCYXAAAAAIg5pwsoXsU7AAAAAAAAAAAAAIV/AAAAAAAAAAAAAAAAAADkDAAAAAAAAGQ+AAAAAAAAAAAAAAAA6hkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAwAAAd5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqAAAAAAAAAAAA5zEAAAAAAAAAAAkcZkYAAAAAAAAAAAAABlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5sIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqGsAAAAAAAAAAEZ2rClFXQAAAAAAAAAAAAAAAAAAxHEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIZRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmrgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEa9AAAAAAAAAAAqGQAAyj+nWQAAAAAIQgAAAAAAAAAAhAIAAAAAAABmnAAAAAAAAGaRAAAAAAAAZiYAAAAAAAAAAAAAZ4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAApTUAAAAAAAAkbgAAAAAAAAAAAACkTQAAAAAAAAAAAAAAAAAABlwAAIYrAACFbAAAAAAAAAAAKDYAAAAAAABqYOe6AAAAAAAAAADqGgAAAAAAAAAAAACNDwAAAAAAAAAAAAAAAAAAAAAAAAAAAADsBgAAAAAAAAAAAAAAAAAAEw7HBwAABGvMIQAAiEcAAAAAAAAAAGZ1AAAAAAAAAAAAAAAAAAAGLAAAAAAAAAAAAAAAAAAAAAAAAORQAAAAAAAAAABSAQAAAAAAAAAAAAAAAAAAihsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA46AAAAAKQNAAAAAAAARtoAAAAAAABmQAAAAAAAAMdGAAAAAAAAAAAAAAAAaggEBQAAAABJWgd8AAAAAGtzAAAAAAAAAAAAAAAAJ48AAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6R4AAAAAAAAAAKRQAAAAAAwpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZqoAAAAAAAAAAAAABqAAAAAAAAAAAAAAAAAAAAAAAAAAAPYAhQMJLUcUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIZfAAAAACloxmsAAAVrAAAAAAAAAAAAAAAAClyFCwAAAACIdgbzAADmuOoHxUkAAAAAAAAmvgAAAAAAAKZYAAAAALQHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABpPAAAAAAAAAAAppcAAAAAAAAAALEDxH8AAAfWAABGOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZFsAAAAAAAAAAAAAAABuFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHgAAAAAAAAAAAAAAAAAAAAAAAAAAAACIeKb6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhokAAAAAAABHdwAAAAAAAAAAAAAAAAAAAAAAAMf0AAAAAEgEpkRMfAAAAAAnODIRR2oAAAAAyFNEEgAAAAAAAAAAyUDmEwAAAAAAAAAAAAAAAAAAAADtEgAAAABmgAAAAAAAAAAAAAAAAAAAAAAAAAAA6noAAAAAAAAAACd8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqEac+AAAAAAAAAAAAAAAAAAAAAAAAhTgAAAAAAAAAAAAAAAAAAAAAAAAAACgdpRIAAAAAAAAAAAAAAAAAAAAAzEgAAAAAAAAoZAAAAAAAAAAAAAAAAMQIAAAAACouAACQBAAAAAAAAAAAAAAAAAAAjBknWso1Jx4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACbjEALGhqp/AAAAAMUyAAAAAAAAAAAAAKYIAAAAAAAAAAAAAMfkAAAAAAAAB2cAAAAAAAAAAAAAAAAAAAAAAABFZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFfahZp+YAAOc0AAAAAAAAAAAAAAAAAAAAAMg/AAAAAAaDAAAAAAAARk0AAAAAAAAEQQAAAAAAAAAAyHsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkKAAAAAAAAAAAAAAAAAAA540AAAAAKHMAAAAAAAAJA6UxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmsAAAAAAABnEU0jpXoAAAUkAAAAAAAAR+xoUQQHAAAAAAAAAAAAAAAAAAAAAKwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChNZq8AAKaWAAAAAGtGAAAAAAAAAAAAAAAAAAAAAKYpAAAAAAAAAAAAACQuAAAAAAAAAAAAAAAAAAAAAAAAxk0AAAAAAADmrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApOBxQAAGQtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaU0AAMsVhiQAAAAAClIGTQAAAAAAAKZVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADnUAAAAAAAAOVOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmngAAAAAAAKbgAAAAAAAAh9IAAAAAqToAAGhCx5krCQAAAAAAAAAAAAAAAAAAAAAAAIwhAAAAAAAAAAAAAMkMxkWqDSUIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhKAAAAAAAAAAAAAMouB+UAAAAAAAAAAAAAAAALAgAAqTLGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlbgAA5roAAAAAAAAAAAAAAAAAAAAAAADFEQAAAAAAAAAAAAAAAAAAAAAAAAAArwJFOuwCJSAAAAAAAAAAAAAAAACsCYcyAAAAAAAAAAAAAAAACFkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiGsG5wAAAACMUaZOAAAAAAAAAAC4ASQvAABH5gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmuwAAAAAAAEfuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkPUodZBUAAAAAAAAAAOpOR5QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABpdAAASxUAAAAAAAAAAAAAAAAAAAAAAAAAAGbGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKVfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABTUAAAAASFkAAAAAAAAAAKdVAAAAAAAAAAAAAAAAqiMAAAAAAAAAAAAAAACkNQAAAAAAAAAAAAAAAAAAAAAAAAAA6ghHAgAAAAAAAAAAAAAAAAAAAAAAAAAAjg6HZwAAAAAAAAAAAAAAACokAAAAAAAAAAAAAAAAAAAAAGRUAAAAAAAABrIAAAAAAAAAAAAA5lAAAAAAAADGpgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACLBCYaAAAAAAAAAAAAAAAAAADEKgAAAAAAAAR0AAAAAAAAAAAAAMfl1A4Ha8tRxCcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMAZ3Lpb8Y4AAAAACxAJ7IAAAAAAAAAAAAAAADqYgAALBMAAAAAAAAAAAAAAACEY6lxpjctKwAAAAAAAAAAAAAAAAAAAABGSAAAAAAAAGatAAAAAAAAZUUAAAAAAAAAAAAAAADIXwAAAAAAAAAAAAAAAAAAAAAAAAAAp0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZuAAAAAAAAAAAAAEa8AAAAAOt6AAAJYAAAAAAAAAAABEkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEHMgDRTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMc5AAAAAAAAJDAAAMUxAAAAAAAAAAAAAAAAAAAAAAAAZCsAAAAAAAAAAKkPZ52IUAURAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApzoAAAAAAAAAAAAA56oAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5VkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOaxAAAAAAAAAAAAAAAAAAAAAAAApl0AAAAAAAAAAEhEp1AAAAAAAAAAAAAAAACsIgAAAABmnwAAAAAAAAAAAAAAAAAApjgIQ2RFAAAAAGp7Z4oAAAAASgsAAAAAAAAAAAAAAAAAAAAAhGsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJCAAAAfdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOaFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmCgAAZGgAAAAAAAAAAAAAAAAAAMb6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOkLx9YAAAAAAAAAAAAAAAAAAEUDAADERAAAAAAAAAAAAACmcAAAAAAAAAAAAAAAAMhmAAAAAEYPAAAAAAAA5mQAAAAAAAAAAAAAxyAAAIVNKEtEBAAAAABJFQAAAAAAAAAAJEMAAAAAAAAAAAAAAAAAAAAAAACFKQAAAAAPGqbuyBamIAAAAAAAACbXAAAAAAAAAAAAAKR0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACbJAADnbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIVlAAAAAMl1hu8AAAAAAAAAAAAAAAAAAEdhAAAAAAAAJBEAAEakAAAAAAAAAAAAAAAAAACmzwAAAAAAAAAAAAAAAAAA5sYAAAAAAAAAAAAAAACLZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkXJQsAAAaRzBzFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6wemAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIbZAAAAACgWRxUAACb1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAawsAACwChwUAAAAAAAAAAAAAAAAAAAAAAADFIQAABSUAAAAAAAAAAAAAAAAAAGa+AAAAAAAAAAAAAAAAAAAAAAAAAACrXuQAAAAAAAAAAAAAAAAAAAAAAAAAAABKQodJAAAAAAAAAAAAAAAAAAAAAAAARmIAAAAAAAAAAAAAh0hoTgcL6TcmBwAAAAAAAAAAAAAAAAAAAACoaeZbAAAAAAAAAAAAAOUD7AEAAIo5JUGMAQY1AAAAAAAAx6IAAAAAAAAAAAAAAAAAAGVKAAAAAAAApQGJRCYMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7iLOOfcAAAAAAAAAAAAAAAAAAAAAAAAAABxDgAAAAAAAAAAAAAAAObAAADnigAAAAAAAAAAKAAAAOgsBT0AAGYhAAAAAAAA5vcAAAAAAAAAAAAAAAAAAGaQAADmxAAAxrPpAwAAAAAlL7EMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACJOwAAAAAAAAAAAAAAAAAAAADn/AAAAAAAAAAAAACH5QAAAAAAAAAAcARlaQAAAAAAAAAAAAAAAAAAREUAAAAAAAAFQytO5RkAAGerAAAAAAAABDUoYgcqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAawPHXQAAAAAAAAAAzB0AAAAAAAAAAAAA7C8AAAAAAAAAAAAAAAAAAAAAZEuqWmQBAAAAAAAAAAAAAAAAAAAAAAAAhDsAAAAAAAAAAAAABsIAAAAAAAAAAAAAAAAAAARVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABrNgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA57IAAAAAtAEFDgAAAACKLAAAAAAAAAAAAAAAAAAAAAAAAAAAZvUAAAAAAACGm0wCAAAAAAAAAAAAAAAAZmwAAAAAAAAAAAAAAABJBoRYKgkHSgAAxD4AAAAAAAAAAAAAAAAqFGYrAAAAAAAAAADIOiQEAADHHmhHRgEAACY6yEwAAKodAAAAAAAAAAAAAA0DRQIAAEY/AAAAAAAAAAAAAAAANgSkJgAAAAAAAAAAAAAAAAAAAAAAAAAAiREAAAAAAAAAAAaEAAAAAAAABtUAAAAAAAAAAAAAAAAAAIaBAAAAAAAAAAAAAAAAAAAAAAAAZqQKNsUKCCGFQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAag0AAAAAAAAAAAAAag/kcwAAAACqd6ePAAAAAAAAAAAAAEVhAADFPogYAAAAAAAAAAAGpAAAAAAAAAAAAAAAAAAA5WoAAAAAAAAAAAAAAAAAAAAAAAAAAKoFB68AAAAAAABkfQAAAAAAAAAAAAAmiQAAAAAAAAAAAAAAAAAAAAAoRIdMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAywYAAAAAAAAAAIcVAAAAAAAApoAAAAAAAAAAAAAAAAAAAAAAAAAERwAAAAAAAIRbKk0AAAAAxnnNC6d7qFsAAAAAAAAAAAAAAACn3wAAAAAsU+f7AAAAAAAAAAAAAAAAymTlIwAAAAAAAAAAAABmwAAAAAAAAAAAAAAAAAAAAAAAAAAAzRZnwwAAAAAAAAAAAAAAAAAAAAAAAIc8AAAAAAAAAAAAAObKAAAAAAAAAAAAAAAAAAAAAMhtJuUAACbEAAAAAAAAAAAAAAAAAAAAAKwLAABoWUR8AAAAAAAAAAAAAOQHAADkSQAAAAAAAAAAAAAAAAAApV0AAAAAAAAAAGxExS0AAAAAAABn2gAAAAAAAAAAAAAAAAAAJwsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5rYAAIZgqm8AAAAAAAAUBgAAAACldQAAAABKViffSw0HNwAAAAAAAAAAAAAAAAAAAAAAAAAAEQQAAIkpBBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFagAAAAAKNIdGAADEcgAAhtwAAAAAeAAAAAAARSIAAAAAAAAAAKg+AAAAAAAAAAAAAAAAAABqauVcAAAkBgAA5m0AAAAA6AUAAAAAAAAAAAAAAAAkbAAARpYAAAAAAAAAAAAAAADpBQUiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOa1AAAAAAAAAABpb+fuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRfAAAAAAAAAAAAAAAAAAAAAAAA5DIAAOcWAAAAAE09AAAAAAAAAAAAAAAAAABrBGZbAAAAAAAAAAAAAAAAAABkZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5EcAAAAAAAAAALEFR2YAAAAAqwnGGwAAAAAAAAAALGoG6wAAAAAAACZPAACGowAAAAAAAAAAAAAAAAAAAAAAAAAAygoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJGYAAAAAAAAAAAAAAAAAAAAAAABFbgAAAAAAAEZyAAAAAAAAAAAAAAAAAAAAAAAAAAAqbAAAAABENegxRgcAAAAAAAAAAAAAAABJQ8cMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIdtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaRHFRgAA5weSAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaABGDgAAAAAAAAAAAAAAAAAAAAAISAAAAAAAAAAAAAAAAAAAAACldAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIZWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACl4AAAAAAAAAAAAAAAAAAAAA5C4AAGZ+AAAAAAkMAAAAAAAAAAAAAAAAAAAAAAAAjRIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKCoHB0pTAADIHkUxAAAAAAAAAAAAAAAAAAAAAKk2AAAAAAAASj8AAAAAAAAAAGZ9AABnkQAABCkAAAAAAAAAAAAAAAAAAAAACH0AAAAAAAAAAAAACF2kDAAAAAAAAAAAAADFWgAAAAAKFgAATBImAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5GgAAAAAAAAAAAAAAADsGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0h5m8asDAAAAAGfdAAAAAAAAAAAAAMZpygClEwAAAAAAAAAAAAAAAAAAAAAAAGVtAAAAAKk7pWAsFuRPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZtoAAAAAAAAAAM0TJm0AAGRSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIhTZG4AAMYJjE4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGtgAARngAAAAAAAAAAAAAhTkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASwTkGAAAAAAAAIYwTjsAAOshAACpKQZMAAAAAAAAAAAAAAAANgYAAIx7AABoWCZNAAAAAAAAAAAAAAAAAACGXgAAAAAAAAAAAADmxQAAAAAAAAAAAAAAAAAAAAAAAAAAqyMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABysAAAAAAAAAAAAAAAAAAAAAakCn1QAAAAAAAAAAAAAAAAAAAACJMgAAAAAAAAAAhD4AAAAAAAAAAAAAAAAAAAAAAACFCAsbAAAAAAAAAAAAAAAAAAAIPSYsAAAAACkWhx0AAAAATDlEPQAAAAAAAAAAAAAAAIxeBrwAAKZeAADn2AAAAACIDcVKAAAAAAAAAAAAAAABgACAAUAAQAHAAMABIAAgAaAAoAFgAGAB4ADgARAAEAGQAJABUABQAdAA0AEwADABsACwAXAAcAHwAPABCAAIAYgAiAFIAEgByADIASgAKAGoAKgBaABoAegA6AEYABgBmACYAVgAWAHYANgBOAA4AbgAuAF4AHgB+AD4AQQABAGEAIQBRABEAcQAxAEkACQBpACkAWQAZAHkAOQBFAAUAZQAlAFUAFQB1ADUATQANAG0ALQBdAB0AfQA9AEMAAwBjACMAUwATAHMAMwBLAAsAawArAFsAGwB7ADsARwAHAGcAJwBXABcAdwA3AE8ADwBvAC8AXwAfAH8APwBAgACAYIAggFCAEIBwgDCASIAIgGiAKIBYgBiAeIA4gESABIBkgCSAVIAUgHSANIBMgAyAbIAsgFyAHIB8gDyAQoACgGKAIoBSgBKAcoAygEqACoBqgCqAWoAagHqAOoBGgAaAZoAmgFaAFoB2gDaAToAOgG6ALoBegB6AfoA+gEGAAYBhgCGAUYARgHGAMYBJgAmAaYApgFmAGYB5gDmARYAFgGWAJYBVgBWAdYA1gE2ADYBtgC2AXYAdgH2APYBDgAOAY4AjgFOAE4BzgDOAS4ALgGuAK4BbgBuAe4A7gEeAB4BngCeAV4AXgHeAN4BPgA+Ab4AvgF+AH4B/gD+AQEAAQGBAIEBQQBBAcEAwQEhACEBoQChAWEAYQHhAOEBEQARAZEAkQFRAFEB0QDRATEAMQGxALEBcQBxAfEA8QEJAAkBiQCJAUkASQHJAMkBKQApAakAqQFpAGkB6QDpARkAGQGZAJkBWQBZAdkA2QE5ADkBuQC5AXkAeQH5APkBBQAFAYUAhQFFAEUBxQDFASUAJQGlAKUBZQBlAeUA5QEVABUBlQCVAVUAVQHVANUBNQA1AbUAtQF1AHUB9QD1AQ0ADQGNAI0BTQBNAc0AzQEtAC0BrQCtAW0AbQHtAO0BHQAdAZ0AnQFdAF0B3QDdAT0APQG9AL0BfQB9Af0A/QEDAAMBgwCDAUMAQwHDAMMBIwAjAaMAowFjAGMB4wDjARMAEwGTAJMBUwBTAdMA0wEzADMBswCzAXMAcwHzAPMBCwALAYsAiwFLAEsBywDLASsAKwGrAKsBawBrAesA6wEbABsBmwCbAVsAWwHbANsBOwA7AbsAuwF7AHsB+wD7AQcABwQHAgcGBwEHBQcDBweHAIcEhwKHBocBhwWHA4cHRwBHBEcCRwZHAUcFRwNHB8cAxwTHAscGxwHHBccDxwcnACcEJwInBicBJwUnAycHpwCnBKcCpwanAacFpwOnB2cAZwRnAmcGZwFnBWcDZwfnAOcE5wLnBucB5wXnA+cHFwAXBBcCFwYXARcFFwMXB5cAlwSXApcGlwGXBZcDlwdXAFcEVwJXBlcBVwVXA1cH1wDXBNcC1wbXAdcF1wPXBzcANwQ3AjcGNwE3BTcDNwe3ALcEtwK3BrcBtwW3A7cHdwB3BHcCdwZ3AXcFdwN3B/cA9wT3AvcG9wH3BfcD9wcPAA8EDwIPBg8BDwUPAw8HjwCPBI8CjwaPAY8FjwOPB08ATwRPAk8GTwFPBU8DTwfPAM8EzwLPBs8BzwXPA88HLwAvBC8CLwYvAS8FLwMvB68ArwSvAq8GrwGvBa8DrwdvAG8EbwJvBm8BbwVvA28H7wDvBO8C7wbvAe8F7wPvBx8AHwQfAh8GHwEfBR8DHwefAJ8EnwKfBp8BnwWfA58HXwBfBF8CXwZfAV8FXwNfB98A3wTfAt8G3wHfBd8D3wc/AD8EPwI/Bj8BPwU/Az8HvwC/BL8Cvwa/Ab8FvwO/B38AfwR/An8GfwF/BX8Dfwf/AP8E/wL/Bv8B/wX/A/8HAAAgABAAMAAIACgAGAA4AAQAJAAUADQADAAsABwAPAACACIAEgAyAAoAKgAaADoABgAmABYANgAOAC4AHgA+AAEAIQARADEACQApABkAOQAFACUAFQA1AA0ALQAdAD0AAwAjABMAMwALACsAGwA7AAcAJwAXADcADwAvAB8APwCAAMAAgAEAAUABAALAAUACgAIAAAAACAAJAAMAIwAHAEcAJwBnABcALwCvAG8A7wAfAAAAAAAAAAQADAACAAoABgANAB0ACwArABsAOwBXADcADwBPAD8BPwO/AL8CvwG/AwAADgABABkABQAVABMAMwB3AJ8AXwDfAN8B3wM/AD8CfwB/An8BfwP/AP8C/wH/Aw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGwA7AAcAJwAXADcAHgABABEACQAZAAUAAAAIAAQADAACAAoABgAVAA0AHQADABMACwAPAC8AHwBfAD8AfwD/AP8C/wr/Bv8O/wH/Cf8F/w3/A/8L/wf/DwAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAwAGAAAAAAAAAAAAAAAUAAAAAAAAABUAAAAWAAAAAAAAAAAAAAAAAAAAAAAXAAAAAAAZAAAAHQAAADUAAAAAAAAAAAAAAAAANwAAAAAAAAAAAAAAAAA9AEwAAAAAAAAAXgAAAAAAAAAAAAAAAABgAAAAYQAAAGIAAAAAAAAAAAAAAAAAAABjAGUAagBsAAAAAAAAAAAAAABuAAAAbwBwAAAAcQB2AHwAAAAAAAAAAAAAAH0AgAAAAAAAAAAAAIEAAAAAAIMAAAAAAAAAAAAAAAAAhAAAAAAAhwAAAAAAAACJAAAAAAAAAAAAAACKAIsAAAAAAAAAAAAAAAAAAACOAI8AkAAAAAAAAAAAAAAAkQAAAAAAAACSAJUAlwCYAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJoAAAAAAAAAAAAAAAAAmwAAAAAAAAAAAKAAtgAAAAAAAAAAAAAAAAC3AAAAAAAAALwAvQAAAAAAwAAAAAAAAAAAAAAAAADCAAAAAAAAAAAAAAAAAAAAAADFAMoA0QAAAAAA0gAAAOAAAAAAAAAA4QAAAAAAAAAAAAAAAAAAAAAAAAAAAOcAAAAAAAAA6AAAAPAAAAAAAPIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPQAAAAAAAAA9gAAAAAA+QD7AP0AAAAAAAAAAAAAAAIBAAAAAAUBBwEAAAAAAAALAQAAAAAMAQAADQEAAAAAAAAAAAAAAAAAAAAAAAAPAQAAAAAAAAAAAAAAABABAAARAQAAFQEAABYBHgEAAAAAAAAAAB8BAAAhASIBIwEAAAAAAAAnAQAAAAAoASkBAAAAAAAAAAAAAAAAAAAAAAAAAAAqAQAAAAAAACsBAAAAADEBAABEAQAAAAAAAAAAAABHAQAASAFJAQAAAAAAAAAAUAEAAAAAVAEAAFUBVgFXAQAAAABaAQAAXAEAAAAAAAAAAAAAAABdAV8BAAAAAGMBAABrAQAAbAEAAHABcQEAAHIBAAAAAAAAAAAAAAAAAAB0AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1AQAAdwEAAAAAAAAAAHgBeQEAAAAAigGLAYwBAAAAAI4BAAAAAAAAAACQAQAAAACYAQAAAAAAAAAApAEAAAAAAAAAAAAAAAClAQAAAACmAacBAAAAAK0BswG0AboBAAAAALsBAAC8Ab0BxQHIAQAAyQEAAAAAAAAAAAAAygEAAAAAAADLAQAAAAAAAMwBAADOAc8B0QEAAAAAAAAAAAAAAADSAdUBAAAAAAAAAAAAAAAA1gEAAAAAAADaAQAA3AEAAAAAAAAAAOMBAADlAQAAAAAAAOYBAAAAAOgB6wHsAQAAAADxAfMB9AEAAPUBAAAAAAAA+QEAAAAA+gEAAAAAAAD7AQAAAAAAAP0BAAAAAAAAAAD/AQACBwIAAAAAAAAAAAAAAAARAhICAAAAAAAAFgIAAAAAAAAAAB8CAAAAAAAAAAAAAAAAAAAAAAAAKQIAAAAAAAAAAC0CMAIAAAAAAAAAAAAAAAAxAgAANAIAAAAAAAAAAAAAAAA1AjYCAAA/AgAAawIAAGwCAAAAAG8CcAIAAAAAAABxAgAAAAByAnMCAAAAAHQCAAAAAAAAAAB2AgAAdwIAAAAAAAAAAAAAAAAAAAAAAACBAgAAAAAAAAAAgwKQApwCAAAAAAAAoQIAAAAAAACiAgAAAAAAAAAAAAAAAAAAAACqAgAArwIAALICAAC1ArsCvAIAAAAAAAAAAAAAAADAAsECAAAAAAAAAADDAsYCAADHAgAAAAAAAAAA1gIAAAAA2QIAAAAAAADaAtsCAAAAAAAAAAAAAPACAAAAAAAA+gIAAPsCAAAAAP8CAAAAAAAAAgMGAwAAAAAHAwAAAAAAAAAAAAAAAAAAAAAAAAAACAMAAAAAAAAJAw8DAAAAAAAAEQMUAwAAAAAAAAAAFgMAAAAAAAAZAwAAAAAAAAAAGgMAAAAAJAMzAzUDAAA7AwAAAAAAAEIDAAAAAEMDAAAAAAAASQMAAEwDAABSA1MDWwMAAFwDAAAAAAAAAAAAAAAAAABqAwAAbAMAAG0DegMAAAAAAAAAAAAAAAAAAAAAfQN+A4IDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgwMAAAAAAACEA4gDigMAAAAAAACLAwAAjAONAwAAjgMAAAAAAAAAAI8DAAAAAAAAAAAAAJQDAAAAAAAAmgOdAwAAogMAAKYDAAAAAAAAAAAAAK8DAAAAALADAAC5A7oDAAAAAAAAAAAAAAAAuwMAAMIDwwMAAAAA0AMAAAAA0QPSA9MD1AMAANUDAAAAAAAAAADYAwAAAADZAwAAAADbA90D3wMAAAAAAAAAAAAAAAAAAAAAAADgAwAAAAAAAOEDAAAAAAAAAAAAAAAA5AMAAAAAAADoAwAAAAAAAAAAAADqAwAAAAAAAAAA7QPvAwAAAAAAAPEDAAAAAAAA8gMAAAAAAAAAAAAAAADzAwAA9AMAAAAAAAAAAPYD+AMAAAAAAAD8AwAA/QMAAAAAAAAAAP4DAAAAAAAAAAQAAAAAAAAAAAAAAAABBAAAAAACBAMEAAAAAAAAAAAAAAcEAAAJBAAAAAAAAAAACgQAAAAAAAANBBAEAAAAAAAAEgQTBAAAAAAdBAAAHgQAAAAAIQQAAAAAAAAiBAAAAAAkBAAAAAAAAAAAAAAAAAAAJQQAAAAAJgQAAAAAAAAAACcEAAAAAAAAAAAoBAAAAAAAAAAAAAApBAAAAAAAAAAAKgQrBAAAAAAAAC0ELgQwBAAAAAAAAAAAAAAAADEEAAAzBAAAAAAAAAAAAAAAADgEPAQAAAAAAAAAAEAEAAAAAAAAAAAAAAAARgQAAEcEAABTBAAAAAAAAFgEWgQAAF8EAABiBAAAAABmBAAAaQQAAGoEAAAAAAAAAAAAAGwEAAAAAAAAAAAAAAAAeAQAAAAAeQR6BAAAfAR9BAAAAAB+BH8EAAAAAAAAAACABAAAgQQAAAAAAAAAAAAAggQAAIsEAAAAAAAAjAQAAAAAAAAAAAAAjQQAAI8EAACSBAAAAAAAAAAAAACTBJQEAAAAAAAAAAAAAAAAAAAAAJUElwSZBAAAogQAAAAAAAAAAAAAAAAAAAAAAAAAAKsEAAAAAMUEAAAAAMgEAAAAAMsEAAAAAAAAAAAAAMwEzQQAAAAAzgQAAAAAAAAAAAAAAAAAAAAAAADPBAAAAAAAANEEAAAAANsE3ATeBOAEAAAAAAAAAADmBOcE6gTrBAAAAAAAAOwEAAAAAO0EAAAAAAAA7gTwBAAAAADxBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPIEAADzBAAAAAAAAAAA+QT6BPwECQUAAAAACwUMBQ0FAAAAAA4FDwUQBQAAAAAAAAAAFgUAABgFAAAAAAAAAAAAAAAAAAAAAAAAHwUgBQAAIgUAACQFKAUpBQAAAAAAAAAAAAAAAAAAKgUrBSwFAAA3BQAAOAUAAAAAAAAAAD0FPgUAAEIFAABNBQAAAAAAAE4FUAUAAAAAAAAAAAAAAABRBQAAAAAAAFIFVQUAAFYFAAAAAAAAAAAAAAAAAABjBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFAABsBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzBQAAAAAAAAAAewUAAH0FAAAAAH8FAAAAAAAAAAAAAIAFgQUAAIIFAAAAAAAAhAWFBYgFAAAAAJUFqwUAAAAArgUAAAAAAAAAAAAAAAAAAK8FAAAAAAAAAAAAAAAAAACwBQAAAAAAAAAAswW0BbUFwwUAAAAAAAAAAAAAAADFBQAAyAUAAMkFAAAAAM4FAAAAANcFAAAAAAAA2AUAAAAA2gXbBd0F8AXxBQAAAAAAAPYFAAAAAAAAAAD4BfkFAAD9BQAGAAAAAAAAAQYCBg0GAAAOBhYGFwYkBgAAJQYAAAAAAAAAAAAAAAAAAAAAAAAnBgAAAAAAAAAAAAArBgAAPwYAAEMGAABEBgAARQYAAAAAAAAAAAAASAZKBgAAAAAAAAAASwYAAE8GAABQBlIGAABTBgAAAABWBgAAAAAAAAAAYgYAAAAAAABjBgAAAAAAAGkGAAAAAAAAAAAAAAAAAAAAAAAAawYAAAAAAAByBgAAAAB0BgAAAAAAAAAAAAB1BgAAAAAAAHYGAAAAAAAAAAB3BgAAfgYAAAAAfwaABgAAAACEBgAAAACFBoYGAACIBokGAAAAAAAAAAAAAIoGAAAAAAAAiwaMBpAGAACSBgAAAACXBgAAAAAAAAAAAACoBgAAAACpBgAAAAC5BgAAAAAAAAAAxgbHBgAAAAAAAAAAyQYAAAAAAAAAAMsGAAAAAMwGAAAAAAAAAAAAAAAAAAAAAAAAAADNBs8GAAAAAAAAAADRBgAAAAAAANUGAAAAAAAA1wYAAAAAAAAAAAAAAADgBgAAAAAAAAAA5QYAAAAAAAAAAAAA+AYAAPkG+wYAAAAAAAAAAPwG/QYAAAAAAAAAAP4G/wYBBwAABgcHBwAAAAAAAAAACQcAAAsHDQcAAAAAAAAOBxMHAAAUBxYHAAAdBwAAAAAAAAAAAAAeBykHAAAAAAAAAAAAAAAAOAcAAAAAAAAAAAAAAABBBwAAAAAAAEMHAAAAAAAAAABFBwAAAAAAAAAAAAAAAAAASgcAAIEHhQcAAAAAAACJB4oHAAAAAAAAAAAAAAAAAAAAAAAAiwcAAAAAAAAAAIwHAAAAAAAAjgcAAAAAAAAAAAAAAAAAAAAAmgcAAAAAnAcAAAAAAAAAAJ4HAAClBwAApgcAAAAAAAAAAAAArQevBwAAAAAAAAAAsAcAALEHAACzB7QHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtQcAAAAAAAAAALcHAAAAAAAAAAC4B7sHAAC+BwAAAAAAAAAAwAfEBwAAAAAAAAAAxgfUB9gHAAAAAAAA3AfdBwAAAAAAAAAAAAAAAAAAAAAAAAAA3wcAAOAH4QcAAAAAAAAAAOUHAAAAAOkHAAAAAAAAAAAAAO0H9Af4BwAA+gcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+wcAAAAAAAAAAAAA/QcAAAAAAAAAAAAAAAAAAP4H/wcAAAAIAQgAAAsIAAAAAA8IAAAQCBEIAAAAABIIAAAAAAAAAAAAAAAAFQgAAAAAAAAAABYIAAAXCAAAGAgAAAAAAAAAACAIIggjCAAAAAAAAAAAAAAlCAAAJggoCCkIOQgAAAAAAAAAADsIAAAAAEQIRQgAAEgIAAAAAEoIAAAAAAAAAAAAAEsIAAAAAE0ITwhQCAAAAAAAAFIIAAAAAAAAWQhbCFwIXQgAAAAAAAAAAAAAAAAAAAAAAABgCGEIAAAAAGIIZQgAAAAAAAAAAGYIAAAAAGcIbggAAG8IAABwCAAAAAAAAAAAAAAAAHEIcggAAAAAkgiaCAAAAAAAAAAAAAAAAJ0IqQgAAKwIAACtCAAArgiwCAAAAAAAAAAAvQgAAAAAAAAAAAAAvggAAL8IwQgAAAAAwggAAAAAAAAAAAAAwwgAAAAAAAAAAAAAAADMCAAAAADNCAAAAAAAANEI0ggAAAAAAADUCAAAAAAAAAAAAAAAAAAA1ggAANgIAAAAAAAAAAAAAN0I3ggAAAAAAAAAAAAAAAAAAAAAAADfCAAA4QgAAAAAAAAAAOUIAAAAAAAAAADmCAAAAAAAAAAA5wgAAOgIAADrCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8IAAAAAAAAAAAAAAAAAADxCPIIAAAAAAAAAADzCAAA9AgAAAAAAAD1CPcI+AgAAAAAAAAAAAAAAAAAAPoIAAAAAAAAAAAAAP8IAAABCQAAAAACCQAAAwkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJCQoJCwkMCQAAAAAOCQAADwkAABIJAAAAABMJAAAUCQAAFgkAAAAAAAAAAAAAAAAAAB8JAAAgCSIJIwkAACQJAAAAAAAAMwkAAEcJAABOCVIJAABTCQAAAABaCQAAAAAAAAAAWwkAAF0JAAAAAAAAAAAAAF4JAAAAAAAAAAAAAAAAAABfCWIJZAloCWsJAAAAAAAAbQkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwkAAAAAcAlxCXMJAAB0CQAAAAAAAAAAAAB5CQAAAAAAAHoJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAewl8CQAAfQkAAAAAfgmCCQAAhAkAAAAAAAAAAAAAAACJCYoJAACNCQAAAACOCZkJAACbCQAAAACeCQAAoAkAAK0JAACuCbYJAAAAAAAAuwkAAAAAvQkAAAAAvgkAAL8JAADRCdsJAAAAAAAAAADcCQAAAAAAAAAAAAAAAOAJ4QniCQAAAADjCQAA5QkAAAAA5gnnCQAA6AnpCQAA6gkAAOsJ7AkAAAAAAADxCfIJAAAAAAAAAAAAAAAAAAD0CQAAAAD1CQAA9gn7CQAAAAAAAAAAAAD9CQAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQoAABAKAAAAAAAAAAAAAAAAAAAAAAAAEQoSCgAAAAAAABMKAAAAAAAAAAAAAAAAAAAUCgAAAAAAAAAAFQoAAAAAAAAAABcKAAAYCgAAHAoeCgAAAAAAAB8KAAAAAAAAAAAhCiIKAAAjCgAAKQoqCgAAAAArCgAALQoAAAAAAAAuCi8KMwoAADcKAAAAAAAAOQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADsKAAAAADwKAAAAAAAAPQoAAD8KAABBCgAAAABECkUKAAAAAEsKTApNCgAAAABPCgAAAAAAAFIKAAAAAAAAAABTCgAAVAoAAFkKAAAAAAAAAAAAAAAAXwpgCgAAAABhCgAAAAAAAAAAAABiCgAAAAAAAAAAAABjCgAAAAAAAAAAaAp9CgAAfwoAAIAKAAAAAIEKAAAAAIYKAACHCgAAAACKCgAAjQqSCgAAAAAAAJMKAACVCpYKlwoAAAAAAACgCqoKrwoAAAAAAAAAALIKtAoAAAAAAAAAALsKAAAAAAAAAAAAAAAAvAoAAAAAvQoAAAAAAAAAAAAAvgoAAAAAwArCCgAAAAAAAAAAAADGCgAAAAAAAAAAygoAAAAAAAAAAMsKAAAAAAAAAAAAAAAAAADMCs8KAAAAAAAAAADQCgAAAADSCgAAAAAAAAAAAAAAAAAA0woAAAAAAAAAAAAAAAAAAAAAAADUCgAAAAAAAAAAAADVCtgKAAAAAN8KAAAAAOAKAADlCgAA5goAAAAAAADoCgAAAAAAAAAAAAAAAAAAAAAAAAAA6QrrCgAAAAAAAAAAAAAAAOwKAAAAAAAAAAAAAAAA7QrvCgAAAAAAAAAA8woAAAAAAAAAAPYKAAD3CvgKAQsDCwAAAAAAAAAAAAAFCwAAAAAAAAAABgsHCwAAAAAAAAAAAAAAAAAACAsAAAAADAsAABILAAAAAAAAAAAAAAAAFAsAABYLAAAAABcLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkLAAAAAAAAGgsAAAAAAAAAAAAAGwscCwAAAAAAAAAAHgsAAAAAHwsAACELAAAlCwAAAAAAAAAAAAApCwAAAAAAAAAAKgsAACsLAAAAACwLAAAuCzQLAAAAAAAAAAA7CwAAPAsAAAAAPQs+C0QLSQtKCwAAAABLCwAAAABMCwAAAAAAAFoLYAsAAGELAAAAAAAAAAAAAAAAAAAAAGQLAAB2CwAAAAAAAAAAAAB3CwAAAAAAAAAAewsAAHwLAAAAAAAAAAAAAAAAAAB9CwAAAAAAAIILAACFCwAAAACGC4oLiwsAAAAAAACPC5ELAAAAAJILAACTCwAAAAAAAAAAAAAAAJQLlQuWC5cLAAAAAAAAAAAAAAAAAACZCwAAAAAAAAAAAACaC58LAACmC6cLqAsAAAAAAAAAAAAArQsAAAAArgsAAAAAAAAAAAAAAAAAAK8LAAAAAAAAAAAAAAAAAAAAALYLAAC4C7kLAAAAALoLAAAAAAAAuwsAAAAAxAsAAAAAzgsAAAAA0AsAAAAA0QvTCwAAAAAAANYLAAAAAAAAAADaC9sLAAAAANwLAADfCwAA6QsAAAAA6gsAAAAAAAAAAAAAAADrCwAA7QsAAAAAAAAAAPELAADyCwAAAAAAAAAAAAAAAAAAAAD3CwAAAAABDAIMBgwHDAAACAwODAAAAAAAAAAAAAAAAAAAAAAPDAAAFAwAABcMAAAbDAAAAAAAABwMAAAdDB4MAAAyDAAAAAAAADQMAAA1DAAAAAAAAAAAAAAAADwMPgwAAAAAQAwAAAAAAAAAAAAAAAAAAEsMAAAAAE0MAAAAAAAAAAAAAE4MTwxQDAAAAAAAAAAAVgwAAAAAWAwAAAAAWQwAAAAAWgwAAFsMXgxgDAAAAABhDGIMAAAAAGMMAAAAAAAAAAAAAAAAAABuDAAAcAwAAAAAdAwAAAAAegwAAAAAAAAAAAAAAACEDAAAAAAAAAAAiQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAyRDAAAAAAAAAAAAAAAAAAAkwwAAAAAlAyWDAAAlwwAAAAAAAAAAJgMAACZDJoMAACcDKEMAACnDKkMqgwAAAAAswy0DLUMtwwAAAAAAAAAAAAAAAAAAAAAvAwAAAAAvQwAAAAAAADDDAAAAAAAAAAAAAAAAAAAAADHDAAAAAAAAM4MAADSDAAAAAAAANQMAAAAAAAA1QzWDAAAAAAAAAAAAAAAAAAA1wzcDAAAAAAAAAAA3gzgDAAAAADjDOQM5QwAAOYMAAAAAAAAAAAAAOgM6gwAAAAAAAAAAAAAAADsDAAAAAAAAAAAAAAAAAAAAAAAAO8MAAAAAAAAAAAAAAAAAAAAAPAM8gzzDAAA9gwAAAAAAAAAAAAAAAAAAAAA9wwAAAAAAAAAAAAA+QwAAAAAAAAAAAAAAAAAAAAAAAD6DAAAAAD8DP0MAAAAAP4MAAAAAAANAQ0DDQAAAAAHDQAAAAAJDQAACg0AAAAAAAAAAA8NEw0AAAAAAAAUDQAAAAAXDQAAAAAAAAAAAAAAABoNAAAAAAAAAAAAAAAAAAAAAAAAAAAbDQAAAAAlDSYNJw0AAAAAAAAAAAAAAAAoDSkNAAAqDQAAAAAtDQAAAAAwDQAAAAAxDQAAMw07DQAAAAAAAAAAAAA+DQAAAAAAAAAAAAAAAAAASg0AAEsNbA1tDW8NAAAAAHENAAAAAAAAcg0AAAAAeQ0AAAAAAAB6DQAAAAAAAAAAAAAAAAAAew0AAAAAfA0AAH0NgA0AAIENAAAAAIINAACDDQAAAAAAAAAAAAAAAAAAAAAAAIQNAAAAAI0Njg0AAAAAkw0AAAAAAACYDZ8NoQ0AAKINAAAAAKMNqw0AAKwNAAAAAK0NAAAAAAAArg0AALoNAAAAAAAAvA29DQAAAAAAAL4NAAAAAAAAAADADcENwg0AAAAAxg3KDQAAAAAAAAAAyw0AAAAAAAAAANANAAAAAAAAAAAAAAAAAADTDdUNAAAAANYN2A0AANsN3A0AAAAA3g0AAOENAAAAAAAAAAAAAAAAAADiDQAA4w0AAOYNAADnDQAAAAAAAAAAAAAAAAAAAADrDQAA/Q0AAAAAAAAPDgAAAAAAABAOAAARDgAAEg4TDgAAAAAWDhgOAAAaDhsOAAAAAAAAAAAAAAAAAAAAAAAAHA4gDiMOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoDiwOAAAtDjIOMw4AAAAAAAAAAAAAAAA0DgAANQ4AAAAANg5DDgAAAAAAAAAAAAAAAEQORQ4AAAAAAAAAAEgOSQ4AAAAAAAAAAAAASg4AAAAAAAAAAEsOAABNDk8OUA4AAFEOAABsDgAAAAAAAG4OcA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAByDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQOAAAAAHUOAAAAAAAAfA59DgAAAAAAAH8OgA4AAAAAAAAAAAAAiw4AAIwOjQ4AAAAAjg4AAAAAAAAAAAAAAACQDpEOAACWDpcOmQ4AAAAAAACfDgAAoQ4AAAAAog4AAAAAow6kDgAArQ4AAK8Otg63DgAAuA4AAAAAAAAAALkOAAAAALsOAAC+DgAAAAAAAAAAAAAAAL8OAAAAAAAAAAAAAAAAwA4AAMEOyg4AAMwOzQ4AAAAAAAAAAAAAAAAAAAAAAADPDgAA4w4AAAAAAAAAAAAA5g7nDugO7A4AAAAAAAAAAAAAAAAAAO0OAAAAAPEOAAAAAAAAAAD7DgAAAAAIDwkPAAAAAAAAAAAKDwsPDQ8AAAAAAAAAABMPAAAUDxYPAAAAAAAAAAAAABcPAAAAAAAAAAAAAAAAAAAAACEPAAAiDwAAIw8uDwAALw8AAAAAAAAAADQPSQ8AAEoPAAAAAAAAVQ9bDwAAAAAAAAAAXg9lD2YPAAAAAAAAAABnDwAAAAAAAGgPAAAAAAAAAAAAAGkPAABrDwAAAAAAAHQPdQ8AAAAAAAAAAAAAAAAAAAAAAAB2DwAAdw99DwAAAAAAAAAAfg8AAAAAAAB/DwAAAAAAAIAPhg8AAAAAAAAAAAAAhw+JD4oPAAAAAAAAAACMDwAAkQ8AAAAAAAAAAAAAAAAAAAAAkg+rDwAAAACxDwAAAAAAAAAAAAAAAAAAAAAAAAAAAACyDwAAAAAAAAAAsw8AALcPAAAAAAAAuw+8DwAAAAAAAAAAAAAAAAAAAAC/D8IPAAAAAMMPxQ/HD8gPAAAAAAAAAAAAANsPAADcD90PAADeD98P4g8AAAAA6A8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgPAAAAAAAAAAAAAPsPAAAAAAAAAAD+D/8PAAAAAAAQAAAAAAAAAAAAAAIQAxAAAAAAAAAFEAAACBAAAAAAAAAJEAwQAAAREAAAAAATEBQQAAAeEAAAAAAfEAAAAAAAAAAAAAAAAAAAIBAkECUQAAAmEAAAAAAAACkQAAAAAC0QAAAAAAAAAAAwEDIQMxAAAAAAAAAAADQQAAAAANcQAAAAAAAA2hDpEAAA6xDsEAAA7RAAAO4QAAAAAAAA7xAAAPAQAAAAAAAA8RAAAAAAAAD2EPkQ+hD+EAAA/xAAEQAAAhEDEQAAAAAMEQAAAAAAAAAAEREAAAAAAAAVEQAAFhEAAAAAAAAAABkRAAAAAAAAAAAaEQAAAAAAABwRAAAAAAAAHREeEQAAAAAAAAAAAAAAAAAAIBEAAAAAAAAAACERAAAAAAAAIhEAAAAAAAAnES4RAAAAAAAAAAA3ETkRAAAAAAAAAAA6EQAAAAA7EQAAPhE/EUIRAABLEUwRThEAAE8RAABgEQAAAAAAAAAAAABhEQAAAAAAAGMRZBEAAGURZhEAAGgRAAAAAAAAAAAAAAAAAABrEQAAbxEAAAAAAAAAAAAAchEAAHMRAAB1EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdhF3EQAAeREAAAAAexEAAAAAAAAAAH0RfhEAAAAAAAB/EYERAACCEQAAhBEAAAAAAAAAAAAAAAAAAIYRAAAAAIgRAAAAAJERAACcEQAAAACeEZ8RAACoEasRAACsEQAArREAAK8RAAAAALARAAAAAAAAAACyEQAAsxEAAAAAtBEAAAAAAAC1EQAAAAAAAAAAAAC3EQAAAAAAALgRAAAAAAAAAAAAAL0RvxHAEcERwxEAAMQRAAAAAAAAAADGEccRAADJEQAAAAAAAAAA0hEAAAAA2xEAAAAAAADeEQAAAAAAAN8RAADgEQAA4REAAAAAAADlEQAAAAAAAAAAAADmEQAAAADqEQAAAAAAAOwRAAAAAPURAAD2EQAAAAAAAAAACBIJEgAAChIAAAAAAAAAAAsSAAAMEgAAAAANEgAAEBIAAAAAAAAAAAAAERIAAAAAAAAAADESAAAzEgAAOxIAAAAAAAA8Ej4SAABAEgAAAAAAAAAAAABBEkQSAAAAAAAAAABPEgAAAAAAAAAAWRIAAAAAAAAAAFsSAABdEgAAAAAAAAAAXhIAAAAAYhIAAAAAaRIAAAAAAABqEmsSbBIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtEgAAAABwEgAAcRJ5En8SAAAAAAAAgRIAAAAAAACDEgAAAAAAAIQSAAAAAAAAhRIAAAAAAAAAAAAAhhIAAIkSihKLEgAAAAAAAAAAAAAAAAAAAACMEgAAAAAAAI0SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjxKyEgAAsxIAALQSvBIAAAAAvRK+EgAAvxLGEscSAAAAAAAAAADJEsoSAAAAAAAAAAAAAAAAyxIAAAAAAAAAAAAAzBIAAM0SAAAAAM8SAADVEtYSAAAAAAAAAADXEgAAAAAAAAAAAAAAAAAAAAAAAAAA2BIAAAAAAAAAANoSAAAAAAAA3BIAAN0SAAAAAAAA6xIAAAAA7xIAAPUS9xL6EgAAAAAAAAAAAAD7EgAAABMAAAAADxMAAAAAAAAAABATAAAAAAAAAAAREwAAEhMAAAAAAAAAAAAAAAAAAAAAAAATEwAAAAAAAAAAFBMAAAAAAAAAAAAAFhMXExgTHhMgEwAAJhMAAAAAKRMAAAAAMxMAAAAAAAAAAAAAAAAAADQTNRM3EzkTAAAAAAAAAAAAAD4TAAAAAAAAAAA/EwAAAAAAAAAAAAAAAAAAAABBEwAAQhNDEwAAShMAAFgTAABZE10TYBNkEwAAAAAAAAAAAAAAAAAAmxOcE54TAAAAAAAAAAAAAJ8TAAAAAAAAoBMAAAAAAAChEwAAAAAAAAAApBMAAAAAAAAAAKUTphOnEwAAqRMAAAAAAAAAAAAAAAAAAAAAAACqE6sTAACsEwAAAACtEwAAAAAAAAAArhMAAAAArxMAAAAAAACxE7ITAAAAAAAAAAC0E7kTvhMAAL8TAADBEwAAAAAAAMQTAAAAAAAAAAAAAMcTAADIE8kTAADLEwAAAAAAAMwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANQTAAAAAAAAAAAAAAAAAADVEwAAAADWE9gTAAAAANsTAAAAAAAAAAAAAAAAAAAAAN0TAAAAAAAAAAAAAAAA6hPrE+0T8RPzEwAA9BMAAPUTAAAAAAAAAAAAAAAAAAD2EwAAAAAAAAAAAAD9E/4TAAABFAAAAhQAAAAAChQAAAAAAAARFAAAAAAAABwUAAAAAAAAAAAAAAAAAAAfFCIUAAAAAAAAIxQAAAAAJBQnFCkUAAAAAAAAAAAqFAAAAAAAAAAAKxQsFAAALhQAAAAAAAAAAAAAAAAAAAAAAAAAAC8UAAAAAAAANBQAAAAAAAAAAAAAAAA6FDsUAAAAAEYUAAAAAEcUSBRKFAAAAABOFFEUAAAAAAAAAAAAAFMUAABWFFkUAAAAAAAAAAAAAAAAXRQAAF4UYBQAAAAAAAAAAAAAYRQAAAAAAAAAAAAAAAAAAAAAYhRjFAAAbxQAAAAAfBSBFAAAhhQAAIcUAAAAAIkUAAAAAAAAAAAAAIoUAACMFJYUAACdFAAAAAAAAAAAAAAAAKAUoRSiFKMUAAAAAAAAAAAAAKQUAAClFAAAAAAAAAAAAACnFKgUAAAAAAAAAAAAAAAAAAAAAAAAAACpFKsUAAAAAK4UAAAAAK8UAAAAAAAAAAAAAAAAAAC4FAAAAAC6FLsUvBQAAL0UAAAAAL4UAAAAAAAAAAC/FMAUAADBFAAAAAAAAAAAAADEFAAAAAAAAMUUAAAAAAAAAAAAAAAAAAAAAAAAzRQAAAAAAAAAAAAAAADOFAAAzxTRFAAA1BQAAAAAAAAAANoUAAAAAAAAAAAAAAAAAAAAANwUAAAAAN0UAAAAAAAA3hQAAN8U4BQAAAAA4RQAAAAAAAAAAAAAAADjFOQUAAAAAAAAAAAAAAAAAAAAAAAA5RQAAOYUAADqFAAAAAAAAAAA7hQAAAAA7xQAAAAA8RQAAAAA9RQAAPcUAAD9FAAAAAAAAAMVAAAAAAAABBUAAAAAAAAGFQAACBUAAAAAAAAAAAAAAAAJFQAAAAAAAAAACxUAAAAAAAAAAAAAAAAMFQ4VERUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBUAAAAAAAAAABUVGhUAAAAAAAAAAAAAGxUAAAAAAAAcFR0VAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHhUAAAAAAAAAACIVAAAAACMVAAAnFQAAAAAAAAAAKBU6FQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+FQAAQBUAAAAAAAAAAAAAAABBFUIVAAAAAAAAQxVEFUcVAAAAAEgVSRVLFQAAAAAAAFAVURUAAAAAAABTFQAAAAAAAFUVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgVAABaFQAAAABbFQAAXhUAAAAAYRUAAAAAYhUAAAAAZBUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZRUAAAAAAAAAAAAAAAAAAGwVAAAAAG0VbhUAAAAAAAAAAAAAcBUAAAAAAAAAAAAAAAAAAHEVAAAAAAAAAAAAAIMVAAAAAAAAhhUAAIcVAAAAAIgVAAAAAAAAiRUAAIsVAAAAAIwVjRUAAI4VAAAAAJIVAAAAAAAAAAAAAJ4VnxUAAAAAoBUAAKIVAAAAAKcVAACoFQAAAACpFQAAqxUAALUVAAAAALYVAAC4Fb8VAAAAAAAAAADAFQAAAAAAAMMVxRUAAMYVAADHFQAAAAAAAAAAyRUAAAAA3hUAAAAAAAAAAAAAAAAAAAAAAADgFekVAAAAAAAAAADqFQAAAADsFQAA+BUAAPkVAAAAAAAA/RUAAAkWAAAKFgsWAAAAAAAAAAAAAAAAExYAAAAAAAAUFhUWAAAdFh4WLhYAAC8WAAAAAAAAAAA1FjYWAAAAAAAAAAAAADoWPBYAAEcWAAAAAAAAAAAAAEoWAAAAAAAAAABLFgAAAAAAAAAAAAAAAEwWAAAAAE0WAABOFgAAAAAAAFAWAABlFgAAZhZnFgAAAABwFncWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeBYAAHoWAAAAAAAAAAAAAAAAfRZ+FgAAgBaBFgAAAAAAAAAAgxaEFoUWAACGFgAAhxaIFgAAihYAAAAAAAAAAJAWlBYAAAAAAAAAAJYWAAAAAAAAAACYFgAAAACcFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAClFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKcWAAAAAKkWAAAAAAAAsxYAAAAAAAAAAAAAAAC4FgAAAADDFgAAAAAAAAAAAAAAAAAAAADGFscWAAAAAMgWAAAAAMkWAADLFtQW1RYAANYWAAAAAAAAAAAAANoWAAAAAAAAAAAAANwWAADfFuEWAAAAAOMWAADlFgAAAADnFgAA6RYAAAAAAADxFvMWAAAAAAAA9RYAAPcWAAAAAAAAABcAAAAAARcDFwAABhcAAAAAAAAAAAAAAAAHFwAACRcAAAAAAAAAAAAAAAATFwAAFxcAAAAAGBcAABkXIhckFwAAJxcoFwAAAAAAAAAAKRcqFwAALRcAAAAAAAAAAD0XAAAAAD8XAAAAAAAAAAAAAAAAAAAAAEEXAAAAAEIXAABHF0gXSRcAAEwXAAAAAAAAWBdaF2MXZhcAAAAAAAAAAAAAZxcAAGgXAAAAAAAAahdrFwAAAABsFwAAAABxF3MXAAAAAAAAAAB3FwAAAAAAAAAAAAB4FwAAAAB5FwAAehcAAAAAAAB7F38XAACBFwAAgxcAAIcXAAAAAAAAAAAAAAAAAACJFwAAAAAAAAAAAAAAAAAAAAAAAAAAihcAAI4XAAAAAJAXAAAAAAAAkReWF5gXAAAAAAAAmRedFwAAAACeFwAAAAClFwAAAACmFwAApxcAAAAAAAAAAAAAAACpFwAArxcAAAAAAACwFwAAshe3F7gXAAAAAAAAAAAAAAAAuxe8FwAAAAC9FwAAAAAAAAAAAAAAAAAAAAAAAL4XvxcAAAAAAAAAAAAAAAAAAAAAwBcAAMMXAAAAAAAAAAAAAMQXAAAAAMgXAADJFwAAAADNF9kXAAAAANsXAADeFwAAAAAAAN8X7RfuFwAAAAAAAPEXAAAAAAAAAADyFwAAAAAAAPMX9hcAAAAAAAAAAAAAAAD+FwAAAAAAAAAAAAAAGAAAAAACGAcYCRgAAAwYAAATGAAAJBglGAAAAAAAAAAAAAAmGAAAAAAAAAAAKBgzGAAAAAA+GAAAQBgAAAAARBhFGEYYAABHGAAAAAAAAFQYAAAAAAAAWhgAAAAAAAAAAAAAAABbGGAYAABiGGMYZBgAAGoYbxgAAAAAAAAAAAAAcRgAAAAAAAByGIYYAACMGAAAAAAAAI0YAAAAAAAAAAAAAAAAAAAAAI4YAAAAAAAAsBgAAAAAshi8GAAAAAAAAAAAAAAAAAAAAAC+GAAAAAAAAAAAAAAAAAAAvxgAAAAAwRgAAMIYAADDGMQYAAAAANQY1RjhGAAAAAAAAOIY4xjkGAAA5RgAAAAAAAAAAAAA6BgAAAAAAAAAAAAA7hjvGPAYAAAAAAAAAADyGAAA9Rj9GAAZCxkAAA4ZAAAAAAAAAAAAAAAAAAAPGRAZAAAAAAAAAAAAAAAAERkAAAAAAAAAABIZAAAAAAAAAAAAAAAAAAAUGQAAFRkXGRkZAAAdGR4ZAAAhGSYZAAAAAAAAAAAAAAAAAAAAAAAAAAAnGSgZAAAAACkZAAAAACwZAAAAAAAAAAAuGQAAAAAAAAAALxkwGQAAAAAyGQAAAAAAADYZAAAAADcZAAA9GQAAAAAAAAAAAAAAAD4ZAAAAAD8ZAABAGQAAQRlDGQAAAAAAAEQZAABPGVAZAAAAAAAAAAAAAAAAAABRGQAAAABVGVcZAAAAAAAAAAAAAAAAXRkAAAAAAAAAAAAAAAAAAAAAXhlfGWAZAAAAAAAAAAAAAGIZAAAAAAAAaxlsGQAAAAAAAAAAAAAAAAAAAAAAAAAAbxlwGQAAAAAAAAAAcRkAAAAAAAByGQAAAAAAAAAAAAB0GQAAAAB1GXYZAAAAAAAAdxl4GXkZAAB7GQAAAAAAAAAAfBmAGQAAghkAAAAAhBkAALIZAAAAAAAAtxkAALgZAAAAAAAAuxkAAAAAAAC+GQAAvxkAAAAAAAAAAAAAwBkAAAAAAAAAAMEZwhkAAAAAAAAAAAAAxxnIGQAAAADJGcoZzBkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0BkAAAAAAAAAAAAAAAAAAAAA0hnTGQAA1xkAANgZ2hncGQAA7RkAAAAAAAAAAO8ZAAAAAAAAAADxGQAA8hkAAAAAAAD3GQAABBoHGgAACBoAAAoaDRoAABMaFBoVGgAAAAAAAAAAAAAAAAAAAAAAABYaAAAAAAAAFxoAABgaAAAAAAAAAAAAAAAAAAAlGgAAAAAAAAAAAAAAAAAAAAAAADAaMRoyGgAAAAA3GjkaAAAAAAAAAAAAADwaAAAAAAAAPRoAAD8aRBoAAAAAAAAAAAAAAAAAAAAARRpGGgAAAAAAAAAAAABIGkkaTxoAAFEaVhoAAAAAVxpeGgAAXxoAAAAAYBphGgAAAAAAAAAAAAAAAGIaAAAAAAAAAAAAAGQaAAAAAAAAAAAAAAAAaxoAAAAAbBptGgAAAAAAAHIaAAAAAAAAeBp8GgAAfRoAAAAAAAB/GgAAgBoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEaAAAAAAAAiBoAAAAAAACJGgAAAACSGgAAAAAAAAAAAACTGgAAAAAAAJQaAAAAAAAAnBoAAAAApxoAAKgatxoAAAAAAAAAAMQaAAAAAMYaAADIGskaAAAAAAAAAAAAAAAAAAAAAAAA0xoAANQa1hrYGgAAAAAAANka2hoAAAAAAAAAAAAA2xoAAAAA3RoAAAAAAAAAAAAAAAAAAN4aAAAAAAAA3xoAAOAaAAAAAAAAAAAAAAAAAAAAAAAAAADnGgAA6BrrGu0aAADvGgAAAAAAAAAAAAAAAAAAAADzGgAAAAAAAAAA9RoAAAAAAAAAAP4aAAD/GgAAAAAAGwAAAAABGwIbAAAAAAAAAxsAAAAAAAAEGwcbAAAAAAAAAAAAAAAADBsAAA0bAAAAAAAADhsPGxAbAAARGwAAEhsAAAAAExsXGwAAGBsAAAAAAAAAABsbHBsdGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4bJBslGwAAAAAAAAAAAAAAAAAAKBsqGzMbNRs2GwAAAAA3GzgbAAAAAAAAAAAAAAAAAAAAAAAAORsAAAAAOhtDGwAAAABEGwAAAABHGwAAAAAAAAAAAABIGwAAAAAAAAAAAAAAAAAATBtOG1AbAAAAAAAAAAAAAAAAAABTGwAAAAAAAGQbAAAAAAAAAAAAAAAAAAAAAAAAaxsAAAAAAAAAAAAAAAAAAAAAbRsAAAAAbhtvG3QbAAB2G3kbAAAAAAAAAAAAAAAAfhsAAAAAAAAAAAAAAAAAAAAAAAAAAH8bAAAAAAAAAAAAAIYbAACHGwAAAAAAAAAAAAAAAAAAAAAAAAAAAACIG4wbAAAAAAAAAAAAAI4bAACUGwAAAAAAAAAAlRsAAJkbAAAAAAAAAACbG50bAACeG58boBsAAAAAphsAAKgbqRsAAKsbAAAAAAAArBuvG7AbAAAAALIbAAC1GwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMMbAAAAAMQbAAAAAAAAAAAAAAAAAAAAAMYbAADKGwAAAAAAAAAAAAAAAAAAyxsAAMwbAAAAAAAAAAAAAM0bAAAAAM4bAAAAANQbAADVGwAAAADWGwAAAAAAAAAA2BsAAAAAAAAAAAAA2RsAANobAADcG90bAAAAAN4bAAAAAOMbAADsG+4bAAAAAAAAAADwGwAAAAAAAPEb9Bv1GwAAAAAAAAAAAAD2GwAAAAAAAAAAAAAAAAAAAAAAAAAA+xv9GwEcAAADHAAAAAAAAAAAAAAAAAAAAAAAAAQcAAAFHA0cAAAAAAAAAAAAAA4cERwAAAAAAAAAABMcAAAhHCQcAAAAAAAAAAAAACYcJxwAAAAAAAAAACscMBwAADIcAAAAAAAAAAA6HDwcPhxAHEEcQxxFHAAAAAAAAAAARhxJHAAAShwAAAAATxwAAAAAAABiHAAAAAAAAAAAAAAAAAAAeRwAAAAAehx7HAAAAAB8HAAAgRwAAAAAAAAAAAAAAAAAAAAAAAAAAIQcAACFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIYcAAAAAAAAAACJHAAAAAAAAAAAixwAAIwcAACOHAAApxwAAAAAAAAAAAAAAAAAAKkcAACvHLMcAAAAAAAAAAAAALQcAAC1HLYcuBy6HAAAAAAAAAAAvRwAAL4cxhwAAMccyBwAAAAAzRwAAAAAAADOHAAAAAAAAAAAAAAAAAAA0BwAAAAAAADRHAAAAAAAAAAAAADSHAAA0xzUHAAAAAAAAAAAAADXHAAAAADaHAAAAAAAAAAA5hwAAAAAAADnHOgcAADpHAAAAAAAAAAAAAAAAAAA6hwAAAAAAAAAAAAA7RwAAAAAAAAAAAAA7hwAAAAAAAAAAAAAAAAAAAAA/RwDHQUdAAAAAAAACx0AAAAADB0AAAAAAAANHQAAAAAAAAAAAAAAAA4dEx0AABYdAAAYHQAAAAAAAAAAAAAAAAAAAAAAAAAAIB0AAAAAAAAAAAAAIR0AAAAAJR0AAAAAAAAAAAAAJh0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJx0qHTAdAAA0HQAAAABCHQAAQx0AAAAARR0AAAAAAABKHUsdAAAAAFQdAAAAAAAAAAAAAFgdAAAAAAAAWR1aHVwdAAAAAAAAAABeHQAAAABfHWEdYh0AAAAAAABmHQAAAABpHQAAAABrHQAAcB0AAHIdAABzHQAAAAB1HXYdeh0AAAAAAAAAAAAAex0AAHwdAAAAAAAAAAAAAH4dAAAAAIAdgR0AAAAAAAAAAAAAAAAAAAAAAAAAAIIdix0AAJUdAAAAAAAAAAAAAAAAlh2YHQAAmh2dHZ8dAAAAAAAAoB0AAKMdAAAAAAAAAAAAAKUdAAAAAAAAqh0AAAAAqx0AAAAAsB2yHbodAAAAAAAAAAAAALwdAAC9Hb4dAAAAAL8dAAAAAMAdAADEHQAAxR3GHQAAxx0AAAAAAAAAAModAAAAAAAAAADLHc0dzx0AAAAA0R0AAAAAAAAAAAAA1x0AANgd2h0AAAAA2x0AAAAAAAAAANwdAAAAAAAAAAAAAAAAAADdHQAAAAAAAAAAAADtHe4d7x3xHQAA8h0AAPMdAAAEHggeCh4AAAseAAAAAAAAAAAAAAAADB4AAAAAFB4AABseAAAcHgAAHR4AACkeAAAAAAAAKh4AACweAAAAAAAAAAAAAAAAMR4zHgAANB4AADUeNx4AAAAAAAAAAAAAAAAAADseAAAAAD0eQR4AAEQeAAAAAAAARx4AAAAAAABIHgAAAAAAAAAAAAAAAAAASR4AAAAATB4AAE0eAABPHgAAUB4AAAAAAAAAAFEeWB4AAAAAWR4AAAAAWh4AAAAAWx4AAAAAXB4AAAAAXR4AAAAAAAAAAAAAYh5nHgAAAAAAAAAAAABoHmkeAABuHgAAAAAAAAAAcB4AAHYeAAAAAAAAAAAAAHceAACCHgAAAACFHgAAhh4AAIgeAACKHpAekR6SHgAAlB6WHgAAAAAAAKAeAACiHgAAox4AAAAAAAAAAKQeAAAAAAAAAAAAAAAAAACmHgAAAAAAAAAAAACwHrEesh62HgAAuR4AAAAAuh4AAAAA6R4AAAAAAAAAAOoeAAAAAOse7R7uHu8eAADwHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEe8h4AAPQeAAAAAPUeAAAAAPceAAD6Hv8eAAAAAAEfAAAAAAAAAAAAAAAAAx8AAAQfAAAAAAAAAAAAAAUfAAAAAAAAAAAJHwAAAAAAAAAADR8AAAAAAAAAAAAAAAAAAAAADh8AABEfAAAAAAAAAAAAAAAAAAAgHwAAAAAAAAAAIR8kHzgfAAA5HwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6HwAAAAAAAAAARx9IHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEofAAAAAAAATB8AAAAAAAAAAAAAAAAAAAAAUh8AAFwfXR8AAAAAXh8AAAAAYB9hHwAAAABiH2QfAAAAAAAAAAAAAAAAAAAAAAAAAABlHwAAAAAAAGsfdB97H3wfAAAAAH0fAAAAAAAAfh8AAH8fAACAHwAAgh+EHwAAAAAAAJAfkR8AAJkfAAAAAAAAAAAAAJwfAAAAAAAAAAAAAAAAnR+uHwAAAAAAAAAAAAAAAAAArx8AAAAAAAAAAAAAsB+zHwAAtR8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALgfuR+6H8AfwR/CH8MfAAAAAMsfAAAAANAfAAAAAAAAAADRH9If2R8AAAAAAAAAAAAAAAAAAAAA2h8AAN0f4B/iHwAA5B/lHwAAAAAAAAAA5h/nHwAAAADzHwAAAAAAAPkfAAAAAAAA+h8AAAAA+x8AAAAAAAD8HwAAAAAAAAAAAAAMIAAAAAAAAAAAEiAAAAAAAAAAAAAAFSAAABYgAAAAABcgAAAAAAAAAAAAAAAAGiAAAAAAAAAAAAAAAAAAAAAAAAAbIAAAHSAAAAAAHiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEgAAAAAAAAKSAAAAAAMiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANyAAADggPCAAAEAgQSAAAAAARSAAAEggSSAAAAAAAAAAAEsgAAAAAAAATSAAAAAAAAAAAAAAAAAAAAAAAABOIAAAAAAAAFYgAABXIFsgAAAAAF0gXiBhIGQgAAAAAAAAAABlIGcgayBsIG0gAAAAAAAAAAAAAAAAcCBzIAAAAAAAAAAAAAAAAAAAgSAAAAAAAACCIIMghSCGIIcgAAAAAIwgkiAAAAAAlCAAAAAAAAAAAAAAniAAAAAAnyAAAKIgoyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqCC0IAAAAAAAAAAAAAAAAAAAAAC5IAAAAAAAAAAAvCAAAAAAAAC/IAAAwCAAAAAAAAAAAMIgyCAAAAAAyiAAAAAAAAAAAAAAAAAAAMwgzSAAAM4gAADPIAAAAAAAAAAAAADQIAAA0SDaINsgAADcIN0g5iAAAAAAAAAAAOcgAAAAAAAAAADoIAAAAADpIAAAAAAAAAAAAAAAAAAA+SD6IAAAAAAAAAAAAAAAAPsgAAAAAPwgAAD/IAAAAAAAAAAAAyEAAAohAAAOIQAAAAAUIQAAFSEAAAAAAAAWIQAAGSEfISAhAAAAAAAAAAAhISMhAAAAAAAAAAAAAAAAAAAAAAAAJCEAAAAAKiEAAAAAAAAAAAAAAAArIS0hLiEAAFAhAAAAAAAAAAAAAAAAAABSIQAAAAAAAAAAAAAAAAAAAABWIVohXCEAAAAAXSEAAAAAYSEAAG0hAAAAAHkheiEAAAAAeyF+IX8hgyEAAIchAAAAAAAAAACPIQAAAAAAAAAAAAAAAAAAAACeIQAAnyEAAAAAAAAAAAAAAAAAAAAAAACgIQAAAAChIQAAAAAAAKIhAAAAAAAAoyEAAAAApSGpIa0hAAAAAK4hAACvIQAAsCGxIQAAAAAAAAAAAAAAAAAAAAAAAL0hviG/IcohAAAAAAAAAADMIc4hzyEAAAAAAAAAAAAAAAAAAAAAAAAAANAhAAAAAAAAAAAAANEhAAAAAAAAAAAAAAAAAAAAAAAA0iEAAAAA0yEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1CEAAAAAAAAAAAAAAADVIdch2CEAAAAAAAAAANkhAADdIQAAAAAAAAAAAAAAAAAA3yHiIQAA7CEAAO4hAAAAAAAA8SEAAAAAAADyIQAAAiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiIAAAciCSIKIhQiFyIYIh0iICIAACEiIyIAAAAAAAAAACYiJyIpIjIiAAAAAAAAAAA0IgAAAAAAAAAAAAAAADUiOCIAAAAAAAAAAAAAOiI7IjwiAAA+IkEiQiJFIgAARiIAAEsiAAAAAAAAAABMIgAAAABNIgAAAABPIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUCIAAAAAAAAAAAAAAAAAAAAAUSIAAAAAAAAAAFIiAAAAAAAAAABUIlYiAAAAAAAAYyIAAG0ibiIAAAAAAAAAAAAAbyJwIgAAAAAAAAAAciIAAAAAAAAAAHYifCJ9IgAAfyIAAAAAAAAAAIEiAAAAAAAAgiIAAAAAAACDIgAAhCIAAAAAAACFIgAAAAAAAAAAAAAAAIYihyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiCIAAAAAAACJIgAAiiIAAAAAAACOIgAAAAAAAAAAAAAAAAAAjyIAAJAiAAAAAKAiAAAAAKIiAAAAAKYiqCIAAAAAqSKqIgAAAAAAAAAAAAAAAKsiAACsIgAAAAAAAAAAwCLEIgAAAAAAAAAAxSIAAAAAAAAAAAAAyCIAAMsiAAAAAAAAAADPItAi0SIAAAAAAADSIgAA0yIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADUIgAAAAAAAOEiAAAAAAAAAAAAAAAAAAAAAAAAAADiIgAA5CIAAO8iAAAAAAAA8SLzIgAAAAAAAAAA9SIAAPYiAAD6Iv0iAAAAAAojAAAAAAAAAAALIwAAJCMAAAAAAAAAACUjKCMAAAAAAAAAACkjKiMAACwjMSNAIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEMjeiMAAAAAeyOBIwAAAAAAAAAAAAAAAIIjAAAAAAAAhCMAAAAAhSMAAIcjAAAAAIgjiSONI44jAAAAAAAAAAAAAAAAAAAAAJgjAAAAAAAAAAAAAAAAmiMAAAAAoCMAAKEjoiMAAAAAAACjI6QjAAAAAKUjAAAAAKYjAACnIwAAAACpI6sjAAAAAAAArCMAAAAAsCMAALgjAAAAALwjAAAAAAAAAAAAAAAAvSMAAMAjyyMAAAAAzSMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM4jAADRIwAAAAAAAAAAAAAAAAAA0iMAAAAAAAAAANQjAADWI9cj2CMAANkjAAAAAAAAAAAAAAAAAAAAAOIjAADjIwAAAAAAAOQj5SMAAAAA5iMAAAAAAAAAAOcjAAAAAAAA6SMAAAAAAAAAAO0j7iMAAAAAAAD4I/sjAAAAAAAAAAAAJAEkAAAEJAAAAAAAAAAABSQGJAckAAAIJAkkAAAAAAskAAAMJA0kAAAAAA4kAAAQJAAAESQAAAAAAAAAAAAAEiQTJAAAAAAVJAAAAAAAAAAAAAAAAAAAAAAWJBgkAAAAABkkAAAAAAAAAAAcJAAAAAAAAAAAHyQAAAAAAAAAAAAAAAAAAAAAAAAAACAkAAAAAAAAISQAAAAAAAAAAAAAIiQAAAAAAAAAACMkAAAAACQkJyQAAAAAAAAoJAAAAAAAAAAAAAAAAAAAKSQAAAAAKiQAAAAAAAAAAAAAAAArJAAAAAAAAAAAAAAuJC8kAAAAADEkMiQAAAAAAAAAAAAAAAAAAAAANCQ3JAAAAAAAAAAAAAAAAAAAAAAAADkkAAAAAAAAPCQ9JD8kAAAAAAAAAAAAAAAAAABAJAAAAABNJAAAAAAAAAAAAABRJFUkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFwkXSRhJGkkaiQAAG4kbyQAAAAABSUAAAclAAAAAAAAAAAKJQAAAAAAAAslAAAMJQAAAAAAAAAAAAAAAAAAAAAAAA0lAAAAAA4lAAAAAAAAESUAAAAAAAAAABIlEyUAAAAAAAAAABUlAAAXJRglAAAAAAAAAAAAAAAAAAAAABwlAAAeJQAAAAAAAAAAAAAgJSMlAAAlJQAAJyUAAAAAKSUAAAAAAAAAAAAAAAAAAAAAKyUAAAAAAAAAAAAAAAAsJS0lAAAAAAAAAAA8JQAAAAA9JQAAAABCJQAAQyVEJQAAAAAAAAAARSUAAAAAAABGJQAAAAAAAAAAAAAAAAAAAABIJUklAABKJQAAAAAAAAAAAAAAAEslTCUAAAAAAABOJQAAVSUAAFYlAABZJQAAWyViJQAAZCVmJWclAAAAAAAAaSV4JQAAAAB8JQAAAAAAAH4lAACAJQAAgSUAAAAAAAAAAAAAAACIJQAApiWnJQAAAAAAAAAAAAAAAAAAqSUAAAAAqyWsJa0lriUAAAAAAACwJQAAAAAAAAAAAAAAAAAAsiW2JQAAAAAAAAAAAAAAAAAAAAC3JQAAAAAAAAAAAAC4JQAAuSUAAAAAAAAAALolAAAAALslAAAAAMAlAAAAAMElAADDJcUlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxyUAAMkl0SUAAAAAAAAAANIl0yXUJQAAAAAAAAAA1iXiJQAAAADkJeUl5iUAAOcl9SUAAAAAAAAAAPYlAAD+JQAAAAAAAAAA/yUAAAAAAAAAJgAADiYAABAmAAAAAAAAFiYAABomGyYAAAAAAAAAAAAAHCYAAB0mKCYAACkmAAAAAAAAKiYrJgAALSYAAC4mAAAvJgAAAAAAADAmMSY4JgAAAAAAADomAAA9JgAAAAAAAAAAQSZCJgAAAAAAAFAmAAAAAAAAAAAAAFMmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVCYAAFwmAABfJgAAZCYAAAAAAAAAAGYmAAAAAGkmbCYAAAAAAABwJgAAAAAAAHEmAAAAAHImAAB1JgAAAAAAAHcmeCYAAAAAfyYAAAAAAAAAAAAAAACAJocmiSYAAAAAAAAAAAAAAAAAAAAAiiaLJowmkSaTJgAAAAAAAAAAAAAAAJgmAACeJgAAAAAAAJ8mAAAAAKMmAAAAAAAAAAAAAAAAAACyJrMmtCYAAAAAAAC1JgAAAAAAAAAAAAAAALYmAAAAAAAAAAC5JgAAAAAAAAAAuiYAAAAAAAAAAAAAwiYAAAAAAAAAAMMmxSYAAAAAAAAAAAAAAADKJgAAAAAAAMsmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzCYAANMmAAAAANQm6ibuJgAA8SbyJgAAAAD2JgAA+yb9Jv4mAAAAAAAAAScAAAAAAAAAAAAAAAADJwAAAAAAAAAAAAAAAAAABCcJJwAAAAAKJwAAAAAAAA0nAAAUJwAAAAAAAAAAAAAXJyMnJCcmJwAAAAAAAC8nAAAAAAAAAAAAADAnAAAAADInAAA0JwAAAAAAAAAANicAADcnOCc5JzonAAAAAAAAAAAAADsnAAAAAAAAAAAAAD0nRicAAAAAAAAAAEcnAAAAAEknSicAAAAAAAAAAAAAAABLJwAAAAAAAAAAAAAAAAAATCcAAAAAAAAAAAAAAAAAAE8nAABSJwAAAAAAAFYnAABYJwAAAABcJ10nAAAAAGQnAABnJ2onaycAAAAAAABuJ3EnAAAAAAAAAAAAAAAAcicAAAAAAAAAAAAAAAB3JwAAeCcAAHwnAAAAAAAAAAAAAAAAAAAAAIgnAAAAAAAAiicAAAAAjScAAAAAAAAAAI8nkCcAAAAAlicAAJcnmCcAAJknAAAAAKMnAAClJ6YnAAAAAKwnAACuJ68nsCe4JwAAAAC7JwAAvScAAAAAAADAJwAAAAAAAAAAwScAAAAAAAAAAMInAAAAAAAAAADSJwAA2icAAAAA2yfcJwAA3SfeJwAA3ycAAAAAAAAAAOEnAAAAAAAAAAAAAAAAAADlJwAAAAAAAAAAAAAAAOknAAD1JwAA9if3JwAAAAD4JwAAAAD9J/4nBCgAAAAAAAAAAAAACigAAAwoAAAAAAAAAAAAAAAADygAAAAAESgAAAAAAAAAAAAAAAASKAAAEygAAAAAAAAAAAAAAAAAAAAAFCgAAAAAAAAAAAAAAAAAACwoMCgxKAAAAAAAADIoAAA4KAAAAAAAAAAAAAA5KAAAAAAAAAAAAAAAADooAAAAAAAAAAA7KD8oAAAAAAAAAAAAAEIoAAAAAAAAQygAAEQoAAAAAAAAAABHKAAAAAAAAAAAAAAAAAAASyhNKAAAAAAAAE4oTygAAFEoAABWKAAAWCgAAAAAAAAAAFkoAAAAAFsoAABcKAAAAAAAAAAAAAAAAF4oAAAAAF8oYigAAAAAAAAAAAAAYyhtKAAAAAAAAAAAAAAAAG8oAABxKAAAAAAAAAAAAAAAAHooAACAKAAAgSgAAAAAAACEKIUoAAAAAAAAAAAAAIYoAAAAAAAAhygAAIgoAAAAAJIolCiWKAAAAAAAAAAAAAAAAAAAlygAAAAAmCiaKAAAAACcKAAAnSgAAKMoAAAAAAAAAAAAAAAAAAAAAKQoAAClKKooAAAAAKsoAACsKAAAAAAAAAAAAAAAAAAAtSi2KLcoAAAAAAAAAAAAAAAAAAAAAAAAuSgAAAAAuygAAAAAvigAAAAAAAAAAAAAwCgAAMEowigAAAAAAAAAAMQoxSgAAMYoAADHKAAAzCjOKAAAAAAAAAAAAADQKAAAAAAAAAAAAADRKAAAAAAAAAAAAAAAAAAA0ygAANUoAAAAAAAA1ijZKAAAAADbKAAA5SgAAAAAAAAAAAAA6CjxKAAAAAAAAAAAAADyKPMoAAD8KAAAAAAAAAAAAAAAAAAAAAAAAAAAAykAAAAAAAAGKQAAAAAOKQAAGSkcKQAAAAAdKR4pICkAAAAAAAAAAAAAAAAAAAAAIikAAAAAAAAAACUpAAAmKQAAAAAAAAAAAAAAAAAAAAAAAAAAJykoKQAAAAAwKQAAOSk8KQAAPSk/KQAAAAAAAAAAAABCKUMpRCkAAEUpAAAAAAAARikAAEcpAAAAAAAAAABPKQAAAABQKQAAUikAAAAAAAAAAAAAAAAAAAAAAAAAAFkpWilbKV0pAABeKQAAAABiKQAAAAAAAAAAAABmKQAAAABpKQAAAAAAAGopAABrKQAAbCkAAG0pAAAAAG8pAACCKQAAgykAAAAAAAAAAAAAhSmGKYcpAAAAAAAAlikAAAAAAACXKQAAmikAAJspAAAAAAAAnCmdKZ8pAACiKQAAAACjKQAAqykAAAAAAAAAAK0pAAAAAAAAAAAAAAAAAAAAAAAArikAAAAAAACvKQAAAAAAAAAAsCmxKQAAsikAAAAAAAC0KQAAAAAAAAAAAAAAALYpAAC6KQAAAADEKQAAySkAAAAAAAAAAMopAAAAAAAAzCkAAAAAAAAAAAAAzykAANApAAAAAAAAAAAAAAAAAADRKQAA2yneKeApAAAAAOIpAAAAAAAAAAAAAAAAAAAAAOMpAAAAAAAAAADmKQAAAAAAAAAAAADnKeop9ykAAAAAAAAAAAAAAAD4KQAAAAD5KQAAAAAAAAAAAAAAAPwpAAAAAAAAAAD+KQAAAAAAKgEqAAAAAAAABCoAAAAAAAAAAAAAAAAGKgAAAAAAAAcqAAARKgAAAAAUKgAAAAAAAAAAAAAAABUqAAAAAAAAGSoAAAAAGyoAAAAAAAAAAAAAAAAAAAAAHCogKgAAAAAAACUqAAAAAAAAJyoAAAAAAAAAAAAAAAAAAAAAAAArKgAAAAAsKgAAOCoAADkqAAAAAAAAOioAAAAAAAA8KgAAAAA+KgAAAAAAAAAAAAAAAAAAAAAAAD8qAAAAAAAAAABAKkEqAAAAAAAAAABDKgAARCoAAAAAAAAAAEUqRipHKgAASiphKgAAAAAAAAAAYioAAAAAZCoAAGUqAAAAAGgqAAAAAGkqaiprKmwqAAAAAAAAAAAAAAAAbyoAAHIqcyp4KooqAAAAAIsqjCoAAAAAAAAAAAAAjSoAAAAAAACQKpMqAAAAAJQqlioAAAAAAAAAAAAAlyoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZKgAAmioAAAAAAAAAAJwqnyoAAKAqAAAAAKQqAAAAAAAAAAAAAKUqAACmKgAAAAAAAKsqAAAAAAAAAAAAAKwqAAAAALAqsSoAAAAAsioAAAAAAAC0KgAAAAAAAAAAuyoAAAAAwSoAAAAAAADDKgAAAADEKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM4qAADQKtIqAAAAANQqAAAAAAAA1ioAAAAAAAAAAAAAAAAAAAAAAAAAANcqAAAAAAAA2CoAAAAAAADdKgAAAAAAAAAAAADfKgAAAAAAAOAq4ioAAAAA5iroKusqAAAAAOwqAADtKgAAAADvKgAAAAAAAAAA8CoAAAAAAADxKgAA8yoAAAAAAAD0KvUqAAAAAAAA9ioAAPcqAAD5KgAAAAAAAAAAAAAAAAIrBCsAAAUrCCsJKwAAAAALKwwrDSsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOKwAAAAAPKxUrAAAAAAAAAAAXKwAAAAAAABorAAAAAAAAAAAvKwAAAAAAAAAAAAAwKzQrAAAAAAAAAAAAAAAANSsAAAAAOCs5KwAAOisAAD0rAABNKwAAAAAAAAAAAABOKwAAAAAAAFArAAAAAAAAVisAAAAAAABXK1grAAAAAAAAAAAAAAAAWStaKwAAAAAAAAAAAAAAAFsrAAAAAF4rZCsAAAAAAABlKwAAaitvKwAAeysAAAAAAACGKwAAAACHKwAAiisAAIsrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjCsAAI0rkCuRK5IrAACUKwAAlSsAAAAAAACWKwAAAACXK5grAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmysAAAAAnCueKwAAAAAAAKQrpisAAAAAAACoKwAAAAAAAAAAAACuK68rAAAAAAAAsCuzKwAAAAC0K7UrAAAAAAAAAAAAAAAAuisAAAAAAAAAAAAAAAAAAMArwisAAAAAAAAAAAAAAADDKwAAxCsAAAAAAAAAAAAAxSsAAAAAAADGKwAAxysAAAAAySsAAMsrAADOKwAAAADfKwAAAAAAAB0sHywAAAAAICwhLCYsAAAAAAAAKywAAAAAAAAAAC0sLiwAAC8sAAAAAAAAMSwAADIsAAAAAAAAAABGLAAASiwAAAAAAABLLAAAAAAAAAAAAABMLAAATSxOLAAAUCwAAFEsAAAAAAAAVCxVLAAAAABWLAAAAAAAAFssAAAAAAAAAAAAAAAAXCwAAF0saiwAAAAAaywAAG4scCwAAAAAAABxLAAAAAByLHcsAAB6LIcsAACILI4sAAAAAAAAkCwAAAAAkSyULAAAAAAAAAAAmSwAAAAAAACaLAAAnSwAAKIspSwAAAAAAAAAAAAApiwAAK0sAACuLAAAAAAAAAAAAACwLL0sAAAAAAAAAAAAAAAAviwAAAAAAAAAAL8sAAAAAMAsxCzFLMcsAADNLAAA0SwAAAAAAAAAANIsAAAAAAAA0ywAANQs1SzYLAAAAAAAAAAA2SwAAAAA3CwAAAAA3ywAAAAAAAAAAAAAAAAAAAAAAAAAAOksAAAAAO4sAAD1LAAAAAD2LPcs+SwAAAAAAAAAAAAAAAAAAAAAAAAAAPssAAAAAAAAAAD8LAAAAC0BLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJLQotCy0OLQAAAAAXLQAAAAAAAAAAAAAbLQAAHC0AAAAAAAAAAAAAIC0kLQAAJS0AAAAAJy0AACgtAAAAAAAAAAAAAAAAKS0AAAAAKy0sLQAALS0AAAAAAAAAAC8tAAAAAAAAMS0AADYtAAA3LQAAAAAAADktAAA6LQAAAAAAADwtPS0AAAAAAAA+LUAtAAAAAAAAAAAAAAAAAABDLQAARC1HLQAASy0AAAAAAAAAAAAAAAAAAAAATC0AAE0tAAAAAAAAAABOLVEtAAAAAAAAUi0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABTLVQtAABWLQAAAABYLQAAAAAAAAAAWi0AAAAAWy0AAAAAAAAAAF0tAABmLQAAAAAAAGctAAAAAAAAAABpLQAAAABqLWstbC1uLQAAAAAAAAAAAAAAAHctAAAAAH4tAACALYEtAACCLQAAAAAAAAAAAAAAAAAAAAAAAIMtAAAAAIQthS2ILQAAAACdLZ8tAAAAAAAAAACgLQAAAAChLQAApS0AAAAAAAAAAAAAAAAAAAAAqC0AAAAAAADELQAAxy0AAAAAAAAAAAAAyS0AAAAAzC3fLQAAAAAAAAAAAAAAAAAAAADhLeQt5i0AAAAAAAAAAAAA5y0AAAAAAADoLeotAADrLQAAAAAAAAAAAAAAAAAA7y0AAAAAAAAAAAAAAADwLQAAAAAAAPEtAAAAAAAAAAAAAAAA9i33LQAA/C39LQAA/i0AAAAA/y0AAAEuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACLgQuAAAAAAAAAAAAAAAAAAAHLgAACC4AAAAAAAAJLgAAAAAAAAouAAAAAAAAAAAMLgAAAAANLg8uEC4AAAAAAAAAABMuOi47LjwuAAAAAD0uAAAAAAAAPi4AAAAARi5LLgAATC4AAF0uAAAAAAAAXy4AAAAAAABgLmIuAAAAAAAAAAAAAAAAYy4AAGQuZS4AAAAAAAAAAAAAAAAAAAAAAAAAAGsuAAAAAAAAAAAAAAAAAABsLgAAbS4AAG4uAAAAAG8uAAB2LncueS6FLoYuAACILo4uAAAAAJAuAACSLpQuly6YLgAAAAAAAAAAmS4AAJ4uAAAAAAAAAAAAAKUupy6oLgAAqS4AAAAAAAAAAKwurS4AAAAAAAAAALEuAACyLgAAsy4AALQuAAAAAAAAAAAAALUuAAAAALcuAAAAAAAAAAAAAAAAAAAAALkuAAAAAAAAAAAAAMouAAAAAAAAyy7MLtIu0y4AANguAAAAAAAAAAAAANkuAAAAAAAA2i4AAN8u5C7lLuYuAAAAAAAAAAAAAOsuAAAAAOwu7i4AAAAA7y4AAAAA8y78LgAAAAD9LgAAAAAALwEvAAAAAAAAAAACLwAACS8LLwAAAAAMLwAAAAAAAAAAAAAAAAAADi8AAAAAAAAAAAAAAAAAABYvFy8AABgvAAAAAAAAHC8gLwAAAAAAAAAAAAAhLyMvJC8AAAAAAAAAAAAAAAAAAAAAKi8AAAAAAAArLywvAAAAAAAALy8AADEvNi83LwAAAAA4LwAAAAAAAAAAOS8AADwvAAAAAAAAAABBLwAAAAAAAAAAAAAAAAAAAABCLwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARi9HL0gvTy8AAAAAUi9ULwAAAAAAAFYvAAAAAAAAVy9YL2AvAAAAAAAAAABiLwAAAAAAAAAAAAAAAGMvAAAAAAAAZC9mLwAAAAAAAAAAaS8AAGsvAABtLwAAAABuLwAAAAAAAHAvAAAAAAAAAAAAAHEvAAB0LwAAeS8AAAAAAAAAAHoviy+NLwAAAAAAAI8vAAAAAAAAAACSLwAAAAAAAAAAAAAAAAAAly8AAAAAAAAAAAAAAAAAAAAAmC8AAAAAAACaLwAAAAAAAAAAAACbL5wvAAAAAJ0vAACkLwAApS8AAAAApi8AAKkvAAAAAAAAAACrLwAAsS8AAAAAAAAAALIvsy+0L7UvAAC5L7ovAAAAAAAAAAAAAAAAAAAAAAAAvi8AAAAAAAAAAAAAAAAAAL8vAAAAAMUvAAAAAAAAAADJLwAAAAAAAAAAyi8AAAAAzC/SLwAAAAAAANMvAAAAAAAA1C/dLwAA3i/gLwAA4S8AAAAA8y8AAAAAAAAAAAAA9S8AAAAAAAAAAAAA9i8AAAEwAAAAAAIwAAAEMAUwAAAAAAYwAAAHMAAAAAAIMAAACTAAAAowAAAAAAAAAAANMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFTAAADIwNDAAAAAAAAAAADUwAAAAAAAAAAAAAAAAAAAAADYwNzAAADgwAAAAAAAAAAAAAAAAAAAAAAAAOTAAAAAAAAAAAAAAAAAAAAAAOjAAAAAAAAAAADwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/MAAAQzBEMEUwAAAAAE8wUjBTMAAAAAAAAAAAAABUMFgwAAAAAAAAAAAAAAAAAAAAAFswAABeMAAAXzAAAAAAYDAAAAAAAAAAAGkwAAAAAGowAAAAAAAAAABuMHMwAAAAAHQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB6MAAAAAAAAHswAAAAAAAAfDAAAAAAAAAAAIQwAACFMAAAAAAAAAAAAACHMAAAiTCNMAAAAAAAAI8wkDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACSMAAAAAAAAAAAAACTMJQwAAAAAAAAAAAAAAAAAAAAAJUwAAAAAAAAAAAAAJYwAAAAAAAAAAAAAAAAAAAAAJ0wAAAAAAAAojCjMAAAAAAAAAAAAAAAAAAAAACkMLswAAAAAM0wzjAAAAAAAADPMAAAAAAAAAAA0DDWMN0wAAAAAAAAAADeMAAA4DDhMAAAAAAAAAAA4jAAAAAAAADjMAAA6DAAAAAAAADsMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7zAAAAAAAADwMAAAAAAAAPEwAAAAAAAAAAAAAPIwAAD3MAAAAAD4MAAA+jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8MAAABDEAAAAAAAAAAAAABjEAAAAAAAAHMQgxAAAAAAAACjEAAAAAAAAAAAAAAAAAAAAACzEAAAAAEjEAABUxAAAWMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkxAAAAAAAAGzEeMQAAAAAAAAAAAAAAAAAAITEAAAAAAAAAAAAAAAAAACIxIzE7MQAAQDEAAAAAQzEAAEQxAABHMQAAUTEAAAAAAAAAAFMxZjEAAGgxAAAAAHExAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH4xAAAAAH8xAACBMYUxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIcxAACJMQAAijGVMQAAljEAAJkxAACdMQAAAAAAAJ8xoDEAAAAAAAAAAKMxwTEAAAAAwzEAAAAAxDEAAAAAxjHHMQAAAAAAAAAAAAAAAAAAAAAAAMkxAADKMcsxAADMMQAAAADXMd8xAAAAAAAAAADlMQAA5jHqMQAAAAAAAAAAAAAAAAAA6zEAAAAAAAAAAAAA7DH5MQAAGDIAABkyAAAkMgAAAAAAAAAAJzIAACoyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKzItMgAALjIAAAAAAAAAAC8yAAAAADIyNDI1MgAAAAAAADYyAAAAAAAANzIAADgyAAA6MgAAAAA7MgAAPjIAAD8yAAAAAEIyAABFMkgySTIAAAAAAAAAAAAAAAAAAAAAAABLMgAATTIAAAAATjIAAAAAAAAAAAAAAAAAAAAAAABUMlUyWDIAAFkyAAAAAAAAAABdMgAAAAAAAF8yYDJiMgAAAAAAAAAAAAAAAAAAZjIAAG0ybjIAAH4yAACAMgAAAAAAAIEyAACCMgAAAAAAAAAAgzIAAIQyhTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIYyAACOMgAAAAAAAAAAkDIAAAAAAAAAAAAAAAAAAAAAkjIAAAAAlDIAAAAAlTIAAAAAAAAAAJYyAAAAAAAAAACXMgAAmDIAAJkyAAAAAAAAmjKeMp8yAAAAAAAAAAAAAKAypDIAAAAAAAAAAAAApjIAAAAAAAAAAAAAAAAAAAAAqjIAAKsyAAAAAAAAAAAAAAAArDIAAAAAtjIAAAAAAAC4MrkyAAC6MsQyxTLJMsoyAAAAAAAAAADMMgAAAADNMgAAAADPMtEyAADZMgAAAAAAANwyAADdMgAAAAAAAAAAAAAAAAAAAAAAAAAA3jIAAAAAAAAAAAAAAAAAAAAA4DLjMgAAAAAAAAAAAADkMgAAAADlMgAAAAAAAAAAAAAAAAAA6DIAAO0yAAAAAAAAAAAAAAAA8DIAAAAA8TIAAAAAAADzMvQy9jIAAAAAAAAAAPcyAAAAAAAAAAAAAAAAAAD5Mv4yAAAAMwAAAAAEMwUzAAAAAAAAAAAAAAszAAAAAAwzAAAPMwAAAAAAAAAAAAAVMxYzAAAAAAAAAAAAABczGDMZMwAAGjMAAAAAAAAdMwAAAAAAAAAAAAAAAAAAHjMAAB8zIDMAAAAAAAAAAAAAJjMAACszAAAsMwAAAAAAAC0zAABFM0YzSDNJMwAAAABKMwAASzMAAAAAAAAAAAAAAABOMwAAAAAAAAAAAAAAAAAAAAAAAAAAAABeMwAAcDMAAAAAAAAAAAAAAAAAAAAAAABxMwAAAAByMwAAAAAAAAAAdjMAAAAAAAB4MwAAAAAAAAAAAAB5MwAAejN/M4MzAAAAAAAAhTMAAAAAhjMAAAAAhzMAAAAAljMAAAAAAACXMwAAAAAAAAAAAAAAAAAAAAAAAAAAnDMAAAAAozOwMwAAAAAAALkzAADBM8UzAAAAAAAAAAAAAMczyzMAAMwzzTMAAM4zAADYMwAAAAAAAAAA3DMAAAAAAAAAAN0z8zMAAAAA9TP2MwAAAAD3MwAAAAD5MwAA/jMAAAAAAAD/MwAAAAAAAAAADTQAABA0AAAAAAAAETQAAAAAAAAAAAAAAAASNAAAAAATNAAAFzQAAAAAHjQAAAAAAAAAAAAAHzQAACo0AAAyNAAANjQ3NDk0AAAAADs0PDQAAD00PjQAAEA0AABENEU0SjQAAEs0TDQAAE00TzRTNAAAAAAAAAAAAABZNGE0AABiNAAAAAAAAAAAbDQAAAAAAAAAAAAAbjQAAAAAAAAAAG80AAAAAAAAAABxNAAAAAAAAAAAAABzNAAAAAAAAHQ0AAAAAHY0fjQAAH80AACFNAAAiDSJNAAAAAAAAAAAAAAAAIs0AACRNAAAAAAAAAAAkjSTNAAAlDQAAAAAAAAAAJg0mTSaNJ40AACfNKA0ojSjNAAApDQAAAAApjSnNAAAqTQAAAAAAAAAAK80AACyNAAAtTQAAAAAtjQAAAAAtzQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuDS5NAAAvDQAAAAAzDTSNAAAAADVNNg0AAAAAAAA2jTfNAAA4TTjNAAA5DQAAOc0AADoNAAAAAAAAAAAAAAAAOk0AAAAAAAAAAAAAAAA6zQAAAAAAADtNPM0AAAAAAAA9DT1NAAAAAAAAAAAAAAAAAAA9jQAAPs0AAAAAAAAAAD8NAAAAAAAAAAAAAAAAAAAAAD+NAAAAAAAAAAAAAAAAAE1AAAAAAM1AAAAAAAAAAAFNQAAAAAAAAAAAAAAAAo1AAAAAAAAAAAAAAAAAAAAAAAAAAANNQAAEjUAABs1AAAgNQAAAAAAAAAAAAAAAAAAAAAhNSM1AAAkNSU1JjUnNQAAAAAxNTI1AAAAAAAAAAAAAAAAAAA3NQAAOTU7NQAAAAAAAAAAAAAAAAAAAAA9NQAAAAAAAEI1AAAAAAAARjUAAAAAAAAAAAAAAAAAAAAAVjUAAAAAAAAAAAAAAAAAAAAAAAAAAFg1AABbNQAAAABcNQAAAABeNQAAAAAAAF81AABgNQAAAAAAAAAAAABkNQAAZTVnNQAAAABoNQAAAAAAAAAAAAAAAGs1dTUAAHY1AAAAAAAAdzUAAAAAAAB8NX41gTUAAAAAAACGNQAAAAAAAAAAAACJNQAAAAAAAAAAizUAAAAAAACSNQAAAAAAAAAAAAAAAAAAAAAAAJM1AACUNZU1AAAAAJc1nDWiNaM1AAAAAAAAAAAAAAAAAAAAAKQ1AAAAAAAAAAAAAAAAAACmNQAAqDUAAAAAqTWqNbM1AAC3NQAAAAC4NQAAAAAAALk1AAC9NQAAAADCNcM1AADENcU1AADGNQAAAADHNQAAAAAAAMg1AAAAAAAAAAAAAAAAAADJNQAAAADMNQAAzzUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQNdI12zUAAAAAAADlNQAA5jUAAOk1AADsNe41AAAAAAAAAAD4Nfk1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKNgAADDYAAAAADjYAAAAADzYAABA2AAAAAAAAAAASNgAAAAAAAAAAAAAAABM2AAAAAAAAAAAAAAAAAAAAAAAAFTYAAAAAAAAAAAAAIjYAAAAAJDYAAAAAJTYAAAAAJjYnNgAALDYAAC02LjYAAAAAAAAAAAAAAAAAAAAAAAAAADA2AAAAAAAAAAAxNjY2AAAAAAAAAAAAAAAAAAAAAAAAAAA+NgAAQDZBNkI2AAAAAEM2RjYAAEk2SzZMNlA2AAAAAFI2AAAAAAAAVTYAAAAAAABWNgAAAAAAAFc2AAAAAAAAAAAAAFg2XTYAAAAAAAAAAF42AABfNgAAAABgNgAAAAAAAGE2AAAAAGI2AAAAAAAAAAAAAAAAAABkNgAAZzYAAAAAAAAAAAAAbDYAAG02AABuNgAAAABvNgAAeDYAAAAAAACCNgAAAACDNgAAAAAAAAAAhDYAAIU2AACPNpE2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkjamNgAApzaqNgAAqzYAAAAAAAAAAKw2AAAAAK82AAAAAAAAwjYAAMM2AADFNgAAAAAAAAAAAAAAANk2AAAAAAAAAAAAAAAAAAAAANs2AAAAAAAAAADeNgAAAAAAAOA24TYAAAAAAAAAAAAAAAAAAAAAAAAAAOM2AAAAAOQ26DYAAO82AADwNvI2AAAAAPM2AAAAAAAAAAAAAAAAAAAAAAAA9DYAAAAAAAD4NgAA+jb7NgAA/Db/NgU3BjcHNw03AAAAAAAAAAAPNwAAAAAAAAAAAAAAABA3ETcAAAAAAAAAAAAAAAAAABI3AAAWNwAAAAAAAAAAAAAXNwAAAAAAABg3AAAAABk3AAAAAAAAGzccNwAAAAAdNwAAAAAAAAAAAAAAAAAAAAAlNwAAAAAAAAAAJjcAAAAAAAAAACc3AAAAACg3AAAAACk3AAAqNy83AAAwNzg3AAAAADo3AAA8NwAAAAAAAD03PjcAAAAAAAAAAEI3AAAAAEU3AABHNwAAAAAAAEg3AAAAAEk3AAAAAAAAAAAAAAAAAAAAAAAASjcAAEw3TTcAAAAATzcAAFE3AAAAAAAAAABSNwAAAAAAAAAAAAAAAFM3AAAAAF03AAAAAAAAAAAAAAAAXjcAAAAAYDcAAAAAYjcAAAAAYzdlNwAAAABmN2k3azcAAG43AAAAAHU3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdjcAAAAAAAAAAAAAAAB3N3g3AAAAAAAAfDcAAAAAgDcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlzcAAAAAAAAAAAAAAAAAAAAAAACaNwAAAACbNwAAAAAAAKA3oTcAAAAAAACmNwAAAAAAAKc3AACqNwAAAACrNwAAAACuNwAAAACwNwAAAAAAALQ3AAC1NwAAAAAAAAAAtje7N703AAAAAMU3AAAAAMY3AADHN8o3AAAAAAAAyzcAAAAAAADMN803AAAAAAAAAADONwAAAAAAANA3AAAAAAAA0TcAANI3AADVN9033jfgN+E3AADjNwAA5DflNwAAAAAAAAAAAAAAAAAAAAAAAAAAAADnN+g3AAAAAO03AAAAAAAAAAAAAAAAAADuNwAAAAAAAAAA8DcAAAAAAAAAAPE38jcAAAAAAAAAAAAA9jf5NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD6N/s3AAAAAAAAAAD8NwAAAAAAAP03AAAAAAE4BDgAAAU4AAAAAAY4AAAJOAo4AAAAAAs4AAAaOAAAAAAAAAAAAAAcOB04IzgAACU4AAAAACY4AAArOAAAQDgAAAAAAAAAAAAAQTgAAAAARTgAAEY4AABIOEk4AAAAAAAAUTgAAAAAWDgAAAAAAAAAAAAAAAAAAAAAAABeOAAAAAAAAF84AAAAAGM4AABoOAAAAAAAAAAAAAAAAGo4AAAAAGs4AAAAAAAAAAAAAG44AAAAAAAAAAAAAAAAAAB2OAAAeTgAAHw4AAAAAII4AAAAAAAAAAAAAIM4AAAAAAAAAAAAAAAAhTgAAI04AAAAAAAAAAAAAAAAjjiSOAAAAAAAAJM4AAAAAAAAlTiWOAAAAAAAAJc4mDiZOJw4nTieOJ84oDihOAAAozgAAKU4AAAAAAAAAAAAAAAAAAAAAAAAAACmOAAAqziwOLE4sjgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAszi+OMI4AADJOAAA0DgAANM4AAAAANQ41jjXOAAAAADYOAAAAAAAANk4AADaOAAAAAAAAAAA3DjkOAAAAADlOOY4AAAAAAAAAAAAAAAA6DgAAAAA6TgAAAAAAADrOPA4AAAAAPE48jjzOAAAAAD0OAAAAAAAAAAA9jgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD3OAAAAAAAAAAAAAD7OAAA/DgAAAAACDkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTkAAAAADDkNORM5AAAVOQAAAAAAAAAAFzkAAAAAAAAAAAAAAAAjOQAAJDkAAAAAAAAAACc5AAApOSo5AAAAAAAAAAArOQAAAAAAAAAAAAAAAAAAAAAsOQAAAAAvOTI5AAAAAAAAAAA0OQAAAAAAAAAANTk2OQAAPTkAAAAAPjkAAEI5AABFOQAAAAAAAEk5AAAAAAAATDkAAAAAAAAAAAAAAAAAAAAAAABNOQAAAABOOQAAAAAAAFg5AAAAAFk5AAAAAAAAAAAAAFo5WzkAAAAAAAAAAF45AAAAAAAAAABfOWk5AAAAAAAAAABrOXE5dzkAAAAAAAAAAAAAAAAAAAAAAAAAAHg5AAAAAAAAeTkAAAAAAAAAAH85AACAOYE5hjkAAAAAAACIOYk5AAAAAAAAAACLOQAAAAAAAAAAAAAAAAAAjTmQOZE5AAAAAJQ5ljkAAAAAAACYOaE5AAAAAAAAAACjOaY5qDkAAAAAAAAAAAAAqTmqOa05szkAALQ5AAC1ObY5AAAAALc5AAAAALg5AAAAAAAAAAC5OQAAuzkAAAAAvjkAAAAAwTnCOcQ5AAAAAAAAAAAAAMs5AAAAAAAAAAAAAAAAzjkAANM51DnWOQAAAAAAANk5AAAAAAAAAAAAAAAA2jkAAAAAAAAAANs5AADcOQAAAAAAAAAAAADfOQAAAAAAAAAAAAAAAAAAAADgOQAA4jkAAAAAAAAAAAAAAADjOQAA5DkAAOc5AAAAAAAA6DkAAAAA6jnrOQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO45AAAAAAAAAAAAAPE5AAD9OQAAAAAAAAAAAAD+OQAAAAD/ORc6AAAZOgAAHDoAAB06HjogOgAAAAAAAAAAAAAhOgAAIjouOgAAAAAAAAAALzoAADs6AAA8OgAAAAAAAAAAAAAAAAAAPzoAAAAAAAAAAEg6AAAAAFM6AABUOlY6VzoAAAAAWDoAAGE6AAAAAAAAAAAAAAAAAABjOgAAAABkOmU6ZzoAAAAAaDoAAAAAAAB0On06AAAAAI46AAAAAAAAAACTOgAAAACWOpk6AAAAAJo6rDoAAAAAAAAAAAAAAACtOgAArjoAAAAAAAAAAK86AAAAALE6tTq5OgAAAAAAALo6AAAAAAAAuzoAAAAAAAAAAAAAwzrEOgAAAAAAAMU6xjrIOso6AADZOgAAAAAAAAAA2joAAAAA4zrqOuw6AAAAAO067joAAAAAAAAAAAAAAAAAAAAA8DoAAAAAAADxOgAAAAAAAAAA9joAAPg6AAD5OgAA/DoAAAAA/joAAAAAAAAAAAAAAAAAAAAAATsAAAAAAjsAAAU7CTsAAAAAAAALOwAADjsAAAAAAAAAAAAAAAAPOwAAAAAQOwAAAAAAAAAAAAATOxk7AAAAAAAAGjsAABs7AAAAAB47AAAfOwAAAAAAACE7IjsAAAAAAAAAAAAAAAAjOwAAAAAAAAAAAAAkOwAAAAAyOzo7AABBO0I7AABHOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEk7AABKO0s7AAAAAAAAAAAAAE87AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUTtTOwAAWjtbO1w7AAAAAAAAAAAAAAAAAABkOwAAAAAAAAAAZjsAAAAAAAAAAAAAZzsAAAAAAAAAAAAAAAAAAAAAAABtOwAAbjsAAAAAAAAAAAAAAAAAAIA7AAAAAAAAAACCOwAAhjuIOwAAkDsAAAAAAAAAAJI7kzsAAAAAAAAAAAAAAAAAAJQ7AAAAAAAAlzueO6I7AAAAAAAAozsAAAAAAACtO687AAAAAAAAsDuxO7I7AAAAAAAAAAAAALU7AAAAAAAAAAC5OwAAAAC7OwAAAAAAAAAAAAAAAAAAwDvBOwAAAADIOwAAAAAAAAAAyjsAAAAAAAAAAAAAAADLO8w7AADNOwAAAADPOwAAAADQO9E7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0jvVOwAAAAAAANY71zsAAAAAAAAAANg7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADZOwAAAAAAAAAAAADcOwAA3TveOwAA4jsAAAAAAAAAAOY7AADnOwAA7TsAAAAA7jsAAAAA7zvwOwAAAAAAAAAA8TsAAAAAAAAAAPM7AAAAAPQ79Tv2OwAA/DsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP07AAD+OwAAAAAAAAAAAAAAAAAA/zsAPAQ8AAAUPAAAAAAAAAAAAAAgPAAAAAAhPAAAIzwAAAAAAAAAAAAAAAAAAAAAJDwAAAAAJTwmPAAAAAAAAAAAAAAAAAAAAAAAACc8AAAoPAAAAAAAACo8AAAtPDI8AAAAAAAAAAAzPAAAAAAAADQ8AAA4PAAAAAAAAAAAAAAAAAAARDwAAEs8AAAAAE48AAAAAAAAAABPPAAAAAAAAFA8AAAAAAAAUTxZPFs8AAAAAAAAAAAAAAAAAABcPAAAAABfPAAAAAAAAGA8AAAAAGI8AABkPGU8AAAAAAAAAAAAAGY8aDwAAGk8AAAAAGo8AAAAAGs8AAAAAAAAAAAAAGw8AAAAAAAAAAB5PAAAAAB8PAAAfTx+PAAAAAAAAH88AAAAAAAAAAAAAIA8AACEPIo8AAAAAAAAizwAAAAAAACMPAAAjTwAAAAAmDwAAKI8AAAAAAAApDwAAKU8pjwAAAAApzwAAAAAuTy6PAAAvDzAPAAAwTwAAAAAAADCPAAAwzwAAMU8zTzVPNk82jwAAN48AADfPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4jwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5DwAAAAAAAAAAAAA5TwAAAAAAAAAAAAAAAAAAOk86jwAAAAAAAAAAOs8AAAAAAAAAAAAAAAA7DwAAAAAAADtPAAAAAAAAAAA8DwAAAAA8TwAAAAAAAAAAPI88zwAAAAAAAAAAAAAAAD0PAAA+TwAAAAA/DwAAAAA/TwAAAAA/zwBPQI9AAAAAAQ9AAAUPRU9AAAAACE9AAAAAAAAAAAAAAAAAAAiPQAAAAAjPQAAAAAAACg9AAAqPQAAAAAAADA9AAAAADE9AAAAADQ9AAAAAAAAAAAAADU9AAAAADo9AAAAADs9AAAAAAAAAAA8PQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9PQAAAAAAAAAAPj0AAAAAAAAAAAAAPz0AAAAAQT0AAEY9AAAAAAAAAABHPQAASD0AAAAASj0AAAAAAABRPQAAUz1UPQAAAAAAAAAAAAAAAAAAAAAAAFU9AABWPVc9AABYPQAAWT0AAFs9AABdPQAAYD1kPQAAZT0AAGY9aD0AAAAAAAAAAAAAbD0AAAAAAABtPQAAbj0AAAAAAAB8PQAAgT2CPQAAAACDPQAAhD0AAAAAAAAAAAAAhT0AAAAAAACIPQAAiT0AAAAAAAAAAAAAAACPPQAAAAAAAJU9AAAAAAAAAAAAAAAAAAAAAAAAlz0AAAAAAACbPQAAAACoPQAAAAAAAAAAqT2uPa89AAAAALA9AAAAAAAAvz0AAMM9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyj0AAAAAAADLPQAAAAAAAAAAzT0AAAAAAAAAAAAAzj3QPQAAAADTPQAAAADVPdc9AADYPQAAAADZPQAA2z3ePd894z0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA5D0AAAAAAAAAAOU96z3wPQAAAAAAAAAAAAAAAAAA8j30PQAA9T0AAAAAAAD4PQAAAAAAAAAA+T0AAAAAAAAAAAAAAAD6PQAAAD4AAAAABD4AAAAAAAAAAAU+Bj4LPg0+AAAAABA+AAAAAAAAAAAAABE+Ej4AAAAAAAAAAAAAAAAAAAAAFD4AAAAAAAAAAAAAAAAAABU+AAAAABY+AAAAAAAAFz4AABg+GT4AABo+HT4ePgAAJz4rPgAALD4AADQ+Pz4AAEE+AAAAAAAAAAAAAE4+AAAAAAAAAAAAAAAAAABWPgAAAAAAAFk+AAAAAF4+AABfPgAAAABpPgAAAABqPgAAAABtPm4+bz4AAAAAAAAAAAAAAAAAAHI+AAAAAAAAdj4AAHc+ez5+PgAAfz4AAIA+AAAAAAAAAACIPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiT6LPgAAjT4AAAAAAAAAAAAAAAAAAAAAjj4AAAAAjz6XPpg+mT4AAAAAmj4AAJ4+AACgPgAAoT4AAAAAAAAAAAAAAACjPqQ+pT4AAAAAAAAAAAAApz4AAAAAAAAAAKk+AAAAAAAAAAAAAKs+rD4AAAAArz4AAAAAAACwPgAAAACxPrI+tD4AAAAAAAAAAAAAtz4AAAAAAAAAAAAAAAAAAAAAuD4AAAAAAAAAAAAAAAAAALo+vD69PgAAAAC/PgAAAADAPgAAAAAAAMM+xD4AAAAAxT7OPgAAAAAAAM8+AAAAAAAA0D4AANE+AAAAAAAA2D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAA2T7dPgAA4T4AAOc+AADoPuk+AAAAAIA/AAAAAIM/AAAAAAAAAAAAAAAAAACEP4U/AAAAAIY/AAAAAIc/AACMPwAAAAAAAAAAAAAAAAAAjT8AAAAAjj+RPwAAkj8AAAAAAAAAAJM/lD+VP5g/AAAAAAAAmT+cPwAAAAAAAJ4/AAChPwAAAAAAAAAAAAAAAAAAAAAAAKI/AAAAAAAAAACjPwAAAAAAAAAAAAAAAAAApD8AAAAAAAAAAAAAAAAAAAAApT+nP6k/AACuPwAAsD8AALE/AACyPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALM/tD+4PwAAAAAAAAAAAAAAALk/uz8AAL4/AAAAAAAAwT8AAAAAAAAAAAAAAAAAAMY/zT/QPwAAAAAAAAAA0T/UPwAAAAAAAAAAAADZPwAAAADaPwAAAAAAAAAAAAAAAAAAAAAAANs/AAAAANw/AAAAAAAAAADdPwAAAAAAAN4/AADlPwAAAAAAAAAA5z/oPwAAAAAAAAAA6j/rP+w/7T8AAAAA7j8AAAAAAAAAAO8/8D8AAPE/9j8AAAAAAAAAAAAAAAAAAPg/AAAAAAAAAAD6P/s/AAD8PwAAAAAAAP0//z8AAAAAAAAAAAAABkAAAAAAAAAPQAAAEkAUQBZAF0AAAAAAAAAZQBtAAAAAAAAAAAAcQAAAHUAfQCdAAAAAAAAAAAAAAChAAAAAAAAALEAyQDNAQUAAAEJAQ0AAAAAAAABFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEZAAAAAAEhASkAAAAAAS0AAAAAATEAAAAAAAAAAAE5AAABPQAAAAABSQAAAAAAAAAAAAABfQAAAAABgQAAAYUBkQAAAAAAAAAAAAAAAAAAAAAAAAAAAZUAAAAAAAAAAAAAAAABpQAAAAAAAAAAAAABrQAAAAAByQAAAAAB3QAAAeUAAAAAAAAAAAAAAAAAAAAAAekAAAAAAAAB8QH1AAAAAAAAAAAAAAAAAAAAAAH9AgUAAAAAAAACEQAAAhUAAAIdAAACRQAAAAACTQAAAAAAAAAAAAAAAAJZAAAAAAJ1AnkAAAAAAAAAAAAAAAAAAAAAAAACfQKNApEAAAAAAAACnQAAAqEAAAAAAAACpQAAAAACuQAAAAACyQLVAAAAAAAAAukAAAAAAAAC9QMlAAAAAAAAAykDLQNNAAADUQAAA1kAAAAAAAADYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2UAAAAAAAAAAANtAAAAAAAAAAAAAAAAAAADcQORAAAAAAAAAAADlQAAA6kAAAAAAAAAAQQAAAAABQQAAAAAAAAAAAAAAAAVBAAAAAAAAAAAGQQAAAAAAAAAAAAAAAAtBAAAAAAAAAAANQQ5BAAAAAAAAD0EAAAAAEEEbQQAAAAAAAAAAH0EAACBBAAAAAAAAIUEAAAAAAAAAAAAAJEEAAC5BAAAAAAAAAAAxQQAAMkEAADRBAAA1QQAANkEAADhBAAAAAAAAQUEAAAAAAAAAAAAAAABDQQAAAAAAAEVBAAAAAAAAAABHQQAASEFJQQAAAAAAAEtBAAAAAAAAAABMQQAAAAAAAAAAAAAAAAAAAAAAAE5BVEEAAAAAVkFXQQAAAAAAAAAAAAAAAAAAWEEAAFlBAAAAAFpBAAAAAAAAAAAAAFtBAAAAAAAAXEEAAAAAAAAAAF5BYkEAAAAAAAAAAAAAAAAAAAAAZ0EAAAAAaUEAAAAAAAAAAAAAbUEAAHBBAAAAAAAAAAB0QQAAAAB2QQAAd0EAAAAAAAAAAAAAeEEAAAAAAAAAAAAAAAAAAHpBAACBQQAAgkEAAIRBAAAAAAAAiUGMQQAAAAAAAAAAAAAAAI1BAAAAAI5BAACQQQAAAACRQZNBmEEAAAAAmkEAAAAAAACeQQAAAACpQQAAAACuQbBBsUEAALNBAAAAAAAAAAAAAAAAAAAAAAAAAAC0QQAAAADEQcdBAAAAAMlB00HZQQAAAADaQdtBAAAAANxBAAAAAAAAAAAAAAAAAAAAAN5BAADfQQAAAAAAAAAAAAAAAAAA4EEAAAAAAAAAAAAAAAAAAOxBAADxQfJBAAD1QfZBAAD3QQAAAAAAAPlB+0EAAAAAAAAAAAAA/kH/QQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQgAAAkIAAAAAAAAAAAAAEUIAAAAAHEIdQh5CAAAAAB9CAAAAAAAAKUIqQgAAAAAAACxCLUIAAAAAAAAuQjFCAAAyQjVCNkIAAAAAAAA4QjtCAAAAAAAARUIAAElCAAAAAE9CAAAAAFBCAAAAAAAAAABSQgAAAABVQgAAV0JdQgAAAAAAAAAAXkIAAAAAX0IAAAAAAABhQgAAYkJkQmhCAAAAAAAAAAAAAGpCbEIAAG5CAAAAAG9CAAAAAAAAAABwQnVCdkIAAAAAAAAAAAAAAAAAAAAAAAB9QgAAh0IAAAAAAAAAAAAAiUKMQgAAjkIAAAAAj0IAAJVCAAAAAJZCl0IAAAAAAAAAAJhCAACZQppCAACbQp1CAACeQgAAn0IAAAAAAAAAAAAAp0IAAAAAqEIAAAAAAAAAAAAAAAAAAKlCAAAAAKxCAAAAAAAAAAAAALBCAAAAAAAAAAAAAAAAsUIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyQgAAuEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC5QrtCvEIAAAAAAAC9QgAAAAAAAAAAxEIAAAAAAAAAAAAAAAAAAAAAAADFQgAAx0LOQgAAAAAAAAAAAAAAAM9CAAAAANFCAADTQgAAAAAAAAAA2kIAAAAAAAAAAAAA20LlQudCAAAAAOhCAAAAAAAA6ULqQgAA60IAAAAAAAAAAAAA7ELvQvlCAAAAAAAAAAAAAAAAAAAAAPpCAAD7QgAA/EIAAAAAAAAAAAAAAAD9Qv5CAAD/QgFDAAADQwAAAAAAAAAAC0MTQwAAFkMAAAAAAAAAABtDAAAAAB5DIUMAAAAAAAAAAAAAIkMAAAAAJEMAAAAAAAAAAAAAAAAAACVDJ0MAACpDAAAAAAAAAAAAAAAAAAAAAAAAK0MsQzNDNEMAAAAANUNBQwAAAAAAAAAAAABCQwAAAAAAAAAAQ0MAAERDAABFQwAAAABOQwAAAAAAAAAAAABUQwAAVkNXQwAAAAAAAFlDXEMAAAAAXUMAAGBDAAAAAGNDAABkQwAAAABwQwAAckMAAAAAAAB0QwAAAAAAAAAAd0N4QwAAeUMAAI9DAACWQwAAmUMAAAAAAACaQwAAAAAAAAAAAAAAAAAAnEMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ1DAACeQ6FDAAAAAAAAAACiQ6NDAAClQwAAAAAAAAAApkMAAAAAAAAAAAAAAAAAAKhDAAAAAAAAAAAAAAAAtkMAAMBDxEMAAAAAAADGQ8dDAAAAAMlDAAAAAMpDAAAAAAAAAAAAAAAAAAAAAAAAy0MAAAAAAAAAAAAAAADMQ81DAAAAAM9DAAAAAAAA20MAANxDAAAAAAAA8UMAAAAAAAAAAPJDAAAAAAAAAAAAAPNDAAAAAPdDAAAAAAAA+UMJRAAACkQAAAtEAAAAAAAAAAAAAA5ED0QAAAAAAAAAAAAAEEQAAAAAAAAAAAAAFEQVRBlEAAAAAAAAHUQAAAAAIUQAAAAAIkQAAAAALUQAAAAAAAAAAAAAAAAAAAAALkQwRDZEAAAAADpEAAAAADxEAAAAAD1EAAAAAAAAAAA+RAAAQ0QAAAAAAAAAAAAAR0QAAAAAAABLRExEAABNRAAATkQAAFNEVEQAAAAAVUQAAFZEV0QAAAAAAABYRAAAAAAAAFlEAAAAAAAAXkQAAAAAAAAAAAAAX0QAAGFEAABjRAAAAAAAAGhEaURqRAAAAABrRAAAAAAAAG9EAAAAAAAAckQAAAAAc0QAAAAAAAAAAAAAAAAAAAAAAAB3RAAAAAAAAHhEAAAAAAAAfkQAAAAAAAAAAIBEAAAAAAAAg0QAAIREh0SNRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlEQAAAAAlkQAAJdEAAAAAJhEAAAAAAAAm0QAAAAAAAAAAAAAAACcRAAAAACdRJ5EAACfRAAAAAAAAAAAAAAAAKFEokQAAKdEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK1EAAAAAAAArkSvRAAAskQAAAAAs0QAAAAAAAAAAAAAAAAAALREAAAAAAAAAAC8RL1EAAAAAL5EwEQAAAAAAAAAAAAAAADBRAAAAAAAAMREAAAAAMVEAAAAAMdEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMRAAAAADSRAAA1UTWRAAAAAAAAAAA10QAAAAA2EQAAAAA3kQAAAAA30ThROJEAAAAAAAAAAAAAAAAAADjRAAAAADkRAAAAADlRAAA5kQAAOhEAAAAAAAAAAAAAAAAAAAAAAAAAADpRAAAAAAAAAAAAAAAAAAAAAAAAAAA60QAAAAAAAAAAO1EAAAAAAAAAAAAAAAAAAAAAO5E/kQAAAAAAAAAAAAAAAAAAAAAAAD/RABFAAABRQJFAAAAAAAABUUHRQlFAAAPRQAAAAAAAAAAAAAAAAAAFEUAAAAAAAAWRQAAMkUAAAAAOEU6RT5FAAAAAEBFAAAAAEFFAAAAAAAAREUAAEVFAABGRQAAAAAAAEdFAAAAAAAAAABJRQAAAAAAAAAAS0UAAAAAAABNRU5FAAAAAAAAAABPRVBFUUUAAAAAAABVRQAAVkVXRVhFWkVhRWJFAABjRQAAZkUAAGxFAAAAAAAAAAAAAG9FAAAAAAAAAAAAAAAAAABwRQAAAABxRQAAAAByRXNFAAB2RXdFAAAAAAAAAAAAAAAAAAAAAAAAAAB4RQAAAAAAAAAAAAAAAAAAnUUAAAAAAACeRQAAAAAAAJ9FoUUAAAAAAAAAAAAAokWnRahFqUUAAAAAtUUAAAAAAAC2RQAAAAAAALhFukW+RQAAv0UAAAAAw0UAAAAAAAAAAAAAAADERcVFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADORc9FAAAAAAAAAAAAAAAA0EUAAAAAAADXRQAAAAAAANlF20UAANxFAADdRQAAAADeRQAAAADfReNFIUYAAAAAAAAAACJGAAAAACNGAAAwRgAAAAA0RgAAAAAAAAAAAAA2RgAAAAAAAAAAOEY6RgAAAAA/RgAAAAAAAAAAU0YAAAAAAAAAAAAAV0YAAAAAAAAAAAAAWUYAAAAAAAAAAAAAAAAAAFpGAAAAAAAAAAAAAAAAXEYAAAAAXkYAAAAAAABfRgAAAAAAAGBGAABhRgAAAAAAAG5GAAAAAAAAAAAAAAAAAABvRgAAAAB0RnVGdkYAAAAAgUaIRgAAiUaKRgAAi0YAAAAAAAAAAAAAAAAAAAAAjkYAAAAAAAAAAJBGAAAAAAAAAAAAAAAAAAAAAJNGAAAAAAAAlEYAAAAAm0YAAAAAnkatRq5GAAAAAAAAAAAAAAAAAAAAALFGAAAAAAAAAAAAALJGtEYAAAAAAAC8RgAAv0YAAAAAwEYAAMFGAAAAAMNGxEYAAMZGAAAAAAAAAADJRgAAAAAAAAAAy0YAAAAAAAAAAAAAAAAAAAAAAADMRgAAAAAAAAAAzUbORgAAz0YAAAAA0EbXRgAAAAAAAAAAAAAAAAAAAAAAAOZGAAAAAAAAAAAAAOdG6EYAAAAA7Eb0RgAA9kb7RgAAAAAAAAAAAAAAAAAAAAAAAPxGB0cAAAhHAAAAAAAAAAAJRwAAC0cAAAAAAAAAAAAADEcAAAAAAAAAAAAAAAAAAAAADUcAAAAADkcAAAAAD0cQRwAAAAASRxNHFEcAAAAAAAAVRwAAG0cAABxHAAAAAAAAAAAdRwAAAAAAAB9HIEcAAAAAJkcAAAAAAAAnRyhHAAAAAAAALEcAAAAALkcAAAAAAAAAAAAAL0cAADFHN0cAADpHAAA7RwAAAAAAAAAAQEcAAAAAQUdCRwAAAAAAAAAAAABDR0tHAABNRwAATkcAAAAAAABaRwAAAAAAAAAAAAAAAF1HXkdfR2FHaUcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqRwAAa0cAAGxHAAAAAAAAAAAAAAAAbUcAAG9HcUcAAAAAckcAAAAAAAAAAIRHAAAAAAAAhkcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACHRwAAiEeJRwAAi0cAAAAAjEeQRwAAm0cAAJxHAACgRwAAAAAAAAAAoUcAAKRHAAAAAAAAAAAAAAAAAAAAAAAApUcAAKhHqUcAAKpHAAAAAAAAAAAAAKxHAACvRwAAAAC0RwAAAAAAAAAAAAAAALVHAAAAAAAAAAAAAL9HAAAAAAAAwEcAAMFHAADCR8NHAAAAAAAABUgMSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANSBJIAAAAAAAAAAATSAAAFEgAAAAAAAAVSAAAAAAAAAAAAAAXSAAAAAAAABhIAAAZSAAAHEgAAAAAHUgAAAAAAAAAAAAAAAAAAAAAIkgAAAAAI0gAAAAAAAAAAClIAAAAAAAALEgAAC1IAAAAAAAALkgvSDBIAAAAAAAANUgAAAAAAAA2SAAAAAAAAAAAAAAAADhIOkgAAAAAAAAAAAAAAAA7SAAAAAAAAAAAAAA/SAAAAABASAAAAAAAAAAAAAAAAElIAABZSAAAWkhbSAAAAAAAAF1IXkgAAAAAAAAAAAAAX0gAAAAAAAAAAGRIZUgAAGZIAAAAAAAAAAAAAAAAZ0hpSAAAakgAAAAAAAAAAAAAAABsSG1IbkhvSAAAckgAAAAAAAAAAHlIfEgAAAAAfkgAAAAAiUiLSAAAAAAAAIxIAACOSAAAAAAAAAAAmkgAAAAAAAAAAAAAnEgAAAAAnUgAAAAAAAAAAAAAAACeSAAAoEgAAAAAAAAAAKJIAAAAAAAApEgAAAAApUimSAAAAACpSAAAAAAAAAAAqkgAAAAAAACrSKxIAACtSAAAAAAAAAAAsEgAAAAAs0gAAAAAAAAAAAAAAAAAAAAAAAC0SAAAuEgAAAAAuUi7SAAAAAAAAMRIAAAAAAAAxUgAAAAAxkgAAAAAAAAAAAAAAAAAAMdIAADISAAAAADLSM1IAAAAAAAAAAAAAAAA0UjTSNhIAADcSAAAAADdSAAA30jgSAAAAAAAAOFIAAAAAOpI8kgAAAAAAAAAAPVI/Ej9SAAAAAD+SAAAAAACSQAAAAAAAAAAAAAAAAAAB0kISQAAAAAAAAAAAAAAAAAAAAAAAAAACUkAAAAADEkAAAAAAAAAAAAAAAAOSQAAFEkAAAAAFUkAABZJAAAAABdJAAAaSQAAAAAeSQAAAAAAAAAAAAAAAB9JAAAAACJJAAAmSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK0kAAAAAAAAAAAAAM0k1SQAAAAA2SQAAN0k4STpJPEkAAEBJQUkAAAAAQklLSQAATUkAAAAAAABOSQAAAAAAAFFJAAAAAAAAAAAAAFVJWklbSV1JAAAAAGBJY0kAAGRJAABpSQAAAAAAAAAAAAAAAGtJAAAAAHBJAAAAAAAAAAAAAHFJdEkAAAAAAAAAAAAAAAAAAHZJAAAAAAAAe0l/SYBJAAAAAAAAAACJSQAAAACLSY1JAAAAAI5JAAAAAAAAAACPSQAAAACQSQAAAAAAAAAAkUkAAJhJAACZSQAAmkkAAAAAAAAAAJtJAACcSQAAAAAAAAAAAAAAAJ1JnkkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKBJAAAAAAAApUmsSQAAAACuSbJJAAAAALNJtUkAAAAAuknBSctJAAAAAAAAAAAAAAAAAAAAAAAAAADMSQAAAAAAAAAAAAAAAAAAAADPSQAA0EkAAAAAAADUSQAAAAAAANVJAADWSeNJ5EkAAAAAAAAAAAAAAAAAAAAA50kAAAAAAAAAAAAA6EkAAAAAAADpSfFJAAAAAAAAAADySQAAAAAAAAAAAAAAAPRJAAAAAAAAAAD2Sf5JAAAAAAAAB0oNSgAAAAAAAAAADkoAAAAAAAAAAA9KEEoAAAAAEUoAAAAAEkoAAAAAAAAAABNKFEoAAAAAAAAVSgAAF0oAAAAAAAAAAAAAAAAAAAAAAAAYSgAAGUoAABpKHUogSgAAAAAAAAAAAAAAACFKAAAAAAAAJUoAAAAAAAAuSgAANkoAAAAAAAAAAAAAN0o7SgAAAAA9SgAAAAAAAD5KAAAAAAAAAAAAAAAAQEpDSgAAAABKSgAAAABLSgAAUEoAAFdKWEoAAF9KAABhSmpKAAAAAAAAa0pvSnBKAABzSndKeEoAAAAAkEoAAAAAAACVSpZKAAAAAAAAAACXSgAAmEoAAAAAAACZSgAAAACaSgAAm0qcSgAAAACfSgAAAAAAAAAAAAAAAAAAp0oAAAAAAAAAAAAAAACoSgAAAAAAAKxKrUoAALFKskoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALNKtEoAAAAAAAAAAAAAAAAAALVKtkoAALhKAAAAAAAAAAAAAAAAAAAAAAAAAAC5SrpKu0q8SgAAAADKSgAAAADLStRK1koAAAAAAAAAAAAAAAAAAAAA7krxSgAAAADzSgAAAAAAAPlKAAAAAAAAAAAAAPpKAAD9SgAAAAAAAAAA/koAAAAAAAAAAAAAAAAAAAAAAAAAAAJLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0sAAAVLCksAAAAAAAANSwAAEksAAAAAAAAXSx1LAAAAAB5LAAAAAB9LIEshSydLAAAAAAAAAAAAAChLAAAwSzFLAAAAAAAAAAA2SwAAOEs6SztLAAAAAD1LAABCSwAAAAAAAEhLAABOS1FLUksAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABTSwAAAABUSwAAAABVS1dLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhLW0sAAFxLAAAAAAAAAABhSwAAYksAAAAAAAAAAGZLZ0sAAAAAAAAAAGhLaUsAAAAAAAAAAHJLAAAAAHNLAAAAAHlLAAAAAAAAAAAAAAAAAAB6SwAAhUsAAIZLh0sAAIhLiUsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkksAAAAAmUsAAJpLoksAAKZLp0sAAAAAqUsAAK9LAACxS7RLvEsAAAAAAAAAAAAAvUu+SwAAAAAAAAAAwEsAAAAAAAAAAAAAyksAAAAAAAAAAAAAAAAAAAAA1EsAAAAA1UveSwAA4EsAAAAAAADhSwAAAAAAAORLAAAAAAAAAADnSwAAAAAAAAAAAADoSwAAAAAAAAAAAAD4SwNMAAAAAAVMAAAGTAdMAAALTBJMGkwAAAAAAAAAACZMAAAAAAAAAAAtTAAAAAAAAAAAAAAAAAAAAAAAAAAALkwwTAAAAAAAAAAAAAAAAAAAMUwAAAAAAAAAADJMM0wAAAAAAAA0TAAAAAA3TAAAAAA6TAAAO0wAADxMAAA+TAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEpMAABRTFJMAABXTFpMAABbTF9MAAAAAAAAAAAAAAAAYExhTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGNMAAAAAGRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaExpTAAAAABqTAAAAAAAAAAAAAAAAG1Mb0wAAHBMAAAAAAAAcUxyTAAAekwAAAAAAAAAAHxMAAAAAAAAAAB9TIBMAAAAAAAAAAAAAAAAAACBTIJMAAAAAAAAg0yETAAAhUwAAAAAAAAAAAAAAACITIlMj0wAAJBMAAAAAJRMAAAAAJVMAACWTJhMmkwAAJ1MnkwAAAAAAAAAAAAAAACgTKFMAAAAAKJMAAAAAKNMAAAAAAAApEylTK9MAAAAALBMsky0TAAAu0wAAAAAvEzKTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADLTAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbTN1MAAAAAAAAAADfTAAA40wAAORMAAAAAAAAAAAAAAAA50wAAAAAAAAAAAAAAAAAAAAA6EzpTOxMAAAAAAAAAAAAAAAAAADvTPFMAAAAAAAAAAAAAPJM80wAAAAA9EwAAPZMAAAAAPdMAAAAAAAAAAAAAAAA+Ez8TAAA/kwAAAFNAAAAAAAAA00AAAAAAAAAAAZNAAAAAAAAAAAAAAAAAAAITQAACk0AAAAADU0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJNAAAAAAAAAAAAABNNAAAWTRdNG00AAAAAHE0AAB1NAAAAAAAAIk0AAAAAI00AADtNAAAAAAAAAAAAAAAAAAAAADxNP00AAAAAAAAAAAAAAABCTQAAAAAAAAAAAABDTQAAAABETU5NAABPTQAAAABQTQAAAAAAAFFNAAAAAFRNVU0AAAAAAABXTQAAAAAAAFlNAAAAAAAAAABbTQAAXE0AAF1NAAAAAF9NAAAAAAAAYE0AAAAAAAAAAAAAAABhTQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoTQAAbU0AAG5Ndk13TQAAAAAAAHlNAAAAAAAAAAAAAAAAAAAAAAAAAAB+TQAAAAAAAAAAf00AAAAAg00AAAAAAAAAAIVNAAAAAAAAAACHTQAAAACITQAAiU0AAAAAAAAAAAAAAAAAAItNAAAAAAAAjk0AAAAAAAAAAAAAAAAAAAAAAACYTQAAmU0AAJpNAAAAAAAAAAAAAAAAAACcTQAAAACeTQAAAACfTQAAAACgTaFNo00AAKhNqk2sTQAAAACtTa5NsE0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyTbRNtU0AAAAAtk0AAAAAAAC3TQAAuE2+TQAAAAC/TQAAAADBTQAAAAAAAMJNAADETQAAxU3HTQAAAAAAAMlN0E0AAOJN403kTQAAAAAAAAAAAAAAAAAA5k0AAOdNAADpTQAAAAAAAO9N8E3yTfhNAAD9TQAAA04AAAAAAAAAAAAAB04AAAhOAAAWTgAAAAAXTgAAGU4AABtOAAAAAAAAHk4fTiFOAAAjTiVOAAArTixOAAAAAAAAAAAAAAAALk4AADROAAAAAAAAAAA1TgAAAAAAAAAAAAA3TjhOAAAAAAAAAAAAADlOAAAAADtOAAAAAD1OAAAAAEBOAAAAAAAAAABMTk1OAABQTlFOAAAAAFJOAABUTgAAAABWTllOAAAAAAAAAAAAAAAAAAAAAAAAW04AAAAAXU4AAF5OAABgTgAAAABiTgAAAABjTgAAAAAAAAAAZU4AAAAAAAAAAAAAAABmTmdOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhOAAAAAGlOak4AAAAAAAAAAAAAa04AAG5OAAAAAAAAAABwTgAAcU4AAAAAAAAAAAAAAAB/TgAAgk4AAAAAAAAAAAAAAAAAAItOAAAAAAAAAAAAAAAAAAAAAJBOAAAAAAAAkU6STgAAAAAAAJNOm06cTgAAAAAAAKNOpU6mTgAAAAAAAAAAqE4AAAAAqU6qTrZOAAC4TgAAAAAAALlOAAAAALpOAAAAAAAAvk4AAMNOAAAAAMROAAAAAAAAAAAAAAAAAADGTgAAyE4AAMpOAADPTgAAAADSTgAAAAAAAAAA/04AAAAAAAAAAABPAAACTwAAAAAGTwAAB08AAAAAAAAAAAhPAAAAAAlPCk8AABRPAAAXTwAAAAAAAAAAAAAAABlPAAAAAAAAGk8AAAAAAAAAABtPAAAdTwAAHk8AAAAAAAAAACBPAAAAAChPAAAAAAAAAAAqTwAAAAAAADZPAAAAADdPOk8AAAAAAAAAAAAAO08AADxPAAA9TwAAP09CTwAAAAAAAAAARE8AAAAAAAAAAEVPSU8AAAAAAAAAAAAAAABLTwAATE9PTwAAAAAAAAAAAAAAAFNPAAAAAFRPAABVTwAAVk8AAAAAAAAAAAAAAABYTwAAAAAAAFpPAAAAAAAAAABbT1xPAABiTwAAAAAAAAAAAAAAAHNPAAAAAAAAdk8AAAAAAAAAAIBPAAAAAAAAAAAAAAAAAAAAAAAAAACKTwAAAACNTwAAl0+ZTwAAAAAAAAAAAAAAAAAAAAAAAAAAAACaT5tPAACcTwAAAACdTwAAnk8AAJ9PAACkTwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmT6hPqU8AAAAAq08AAAAAAAAAAAAArE8AAAAAAAAAAAAAAAAAAAAArk+/TwAAAAAAAMFPAAAAAMRPAAAAAMpPzE8AAM9PAAAAANBPAADRT9JP008AAAAAAAAAANhPAAAAAAAAAAAAANpPAADbTwAA3k8AAAAAAAAAAOBPAADjTwAAAAAAAAAAAAAAAAAAAAAAAORP5U8AAAAA5k8AAAAAAAAAAAAAAADpTwAA6k8AAAAAAADxTwAAAAAAAAAAAAD1TwAAAAAAAPlPAAD8TwAAAAAAAAAAAAAAAAAAAAD9TwAAAAAFUAAAAAAGUAAAAAAHUAAAEFAAABFQAAAAABJQAAAAAAAAAAAAAAAAAAAAAAAAAAATUBRQAAAVUAAAAAAAAAAAAAAoUC9QAAAxUAAAAAAAAAAAO1AAAAAAPFAAAAAAAAA/UAAAAAAAAEJQAAAAAAAAAAAAAERQAAAAAFNQAAAAAFRQAABWUAAAAAAAAAAAAABtUAAAAAAAAAAAblAAAAAAcVByUAAAAAAAAAAAc1AAAHVQdlAAAAAAAACKUIxQAAAAAAAAAACNUAAAAAAAAAAAk1AAAAAAAAAAAAAAlFAAAAAAAACVUAAAllAAAAAAn1AAAAAAAAAAAAAA41AAAAAA5VAAAAAAAADpUOpQAAAAAAAAAAAAAPRQ9VAAAAAAAAAAAPZQ+FD5UAAA/VAAAP5QAAD/UABRAAABUQAAAAAIUQAACVEAAAxRAAAAAA1RAAAAAAAAAAAAAAAAAAAAAA5RAAAAAAAAAAASUQAAAAAAABlRAAAAABtRAAAAAAAAAAAAAAAAAAAeUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfUQAAAAAAAAAAIFEAACFRKVEAAAAAAAAAAAAAAAAxUQAAAAAAADJRO1FBUQAAQlEAAEdRAAAAAEhRAAAAAEpRAAAAAEtRAABMUQAAAAAAAAAAAABNUQAAAABSUVRRVVEAAAAAAABWUQAAV1EAAAAAAABaUQAAAAAAAAAAAAAAAAAAXVFeUV9RAABgUWRRAAAAAGdRAAAAAGhRalEAAGtRAABsUQAAdlEAAAAAAAB3UQAAAAAAAAAAeFEAAAAAAACFUQAAAACHUQAAAAAAAAAAAAAAAAAAiVEAAAAAAAAAAAAAjFEAAAAAAAAAAAAAkFEAAAAAklEAAAAAAAAAAJNRlFEAAAAAmlEAAAAAAAAAAAAAAAAAAAAAAACbUQAAAAAAAAAAAACpUQAAqlGuUQAAAACwUbNRAAAAAAAAAAAAALRRAAC1UQAAt1G4UbpRAAC/UQAAwFHBUcJRAAAAAMdRAAAAAMtRAAAAAM1RAAAAAAAAz1EAAAAAAADSUdNRAAAAAAAAAAAAANZRAADaUQAAAADbUeRRAAAAAOdRAAAAAAAAAAAAAO1R71EAAAAAAAD4UQAA+1H8UQAAAAAAAAAAAAD9UQAAAAAAAANSAAAGUgAAB1IAAAAAAAAAAAhSCVIAAAAAAAAAABBSAAASUgAAGFIAAAAAAAAZUhpSAAAAAAAAAAAAAB1SIlIjUiRSAAAAACVSAAAAAAAAAAAAACZSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnUihSAAAAAAAAAAAAAC1SAAAAAC5SAAAAAAAAAAAAAAAAAAAAAAAAL1IAADFSAAA2UjdSAAAAAAAAOVI9UgAAAABBUkhSSVIAAAAASlJLUgAAAAAAAE1SAAAAAAAAT1JQUgAAAABRUgAAUlIAAAAAVlIAAAAAAAAAAFdSAAAAAFhSWVIAAAAAXlJfUgAAYVIAAAAAAAAAAAAAAAAAAGNSAABlUgAAZlIAAAAAAAAAAAAAAAAAAAAAZ1IAAAAAAAAAAAAAaFIAAGpSAAAAAAAAAAAAAAAAAABrUgAAAABsUm1SblIAAAAAAAAAAAAAb1IAAHBSAAAAAAAAAAAAAHFSdFJ1UgAAAAB4UnlSAAAAAAAAAAAAAAAAe1KCUoNSAAAAAAAAAAAAAIVSAAAAAAAAAAAAAAAAAAAAAIlSi1IAAAAAjlIAAAAAAACRUpZSAACXUgAAAACYUgAAmVKaUgAAoFKiUqNSpFIAAAAAAACoUgAAAAAAAAAAAAAAAKlSAACsUgAArlIAAAAAAAAAALJSAAAAAAAAAACzUgAAAAC0UgAAtlIAALdSAAAAAAAAAAAAALhSu1LEUgAAAAAAAMVSAAAAAMZSAAAAAAAAyFIAAAAAyVIAAAAAAADOUgAA3FIAAAAA3VIAAAAAAAAAAAAAAADfUuBSAAAAAOdS6VIAAOpSAAAAAAAAAADrUuxSAAAAAO1SAAAAAAAAAADuUvRSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1UgAAAAD2UvdSAAAAAAAAAAAIUwAAAAAAAAAAAAAJUwAAAAAAAAAAAAAAAAAAC1MAAAAAAAAPUwAAGFMAABpTAAAiUwAAAAAAAAAAAAAAAAAAAAAjUwAAAAAAAAAAAAAAAAAAAAAuUwAAAAAxUwAAAAAAAAAAMlMAAAAAAAAzUwAANFM2UwAARFMAAEZTSlNLUwAATFMAAE5TAAAAAAAAT1NQUwAAAAAAAGhTAAAAAGpTcVMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHJTAAAAAAAAc1MAAAAAAAAAAAAAAAAAAAAAAAB2UwAAAAB3U3xTflMAAAAAAAB/U4FTAACCUwAAAAAAAIRTAAAAAAAAAAAAAAAAAAAAAAAAAACFUwAAAAAAAAAAAAAAAIZTAACHUwAAAACIUwAAAACJUwAAAAAAAAAAjVOOUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlVOWUwAAAAAAAAAAAAAAAAAAAAAAAAAAl1MAAJhTAAAAAAAAAACaUwAAAAAAAJtTnFMAAJ1TnlMAAAAAAACfUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKBTAAAAAAAAAAChUwAArVMAAK5TAAAAAAAAsVO0UwAAAAAAAAAAtVMAAAAAAAAAAAAAuVMAAAAAAAAAAAAAAAAAAAAAAAAAALpTAADDUwAAxFPJUwAAzFMAAM1TzlMAAAAAAADRUwAAAADSUwAAAAAAANRT1VMAAAAA2FMAAAAAAADhU+ZTAAAAAOdTAAAAAOlT61MAAAAAAAAAAAAAAAAAAAAA7FMAAAAA7VPuUwAAAADwUwAAAAAAAAAAAAAAABNUAAAAABVUAAAAAAAAAAAAAAAAAAAWVAAAAAAAAAAAAAAAABlUGlQAAAAAG1QAAAAAHVQAAAAAI1Q8VAAAP1QAAAAAAAAAAAAAAAAAAAAAR1QAAAAAAAAAAElUAAAAAAAAAAAAAFdUAAAAAGRUAAAAAAAAAAAAAAAAAAAAAAAAZVQAAGZUAAAAAHFUclRzVHRUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3VAAAAAAAAAAAf1QAAINUAAAAAAAAAACHVI5UlVSeVAAAAACfVKBUAACiVAAAAACjVAAAplSoVKlUAACqVLNUAAAAAAAAAAAAALRUAAC+VAAAAAAAAAAAv1TEVAAAx1QAAMhUAAAAAM1UAAAAAAAAzlQAAAAAAAAAAAAAAAAAAAAAz1QAAAAAAADQVAAA1VQAAOJUAAAAAAAA41TlVAAAAAAAAAAA6VTtVO5UAADzVAAAAAAAAPVUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2VAAAAAAAAAAAAAD4VAAAAAAAAAAA+VQAAAAAAAAAAAAAAAD7VPxUAAD9VAAAAAAAAAAAAAAAAABVAAAAAANVAAAAAAAAAAAAAAAAAAAAAAAABFUAAAAABlUAAAAAB1UAAAAAAAAAAAAAAAAAAAAAAAANVQAADlUAAAAAD1UAAAAAAAAAABBVAAAAABFVAAAAAAAAAAAAAAAAAAAAAAAAFFUbVRxVH1UAAAAAAAAlVQAAAAAAAAAAAAAtVQAAAAAAAAAALlUAAC9VMVUAADJVM1UAADlVO1U8VQAAP1UAAEBVAAAAAEFVAAAAAEJVSFUAAAAAAAAAAAAASVVYVVlVAAAAAGtVblVvVXFVAAAAAAAAclUAAAAAAAAAAAAAAAAAAAAAAABzVQAAdlUAAAAAAAB3VQAAeVV+VQAAAAAAAAAAf1UAAAAAgFWGVYdViVUAAI1VAACQVQAAAACSVQAAAAAAAJVVllWXVQAAAACYVQAAAACZVZpVm1UAAJ9VAAAAAAAAAAAAAAAAAAChVQAAAACiVa1Vs1UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuFUAAAAAAAAAAAAAuVUAALtVAAAAAAAAAAAAAAAAAAAAAAAAAAC9VQAAAAAAAL5VAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/VQAAwFUAAAAAAAAAAAAAAAAAAAAAAADCVcVVAAAAAAAAAADGVQAAx1UAAAAAAAAAAAAAAADKVctVAAAAAAAAAAAAAAAAAAAAAMxVzVUAAAAA0VXSVQAAAAAAANZVAAAAANxV3VUAAN5VAAAAAAAAAAAAAOFVAADkVQAA6FUAAO9VAAAAAAAAAAAAAAAA8VUAAPJVAAAAAAAAAAAAAAAA81UAAAAAAAAAAAAA9FUAAAAAAAD4VQAA+VX/VQAAAAAAVgAAAAAAAAFWA1YAAAAAAAAAAAAAAAAAAAAAAAAEVgAAAAAAAAAAAAAAAAAAAAAAAAAABVYVVgAAF1YAAAAAAAAYVgAAAAAAACBWIVYAAAAAJVYnVihWK1YAAAAALFYtVgAAAAAwVgAAAAAAAAAAMlYAAAAAAAAAAAAAAAAAADlWAAAAAAAAOlY7VgAAAAAAAAAAAAAAAAAAPFYAAAAAAAAAAD1WRFZTVgAAAAAAAAAAAAAAAAAAWFYAAAAAW1YAAFxWAABdVgAAXlYAAAAAAAAAAAAAAAAAAF9WZ1YAAGhWalYAAAAAAAAAAG1WAAAAAAAAcFZxVgAAAAAAAAAAAAAAAH1WAAAAAAAAflYAAAAAgFaCVgAAhFaFVodWilYAAAAAAACSVgAAAAAAAAAAlFahVgAAAAAAAAAAo1YAAKZWp1YAAAAAqFasVgAAAAAAAAAAAAAAAAAAAACuVgAAsla5VgAAAADAVgAAwVYAAMRWAAAAAMdWAADPVtdWAAAAANhWAADaVgAAAADbVtxWAADdVgAA4FYAAAAAAAAAAAAA4VYAAAAAAADiVuZW51YAAAAAAADzVvxWAAD9VgAAAAAAAAAAAAAAAAAA/lYAAAAAAAAAAP9WAAAAVwAABVcAAAAAAAAAAAAABlcIVwtXDlcAAAAAD1cRVwAAAAASVwAAFVcAAAAAAAAAAAAAAAAAAAAAAAAAABdXAAAdVx5XAAAAAAAAIVcAACRXAAAAAAAAAAAAAAAAAAAAAAAAAAArVwAAAAAAAC1XAAA+VwAAAAAAAD9XAAAAAAAAAAAAAEBXAABCV0hXAABLV01XAABOVwAAAAAAAAAAAAAAAAAAVVcAAAAAAAAAAAAAVlcAAAAAAAAAAAAAAAAAAAAAAAAAAFdXWFcAAAAAAAAAAAAAAAAAAAAAWVdeVwAAAABhVwAAYldlVwAAAAAAAAAAAABnVwAAaVcAAAAAAAAAAAAAalcAAAAAAAAAAG1XAAAAAAAAAABuVwAAb1cAAAAAAAAAAAAAAAAAAAAAAAB3VwAAAAB4V3tXfFeCVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhVcAAAAAhlcAAAAAiFcAAAAAiVeKVwAAAAAAAAAAAAAAAJhXAAAAAAAAAACaVwAAAAAAAJtXAACcVwAAoFcAAKNXqlerVwAAAAAAAAAArFcAAAAAAAAAAAAArlcAALZXAAC3VwAAAAAAAMFXAADGVwAAx1cAAAAAAAAAAMhXyVcAANdXAAAAAAAA2FcAAAAAAAAAANlXAAAAAONXAAAAAAAAAAAAAAAA8lcAAAAA81cAAAAAAAAAAAAAAAAAAPRXAAAAAAAA9Vf4VwAAAAAAAAZYAAAAAAdYAAAAAAhYAAAMWBlYAAAbWAAAAAAAAAAAIVgAAAAAIlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJlgAAAAAAAAAACdYKFgAAAAAL1gAADNYAAA2WDdYOVgAAAAAAAAAAAAAOlgAAAAAO1gAAAAAPlgAAAAAAAAAAAAAP1gAAEBYAAAAAAAAAAAAAEFYAABKWAAAAABMWAAAAABRWAAAAABaWAAAAAAAAAAAAAAAAFtYAABgWGFYAAAAAG5YAAAAAAAAAAAAAG9YAAAAAHBYAAAAAAAAAAAAAAAAAAB0WAAAdVh3WAAAAAAAAAAAfFh9WAAAAAAAAH5YAAB/WAAAAAAAAIBYAAAAAAAAAAAAAAAAAAAAAAAAAACRWJNYlFgAAAAAlliXWAAAo1gAAAAAAAAAAAAAAAAAAKVYAAAAAKhYAACrWLNYtFgAAAAAAAAAAAAAAAAAAAAAvlgAAL9YAAAAAAAAAADDWAAAAAAAAMRYxVgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxljIWAAAAAAAAAAAAAAAAAAAAADJWAAAAADLWAAAAAAAAAAAzFjPWNBYAAAAAAAAAADTWAAA3VgAAAAA31gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5lgAAAAAAAAAAAAA6FgAAAAAAAAAAAAA7FjtWO5YAADwWAAAAAAAAAAAAADxWPJYAAAAAAAAAAAAAAAA81gAAAAA9Fj3WAAA+Fj5WPxYAAAAAP5YAFkAAANZAAAFWQxZAAAAAAAAAAAAAA5ZAAAAAAAAAAAAAAAAElkAABNZFFkAAAAAAAAAAAAAAAAAAAAAAAAAABVZAAAAABpZG1keWSBZAAApWSpZAAAvWTFZAAAAAAAAAAAAAAAAAAAAAAAAMlkAADRZNlkAADdZAAAAAAAAAAAAADhZAAA/WQAAAAAAAAAAAABIWUlZAABKWUtZAAAAAE5ZAAAAAFBZAAAAAAAAAABRWQAAAAAAAAAAAAAAAAAAAAAAAAAAAABSWQAAU1lUWQAAAAAAAAAAVVkAAFdZAABYWQAAWVlhWWJZZFllWQAAAAAAAAAAAAAAAAAAZllnWQAAblkAAG9ZAAAAAAAAdFkAAHVZAAAAAAAAAAB4WQAAAAAAAAAAeVl7WQAAAAAAAINZhVkAAAAAhlkAAAAAAACIWQAAAAAAAJFZklkAAAAAAACdWZ5ZAAAAAAAAn1kAAAAAAACgWQAAAAAAAAAAAAAAAAAAolkAAKNZAAAAAKpZAACsWQAAAACyWQAAAAAAAAAAAAAAAAAAs1kAAAAAtFkAAAAAAAAAAAAAAAAAALVZAAC4WQAAAAAAALlZAAAAAAAAAAAAALpZAAC7WQAAAAAAAAAAAADCWQAAAADDWQAAy1kAAAAAzVkAAAAAAAAAAAAAAADOWQAA3VkAAAAAAAAAAAAAAAAAAN5Z31ngWQAAAADvWfBZ9VkAAAAAAAAAAPZZAAAAAAAAAAAAAPhZAAAAAAAAAAAAAPtZAAAAAAAAAAD+WQAAAAAAAAhaAAAJWgxaDVoUWhVaAAAXWgAAAAAAAAAAG1ocWgAAAAAAAB1aIVoAAAAAAABXWgAAWFoAAAAAAAAAAAAAWVoAAGJaZVoAAG1aAAAAAG5aAAAAAAAAcFoAAAAAAAAAAAAAAAAAAAAAcloAAAAAAAAAAHVad1p4WgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIxaAAAAAAAAAACNWgAAAACUWgAAlVoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACbWgAAAACcWp9aAAAAAAAAAAAAAAAAAAAAAAAAoloAAKRaAACnWgAAqVqqWgAAAAAAAAAAAAAAALtavVoAAAAAvlrCWsZaAAAAAAAAzVrOWtBaAAAAAAAAAADRWtZaAAAAAAAA4VoAAAAAAAAAAAAAAAAAAORaAADsWgAAAAAAAAAA7VoAAAFbAAACWwAAAAAAAAAAA1sAAAZbAAAAAAdbEFsAAAAAElsAABhbAAAAAAAAAAAcWwAAHVsAACBbAAAmWwAAAAAAAClbAAAAAAAAAAAvWzBbMlsAADRbAAAAAAAAAAAAAAAAAAAAADlbAAAAAAAAAAA7WwAAPFs+WwAAAAAAAD9bQFsAAEFbAABHWwAASVsAAAAATVsAAFJbU1sAAFZbV1sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW1sAAAAAAAAAAAAAAABcW15bAAAAAGFbZlsAAAAAAABnWwAAAAAAAGhbAAAAAAAAAABpWwAAAAAAAHdbAAAAAAAAAAAAAAAAAAAAAHhbAAB+WwAAk1uUWwAAAAAAAAAAmFsAAJ5bAAAAAAAAAAAAAAAAoFsAAAAAoluoWwAAAAAAAAAAAAAAAKlbAAAAAAAArluvWwAAAACwWwAAAAAAALFbyFsAAAAAAAAAAAAAAAAAAAAAyVsAAMtbAAAAAM5bAAAAAM9bAAAAANlbAAAAANtbAAAAAAAA3VsAAAAAAAAAAN5b31vhW+RbAADlW+hb81sAAAAAAAAAAAAA9VsAAAAA+FsAAAAABFwAAAAABVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdcAAAIXAAAAAAJXAAAAAAOXAAAAAAAAAAAAAAQXBFcElwAAAAAAAAAABNcAAAWXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXXAAAG1wAAAAAHVwAAAAAAAAAAAAAAAAjXAAAAAAAAAAAAAAAAAAALFwuXAAAAAAAAAAAMlw2XAAAAAA3XAAAOFwAAAAAAAA+XEBcAAAAAAAAAAAAAEJcAAAAAENcAAAAAAAAAABFXEpcAABLXAAAAAAAAAAAAAAAAAAATVwAAE5cAAAAAAAAAABSXAAAVFwAAAAAAAAAAAAAAABWXAAAAAAAAAAAWFxzXAAAdVwAAAAAAACBXAAAAAAAAAAAAAAAAAAAglwAAINcAAAAAAAAAAAAAIRcAAAAAAAAhVyJXAAAjVyOXJRcAACWXAAAnVwAAAAAAAAAAAAAAAAAAKBcAAAAAAAAAAAAAKJcAAAAAKNcAAAAAAAAAACmXAAAAACoXAAAAAAAAAAAqlwAAAAAAACuXLFcAAC9XMJcAADEXAAAAAAAAAAAxVwAAAAAAAAAAAAAxlwAAAAAAAAAAMdcAADJXAAAAAAAAAAAzVzVXAAAAAAAANpcAAAAAAAAAAAAAAAAAADbXAAA3FzlXAAAAAD0XAAAAAAAAAAA9lwAAPdcAAAAAAAA+lwAAAAA/lwAAP9cAAAAAABdAAABXQAAC10AAAAAAAANXQAAE10AAAAAAAAVXQAAAAAAAAAAAAAAAAAAFl0AAAAAAAAAAAAAAAAYXRldGl0bXQAAAAAAAAAAHV0eXQAAAAAAAAAAAAAmXQAAAAAAAAAAAAAAACddAAAAAAAAAAAAAEddSV0AAAAASl1LXVddAABbXQAAAAAAAAAAXV0AAAAAAAAAAAAAAABeXQAAAAAAAAAAAABfXWFdAABiXQAAY11uXW9dcF0AAHJdAAB0XQAAd10AAH5dAACBXYVdAACGXYpdAAAAAAAAAAAAAJNdlF2WXQAAAAAAAAAAAAAAAJddAACaXZ1dAACeXQAAAAAAAAAAn12gXQAAAAClXQAAAACmXQAAAAAAAAAAp10AAKhdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACpXQAAAAAAAAAAAAAAAAAAAACsXQAAAACwXQAAsV0AAAAAs10AAAAAtF22XbddAAAAAAAAAAAAAAAAuF0AAAAAAAAAAAAAAAAAAAAAul0AAAAAAAC+XQAAAAAAAAAAAAAAAAAAAAAAAL9dAAAAAMNdAADEXQAAxl0AAAAAAADHXQAAAADIXQAAAAAAAAAAAAAAAAAAyV0AAAAAyl0AAAAAy10AAAAAzV3OXQAAAADPXdBd210AANxd3V0AAN5dAAAAAAAAAAAAAOFd4l0AAONdAAAAAORdAAAAAOxdAADwXfFd/10DXgAABF4GXgAAAAAHXg5eF14AABpeAAAAAAAAH14AACJeJV4oXipeAAArXgAAAAAAACxeAAAAAAAAAAAuXi9eAAAxXgAAAAAzXjheAAAAAAAAAAAAAAAAPF4AAD1eAAA+XgAAP14AAAAAAAAAAAAAR14AAAAASF4AAEleTl4AAAAAAABSXgAAAABTXlVeWl4AAGNeAAAAAAAAZV5mXmdeAAAAAAAAAAAAAAAAAAAAAAAAAABpXmpeb14AAAAAAAByXgAAAABzXgAAAAB1XgAAeF6FXgAAiV6MXgAAAAAAAAAAAAAAAI5elF6cXgAAAAAAAKBeAAAAAAAAAAAAAAAAAAAAAKJeAACqXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq14AAKxeAAAAAAAAAAAAAK9esF6xXgAAAAC4XgAAAAC5XgAAu14AAAAAAAAAAAAAAAC9XgAAzF4AAAAAAADNXgAAz17QXgAAAAAAAAAA0V4AAAAA0l4AAAAA114AAAAAAAAAAAAAAAAAANheAADlXuZeAAAAAAAAAAAAAAAA6F4AAAAAA18AAAAAAAAJXwpfC18TXwAAH18AAAAAMV8yXwAAAAAAADNfAAAAAAAAAAA0XzVfNl8AAAAAAAAAAAAAOl8AAAAAAAAAADtfAAA9XwAAP19FXwAARl8AAAAASl9LX1BfAAAAAAAAUV9SXwAAVl8AAAAAAABbXwAAAAAAAF9fAABgXwAAAAAAAAAAAABhXwAAY18AAGZfAABnX2xfAABzXwAAAAAAAHdfAAAAAAAAeF96X35fAAAAAAAAf1+AX4FfhF8AAAAAAAAAAIVfiV8AAAAAil+LX4xfAACRXwAAAAAAAAAAAAAAAAAAll8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXXwAAmV+aX5tfnF8AAJ5fAAAAAAAAAACgXwAAAAAAAAAAAAAAAAAAAAAAAAAAoV8AAAAAAAAAAAAAAAAAAAAAAAAAAKJfpV8AAAAAAAAAAKZfAAAAAAAAqF8AAAAAAACuXwAAAAAAAAAAsV8AAAAAsl8AAAAAAACzX7pfAAAAAAAAu18AAAAAv18AAAAAwV/CXwAAAAAAAAAAAADFXwAAxl8AAMhfAADJX8xfzV8AAAAAAAAAAAAAz18AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0F8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANlf218AANxfAAAAAAAA5F8AAAAAAAAAAAAA5V/mXwAAAAAAAOlf6l8AAOtfAADsXwAA7l8AAAAAAAAAAAAA8F8AAAAAAADxXwAAAAAAAAAAAADyXwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA918AAAAAAAAAAAAA+V8AAAAAAAD+XwAA/18AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAFYAAACGAAAAAAAAAAAAAACWAAAAAAAAAAAAAACmAAAAAAC2AAAAxgAAAAAAAAAAAAAAAAAAAAAAAAAAAOYA9gAAAAAAAAAAAQYAAAAAAAAAAAAAAAAAAAEmAAAAAAAAAAAAAAAAAAABRgFWAAAAAAAAAAABpgG2AAAAAAAAAAABxgAAAAAB1gAAAiYAAAAAAjYAAAAAAAAAAAJGAnYChgMGAAAAAAAAAzYAAAPmA/YAAAAAAAAAAAQGAAAAAAAABPYFBgUWAAAAAAAAAAAAAAAAAAAAAAVmAAAFdgWGAAAAAAAAAAAAAAWWAAAAAAAAAAAFtgAAAAAAAAAAAAAAAAXGBdYAAAXmBiYAAAAAAAAGNgAABmYAAAAABnYAAAAAAAAGlgAABrYAAAAAAAAAAAbGAAAG1gAAAAAG5gAAAAAHBgcWAAAAAAAAAAAHJgc2AAAAAAAAAAAAAAAAAAAHlgAAB6YAAAAAAAAAAAAAAAAAAAAACFYAAAAAAAAAAAAACGYAAAiGAAAAAAAAAAAAAAAACJYIpgAACLYAAAjGCOYAAAj2AAAAAAAAAAAJBgAAAAAJVgAAAAAKJgAACtYK5gAAAAAAAAsGAAAAAAAACxYAAAAAAAALZgAAAAAAAAAAAAALpgAAC7YAAAAAAAAAAAAAAAAAAAvGAAAAAAAAAAAAAAvWC/YMBgAADEYAAAAAAAAAAAxWAAAAAAAAAAAMlgAAAAAAAAAAAAANFgAADSYNRgAAAAAAAA1WAAAAAAAAAAANpg3mAAAN9g4GAAAAAAAADjYAAA5GDmYAAA52AAAAAAAADqYAAAAAAAAAAAAAAAAPtg/GAAAANhAAAAAAAAAAAAAAAABGEAAAAAAAAAAAAAB2EAAAthDGEAAAAAAAAAAAAAAAAAAAAAAAAAAA9hAAAAABBhAAAAAAAAAAAAAAAAEWEAABJhE2EAAAAAAAAUYQAAFWEAAAAAAAAAAAAAAAAAAAAAAAAWYQAAF2EAAAAAJGEAAAAAAAAzYQAAAAAAADRhAAA/YUFhAAAAAAAAAAAAAENhAAAAAAAAAAAAAERhAABRYQAAAAAAAAAAAAAAAFJhAAAAAFVhYmFjYQAAAAAAAGRhAAAAAGthAAAAAG5hAAAAAAAAAAAAAAAAAAAAAAAAcWF2YQAAd2EAAAAAeWEAAAAAAAB6YQAAf2EAAAAAAACBYQAAAACCYQAAhGGIYYphjGEAAAAAAAAAAAAAkGEAAAAAAACRYQAAlmEAAAAAl2EAAAAAmGEAAAAAAAChYQAAAAAAAKJhAAAAAKlhAAAAAAAAq2EAAAAAumEAAAAAv2EAAAAAAADKYQAAAADLYcxhAADNYQAAAAAAAAAAAAAAAAAAz2EAAAAAAAAAAAAA0GEAAAAAAAAAAAAAAAAAANJhAAAAANNh1WEAAAAAAAAAAAAAAADZYQAAAADbYQAA3GHdYQAAAADeYQAAAAAAAN9hAAAAAAAAAADhYeNhAAAAAORh6GEAAOlh7WHuYQAAAAAAAAAA8GEAAPFhAAACYgAAAAAEYgViDWIAAAAAAAAAAAAAAAARYhRiAAAAABliAAAAABtiHGIAAAAAAAAAAAAAAAAdYgAAAAAAACBiIWIAAAAAAAAAAAAAAAAAACViAAAAAAAAJmIAACpiLmIAADNiAAA3YgAAAAAAAD9iAABJYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS2IAAAAAAAAAAAAAAAAAAFZiAABXYgAAd2IAAAAAAAB5YgAAAAAAAAAAfWIAAINiAACHYgAAiWIAAAAAAACLYgAAAAAAAIxiAAAAAAAAjWIAAAAAAAAAAAAAAAAAAI9ikWIAAAAAAAAAAJVil2IAAAAAAACbYgAAAAAAAKRiAACpYqpiAAAAAAAAAACsYrFiAAC0YgAAAAC5YuxiAADtYgAA7mIAAAAAAAAAAAAAAAAAAAAA72IAAAAAAAAAAAAA8GIAAAAAAAAAAAAAAAD0YgAAAAAAAPViAAAAAAAA+GL5YvpiAAAAAP9iAAAGYwAAAAAAAAAAAAAAAAAACGMAAApjAAAfYwAAI2MAAAAAAAAAAChjAAAAAAAAAAAAAAAAAAAAAAAAKmMAACxjAAAuYwAAAAA3YwAAAAA5YwAAAAAAADpjAAAAAAAAP2MAAAAAAAAAAAAAAAAAAAAAAAAAAAAARWNHYwAAAABJYwAAAAAAAAAAAAAAAAAAS2MAAAAAAABNYwAAAAAAAFBjAAAAAAAAAABZYwAAAAAAAAAAAAAAAAAAAAAAAFtjAAAAAAAAAAAAAAAAXGMAAAAAAABdYwAAAABgYwAAAAAAAAAAAAAAAGJjAAAAAGNjAABmYwAAAABpYwAAAAAAAGpjAAAAAAAAAABsYwAAbWNuY29jAAAAAAAAcGMAAHFjAAAAAAAAc2MAAHVjAAB8YwAAAAAAAAAAAAAAAAAAAAB9YwAAAAAAAAAAAAB/YwAAAAAAAAAAAACCYwAAAAAAAAAAAAAAAAAAAACDYwAAAAAAAAAAhWMAAAAAAAAAAItjAAAAAAAAAAAAAIxjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjWMAAJljAAAAAJpjAACgYwAApmMAAKhjAAAAAKljqmMAAAAAAAAAAAAAAACtY65jr2MAALBjAAAAAAAAAAAAAAAAAACxYwAAsmO3Y75jAADAYwAAwWMAAAAAzGPOYwAAAADPYwAA0GMAAAAAAAAAAAAA0mMAANNjAADUY9Vj4GMAAAAAAADiY+NjAAAAAAAAAAAAAAAA5mMAAAAAAAAAAOtjAAAAAAAA7WMAAAAAAADuYwAAAAAAAAAAAAAAAAAAAAAAAPRjAAAAAAAAAAD1YwAAAAAAAAAA9mMAAPdj+GP5YwAA+mMAAAAAAAD8YwAA/WMPZAAAAAAAAAAAAAASZAAAAAAAAAAAE2QXZAAAAAAdZAAAAAAfZAAAAAAAACNkJGQAAAAAMWQAAAAAAAAAADZkAAAAAAAAPWQ/ZAAAAABHZAAAAABOZGJkAABjZGZkZ2QAAAAAAAAAAAAAAAAAAAAAaGQAAAAAAAAAAAAAamQAAAAAbmQAAG9kAABwZAAAc2R0ZHVkAAAAAHZkgGSEZAAAAAAAAIZkAAAAAAAAAAAAAAAAAAAAAAAAiWQAAAAAi2QAAAAAAACMZAAAjWSRZAAAkmQAAJRkrGSyZAAAAAAAAAAAAAC0ZAAAAAAAAAAAtWQAALZkuGS5ZAAAAAAAAL1kAAAAAAAAAAAAAAAAxWTJZAAAAAAAANBk0WQAAAAA02TWZNdkAAAAANlkAAAAAAAAAAAAAAAAAAAAANxkAAAAAAAAAADoZOlkAAAAAAAA9mQAAAAAAAD3ZPhkAAAAAAAAAAAAAAAAAAAAAAAA+WT6ZAAAAAD7ZAAAAAD8ZAAABmUAAAAAAAAHZQllAAAAAAAAAAAAAAAAAAALZQxlAAANZRJlAAATZQAAFGUVZQAAAAAAAAAAFmUuZQAAAAAAAAAAAAAAAAAAL2UwZTFlAAAAAAAANGU1ZQAAAAAAAAAANmUAAAAAAAAAAAAAAAAAADhlAAA5ZQAAAAAAAAAAAAAAAAAAAAA6ZQAAAAA8ZQAAAAAAAAAAAAA9ZUdlAAAAAAAAAABIZQAAAABKZQAAAAAAAE1lAAAAAFJlVmUAAAAAAAAAAAAAAAAAAFllAABeZQAAZGUAAAAAaWVqZQAAAABrZQAAbGVtZW5lAAAAAAAAAAAAAG9lAAAAAAAAAABwZQAAAAAAAHFlc2UAAAAAAAAAAAAAdWV3ZQAAAAAAAAAAAAAAAAAAemUAAH1lAAAAAAAAfmUAAAAAAACAZQAAAAAAAAAAAAAAAAAAiWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJJlAAAAAAAAlWUAAAAAAACWZZdlAAAAAJ5ln2WgZQAAAAAAAAAAAAAAAKFlomWkZQAApmWnZQAAAAAAAKhlrGUAAK1lsWWyZbxlAAAAAAAAAAAAAL5lAAAAAL9lAAAAAMFlAADCZQAAw2UAAAAAAAAAAAAAxWUAAAAAAAAAAMZly2UAAAAAAAAAAAAAAADMZQAA0mUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADTZQAA1WUAAAAA12UAAAAAAADZZQAA2mXdZQAAAAAAAAAA3mUAAAAAAADfZQAA6mUAAAAA7mUAAAAAAAAAAAAAAAAAAAAA72UAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8GX1ZQAA+2UKZgAADGYAAAAADWYAAAAAAAAAAAAAAAAYZh1mK2YAAAAAAAAAAAAAAAAAAAAAAAA0ZjZmAAAAAAAAN2YAADpmO2YAAAAAPGYAAAAAPmYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9mAAAAAAAAQGZBZgAA0WbSZgAA02YAAAAA1GYAAAAAAAAAAAAAAAAAANVmAADbZgAAAAAAAAAAAAAAAN9mAAAAAAAA7mYAAAAAAAALZwAAAAAOZw9nEWcAAAAAGGcmZwAAAAAAAAAAK2cAAAAAAAAAAAAALGcAAAAANGcAAAAAN2cAADhnOmdAZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ2cAAERnAAAAAAAAAAAAAElnAABMZwAAAAAAAE5nAAAAAAAAAABPZwAAAAAAAAAAUWcAAFJnVGcAAFVnVmcAAAAAAABXZwAAAAAAAFhnAAAAAFpnAAAAAFxnAABfZwAAAAAAAAAAAAAAAAAAAABgZ2ZnAAAAAAAAAAAAAAAAAAAAAAAAaWcAAAAAamcAAAAAAAAAAAAAAAAAAGtnAAAAAAAAAAAAAAAAAABtZwAAdWcAAAAAdmcAAHdnAAAAAHhnfWd+ZwAAAAB/ZwAAgWeIZ4pnAAAAAAAAAAAAAItnAAAAAAAAAAAAAI1nAAAAAI5nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQZwAAkWeTZwAAAAAAAJZnAAAAAAAAl2cAAJxnnmcAAAAAAACfZwAApGcAAKVnqWe+ZwAAAAAAAL9nAAAAAAAAy2cAAAAAzWcAANxnAADhZwAAAAAAAAAAAAAAAOtnAADsZwAAAAAAAAAAAAAAAAAAAAAAAAAA7mcAAAAAAAAAAAAAAAAAAO9n8WfzZ/ZnAAAAAAAA+Gf8ZwAA/WcAAAAAAAAAAAAAA2gAAAVoAAAAAAZoAAAAAAhoE2gAAAAAAAAUaAAAAAAAAAAAAAAAAAAAAAAAABZoF2gAAAAAAAAaaAAAAAAgaAAAAAAAAAAAJ2guaC9oAAAAAAAAPWg+aD9oAABBaAAAAAAAAAAAeGgAAHloAAB7aHxoAAB9aH5of2gAAAAAAAAAAIBog2gAAAAAAACEaJFoAAAAAAAAlmgAAAAAAAAAAAAAl2gAAJlommgAAKJoAAAAAAAAo2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKRoAAAAAKVoAAAAAAAAAAAAAKdoAACoaKloAAAAAAAAqmgAAK1ormgAAAAAAACwaAAAAACzaAAAtGgAAAAAAAAAAAAAAAAAAAAAAAC1aAAAAAC4aAAAAAC5aAAAAAAAAAAAAAAAAAAAvGgAAMloAAAAAAAAAAAAAAAAAADKaAAAAADLaM1o0mgAAAAAAAAAANNoAAAAAOFoAADjaAAAAAAAAAAAAAAAAAAAAAAAAORoAADlaOloAADqaAAA62gAAAAAAAAAAAAAAAAAAPxoAAD+aAJpA2kAAAAAAAAAAAppDmkAAAAAAAAAAA9pEGkAAAAAAAAAAAAAFGkAAAAAAAAAAAAAAAAAAB9pIWkiaSNpJGknaQAAAAAAAClpKmkAAAAALWkAAAAAAAAwaQAAAAAxaTJpAAAAAAAAM2kAADRpAAAAAAAAAAAAADVpAAAAAAAAAAAAAAAAOWkAAAAAP2kAAAAAQGkAAAAAAABCaQAAAAAAAAAAAAAAAAAATGkAAE5pAAAAAFNpAAAAAAAAAAAAAAAAAABVaQAAWWlaaVxpAAAAAAAAAAAAAF1pAABeaQAAYmkAAGRpAAAAAAAAAAAAAAAAZmkAAGppa2kAAG5pAAAAAAAAAAB7aX5pAAAAAH9pgmmEaYVpAAAAAAAAAAAAAAAAAAAAAIZph2mKaQAAi2kAAAAAAAAAAAAAkWkAAAAAAACSaQAAAAAAAAAAlWmWaZdpmmkAAAAAnGmdaQAAAAAAAJ5pomkAAAAAAACkaQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAClaQAAAAAAAAAAAAAAAAAApmkAAAAAAAAAAAAAAAAAAKdpqWkAAKppAAAAAAAAq2msaQAAr2kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALBpsmmzaQAAtWkAALhpAAAAAAAAAAAAAL1pAAAAAL5pAAAAAAAAAAAAAAAAAADAaQAAAAAAAAAAAAAAAAAAAADEaQAAAAAAAAAAAADGaQAAx2kAAAAAAADJaQAAAAAAAAAAAAAAAMppAADLac5pAAAAAAAAAADPaQAAAAAAAAAAAADQadJpAADWaQAAAADXaQAA22neaQAAAAAAAN9pAAAAAAAAAADhaQAAAAAAAOJpAAAAAAAAAAAAAAAA42kAAAAAAAAAAORp7WkAAAAAAAAAAO5pAAAAAPRpAAD2aQAAAAD6aftpAAAAAAAAAAAAAAAAC2oAAAAAAAAAAAxqDWoAAAAAAAAAAA5qD2oAABBqAAAXagAAAAAAABxqAAAAAAAAAAAAAAAAAAAnagAANWoAAAAAN2oAADlqAAA7agAAPmoAAAAAAAAAAAAAQGoAAAAAAAAAAEJqAAAAAAAAAABDagAAAABEagAAAABGagAAR2oAAAAAAAAAAElqAAAAAAAATWoAAAAAUGpTalRqVmpXagAAWGoAAFlqWmoAAAAAYWoAAAAAAAAAAGNqAABlagAAZmoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ2oAAGpqa2oAAHJqAAAAAAAAc2oAAHVqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdmp3anpqAAAAAAAAe2oAAAAAAAAAAAAAAACDagAAjGqOagAAAAAAAAAAAAAAAAAAAAAAAKBqoWqlagAAAAAAAAAAAAAAAKZqAAAAAAAAAAAAAAAAsGqxagAAAAAAAAAAAAC2agAAuGoAAMFqAADCasNqAADEagAAAAAAAAAAzGoAAAAAAADUagAAAAAAAAAAAAAAANZqAADXagAAAAAAAAAA22oAAAAA3mrfauFqAAAAAAAA5WoAAOdqAADwavJqAAAAAPNqAAAAAAAAAAAAAAAABGsAAAVrDGsAAAAAAAAAAAAAEGsAAAAAAAAAAD1rAAAAAAAAQGsAAAAAAABCawAAAAAAAAAAAAAAAAAAQ2sAAAAAAABEawAAAABFawAASWtLawAAAABNawAATmsAAE9rAABVa1prAAAAAAAAAAAAAAAAXGsAAAAAAAAAAAAAAABdawAAAAAAAAAAAABlawAAZmtuawAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHdrjGsAAAAAAACNa5lrAAAAAAAAmmsAAAAAAAAAAAAAAAAAAAAAAAAAAJtrAAAAAJ1rnmsAAJ9rAAAAAAAAAAAAAAAAAACjawAAAACzawAAtWu2a7druWsAALprAAAAALtrwWsAAAAAAAAAAAAAwmsAAAAAxGvFawAAAAAAAAAAzGsAAAAA0GsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2GsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2msAAAAAAADiawAAAADkawAAAAAAAO9rAAAAAPBr8msAAPRr9msAAAAAAAD7awAA/GsBbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2wMbAAADWwAAAAAAAAAAAAAAAAAAA5sAAAAABBsAAARbAAAAAAAABVsAAAXbAAAAAAAABlsGmwAAAAAAAAibAAAAAAAAD9sAABAbEFsR2xIbAAAAABQbAAAUWwAAAAAAAAAAAAAAAAAAAAAAABTbAAAAABUbAAAVWwAAFpsAAAAAAAAXmwAAAAAAABfbGBsAAAAAAAAAAAAAAAAYWxibAAAAAAAAGNsZGxnbGhsAAAAAAAAeGx6bAAAAAAAAH5sf2wAAIBsgWwAAAAAhWwAAIhsAACKbAAAAACPbAAAkGyRbJxsAACkbKVsAAAAAAAAAAAAAAAAAAAAAKZsAACxbAAAs2wAAAAAAAAAALRs1WzWbAAAAAAAANhsAAAAAAAA2WzsbAAA8WwAAAAAAAAAAAAA8mwAAPNsAAAAAAAA9GwAAAAAAAAAAAAA+Wz6bAAAAAD7bAAAAAAAAP1sAW0AAAAAEG0AAAAAEW0AABJtAAAAAAAAG20ebQAAAAAAAAAAAAAAAAAAAAAAAAAAJW0AACZtAAApbQAAK20ybQAAAAAAAAAAOG07bQAAAAAAAAAAAAAAAAAAAAA8bT1tAAAAAAAAP20AAEFtR20AAEhtSW0AAE1tAABPbZNtlG0AAAAAAAAAAAAAmG0AAAAAAAAAAAAAAACabZttAAAAAJ1tAAAAAAAAAAAAAAAAAACfbQAAAAAAAAAAAAAAAKJtAAAAAAAAAAAAAAAApW2mbahtAACpbQAAAACqbQAAAAAAAAAAq20AAAAAAAAAAAAAAAAAAK5tAAAAAAAAAAC1bQAAAAAAAAAAtm0AAAAAAAAAAAAAAAC4bQAAAAAAAAAAAAAAAAAAAAC6bQAAwW3SbdNtAAAAAAAAAAAAAAAAAADUbQAAAAAAAAAAAADWbQAA4W0AAONtAAAAAOdtAAAAAAAA7G3tbQAAAAAAAPJtAAAAAAAAAAD4bQAAAAAAAAAA+239bQFuAAAAAAAAAAAGbgAAB24AAAAAAAAAAAAAAAAAAAAAAAAAAAAADG4AAAAAAAAAAAAAAAANbgAAAAAPbgAAAAAAAAAAAAAAAAAAAAAAABJuHG4AAB5uAAAAAAAAAAAAAB9uAAAhbi5uAAAAAC9uMW4AADNuAAA1bgAAAAAAADduOG45bgAAPm4AAD9uQW4AAAAAAABCbgAAQ25FbkhuAAAAAAAAAAAAAAAAAAAAAAAAS24AAFFuAAAAAFJuAAAAAAAAAABTbgAAAAAAAFVuAAAAAAAAWG5abgAAW25cbgAAAAAAAAAAAAAAAF1uAAAAAF5uX24AAAAAYG4AAAAAYm4AAAAAAAAAAAAAY24AAAAAZG4AAAAAZW4AAAAAAAAAAGZuZ24AAAAAaG4AAAAAAABqbgAAbG5tbgAAbm5wbnJuAAB1bnZuAAAAAAAAd24AAHhueW57bgAAhG4AAIZuAACJbgAAAAAAAAAAi24AAAAAAAAAAAAAjG4AAAAAAAAAAAAAAAAAAI1uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACObo9uAAAAAAAAAACQbgAAAACRbgAAmG4AAJlumm4AAAAAAAAAAAAAAACbbgAAAAAAAKBuoW4AAAAAqG4AAAAAAACpbrJuAACzbgAAAAC4bgAAAAAAAAAAAAAAAAAAAAC7bgAAAAAAAAAAAAAAAAAAAAC8bgAAAAAAAAAAAAD7bgAA/G79bgAAAG8AAAAAAAAEbwAAAAAAAAAAAAAFbwAAAAAAAAAAB28AAAAAAAAIbwAAAAAMbwAAAAAAAAAAAAANbwAAAAAAAA9vEm8AACpvAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBvAAAAAAAAAAAxbwAAM28AAAAAAAAAAAAAAAA3bwAAAAAAAAAAOm8AAEBvAABBbwAAAABFbwAAAAAAAAAARm9IbwAAAABJbwAAAAAAAAAATG8AAAAAAABPbwAAUW8AAFNvAAAAAAAAAABUbwAAAABWb1dvAAAAAAAAXG8AAAAAAABebwAAAABgb2FvYm9pbwAAbm8AAG9vcG8AAAAAAAAAAHFvAAAAAHRvAAAAAHlvem8AAAAAAAB7bwAAhG8AAIlvim8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQb5NvAAAAAJRvAAAAAAAAAACVbwAAAAAAAAAAAAAAAAAAlm+YbwAAAAAAAAAAAAAAAJlvAAAAAAAAmm8AAJxvnW8AAAAAAAAAAJ9vAAAAAAAAAACgb6VvrG8AAAAArW8AAAAAAACub7NvAAC2bwAAAAC5bwAAAAC9bwAAAAAAAAAAxm/Hb8tvAAAAAAAAAAAAAAAAzG8AANJvAAAAANRvAADXbwAA2G8AAAAAAAAAAAAAAADbbwAAAAAAAN1v3m8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADfbwAA428AAAAA7G8AAAAAAAD2bwAA/m//bwAAAAAAAAAAAAAAAAAAAAAAAABwAXADcARwAAAAAAAAAAAAAAAAAAATcAAAAAAAABdwAAAAAAAAGHAAABlwGnAAACFwAAAjcCRwJnAAAAAAAAAAAAAAAAAAACdwOHAAAAAAAABAcAAAAAAAAEFwAAAAAAAAAAAAAAAAAAAAAAAAQnAAAENwAABFcAAAAABGcAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJcAAAAAAAAAAAAAAAAE1wTnBQcFJwVHAAAFVwAAAAAAAAAABXcFhwAAAAAAAAAAAAAAAAWnAAAAAAAABccAAAAAAAAAAAAAAAAF5wAABfcGBwAAAAAAAAAABhcGJwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABjcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRwAABlcAAAbnAAAAAAAAAAAAAAAABwcAAAcXAAAHJwAAAAAAAAc3AAAAAAAAB9cAAAAAAAAAAAAAAAAH9wAAAAAIFwAAAAAAAAAACCcAAAhXAAAAAAhnAAAAAAh3AAAAAAAAAAAAAAAAAAAIhwAAAAAAAAAAAAAIpwjHAAAAAAkHCTcAAAAACVcAAAmnAAAAAAAACqcLRwAAAAALVwAAC2cLdwAAAAAAAAuXAAAAAAAAC6cAAAw3DEcMVwAAAAAAAAynDQcNJw2nDccAAAAAAAAAAAAAAAAAAA33AAAAAAAADicONwAAAAAAAA5HAAAAAA6HAAAOpwAAAAAAAAAADrcAAAAAAAAAAAAAAAAOxwAAAAAAAA7nAAAPJwAAAAAAAAAAAAAAAAAADzcPRw93AAAAAA+HAAAPlwAAAAAAAAAAAAAAAAAAAAAPxwAAAAAAAAAAD+cAFxAAAAAAAAAnEAAAhxAAALcQAAAAAAAAAADnEAAAAAAAAAAAAAAAAccQAAAAAAACZxAAAAAAAAAAAncQAAAAAAAAAAAAAAAAAAAAAAAChxAAArcQAAL3EwcQAANnE3cQAAAAA4cT1xRHFFcUZxAAAAAAAAAAAAAAAAR3EAAAAAAAAAAAAASHEAAElxAAAAAAAAUXEAAAAAU3EAAAAAXXEAAAAAAAAAAGBxAABhcQAAAAAAAAAAAABicQAAAAAAAGxxAAAAAAAAbXEAAAAAAAAAAG5xAAB1cQAAd3EAAAAAAAAAAAAAAAAAAAAAAAB7cQAAAAAAAH5xgHGGcQAAjnGacQAAAAAAAJtxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACccQAAAAAAAAAAnXGgcQAAAAAAAAAAAAAAAAAAonGpcQAAAAAAAK9xAAAAAAAAAAAAAAAAAAAAALFxAAAAAAAAAAAAALNxAAC1cQAAAAAAALtxAAAAAMBxAAAAANJx1HEAAAAAAAAAAAAAAAAAAAAAAADgcQAA6HH2cQAA+HEAAAAA/HEAAP1xAAAAAAAAAAAAAAAAAAAAACxyAAAAAC1yAAAAAC5yAAAAAAAAAAAAAAAAAAAAAAAAAAAycgAAAAAAADlyAAA9cgAAQHIAAEJySHJgcgAAYnIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlcgAAAABmcmtybHIAAAAAAAAAAG5yAABvcgAAAAAAAAAAAABwcnFycnJ0cgAAdnIAAAAAeHJ7cgAAgHIAAAAAAACKcgAAAACLcgAAAACMco5ykHIAAJdyAAAAAAAAAAAAAAAAAACacptyAAAAAAAAAAAAAJ1yn3IAAAAAAAAAAKByAAAAAAAAAAAAAKFyAAAAAAAAAACicgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3KkcqVyAAAAAKpyAAAAAKtyAAAAAAAAAAAAAAAAAAAAAK1yAAAAAAAAAAC0cgAAtXIAAAAAAAAAAAAAAAAAALZyAAAAALhyAAAAAAAAAAAAAAAAAAAAAMJyAADFcgAAAAAAAAAAAAAAAAAAAADKcgAAAAAAAAAAAAAAAM1yAAAAAAAAznIAAAAAz3LVcgAA1nLkcuZy6nLrcgAAAAAAAAAAAAAAAAAA7HIAAAAAAAAAAAAAAAAAAO9yAAAAAAAA+3IAAAAAAAD9cgAAAAD/cgAAAXMAAAAAAAAAAANzAAAGcwpzDHMAAAAAAAAAAAAAEHMAAAAAAAAAAAAAFXMAAAAAAAAYcwAAAAAAAAAAAAAAAAAAAAAccwAAIXMAAAAAAAAucwAAAAAAADJzAAAAAAAAM3M0cwAAAAA5cwAAAAAAADpzAAA7cwAAPnNBcwAARXMAAAAAAABGcwAAAAAAAEhzAAAAAAAATHMAAAAAAAAAAAAAAAAAAAAATnMAAE9zAAAAAAAAAAAAAFBzUXNZcwAAAAAAAAAAAAAAAAAAAABacwAAAABbc2JzAABkcwAAAAAAAGZzAABnc2hza3MAAAAAbHMAAAAAAABtcwAAAAAAAG5zAAAAAHBzAAAAAAAAAAB2c3lzAAB6c3xzAAAAAH1zAAAAAH5zAAAAAAAAAAAAAAAAAAAAAAAAAACKc5BzknOXcwAAAAAAAAAAmXOacwAAAACdcwAAAACtcwAArnMAAK9zAAAAAAAAAACwc7FzAAAAALlzAAAAAAAAwHMAAAAAAAAAAAAAAAAAAMFzAAAAAAAAAAAAAMJzw3PFcwAAxnMAAMlzy3MAAAAAAAAAAAAAAADMcwAAzXMAANFzAAAAAAAA0nMAANVzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANhz23MAAAAA3HMAAAAAAADdcwAAAAAAAAAAAADgcwAAAAAAAOdz6XMAAAAAAAAAAAAAAAAAAOtzAADtc+9zAAAAAPRzAAAAAAAAAAAAAPVzAAAAAAAA93MAAAAAAAD4cwAA+XP6cwR0AAAFdAAAAAAAAAZ0AAAKdAAAAAAAAAAAAAAAAAAAGHQAABl0AAAfdAAAJXQmdAAANnRBdAAAQ3QAAAAAAAAAAAAARHQAAAAARXQAAAAAAABLdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEx0AAAAAAAATXROdE90AAAAAAAAAAAAAAAAAAAAAAAAAAAAAH50AAAAAAAAgHQAAIF0AAAAAAAAAAAAAIN0AAAAAAAAAAAAAAAAAAAAAIV0AACIdIp0AAAAAIt0AAAAAI10jnQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTdAAAAAAAAAAAlHSVdAAAAAAAAAAAAAAAAAAAAAAAAJl0AAAAAK10sHTCdNF0AAAAAAAAAAAAANN04XQAAOJ0AAAAAON05nT4dPp0AAAAAAAAAAAAAAAAAAD7dPx0AAAAAAAA/3QAAAAAAAAAAAAAAXUAAAAABHUAAAV1AAAAAAp1AAAAAAAAAAATdQAAAAAAABR1AAAAAAAAAAAAABp1AAAbdSh1N3U4dTp1AAAAAAAAPXUAAAAAAAAAAD51QHUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQXUAAAAAAAAAAAAAR3VPdQAAAABRdQAAAAAAAAAAAAAAAAAAAAAAAAAAUnUAAFZ1AABXdQAAWHUAAAAAAAAAAAAAAABzdXR1AAAAAAAAdXUAAHh1AAAAAAAAeXUAAAAAAAAAAHt1AAAAAAAAAAAAAAAAf3UAAAAAgHUAAAAAAAAAAAAAgnUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhHWKdQAAAACLdQAAAAAAAAAAknWmdQAAp3UAAKl1snUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALN1tHW1dQAAAAAAAAAAAAAAALd1AAAAAAAAAAAAAAAAAAAAAAAAAAAAALh1AAAAALl1unUAAAAAAAC7dcJ1AAAAAAAAAAAAAMN1AAAAAMR1x3UAAAAAAADYdQAA3HXddQAAAAAAAAAAAAAAAAAAAADkdeV1AADwdQAAAAAAAAAAAAAAAAAA8nX0dQAAAAD3dQAAAAD6dQAAAAAAAAAA+3UAAAAAAAAAAAAAAAAAAAAAAAAAAAV2AAAAAAAACHYAAAAACXYAAAAAAAAKdgAAAAAAAAAAC3YAAAx2AAAOdhN2AAAAAAAAAAAAABd2AAAAABl2G3YAAAAAAAAAAB52AAAgdiN2JXYAACp2LHYAAAAAAAA9dgAAAAA/dkB2AAAAAAAARnZIdgAAAABKdgAATHYAAFZ2AAAAAAAAAABXdlh2AAAAAAAAAAAAAFp2W3ZedmB2YnYAAAAAAAAAAAAAAABsdm12AAAAAAAAbnYAAAAAAABvdgAAcHZydnZ2AAAAAAAAAAAAAHd2AAB8dox2jXYAAAAAlHYAAAAAAAAAAAAAAAAAAAAAlXYAAJZ2AACXdph2AAAAAJ12nnaqdgAAAAAAAAAAq3YAAAAArXYAALF2AAC0dr12AAAAAAAAwXYAAAAAAAAAAMN2AAAAAAAAAAAAAMR2AAAAAMV2AADGdsh2AADJdgAAynYAAAAAAADRdgAAAADSdtN2AADUdgAA2HYAAAAAAADbdt524HYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOF2AAAAAAAAAAAAAAAAAADkdgAA5XbmdgAA6XbqdgAAAAAAAO12AAAAAAAAAAD0dvh2+XYAAAAAAAD6dgAAAHcAAAAAAAAAAAAAAAADdwAABXcAAAAAAAAAAAAADXcAAAAAFHcAAAAAAAAAAAAAFXcAAAAAAAAAAAAAFncXdyF3IncAAAAAAAAAAAAAAAAAAAAAAAAAACl3AAAsdwAAAAAAAC13LncAADJ3NHcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO3cAADx3AAA9dwAAAAAAAAAASXcAAAAASncAAAAAAAAAAAAAWXcAAAAAW3dcd153X3dgdwAAAABhdwAAYncAAAAAAAAAAAAAAAAAAAAAY3dqd2t3AAB6d3t3AAAAAH53AAAAAIJ3AAAAAAAAAACTd5R3n3eqdwAAAACsd7B3v3fAdwAAwXcAAAAAwnfNdwAAzncAANR31ncAAAAAAAAAAAAAAAAAANd3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOd3AAAAAOp3AAAAAAAAAADsdwAAAAAAAAAA7XcAAO5373cAAAAAAAAAAPN3AAAAAAAA9XcAAAAA9nf/dwl4AAAAAAAAAAAAAAAAAAAAAAAAC3gAAAAADXgAAAAAAAAOeAAAAAAAAAAAAAAQeBF4AAAAAAAAFHgAAAAAAAAXeAAAGngAABt4HHgAAAAAH3ggeCF4AAAAAAAAIngAAAAAKHgAAAAAAAAAAAAAAAAAACt4AAAseAAAAAAueAAAMXgyeDN4Nng5eAAAAAA7eDx4PXgAAAAAAAAAAEZ4AAAAAAAASHgAAAAAAAAAAFp4AAAAAAAAAAAAAAAAAABceGN4AAAAAGd4aHgAAGl4AABreAAAAAAAAAAAAAAAAGx4AAAAAG54AAAAAAAAcngAAHN4AAB1eHZ4AAB9eAAAAAAAAAAAAAB+eH94AAAAAIF4AACDeAAAAAAAAAAAAACEeIp4AAAAAIt4AACReAAAAACSeAAAAACUeAAAAACVeAAAAAAAAKF4o3gAAAAAAAAAAAAAqXgAAKt4AAAAAAAAAACueAAAr3gAALF4AACyeAAAAAAAALh4ungAAL14AAAAAAAAAAAAAAAAvngAAAAAAADDeNV43ngAAAAAAAAAAN94AAAAAOF4AAAAAAAAAAAAAAAA4ngAAAAA43gAAAAA63jseAAAAADweAAAAADxePJ49ngAAAAA+Xj+eAAAAAAAAAB5AAAAAAF5AAACeQZ5AAAAAAAAAAAAAAAAAAASeRN5FnkAABh5AAAAABl5AAAAABt5HXkAAAAAHnkjeQAAAAAmeQAAKHkAAAAAAAAAACp5AAAAACx5L3kweTF5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADN5NHk1eQAAAAAAAAAAAAAAADh5AAAAAAAAAAAAAAAAAAAAAAAAAAAAADx5PXk+eQAAAAAAAEF5Q3lFeQAAR3kAAAAAAABIeQAASXkAAAAAAABNeU55T3kAAAAAV3kAAAAAAAAAAAAAWnkAAFx5X3kAAAAAAABgeWF5AAAAAAAAAABjeQAAAABkeQAAAAAAAGV5Z3kAAGh5AAAAAAAAAAAAAAAAAAAAAAAAAABveQAApnkAAKh5AAAAAKl5qnmreQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACteQAAr3mweQAAAAAAAAAAAAAAAAAAunnDecZ5x3kAAAAAAADIeQAAAAAAAAAAAAAAAAAAy3kAAAAAAADSeQAAAAAAANh523kAAAAA3HkAAAAAAAAAAAAAAAAAAAAA3nkAAAAAAAAAAAAA33kAAAAAAADleQAAAAAAAAAA63nveQAAAAAAAAAA/3kAAAB6AAAAAAAAAAAAAAAAAAAAAAAAAAABegR6FXoAABZ6AAAAAAAAAAAAAAAAF3oAAAAAGXoAAAAAAAAAAAAAAAAAAAAAAAAaeht6AAAAABx6AAAdegAAAAAAAAAAAAAeeh96AAAAACB6AAAiegAAI3oAAAAAAAAAAAAAMXoAADJ6AAA0egAAAAA1ejd6OHoAAAAAOnoAAAAAAAA8ej96AABDegAARHoAAAAAAAAAAAAARnoAAAAAAAAAAEd6AAAAAAAAAAAAAAAASHoAAAAAAAAAAAAASXpMek16U3oAAFV6AAAAAAAAAAAAAFt6AABcegAAAAAAAAAAAABdel96AAAAAGN6AAAAAAAAAAAAAGV6AAAAAAAAAAAAAGh6AAAAAGl6AAAAAAAAAAAAAAAAanoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABregAAAAAAAAAAAAAAAAAAbnoAAAAAAAAAAHF6AAAAAAAAAAAAAAAAAAAAAHN6AAAAAAAAAAAAAAAAdHoAAAAAdnp3egAAeHoAAAAAenoAAAAAAAAAAHt6AAAAAHx6AAAAAAAAAAAAAAAAAAAAAAAAAACDegAAjHoAAAAAjXoAAAAAAAAAAAAAAAAAAAAAAACQegAAnHoAAJ16AACgegAAqXoAAK16r3qwegAAsXoAAAAAAAAAAAAAAAC1erd6AAAAAAAAuHq6egAAAAAAAAAAAAAAAL56v3oAAAAAwHoAAMF6yHoAAAAAAAAAAAAAAAAAAAAAAADJegAAAAAAAAAAAAAAAAAAAADKegAAAAAAAAAAAAAAAMt6AAAAAAAAAADOegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANJ6AADUegAA2HoAAAAA23oAAAAAAAAAANx6AADleul6AAAAAOp6AAAAAOt6AAAAAOx6AAAAAAAA7XrxegAA9HoAAAAAAAAAAAF7AnsAAAAAAAAAAAAAAAAAAAR7BXsGewAAAAAAAAAADXsQexF7AAAAAAAAAAAAAAAAAAAAAAAAFXsAAAAAAAAAABZ7AAAAABd7AAAAABl7AAAAAAAAAAAAAAAAAAAAAAAAGnsAACJ7MHszezR7AAA1ewAAAAAAAAAAAAAAADp7QXtHewAAAAAAAEh7SXtKewAAAABMe097AABRewAAAAAAAFJ7AAAAAAAAAABTewAAAAAAAAAAAAAAAFR7Vntce117AAAAAF57YHthe2J7a3sAAGx7AAAAAAAAAABtewAAb3sAAHB7cXsAAAAAc3t0ewAAAAB4e3p7AAAAAAAAe3sAAH97AAAAAAAAAACAewAAAAAAAAAAAAAAAIF7AAAAAAAAAAAAAIJ7AAAAAAAAAAAAAAAAhXsAAAAAAAAAAAAAAAAAAAAAAACGe4l7AAAAAAAAAACLewAAmXsAAAAAmnsAAAAAm3sAAAAAAAAAAAAAAAAAAAAAAACcewAAnnsAAAAAAAAAAKB7AAAAAAAApHsAAAAAAACpewAAAAC8ewAAAAAAAAAAAAAAAAAAyXvLe8x7AADOewAAAAAAANB7AADWewAA13sAAAAAAAAIAOoDiAD3AwQAqwIECkUBigp9AAcLPAIJC1ACCwuoAgsLSgMLC5wDDAtkAQwLJgINCz0BDQtyAQ0L1QENC9cBDguNARILRQCSC5EAhgDxBIgLFgKGAJcFCwCKAIwAKAAEAJsABwCZBgQKzgKHCsAEBAD1AAUAlwAFAOUCBgB7BAcA8gEHAGYDBwAGBgwA1QAOACQADgCHAREAbwASAAYAEgAuABIAlwATACQAFAAgABQAOAAUAEUAFABmABUABAAWAAgAFgAKABYADgCWAB8ABABwAocA2AYFCnwABQqQAAYKJAIHCg8ABwqZAIkKdQIGAPcBCQBKAg0A1AEOAEIAEAA6AAcK+wUICqABCQoTAQoKZAALCpICCwrTAwwKVgAOCs8ADwoUAI8KGQAFAFsCBwC8BAkANQIOAC0BBQqTAwYK9wYHCtMABwpJBQkKUwAKCngBCgqvAQsKHwIMCpgCDQoYAQ0KrAEOCoAAEQo0AJEKUQAEAOwBhQDDAYcAQwONAEYAhAAbAgcL7AKLC7wCBwvtBQsLVQIOC0wADgtPAZQLIQAGAHEAhwC0AQQKUgGFCpABiADOAoULfwCFC6IBBgDhBQcACAIGC8YACwp8A4wLUwAECt0ABQqTAgUK3QMHCrkCBwq7BIoKHAGHAC4EBQsUAQYLNwCHC1kFhgDrBQYL2AaIC9YCigr7AQ8ATgAECrwAhwolAwUKdAOLCt8DhQv8AoYKdQYGCzUBBwtLAYoLJgKHC0UHhAtcAYcL2gOHCyUGDABiAg0ArwGQADsACQsfA4wKpgCGAPoFhADuAoQAMwGFAMQDBgvCAAcLhQAKC+0BCgs6AosLmAIFCxgABQs5AgYLAwAGC3cABguPAAYLuAEHCycBBwtXAgcLlgYHCz4HCAuoAQkLKwAJC0gCCQv4AgoLlAAKC0gBCwufAAsL/QALC/oBDAvnAQwLEwKQCyEAiAr4AgULDgAFC3wDBgsbAQcL6gCICxkChwvjBAQLfgAIC3sCkwsiAAQLPAGHCxkGBgDnAwYAHgWJC10DBAtAAAULYAEFC9ACBgtwAYsLZwEEAEsABQC0AAYA9AEHADoABwDGAgoAhQKICgIDhQCJAgYAFAEHABoBBwBvAwcAnAMIAMsBCQBXAgkA8gILAD4CDACAAAwA7gENADQADQAtAQ8AHgCPAIQAhADIAAQKWQAFCukBBgo7AQcKKQIHCtEGigrzAIcLGgQHAFUGBgp6BgkKAwAKCpoACwqBAg0KVQANCskAjQpaAQYLrwCJCyEBBQuwAYULkQMGAOEAiQDTAAcAzgIIAK8CiwB2AQQKpgCFCvkBCQBuAIYKhgYIADoACQDUAgsAKQMNAHEAkQBIAAYAWQEHAN8EkAtSAAULowOGC6IGCAD/AggAIwMJAC0BiQCHA4sAywCGAIIEBwCdB4gAogKGAAMBhwD7BAULBgMGC2UGBguWBoYL1waGAM8EBwq9AQgKMwEICsACCgopAAoKtwELCu0ACwpuAowKyQCIAP4ABgsEAYcLzAWLABUBhwq5BwQKvQAFCskCBgs9AogKOQCKCnMBhAooAoYLWAGFAPgACQAgAwoAtQILAOIBCwDeAgsAFQOGC/AABAB0AAUAXwAFAL0BBwCYBggAHQAJABABCwD9AQsAkwMECyQBBAvgAgULZwMGC6sABguZBgcLLAUHC5gHCQufAQkLRAIOC+YAkgtEAAcA6gENAGQAjwBLAIcAaQaFAB8CBwvRAAgLlQIKCyoACws6AAwLOgAMC3YAjQsgAAUAtQAIACkABgs/AIcLmAOFAJEChQsZA4oAxQIHABkACADKAIoAGAIFC5kChwr8BpEKMQAJAKcBjABZAAULQwAGCz4ABgt2AYcLbwUIAHEACQBtAwoAKgILAFMADACIABMAbQAJCxYDjAsvAIoKlQIEAMMDCgCfAw4AugGHCpkHhQDQA4QAzgAEC4cBhwuRBIYA0gcGALgChgDwA4YAkgSECw8BBwANAAgA4gAKABkCCwA6AgsAXQILAB8DCwAkAwwAVQAMAAQCDABvAg0AcAANAGkBDgBNAA4ATgARABwAEwBuAIwLOgGEAAEDhgAIBgQAJwKJAKYCBQpUAIYKowAJADkACQDLAQoAqQELAHcADAC4AAwAcwENAGYBkQAzAAUAvAAFAC4DCAAKAAkApQEJANkCCgBhAgsAsQIEC/0ABQqaAQULIAIHCywBiQtUAYYAcAKKC0EBhwCVBxIAggAFCkIBCAq6AAkKBgEKCrsAjgrQAAULNQAFCx0CBgteAAYL8wEHC+YAiwtBAYUK4wAEAHoBBAuYAwULGQAFCxYDBgvJAYcLVQOJAA0BhAAQAoYAegQHCnMFCArmAQkK7AAJCm4DCgraAAsKXwATChEAkwofAAcK+wcICqACjQrAAYYAUQSGAFAGhgvlBowLowAFCpwBhQs2A4QLegIGAJAChgvCBoYAlAcFAGgABgCtAIcAXwaICjICBgskAAcLkgIIC8YBkwtWAAUAyQGGCusGBwAqAwgAigAIAFYBCQBUAAoAwQALAHMDjABnAQkAbAKHCqYEiQqEAAcLzwOJCxUDBgBfAAYAjgeIAMcDjQtPAQYAlgEKAJkBCgC/AQsALACMAGQABAo9AYcK/wSEAN0BhgD0BAYAlQcIALADBQo/AIUK/QGEAHUChAtoAAQA9gCFAHcBBgBkBoQKIAGHC04GCQAxAAoABgMIClkACApsAgsKdAIMCkIBjwp8AAQAGgEHAAoECwCOAQsAegIMAAEADABPAAwAIAIOAO0AEQAKAJIAFACEADgDBwstAAkLHgIJCzYCigvYAgUAdgAFAPMBBgDcAQYAmQIGAJgEBgCsBAcAWAIHAHgDhwBIBAcAKAEHAFQCCAAwAggASgIJAGQCCwAwAQwALgANAFkADgBwAJEAegAFAH4DBgDsBgkA8QOKCngABQsVAgcL8wKKCwwDlwoBAAYAwgUHC1cAjgsgAYsAbgGJCs0BBwvcAwcLkwcJC0AACQv2AQwLBwAMCyIADQsMAA0L6gCTC00ABwA/BgcAuwYIAE8ACABqAAgAvgAIAC4BCAB/AQgAyQIJAHcACQDpAAkAowEJANcBCgC1AAoAlgELADkACwBVAAsAeAALALEACwAoAQsAfgELAMYBCwD2AgsA5wMMABsADABiAAwAgwAMAPUADAA4AQwAvgEMAMYBDQAZAA0AYgANAKoBDQD8AQ4ARgAOAKMADgAQAQ4AFQEOAHIBDwBfAA8AigAPAKcAEQAmAJQAYACHCkIFCgDIABMAAgCXABYAhwuNAIYKVQCGAN8GigB0AZEAEAAIAK8DhAtrAosLWAAFC/YACAu9AAkLYwEJCwACCgt8AAoLxQELC48ACwugAQsLWwONC1UBBQACAYYAzwIGAAYHBgAvBwgAhAMKAGoDCgB2AwwAugIMANwCDAACAxAAagASAKMAEgCqABIAqwCYABQACQDDAgsARgELAFMBDACnAQwA9gEUAD4ACQvDAgsLRgELC1MBDAunAQwL9gGUCz4ABQAeAAcA7wEIAIYACQAUA4wAtgGFC6YCBQoXAQYK6wAHCtQBCAq+AQkKfQIKCs0CCwriAowKAgIFCyMABgsfAQcLXgMHC14HiguzAAcAnAcHANQHhAsFAgUKEQAGCnMBiQoQAgQAcwAFAJ0CBgCXAQgANwELAAoAjQAFAIkAfQEFADIABgC3AQcADAOHABAEiAubAgsLkwGSC1MABQABAAYAUQCKAAgChgDiAgUA4gEIAGIACQCsAAoAaAEKALwCCgA2AwsALgELAAoDDAAyAAwAfwAMAIwBDQA+AA0ASAEOAHoAkwBIAAkLnQAKC4MAjAtIAIcLygKHCxsCBQACAAYAAAIHAB0DBwDWBQgA/QAIAE0CCQBNAAoAAQAKAIEACgDhAAsAdgALAOIACwD7AAsArgELAL0CCwDOAwsA1gMMAEAADAAEAQwA6AGMALICBQuKAQcLbwEHC+cBBwtZAwcLsQYIC/YACQsZAgoLpQAMC9sAjAsxAogALQIFCgsDBQonAwYKdwaGCowGBArEAAUKLgKFCrUDCws7AwwLOAAOCyIAjwuUAIkAWwGFADwChgBAAwQADAAHAPgBBwAKAgcAKQMIAB0DjQBYAAQK8AKFC8EBBwtWAAgLZwCRC0UABwvsB4oLgQIFABACBgsBAI4LAgCGAF0DCgAmAQQK4wAFCp8ABQqZAQcKUAAKCt8BDAqiAQ4KMgAOCvkAjgonAQcKvgUICkIACAqJAAgK+QIJCn4CCwpQAAsK1AALCnABCwqiAQwKCAANCg8AEAo9ABEKOwATChwAlApUABQAbQCHC3wEBgsVAQcL+gQHC2oFBwtwBQwLgQCSC1cABgu7AAcLJwAHC7MECAt8AQgLHgIOC3UAlQscAIYAowQFAAoBCQAiAQkAbAEKACUBCwBeAo4ALQAGCykBBwsZA4sLqgMEADIABgBSAgkAeQAKADEACgCcAYsAQgOIAOwCBwvQAQgLtgELC2kACwtrAQwL5wAOC4IBDwtmAJQLSwCEANIBDQCPAQ4AUQEGCiYABwrEBAgKuQAICgABCQoWAAkKSwEKCuICCwrNAAsKHAILCuoCDQrRAY4KwgAJAHoBjQCiAIkABwIECp8ABgpzAAcK/AAHCgEBBwqIBwgKRQAJCoABCgpbAAoKZwIMCncBDgrrABIKdQCTCnsABQtcAgUKjwOIChYBhACbAggAXwEJAEIBBAqXAIcKHwaGAIYDhQreAwwAtAAFCsIABwp+BokKWgAEAGUDhgDMB4YALQOFCqkBiQv5AoQABAGFCssDBQsUAAYLKgEHC5MCBwtWBYkL2wAEACcABQAkAAcAMwcIAJcBCwCQAIwACwIEAP4BCgBLAosK8AIHAB0ABwBCAAcAvAcKAOcBigApAw0ABAEOAFIAEgA/AIkKlgIFCkgABgoIAQcKFQAHCi4ABwrdBwgK1wAICgECCgoKAYsKFgCGADoCBgA1AgcAgwYEC7cBCgpfAAsKWwIMC/IADQq7AQ4KoACPCgQAhgC4BYYKrwEJAHQBDwACABMACgATABIABQpqAwYKjQaPCgAAhAATAwYAfAEMAI8BFQATAAcKqwMHCpQEBwqHBgkKHAIKCrgCCwoJAQsK3AILCqADCwqpA40KtgGJAMgAhAvpAIQABAKGC0EChABMAwsAdwMOAG0BjgB3AYQL4gEIADUDjAAsAAcAdwaIADEBBQqqAocKXweHC1oBhAq4AgQACgAHAJUDiwASAwULGwMGC80GCAuhAYkLDgMEAPgDhgDvBwUArAIECtYChQp2AgYA/QOGAMgFCAoiA4gKRgOGABsAhgCLAYcLbgIHC3EChwvWBgQLywCHC5AHBgp2AAcK1wAHCvEFjAoLAIQALQOIAP8BBwpnAooK+wCHChQEkQA4AIUK4QAGAFYBBgDwAQgAEwGJAM4ABACNA4UArAOEAHsDBws3AQkLNAGMC/8ABApyAQUK9AKHCi4FBACvAoYAPAaGAD4FBgp+BgcKMAAICgMDCgp0AA0KaAAOCmkADgq4AA8KqAATClwAlApEAIoK0QAEC5ABBQsLAYcL6ACXCwwABgApAI0AoACNCzoBhgC2BogACgOOCwUBhgBKBoUAcwCEACYBDgA6AYQKeACEANcDBQDBAIwAsgCKCq0BBQo0A4cKowMGAOIDBgAbBAYAnwUHAK4AhQvcAgQLZAAHC6cCCAs5AYoKxwAGCpcABgqLBgcKfwGXCgoABgAEBwgAUAMIAGMDCACLAwoAVwOMAL8CjADdAAQAegAFABwDBQC4AwYAfAYGAIcGCAA3AgkArwIJAOYCCgCuAgsAqgILAI0DjAAZAQULagEFC7sBBgs+AQcL+wOLC28CBQvPAYgLKAELAEcCDQAGAQYKWAYMCqYBjgpoAQUAswAHAEcEhwC9BAQKKwAEC8YBBQpYAYUKZQEEAEIABwDSAocAiAOGAAUDBwBgAYUKeAMFCzAABQuUAQYLLQIHC8oBCAtVAgoLxwEKC14CCwsxAAsLJAIMC9wBDQsSAI0LwgGGC6IBhArHAgULugGHC8AHjQAjAIkAmACGAK0EhwtFBIkLywCJCrgBCgBQAgoA8QIMAD0BDABjAQwA0QEMANUBDAAwAgwAQgKNAPMAhQA0AoYAHQMFCr4DhQrbAwULNwAHC3gBjAuhAIULwgGGACwChgAzAwsKFAGOCiUBBwAgAooAPQAIAM8CBApBAAUK3wEFCuwDBwp5BwgKPQEJCi4BCgpkAo0KFgAEAAUABQDyAQgAfQIJAAkCBAvVAAQKBQEHC98ABwr+AYgLUAAFAJ8DBwBlAAQKIwEHC30BBwsmAwcLNAMIC2IBCAu1AQgLEwMJCgMCCQuRAgoLOgAKC1MBCgvtAgsLkgMMCpgADAuiAAwKuwENC0sADQqIAQ4LagAOC8YADgtAAQ4KZQEOC50BkgsrAAYAgQQHAKEFiAvrAgQAfQMFAAwDhQB9A4oLjgKFC7QChQDuAIYLvwAECoIAhwpLAwYAEAUFCioABQpvAwcK9QAHCkQBBwr8BQsKzwELCtgBDQprAZAKNACGAMEGBgDPB4gAyQMECoYAhQp0AQQAPAAHAK0DBwAIBwgAOgEJALwCiwDnAYYAeAQGC6IABwuoB4gLPwOEC8IChwB7BIoLqgGKC1kABwA9B4oAtQGIAKMBhwpiBoUAPAMFACYDBwCwAAcAsgAHANgEBwC4B4QKhAKHC1UHBQukAYcLqQUEADMABQAnAAYABAAHAE8CBwBRAwcAtwMHAE0GBwDgBgcAxAcJALIBCgDyAgsAGQCLACUACgs5AIoLFQGHChwChAvMAIcAnwCLC+cAhQCGAwcAoAMHC24BCQsfAQwLxwAMCywCjAtBAgYKbwKIChUDBAqMAwUKZwEFCvwBBgq7BgcKVwEHCswHhwrqB4YADgEEClUBhwrgAQULZAGHC+AACwtMAgsLYAMLC8gDjwugAIQALAKJACEDhACgAY4AdAEFAJgABQDFAAcAVAEHAGMDCgAkAgoARQILAAYADAADAAwAEwAOAG4AjgAhAYsAcQEHC3YCCQs3AgsLlgALC7wBjQt3AIYLGwIHCssHCAorAQsKegOMCqICBwAiAAcAvgAIABwACACNAAgAvAEIACsDCQDUAQsATgEMABgADACCAYwAQAKFAPUCBwARBogAggOFANECiAD0AwQAFQMFAIcChwBOBIQAggMKALcABAruAAUK9wEGCrMABwrTBwgKfQEICtkBCQqVAAoKFAMPCi0ADwpWABQKbgCWCjkACQCIABMAawAECnkABQqcAAUKXQEKCl0CjgpWAQQL6wCHC/8ABAvCAAULSAIGC4ABBwtHAgoL+QILC/gCiwtTAwYKUAAGCp4GBwqtAAcKtgcJCiMCCgraAg4KEgCWCicABAqbA4YKrwYFABUBjQD3AIQAswGFCzIChgAfBQULvwCJCw8BhApTAgcLAQYOC2AAjwtJAAUAtQEHAPYBBwAHAgcAYgQHANcGDgDTAAYKywEHCtkGBwoNBwgKkgIJCgEACwq/A40KvgEGAC4DBAvWAQUL2QEGC5kABwvfBQcLgwcKC70CCwuEAAsLqAALC+MACwtAAQsLtAELCw0CCwtXAwwLKQAMCx4BDQtnAA0LHAEOC/8ADgsGAQ8LdQCPC38ABQAJAQYA1ACHABwAigDuAoULRwEGCygCBwvaBokLXAKGANwHhAC+AgULUAAGC5UBBwuTAQcL3gUHC1oGCAvIAQkL5wEJC1UDCQt5AwoLNQELC9ECCwviAwwLrgGNC6UABQAoA4cA/QcFAKYACADjAowA/wGGCuoBBAvFAQULdwMGCxcCCAsGAIgLHwIEAHcABQCqAAUAvwEHAKwGBwBhBwkAZQEJAM8CDADmAYwAVAKJAPQBBwr6AIgK+wGECp4ABgApA4YA3AUJAEcBCwBeAQsAPwMNAGABBAqMAAcKagEICtEACQoKAAkK9wEJCmYCCgqxAgsKRwELCtUCDAr8AAwKRwINCsAADgoNAQ4KZAGUCjIAhwvlAgQAwgEHAIYEEwoBABMKGgCWCgkABgBVAocAJgWGAEIGBgrkAAcKPQUJCpgBigpXAQcAXwUHALoFigBLAYQA8gKECi0CBQtlAAYLWAAGCx8CBwuNBgkLZAAKC6UCDgupAA4LLgEOCzkBDwswAI8LVACGAFgFBAs2AQkLGwMKC90CCwvDAQwL+QAOC3MADgseAY8LZACECiQCCgAtAgcKxQAICo4ACApFAQkKlgAJClQCCgphAQsKSgALCjsBDAqWAgwKqQIOCqcBjwqNAIULSwIFAFIDiAAfAwoAjAMMAL0CDAD1Ao4A0gEEAD4ABQATARIAEwAGCo8BBgpDAgcKtAIHCk4DBwr3AwcKBwcICpMBCQqKAQoKhQAMCgQADAopAQwKxAEQClEAEgoZABUKDgAWCgwAlwoSAAwAywEHCgoGCworAY4KlwGECrEAhAvyAQcL2QAIC4wAigtiAgUKmwGHCo0ChgAKBwcKtwEKCtcCCwoEAYsKrAKFC4kDCwtEAo4LyQCGAHUFBQrQAAcK8QKHCvgFBwDuAAcA8QcIAHgACAC8AAgAkwIJAFYCCgDSAQwAVgEMAEwCDQD3AQ4A9gCPAFwAhwsRBAQLyAEHC2kABwtmAQcLZQYIC4MCiwvjAQYAJgWGACwFBADJAAcA0AYIAFoCCwD3AAsAOgMRAEEAhQryAAgApACSAD4AhQq5A4sKIgOFAGcCBwseBggLDQEJC9QACQvOAg4LDwAOC4QAjgvjAIUKIgGECnwBBQo0AAcKFQEJCnABiwoXA4cA2wSFCxsCCwuXA40LmQGIAMgDhQvWAYYAcgOEAIsDBQBkAAoASQEMAKABlQAdAAoKigCLCtwBBQrVAgUK1wIGC1sABwuzAYcKEwcECxAABQs8AQULSgMGC3IBBgvyBggLpgALCywDDAvOAAwLXwEOC6IBEAsPABALIgASCwMAEwsDABMLBwAUCwQAlQsVAIQAsAAFAHwCBQDmAwcACQAHAOQFCAAaAAkAPQEJAGYBCgDSAAoAJAEKABUCCwArAgwADgIMAF8CDQAHAQ0AywGOAA8BBgAAAQgACQEECiYABwozAQcK5wMHCskFBwrEBgcKygYJCp4BCwo8AQwKNAANCqQBkwpkAIcKEAUEC2MChQteAgQAgwKOCxUAhQvLAoUK0wIGAGIChwtVAgoAfwCNABsABgDLBwYA0QcIAHcAiADNAwQLlQCKC3ABDAAKAgQLmgAFCm0ABgr4BgcLbgQHCmcHCAtpAAwKKAGMCi4BBAsfAAYLrQEHC8IDCQvKAYsLswIKACkCCwBsAw0AwQANAKcBDgCmABMAVAAECzgBBQrYAAcKVwcJCo0ACQoOAQkKpwIKCp8ACwrFAAwKGgIMCi8CDgqQAA4KpwCPCkMAhgAuBgcAKgaHCyoGiQpRAIQL7ACGCocBhgAbAwcKQgGICvkABQtEAwULWQMGC5AGBws7AJMLNQCHALABCgtEAIsL7gEEC1EAiwtjAwcAfgCIAFQAjgsYAQULGgEIC4oCCQsnAQkLiwOKC7sBiAAWAwUKeAKKCg4CBgBAAAwAeQENADUBDgCNAA4ArQEOC40AjgutAYYA+QUGAEEBBwBBBwkAEgITAGMABwq0AwcKEgQICusACArNAQkKxQEKCmIBkQpNAAcAUAQLAA0BCwAbAgsAcwILAMICCwDPAwwA+AAMALIBDABYAgwAbgINACkBDQDlAQ4ARQAOAJkBjwBsAAQKagEHCjQABwovAQoLRgAMCxoADgsRAA4LsgAPCyIAlQsMAAsA0QONAPsBCQAiAIsA5AEFCsQABgrmAQcK1AAICjUBiApaAQYApAYHABoABwAlAQcAfgEHAAIEBwA/BAcA6wcIABgACAByAAgA/AAIANcCCADZAgkAHgAJAMcACQDnAAkA+wAJAE4BCQBpAQkAyAIKADcACgA8AAoA6AAKAEwBCgCAAQoAjAEKAPgBCgAeAgoAjAILABQACwAwAAsAzwALACMBCwAqAQsAVgELAG0BCwCKAQsAbAILAMECCwD5AwwAewAMAFQBDACWAQwAgwINAD0ADQANAQ0ANwENAD8BDQDmAQ4A6gAPAD4ADwBVABAARwASAHcAFABpAIcKeAcEC0cABQt4AQcLdwCKC5kCCgCWAwoAngMECq4CiAs3AIoKcQKICsIChAvfAQQKHgCFCisABgB7AQcADgEIALAACAC3AAkAsAEJAJUCDAD3AAwAaQISAH0ABwtfAggLYwCYCwQABQAYA4UAhAMEC2QChQsxAgQLKQAECtwABQtKAAcK/wUHC1sGCwtnA4wLawKHAIAHBwteAAsLSQELC8UDDAvxAA4LYgEPCxYAlAs/AAkL0QCJCywBhgADA4cAuwcEAIUDhQAIA44A/gCFC2IACQsQAI0LggGFC9gDBAu2AAYLzQCHC9wABwq9BgcK7gaKCokBBQoHAYYKngEECyoACQvNAAkLEgOKC5MCDgCMAJQAKQAIALgBCgBnAQYKsgAGCyEBBgrWBgcLhgYJCrICCgqbAAoKdQELCroCDAs5AA0KmwAUCl0AlwsEAAQAJQAFAE4BBwDlBJcLGQAEAPwBBAt7AgUKYQCJCokBiwsVAgQAgAKFAAEChgpnBoQLcwEECxABBwtEAwcLcwaRC1kABQs5AwYLvAEGC2gGiAs0AQQKvwAHCqYDCAqHApEKYQAMAPYADwCiABMAQAAUAAgAFABfABYAGACYABEABAAVAgUKpQAJCloBigqPAgUL4QKLCnUDhQptAwgKgACLCrMAiQszAYwA8AKFAJgDhwAYBAUAmQAGAEQCBgp/BgcKhAAHCoIEBwqHBQcK4wUMCu0BDwppAJcKDwAFCssBBwoxBAgK8QCICk4BigCHAYcAoAeFCw0CCAuBAgsLhAGMC0QCjgB+AIYAgAKEAOMBBwBQBgkARQAGCkQBBgoIAgcKUgEHCsEGCArkAIsK7gIFC+0BhgsQAocA3gIEC64AhwuPA4oA4AEJAO8BkgBoAIcKwQIJANgBBApJAAYKZAIHCp8DBwoyBQcKHgcICtkACQr9AgkK/gIKCpgBCwozAAsKGQMMCgoBDwqeABQKWQCWCiAABwskAokLOgAECyAABQvXAAYLDQEHC/YGBwtkBwoLEAALCzYDCwu6A40L4QGEAGoDCQDlAAUKhQGICnwCBwvVBogL3QGGALQDBQs0AYcLQAQEAOwCiwDxA4gKFQAGACsChwDlAQULfgAICykBCQtuAQkLvQEMCzUADAt2AY0L7AEHCw8GiwtpAYgAwQCIANgBCACNAg0AXQCTAA4AhADYA4QLrwAFAKwABgCzB4QLrQKVCwgAhQsdAw0AUwAFCr0ABwq6AQcKuwEIChkBDAquAI0KBQGGACAGhQs1AosAgAGFAAQBBwD2AgcAcAMHAE8FCQCkAAkApwAKAJwACgBMAgwAZQAOADAADwBGAAYKAgAHCu4EBwrJBggKFgAICg4BCApkAgkKOAEJCrQBCgo3AQoKbwILCkgACwpKAQsKxwEMCkEBDAr4AQwKEgIMCh8CDQoRAA0KnAANCk4BEQo8AJQKQAAEC/wABwssBAoLsgELC+QACwuqAQ0L5wASC2oAlAtXAAcKYgEKCpoBiwovAwYAbwEHCp4CBwovBQgKmwEICrMBCQqNAgkK5AIKCoEBCwreAAsKRAELCj0DjApjAgcAlgQGCqYAhwp2AZIAeQCEADwDBQvnAIoL/QEHC1kCCQsVAQkLogIKC7IACgsBAQoLogELCxMCCwsgAgsLSQIMC3EADAvbAQ0L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/wAGCmYABwpIAA8KjgCTCkMAlwoeAIcKNwOHAPIEhwvSBocKTgcEAJABBQALAYcA6AAHCxgACwseAosLVAOHC8sGBAv3AYcLfQYFC4IABwsiBQkLYgIKC84CCwtZAgsLMwMLC7IDjAsYAgoLlQALCxgBjgtQAQcA4wILALICBwuaBwgKMAAIClgACApGAggKqQIJCnUBCQpgAwsKnQALCksDlAobAIYA3gMEClgABQqJAAUKrgAFCgkDBgqABgYKvQYHCk0ABwqqAQcKJQUHCksFCAp+AAgKMwIJCgsCCQruAgoKNgEKCkQDCwoqAAsKPgELCtsCDApEAAwKXAAMCvsBDAq0Ag0KUQANCu4ADQp2AQ4KtAESCooAEwpOABMKbwAUCjcAFApNAJQKXACNCqIBBwAnB4QKqgMGAAgDhgCTA4oKXwEFC1wBBgsKAgYKhAYHCtsFCAp1AAkKOgGKCq4AhwrDAoQAZQKFCpMBhAuIAQULsQEJC3kCiwt1AoUA+wKEAG4DhADRA4QAZAAGAM8BBAosAAUKNwEHCn8CBwr6AgcKIwcJCggACQrOAZQKUwCGC+oABApaAQcKcwAJCrQACQrIAYoKawEFAGoBBQC7AQYAPgEHAPsDiwBvAgUAzwEIACgBBwuMAAcLngcIC6gCCwsxA5MLWAAHC8YEiguCAY4AiQCEAMYBBwB6BwYLBQAHChsECQohAgsL+QAMCzkBEAtCAJELGgCHAPcFkQA6AJQLOwAFADAABQCUAQYALQIHAMoBCABVAgoAxwEKAF4CCwAxAAsAJAIMANwBDQASAI0AwgEFC8MDhgvtBoUA2QKKC0oCBQC6AYcAwAeGAMEBkAAoAAQAVQMHC7QACAv9AYgLGAMGCrkABwprBwkKawOLCqEChgsMAgwA4wAECkcBBQreAQcKNAWICvECBgDTBQUK/AOFCv4DBApnAIUKkQGEC6MDBArzAYcKjQUFADcABwB4AYwAoQCFAMIBBgCWBIYAGgYKAD4ADQCQAYcLLQeMAM8AhwBlAwQLBQMFC2oCiQv0AoQKYAAEANUABwDfAAgAUACHCsgDBAtaAAULUQEFCyECBwvyAgkLugAKC0gACgsOAwsLAQILC0ECCwtiAgsLeQMLC8EDDAtiAQwLagEMC80BDAtTAg0LTwCPC3kABwB9AQcAJgMHADQDCABiAQgA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KgILClMADAqIAJMKbQCFCtADBwDqAoQKzgCIAA4CiwBZAYgA+QMIC5gACQs1AAkLDAEJC4UDCgsGAgoLPQMLC7wADQtKAA4LLgAPCxEADwshABELKAASCyQAEwsUABYLAQCYCwIAhQvgAogLFAIFAKwBigCLAocLqQKHAIoEBwBHAQ0A5gARAHEACAriAAoKGQILCjoCCwpdAgsKHwMLCiQDDApVAAwKBAIMCm8CDAulAg0KaQEOCk0ADgpOAJMKbgAEABgDBwC1BgoAIgKECgEDBAusAogLgAGECicChgCzBAkKOQAJCssBCgqpAQsKdwAMCrgADApzAQ0KZgGRCjMABQCgAgUKLgMICgoACQqlAQkK2QIKCmECiwqxAooAvQCGCnACBwtuAAcLvAAICyIBCAtPAgkLfgEJC4kCCwtHAAsLmwALCzkBDAsFAA0LRQGOCx8BhQBjAAYAHQSHACoBBwtoAQcLqQEJC0IACQsWAYoLhAIEAI0BiAArAokKDQGEChACBAuEA4ULXQMGAIUEBQv+AAcL2QOIC0kABwunB4gLqwIMAI4BFAAnABUACwCWACkABADlAQcAYQGHAPMFBgBuAQcAaAWHAEEGigATA4kAGgEFCmgABgqtAIcKXwaLC5IABACdAIUA1wGGAK0DhAvVAgcAOAUICooACApWAQkKVAAKCsEACwpzA4wKZwGGC8QAiAB0AIULPwOGABMDhgpfAAYKlgEKCpkBCgq/AQsKLACMCmQABQCgAAcAawEHAE0CCgCqAI0ANwCGABcHhABiAwYAeQMGACsEBgCfBAQLQQGGCzkCBQtQA4YLQgAECyQABgpkBgcLawUKC80ACwvzAo0LDwGEALECCQA0AwQKGgEHCgoECwqOAQsKegIMCgEADApPAAwKIAIOCu0AEQoKAJIKFAAEAGwABwAkA4sA8gGEC3cDBgBfBIcLbAIGC6UAiguEAQUA9AAFCvMBBgrcAQcKWAIHCngDhwpIBIwAYQKHAO0DBACcAYUARQIEC88ChwubAAcKKAEHClQCCAowAggKSgIJCmQCCwowAQwKLgANClkADgpwAJEKegAEAH8DhQAEA44LMwGHAGoHBACeA4UA1wMEC2EBBguSAAYL/QYHCyABBwveAwcLRAUJC5kCCQuCAwsLfQOOC9QAhAAaAoULFAIGACYBBwDzBAgA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uwEGCj4BBwr7A4sKbwIFCs8BiAooAQQKxgEFC7YDBQviA4YLXwGKAIkABQowAAUKlAEGCi0CBwrKAQgKVQIKCscBCgpeAgsKMQALCiQCDArcAQ0KEgCNCsIBhQCeAYcA4gYFC6UBhwsvAAUKugGHCsAHhgBXAoYA1QaGAFsGBADoAYQLXgGJC+8ChABTAIwApAKFC8cDBwBnBgUKNwCMCqEABAvZAQcLbwIICygDCQtnAwkLfQMLCyYACwuvAQwLcAAMC9kADAvzAAwLMgIMC6sCDQuNAA0LxQANC+MADQuWAQ0L5wEOC5wADgvLAA4L4AAOCwABEgs6AJYLAACFCsIBBwvgAosLCAGGABYBBAveAAcLHgGIC3UChwplA4wAYQCQAA4AhgA9BAQK1QAHCt8AiApQAAcAhAEHAIQCiwANA4QAUQMHAOUACAA7AAkAvgAKAHoBjAC/AAcKfQEHCiYDBwo0AwgKYgEICrUBCAoTAwkKkQIKCjoACgpTAQoK7QILCpIDDAqiAA0KSwAOCmoADgrGAA4KQAEOCp0BkgorAI0LMgGICusChgBbBBAAXgAQAGwAiAuSAAYAvAIGADEDhgDqA4UKtAIEC9EBhwt/BoYKvwAGAIYFhwuRA4QAlAIHAAsEigDhAgYKogAHCqgHiAo/A4QKwgIHALICCQDZAAkASwKMAAkCigqqAYcK0wQGC1IABwuKAAcLBQIJC6ECiwvuAIoAEAEFC+8BBwtCAwkL3QKLC3oBhgDQBoQA8wMHCzwDjgt0AAQA3QIJAMIACgBcAAsAxgAMAFQADQCAAIULLwIKADkACgAVAQYLFQAGC8kGBwukBYgL4AAECswAiQqGA4gKQQMLAFwBDABjABIAAQASAAsAEwAEAAcKbgEJCh8BDArHAAwKLAKMCkECBgC9B4gAqAMVACEAlgAoAAULBwKKC8wABQpkAYcK4ACGAAcDhwAyAQcKdgIJCjcCCwqWAAsKvAGNCncABQDTA4YKGwKFAGMCBAuSAYcLjwYFALIABwsCAAgLQwGIC98BBQs7AIcLoAIEAPIDBgCxB4oL7QCFC5wBkgsiAAcLzAaSCzAAhgCYAosKLgMEC1UAhwslAoULXgCFC8kBhACGAYYA5gUECusAhwr/AAQKwgAFCkgCBgsLAAYKgAEHC7sABwpHAgoK+QILCvgCiwpTAwQLCgKLCyIDhwDtAQoLCAMNC1kBjgupAZIAJQAECzQAhwuVAoYA1AKGAD0DhQsIAoUKMgIECxkBBQsmAAcLwgAHC5wCBwtlB4kLjQEFCr8AiQoPAQcAAQYOAGAAjwBJAAUA2QELAKgABArWAQYKmQAHCt8FBwqDBwoKvQILCoQACwrjAAsKQAELCrQBCwoNAgsKVwMMCikADAoeAQ0KZwANChwBDgr/AA4KBgEPCnUAjwp/AIUAaQAFALYBCQC2AgwAcwKNANIAhQpHAQYKKAIHCtoGiQpcAoYA6ASYAAsABQvAAQsLYgCLCwwCBwBaBgUKUAAGCpUBBwqTAQcK3gUICsgBCQrnAQkKVQMJCnkDCgo1AQsK0QILCuIDDAquAQ0KpQAOCxAAkgssAIQACwMIABkAigA6AwQKxQEFCncDBgoXAggKBgAICh8CiAo6A4kLzQGMC3gChAA0AYcA5QKEAJ8CBwCWAAgAiQKIAPwDCQBjAAYLUAEICygCCQsdAQoLYwCLCzgChgAJAgUAUwEOAAMADwApAA8ApgCTAEIABgunAQcLmQIHC7oECQvaAI0L3gAGAB8CBQplAAULAAEGClgABwqNBgkKZAAKCqUCDgqpAA4KLgEOCjkBDwowAI8KVAAECjYBBwrEAgcK5AMJChsDCgqGAQoK3QILCsMBDAr5AA4KcwAOCh4BjwpkAIUKSwINC6EBDguBAI8LDwCGAE4FiAsqAoQK8gEHCtkACAqMAIoKYgKHC90Dhwt6AgYAmwCMAOoAhwvOAYQLagKGAFwGhAD+AgQLUwEFCokDhwsDAYcAPQMEC/cCjQupAAcApQUECsgBBwpmAQcKZQYICoMCiwrjAQUA5gGHAEUFBQuwAocLyAIHAGMGCAARAAoA2QAKACcBDAACAIwLAgCKAC4Clgo4AAQLFgEFC9EBhwtXBYgL4gGFChcCBgBSBQYAtQUKCxIBCgtxAosLEgIFAFcCBQtQAQYLVQEGC94BBgvjBogLggEHCtQGiQuXAIYAYAWFChsChwtJAIcLsweLCxsBCQBdAIsA2gEGClsAhwqzAQYAvwEFC4wBhgv1AQQKEAAFCjwBBQpKAwYKcgEGCvIGCAqmAAsKLAMMCs4ADApfAQ4KogEQCg8AEAoiABIKAwATCgMAEwoHABQKBACVChUABwBBAgcAmAUJANsBCQD5AQkA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TgEMALoBDgACAQ4AbgGPAIMAiQA0AAQLLwAGC3UBBwvEAQcLHwIHC7IGBwtABwkLBgALCwEBiwuHAQQKCAAHCoAEBwqBBAcKswYJCnYBCgreAYsKiAIECxEDhQtwAYcKSwSHC1wDBQvUA4YL2gaGAOoEBgAiBAYATwUHCxgCBwszBYgLjwAEAJAChwALA4gKVwAFCxMABgsVApILfgAHAJAAigq2AQULiwEFC7cDhgvwBocAXQUHACoCBwBdAo0ACgAECkUABQp6AAkKkAKKCtABBQpRA4YKYQYFAEYDBQBJA4YAcQaFAPQDiwrzAQcK3AEHCjgGigpXAAYA+wAHAG0BBwBNBQcA2QUIAJoAjQAZAYQLuQGEC7cCBwvxAQkLgwGTC1EAhQBUAQ4KGwGOCxsBhgAqA4cLZgeLAO8BBQscAQYLMQAGC14BBwsBAAcLeQEHC50GCAsSAAgLpgIJC6EACQtJAgkLnwIJC0cDCwuQA40LqwEFClsDBwqIBAgKawAJCiMBCQq3AQoKlwILCmECjArFAAgABQEJAJAACQDSAQoAcgEMANYBDQCQAI4AXAGJAIEDBgD4AAkAIgIKABcCCwCpAo0AhwAEAGYBhwDYBYYANwKIAL0BBAp1AAYKdAEHCnEHjgpDAQQK0gKLCtcBBgC5AoYA5AMHC9cHCQtlAAkLwgEKC0IACgtKAwsLGAKMC0sChABBAoYAOAUJCgUADArYAAwKJgEMCioBDAqQAQwKBgINCuUAjwqLAAYArgCKAJUDhgruBgUKDAAHCncBCQpYAAkKtgELCz4AiwoOAYYL5gYGCwAABwtUAAcKMAMHCtkECQobAQkKCAIKCtUACgozAQoKzwEKCp8CCgrqAgsKkQELChoDCwt/AwwKBQIRCwsAEgprAJMKcwAFAG4DhQDMAwYLgQYHCwABBwtsBYoL8wEECgIBiAp/AgQLFgAFCwoABgoWAAcLUAMHCocDBwqrBwgLYQCKCkECBQqpAogKDgOFC+EBhABfAQQKmAIFCiQDiwr1AwYLhgAHC7UBBwu/AwkLJQAOCx0BDgtzAZALPAAHC+YBCAubAAsLXQCMC6QAhAAeAQcAtgEHAHMCBwDsBQgAKAAJADgACQAmAQoAHgALAMkDCwDjA5IAlAAFC08ChwtRAYYAngeFCiAAigv0AQULfAEFC4oCiAs2AQQL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aQAFANoBBwD7AQQK0QAHC/sBhwqGA4QAqwEGAJ0BBwpPAQcKnQUHCoQGCAopAggKjAIICpACCQouAgsK5wKVChIAhADaAgYLEwAHC4UFiwusAYUAdQGECi8CBwtgAAgLkQGJC4ADBwAfAwcAtAcFCvkDigr/AYcAAQcHC6kHBwutBwgLvgKIC+4CCAuWAAgL4QKMC24BhABCAYUKxQIICyADCQuUAAkLaAMJC3oDCws1AQsL6QMNCwsBjQtDAYYK0QYHACIBiArOAAcAcwaRAFkAiwACAIQAoAIGAEQHCACJAwoATAMKAE4DCgBaAwwAuwIMAOoCjAAEA4cLqAGFCyMChQDhAgUL6gEGC2cCBgtsAocLqwIGAOoChgBMBoQKCAMJC4EBlQsRAIUAkQCHCvgEBwB0A4wAfAAEAIMBhwAIBQULhQCICpYBiAu7AAYApwIICwgAigsAAIcAJgKHCx4DiAutAgcLPgSRCy4ACAqvAAoKqACKCj0ChwAZBQQAQAKHAO8EBgCuAoYAGwaGAF8CBQCXA4YAiQaUACUACAsGAwoLngKMCzMAhQoQA4sKcgMEAFIABQBNAQUAiAMGAM8ABwBFAQcAvgYIAGUACgAKA4sA3ACHC3MBhAC+A4UAhwMEC38ABQteAQYLZAEIC6oBCQs8AgoL9wCLCzgBjACTAAYLOwAHC3UDCQtbAo0LjQEKAG8BCQoOAAkKuQGLCgkACwrGAwwKHwENClYBDQqSAQ8KbgCPCqMAhgCyAoQAwQIJAIsCCwDLAw0AEQEHCpQFBwpoBgcKSwcJCqkACQq2AAkKbwEJCt4BCQr6AQkKJwIJCi0CCQqIAgkKuQIJCsECCQrVAgkKEwMJChoDCgrGAAoK1gAKCgsBCgoTAQoKyAEKCicCCgoxAgoKZQIKCnMCCgqcAgoKowIKCrMCCgq3AgoKwwIKCssCCwq3AAsKyQALCgYBCwpgAQsKtwELCu0BCwo8AgsKTwILCmACCwpjAgsKhgILCqICCwrHAgsK7wILCvkCCwoIAwsKEQMLClIDCwpVAwsKXgMLCmEDCwpkAwsKawMLCoIDCwqGAwsKhwMLCo4DCwqkAwsKrgMLCr0DCwrHAwsKzAMMCpQADArDAAwK3AAMCu0ADAo+AQwKUwEMCokBDAq9AQwKwgEMCtoBDAr5AQwK/QEMChUCDApPAgwKUgIMClUCDAptAgwKeQIMCoICDQo7AA0KPAANCpEADQrvAA0K+gANCkkBDQpYAQ0KbQENCnQBDQqDAQ0KkwENCp4BDQrIAQ0K1gENCt4BDQrjAQ0K6QEOCjcADgo5AA4KUQAOCloADgqUAA4K7wAOCgoBDgpBAQ4KRgEOCkcBDgpKAQ4KWwEOCmMBDgqRAQ4KlAEOCpsBDgqeAQ4KoAEOCqQBDwo9AA8KSgAPClcADwpYAA8KXgAPCmAADwp0AA8KlQAPCpoAEAoyABAKPwAQCkkAEQoCABEKQgARClwAEQpnABEKcAARCngAEgoyABIKNgASClIAEgpWABIKWgASCm8AEgpzABIKnAATCigAEwpPABQKTgCVChYABwB3AwUKoQCHCkcDjgtiAIYAWgCKC2QBhwu5AQYLbwAHCwQACAujAAgLCAOKCzYChgCMA4YA7QQHAC0DDADxAY0AOACGANMEhwCtAYcLygeKAIgDBgB9AAcA/QSJAAQDlwAMAAQASQMFAIIBhQuCAQULKQGHCw4EBgBcAwYALQSHCzUBiACyA4cKFgeNC6IBiAtrAQoAAAOLABMDFgseAJYLIQAGAKAABwBSBAkAAgMLAHAAjACdAQsL2ACLC1QBiAqLAIcLbgWHCygDhAsYAQwADwERAG0ABwqDAogK7ACMCzYABAulAYULJAILAM8CDAAkAI0AUQEHAEUCCQCEAokAuwILC/8BDQuKAQ4LKgEOCz4BkgtnAAcAMAEJAIYCCQBeAwsAuAIMANAADwBPAJMAbAAEAHcCBwBmBIcAAAaHC/cFCABwAwoAZQOKAJEDBwDpBQUKNgAGC/4ACQttAIoLZwCHANUDhQvZAoQK6AKEALIBhgAmAgcAogMKANwBDQDEARMAaAAGC14GCgqSAZIKNwAFACkCigA4A4gAxAEIAJcAiQpwAoQKPAKEAAQDhQufAoUAJAGKAIcAhAt5A4wLzwAJAPgBBgorAAcKJgAICvgAigoBAgYAQQSHC3YHBAtzAoULBwOHAA8DhQr+AoUKawEHAIMBhwuDAQcAiQEKAFsCCwDOAAcLygALC2oBCwu0A4wLhAEGC/sBBwvDAQgLhQEMC+oBDQsQAA0L1wANC18BEguEAJMLfQAEAJADCQDoAIcLSQMGCgIBjAqZAQUK+QCUClIAiAs2AgYA0QOHC74EBwC1B4gA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SgAJAG8CDAD0AYwAQwKQAEEAigv2AAYA3AAHAE0EDQBpAI4LOgEFCuoDiArpAoYAwAMUAAAAlAsAAAQA7QMECu8ABgrdAQcKRwYLCkQAiwppAgYAEwAHAIUFiwCsAZUKDQAHAGAACACRAQgAvwIJAIADiAssAYYAOwaRAHQAiAD9AwcAqQcHAK0HBwDuBwgAlgAIAL4CCADhAggA7gKMAG4BCwtLAI4LCwGECm8BCAAgAwkAlAAJAGgDCQB6AwsANQELAOkDDQALAQ0AQwEFC6sBBQveAgcL3gGICzQABwvvAAsL2QCOC6UAhAtDAYwLowENACsBjgBLAAYLVwAGC8YGBwsUAAcLIAQIC9wCCQuWAQkLjwOKC7YChgBnBYQKtgKFC2UCiQALAwQAVgKMCq8CBgDKA4cAqAGFACMCBwsgAAcL2AMIC1UACAvFAgkLQwIJC08DCQtYAwoLHwMLCwIBCwvvAwwLSwEMC2cCDQu8AA0LswEOCwgADwulABALGwCUCygABgDGBIYAaQWEAGwDiguXAIcK1QAEC6cAhwtSAIUAhQAGCxgABwtKAAcLpgKJCwIBBQs+AAYLFgIHC6wCBwsTBAcLMAQICxgBCAsdAggLrgIKCwcCCwv8AIwLGgGIALsACAAIAAoAAAAKADIDiwDcA4QLZwELAK0BDwAzAIcKiAaIAK0CBQvTAAcLWACIC3MChgDYAYgAhAAGC5EAjQtQAQQK7wILCoYBjAogAAYAqgMGACQEBAsHAQQKmQGFCk4AiQBqAwgABgMKAJ4CDAAzAAQLlAMGCtkBBwpCBgoKugIMCtQADQozAZEKaQCSAFwAjwqcAIQAPgOJAL0CBAtXAgYLYgYHCwUABws3AAcLQwAHC2EABwuzAgcL0wMHC6EGCAvPAAgL1gAIC+cACAsmAQgLUAEIC6wBCAvDAQgLzAEIC9cBCAtuAggLcgIIC6cCCAv3AggLPQMJCwsACQv2AAkL5AEJCz0CCQvCAgkL+gIJCx4DCQtXAwkLZgMJC5ADCgsvAQoLTwEKC6gBCgvNAQoLHwIKC/cCCgsuAwsLOwALC8cACwvrAAsL2wELC04CCwuhAwsLwwMMC3IADAu2AAwL4gAMC0wBDAu3AQwLPwIMC1YCDQsIAA0LfQANC8IADQsfAQ4LxQAOC38BDws1ABELPwATCy4AEwtiABML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hwUHAOMFDADtAQ8AaQCXAA8ABQDLAQcAMQQIAPEAiABOAYULOgOFCmwABQrbAAoLhAALC78ACwtmAYsLzAEGAEQBBgAIAgcAUgEHAMEGCADkAIsA7gIVAB4AFgA1AAQKwQAFCpQDBwpsAQoKjgEKCtYCCwo9AQsKcgIMCo4ADAogAQwKpgINCjkBDwpxAJIKcgAGC24AhwuRBocAjgMGCvEABwqLAwgKQAMJClYBCgrZAgsKHAELCr0BCwqLAgsKXwMNCo4BkgpjAAcAwQIJAN4CBQvoAwcL3QKJC0cCBABJAAYAZAIHAJ8DBwAeBwgA2QAJAP0CCQD+AgoAmAELADMACwAZAwwACgEPAJ4AFABZAJYAIAAHADIFBAspAQYLEQIHC5gABwvJAgcLNQcIC8YCCAvNAowLfwIFAIUBiAB8AoYAgQUECjICCQr+AIsKbwOGAH0DhAoSAwQLCAKHCz8CiAAVAIwA0QKIAL8DBwuUBQcLaAYJC6kACQu2AAkLbwEJC94BCQv6AQkLJwIJC4gCCQuLAgkLuQIJC8ECCQvVAgkLEwMJCxoDCgvGAAoL1gAKCwsBCgsTAQoLyAEKCycCCgsxAgoLZQIKC3MCCgucAgoLowIKC7MCCgu3AgoLwwIKC8sCCwu3AAsLyQALC/QACwsGAQsLYAELC7cBCwvtAQsLPAILC08CCwtgAgsLYwILC4YCCwuiAgsLxwILC+8CCwv5AgsLCAMLCxEDCwtSAwsLVQMLC14DCwthAwsLZAMLC4IDCwuGAwsLhwMLC44DCwukAwsLrgMLC70DCwvHAwsLzAMMC5QADAvDAAwL3AAMC+0ADAs+AQwLUwEMC4kBDAu9AQwLwgEMC9oBDAv9AQwLFQIMC08CDAtSAgwLVQIMC20CDAt5AgwLggINCzsADQs8AA0LkQANC+8ADQv6AA0LEQENC0kBDQtYAQ0LbQENC3QBDQuDAQ0LkwENC54BDQvIAQ0L3gENC+MBDQvpAQ4LNwAOCzkADgtRAA4LWgAOC5QADgvvAA4LCgEOC0EBDgtGAQ4LRwEOC0oBDgtbAQ4LYwEOC5EBDgubAQ4LngEOC6ABDgukAQ8LPQAPC0oADwtXAA8LWAAPC14ADwtgAA8LdAAPC5UADwuaABALMgAQCz8AEAtJABELAgARC0IAEQtcABELZwARC3AAEgsyABIL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igKHCh4FhgDtAocL2wSHAFMFBgB9AQcAhQIHALYCCAAiAgcKNAQJClAACwpOAAsKpQELChYCjAohAoYLZAaHC0AFDAAVAQcKEgELCt8Biwr7AQYAwQIGAA8DBgD7BAYAyQUECxoBBwsKBAsLjgELC3oCDAsBAAwLTwAMCyACDgvtABELCgCSCxQAhgDFAQQAKwIIABgCCgAgAQsA7QMECvEBhwowBgULdgAFC/MBBgvcAQcLWAIHC3gDhwtIBIoA2wMHAFMEBwoFAQcKWwQHCkoFBwo0BgcKqQYHCm4HCQrRAQoK+AAKCl0BCgqHAgsKDwILCpQCCwqdAgwKEQKNCjEBBwsoAQcLVAIICzACCAtKAgkLZAILC2QACwswAQwLLgANC1kADgtwAJELegAJAHIBigBaAIgKDQCEAFwDBwqCAggK+gALCnsACwqJAA0KMACOCl8AhwqVBYkLQQGEAAEBhwDvBwcA6AYHCz8GBwu7BggLTwAIC2oACAu+AAgLLgEIC38BCQt3AAkL6QAJCyoBCQujAQkL1wEKC7UACguWAQsLOQALC1UACwt4AAsLsQALCygBCwt+AQsLxgELC/YCCwvnAwwLGwAMC2IADAuDAAwL9QAMCzgBDAu+AQwLxgENCxkADQtiAA0LqgENC/wBDgsGAA4LowAOCxABDgsVAQ4LcgEPC18ADwuKAA8LpwARCxIAEQsmABQLYACVCyAABQvSAoYL3waRCxAABgAvBIYAGQYKCiECjAotAQYAUwAGAMUGhwBtBQQAQwOHABoHhQsCAQQKiAOFChoDhgDWBwULHgAHC+8BCAuGAAkLFAOMC7YBhwvUB4kAuAIFCzIABgu3AQcLDAOHCxAEBwsEAwcLUAQHC28GCwsNAQsLGwILC18CCwtzAgsLwgILC88DDAv4AAwLNwEMC7IBDAtYAgwLbgINCykBDQtvAQ0L5QEOC0UADguZAY8LbAAFCwEABgtRAIoLCAIHALYGCQBfAAkAEgEKABcBCgA9AQoApAELAC8BCwAoAwwAhgAMAG8BDQCVAA0AWwEOAF0BDgCWARIAFgASAFkAEgB6AJMALwAFC+IBCAtiAAkLrAAKC94ACgu8AgoLNgMLCy4BCwsKAwwLMgAMC38ADAuMAQ0LPgANC0gBDgt6AJMLSAAHCoIBigrJAgYKBwAGCiMABwqTAAcK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BgUFdGltZWRvd25saWZlbGVmdGJhY2tjb2RlZGF0YXNob3dvbmx5c2l0ZWNpdHlvcGVuanVzdGxpa2VmcmVld29ya3RleHR5ZWFyb3ZlcmJvZHlsb3ZlZm9ybWJvb2twbGF5bGl2ZWxpbmVoZWxwaG9tZXNpZGVtb3Jld29yZGxvbmd0aGVtdmlld2ZpbmRwYWdlZGF5c2Z1bGxoZWFkdGVybWVhY2hhcmVhZnJvbXRydWVtYXJrYWJsZXVwb25oaWdoZGF0ZWxhbmRuZXdzZXZlbm5leHRjYXNlYm90aHBvc3R1c2VkbWFkZWhhbmRoZXJld2hhdG5hbWVMaW5rYmxvZ3NpemViYXNlaGVsZG1ha2VtYWludXNlcicpICtob2xkZW5kc3dpdGhOZXdzcmVhZHdlcmVzaWdudGFrZWhhdmVnYW1lc2VlbmNhbGxwYXRod2VsbHBsdXNtZW51ZmlsbXBhcnRqb2ludGhpc2xpc3Rnb29kbmVlZHdheXN3ZXN0am9ic21pbmRhbHNvbG9nb3JpY2h1c2VzbGFzdHRlYW1hcm15Zm9vZGtpbmd3aWxsZWFzdHdhcmRiZXN0ZmlyZVBhZ2Vrbm93YXdheS5wbmdtb3ZldGhhbmxvYWRnaXZlc2VsZm5vdGVtdWNoZmVlZG1hbnlyb2NraWNvbm9uY2Vsb29raGlkZWRpZWRIb21lcnVsZWhvc3RhamF4aW5mb2NsdWJsYXdzbGVzc2hhbGZzb21lc3VjaHpvbmUxMDAlb25lc2NhcmVUaW1lcmFjZWJsdWVmb3Vyd2Vla2ZhY2Vob3BlZ2F2ZWhhcmRsb3N0d2hlbnBhcmtrZXB0cGFzc3NoaXByb29tSFRNTHBsYW5UeXBlZG9uZXNhdmVrZWVwZmxhZ2xpbmtzb2xkZml2ZXRvb2tyYXRldG93bmp1bXB0aHVzZGFya2NhcmRmaWxlZmVhcnN0YXlraWxsdGhhdGZhbGxhdXRvZXZlci5jb210YWxrc2hvcHZvdGVkZWVwbW9kZXJlc3R0dXJuYm9ybmJhbmRmZWxscm9zZXVybChza2lucm9sZWNvbWVhY3RzYWdlc21lZXRnb2xkLmpwZ2l0ZW12YXJ5ZmVsdHRoZW5zZW5kZHJvcFZpZXdjb3B5MS4wIjwvYT5zdG9wZWxzZWxpZXN0b3VycGFjay5naWZwYXN0Y3NzP2dyYXltZWFuJmd0O3JpZGVzaG90bGF0ZXNhaWRyb2FkdmFyIGZlZWxqb2hucmlja3BvcnRmYXN0J1VBLWRlYWQ8L2I+cG9vcmJpbGx0eXBlVS5TLndvb2RtdXN0MnB4O0luZm9yYW5rd2lkZXdhbnR3YWxsbGVhZFswXTtwYXVsd2F2ZXN1cmUkKCcjd2FpdG1hc3Nhcm1zZ29lc2dhaW5sYW5ncGFpZCEtLSBsb2NrdW5pdHJvb3R3YWxrZmlybXdpZmV4bWwic29uZ3Rlc3QyMHB4a2luZHJvd3N0b29sZm9udG1haWxzYWZlc3Rhcm1hcHNjb3JlcmFpbmZsb3diYWJ5c3BhbnNheXM0cHg7NnB4O2FydHNmb290cmVhbHdpa2loZWF0c3RlcHRyaXBvcmcvbGFrZXdlYWt0b2xkRm9ybWNhc3RmYW5zYmFua3ZlcnlydW5zanVseXRhc2sxcHg7Z29hbGdyZXdzbG93ZWRnZWlkPSJzZXRzNXB4Oy5qcz80MHB4aWYgKHNvb25zZWF0bm9uZXR1YmV6ZXJvc2VudHJlZWRmYWN0aW50b2dpZnRoYXJtMThweGNhbWVoaWxsYm9sZHpvb212b2lkZWFzeXJpbmdmaWxscGVha2luaXRjb3N0M3B4O2phY2t0YWdzYml0c3JvbGxlZGl0a25ld25lYXI8IS0tZ3Jvd0pTT05kdXR5TmFtZXNhbGV5b3UgbG90c3BhaW5qYXp6Y29sZGV5ZXNmaXNod3d3LnJpc2t0YWJzcHJldjEwcHhyaXNlMjVweEJsdWVkaW5nMzAwLGJhbGxmb3JkZWFybndpbGRib3guZmFpcmxhY2t2ZXJzcGFpcmp1bmV0ZWNoaWYoIXBpY2tldmlsJCgiI3dhcm1sb3JkZG9lc3B1bGwsMDAwaWRlYWRyYXdodWdlc3BvdGZ1bmRidXJuaHJlZmNlbGxrZXlzdGlja2hvdXJsb3NzZnVlbDEycHhzdWl0ZGVhbFJTUyJhZ2VkZ3JleUdFVCJlYXNlYWltc2dpcmxhaWRzOHB4O25hdnlncmlkdGlwcyM5OTl3YXJzbGFkeWNhcnMpOyB9cGhwP2hlbGx0YWxsd2hvbXpoOuUqLw0KIDEwMGhhbGwuCgpBN3B4O3B1c2hjaGF0MHB4O2NyZXcqLzwvaGFzaDc1cHhmbGF0cmFyZSAmJiB0ZWxsY2FtcG9udG9sYWlkbWlzc3NraXB0ZW50ZmluZW1hbGVnZXRzcGxvdDQwMCwNCg0KY29vbGZlZXQucGhwPGJyPmVyaWNtb3N0Z3VpZGJlbGxkZXNjaGFpcm1hdGhhdG9tL2ltZyYjODJsdWNrY2VudDAwMDt0aW55Z29uZWh0bWxzZWxsZHJ1Z0ZSRUVub2Rlbmljaz9pZD1sb3NlbnVsbHZhc3R3aW5kUlNTIHdlYXJyZWx5YmVlbnNhbWVkdWtlbmFzYWNhcGV3aXNoZ3VsZlQyMzpoaXRzc2xvdGdhdGVraWNrYmx1cnRoZXkxNXB4JycpOyk7Ij5tc2lld2luc2JpcmRzb3J0YmV0YXNlZWtUMTg6b3Jkc3RyZWVtYWxsNjBweGZhcm3igJlzYm95c1swXS4nKTsiUE9TVGJlYXJraWRzKTt9fW1hcnl0ZW5kKFVLKXF1YWR6aDrmLXNpei0tLS1wcm9wJyk7DWxpZnRUMTk6dmljZWFuZHlkZWJ0PlJTU3Bvb2xuZWNrYmxvd1QxNjpkb29yZXZhbFQxNzpsZXRzZmFpbG9yYWxwb2xsbm92YWNvbHNnZW5lIOKAlHNvZnRyb21ldGlsbHJvc3M8aDM+cG91cmZhZGVwaW5rPHRyPm1pbmkpfCEobWluZXpoOuhiYXJzaGVhcjAwKTttaWxrIC0tPmlyb25mcmVkZGlza3dlbnRzb2lscHV0cy9qcy9ob2x5VDIyOklTQk5UMjA6YWRhbXNlZXM8aDI+anNvbicsICdjb250VDIxOiBSU1Nsb29wYXNpYW1vb248L3A+c291bExJTkVmb3J0Y2FydFQxNDo8aDE+ODBweCEtLTw5cHg7VDA0Om1pa2U6NDZabmljZWluY2hZb3JrcmljZXpoOuQnKSk7cHVyZW1hZ2VwYXJhdG9uZWJvbmQ6MzdaX29mXyddKTswMDAsemg653Rhbmt5YXJkYm93bGJ1c2g6NTZaSmF2YTMwcHgKfH0KJUMzJTozNFpqZWZmRVhQSWNhc2h2aXNhZ29sZnNub3d6aDrpcXVlci5jc3NzaWNrbWVhdG1pbi5iaW5kZGVsbGhpcmVwaWNzcmVudDozNlpIVFRQLTIwMWZvdG93b2xmRU5EIHhib3g6NTRaQk9EWWRpY2s7Cn0KZXhpdDozNVp2YXJzYmVhdCd9KTtkaWV0OTk5O2FubmV9fTwvW2ldLkxhbmdrbcKyd2lyZXRveXNhZGRzc2VhbGFsZXg7Cgl9ZWNob25pbmUub3JnMDA1KXRvbnlqZXdzc2FuZGxlZ3Nyb29mMDAwKSAyMDB3aW5lZ2VhcmRvZ3Nib290Z2FyeWN1dHN0eWxldGVtcHRpb24ueG1sY29ja2dhbmckKCcuNTBweFBoLkRtaXNjYWxhbmxvYW5kZXNrbWlsZXJ5YW51bml4ZGlzYyk7fQpkdXN0Y2xpcCkuCgo3MHB4LTIwMERWRHM3XT48dGFwZWRlbW9pKyspd2FnZWV1cm9waGlsb3B0c2hvbGVGQVFzYXNpbi0yNlRsYWJzcGV0c1VSTCBidWxrY29vazt9DQpIRUFEWzBdKWFiYnJqdWFuKDE5OGxlc2h0d2luPC9pPnNvbnlndXlzZnVja3BpcGV8LQohMDAyKW5kb3dbMV07W107CkxvZyBzYWx0DQoJCWJhbmd0cmltYmF0aCl7DQowMHB4Cn0pO2tvOuxmZWVzYWQ+DXM6Ly8gW107dG9sbHBsdWcoKXsKew0KIC5qcycyMDBwZHVhbGJvYXQuSlBHKTsKfXF1b3QpOwoKJyk7Cg0KfQ0yMDE0MjAxNTIwMTYyMDE3MjAxODIwMTkyMDIwMjAyMTIwMjIyMDIzMjAyNDIwMjUyMDI2MjAyNzIwMjgyMDI5MjAzMDIwMzEyMDMyMjAzMzIwMzQyMDM1MjAzNjIwMzcyMDEzMjAxMjIwMTEyMDEwMjAwOTIwMDgyMDA3MjAwNjIwMDUyMDA0MjAwMzIwMDIyMDAxMjAwMDE5OTkxOTk4MTk5NzE5OTYxOTk1MTk5NDE5OTMxOTkyMTk5MTE5OTAxOTg5MTk4ODE5ODcxOTg2MTk4NTE5ODQxOTgzMTk4MjE5ODExOTgwMTk3OTE5NzgxOTc3MTk3NjE5NzUxOTc0MTk3MzE5NzIxOTcxMTk3MDE5NjkxOTY4MTk2NzE5NjYxOTY1MTk2NDE5NjMxOTYyMTk2MTE5NjAxOTU5MTk1ODE5NTcxOTU2MTk1NTE5NTQxOTUzMTk1MjE5NTExOTUwMTAwMDEwMjQxMzk0MDAwMDk5OTljb21vbcOhc2VzdGVlc3RhcGVyb3RvZG9oYWNlY2FkYWHDsW9iaWVuZMOtYWFzw612aWRhY2Fzb290cm9mb3Jvc29sb290cmFjdWFsZGlqb3NpZG9ncmFudGlwb3RlbWFkZWJlYWxnb3F1w6llc3RvbmFkYXRyZXNwb2NvY2FzYWJham90b2Rhc2lub2FndWFwdWVzdW5vc2FudGVkaWNlbHVpc2VsbGFtYXlvem9uYWFtb3JwaXNvb2JyYWNsaWNlbGxvZGlvc2hvcmFjYXNp0LfQsNC90LDQvtC80YDQsNGA0YPRgtCw0L3QtdC/0L7QvtGC0LjQt9C90L7QtNC+0YLQvtC20LXQvtC90LjRhdCd0LDQtdC10LHRi9C80YvQktGL0YHQvtCy0YvQstC+0J3QvtC+0LHQn9C+0LvQuNC90LjQoNCk0J3QtdCc0YvRgtGL0J7QvdC40LzQtNCw0JfQsNCU0LDQndGD0J7QsdGC0LXQmNC30LXQudC90YPQvNC80KLRi9GD0LbZgdmK2KPZhtmF2KfZhdi52YPZhNij2YjYsdiv2YrYp9mB2YnZh9mI2YTZhdmE2YPYp9mI2YTZh9io2LPYp9mE2KXZhtmH2YrYo9mK2YLYr9mH2YTYq9mF2KjZh9mE2YjZhNmK2KjZhNin2YrYqNmD2LTZitin2YXYo9mF2YbYqtio2YrZhNmG2K3YqNmH2YXZhdi02YjYtGZpcnN0dmlkZW9saWdodHdvcmxkbWVkaWF3aGl0ZWNsb3NlYmxhY2tyaWdodHNtYWxsYm9va3NwbGFjZW11c2ljZmllbGRvcmRlcnBvaW50dmFsdWVsZXZlbHRhYmxlYm9hcmRob3VzZWdyb3Vwd29ya3N5ZWFyc3N0YXRldG9kYXl3YXRlcnN0YXJ0c3R5bGVkZWF0aHBvd2VycGhvbmVuaWdodGVycm9yaW5wdXRhYm91dHRlcm1zdGl0bGV0b29sc2V2ZW50bG9jYWx0aW1lc2xhcmdld29yZHNnYW1lc3Nob3J0c3BhY2Vmb2N1c2NsZWFybW9kZWxibG9ja2d1aWRlcmFkaW9zaGFyZXdvbWVuYWdhaW5tb25leWltYWdlbmFtZXN5b3VuZ2xpbmVzbGF0ZXJjb2xvcmdyZWVuZnJvbnQmYW1wO3dhdGNoZm9yY2VwcmljZXJ1bGVzYmVnaW5hZnRlcnZpc2l0aXNzdWVhcmVhc2JlbG93aW5kZXh0b3RhbGhvdXJzbGFiZWxwcmludHByZXNzYnVpbHRsaW5rc3NwZWVkc3R1ZHl0cmFkZWZvdW5kc2Vuc2V1bmRlcnNob3duZm9ybXNyYW5nZWFkZGVkc3RpbGxtb3ZlZHRha2VuYWJvdmVmbGFzaGZpeGVkb2Z0ZW5vdGhlcnZpZXdzY2hlY2tsZWdhbHJpdmVyaXRlbXNxdWlja3NoYXBlaHVtYW5leGlzdGdvaW5nbW92aWV0aGlyZGJhc2ljcGVhY2VzdGFnZXdpZHRobG9naW5pZGVhc3dyb3RlcGFnZXN1c2Vyc2RyaXZlc3RvcmVicmVha3NvdXRodm9pY2VzaXRlc21vbnRod2hlcmVidWlsZHdoaWNoZWFydGhmb3J1bXRocmVlc3BvcnRwYXJ0eUNsaWNrbG93ZXJsaXZlc2NsYXNzbGF5ZXJlbnRyeXN0b3J5dXNhZ2Vzb3VuZGNvdXJ0eW91ciBiaXJ0aHBvcHVwdHlwZXNhcHBseUltYWdlYmVpbmd1cHBlcm5vdGVzZXZlcnlzaG93c21lYW5zZXh0cmFtYXRjaHRyYWNra25vd25lYXJseWJlZ2Fuc3VwZXJwYXBlcm5vcnRobGVhcm5naXZlbm5hbWVkZW5kZWRUZXJtc3BhcnRzR3JvdXBicmFuZHVzaW5nd29tYW5mYWxzZXJlYWR5YXVkaW90YWtlc3doaWxlLmNvbS9saXZlZGNhc2VzZGFpbHljaGlsZGdyZWF0anVkZ2V0aG9zZXVuaXRzbmV2ZXJicm9hZGNvYXN0Y292ZXJhcHBsZWZpbGVzY3ljbGVzY2VuZXBsYW5zY2xpY2t3cml0ZXF1ZWVucGllY2VlbWFpbGZyYW1lb2xkZXJwaG90b2xpbWl0Y2FjaGVjaXZpbHNjYWxlZW50ZXJ0aGVtZXRoZXJldG91Y2hib3VuZHJveWFsYXNrZWR3aG9sZXNpbmNlc3RvY2sgbmFtZWZhaXRoaGVhcnRlbXB0eW9mZmVyc2NvcGVvd25lZG1pZ2h0YWxidW10aGlua2Jsb29kYXJyYXltYWpvcnRydXN0Y2Fub251bmlvbmNvdW50dmFsaWRzdG9uZVN0eWxlTG9naW5oYXBweW9jY3VybGVmdDpmcmVzaHF1aXRlZmlsbXNncmFkZW5lZWRzdXJiYW5maWdodGJhc2lzaG92ZXJhdXRvO3JvdXRlLmh0bWxtaXhlZGZpbmFsWW91ciBzbGlkZXRvcGljYnJvd25hbG9uZWRyYXduc3BsaXRyZWFjaFJpZ2h0ZGF0ZXNtYXJjaHF1b3RlZ29vZHNMaW5rc2RvdWJ0YXN5bmN0aHVtYmFsbG93Y2hpZWZ5b3V0aG5vdmVsMTBweDtzZXJ2ZXVudGlsaGFuZHNDaGVja1NwYWNlcXVlcnlqYW1lc2VxdWFsdHdpY2UwLDAwMFN0YXJ0cGFuZWxzb25nc3JvdW5kZWlnaHRzaGlmdHdvcnRocG9zdHNsZWFkc3dlZWtzYXZvaWR0aGVzZW1pbGVzcGxhbmVzbWFydGFscGhhcGxhbnRtYXJrc3JhdGVzcGxheXNjbGFpbXNhbGVzdGV4dHNzdGFyc3dyb25nPC9oMz50aGluZy5vcmcvbXVsdGloZWFyZFBvd2Vyc3RhbmR0b2tlbnNvbGlkKHRoaXNicmluZ3NoaXBzc3RhZmZ0cmllZGNhbGxzZnVsbHlmYWN0c2FnZW50VGhpcyAvLy0tPmFkbWluZWd5cHRFdmVudDE1cHg7RW1haWx0cnVlImNyb3Nzc3BlbnRibG9nc2JveCI+bm90ZWRsZWF2ZWNoaW5hc2l6ZXNndWVzdDwvaDQ+cm9ib3RoZWF2eXRydWUsc2V2ZW5ncmFuZGNyaW1lc2lnbnNhd2FyZWRhbmNlcGhhc2U+PCEtLWVuX1VTJiMzOTsyMDBweF9uYW1lbGF0aW5lbmpveWFqYXguYXRpb25zbWl0aFUuUy4gaG9sZHNwZXRlcmluZGlhbmF2Ij5jaGFpbnNjb3JlY29tZXNkb2luZ3ByaW9yU2hhcmUxOTkwc3JvbWFubGlzdHNqYXBhbmZhbGxzdHJpYWxvd25lcmFncmVlPC9oMj5hYnVzZWFsZXJ0b3BlcmEiLS8vV2NhcmRzaGlsbHN0ZWFtc1Bob3RvdHJ1dGhjbGVhbi5waHA/c2FpbnRtZXRhbGxvdWlzbWVhbnRwcm9vZmJyaWVmcm93Ij5nZW5yZXRydWNrbG9va3NWYWx1ZUZyYW1lLm5ldC8tLT4KPHRyeSB7CnZhciBtYWtlc2Nvc3RzcGxhaW5hZHVsdHF1ZXN0dHJhaW5sYWJvcmhlbHBzY2F1c2VtYWdpY21vdG9ydGhlaXIyNTBweGxlYXN0c3RlcHNDb3VudGNvdWxkZ2xhc3NzaWRlc2Z1bmRzaG90ZWxhd2FyZG1vdXRobW92ZXNwYXJpc2dpdmVzZHV0Y2h0ZXhhc2ZydWl0bnVsbCx8fFtdO3RvcCI+CjwhLS1QT1NUIm9jZWFuPGJyLz5mbG9vcnNwZWFrZGVwdGggc2l6ZWJhbmtzY2F0Y2hjaGFydDIwcHg7YWxpZ25kZWFsc3dvdWxkNTBweDt1cmw9InBhcmtzbW91c2VNb3N0IC4uLjwvYW1vbmdicmFpbmJvZHkgbm9uZTtiYXNlZGNhcnJ5ZHJhZnRyZWZlcnBhZ2VfaG9tZS5tZXRlcmRlbGF5ZHJlYW1wcm92ZWpvaW50PC90cj5kcnVnczwhLS0gYXByaWxpZGVhbGFsbGVuZXhhY3Rmb3J0aGNvZGVzbG9naWNWaWV3IHNlZW1zYmxhbmtwb3J0cyAoMjAwc2F2ZWRfbGlua2dvYWxzZ3JhbnRncmVla2hvbWVzcmluZ3NyYXRlZDMwcHg7d2hvc2VwYXJzZSgpOyIgQmxvY2tsaW51eGpvbmVzcGl4ZWwnKTsiPik7aWYoLWxlZnRkYXZpZGhvcnNlRm9jdXNyYWlzZWJveGVzVHJhY2tlbWVudDwvZW0+YmFyIj4uc3JjPXRvd2VyYWx0PSJjYWJsZWhlbnJ5MjRweDtzZXR1cGl0YWx5c2hhcnBtaW5vcnRhc3Rld2FudHN0aGlzLnJlc2V0d2hlZWxnaXJscy9jc3MvMTAwJTtjbHVic3N0dWZmYmlibGV2b3RlcyAxMDAwa29yZWF9KTsNCmJhbmRzcXVldWU9IHt9OzgwcHg7Y2tpbmd7DQoJCWFoZWFkY2xvY2tpcmlzaGxpa2UgcmF0aW9zdGF0c0Zvcm0ieWFob28pWzBdO0Fib3V0ZmluZHM8L2gxPmRlYnVndGFza3NVUkwgPWNlbGxzfSkoKTsxMnB4O3ByaW1ldGVsbHN0dXJuczB4NjAwLmpwZyJzcGFpbmJlYWNodGF4ZXNtaWNyb2FuZ2VsLS0+PC9naWZ0c3N0ZXZlLWxpbmtib2R5Ln0pOwoJbW91bnQgKDE5OUZBUTwvcm9nZXJmcmFua0NsYXNzMjhweDtmZWVkczxoMT48c2NvdHR0ZXN0czIycHg7ZHJpbmspIHx8IGxld2lzc2hhbGwjMDM5OyBmb3IgbG92ZWR3YXN0ZTAwcHg7amE644JzaW1vbjxmb250cmVwbHltZWV0c3VudGVyY2hlYXB0aWdodEJyYW5kKSAhPSBkcmVzc2NsaXBzcm9vbXNvbmtleW1vYmlsbWFpbi5OYW1lIHBsYXRlZnVubnl0cmVlc2NvbS8iMS5qcGd3bW9kZXBhcmFtU1RBUlRsZWZ0IGlkZGVuLCAyMDEpOwp9CmZvcm0udmlydXNjaGFpcnRyYW5zd29yc3RQYWdlc2l0aW9ucGF0Y2g8IS0tCm8tY2FjZmlybXN0b3VycywwMDAgYXNpYW5pKyspe2Fkb2JlJylbMF1pZD0xMGJvdGg7bWVudSAuMi5taS5wbmcia2V2aW5jb2FjaENoaWxkYnJ1Y2UyLmpwZ1VSTCkrLmpwZ3xzdWl0ZXNsaWNlaGFycnkxMjAiIHN3ZWV0dHI+DQpuYW1lPWRpZWdvcGFnZSBzd2lzcy0tPgoKI2ZmZjsiPkxvZy5jb20idHJlYXRzaGVldCkgJiYgMTRweDtzbGVlcG50ZW50ZmlsZWRqYTrjg2lkPSJjTmFtZSJ3b3JzZXNob3RzLWJveC1kZWx0YQombHQ7YmVhcnM6NDhaPGRhdGEtcnVyYWw8L2E+IHNwZW5kYmFrZXJzaG9wcz0gIiI7cGhwIj5jdGlvbjEzcHg7YnJpYW5oZWxsb3NpemU9bz0lMkYgam9pbm1heWJlPGltZyBpbWciPiwgZmpzaW1nIiAiKVswXU1Ub3BCVHlwZSJuZXdseURhbnNrY3plY2h0cmFpbGtub3dzPC9oNT5mYXEiPnpoLWNuMTApOwotMSIpO3R5cGU9Ymx1ZXN0cnVseWRhdmlzLmpzJzs+DQo8IXN0ZWVsIHlvdSBoMj4NCmZvcm0gamVzdXMxMDAlIG1lbnUuDQoJDQp3YWxlc3Jpc2tzdW1lbnRkZGluZ2ItbGlrdGVhY2hnaWYiIHZlZ2FzZGFuc2tlZXN0aXNocWlwc3VvbWlzb2JyZWRlc2RlZW50cmV0b2Rvc3B1ZWRlYcOxb3Nlc3TDoXRpZW5laGFzdGFvdHJvc3BhcnRlZG9uZGVudWV2b2hhY2VyZm9ybWFtaXNtb21lam9ybXVuZG9hcXXDrWTDrWFzc8OzbG9heXVkYWZlY2hhdG9kYXN0YW50b21lbm9zZGF0b3NvdHJhc3NpdGlvbXVjaG9haG9yYWx1Z2FybWF5b3Jlc3Rvc2hvcmFzdGVuZXJhbnRlc2ZvdG9zZXN0YXNwYcOtc251ZXZhc2FsdWRmb3Jvc21lZGlvcXVpZW5tZXNlc3BvZGVyY2hpbGVzZXLDoXZlY2VzZGVjaXJqb3PDqWVzdGFydmVudGFncnVwb2hlY2hvZWxsb3N0ZW5nb2FtaWdvY29zYXNuaXZlbGdlbnRlbWlzbWFhaXJlc2p1bGlvdGVtYXNoYWNpYWZhdm9yanVuaW9saWJyZXB1bnRvYnVlbm9hdXRvcmFicmlsYnVlbmF0ZXh0b21hcnpvc2FiZXJsaXN0YWx1ZWdvY8OzbW9lbmVyb2p1ZWdvcGVyw7poYWJlcmVzdG95bnVuY2FtdWplcnZhbG9yZnVlcmFsaWJyb2d1c3RhaWd1YWx2b3Rvc2Nhc29zZ3XDrWFwdWVkb3NvbW9zYXZpc291c3RlZGRlYmVubm9jaGVidXNjYWZhbHRhZXVyb3NzZXJpZWRpY2hvY3Vyc29jbGF2ZWNhc2FzbGXDs25wbGF6b2xhcmdvb2JyYXN2aXN0YWFwb3lvanVudG90cmF0YXZpc3RvY3JlYXJjYW1wb2hlbW9zY2luY29jYXJnb3Bpc29zb3JkZW5oYWNlbsOhcmVhZGlzY29wZWRyb2NlcmNhcHVlZGFwYXBlbG1lbm9yw7p0aWxjbGFyb2pvcmdlY2FsbGVwb25lcnRhcmRlbmFkaWVtYXJjYXNpZ3VlZWxsYXNzaWdsb2NvY2hlbW90b3NtYWRyZWNsYXNlcmVzdG9uacOxb3F1ZWRhcGFzYXJiYW5jb2hpam9zdmlhamVwYWJsb8Opc3RldmllbmVyZWlub2RlamFyZm9uZG9jYW5hbG5vcnRlbGV0cmFjYXVzYXRvbWFybWFub3NsdW5lc2F1dG9zdmlsbGF2ZW5kb3Blc2FydGlwb3N0ZW5nYW1hcmNvbGxldmFwYWRyZXVuaWRvdmFtb3N6b25hc2FtYm9zYmFuZGFtYXJpYWFidXNvbXVjaGFzdWJpcnJpb2phdml2aXJncmFkb2NoaWNhYWxsw61qb3ZlbmRpY2hhZXN0YW50YWxlc3NhbGlyc3VlbG9wZXNvc2ZpbmVzbGxhbWFidXNjb8Opc3RhbGxlZ2FuZWdyb3BsYXphaHVtb3JwYWdhcmp1bnRhZG9ibGVpc2xhc2JvbHNhYmHDsW9oYWJsYWx1Y2hhw4FyZWFkaWNlbmp1Z2Fybm90YXN2YWxsZWFsbMOhY2FyZ2Fkb2xvcmFiYWpvZXN0w6lndXN0b21lbnRlbWFyaW9maXJtYWNvc3RvZmljaGFwbGF0YWhvZ2FyYXJ0ZXNsZXllc2FxdWVsbXVzZW9iYXNlc3BvY29zbWl0YWRjaWVsb2NoaWNvbWllZG9nYW5hcnNhbnRvZXRhcGFkZWJlc3BsYXlhcmVkZXNzaWV0ZWNvcnRlY29yZWFkdWRhc2Rlc2Vvdmllam9kZXNlYWFndWFzJnF1b3Q7ZG9tYWluY29tbW9uc3RhdHVzZXZlbnRzbWFzdGVyc3lzdGVtYWN0aW9uYmFubmVycmVtb3Zlc2Nyb2xsdXBkYXRlZ2xvYmFsbWVkaXVtZmlsdGVybnVtYmVyY2hhbmdlcmVzdWx0cHVibGljc2NyZWVuY2hvb3Nlbm9ybWFsdHJhdmVsaXNzdWVzc291cmNldGFyZ2V0c3ByaW5nbW9kdWxlbW9iaWxlc3dpdGNocGhvdG9zYm9yZGVycmVnaW9uaXRzZWxmc29jaWFsYWN0aXZlY29sdW1ucmVjb3JkZm9sbG93dGl0bGU+ZWl0aGVybGVuZ3RoZmFtaWx5ZnJpZW5kbGF5b3V0YXV0aG9yY3JlYXRlcmV2aWV3c3VtbWVyc2VydmVycGxheWVkcGxheWVyZXhwYW5kcG9saWN5Zm9ybWF0ZG91YmxlcG9pbnRzc2VyaWVzcGVyc29ubGl2aW5nZGVzaWdubW9udGhzZm9yY2VzdW5pcXVld2VpZ2h0cGVvcGxlZW5lcmd5bmF0dXJlc2VhcmNoZmlndXJlaGF2aW5nY3VzdG9tb2Zmc2V0bGV0dGVyd2luZG93c3VibWl0cmVuZGVyZ3JvdXBzdXBsb2FkaGVhbHRobWV0aG9kdmlkZW9zc2Nob29sZnV0dXJlc2hhZG93ZGViYXRldmFsdWVzT2JqZWN0b3RoZXJzcmlnaHRzbGVhZ3VlY2hyb21lc2ltcGxlbm90aWNlc2hhcmVkZW5kaW5nc2Vhc29ucmVwb3J0b25saW5lc3F1YXJlYnV0dG9uaW1hZ2VzZW5hYmxlbW92aW5nbGF0ZXN0d2ludGVyRnJhbmNlcGVyaW9kc3Ryb25ncmVwZWF0TG9uZG9uZGV0YWlsZm9ybWVkZGVtYW5kc2VjdXJlcGFzc2VkdG9nZ2xlcGxhY2VzZGV2aWNlc3RhdGljY2l0aWVzc3RyZWFteWVsbG93YXR0YWNrc3RyZWV0ZmxpZ2h0aGlkZGVuaW5mbyI+b3BlbmVkdXNlZnVsdmFsbGV5Y2F1c2VzbGVhZGVyc2VjcmV0c2Vjb25kZGFtYWdlc3BvcnRzZXhjZXB0cmF0aW5nc2lnbmVkdGhpbmdzZWZmZWN0ZmllbGRzc3RhdGVzb2ZmaWNldmlzdWFsZWRpdG9ydm9sdW1lUmVwb3J0bXVzZXVtbW92aWVzcGFyZW50YWNjZXNzbW9zdGx5bW90aGVyIiBpZD0ibWFya2V0Z3JvdW5kY2hhbmNlc3VydmV5YmVmb3Jlc3ltYm9sbW9tZW50c3BlZWNobW90aW9uaW5zaWRlbWF0dGVyQ2VudGVyb2JqZWN0ZXhpc3RzbWlkZGxlRXVyb3BlZ3Jvd3RobGVnYWN5bWFubmVyZW5vdWdoY2FyZWVyYW5zd2Vyb3JpZ2lucG9ydGFsY2xpZW50c2VsZWN0cmFuZG9tY2xvc2VkdG9waWNzY29taW5nZmF0aGVyb3B0aW9uc2ltcGx5cmFpc2VkZXNjYXBlY2hvc2VuY2h1cmNoZGVmaW5lcmVhc29uY29ybmVyb3V0cHV0bWVtb3J5aWZyYW1lcG9saWNlbW9kZWxzTnVtYmVyZHVyaW5nb2ZmZXJzc3R5bGVza2lsbGVkbGlzdGVkY2FsbGVkc2lsdmVybWFyZ2luZGVsZXRlYmV0dGVyYnJvd3NlbGltaXRzR2xvYmFsc2luZ2xld2lkZ2V0Y2VudGVyYnVkZ2V0bm93cmFwY3JlZGl0Y2xhaW1zZW5naW5lc2FmZXR5Y2hvaWNlc3Bpcml0LXN0eWxlc3ByZWFkbWFraW5nbmVlZGVkcnVzc2lhcGxlYXNlZXh0ZW50U2NyaXB0YnJva2VuYWxsb3dzY2hhcmdlZGl2aWRlZmFjdG9ybWVtYmVyLWJhc2VkdGhlb3J5Y29uZmlnYXJvdW5kd29ya2VkaGVscGVkQ2h1cmNoaW1wYWN0c2hvdWxkYWx3YXlzbG9nbyIgYm90dG9tbGlzdCI+KXt2YXIgcHJlZml4b3JhbmdlSGVhZGVyLnB1c2goY291cGxlZ2FyZGVuYnJpZGdlbGF1bmNoUmV2aWV3dGFraW5ndmlzaW9ubGl0dGxlZGF0aW5nQnV0dG9uYmVhdXR5dGhlbWVzZm9yZ290U2VhcmNoYW5jaG9yYWxtb3N0bG9hZGVkQ2hhbmdlcmV0dXJuc3RyaW5ncmVsb2FkTW9iaWxlaW5jb21lc3VwcGx5U291cmNlb3JkZXJzdmlld2VkJm5ic3A7Y291cnNlQWJvdXQgaXNsYW5kPGh0bWwgY29va2llbmFtZT0iYW1hem9ubW9kZXJuYWR2aWNlaW48L2E+OiBUaGUgZGlhbG9naG91c2VzQkVHSU4gTWV4aWNvc3RhcnRzY2VudHJlaGVpZ2h0YWRkaW5nSXNsYW5kYXNzZXRzRW1waXJlU2Nob29sZWZmb3J0ZGlyZWN0bmVhcmx5bWFudWFsU2VsZWN0LgoKT25lam9pbmVkbWVudSI+UGhpbGlwYXdhcmRzaGFuZGxlaW1wb3J0T2ZmaWNlcmVnYXJkc2tpbGxzbmF0aW9uU3BvcnRzZGVncmVld2Vla2x5IChlLmcuYmVoaW5kZG9jdG9ybG9nZ2VkdW5pdGVkPC9iPjwvYmVnaW5zcGxhbnRzYXNzaXN0YXJ0aXN0aXNzdWVkMzAwcHh8Y2FuYWRhYWdlbmN5c2NoZW1lcmVtYWluQnJhemlsc2FtcGxlbG9nbyI+YmV5b25kLXNjYWxlYWNjZXB0c2VydmVkbWFyaW5lRm9vdGVyY2FtZXJhPC9oMT4KX2Zvcm0ibGVhdmVzc3RyZXNzIiAvPg0KLmdpZiIgb25sb2FkbG9hZGVyT3hmb3Jkc2lzdGVyc3Vydml2bGlzdGVuZmVtYWxlRGVzaWduc2l6ZT0iYXBwZWFsdGV4dCI+bGV2ZWxzdGhhbmtzaGlnaGVyZm9yY2VkYW5pbWFsYW55b25lQWZyaWNhYWdyZWVkcmVjZW50UGVvcGxlPGJyIC8+d29uZGVycHJpY2VzdHVybmVkfHwge307bWFpbiI+aW5saW5lc3VuZGF5d3JhcCI+ZmFpbGVkY2Vuc3VzbWludXRlYmVhY29ucXVvdGVzMTUwcHh8ZXN0YXRlcmVtb3RlZW1haWwibGlua2VkcmlnaHQ7c2lnbmFsZm9ybWFsMS5odG1sc2lnbnVwcHJpbmNlZmxvYXQ6LnBuZyIgZm9ydW0uQWNjZXNzcGFwZXJzc291bmRzZXh0ZW5kSGVpZ2h0c2xpZGVyVVRGLTgiJmFtcDsgQmVmb3JlLiBXaXRoc3R1ZGlvb3duZXJzbWFuYWdlcHJvZml0alF1ZXJ5YW5udWFscGFyYW1zYm91Z2h0ZmFtb3VzZ29vZ2xlbG9uZ2VyaSsrKSB7aXNyYWVsc2F5aW5nZGVjaWRlaG9tZSI+aGVhZGVyZW5zdXJlYnJhbmNocGllY2VzYmxvY2s7c3RhdGVkdG9wIj48cmFjaW5ncmVzaXplLS0mZ3Q7cGFjaXR5c2V4dWFsYnVyZWF1LmpwZyIgMTAsMDAwb2J0YWludGl0bGVzYW1vdW50LCBJbmMuY29tZWR5bWVudSIgbHlyaWNzdG9kYXkuaW5kZWVkY291bnR5X2xvZ28uRmFtaWx5bG9va2VkTWFya2V0bHNlIGlmUGxheWVydHVya2V5KTt2YXIgZm9yZXN0Z2l2aW5nZXJyb3JzRG9tYWlufWVsc2V7aW5zZXJ0QmxvZzwvZm9vdGVybG9naW4uZmFzdGVyYWdlbnRzPGJvZHkgMTBweCAwcHJhZ21hZnJpZGF5anVuaW9yZG9sbGFycGxhY2VkY292ZXJzcGx1Z2luNSwwMDAgcGFnZSI+Ym9zdG9uLnRlc3QoYXZhdGFydGVzdGVkX2NvdW50Zm9ydW1zc2NoZW1haW5kZXgsZmlsbGVkc2hhcmVzcmVhZGVyYWxlcnQoYXBwZWFyU3VibWl0bGluZSI+Ym9keSI+CiogVGhlVGhvdWdoc2VlaW5namVyc2V5TmV3czwvdmVyaWZ5ZXhwZXJ0aW5qdXJ5d2lkdGg9Q29va2llU1RBUlQgYWNyb3NzX2ltYWdldGhyZWFkbmF0aXZlcG9ja2V0Ym94Ij4KU3lzdGVtIERhdmlkY2FuY2VydGFibGVzcHJvdmVkQXByaWwgcmVhbGx5ZHJpdmVyaXRlbSI+bW9yZSI+Ym9hcmRzY29sb3JzY2FtcHVzZmlyc3QgfHwgW107bWVkaWEuZ3VpdGFyZmluaXNod2lkdGg6c2hvd2VkT3RoZXIgLnBocCIgYXNzdW1lbGF5ZXJzd2lsc29uc3RvcmVzcmVsaWVmc3dlZGVuQ3VzdG9tZWFzaWx5IHlvdXIgU3RyaW5nCgpXaGlsdGF5bG9yY2xlYXI6cmVzb3J0ZnJlbmNodGhvdWdoIikgKyAiPGJvZHk+YnV5aW5nYnJhbmRzTWVtYmVybmFtZSI+b3BwaW5nc2VjdG9yNXB4OyI+dnNwYWNlcG9zdGVybWFqb3IgY29mZmVlbWFydGlubWF0dXJlaGFwcGVuPC9uYXY+a2Fuc2FzbGluayI+SW1hZ2VzPWZhbHNld2hpbGUgaHNwYWNlMCZhbXA7IAoKSW4gIHBvd2VyUG9sc2tpLWNvbG9yam9yZGFuQm90dG9tU3RhcnQgLWNvdW50Mi5odG1sbmV3cyI+MDEuanBnT25saW5lLXJpZ2h0bWlsbGVyc2VuaW9ySVNCTiAwMCwwMDAgZ3VpZGVzdmFsdWUpZWN0aW9ucmVwYWlyLnhtbCIgIHJpZ2h0cy5odG1sLWJsb2NrcmVnRXhwOmhvdmVyd2l0aGludmlyZ2lucGhvbmVzPC90cj4NdXNpbmcgCgl2YXIgPicpOwoJPC90ZD4KPC90cj4KYmFoYXNhYnJhc2lsZ2FsZWdvbWFneWFycG9sc2tpc3Jwc2tp2LHYr9mI5Lit5paH566A5L2T57mB6auU5L+h5oGv5Lit5Zu95oiR5Lus5LiA5Liq5YWs5Y+4566h55CG6K665Z2b5Y+v5Lul5pyN5Yqh5pe26Ze05Liq5Lq65Lqn5ZOB6Ieq5bex5LyB5Lia5p+l55yL5bel5L2c6IGU57O75rKh5pyJ572R56uZ5omA5pyJ6K+E6K665Lit5b+D5paH56ug55So5oi36aaW6aG15L2c6ICF5oqA5pyv6Zeu6aKY55u45YWz5LiL6L295pCc57Si5L2/55So6L2v5Lu25Zyo57q/5Li76aKY6LWE5paZ6KeG6aKR5Zue5aSN5rOo5YaM572R57uc5pS26JeP5YaF5a655o6o6I2Q5biC5Zy65raI5oGv56m66Ze05Y+R5biD5LuA5LmI5aW95Y+L55Sf5rS75Zu+54mH5Y+R5bGV5aaC5p6c5omL5py65paw6Ze75pyA5paw5pa55byP5YyX5Lqs5o+Q5L6b5YWz5LqO5pu05aSa6L+Z5Liq57O757uf55+l6YGT5ri45oiP5bm/5ZGK5YW25LuW5Y+R6KGo5a6J5YWo56ys5LiA5Lya5ZGY6L+b6KGM54K55Ye754mI5p2D55S15a2Q5LiW55WM6K6+6K6h5YWN6LS55pWZ6IKy5Yqg5YWl5rS75Yqo5LuW5Lus5ZWG5ZOB5Y2a5a6i546w5Zyo5LiK5rW35aaC5L2V5bey57uP55WZ6KiA6K+m57uG56S+5Yy655m75b2V5pys56uZ6ZyA6KaB5Lu35qC85pSv5oyB5Zu96ZmF6ZO+5o6l5Zu95a625bu66K6+5pyL5Y+L6ZiF6K+75rOV5b6L5L2N572u57uP5rWO6YCJ5oup6L+Z5qC35b2T5YmN5YiG57G75o6S6KGM5Zug5Li65Lqk5piT5pyA5ZCO6Z+z5LmQ5LiN6IO96YCa6L+H6KGM5Lia56eR5oqA5Y+v6IO96K6+5aSH5ZCI5L2c5aSn5a6256S+5Lya56CU56m25LiT5Lia5YWo6YOo6aG555uu6L+Z6YeM6L+Y5piv5byA5aeL5oOF5Ya155S16ISR5paH5Lu25ZOB54mM5biu5Yqp5paH5YyW6LWE5rqQ5aSn5a2m5a2m5Lmg5Zyw5Z2A5rWP6KeI5oqV6LWE5bel56iL6KaB5rGC5oCO5LmI5pe25YCZ5Yqf6IO95Li76KaB55uu5YmN6LWE6K6v5Z+O5biC5pa55rOV55S15b2x5oub6IGY5aOw5piO5Lu75L2V5YGl5bq35pWw5o2u576O5Zu95rG96L2m5LuL57uN5L2G5piv5Lqk5rWB55Sf5Lqn5omA5Lul55S16K+d5pi+56S65LiA5Lqb5Y2V5L2N5Lq65ZGY5YiG5p6Q5Zyw5Zu+5peF5ri45bel5YW35a2m55Sf57O75YiX572R5Y+L5biW5a2Q5a+G56CB6aKR6YGT5o6n5Yi25Zyw5Yy65Z+65pys5YWo5Zu9572R5LiK6YeN6KaB56ys5LqM5Zac5qyi6L+b5YWl5Y+L5oOF6L+Z5Lqb6ICD6K+V5Y+R546w5Z+56K6t5Lul5LiK5pS/5bqc5oiQ5Li6546v5aKD6aaZ5riv5ZCM5pe25aix5LmQ5Y+R6YCB5LiA5a6a5byA5Y+R5L2c5ZOB5qCH5YeG5qyi6L+O6Kej5Yaz5Zyw5pa55LiA5LiL5Lul5Y+K6LSj5Lu75oiW6ICF5a6i5oi35Luj6KGo56ev5YiG5aWz5Lq65pWw56CB6ZSA5ZSu5Ye6546w56a757q/5bqU55So5YiX6KGo5LiN5ZCM57yW6L6R57uf6K6h5p+l6K+i5LiN6KaB5pyJ5YWz5py65p6E5b6I5aSa5pKt5pS+57uE57uH5pS/562W55u05o6l6IO95Yqb5p2l5rqQ5pmC6ZaT55yL5Yiw54Ot6Zeo5YWz6ZSu5LiT5Yy66Z2e5bi46Iux6K+t55m+5bqm5biM5pyb576O5aWz5q+U6L6D55+l6K+G6KeE5a6a5bu66K6u6YOo6Zeo5oSP6KeB57K+5b2p5pel5pys5o+Q6auY5Y+R6KiA5pa56Z2i5Z+66YeR5aSE55CG5p2D6ZmQ5b2x54mH6ZO26KGM6L+Y5pyJ5YiG5Lqr54mp5ZOB57uP6JCl5re75Yqg5LiT5a626L+Z56eN6K+d6aKY6LW35p2l5Lia5Yqh5YWs5ZGK6K6w5b2V566A5LuL6LSo6YeP55S35Lq65b2x5ZON5byV55So5oql5ZGK6YOo5YiG5b+r6YCf5ZKo6K+i5pe25bCa5rOo5oSP55Sz6K+35a2m5qCh5bqU6K+l5Y6G5Y+y5Y+q5piv6L+U5Zue6LSt5Lmw5ZCN56ew5Li65LqG5oiQ5Yqf6K+05piO5L6b5bqU5a2p5a2Q5LiT6aKY56iL5bqP5LiA6Iis5pyD5ZOh5Y+q5pyJ5YW25a6D5L+d5oqk6ICM5LiU5LuK5aSp56qX5Y+j5Yqo5oCB54q25oCB54m55Yir6K6k5Li65b+F6aG75pu05paw5bCP6K+05oiR5YCR5L2c5Li65aqS5L2T5YyF5ous6YKj5LmI5LiA5qC35Zu95YaF5piv5ZCm5qC55o2u55S16KeG5a2m6Zmi5YW35pyJ6L+H56iL55Sx5LqO5Lq65omN5Ye65p2l5LiN6L+H5q2j5Zyo5piO5pif5pWF5LqL5YWz57O75qCH6aKY5ZWG5Yqh6L6T5YWl5LiA55u05Z+656GA5pWZ5a2m5LqG6Kej5bu6562R57uT5p6c5YWo55CD6YCa55+l6K6h5YiS5a+55LqO6Im65pyv55u45YaM5Y+R55Sf55yf55qE5bu656uL562J57qn57G75Z6L57uP6aqM5a6e546w5Yi25L2c5p2l6Ieq5qCH562+5Lul5LiL5Y6f5Yib5peg5rOV5YW25Lit5YCL5Lq65LiA5YiH5oyH5Y2X5YWz6Zet6ZuG5Zui56ys5LiJ5YWz5rOo5Zug5q2k54Wn54mH5rex5Zyz5ZWG5Lia5bm/5bee5pel5pyf6auY57qn5pyA6L+R57u85ZCI6KGo56S65LiT6L6R6KGM5Li65Lqk6YCa6K+E5Lu36KeJ5b6X57K+5Y2O5a625bqt5a6M5oiQ5oSf6KeJ5a6J6KOF5b6X5Yiw6YKu5Lu25Yi25bqm6aOf5ZOB6Jm954S26L2s6L295oql5Lu36K6w6ICF5pa55qGI6KGM5pS/5Lq65rCR55So5ZOB5Lic6KW/5o+Q5Ye66YWS5bqX54S25ZCO5LuY5qy+54Ot54K55Lul5YmN5a6M5YWo5Y+R5biW6K6+572u6aKG5a+85bel5Lia5Yy76Zmi55yL55yL57uP5YW45Y6f5Zug5bmz5Y+w5ZCE56eN5aKe5Yqg5p2Q5paZ5paw5aKe5LmL5ZCO6IGM5Lia5pWI5p6c5LuK5bm06K665paH5oiR5Zu95ZGK6K+J54mI5Li75L+u5pS55Y+C5LiO5omT5Y2w5b+r5LmQ5py65qKw6KeC54K55a2Y5Zyo57K+56We6I635b6X5Yip55So57un57ut5L2g5Lus6L+Z5LmI5qih5byP6K+t6KiA6IO95aSf6ZuF6JmO5pON5L2c6aOO5qC85LiA6LW356eR5a2m5L2T6IKy55+t5L+h5p2h5Lu25rK755aX6L+Q5Yqo5Lqn5Lia5Lya6K6u5a+86Iiq5YWI55Sf6IGU55uf5Y+v5piv5ZWP6aGM57uT5p6E5L2c55So6LCD5p+l6LOH5paZ6Ieq5Yqo6LSf6LSj5Yac5Lia6K6/6Zeu5a6e5pa95o6l5Y+X6K6o6K666YKj5Liq5Y+N6aaI5Yqg5by65aWz5oCn6IyD5Zu05pyN5YuZ5LyR6Zey5LuK5pel5a6i5pyN6KeA55yL5Y+C5Yqg55qE6K+d5LiA54K55L+d6K+B5Zu+5Lmm5pyJ5pWI5rWL6K+V56e75Yqo5omN6IO95Yaz5a6a6IKh56Wo5LiN5pat6ZyA5rGC5LiN5b6X5Yqe5rOV5LmL6Ze06YeH55So6JCl6ZSA5oqV6K+J55uu5qCH54ix5oOF5pGE5b2x5pyJ5Lqb6KSH6KO95paH5a2m5py65Lya5pWw5a2X6KOF5L+u6LSt54mp5Yac5p2R5YWo6Z2i57K+5ZOB5YW25a6e5LqL5oOF5rC05bmz5o+Q56S65LiK5biC6LCi6LCi5pmu6YCa5pWZ5biI5LiK5Lyg57G75Yir5q2M5puy5oul5pyJ5Yib5paw6YWN5Lu25Y+q6KaB5pe25Luj6LOH6KiK6L6+5Yiw5Lq655Sf6K6i6ZiF6ICB5biI5bGV56S65b+D55CG6LS05a2Q57ay56uZ5Li76aGM6Ieq54S257qn5Yir566A5Y2V5pS56Z2p6YKj5Lqb5p2l6K+05omT5byA5Luj56CB5Yig6Zmk6K+B5Yi46IqC55uu6YeN54K55qyh5pW45aSa5bCR6KeE5YiS6LWE6YeR5om+5Yiw5Lul5ZCO5aSn5YWo5Li76aG15pyA5L2z5Zue562U5aSp5LiL5L+d6Zqc546w5Luj5qOA5p+l5oqV56Wo5bCP5pe25rKS5pyJ5q2j5bi455Sa6Iez5Luj55CG55uu5b2V5YWs5byA5aSN5Yi26YeR6J6N5bm456aP54mI5pys5b2i5oiQ5YeG5aSH6KGM5oOF5Zue5Yiw5oCd5oOz5oCO5qC35Y2P6K6u6K6k6K+B5pyA5aW95Lqn55Sf5oyJ54Wn5pyN6KOF5bm/5Lic5Yqo5ryr6YeH6LSt5paw5omL57uE5Zu+6Z2i5p2/5Y+C6ICD5pS/5rK75a655piT5aSp5Zyw5Yqq5Yqb5Lq65Lus5Y2H57qn6YCf5bqm5Lq654mp6LCD5pW05rWB6KGM6YCg5oiQ5paH5a2X6Z+p5Zu96LS45piT5byA5bGV55u46Zec6KGo546w5b2x6KeG5aaC5q2k576O5a655aSn5bCP5oql6YGT5p2h5qy+5b+D5oOF6K645aSa5rOV6KeE5a625bGF5Lmm5bqX6L+e5o6l56uL5Y2z5Li+5oql5oqA5ben5aWl6L+Q55m75YWl5Lul5p2l55CG6K665LqL5Lu26Ieq55Sx5Lit5Y2O5Yqe5YWs5aaI5aaI55yf5q2j5LiN6ZSZ5YWo5paH5ZCI5ZCM5Lu35YC85Yir5Lq655uR552j5YW35L2T5LiW57qq5Zui6Zif5Yib5Lia5om/5ouF5aKe6ZW/5pyJ5Lq65L+d5oyB5ZWG5a6257u05L+u5Y+w5rm+5bem5Y+z6IKh5Lu9562U5qGI5a6e6ZmF55S15L+h57uP55CG55Sf5ZG95a6j5Lyg5Lu75Yqh5q2j5byP54m56Imy5LiL5p2l5Y2P5Lya5Y+q6IO95b2T54S26YeN5paw5YWn5a655oyH5a+86L+Q6KGM5pel5b+X6LOj5a626LaF6L+H5Zyf5Zyw5rWZ5rGf5pSv5LuY5o6o5Ye656uZ6ZW/5p2t5bee5omn6KGM5Yi26YCg5LmL5LiA5o6o5bm/546w5Zy65o+P6L+w5Y+Y5YyW5Lyg57uf5q2M5omL5L+d6Zmp6K++56iL5Yy755aX57uP6L+H6L+H5Y675LmL5YmN5pS25YWl5bm05bqm5p2C5b+X576O5Li95pyA6auY55m76ZmG5pyq5p2l5Yqg5bel5YWN6LSj5pWZ56iL54mI5Z2X6Lqr5L2T6YeN5bqG5Ye65ZSu5oiQ5pys5b2i5byP5Zyf6LGG5Ye65YO55Lic5pa56YKu566x5Y2X5Lqs5rGC6IGM5Y+W5b6X6IGM5L2N55u45L+h6aG16Z2i5YiG6ZKf572R6aG156Gu5a6a5Zu+5L6L572R5Z2A56ev5p6B6ZSZ6K+v55uu55qE5a6d6LSd5py65YWz6aOO6Zmp5o6I5p2D55eF5q+S5a6g54mp6Zmk5LqG6KmV6KuW55a+55eF5Y+K5pe25rGC6LSt56uZ54K55YS/56ul5q+P5aSp5Lit5aSu6K6k6K+G5q+P5Liq5aSp5rSl5a2X5L2T5Y+w54Gj57u05oqk5pys6aG15Liq5oCn5a6Y5pa55bi46KeB55u45py65oiY55Wl5bqU5b2T5b6L5biI5pa55L6/5qCh5Zut6IKh5biC5oi/5bGL5qCP55uu5ZGY5bel5a+86Ie056qB54S26YGT5YW35pys572R57uT5ZCI5qGj5qGI5Yqz5Yqo5Y+m5aSW576O5YWD5byV6LW35pS55Y+Y56ys5Zub5Lya6K6h6Kqq5piO6ZqQ56eB5a6d5a6d6KeE6IyD5raI6LS55YWx5ZCM5b+Y6K6w5L2T57O75bim5p2l5ZCN5a2X55m86KGo5byA5pS+5Yqg55uf5Y+X5Yiw5LqM5omL5aSn6YeP5oiQ5Lq65pWw6YeP5YWx5Lqr5Yy65Z+f5aWz5a2p5Y6f5YiZ5omA5Zyo57uT5p2f6YCa5L+h6LaF57qn6YWN572u5b2T5pe25LyY56eA5oCn5oSf5oi/5Lqn6YGK5oiy5Ye65Y+j5o+Q5Lqk5bCx5Lia5L+d5YGl56iL5bqm5Y+C5pWw5LqL5Lia5pW05Liq5bGx5Lic5oOF5oSf54m55q6K5YiG6aGe5pCc5bCL5bGe5LqO6Zeo5oi36LSi5Yqh5aOw6Z+z5Y+K5YW26LSi57uP5Z2a5oyB5bmy6YOo5oiQ56uL5Yip55uK6ICD6JmR5oiQ6YO95YyF6KOF55So5oi25q+U6LWb5paH5piO5oub5ZWG5a6M5pW055yf5piv55y8552b5LyZ5Ly05aiB5pyb6aKG5Z+f5Y2r55Sf5LyY5oOg6KuW5aOH5YWs5YWx6Imv5aW95YWF5YiG56ym5ZCI6ZmE5Lu254m554K55LiN5Y+v6Iux5paH6LWE5Lqn5qC55pys5piO5pi+5a+G56K85YWs5LyX5rCR5peP5pu05Yqg5Lqr5Y+X5ZCM5a2m5ZCv5Yqo6YCC5ZCI5Y6f5p2l6Zeu562U5pys5paH576O6aOf57u/6Imy56iz5a6a57uI5LqO55Sf54mp5L6b5rGC5pCc54uQ5Yqb6YeP5Lil6YeN5rC46L+c5YaZ55yf5pyJ6ZmQ56ue5LqJ5a+56LGh6LS555So5LiN5aW957ud5a+55Y2B5YiG5L+D6L+b54K56K+E5b2x6Z+z5LyY5Yq/5LiN5bCR5qyj6LWP5bm25LiU5pyJ54K55pa55ZCR5YWo5paw5L+h55So6K6+5pa95b2i6LGh6LWE5qC856qB56C06ZqP552A6YeN5aSn5LqO5piv5q+V5Lia5pm66IO95YyW5bel5a6M576O5ZWG5Z+O57uf5LiA5Ye654mI5omT6YCg55Si5ZOB5qaC5Ya155So5LqO5L+d55WZ5Zug57Sg5Lit5ZyL5a2Y5YKo6LS05Zu+5pyA5oSb6ZW/5pyf5Y+j5Lu355CG6LSi5Z+65Zyw5a6J5o6S5q2m5rGJ6YeM6Z2i5Yib5bu65aSp56m66aaW5YWI5a6M5ZaE6amx5Yqo5LiL6Z2i5LiN5YaN6K+a5L+h5oSP5LmJ6Ziz5YWJ6Iux5Zu95ryC5Lqu5Yab5LqL546p5a62576k5LyX5Yac5rCR5Y2z5Y+v5ZCN56ix5a625YW35Yqo55S75oOz5Yiw5rOo5piO5bCP5a2m5oCn6IO96ICD56CU56Gs5Lu26KeC55yL5riF5qWa5pCe56yR6aaW6aCB6buE6YeR6YCC55So5rGf6IuP55yf5a6e5Li7566h6Zi25q616Ki75YaK57+76K+R5p2D5Yip5YGa5aW95Ly85LmO6YCa6K6v5pa95bel54uA5oWL5Lmf6K64546v5L+d5Z+55YW75qaC5b+15aSn5Z6L5py656Wo55CG6Kej5Yy/5ZCNY3VhbmRvZW52aWFybWFkcmlkYnVzY2FyaW5pY2lvdGllbXBvcG9ycXVlY3VlbnRhZXN0YWRvcHVlZGVuanVlZ29zY29udHJhZXN0w6Fubm9tYnJldGllbmVucGVyZmlsbWFuZXJhYW1pZ29zY2l1ZGFkY2VudHJvYXVucXVlcHVlZGVzZGVudHJvcHJpbWVycHJlY2lvc2Vnw7puYnVlbm9zdm9sdmVycHVudG9zc2VtYW5haGFiw61hYWdvc3RvbnVldm9zdW5pZG9zY2FybG9zZXF1aXBvbmnDsW9zbXVjaG9zYWxndW5hY29ycmVvaW1hZ2VucGFydGlyYXJyaWJhbWFyw61haG9tYnJlZW1wbGVvdmVyZGFkY2FtYmlvbXVjaGFzZnVlcm9ucGFzYWRvbMOtbmVhcGFyZWNlbnVldmFzY3Vyc29zZXN0YWJhcXVpZXJvbGlicm9zY3VhbnRvYWNjZXNvbWlndWVsdmFyaW9zY3VhdHJvdGllbmVzZ3J1cG9zc2Vyw6FuZXVyb3BhbWVkaW9zZnJlbnRlYWNlcmNhZGVtw6Fzb2ZlcnRhY29jaGVzbW9kZWxvaXRhbGlhbGV0cmFzYWxnw7puY29tcHJhY3VhbGVzZXhpc3RlY3VlcnBvc2llbmRvcHJlbnNhbGxlZ2FydmlhamVzZGluZXJvbXVyY2lhcG9kcsOhcHVlc3RvZGlhcmlvcHVlYmxvcXVpZXJlbWFudWVscHJvcGlvY3Jpc2lzY2llcnRvc2VndXJvbXVlcnRlZnVlbnRlY2VycmFyZ3JhbmRlZWZlY3RvcGFydGVzbWVkaWRhcHJvcGlhb2ZyZWNldGllcnJhZS1tYWlsdmFyaWFzZm9ybWFzZnV0dXJvb2JqZXRvc2VndWlycmllc2dvbm9ybWFzbWlzbW9zw7puaWNvY2FtaW5vc2l0aW9zcmF6w7NuZGViaWRvcHJ1ZWJhdG9sZWRvdGVuw61hamVzw7pzZXNwZXJvY29jaW5hb3JpZ2VudGllbmRhY2llbnRvY8OhZGl6aGFibGFyc2Vyw61hbGF0aW5hZnVlcnphZXN0aWxvZ3VlcnJhZW50cmFyw6l4aXRvbMOzcGV6YWdlbmRhdsOtZGVvZXZpdGFycGFnaW5hbWV0cm9zamF2aWVycGFkcmVzZsOhY2lsY2FiZXphw6FyZWFzc2FsaWRhZW52w61vamFww7NuYWJ1c29zYmllbmVzdGV4dG9zbGxldmFycHVlZGFuZnVlcnRlY29tw7puY2xhc2VzaHVtYW5vdGVuaWRvYmlsYmFvdW5pZGFkZXN0w6FzZWRpdGFyY3JlYWRv0LTQu9GP0YfRgtC+0LrQsNC60LjQu9C40Y3RgtC+0LLRgdC10LXQs9C+0L/RgNC40YLQsNC60LXRidC10YPQttC10JrQsNC60LHQtdC30LHRi9C70L7QvdC40JLRgdC10L/QvtC00K3RgtC+0YLQvtC80YfQtdC80L3QtdGC0LvQtdGC0YDQsNC30L7QvdCw0LPQtNC10LzQvdC10JTQu9GP0J/RgNC40L3QsNGB0L3QuNGF0YLQtdC80LrRgtC+0LPQvtC00LLQvtGC0YLQsNC80KHQqNCQ0LzQsNGP0KfRgtC+0LLQsNGB0LLQsNC80LXQvNGD0KLQsNC60LTQstCw0L3QsNC80Y3RgtC40Y3RgtGD0JLQsNC80YLQtdGF0L/RgNC+0YLRg9GC0L3QsNC00LTQvdGP0JLQvtGC0YLRgNC40L3QtdC50JLQsNGB0L3QuNC80YHQsNC80YLQvtGC0YDRg9Cx0J7QvdC40LzQuNGA0L3QtdC10J7QntCe0LvQuNGG0Y3RgtCw0J7QvdCw0L3QtdC80LTQvtC80LzQvtC50LTQstC10L7QvdC+0YHRg9C04KSV4KWH4KS54KWI4KSV4KWA4KS44KWH4KSV4KS+4KSV4KWL4KSU4KSw4KSq4KSw4KSo4KWH4KSP4KSV4KSV4KS/4KSt4KWA4KSH4KS44KSV4KSw4KSk4KWL4KS54KWL4KSG4KSq4KS54KWA4KSv4KS54KSv4KS+4KSk4KSV4KSl4KS+amFncmFu4KSG4KSc4KSc4KWL4KSF4KSs4KSm4KWL4KSX4KSI4KSc4KS+4KSX4KSP4KS54KSu4KSH4KSo4KS14KS54KSv4KWH4KSl4KWH4KSl4KWA4KSY4KSw4KSc4KSs4KSm4KWA4KSV4KSI4KSc4KWA4KS14KWH4KSo4KSI4KSo4KSP4KS54KSw4KSJ4KS44KSu4KWH4KSV4KSu4KS14KWL4KSy4KWH4KS44KSs4KSu4KSI4KSm4KWH4KST4KSw4KSG4KSu4KSs4KS44KSt4KSw4KSs4KSo4KSa4KSy4KSu4KSo4KSG4KSX4KS44KWA4KSy4KWA2LnZhNmJ2KXZhNmJ2YfYsNin2KLYrtix2LnYr9iv2KfZhNmJ2YfYsNmH2LXZiNix2LrZitix2YPYp9mG2YjZhNin2KjZitmG2LnYsdi22LDZhNmD2YfZhtin2YrZiNmF2YLYp9mE2LnZhNmK2KfZhtin2YTZg9mG2K3YqtmJ2YLYqNmE2YjYrdip2KfYrtix2YHZgti32LnYqNiv2LHZg9mG2KXYsNin2YPZhdin2KfYrdiv2KXZhNin2YHZitmH2KjYudi22YPZitmB2KjYrdir2YjZhdmG2YjZh9mI2KPZhtin2KzYr9in2YTZh9in2LPZhNmF2LnZhtiv2YTZitiz2LnYqNix2LXZhNmJ2YXZhtiw2KjZh9in2KPZhtmH2YXYq9mE2YPZhtiq2KfZhNin2K3Zitir2YXYtdix2LTYsdit2K3ZiNmE2YjZgdmK2KfYsNin2YTZg9mE2YXYsdip2KfZhtiq2KfZhNmB2KPYqNmI2K7Yp9i12KPZhtiq2KfZhtmH2KfZhNmK2LnYttmI2YjZgtiv2KfYqNmG2K7Zitix2KjZhtiq2YTZg9mF2LTYp9ih2YjZh9mK2KfYqNmI2YLYtdi12YjZhdin2LHZgtmF2KPYrdiv2YbYrdmG2LnYr9mF2LHYo9mK2KfYrdip2YPYqtio2K/ZiNmG2YrYrNio2YXZhtmH2KrYrdiq2KzZh9ip2LPZhtip2YrYqtmF2YPYsdip2LrYstip2YbZgdiz2KjZitiq2YTZhNmH2YTZhtin2KrZhNmD2YLZhNio2YTZhdin2LnZhtmH2KPZiNmE2LTZitih2YbZiNix2KPZhdin2YHZitmD2KjZg9mE2LDYp9iq2LHYqtio2KjYo9mG2YfZhdiz2KfZhtmD2KjZiti52YHZgtiv2K3Ys9mG2YTZh9mF2LTYudix2KPZh9mE2LTZh9ix2YLYt9ix2LfZhNiocHJvZmlsZXNlcnZpY2VkZWZhdWx0aGltc2VsZmRldGFpbHNjb250ZW50c3VwcG9ydHN0YXJ0ZWRtZXNzYWdlc3VjY2Vzc2Zhc2hpb248dGl0bGU+Y291bnRyeWFjY291bnRjcmVhdGVkc3Rvcmllc3Jlc3VsdHNydW5uaW5ncHJvY2Vzc3dyaXRpbmdvYmplY3RzdmlzaWJsZXdlbGNvbWVhcnRpY2xldW5rbm93bm5ldHdvcmtjb21wYW55ZHluYW1pY2Jyb3dzZXJwcml2YWN5cHJvYmxlbVNlcnZpY2VyZXNwZWN0ZGlzcGxheXJlcXVlc3RyZXNlcnZld2Vic2l0ZWhpc3RvcnlmcmllbmRzb3B0aW9uc3dvcmtpbmd2ZXJzaW9ubWlsbGlvbmNoYW5uZWx3aW5kb3cuYWRkcmVzc3Zpc2l0ZWR3ZWF0aGVyY29ycmVjdHByb2R1Y3RlZGlyZWN0Zm9yd2FyZHlvdSBjYW5yZW1vdmVkc3ViamVjdGNvbnRyb2xhcmNoaXZlY3VycmVudHJlYWRpbmdsaWJyYXJ5bGltaXRlZG1hbmFnZXJmdXJ0aGVyc3VtbWFyeW1hY2hpbmVtaW51dGVzcHJpdmF0ZWNvbnRleHRwcm9ncmFtc29jaWV0eW51bWJlcnN3cml0dGVuZW5hYmxlZHRyaWdnZXJzb3VyY2VzbG9hZGluZ2VsZW1lbnRwYXJ0bmVyZmluYWxseXBlcmZlY3RtZWFuaW5nc3lzdGVtc2tlZXBpbmdjdWx0dXJlJnF1b3Q7LGpvdXJuYWxwcm9qZWN0c3VyZmFjZXMmcXVvdDtleHBpcmVzcmV2aWV3c2JhbGFuY2VFbmdsaXNoQ29udGVudHRocm91Z2hQbGVhc2Ugb3BpbmlvbmNvbnRhY3RhdmVyYWdlcHJpbWFyeXZpbGxhZ2VTcGFuaXNoZ2FsbGVyeWRlY2xpbmVtZWV0aW5nbWlzc2lvbnBvcHVsYXJxdWFsaXR5bWVhc3VyZWdlbmVyYWxzcGVjaWVzc2Vzc2lvbnNlY3Rpb253cml0ZXJzY291bnRlcmluaXRpYWxyZXBvcnRzZmlndXJlc21lbWJlcnNob2xkaW5nZGlzcHV0ZWVhcmxpZXJleHByZXNzZGlnaXRhbHBpY3R1cmVBbm90aGVybWFycmllZHRyYWZmaWNsZWFkaW5nY2hhbmdlZGNlbnRyYWx2aWN0b3J5aW1hZ2VzL3JlYXNvbnNzdHVkaWVzZmVhdHVyZWxpc3RpbmdtdXN0IGJlc2Nob29sc1ZlcnNpb251c3VhbGx5ZXBpc29kZXBsYXlpbmdncm93aW5nb2J2aW91c292ZXJsYXlwcmVzZW50YWN0aW9uczwvdWw+DQp3cmFwcGVyYWxyZWFkeWNlcnRhaW5yZWFsaXR5c3RvcmFnZWFub3RoZXJkZXNrdG9wb2ZmZXJlZHBhdHRlcm51bnVzdWFsRGlnaXRhbGNhcGl0YWxXZWJzaXRlZmFpbHVyZWNvbm5lY3RyZWR1Y2VkQW5kcm9pZGRlY2FkZXNyZWd1bGFyICZhbXA7IGFuaW1hbHNyZWxlYXNlQXV0b21hdGdldHRpbmdtZXRob2Rzbm90aGluZ1BvcHVsYXJjYXB0aW9ubGV0dGVyc2NhcHR1cmVzY2llbmNlbGljZW5zZWNoYW5nZXNFbmdsYW5kPTEmYW1wO0hpc3RvcnkgPSBuZXcgQ2VudHJhbHVwZGF0ZWRTcGVjaWFsTmV0d29ya3JlcXVpcmVjb21tZW50d2FybmluZ0NvbGxlZ2V0b29sYmFycmVtYWluc2JlY2F1c2VlbGVjdGVkRGV1dHNjaGZpbmFuY2V3b3JrZXJzcXVpY2tseWJldHdlZW5leGFjdGx5c2V0dGluZ2Rpc2Vhc2VTb2NpZXR5d2VhcG9uc2V4aGliaXQmbHQ7IS0tQ29udHJvbGNsYXNzZXNjb3ZlcmVkb3V0bGluZWF0dGFja3NkZXZpY2VzKHdpbmRvd3B1cnBvc2V0aXRsZT0iTW9iaWxlIGtpbGxpbmdzaG93aW5nSXRhbGlhbmRyb3BwZWRoZWF2aWx5ZWZmZWN0cy0xJ10pOwpjb25maXJtQ3VycmVudGFkdmFuY2VzaGFyaW5nb3BlbmluZ2RyYXdpbmdiaWxsaW9ub3JkZXJlZEdlcm1hbnlyZWxhdGVkPC9mb3JtPmluY2x1ZGV3aGV0aGVyZGVmaW5lZFNjaWVuY2VjYXRhbG9nQXJ0aWNsZWJ1dHRvbnNsYXJnZXN0dW5pZm9ybWpvdXJuZXlzaWRlYmFyQ2hpY2Fnb2hvbGlkYXlHZW5lcmFscGFzc2FnZSwmcXVvdDthbmltYXRlZmVlbGluZ2Fycml2ZWRwYXNzaW5nbmF0dXJhbHJvdWdobHkuCgpUaGUgYnV0IG5vdGRlbnNpdHlCcml0YWluQ2hpbmVzZWxhY2sgb2Z0cmlidXRlSXJlbGFuZCIgZGF0YS1mYWN0b3JzcmVjZWl2ZXRoYXQgaXNMaWJyYXJ5aHVzYmFuZGluIGZhY3RhZmZhaXJzQ2hhcmxlc3JhZGljYWxicm91Z2h0ZmluZGluZ2xhbmRpbmc6bGFuZz0icmV0dXJuIGxlYWRlcnNwbGFubmVkcHJlbWl1bXBhY2thZ2VBbWVyaWNhRWRpdGlvbl0mcXVvdDtNZXNzYWdlbmVlZCB0b3ZhbHVlPSJjb21wbGV4bG9va2luZ3N0YXRpb25iZWxpZXZlc21hbGxlci1tb2JpbGVyZWNvcmRzd2FudCB0b2tpbmQgb2ZGaXJlZm94eW91IGFyZXNpbWlsYXJzdHVkaWVkbWF4aW11bWhlYWRpbmdyYXBpZGx5Y2xpbWF0ZWtpbmdkb21lbWVyZ2VkYW1vdW50c2ZvdW5kZWRwaW9uZWVyZm9ybXVsYWR5bmFzdHlob3cgdG8gU3VwcG9ydHJldmVudWVlY29ub215UmVzdWx0c2Jyb3RoZXJzb2xkaWVybGFyZ2VseWNhbGxpbmcuJnF1b3Q7QWNjb3VudEVkd2FyZCBzZWdtZW50Um9iZXJ0IGVmZm9ydHNQYWNpZmljbGVhcm5lZHVwIHdpdGhoZWlnaHQ6d2UgaGF2ZUFuZ2VsZXNuYXRpb25zX3NlYXJjaGFwcGxpZWRhY3F1aXJlbWFzc2l2ZWdyYW50ZWQ6IGZhbHNldHJlYXRlZGJpZ2dlc3RiZW5lZml0ZHJpdmluZ1N0dWRpZXNtaW5pbXVtcGVyaGFwc21vcm5pbmdzZWxsaW5naXMgdXNlZHJldmVyc2V2YXJpYW50IHJvbGU9Im1pc3NpbmdhY2hpZXZlcHJvbW90ZXN0dWRlbnRzb21lb25lZXh0cmVtZXJlc3RvcmVib3R0b206ZXZvbHZlZGFsbCB0aGVzaXRlbWFwZW5nbGlzaHdheSB0byAgQXVndXN0c3ltYm9sc0NvbXBhbnltYXR0ZXJzbXVzaWNhbGFnYWluc3RzZXJ2aW5nfSkoKTsNCnBheW1lbnR0cm91YmxlY29uY2VwdGNvbXBhcmVwYXJlbnRzcGxheWVyc3JlZ2lvbnNtb25pdG9yICcnVGhlIHdpbm5pbmdleHBsb3JlYWRhcHRlZEdhbGxlcnlwcm9kdWNlYWJpbGl0eWVuaGFuY2VjYXJlZXJzKS4gVGhlIGNvbGxlY3RTZWFyY2ggYW5jaWVudGV4aXN0ZWRmb290ZXIgaGFuZGxlcnByaW50ZWRjb25zb2xlRWFzdGVybmV4cG9ydHN3aW5kb3dzQ2hhbm5lbGlsbGVnYWxuZXV0cmFsc3VnZ2VzdF9oZWFkZXJzaWduaW5nLmh0bWwiPnNldHRsZWR3ZXN0ZXJuY2F1c2luZy13ZWJraXRjbGFpbWVkSnVzdGljZWNoYXB0ZXJ2aWN0aW1zVGhvbWFzIG1vemlsbGFwcm9taXNlcGFydGllc2VkaXRpb25vdXRzaWRlOmZhbHNlLGh1bmRyZWRPbHltcGljX2J1dHRvbmF1dGhvcnNyZWFjaGVkY2hyb25pY2RlbWFuZHNzZWNvbmRzcHJvdGVjdGFkb3B0ZWRwcmVwYXJlbmVpdGhlcmdyZWF0bHlncmVhdGVyb3ZlcmFsbGltcHJvdmVjb21tYW5kc3BlY2lhbHNlYXJjaC53b3JzaGlwZnVuZGluZ3Rob3VnaHRoaWdoZXN0aW5zdGVhZHV0aWxpdHlxdWFydGVyQ3VsdHVyZXRlc3RpbmdjbGVhcmx5ZXhwb3NlZEJyb3dzZXJsaWJlcmFsfSBjYXRjaFByb2plY3RleGFtcGxlaGlkZSgpO0Zsb3JpZGFhbnN3ZXJzYWxsb3dlZEVtcGVyb3JkZWZlbnNlc2VyaW91c2ZyZWVkb21TZXZlcmFsLWJ1dHRvbkZ1cnRoZXJvdXQgb2YgIT0gbnVsbHRyYWluZWREZW5tYXJrdm9pZCgwKS9hbGwuanNwcmV2ZW50UmVxdWVzdFN0ZXBoZW4KCldoZW4gb2JzZXJ2ZTwvaDI+DQpNb2Rlcm4gcHJvdmlkZSIgYWx0PSJib3JkZXJzLgoKRm9yIAoKTWFueSBhcnRpc3RzcG93ZXJlZHBlcmZvcm1maWN0aW9udHlwZSBvZm1lZGljYWx0aWNrZXRzb3Bwb3NlZENvdW5jaWx3aXRuZXNzanVzdGljZUdlb3JnZSBCZWxnaXVtLi4uPC9hPnR3aXR0ZXJub3RhYmx5d2FpdGluZ3dhcmZhcmUgT3RoZXIgcmFua2luZ3BocmFzZXNtZW50aW9uc3Vydml2ZXNjaG9sYXI8L3A+DQogQ291bnRyeWlnbm9yZWRsb3NzIG9manVzdCBhc0dlb3JnaWFzdHJhbmdlPGhlYWQ+PHN0b3BwZWQxJ10pOw0KaXNsYW5kc25vdGFibGVib3JkZXI6bGlzdCBvZmNhcnJpZWQxMDAsMDAwPC9oMz4KIHNldmVyYWxiZWNvbWVzc2VsZWN0IHdlZGRpbmcwMC5odG1sbW9uYXJjaG9mZiB0aGV0ZWFjaGVyaGlnaGx5IGJpb2xvZ3lsaWZlIG9mb3IgZXZlbnJpc2Ugb2YmcmFxdW87cGx1c29uZWh1bnRpbmcodGhvdWdoRG91Z2xhc2pvaW5pbmdjaXJjbGVzRm9yIHRoZUFuY2llbnRWaWV0bmFtdmVoaWNsZXN1Y2ggYXNjcnlzdGFsdmFsdWUgPVdpbmRvd3NlbmpveWVkYSBzbWFsbGFzc3VtZWQ8YSBpZD0iZm9yZWlnbiBBbGwgcmlob3cgdGhlRGlzcGxheXJldGlyZWRob3dldmVyaGlkZGVuO2JhdHRsZXNzZWVraW5nY2FiaW5ldHdhcyBub3Rsb29rIGF0Y29uZHVjdGdldCB0aGVKYW51YXJ5aGFwcGVuc3R1cm5pbmdhOmhvdmVyT25saW5lIEZyZW5jaCBsYWNraW5ndHlwaWNhbGV4dHJhY3RlbmVtaWVzZXZlbiBpZmdlbmVyYXRkZWNpZGVkYXJlIG5vdC9zZWFyY2hiZWxpZWZzLWltYWdlOmxvY2F0ZWRzdGF0aWMubG9naW4iPmNvbnZlcnR2aW9sZW50ZW50ZXJlZGZpcnN0Ij5jaXJjdWl0RmlubGFuZGNoZW1pc3RzaGUgd2FzMTBweDsiPmFzIHN1Y2hkaXZpZGVkPC9zcGFuPndpbGwgYmVsaW5lIG9mYSBncmVhdG15c3RlcnkvaW5kZXguZmFsbGluZ2R1ZSB0byByYWlsd2F5Y29sbGVnZW1vbnN0ZXJkZXNjZW50aXQgd2l0aG51Y2xlYXJKZXdpc2ggcHJvdGVzdEJyaXRpc2hmbG93ZXJzcHJlZGljdHJlZm9ybXNidXR0b24gd2hvIHdhc2xlY3R1cmVpbnN0YW50c3VpY2lkZWdlbmVyaWNwZXJpb2RzbWFya2V0c1NvY2lhbCBmaXNoaW5nY29tYmluZWdyYXBoaWN3aW5uZXJzPGJyIC8+PGJ5IHRoZSBOYXR1cmFsUHJpdmFjeWNvb2tpZXNvdXRjb21lcmVzb2x2ZVN3ZWRpc2hicmllZmx5UGVyc2lhbnNvIG11Y2hDZW50dXJ5ZGVwaWN0c2NvbHVtbnNob3VzaW5nc2NyaXB0c25leHQgdG9iZWFyaW5nbWFwcGluZ3JldmlzZWRqUXVlcnkoLXdpZHRoOnRpdGxlIj50b29sdGlwU2VjdGlvbmRlc2lnbnNUdXJraXNoeW91bmdlci5tYXRjaCh9KSgpOwoKYnVybmluZ29wZXJhdGVkZWdyZWVzc291cmNlPVJpY2hhcmRjbG9zZWx5cGxhc3RpY2VudHJpZXM8L3RyPg0KY29sb3I6I3VsIGlkPSJwb3NzZXNzcm9sbGluZ3BoeXNpY3NmYWlsaW5nZXhlY3V0ZWNvbnRlc3RsaW5rIHRvRGVmYXVsdDxiciAvPgo6IHRydWUsY2hhcnRlcnRvdXJpc21jbGFzc2ljcHJvY2VlZGV4cGxhaW48L2gxPg0Kb25saW5lLj94bWwgdmVoZWxwaW5nZGlhbW9uZHVzZSB0aGVhaXJsaW5lZW5kIC0tPikuYXR0cihyZWFkZXJzaG9zdGluZyNmZmZmZmZyZWFsaXplVmluY2VudHNpZ25hbHMgc3JjPSIvUHJvZHVjdGRlc3BpdGVkaXZlcnNldGVsbGluZ1B1YmxpYyBoZWxkIGluSm9zZXBoIHRoZWF0cmVhZmZlY3RzPHN0eWxlPmEgbGFyZ2Vkb2Vzbid0bGF0ZXIsIEVsZW1lbnRmYXZpY29uY3JlYXRvckh1bmdhcnlBaXJwb3J0c2VlIHRoZXNvIHRoYXRNaWNoYWVsU3lzdGVtc1Byb2dyYW1zLCBhbmQgIHdpZHRoPWUmcXVvdDt0cmFkaW5nbGVmdCI+CnBlcnNvbnNHb2xkZW4gQWZmYWlyc2dyYW1tYXJmb3JtaW5nZGVzdHJveWlkZWEgb2ZjYXNlIG9mb2xkZXN0IHRoaXMgaXMuc3JjID0gY2FydG9vbnJlZ2lzdHJDb21tb25zTXVzbGltc1doYXQgaXNpbiBtYW55bWFya2luZ3JldmVhbHNJbmRlZWQsZXF1YWxseS9zaG93X2FvdXRkb29yZXNjYXBlKEF1c3RyaWFnZW5ldGljc3lzdGVtLEluIHRoZSBzaXR0aW5nSGUgYWxzb0lzbGFuZHNBY2FkZW15CgkJPCEtLURhbmllbCBiaW5kaW5nYmxvY2siPmltcG9zZWR1dGlsaXplQWJyYWhhbShleGNlcHR7d2lkdGg6cHV0dGluZykuaHRtbCh8fCBbXTsKREFUQVsgKmtpdGNoZW5tb3VudGVkYWN0dWFsIGRpYWxlY3RtYWlubHkgX2JsYW5rJ2luc3RhbGxleHBlcnRzaWYodHlwZUl0IGFsc28mY29weTsgIj5UZXJtc2Jvcm4gaW5PcHRpb25zZWFzdGVybnRhbGtpbmdjb25jZXJuZ2FpbmVkIG9uZ29pbmdqdXN0aWZ5Y3JpdGljc2ZhY3RvcnlpdHMgb3duYXNzYXVsdGludml0ZWRsYXN0aW5naGlzIG93bmhyZWY9Ii8iIHJlbD0iZGV2ZWxvcGNvbmNlcnRkaWFncmFtZG9sbGFyc2NsdXN0ZXJwaHA/aWQ9YWxjb2hvbCk7fSkoKTt1c2luZyBhPjxzcGFuPnZlc3NlbHNyZXZpdmFsQWRkcmVzc2FtYXRldXJhbmRyb2lkYWxsZWdlZGlsbG5lc3N3YWxraW5nY2VudGVyc3F1YWxpZnltYXRjaGVzdW5pZmllZGV4dGluY3REZWZlbnNlZGllZCBpbgoJPCEtLSBjdXN0b21zbGlua2luZ0xpdHRsZSBCb29rIG9mZXZlbmluZ21pbi5qcz9hcmUgdGhla29udGFrdHRvZGF5J3MuaHRtbCIgdGFyZ2V0PXdlYXJpbmdBbGwgUmlnOwp9KSgpO3JhaXNpbmcgQWxzbywgY3J1Y2lhbGFib3V0Ij5kZWNsYXJlLS0+CjxzY2ZpcmVmb3hhcyBtdWNoYXBwbGllc2luZGV4LCBzLCBidXQgdHlwZSA9IAoNCjwhLS10b3dhcmRzUmVjb3Jkc1ByaXZhdGVGb3JlaWduUHJlbWllcmNob2ljZXNWaXJ0dWFscmV0dXJuc0NvbW1lbnRQb3dlcmVkaW5saW5lO3BvdmVydHljaGFtYmVyTGl2aW5nIHZvbHVtZXNBbnRob255bG9naW4iIFJlbGF0ZWRFY29ub215cmVhY2hlc2N1dHRpbmdncmF2aXR5bGlmZSBpbkNoYXB0ZXItc2hhZG93Tm90YWJsZTwvdGQ+DQogcmV0dXJuc3RhZGl1bXdpZGdldHN2YXJ5aW5ndHJhdmVsc2hlbGQgYnl3aG8gYXJld29yayBpbmZhY3VsdHlhbmd1bGFyd2hvIGhhZGFpcnBvcnR0b3duIG9mCgpTb21lICdjbGljaydjaGFyZ2Vza2V5d29yZGl0IHdpbGxjaXR5IG9mKHRoaXMpO0FuZHJldyB1bmlxdWUgY2hlY2tlZG9yIG1vcmUzMDBweDsgcmV0dXJuO3JzaW9uPSJwbHVnaW5zd2l0aGluIGhlcnNlbGZTdGF0aW9uRmVkZXJhbHZlbnR1cmVwdWJsaXNoc2VudCB0b3RlbnNpb25hY3RyZXNzY29tZSB0b2ZpbmdlcnNEdWtlIG9mcGVvcGxlLGV4cGxvaXR3aGF0IGlzaGFybW9ueWEgbWFqb3IiOiJodHRwaW4gaGlzIG1lbnUiPgptb250aGx5b2ZmaWNlcmNvdW5jaWxnYWluaW5nZXZlbiBpblN1bW1hcnlkYXRlIG9mbG95YWx0eWZpdG5lc3NhbmQgd2FzZW1wZXJvcnN1cHJlbWVTZWNvbmQgaGVhcmluZ1J1c3NpYW5sb25nZXN0QWxiZXJ0YWxhdGVyYWxzZXQgb2Ygc21hbGwiPi5hcHBlbmRkbyB3aXRoZmVkZXJhbGJhbmsgb2ZiZW5lYXRoRGVzcGl0ZUNhcGl0YWxncm91bmRzKSwgYW5kIHBlcmNlbnRpdCBmcm9tY2xvc2luZ2NvbnRhaW5JbnN0ZWFkZmlmdGVlbmFzIHdlbGwueWFob28ucmVzcG9uZGZpZ2h0ZXJvYnNjdXJlcmVmbGVjdG9yZ2FuaWM9IE1hdGguZWRpdGluZ29ubGluZSBwYWRkaW5nYSB3aG9sZW9uZXJyb3J5ZWFyIG9mZW5kIG9mIGJhcnJpZXJ3aGVuIGl0aGVhZGVyIGhvbWUgb2ZyZXN1bWVkcmVuYW1lZHN0cm9uZz5oZWF0aW5ncmV0YWluc2Nsb3VkZnJ3YXkgb2YgTWFyY2ggMWtub3dpbmdpbiBwYXJ0QmV0d2Vlbmxlc3NvbnNjbG9zZXN0dmlydHVhbGxpbmtzIj5jcm9zc2VkRU5EIC0tPmZhbW91cyBhd2FyZGVkTGljZW5zZUhlYWx0aCBmYWlybHkgd2VhbHRoeW1pbmltYWxBZnJpY2FuY29tcGV0ZWxhYmVsIj5zaW5naW5nZmFybWVyc0JyYXNpbClkaXNjdXNzcmVwbGFjZUdyZWdvcnlmb250IGNvcHVyc3VlZGFwcGVhcnNtYWtlIHVwcm91bmRlZGJvdGggb2ZibG9ja2Vkc2F3IHRoZW9mZmljZXNjb2xvdXJzaWYoZG9jdXdoZW4gaGVlbmZvcmNlcHVzaChmdUF1Z3VzdCBVVEYtOCI+RmFudGFzeWluIG1vc3Rpbmp1cmVkVXN1YWxseWZhcm1pbmdjbG9zdXJlb2JqZWN0IGRlZmVuY2V1c2Ugb2YgTWVkaWNhbDxib2R5PgpldmlkZW50YmUgdXNlZGtleUNvZGVzaXh0ZWVuSXNsYW1pYyMwMDAwMDBlbnRpcmUgd2lkZWx5IGFjdGl2ZSAodHlwZW9mb25lIGNhbmNvbG9yID1zcGVha2VyZXh0ZW5kc1BoeXNpY3N0ZXJyYWluPHRib2R5PmZ1bmVyYWx2aWV3aW5nbWlkZGxlIGNyaWNrZXRwcm9waGV0c2hpZnRlZGRvY3RvcnNSdXNzZWxsIHRhcmdldGNvbXBhY3RhbGdlYnJhc29jaWFsLWJ1bGsgb2ZtYW4gYW5kPC90ZD4KIGhlIGxlZnQpLnZhbCgpZmFsc2UpO2xvZ2ljYWxiYW5raW5naG9tZSB0b25hbWluZyBBcml6b25hY3JlZGl0cyk7Cn0pOwpmb3VuZGVyaW4gdHVybkNvbGxpbnNiZWZvcmUgQnV0IHRoZWNoYXJnZWRUaXRsZSI+Q2FwdGFpbnNwZWxsZWRnb2RkZXNzVGFnIC0tPkFkZGluZzpidXQgd2FzUmVjZW50IHBhdGllbnRiYWNrIGluPWZhbHNlJkxpbmNvbG53ZSBrbm93Q291bnRlckp1ZGFpc21zY3JpcHQgYWx0ZXJlZCddKTsKICBoYXMgdGhldW5jbGVhckV2ZW50Jyxib3RoIGlubm90IGFsbAoKPCEtLSBwbGFjaW5naGFyZCB0byBjZW50ZXJzb3J0IG9mY2xpZW50c3N0cmVldHNCZXJuYXJkYXNzZXJ0c3RlbmQgdG9mYW50YXN5ZG93biBpbmhhcmJvdXJGcmVlZG9tamV3ZWxyeS9hYm91dC4uc2VhcmNobGVnZW5kc2lzIG1hZGVtb2Rlcm4gb25seSBvbm9ubHkgdG9pbWFnZSIgbGluZWFyIHBhaW50ZXJhbmQgbm90cmFyZWx5IGFjcm9ueW1kZWxpdmVyc2hvcnRlcjAwJmFtcDthcyBtYW55d2lkdGg9Ii8qIDwhW0N0aXRsZSA9b2YgdGhlIGxvd2VzdCBwaWNrZWQgZXNjYXBlZHVzZXMgb2ZwZW9wbGVzIFB1YmxpY01hdHRoZXd0YWN0aWNzZGFtYWdlZHdheSBmb3JsYXdzIG9mZWFzeSB0byB3aW5kb3dzdHJvbmcgIHNpbXBsZX1jYXRjaChzZXZlbnRoaW5mb2JveHdlbnQgdG9wYWludGVkY2l0aXplbkkgZG9uJ3RyZXRyZWF0LiBTb21lIHd3LiIpOwpib21iaW5nbWFpbHRvOm1hZGUgaW4uIE1hbnkgY2Fycmllc3x8e307d2l3b3JrIG9mc3lub255bWRlZmVhdHNmYXZvcmVkb3B0aWNhbHBhZ2VUcmF1bmxlc3Mgc2VuZGluZ2xlZnQiPjxjb21TY29yQWxsIHRoZWpRdWVyeS50b3VyaXN0Q2xhc3NpY2ZhbHNlIiBXaWxoZWxtc3VidXJic2dlbnVpbmViaXNob3BzLnNwbGl0KGdsb2JhbCBmb2xsb3dzYm9keSBvZm5vbWluYWxDb250YWN0c2VjdWxhcmxlZnQgdG9jaGllZmx5LWhpZGRlbi1iYW5uZXI8L2xpPgoKLiBXaGVuIGluIGJvdGhkaXNtaXNzRXhwbG9yZWFsd2F5cyB2aWEgdGhlc3Bhw7FvbHdlbGZhcmVydWxpbmcgYXJyYW5nZWNhcHRhaW5oaXMgc29ucnVsZSBvZmhlIHRvb2tpdHNlbGYsPTAmYW1wOyhjYWxsZWRzYW1wbGVzdG8gbWFrZWNvbS9wYWdNYXJ0aW4gS2VubmVkeWFjY2VwdHNmdWxsIG9maGFuZGxlZEJlc2lkZXMvLy0tPjwvYWJsZSB0b3RhcmdldHNlc3NlbmNlaGltIHRvIGl0cyBieSBjb21tb24ubWluZXJhbHRvIHRha2V3YXlzIHRvcy5vcmcvbGFkdmlzZWRwZW5hbHR5c2ltcGxlOmlmIHRoZXlMZXR0ZXJzYSBzaG9ydEhlcmJlcnRzdHJpa2VzIGdyb3Vwcy5sZW5ndGhmbGlnaHRzb3ZlcmxhcHNsb3dseSBsZXNzZXIgc29jaWFsIDwvcD4KCQlpdCBpbnRvcmFua2VkIHJhdGUgb2Z1bD4NCiAgYXR0ZW1wdHBhaXIgb2ZtYWtlIGl0S29udGFrdEFudG9uaW9oYXZpbmcgcmF0aW5ncyBhY3RpdmVzdHJlYW1zdHJhcHBlZCIpLmNzcyhob3N0aWxlbGVhZCB0b2xpdHRsZSBncm91cHMsUGljdHVyZS0tPg0KDQogcm93cz0iIG9iamVjdGludmVyc2U8Zm9vdGVyQ3VzdG9tVj48XC9zY3Jzb2x2aW5nQ2hhbWJlcnNsYXZlcnl3b3VuZGVkd2hlcmVhcyE9ICd1bmRmb3IgYWxscGFydGx5IC1yaWdodDpBcmFiaWFuYmFja2VkIGNlbnR1cnl1bml0IG9mbW9iaWxlLUV1cm9wZSxpcyBob21lcmlzayBvZmRlc2lyZWRDbGludG9uY29zdCBvZmFnZSBvZiBiZWNvbWUgbm9uZSBvZnAmcXVvdDtNaWRkbGUgZWFkJylbMENyaXRpY3NzdHVkaW9zPiZjb3B5O2dyb3VwIj5hc3NlbWJsbWFraW5nIHByZXNzZWR3aWRnZXQucHM6IiA/IHJlYnVpbHRieSBzb21lRm9ybWVyIGVkaXRvcnNkZWxheWVkQ2Fub25pY2hhZCB0aGVwdXNoaW5nY2xhc3M9ImJ1dCBhcmVwYXJ0aWFsQmFieWxvbmJvdHRvbSBjYXJyaWVyQ29tbWFuZGl0cyB1c2VBcyB3aXRoY291cnNlc2EgdGhpcmRkZW5vdGVzYWxzbyBpbkhvdXN0b24yMHB4OyI+YWNjdXNlZGRvdWJsZSBnb2FsIG9mRmFtb3VzICkuYmluZChwcmllc3RzIE9ubGluZWluIEp1bHlzdCArICJnY29uc3VsdGRlY2ltYWxoZWxwZnVscmV2aXZlZGlzIHZlcnlyJysnaXB0bG9zaW5nIGZlbWFsZXNpcyBhbHNvc3RyaW5nc2RheXMgb2ZhcnJpdmFsZnV0dXJlIDxvYmplY3Rmb3JjaW5nU3RyaW5nKCIgLz4KCQloZXJlIGlzZW5jb2RlZC4gIFRoZSBiYWxsb29uZG9uZSBieS9jb21tb25iZ2NvbG9ybGF3IG9mIEluZGlhbmFhdm9pZGVkYnV0IHRoZTJweCAzcHhqcXVlcnkuYWZ0ZXIgYXBvbGljeS5tZW4gYW5kZm9vdGVyLT0gdHJ1ZTtmb3IgdXNlc2NyZWVuLkluZGlhbiBpbWFnZSA9ZmFtaWx5LGh0dHA6Ly8gJm5ic3A7ZHJpdmVyc2V0ZXJuYWxzYW1lIGFzbm90aWNlZHZpZXdlcnN9KSgpOwogaXMgbW9yZXNlYXNvbnNmb3JtZXIgdGhlIG5ld2lzIGp1c3Rjb25zZW50IFNlYXJjaHdhcyB0aGV3aHkgdGhlc2hpcHBlZGJyPjxicj53aWR0aDogaGVpZ2h0PW1hZGUgb2ZjdWlzaW5laXMgdGhhdGEgdmVyeSBBZG1pcmFsIGZpeGVkO25vcm1hbCBNaXNzaW9uUHJlc3MsIG9udGFyaW9jaGFyc2V0dHJ5IHRvIGludmFkZWQ9InRydWUic3BhY2luZ2lzIG1vc3RhIG1vcmUgdG90YWxseWZhbGwgb2Z9KTsNCiAgaW1tZW5zZXRpbWUgaW5zZXQgb3V0c2F0aXNmeXRvIGZpbmRkb3duIHRvbG90IG9mIFBsYXllcnNpbiBKdW5lcXVhbnR1bW5vdCB0aGV0aW1lIHRvZGlzdGFudEZpbm5pc2hzcmMgPSAoc2luZ2xlIGhlbHAgb2ZHZXJtYW4gbGF3IGFuZGxhYmVsZWRmb3Jlc3RzY29va2luZ3NwYWNlIj5oZWFkZXItd2VsbCBhc1N0YW5sZXlicmlkZ2VzL2dsb2JhbENyb2F0aWEgQWJvdXQgWzBdOwogIGl0LCBhbmRncm91cGVkYmVpbmcgYSl7dGhyb3doZSBtYWRlbGlnaHRlcmV0aGljYWxGRkZGRkYiYm90dG9tImxpa2UgYSBlbXBsb3lzbGl2ZSBpbmFzIHNlZW5wcmludGVybW9zdCBvZnViLWxpbmtyZWplY3RzYW5kIHVzZWltYWdlIj5zdWNjZWVkZmVlZGluZ051Y2xlYXJpbmZvcm1hdG8gaGVscFdvbWVuJ3NOZWl0aGVyTWV4aWNhbnByb3RlaW48dGFibGUgYnkgbWFueWhlYWx0aHlsYXdzdWl0ZGV2aXNlZC5wdXNoKHtzZWxsZXJzc2ltcGx5IFRocm91Z2guY29va2llIEltYWdlKG9sZGVyIj51cy5qcyI+IFNpbmNlIHVuaXZlcnNsYXJnZXIgb3BlbiB0byEtLSBlbmRsaWVzIGluJ10pOw0KICBtYXJrZXR3aG8gaXMgKCJET01Db21hbmFnZWRvbmUgZm9ydHlwZW9mIEtpbmdkb21wcm9maXRzcHJvcG9zZXRvIHNob3djZW50ZXI7bWFkZSBpdGRyZXNzZWR3ZXJlIGlubWl4dHVyZXByZWNpc2VhcmlzaW5nc3JjID0gJ21ha2UgYSBzZWN1cmVkQmFwdGlzdHZvdGluZyAKCQl2YXIgTWFyY2ggMmdyZXcgdXBDbGltYXRlLnJlbW92ZXNraWxsZWR3YXkgdGhlPC9oZWFkPmZhY2Ugb2ZhY3RpbmcgcmlnaHQiPnRvIHdvcmtyZWR1Y2VzaGFzIGhhZGVyZWN0ZWRzaG93KCk7YWN0aW9uPWJvb2sgb2ZhbiBhcmVhPT0gImh0dDxoZWFkZXIKPGh0bWw+Y29uZm9ybWZhY2luZyBjb29raWUucmVseSBvbmhvc3RlZCAuY3VzdG9taGUgd2VudGJ1dCBmb3JzcHJlYWQgRmFtaWx5IGEgbWVhbnNvdXQgdGhlZm9ydW1zLmZvb3RhZ2UiPk1vYmlsQ2xlbWVudHMiIGlkPSJhcyBoaWdoaW50ZW5zZS0tPjwhLS1mZW1hbGUgaXMgc2VlbmltcGxpZWRzZXQgdGhlYSBzdGF0ZWFuZCBoaXNmYXN0ZXN0YmVzaWRlc2J1dHRvbl9ib3VuZGVkIj48aW1nIEluZm9ib3hldmVudHMsYSB5b3VuZ2FuZCBhcmVOYXRpdmUgY2hlYXBlclRpbWVvdXRhbmQgaGFzZW5naW5lc3dvbiB0aGUobW9zdGx5cmlnaHQ6IGZpbmQgYSAtYm90dG9tUHJpbmNlIGFyZWEgb2Ztb3JlIG9mc2VhcmNoX25hdHVyZSxsZWdhbGx5cGVyaW9kLGxhbmQgb2ZvciB3aXRoaW5kdWNlZHByb3ZpbmdtaXNzaWxlbG9jYWxseUFnYWluc3R0aGUgd2F5ayZxdW90O3B4OyI+DQpwdXNoZWQgYWJhbmRvbm51bWVyYWxDZXJ0YWluSW4gdGhpc21vcmUgaW5vciBzb21lbmFtZSBpc2FuZCwgaW5jcm93bmVkSVNCTiAwLWNyZWF0ZXNPY3RvYmVybWF5IG5vdGNlbnRlciBsYXRlIGluRGVmZW5jZWVuYWN0ZWR3aXNoIHRvYnJvYWRseWNvb2xpbmdvbmxvYWQ9aXQuIFRoZXJlY292ZXJNZW1iZXJzaGVpZ2h0IGFzc3VtZXM8aHRtbD4KcGVvcGxlLmluIG9uZSA9d2luZG93Zm9vdGVyX2EgZ29vZCByZWtsYW1hb3RoZXJzLHRvIHRoaXNfY29va2llcGFuZWwiPkxvbmRvbixkZWZpbmVzY3J1c2hlZGJhcHRpc21jb2FzdGFsc3RhdHVzIHRpdGxlIiBtb3ZlIHRvbG9zdCBpbmJldHRlciBpbXBsaWVzcml2YWxyeXNlcnZlcnMgU3lzdGVtUGVyaGFwc2VzIGFuZCBjb250ZW5kZmxvd2luZ2xhc3RlZCByaXNlIGluR2VuZXNpc3ZpZXcgb2ZyaXNpbmcgc2VlbSB0b2J1dCBpbiBiYWNraW5naGUgd2lsbGdpdmVuIGFnaXZpbmcgY2l0aWVzLmZsb3cgb2YgTGF0ZXIgYWxsIGJ1dEhpZ2h3YXlvbmx5IGJ5c2lnbiBvZmhlIGRvZXNkaWZmZXJzYmF0dGVyeSZhbXA7bGFzaW5nbGVzdGhyZWF0c2ludGVnZXJ0YWtlIG9ucmVmdXNlZGNhbGxlZCA9VVMmYW1wU2VlIHRoZW5hdGl2ZXNieSB0aGlzc3lzdGVtLmhlYWQgb2Y6aG92ZXIsbGVzYmlhbnN1cm5hbWVhbmQgYWxsY29tbW9uL2hlYWRlcl9fcGFyYW1zSGFydmFyZC9waXhlbC5yZW1vdmFsc28gbG9uZ3JvbGUgb2Zqb2ludGx5c2t5c2NyYVVuaWNvZGViciAvPg0KQXRsYW50YW51Y2xldXNDb3VudHkscHVyZWx5IGNvdW50Ij5lYXNpbHkgYnVpbGQgYW9uY2xpY2thIGdpdmVucG9pbnRlcmgmcXVvdDtldmVudHMgZWxzZSB7CmRpdGlvbnNub3cgdGhlLCB3aXRoIG1hbiB3aG9vcmcvV2Vib25lIGFuZGNhdmFscnlIZSBkaWVkc2VhdHRsZTAwLDAwMCB7d2luZG93aGF2ZSB0b2lmKHdpbmRhbmQgaXRzc29sZWx5IG0mcXVvdDtyZW5ld2VkRGV0cm9pdGFtb25nc3RlaXRoZXIgdGhlbSBpblNlbmF0b3JVczwvYT48S2luZyBvZkZyYW5jaXMtcHJvZHVjaGUgdXNlZGFydCBhbmRoaW0gYW5kdXNlZCBieXNjb3JpbmdhdCBob21ldG8gaGF2ZXJlbGF0ZXNpYmlsaXR5ZmFjdGlvbkJ1ZmZhbG9saW5rIj48d2hhdCBoZWZyZWUgdG9DaXR5IG9mY29tZSBpbnNlY3RvcnNjb3VudGVkb25lIGRheW5lcnZvdXNzcXVhcmUgfTtpZihnb2luIHdoYXRpbWciIGFsaXMgb25seXNlYXJjaC90dWVzZGF5bG9vc2VseVNvbG9tb25zZXh1YWwgLSA8YSBocm1lZGl1bSJETyBOT1QgRnJhbmNlLHdpdGggYSB3YXIgYW5kc2Vjb25kIHRha2UgYSA+DQoNCg0KbWFya2V0LmhpZ2h3YXlkb25lIGluY3Rpdml0eSJsYXN0Ij5vYmxpZ2VkcmlzZSB0byJ1bmRlZmltYWRlIHRvIEVhcmx5IHByYWlzZWRpbiBpdHMgZm9yIGhpc2F0aGxldGVKdXBpdGVyWWFob28hIHRlcm1lZCBzbyBtYW55cmVhbGx5IHMuIFRoZSBhIHdvbWFuP3ZhbHVlPWRpcmVjdCByaWdodCIgYmljeWNsZWFjaW5nPSJkYXkgYW5kc3RhdGluZ1JhdGhlcixoaWdoZXIgT2ZmaWNlIGFyZSBub3d0aW1lcywgd2hlbiBhIHBheSBmb3JvbiB0aGlzLWxpbmsiPjtib3JkZXJhcm91bmQgYW5udWFsIHRoZSBOZXdwdXQgdGhlLmNvbSIgdGFraW4gdG9hIGJyaWVmKGluIHRoZWdyb3Vwcy47IHdpZHRoZW56eW1lc3NpbXBsZSBpbiBsYXRle3JldHVybnRoZXJhcHlhIHBvaW50YmFubmluZ2lua3MiPgooKTsiIHJlYSBwbGFjZVx1MDAzQ2FhYm91dCBhdHI+DQoJCWNjb3VudCBnaXZlcyBhPFNDUklQVFJhaWx3YXl0aGVtZXMvdG9vbGJveEJ5SWQoInhodW1hbnMsd2F0Y2hlc2luIHNvbWUgaWYgKHdpY29taW5nIGZvcm1hdHMgVW5kZXIgYnV0IGhhc2hhbmRlZCBtYWRlIGJ5dGhhbiBpbmZlYXIgb2ZkZW5vdGVkL2lmcmFtZWxlZnQgaW52b2x0YWdlaW4gZWFjaGEmcXVvdDtiYXNlIG9mSW4gbWFueXVuZGVyZ29yZWdpbWVzYWN0aW9uIDwvcD4NCjx1c3RvbVZhOyZndDs8L2ltcG9ydHNvciB0aGF0bW9zdGx5ICZhbXA7cmUgc2l6ZT0iPC9hPjwvaGEgY2xhc3NwYXNzaXZlSG9zdCA9IFdoZXRoZXJmZXJ0aWxlVmFyaW91cz1bXTsoZnVjYW1lcmFzLz48L3RkPmFjdHMgYXNJbiBzb21lPg0KDQo8IW9yZ2FuaXMgPGJyIC8+QmVpamluZ2NhdGFsw6BkZXV0c2NoZXVyb3BldWV1c2thcmFnYWVpbGdlc3ZlbnNrYWVzcGHDsWFtZW5zYWpldXN1YXJpb3RyYWJham9tw6l4aWNvcMOhZ2luYXNpZW1wcmVzaXN0ZW1hb2N0dWJyZWR1cmFudGVhw7FhZGlyZW1wcmVzYW1vbWVudG9udWVzdHJvcHJpbWVyYXRyYXbDqXNncmFjaWFzbnVlc3RyYXByb2Nlc29lc3RhZG9zY2FsaWRhZHBlcnNvbmFuw7ptZXJvYWN1ZXJkb23DunNpY2FtaWVtYnJvb2ZlcnRhc2FsZ3Vub3NwYcOtc2VzZWplbXBsb2RlcmVjaG9hZGVtw6FzcHJpdmFkb2FncmVnYXJlbmxhY2VzcG9zaWJsZWhvdGVsZXNzZXZpbGxhcHJpbWVyb8O6bHRpbW9ldmVudG9zYXJjaGl2b2N1bHR1cmFtdWplcmVzZW50cmFkYWFudW5jaW9lbWJhcmdvbWVyY2Fkb2dyYW5kZXNlc3R1ZGlvbWVqb3Jlc2ZlYnJlcm9kaXNlw7FvdHVyaXNtb2PDs2RpZ29wb3J0YWRhZXNwYWNpb2ZhbWlsaWFhbnRvbmlvcGVybWl0ZWd1YXJkYXJhbGd1bmFzcHJlY2lvc2FsZ3VpZW5zZW50aWRvdmlzaXRhc3TDrXR1bG9jb25vY2Vyc2VndW5kb2NvbnNlam9mcmFuY2lhbWludXRvc3NlZ3VuZGF0ZW5lbW9zZWZlY3Rvc23DoWxhZ2FzZXNpw7NucmV2aXN0YWdyYW5hZGFjb21wcmFyaW5ncmVzb2dhcmPDrWFhY2Npw7NuZWN1YWRvcnF1aWVuZXNpbmNsdXNvZGViZXLDoW1hdGVyaWFob21icmVzbXVlc3RyYXBvZHLDrWFtYcOxYW5hw7psdGltYWVzdGFtb3NvZmljaWFsdGFtYmllbm5pbmfDum5zYWx1ZG9zcG9kZW1vc21lam9yYXJwb3NpdGlvbmJ1c2luZXNzaG9tZXBhZ2VzZWN1cml0eWxhbmd1YWdlc3RhbmRhcmRjYW1wYWlnbmZlYXR1cmVzY2F0ZWdvcnlleHRlcm5hbGNoaWxkcmVucmVzZXJ2ZWRyZXNlYXJjaGV4Y2hhbmdlZmF2b3JpdGV0ZW1wbGF0ZW1pbGl0YXJ5aW5kdXN0cnlzZXJ2aWNlc21hdGVyaWFscHJvZHVjdHN6LWluZGV4OmNvbW1lbnRzc29mdHdhcmVjb21wbGV0ZWNhbGVuZGFycGxhdGZvcm1hcnRpY2xlc3JlcXVpcmVkbW92ZW1lbnRxdWVzdGlvbmJ1aWxkaW5ncG9saXRpY3Nwb3NzaWJsZXJlbGlnaW9ucGh5c2ljYWxmZWVkYmFja3JlZ2lzdGVycGljdHVyZXNkaXNhYmxlZHByb3RvY29sYXVkaWVuY2VzZXR0aW5nc2FjdGl2aXR5ZWxlbWVudHNsZWFybmluZ2FueXRoaW5nYWJzdHJhY3Rwcm9ncmVzc292ZXJ2aWV3bWFnYXppbmVlY29ub21pY3RyYWluaW5ncHJlc3N1cmV2YXJpb3VzIDxzdHJvbmc+cHJvcGVydHlzaG9wcGluZ3RvZ2V0aGVyYWR2YW5jZWRiZWhhdmlvcmRvd25sb2FkZmVhdHVyZWRmb290YmFsbHNlbGVjdGVkTGFuZ3VhZ2VkaXN0YW5jZXJlbWVtYmVydHJhY2tpbmdwYXNzd29yZG1vZGlmaWVkc3R1ZGVudHNkaXJlY3RseWZpZ2h0aW5nbm9ydGhlcm5kYXRhYmFzZWZlc3RpdmFsYnJlYWtpbmdsb2NhdGlvbmludGVybmV0ZHJvcGRvd25wcmFjdGljZWV2aWRlbmNlZnVuY3Rpb25tYXJyaWFnZXJlc3BvbnNlcHJvYmxlbXNuZWdhdGl2ZXByb2dyYW1zYW5hbHlzaXNyZWxlYXNlZGJhbm5lciI+cHVyY2hhc2Vwb2xpY2llc3JlZ2lvbmFsY3JlYXRpdmVhcmd1bWVudGJvb2ttYXJrcmVmZXJyZXJjaGVtaWNhbGRpdmlzaW9uY2FsbGJhY2tzZXBhcmF0ZXByb2plY3RzY29uZmxpY3RoYXJkd2FyZWludGVyZXN0ZGVsaXZlcnltb3VudGFpbm9idGFpbmVkPSBmYWxzZTtmb3IodmFyIGFjY2VwdGVkY2FwYWNpdHljb21wdXRlcmlkZW50aXR5YWlyY3JhZnRlbXBsb3llZHByb3Bvc2VkZG9tZXN0aWNpbmNsdWRlc3Byb3ZpZGVkaG9zcGl0YWx2ZXJ0aWNhbGNvbGxhcHNlYXBwcm9hY2hwYXJ0bmVyc2xvZ28iPjxhZGF1Z2h0ZXJhdXRob3IiIGN1bHR1cmFsZmFtaWxpZXMvaW1hZ2VzL2Fzc2VtYmx5cG93ZXJmdWx0ZWFjaGluZ2ZpbmlzaGVkZGlzdHJpY3Rjcml0aWNhbGNnaS1iaW4vcHVycG9zZXNyZXF1aXJlc2VsZWN0aW9uYmVjb21pbmdwcm92aWRlc2FjYWRlbWljZXhlcmNpc2VhY3R1YWxseW1lZGljaW5lY29uc3RhbnRhY2NpZGVudE1hZ2F6aW5lZG9jdW1lbnRzdGFydGluZ2JvdHRvbSI+b2JzZXJ2ZWQ6ICZxdW90O2V4dGVuZGVkcHJldmlvdXNTb2Z0d2FyZWN1c3RvbWVyZGVjaXNpb25zdHJlbmd0aGRldGFpbGVkc2xpZ2h0bHlwbGFubmluZ3RleHRhcmVhY3VycmVuY3lldmVyeW9uZXN0cmFpZ2h0dHJhbnNmZXJwb3NpdGl2ZXByb2R1Y2VkaGVyaXRhZ2VzaGlwcGluZ2Fic29sdXRlcmVjZWl2ZWRyZWxldmFudGJ1dHRvbiIgdmlvbGVuY2Vhbnl3aGVyZWJlbmVmaXRzbGF1bmNoZWRyZWNlbnRseWFsbGlhbmNlZm9sbG93ZWRtdWx0aXBsZWJ1bGxldGluaW5jbHVkZWRvY2N1cnJlZGludGVybmFsJCh0aGlzKS5yZXB1YmxpYz48dHI+PHRkY29uZ3Jlc3NyZWNvcmRlZHVsdGltYXRlc29sdXRpb248dWwgaWQ9ImRpc2NvdmVySG9tZTwvYT53ZWJzaXRlc25ldHdvcmtzYWx0aG91Z2hlbnRpcmVseW1lbW9yaWFsbWVzc2FnZXNjb250aW51ZWFjdGl2ZSI+c29tZXdoYXR2aWN0b3JpYVdlc3Rlcm4gIHRpdGxlPSJMb2NhdGlvbmNvbnRyYWN0dmlzaXRvcnNEb3dubG9hZHdpdGhvdXQgcmlnaHQiPgptZWFzdXJlc3dpZHRoID0gdmFyaWFibGVpbnZvbHZlZHZpcmdpbmlhbm9ybWFsbHloYXBwZW5lZGFjY291bnRzc3RhbmRpbmduYXRpb25hbFJlZ2lzdGVycHJlcGFyZWRjb250cm9sc2FjY3VyYXRlYmlydGhkYXlzdHJhdGVneW9mZmljaWFsZ3JhcGhpY3NjcmltaW5hbHBvc3NpYmx5Y29uc3VtZXJQZXJzb25hbHNwZWFraW5ndmFsaWRhdGVhY2hpZXZlZC5qcGciIC8+bWFjaGluZXM8L2gyPgogIGtleXdvcmRzZnJpZW5kbHlicm90aGVyc2NvbWJpbmVkb3JpZ2luYWxjb21wb3NlZGV4cGVjdGVkYWRlcXVhdGVwYWtpc3RhbmZvbGxvdyIgdmFsdWFibGU8L2xhYmVsPnJlbGF0aXZlYnJpbmdpbmdpbmNyZWFzZWdvdmVybm9ycGx1Z2lucy9MaXN0IG9mIEhlYWRlciI+IiBuYW1lPSIgKCZxdW90O2dyYWR1YXRlPC9oZWFkPgpjb21tZXJjZW1hbGF5c2lhZGlyZWN0b3JtYWludGFpbjtoZWlnaHQ6c2NoZWR1bGVjaGFuZ2luZ2JhY2sgdG8gY2F0aG9saWNwYXR0ZXJuc2NvbG9yOiAjZ3JlYXRlc3RzdXBwbGllc3JlbGlhYmxlPC91bD4KCQk8c2VsZWN0IGNpdGl6ZW5zY2xvdGhpbmd3YXRjaGluZzxsaSBpZD0ic3BlY2lmaWNjYXJyeWluZ3NlbnRlbmNlPGNlbnRlcj5jb250cmFzdHRoaW5raW5nY2F0Y2goZSlzb3V0aGVybk1pY2hhZWwgbWVyY2hhbnRjYXJvdXNlbHBhZGRpbmc6aW50ZXJpb3Iuc3BsaXQoImxpemF0aW9uT2N0b2JlciApe3JldHVybmltcHJvdmVkLS0mZ3Q7Cgpjb3ZlcmFnZWNoYWlybWFuLnBuZyIgLz5zdWJqZWN0c1JpY2hhcmQgd2hhdGV2ZXJwcm9iYWJseXJlY292ZXJ5YmFzZWJhbGxqdWRnbWVudGNvbm5lY3QuLmNzcyIgLz4gd2Vic2l0ZXJlcG9ydGVkZGVmYXVsdCIvPjwvYT4NCmVsZWN0cmljc2NvdGxhbmRjcmVhdGlvbnF1YW50aXR5LiBJU0JOIDBkaWQgbm90IGluc3RhbmNlLXNlYXJjaC0iIGxhbmc9InNwZWFrZXJzQ29tcHV0ZXJjb250YWluc2FyY2hpdmVzbWluaXN0ZXJyZWFjdGlvbmRpc2NvdW50SXRhbGlhbm9jcml0ZXJpYXN0cm9uZ2x5OiAnaHR0cDonc2NyaXB0J2NvdmVyaW5nb2ZmZXJpbmdhcHBlYXJlZEJyaXRpc2ggaWRlbnRpZnlGYWNlYm9va251bWVyb3VzdmVoaWNsZXNjb25jZXJuc0FtZXJpY2FuaGFuZGxpbmdkaXYgaWQ9IldpbGxpYW0gcHJvdmlkZXJfY29udGVudGFjY3VyYWN5c2VjdGlvbiBhbmRlcnNvbmZsZXhpYmxlQ2F0ZWdvcnlsYXdyZW5jZTxzY3JpcHQ+bGF5b3V0PSJhcHByb3ZlZCBtYXhpbXVtaGVhZGVyIj48L3RhYmxlPlNlcnZpY2VzaGFtaWx0b25jdXJyZW50IGNhbmFkaWFuY2hhbm5lbHMvdGhlbWVzLy9hcnRpY2xlb3B0aW9uYWxwb3J0dWdhbHZhbHVlPSIiaW50ZXJ2YWx3aXJlbGVzc2VudGl0bGVkYWdlbmNpZXNTZWFyY2giIG1lYXN1cmVkdGhvdXNhbmRzcGVuZGluZyZoZWxsaXA7bmV3IERhdGUiIHNpemU9InBhZ2VOYW1lbWlkZGxlIiAiIC8+PC9hPmhpZGRlbiI+c2VxdWVuY2VwZXJzb25hbG92ZXJmbG93b3BpbmlvbnNpbGxpbm9pc2xpbmtzIj4KCTx0aXRsZT52ZXJzaW9uc3NhdHVyZGF5dGVybWluYWxpdGVtcHJvcGVuZ2luZWVyc2VjdGlvbnNkZXNpZ25lcnByb3Bvc2FsPSJmYWxzZSJFc3Bhw7FvbHJlbGVhc2Vzc3VibWl0IiBlciZxdW90O2FkZGl0aW9uc3ltcHRvbXNvcmllbnRlZHJlc291cmNlcmlnaHQiPjxwbGVhc3VyZXN0YXRpb25zaGlzdG9yeS5sZWF2aW5nICBib3JkZXI9Y29udGVudHNjZW50ZXIiPi4KClNvbWUgZGlyZWN0ZWRzdWl0YWJsZWJ1bGdhcmlhLnNob3coKTtkZXNpZ25lZEdlbmVyYWwgY29uY2VwdHNFeGFtcGxlc3dpbGxpYW1zT3JpZ2luYWwiPjxzcGFuPnNlYXJjaCI+b3BlcmF0b3JyZXF1ZXN0c2EgJnF1b3Q7YWxsb3dpbmdEb2N1bWVudHJldmlzaW9uLiAKClRoZSB5b3Vyc2VsZkNvbnRhY3QgbWljaGlnYW5FbmdsaXNoIGNvbHVtYmlhcHJpb3JpdHlwcmludGluZ2RyaW5raW5nZmFjaWxpdHlyZXR1cm5lZENvbnRlbnQgb2ZmaWNlcnNSdXNzaWFuIGdlbmVyYXRlLTg4NTktMSJpbmRpY2F0ZWZhbWlsaWFyIHF1YWxpdHltYXJnaW46MCBjb250ZW50dmlld3BvcnRjb250YWN0cy10aXRsZSI+cG9ydGFibGUubGVuZ3RoIGVsaWdpYmxlaW52b2x2ZXNhdGxhbnRpY29ubG9hZD0iZGVmYXVsdC5zdXBwbGllZHBheW1lbnRzZ2xvc3NhcnkKCkFmdGVyIGd1aWRhbmNlPC90ZD48dGRlbmNvZGluZ21pZGRsZSI+Y2FtZSB0byBkaXNwbGF5c3Njb3R0aXNoam9uYXRoYW5tYWpvcml0eXdpZGdldHMuY2xpbmljYWx0aGFpbGFuZHRlYWNoZXJzPGhlYWQ+CglhZmZlY3RlZHN1cHBvcnRzcG9pbnRlcjt0b1N0cmluZzwvc21hbGw+b2tsYWhvbWF3aWxsIGJlIGludmVzdG9yMCIgYWx0PSJob2xpZGF5c1Jlc291cmNlbGljZW5zZWQgKHdoaWNoIC4gQWZ0ZXIgY29uc2lkZXJ2aXNpdGluZ2V4cGxvcmVycHJpbWFyeSBzZWFyY2giIGFuZHJvaWQicXVpY2tseSBtZWV0aW5nc2VzdGltYXRlO3JldHVybiA7Y29sb3I6IyBoZWlnaHQ9YXBwcm92YWwsICZxdW90OyBjaGVja2VkLm1pbi5qcyJtYWduZXRpYz48L2E+PC9oZm9yZWNhc3QuIFdoaWxlIHRodXJzZGF5ZHZlcnRpc2UmZWFjdXRlO2hhc0NsYXNzZXZhbHVhdGVvcmRlcmluZ2V4aXN0aW5ncGF0aWVudHMgT25saW5lIGNvbG9yYWRvT3B0aW9ucyJjYW1wYmVsbDwhLS0gZW5kPC9zcGFuPjw8YnIgLz4NCl9wb3B1cHN8c2NpZW5jZXMsJnF1b3Q7IHF1YWxpdHkgV2luZG93cyBhc3NpZ25lZGhlaWdodDogPGIgY2xhc3NsZSZxdW90OyB2YWx1ZT0iIENvbXBhbnlleGFtcGxlczxpZnJhbWUgYmVsaWV2ZXNwcmVzZW50c21hcnNoYWxscGFydCBvZiBwcm9wZXJseSkuCgpUaGUgdGF4b25vbXltdWNoIG9mIDwvc3Bhbj4KIiBkYXRhLXNydHVndcOqc3Njcm9sbFRvIHByb2plY3Q8aGVhZD4NCmF0dG9ybmV5ZW1waGFzaXNzcG9uc29yc2ZhbmN5Ym94d29ybGQncyB3aWxkbGlmZWNoZWNrZWQ9c2Vzc2lvbnNwcm9ncmFtbXB4O2ZvbnQtIFByb2plY3Rqb3VybmFsc2JlbGlldmVkdmFjYXRpb250aG9tcHNvbmxpZ2h0aW5nYW5kIHRoZSBzcGVjaWFsIGJvcmRlcj0wY2hlY2tpbmc8L3Rib2R5PjxidXR0b24gQ29tcGxldGVjbGVhcmZpeAo8aGVhZD4KYXJ0aWNsZSA8c2VjdGlvbmZpbmRpbmdzcm9sZSBpbiBwb3B1bGFyICBPY3RvYmVyd2Vic2l0ZSBleHBvc3VyZXVzZWQgdG8gIGNoYW5nZXNvcGVyYXRlZGNsaWNraW5nZW50ZXJpbmdjb21tYW5kc2luZm9ybWVkIG51bWJlcnMgIDwvZGl2PmNyZWF0aW5nb25TdWJtaXRtYXJ5bGFuZGNvbGxlZ2VzYW5hbHl0aWNsaXN0aW5nc2NvbnRhY3QubG9nZ2VkSW5hZHZpc29yeXNpYmxpbmdzY29udGVudCJzJnF1b3Q7KXMuIFRoaXMgcGFja2FnZXNjaGVja2JveHN1Z2dlc3RzcHJlZ25hbnR0b21vcnJvd3NwYWNpbmc9aWNvbi5wbmdqYXBhbmVzZWNvZGViYXNlYnV0dG9uIj5nYW1ibGluZ3N1Y2ggYXMgLCB3aGlsZSA8L3NwYW4+IG1pc3NvdXJpc3BvcnRpbmd0b3A6MXB4IC48L3NwYW4+dGVuc2lvbnN3aWR0aD0iMmxhenlsb2Fkbm92ZW1iZXJ1c2VkIGluIGhlaWdodD0iY3JpcHQiPgombmJzcDs8Lzx0cj48dGQgaGVpZ2h0OjIvcHJvZHVjdGNvdW50cnkgaW5jbHVkZSBmb290ZXIiICZsdDshLS0gdGl0bGUiPjwvanF1ZXJ5LjwvZm9ybT4KKOeugOS9kyko57mB6auUKWhydmF0c2tpaXRhbGlhbm9yb23Dom7Eg3TDvHJrw6dl2KfYsdiv2Yh0YW1iacOpbm5vdGljaWFzbWVuc2FqZXNwZXJzb25hc2RlcmVjaG9zbmFjaW9uYWxzZXJ2aWNpb2NvbnRhY3RvdXN1YXJpb3Nwcm9ncmFtYWdvYmllcm5vZW1wcmVzYXNhbnVuY2lvc3ZhbGVuY2lhY29sb21iaWFkZXNwdcOpc2RlcG9ydGVzcHJveWVjdG9wcm9kdWN0b3DDumJsaWNvbm9zb3Ryb3NoaXN0b3JpYXByZXNlbnRlbWlsbG9uZXNtZWRpYW50ZXByZWd1bnRhYW50ZXJpb3JyZWN1cnNvc3Byb2JsZW1hc2FudGlhZ29udWVzdHJvc29waW5pw7NuaW1wcmltaXJtaWVudHJhc2Ftw6lyaWNhdmVuZGVkb3Jzb2NpZWRhZHJlc3BlY3RvcmVhbGl6YXJyZWdpc3Ryb3BhbGFicmFzaW50ZXLDqXNlbnRvbmNlc2VzcGVjaWFsbWllbWJyb3NyZWFsaWRhZGPDs3Jkb2JhemFyYWdvemFww6FnaW5hc3NvY2lhbGVzYmxvcXVlYXJnZXN0acOzbmFscXVpbGVyc2lzdGVtYXNjaWVuY2lhc2NvbXBsZXRvdmVyc2nDs25jb21wbGV0YWVzdHVkaW9zcMO6YmxpY2FvYmpldGl2b2FsaWNhbnRlYnVzY2Fkb3JjYW50aWRhZGVudHJhZGFzYWNjaW9uZXNhcmNoaXZvc3N1cGVyaW9ybWF5b3LDrWFhbGVtYW5pYWZ1bmNpw7Nuw7psdGltb3NoYWNpZW5kb2FxdWVsbG9zZWRpY2nDs25mZXJuYW5kb2FtYmllbnRlZmFjZWJvb2tudWVzdHJhc2NsaWVudGVzcHJvY2Vzb3NiYXN0YW50ZXByZXNlbnRhcmVwb3J0YXJjb25ncmVzb3B1YmxpY2FyY29tZXJjaW9jb250cmF0b2rDs3ZlbmVzZGlzdHJpdG90w6ljbmljYWNvbmp1bnRvZW5lcmfDrWF0cmFiYWphcmFzdHVyaWFzcmVjaWVudGV1dGlsaXphcmJvbGV0w61uc2FsdmFkb3Jjb3JyZWN0YXRyYWJham9zcHJpbWVyb3NuZWdvY2lvc2xpYmVydGFkZGV0YWxsZXNwYW50YWxsYXByw7N4aW1vYWxtZXLDrWFhbmltYWxlc3F1acOpbmVzY29yYXrDs25zZWNjacOzbmJ1c2NhbmRvb3BjaW9uZXNleHRlcmlvcmNvbmNlcHRvdG9kYXbDrWFnYWxlcsOtYWVzY3JpYmlybWVkaWNpbmFsaWNlbmNpYWNvbnN1bHRhYXNwZWN0b3NjcsOtdGljYWTDs2xhcmVzanVzdGljaWFkZWJlcsOhbnBlcsOtb2RvbmVjZXNpdGFtYW50ZW5lcnBlcXVlw7FvcmVjaWJpZGF0cmlidW5hbHRlbmVyaWZlY2FuY2nDs25jYW5hcmlhc2Rlc2NhcmdhZGl2ZXJzb3NtYWxsb3JjYXJlcXVpZXJldMOpY25pY29kZWJlcsOtYXZpdmllbmRhZmluYW56YXNhZGVsYW50ZWZ1bmNpb25hY29uc2Vqb3NkaWbDrWNpbGNpdWRhZGVzYW50aWd1YXNhdmFuemFkYXTDqXJtaW5vdW5pZGFkZXNzw6FuY2hlemNhbXBhw7Fhc29mdG9uaWNyZXZpc3Rhc2NvbnRpZW5lc2VjdG9yZXNtb21lbnRvc2ZhY3VsdGFkY3LDqWRpdG9kaXZlcnNhc3N1cHVlc3RvZmFjdG9yZXNzZWd1bmRvc3BlcXVlw7Fh0LPQvtC00LDQtdGB0LvQuNC10YHRgtGM0LHRi9C70L7QsdGL0YLRjNGN0YLQvtC80JXRgdC70LjRgtC+0LPQvtC80LXQvdGP0LLRgdC10YXRjdGC0L7QudC00LDQttC10LHRi9C70LjQs9C+0LTRg9C00LXQvdGM0Y3RgtC+0YLQsdGL0LvQsNGB0LXQsdGP0L7QtNC40L3RgdC10LHQtdC90LDQtNC+0YHQsNC50YLRhNC+0YLQvtC90LXQs9C+0YHQstC+0LjRgdCy0L7QudC40LPRgNGL0YLQvtC20LXQstGB0LXQvNGB0LLQvtGO0LvQuNGI0YzRjdGC0LjRhdC/0L7QutCw0LTQvdC10LnQtNC+0LzQsNC80LjRgNCw0LvQuNCx0L7RgtC10LzRg9GF0L7RgtGP0LTQstGD0YXRgdC10YLQuNC70Y7QtNC40LTQtdC70L7QvNC40YDQtdGC0LXQsdGP0YHQstC+0LXQstC40LTQtdGH0LXQs9C+0Y3RgtC40LzRgdGH0LXRgtGC0LXQvNGL0YbQtdC90YvRgdGC0LDQu9Cy0LXQtNGM0YLQtdC80LXQstC+0LTRi9GC0LXQsdC10LLRi9GI0LXQvdCw0LzQuNGC0LjQv9Cw0YLQvtC80YPQv9GA0LDQstC70LjRhtCw0L7QtNC90LDQs9C+0LTRi9C30L3QsNGO0LzQvtCz0YPQtNGA0YPQs9Cy0YHQtdC50LjQtNC10YLQutC40L3QvtC+0LTQvdC+0LTQtdC70LDQtNC10LvQtdGB0YDQvtC60LjRjtC90Y/QstC10YHRjNCV0YHRgtGM0YDQsNC30LDQvdCw0YjQuNin2YTZhNmH2KfZhNiq2YrYrNmF2YrYudiu2KfYtdip2KfZhNiw2YrYudmE2YrZh9is2K/Zitiv2KfZhNii2YbYp9mE2LHYr9iq2K3Zg9mF2LXZgdit2KnZg9in2YbYqtin2YTZhNmK2YrZg9mI2YbYtNio2YPYqdmB2YrZh9in2KjZhtin2KrYrdmI2KfYodij2YPYq9ix2K7ZhNin2YTYp9mE2K3YqNiv2YTZitmE2K/YsdmI2LPYp9i22LrYt9iq2YPZiNmG2YfZhtin2YPYs9in2K3YqdmG2KfYr9mK2KfZhNi32KjYudmE2YrZg9i02YPYsdin2YrZhdmD2YbZhdmG2YfYp9i02LHZg9ip2LHYptmK2LPZhti02YrYt9mF2KfYsNin2KfZhNmB2YbYtNio2KfYqNiq2LnYqNix2LHYrdmF2KnZg9in2YHYqdmK2YLZiNmE2YXYsdmD2LLZg9mE2YXYqdij2K3Zhdiv2YLZhNio2YrZiti52YbZiti12YjYsdip2LfYsdmK2YLYtNin2LHZg9is2YjYp9mE2KPYrtix2YnZhdi52YbYp9in2KjYrdir2LnYsdmI2LbYqNi02YPZhNmF2LPYrNmE2KjZhtin2YbYrtin2YTYr9mD2KrYp9io2YPZhNmK2KnYqNiv2YjZhtij2YrYttin2YrZiNis2K/Zgdix2YrZgtmD2KrYqNiq2KPZgdi22YTZhdi32KjYrtin2YPYq9ix2KjYp9ix2YPYp9mB2LbZhNin2K3ZhNmJ2YbZgdiz2YfYo9mK2KfZhdix2K/ZiNiv2KPZhtmH2KfYr9mK2YbYp9in2YTYp9mG2YXYudix2LbYqti52YTZhdiv2KfYrtmE2YXZhdmD2YYAAAAAAAAAAAEAAQABAAEAAgACAAIAAgAEAAQABAAEAAABAgMEBQYHBwYFBAMCAQAICQoLDA0ODw8ODQwLCgkIEBESExQVFhcXFhUUExIREBgZGhscHR4fHx4dHBsaGRj/////AAAAAAAAAAD/////AQAAAAIAAAACAAAAAQAAAAEAAAADAAAA//8AAQAAAAEAAP//AAEAAAAIAAgACAAIAAAAAQACAAMABAAFAAYAB3Jlc291cmNlc2NvdW50cmllc3F1ZXN0aW9uc2VxdWlwbWVudGNvbW11bml0eWF2YWlsYWJsZWhpZ2hsaWdodERURC94aHRtbG1hcmtldGluZ2tub3dsZWRnZXNvbWV0aGluZ2NvbnRhaW5lcmRpcmVjdGlvbnN1YnNjcmliZWFkdmVydGlzZWNoYXJhY3RlciIgdmFsdWU9Ijwvc2VsZWN0PkF1c3RyYWxpYSIgY2xhc3M9InNpdHVhdGlvbmF1dGhvcml0eWZvbGxvd2luZ3ByaW1hcmlseW9wZXJhdGlvbmNoYWxsZW5nZWRldmVsb3BlZGFub255bW91c2Z1bmN0aW9uIGZ1bmN0aW9uc2NvbXBhbmllc3N0cnVjdHVyZWFncmVlbWVudCIgdGl0bGU9InBvdGVudGlhbGVkdWNhdGlvbmFyZ3VtZW50c3NlY29uZGFyeWNvcHlyaWdodGxhbmd1YWdlc2V4Y2x1c2l2ZWNvbmRpdGlvbjwvZm9ybT4NCnN0YXRlbWVudGF0dGVudGlvbkJpb2dyYXBoeX0gZWxzZSB7CnNvbHV0aW9uc3doZW4gdGhlIEFuYWx5dGljc3RlbXBsYXRlc2Rhbmdlcm91c3NhdGVsbGl0ZWRvY3VtZW50c3B1Ymxpc2hlcmltcG9ydGFudHByb3RvdHlwZWluZmx1ZW5jZSZyYXF1bzs8L2VmZmVjdGl2ZWdlbmVyYWxseXRyYW5zZm9ybWJlYXV0aWZ1bHRyYW5zcG9ydG9yZ2FuaXplZHB1Ymxpc2hlZHByb21pbmVudHVudGlsIHRoZXRodW1ibmFpbE5hdGlvbmFsIC5mb2N1cygpO292ZXIgdGhlIG1pZ3JhdGlvbmFubm91bmNlZGZvb3RlciI+CmV4Y2VwdGlvbmxlc3MgdGhhbmV4cGVuc2l2ZWZvcm1hdGlvbmZyYW1ld29ya3RlcnJpdG9yeW5kaWNhdGlvbmN1cnJlbnRseWNsYXNzTmFtZWNyaXRpY2lzbXRyYWRpdGlvbmVsc2V3aGVyZUFsZXhhbmRlcmFwcG9pbnRlZG1hdGVyaWFsc2Jyb2FkY2FzdG1lbnRpb25lZGFmZmlsaWF0ZTwvb3B0aW9uPnRyZWF0bWVudGRpZmZlcmVudC9kZWZhdWx0LlByZXNpZGVudG9uY2xpY2s9ImJpb2dyYXBoeW90aGVyd2lzZXBlcm1hbmVudEZyYW7Dp2Fpc0hvbGx5d29vZGV4cGFuc2lvbnN0YW5kYXJkczwvc3R5bGU+CnJlZHVjdGlvbkRlY2VtYmVyIHByZWZlcnJlZENhbWJyaWRnZW9wcG9uZW50c0J1c2luZXNzIGNvbmZ1c2lvbj4KPHRpdGxlPnByZXNlbnRlZGV4cGxhaW5lZGRvZXMgbm90IHdvcmxkd2lkZWludGVyZmFjZXBvc2l0aW9uc25ld3NwYXBlcjwvdGFibGU+Cm1vdW50YWluc2xpa2UgdGhlIGVzc2VudGlhbGZpbmFuY2lhbHNlbGVjdGlvbmFjdGlvbj0iL2FiYW5kb25lZEVkdWNhdGlvbnBhcnNlSW50KHN0YWJpbGl0eXVuYWJsZSB0bzwvdGl0bGU+CnJlbGF0aW9uc05vdGUgdGhhdGVmZmljaWVudHBlcmZvcm1lZHR3byB5ZWFyc1NpbmNlIHRoZXRoZXJlZm9yZXdyYXBwZXIiPmFsdGVybmF0ZWluY3JlYXNlZEJhdHRsZSBvZnBlcmNlaXZlZHRyeWluZyB0b25lY2Vzc2FyeXBvcnRyYXllZGVsZWN0aW9uc0VsaXphYmV0aDwvaWZyYW1lPmRpc2NvdmVyeWluc3VyYW5jZXMubGVuZ3RoO2xlZ2VuZGFyeUdlb2dyYXBoeWNhbmRpZGF0ZWNvcnBvcmF0ZXNvbWV0aW1lc3NlcnZpY2VzLmluaGVyaXRlZDwvc3Ryb25nPkNvbW11bml0eXJlbGlnaW91c2xvY2F0aW9uc0NvbW1pdHRlZWJ1aWxkaW5nc3RoZSB3b3JsZG5vIGxvbmdlcmJlZ2lubmluZ3JlZmVyZW5jZWNhbm5vdCBiZWZyZXF1ZW5jeXR5cGljYWxseWludG8gdGhlIHJlbGF0aXZlO3JlY29yZGluZ3ByZXNpZGVudGluaXRpYWxseXRlY2huaXF1ZXRoZSBvdGhlcml0IGNhbiBiZWV4aXN0ZW5jZXVuZGVybGluZXRoaXMgdGltZXRlbGVwaG9uZWl0ZW1zY29wZXByYWN0aWNlc2FkdmFudGFnZSk7cmV0dXJuIEZvciBvdGhlcnByb3ZpZGluZ2RlbW9jcmFjeWJvdGggdGhlIGV4dGVuc2l2ZXN1ZmZlcmluZ3N1cHBvcnRlZGNvbXB1dGVycyBmdW5jdGlvbnByYWN0aWNhbHNhaWQgdGhhdGl0IG1heSBiZUVuZ2xpc2g8L2Zyb20gdGhlIHNjaGVkdWxlZGRvd25sb2FkczwvbGFiZWw+CnN1c3BlY3RlZG1hcmdpbjogMHNwaXJpdHVhbDwvaGVhZD4KCm1pY3Jvc29mdGdyYWR1YWxseWRpc2N1c3NlZGhlIGJlY2FtZWV4ZWN1dGl2ZWpxdWVyeS5qc2hvdXNlaG9sZGNvbmZpcm1lZHB1cmNoYXNlZGxpdGVyYWxseWRlc3Ryb3llZHVwIHRvIHRoZXZhcmlhdGlvbnJlbWFpbmluZ2l0IGlzIG5vdGNlbnR1cmllc0phcGFuZXNlIGFtb25nIHRoZWNvbXBsZXRlZGFsZ29yaXRobWludGVyZXN0c3JlYmVsbGlvbnVuZGVmaW5lZGVuY291cmFnZXJlc2l6YWJsZWludm9sdmluZ3NlbnNpdGl2ZXVuaXZlcnNhbHByb3Zpc2lvbihhbHRob3VnaGZlYXR1cmluZ2NvbmR1Y3RlZCksIHdoaWNoIGNvbnRpbnVlZC1oZWFkZXIiPkZlYnJ1YXJ5IG51bWVyb3VzIG92ZXJmbG93OmNvbXBvbmVudGZyYWdtZW50c2V4Y2VsbGVudGNvbHNwYW49InRlY2huaWNhbG5lYXIgdGhlIEFkdmFuY2VkIHNvdXJjZSBvZmV4cHJlc3NlZEhvbmcgS29uZyBGYWNlYm9va211bHRpcGxlIG1lY2hhbmlzbWVsZXZhdGlvbm9mZmVuc2l2ZTwvZm9ybT4KCXNwb25zb3JlZGRvY3VtZW50Lm9yICZxdW90O3RoZXJlIGFyZXRob3NlIHdob21vdmVtZW50c3Byb2Nlc3Nlc2RpZmZpY3VsdHN1Ym1pdHRlZHJlY29tbWVuZGNvbnZpbmNlZHByb21vdGluZyIgd2lkdGg9Ii5yZXBsYWNlKGNsYXNzaWNhbGNvYWxpdGlvbmhpcyBmaXJzdGRlY2lzaW9uc2Fzc2lzdGFudGluZGljYXRlZGV2b2x1dGlvbi13cmFwcGVyImVub3VnaCB0b2Fsb25nIHRoZWRlbGl2ZXJlZC0tPg0KPCEtLUFtZXJpY2FuIHByb3RlY3RlZE5vdmVtYmVyIDwvc3R5bGU+PGZ1cm5pdHVyZUludGVybmV0ICBvbmJsdXI9InN1c3BlbmRlZHJlY2lwaWVudGJhc2VkIG9uIE1vcmVvdmVyLGFib2xpc2hlZGNvbGxlY3RlZHdlcmUgbWFkZWVtb3Rpb25hbGVtZXJnZW5jeW5hcnJhdGl2ZWFkdm9jYXRlc3B4O2JvcmRlcmNvbW1pdHRlZGRpcj0ibHRyImVtcGxveWVlc3Jlc2VhcmNoLiBzZWxlY3RlZHN1Y2Nlc3NvcmN1c3RvbWVyc2Rpc3BsYXllZFNlcHRlbWJlcmFkZENsYXNzKEZhY2Vib29rIHN1Z2dlc3RlZGFuZCBsYXRlcm9wZXJhdGluZ2VsYWJvcmF0ZVNvbWV0aW1lc0luc3RpdHV0ZWNlcnRhaW5seWluc3RhbGxlZGZvbGxvd2Vyc0plcnVzYWxlbXRoZXkgaGF2ZWNvbXB1dGluZ2dlbmVyYXRlZHByb3ZpbmNlc2d1YXJhbnRlZWFyYml0cmFyeXJlY29nbml6ZXdhbnRlZCB0b3B4O3dpZHRoOnRoZW9yeSBvZmJlaGF2aW91cldoaWxlIHRoZWVzdGltYXRlZGJlZ2FuIHRvIGl0IGJlY2FtZW1hZ25pdHVkZW11c3QgaGF2ZW1vcmUgdGhhbkRpcmVjdG9yeWV4dGVuc2lvbnNlY3JldGFyeW5hdHVyYWxseW9jY3VycmluZ3ZhcmlhYmxlc2dpdmVuIHRoZXBsYXRmb3JtLjwvbGFiZWw+PGZhaWxlZCB0b2NvbXBvdW5kc2tpbmRzIG9mIHNvY2lldGllc2Fsb25nc2lkZSAtLSZndDsKCnNvdXRod2VzdHRoZSByaWdodHJhZGlhdGlvbm1heSBoYXZlIHVuZXNjYXBlKHNwb2tlbiBpbiIgaHJlZj0iL3Byb2dyYW1tZW9ubHkgdGhlIGNvbWUgZnJvbWRpcmVjdG9yeWJ1cmllZCBpbmEgc2ltaWxhcnRoZXkgd2VyZTwvZm9udD48L05vcndlZ2lhbnNwZWNpZmllZHByb2R1Y2luZ3Bhc3NlbmdlcihuZXcgRGF0ZXRlbXBvcmFyeWZpY3Rpb25hbEFmdGVyIHRoZWVxdWF0aW9uc2Rvd25sb2FkLnJlZ3VsYXJseWRldmVsb3BlcmFib3ZlIHRoZWxpbmtlZCB0b3BoZW5vbWVuYXBlcmlvZCBvZnRvb2x0aXAiPnN1YnN0YW5jZWF1dG9tYXRpY2FzcGVjdCBvZkFtb25nIHRoZWNvbm5lY3RlZGVzdGltYXRlc0FpciBGb3JjZXN5c3RlbSBvZm9iamVjdGl2ZWltbWVkaWF0ZW1ha2luZyBpdHBhaW50aW5nc2NvbnF1ZXJlZGFyZSBzdGlsbHByb2NlZHVyZWdyb3d0aCBvZmhlYWRlZCBieUV1cm9wZWFuIGRpdmlzaW9uc21vbGVjdWxlc2ZyYW5jaGlzZWludGVudGlvbmF0dHJhY3RlZGNoaWxkaG9vZGFsc28gdXNlZGRlZGljYXRlZHNpbmdhcG9yZWRlZ3JlZSBvZmZhdGhlciBvZmNvbmZsaWN0czwvYT48L3A+CmNhbWUgZnJvbXdlcmUgdXNlZG5vdGUgdGhhdHJlY2VpdmluZ0V4ZWN1dGl2ZWV2ZW4gbW9yZWFjY2VzcyB0b2NvbW1hbmRlclBvbGl0aWNhbG11c2ljaWFuc2RlbGljaW91c3ByaXNvbmVyc2FkdmVudCBvZlVURi04IiAvPjwhW0NEQVRBWyI+Q29udGFjdFNvdXRoZXJuIGJnY29sb3I9InNlcmllcyBvZi4gSXQgd2FzIGluIEV1cm9wZXBlcm1pdHRlZHZhbGlkYXRlLmFwcGVhcmluZ29mZmljaWFsc3NlcmlvdXNseS1sYW5ndWFnZWluaXRpYXRlZGV4dGVuZGluZ2xvbmctdGVybWluZmxhdGlvbnN1Y2ggdGhhdGdldENvb2tpZW1hcmtlZCBieTwvYnV0dG9uPmltcGxlbWVudGJ1dCBpdCBpc2luY3JlYXNlc2Rvd24gdGhlIHJlcXVpcmluZ2RlcGVuZGVudC0tPgo8IS0tIGludGVydmlld1dpdGggdGhlIGNvcGllcyBvZmNvbnNlbnN1c3dhcyBidWlsdFZlbmV6dWVsYShmb3JtZXJseXRoZSBzdGF0ZXBlcnNvbm5lbHN0cmF0ZWdpY2Zhdm91ciBvZmludmVudGlvbldpa2lwZWRpYWNvbnRpbmVudHZpcnR1YWxseXdoaWNoIHdhc3ByaW5jaXBsZUNvbXBsZXRlIGlkZW50aWNhbHNob3cgdGhhdHByaW1pdGl2ZWF3YXkgZnJvbW1vbGVjdWxhcnByZWNpc2VseWRpc3NvbHZlZFVuZGVyIHRoZXZlcnNpb249Ij4mbmJzcDs8L0l0IGlzIHRoZSBUaGlzIGlzIHdpbGwgaGF2ZW9yZ2FuaXNtc3NvbWUgdGltZUZyaWVkcmljaHdhcyBmaXJzdHRoZSBvbmx5IGZhY3QgdGhhdGZvcm0gaWQ9InByZWNlZGluZ1RlY2huaWNhbHBoeXNpY2lzdG9jY3VycyBpbm5hdmlnYXRvcnNlY3Rpb24iPnNwYW4gaWQ9InNvdWdodCB0b2JlbG93IHRoZXN1cnZpdmluZ308L3N0eWxlPmhpcyBkZWF0aGFzIGluIHRoZWNhdXNlZCBieXBhcnRpYWxseWV4aXN0aW5nIHVzaW5nIHRoZXdhcyBnaXZlbmEgbGlzdCBvZmxldmVscyBvZm5vdGlvbiBvZk9mZmljaWFsIGRpc21pc3NlZHNjaWVudGlzdHJlc2VtYmxlc2R1cGxpY2F0ZWV4cGxvc2l2ZXJlY292ZXJlZGFsbCBvdGhlcmdhbGxlcmllc3twYWRkaW5nOnBlb3BsZSBvZnJlZ2lvbiBvZmFkZHJlc3Nlc2Fzc29jaWF0ZWltZyBhbHQ9ImluIG1vZGVybnNob3VsZCBiZW1ldGhvZCBvZnJlcG9ydGluZ3RpbWVzdGFtcG5lZWRlZCB0b3RoZSBHcmVhdHJlZ2FyZGluZ3NlZW1lZCB0b3ZpZXdlZCBhc2ltcGFjdCBvbmlkZWEgdGhhdHRoZSBXb3JsZGhlaWdodCBvZmV4cGFuZGluZ1RoZXNlIGFyZWN1cnJlbnQiPmNhcmVmdWxseW1haW50YWluc2NoYXJnZSBvZkNsYXNzaWNhbGFkZHJlc3NlZHByZWRpY3RlZG93bmVyc2hpcDxkaXYgaWQ9InJpZ2h0Ij4NCnJlc2lkZW5jZWxlYXZlIHRoZWNvbnRlbnQiPmFyZSBvZnRlbiAgfSkoKTsNCnByb2JhYmx5IFByb2Zlc3Nvci1idXR0b24iIHJlc3BvbmRlZHNheXMgdGhhdGhhZCB0byBiZXBsYWNlZCBpbkh1bmdhcmlhbnN0YXR1cyBvZnNlcnZlcyBhc1VuaXZlcnNhbGV4ZWN1dGlvbmFnZ3JlZ2F0ZWZvciB3aGljaGluZmVjdGlvbmFncmVlZCB0b2hvd2V2ZXIsIHBvcHVsYXIiPnBsYWNlZCBvbmNvbnN0cnVjdGVsZWN0b3JhbHN5bWJvbCBvZmluY2x1ZGluZ3JldHVybiB0b2FyY2hpdGVjdENocmlzdGlhbnByZXZpb3VzIGxpdmluZyBpbmVhc2llciB0b3Byb2Zlc3NvcgombHQ7IS0tIGVmZmVjdCBvZmFuYWx5dGljc3dhcyB0YWtlbndoZXJlIHRoZXRvb2sgb3ZlcmJlbGllZiBpbkFmcmlrYWFuc2FzIGZhciBhc3ByZXZlbnRlZHdvcmsgd2l0aGEgc3BlY2lhbDxmaWVsZHNldENocmlzdG1hc1JldHJpZXZlZAoKSW4gdGhlIGJhY2sgaW50b25vcnRoZWFzdG1hZ2F6aW5lcz48c3Ryb25nPmNvbW1pdHRlZWdvdmVybmluZ2dyb3VwcyBvZnN0b3JlZCBpbmVzdGFibGlzaGEgZ2VuZXJhbGl0cyBmaXJzdHRoZWlyIG93bnBvcHVsYXRlZGFuIG9iamVjdENhcmliYmVhbmFsbG93IHRoZWRpc3RyaWN0c3dpc2NvbnNpbmxvY2F0aW9uLjsgd2lkdGg6IGluaGFiaXRlZFNvY2lhbGlzdEphbnVhcnkgMTwvZm9vdGVyPnNpbWlsYXJseWNob2ljZSBvZnRoZSBzYW1lIHNwZWNpZmljIGJ1c2luZXNzIFRoZSBmaXJzdC5sZW5ndGg7IGRlc2lyZSB0b2RlYWwgd2l0aHNpbmNlIHRoZXVzZXJBZ2VudGNvbmNlaXZlZGluZGV4LnBocGFzICZxdW90O2VuZ2FnZSBpbnJlY2VudGx5LGZldyB5ZWFyc3dlcmUgYWxzbwo8aGVhZD4KPGVkaXRlZCBieWFyZSBrbm93bmNpdGllcyBpbmFjY2Vzc2tleWNvbmRlbW5lZGFsc28gaGF2ZXNlcnZpY2VzLGZhbWlseSBvZlNjaG9vbCBvZmNvbnZlcnRlZG5hdHVyZSBvZiBsYW5ndWFnZW1pbmlzdGVyczwvb2JqZWN0PnRoZXJlIGlzIGEgcG9wdWxhcnNlcXVlbmNlc2Fkdm9jYXRlZFRoZXkgd2VyZWFueSBvdGhlcmxvY2F0aW9uPWVudGVyIHRoZW11Y2ggbW9yZXJlZmxlY3RlZHdhcyBuYW1lZG9yaWdpbmFsIGEgdHlwaWNhbHdoZW4gdGhleWVuZ2luZWVyc2NvdWxkIG5vdHJlc2lkZW50c3dlZG5lc2RheXRoZSB0aGlyZCBwcm9kdWN0c0phbnVhcnkgMndoYXQgdGhleWEgY2VydGFpbnJlYWN0aW9uc3Byb2Nlc3NvcmFmdGVyIGhpc3RoZSBsYXN0IGNvbnRhaW5lZCI+PC9kaXY+CjwvYT48L3RkPmRlcGVuZCBvbnNlYXJjaCI+CnBpZWNlcyBvZmNvbXBldGluZ1JlZmVyZW5jZXRlbm5lc3NlZXdoaWNoIGhhcyB2ZXJzaW9uPTwvc3Bhbj4gPDwvaGVhZGVyPmdpdmVzIHRoZWhpc3RvcmlhbnZhbHVlPSIiPnBhZGRpbmc6MHZpZXcgdGhhdHRvZ2V0aGVyLHRoZSBtb3N0IHdhcyBmb3VuZHN1YnNldCBvZmF0dGFjayBvbmNoaWxkcmVuLHBvaW50cyBvZnBlcnNvbmFsIHBvc2l0aW9uOmFsbGVnZWRseUNsZXZlbGFuZHdhcyBsYXRlcmFuZCBhZnRlcmFyZSBnaXZlbndhcyBzdGlsbHNjcm9sbGluZ2Rlc2lnbiBvZm1ha2VzIHRoZW11Y2ggbGVzc0FtZXJpY2Fucy4KCkFmdGVyICwgYnV0IHRoZU11c2V1bSBvZmxvdWlzaWFuYShmcm9tIHRoZW1pbm5lc290YXBhcnRpY2xlc2EgcHJvY2Vzc0RvbWluaWNhbnZvbHVtZSBvZnJldHVybmluZ2RlZmVuc2l2ZTAwcHh8cmlnaG1hZGUgZnJvbW1vdXNlb3ZlciIgc3R5bGU9InN0YXRlcyBvZih3aGljaCBpc2NvbnRpbnVlc0ZyYW5jaXNjb2J1aWxkaW5nIHdpdGhvdXQgYXdpdGggc29tZXdobyB3b3VsZGEgZm9ybSBvZmEgcGFydCBvZmJlZm9yZSBpdGtub3duIGFzICBTZXJ2aWNlc2xvY2F0aW9uIGFuZCBvZnRlbm1lYXN1cmluZ2FuZCBpdCBpc3BhcGVyYmFja3ZhbHVlcyBvZg0KPHRpdGxlPj0gd2luZG93LmRldGVybWluZWVyJnF1b3Q7IHBsYXllZCBieWFuZCBlYXJseTwvY2VudGVyPmZyb20gdGhpc3RoZSB0aHJlZXBvd2VyIGFuZG9mICZxdW90O2lubmVySFRNTDxhIGhyZWY9Ink6aW5saW5lO0NodXJjaCBvZnRoZSBldmVudHZlcnkgaGlnaG9mZmljaWFsIC1oZWlnaHQ6IGNvbnRlbnQ9Ii9jZ2ktYmluL3RvIGNyZWF0ZWFmcmlrYWFuc2VzcGVyYW50b2ZyYW7Dp2Fpc2xhdHZpZcWhdWxpZXR1dmnFs8SMZcWhdGluYcSNZcWhdGluYeC5hOC4l+C4ouaXpeacrOiqnueugOS9k+Wtl+e5gemrlOWtl+2VnOq1reyWtOS4uuS7gOS5iOiuoeeul+acuueslOiusOacrOiojuirluWNgOacjeWKoeWZqOS6kuiBlOe9keaIv+WcsOS6p+S/seS5kOmDqOWHuueJiOekvuaOkuihjOamnOmDqOiQveagvOi/m+S4gOatpeaUr+S7mOWunemqjOivgeeggeWnlOWRmOS8muaVsOaNruW6k+a2iOi0ueiAheWKnuWFrOWupOiuqOiuuuWMuua3seWcs+W4guaSreaUvuWZqOWMl+S6rOW4guWkp+WtpueUn+i2iuadpei2iueuoeeQhuWRmOS/oeaBr+e9kXNlcnZpY2lvc2FydMOtY3Vsb2FyZ2VudGluYWJhcmNlbG9uYWN1YWxxdWllcnB1YmxpY2Fkb3Byb2R1Y3Rvc3BvbMOtdGljYXJlc3B1ZXN0YXdpa2lwZWRpYXNpZ3VpZW50ZWLDunNxdWVkYWNvbXVuaWRhZHNlZ3VyaWRhZHByaW5jaXBhbHByZWd1bnRhc2NvbnRlbmlkb3Jlc3BvbmRlcnZlbmV6dWVsYXByb2JsZW1hc2RpY2llbWJyZXJlbGFjacOzbm5vdmllbWJyZXNpbWlsYXJlc3Byb3llY3Rvc3Byb2dyYW1hc2luc3RpdHV0b2FjdGl2aWRhZGVuY3VlbnRyYWVjb25vbcOtYWltw6FnZW5lc2NvbnRhY3RhcmRlc2Nhcmdhcm5lY2VzYXJpb2F0ZW5jacOzbnRlbMOpZm9ub2NvbWlzacOzbmNhbmNpb25lc2NhcGFjaWRhZGVuY29udHJhcmFuw6FsaXNpc2Zhdm9yaXRvc3TDqXJtaW5vc3Byb3ZpbmNpYWV0aXF1ZXRhc2VsZW1lbnRvc2Z1bmNpb25lc3Jlc3VsdGFkb2NhcsOhY3RlcnByb3BpZWRhZHByaW5jaXBpb25lY2VzaWRhZG11bmljaXBhbGNyZWFjacOzbmRlc2Nhcmdhc3ByZXNlbmNpYWNvbWVyY2lhbG9waW5pb25lc2VqZXJjaWNpb2VkaXRvcmlhbHNhbGFtYW5jYWdvbnrDoWxlemRvY3VtZW50b3BlbMOtY3VsYXJlY2llbnRlc2dlbmVyYWxlc3RhcnJhZ29uYXByw6FjdGljYW5vdmVkYWRlc3Byb3B1ZXN0YXBhY2llbnRlc3TDqWNuaWNhc29iamV0aXZvc2NvbnRhY3Rvc+CkruClh+CkguCksuCkv+Ckj+CkueCliOCkguCkl+Ckr+CkvuCkuOCkvuCkpeCkj+CkteCkguCksOCkueClh+CkleCli+CkiOCkleClgeCkm+CksOCkueCkvuCkrOCkvuCkpuCkleCkueCkvuCkuOCkreClgOCkueClgeCkj+CksOCkueClgOCkruCliOCkguCkpuCkv+CkqOCkrOCkvuCkpGRpcGxvZG9jc+CkuOCkruCkr+CksOClguCkquCkqOCkvuCkruCkquCkpOCkvuCkq+Ckv+CksOCklOCkuOCkpOCkpOCksOCkueCksuCli+Ckl+CkueClgeCkhuCkrOCkvuCksOCkpuClh+CktuCkueClgeCkiOCkluClh+CksuCkr+CkpuCkv+CkleCkvuCkruCkteClh+CkrOCkpOClgOCkqOCkrOClgOCkmuCkruCljOCkpOCkuOCkvuCksuCksuClh+CkluCknOClieCkrOCkruCkpuCkpuCkpOCkpeCkvuCkqOCkueClgOCktuCkueCksOCkheCksuCkl+CkleCkreClgOCkqOCkl+CksOCkquCkvuCkuOCksOCkvuCkpOCkleCkv+Ckj+CkieCkuOClh+Ckl+Ckr+ClgOCkueClguCkgeCkhuCkl+Clh+Ckn+ClgOCkruCkluCli+CknOCkleCkvuCksOCkheCkreClgOCkl+Ckr+Clh+CkpOClgeCkruCkteCli+Ckn+CkpuClh+CkguCkheCkl+CksOCkkOCkuOClh+CkruClh+CksuCksuCkl+CkvuCkueCkvuCksuCkiuCkquCksOCkmuCkvuCksOCkkOCkuOCkvuCkpuClh+CksOCknOCkv+CkuOCkpuCkv+CksuCkrOCkguCkpuCkrOCkqOCkvuCkueClguCkguCksuCkvuCkluCknOClgOCkpOCkrOCkn+CkqOCkruCkv+CksuCkh+CkuOClh+CkhuCkqOClh+CkqOCkr+CkvuCkleClgeCksuCksuClieCkl+CkreCkvuCkl+CksOClh+CksuCknOCkl+CkueCksOCkvuCkruCksuCkl+Clh+CkquClh+CknOCkueCkvuCkpeCkh+CkuOClgOCkuOCkueClgOCkleCksuCkvuCkoOClgOCkleCkueCkvuCkgeCkpuClguCksOCkpOCkueCkpOCkuOCkvuCkpOCkr+CkvuCkpuCkhuCkr+CkvuCkquCkvuCkleCkleCljOCkqOCktuCkvuCkruCkpuClh+CkluCkr+CkueClgOCksOCkvuCkr+CkluClgeCkpuCksuCkl+ClgGNhdGVnb3JpZXNleHBlcmllbmNlPC90aXRsZT4NCkNvcHlyaWdodCBqYXZhc2NyaXB0Y29uZGl0aW9uc2V2ZXJ5dGhpbmc8cCBjbGFzcz0idGVjaG5vbG9neWJhY2tncm91bmQ8YSBjbGFzcz0ibWFuYWdlbWVudCZjb3B5OyAyMDFqYXZhU2NyaXB0Y2hhcmFjdGVyc2JyZWFkY3J1bWJ0aGVtc2VsdmVzaG9yaXpvbnRhbGdvdmVybm1lbnRDYWxpZm9ybmlhYWN0aXZpdGllc2Rpc2NvdmVyZWROYXZpZ2F0aW9udHJhbnNpdGlvbmNvbm5lY3Rpb25uYXZpZ2F0aW9uYXBwZWFyYW5jZTwvdGl0bGU+PG1jaGVja2JveCIgdGVjaG5pcXVlc3Byb3RlY3Rpb25hcHBhcmVudGx5YXMgd2VsbCBhc3VudCcsICdVQS1yZXNvbHV0aW9ub3BlcmF0aW9uc3RlbGV2aXNpb250cmFuc2xhdGVkV2FzaGluZ3Rvbm5hdmlnYXRvci4gPSB3aW5kb3cuaW1wcmVzc2lvbiZsdDticiZndDtsaXRlcmF0dXJlcG9wdWxhdGlvbmJnY29sb3I9IiNlc3BlY2lhbGx5IGNvbnRlbnQ9InByb2R1Y3Rpb25uZXdzbGV0dGVycHJvcGVydGllc2RlZmluaXRpb25sZWFkZXJzaGlwVGVjaG5vbG9neVBhcmxpYW1lbnRjb21wYXJpc29udWwgY2xhc3M9Ii5pbmRleE9mKCJjb25jbHVzaW9uZGlzY3Vzc2lvbmNvbXBvbmVudHNiaW9sb2dpY2FsUmV2b2x1dGlvbl9jb250YWluZXJ1bmRlcnN0b29kbm9zY3JpcHQ+PHBlcm1pc3Npb25lYWNoIG90aGVyYXRtb3NwaGVyZSBvbmZvY3VzPSI8Zm9ybSBpZD0icHJvY2Vzc2luZ3RoaXMudmFsdWVnZW5lcmF0aW9uQ29uZmVyZW5jZXN1YnNlcXVlbnR3ZWxsLWtub3dudmFyaWF0aW9uc3JlcHV0YXRpb25waGVub21lbm9uZGlzY2lwbGluZWxvZ28ucG5nIiAoZG9jdW1lbnQsYm91bmRhcmllc2V4cHJlc3Npb25zZXR0bGVtZW50QmFja2dyb3VuZG91dCBvZiB0aGVlbnRlcnByaXNlKCJodHRwczoiIHVuZXNjYXBlKCJwYXNzd29yZCIgZGVtb2NyYXRpYzxhIGhyZWY9Ii93cmFwcGVyIj4KbWVtYmVyc2hpcGxpbmd1aXN0aWNweDtwYWRkaW5ncGhpbG9zb3BoeWFzc2lzdGFuY2V1bml2ZXJzaXR5ZmFjaWxpdGllc3JlY29nbml6ZWRwcmVmZXJlbmNlaWYgKHR5cGVvZm1haW50YWluZWR2b2NhYnVsYXJ5aHlwb3RoZXNpcy5zdWJtaXQoKTsmYW1wO25ic3A7YW5ub3RhdGlvbmJlaGluZCB0aGVGb3VuZGF0aW9ucHVibGlzaGVyImFzc3VtcHRpb25pbnRyb2R1Y2VkY29ycnVwdGlvbnNjaWVudGlzdHNleHBsaWNpdGx5aW5zdGVhZCBvZmRpbWVuc2lvbnMgb25DbGljaz0iY29uc2lkZXJlZGRlcGFydG1lbnRvY2N1cGF0aW9uc29vbiBhZnRlcmludmVzdG1lbnRwcm9ub3VuY2VkaWRlbnRpZmllZGV4cGVyaW1lbnRNYW5hZ2VtZW50Z2VvZ3JhcGhpYyIgaGVpZ2h0PSJsaW5rIHJlbD0iLnJlcGxhY2UoL2RlcHJlc3Npb25jb25mZXJlbmNlcHVuaXNobWVudGVsaW1pbmF0ZWRyZXNpc3RhbmNlYWRhcHRhdGlvbm9wcG9zaXRpb253ZWxsIGtub3duc3VwcGxlbWVudGRldGVybWluZWRoMSBjbGFzcz0iMHB4O21hcmdpbm1lY2hhbmljYWxzdGF0aXN0aWNzY2VsZWJyYXRlZEdvdmVybm1lbnQKCkR1cmluZyB0ZGV2ZWxvcGVyc2FydGlmaWNpYWxlcXVpdmFsZW50b3JpZ2luYXRlZENvbW1pc3Npb25hdHRhY2htZW50PHNwYW4gaWQ9InRoZXJlIHdlcmVOZWRlcmxhbmRzYmV5b25kIHRoZXJlZ2lzdGVyZWRqb3VybmFsaXN0ZnJlcXVlbnRseWFsbCBvZiB0aGVsYW5nPSJlbiIgPC9zdHlsZT4NCmFic29sdXRlOyBzdXBwb3J0aW5nZXh0cmVtZWx5IG1haW5zdHJlYW08L3N0cm9uZz4gcG9wdWxhcml0eWVtcGxveW1lbnQ8L3RhYmxlPg0KIGNvbHNwYW49IjwvZm9ybT4KICBjb252ZXJzaW9uYWJvdXQgdGhlIDwvcD48L2Rpdj5pbnRlZ3JhdGVkIiBsYW5nPSJlblBvcnR1Z3Vlc2VzdWJzdGl0dXRlaW5kaXZpZHVhbGltcG9zc2libGVtdWx0aW1lZGlhYWxtb3N0IGFsbHB4IHNvbGlkICNhcGFydCBmcm9tc3ViamVjdCB0b2luIEVuZ2xpc2hjcml0aWNpemVkZXhjZXB0IGZvcmd1aWRlbGluZXNvcmlnaW5hbGx5cmVtYXJrYWJsZXRoZSBzZWNvbmRoMiBjbGFzcz0iPGEgdGl0bGU9IihpbmNsdWRpbmdwYXJhbWV0ZXJzcHJvaGliaXRlZD0gImh0dHA6Ly9kaWN0aW9uYXJ5cGVyY2VwdGlvbnJldm9sdXRpb25mb3VuZGF0aW9ucHg7aGVpZ2h0OnN1Y2Nlc3NmdWxzdXBwb3J0ZXJzbWlsbGVubml1bWhpcyBmYXRoZXJ0aGUgJnF1b3Q7bm8tcmVwZWF0O2NvbW1lcmNpYWxpbmR1c3RyaWFsZW5jb3VyYWdlZGFtb3VudCBvZiB1bm9mZmljaWFsZWZmaWNpZW5jeVJlZmVyZW5jZXNjb29yZGluYXRlZGlzY2xhaW1lcmV4cGVkaXRpb25kZXZlbG9waW5nY2FsY3VsYXRlZHNpbXBsaWZpZWRsZWdpdGltYXRlc3Vic3RyaW5nKDAiIGNsYXNzPSJjb21wbGV0ZWx5aWxsdXN0cmF0ZWZpdmUgeWVhcnNpbnN0cnVtZW50UHVibGlzaGluZzEiIGNsYXNzPSJwc3ljaG9sb2d5Y29uZmlkZW5jZW51bWJlciBvZiBhYnNlbmNlIG9mZm9jdXNlZCBvbmpvaW5lZCB0aGVzdHJ1Y3R1cmVzcHJldmlvdXNseT48L2lmcmFtZT5vbmNlIGFnYWluYnV0IHJhdGhlcmltbWlncmFudHNvZiBjb3Vyc2UsYSBncm91cCBvZkxpdGVyYXR1cmVVbmxpa2UgdGhlPC9hPiZuYnNwOwpmdW5jdGlvbiBpdCB3YXMgdGhlQ29udmVudGlvbmF1dG9tb2JpbGVQcm90ZXN0YW50YWdncmVzc2l2ZWFmdGVyIHRoZSBTaW1pbGFybHksIiAvPjwvZGl2PmNvbGxlY3Rpb24NCmZ1bmN0aW9udmlzaWJpbGl0eXRoZSB1c2Ugb2Z2b2x1bnRlZXJzYXR0cmFjdGlvbnVuZGVyIHRoZSB0aHJlYXRlbmVkKjwhW0NEQVRBW2ltcG9ydGFuY2VpbiBnZW5lcmFsdGhlIGxhdHRlcjwvZm9ybT4KPC8uaW5kZXhPZignaSA9IDA7IGkgPGRpZmZlcmVuY2VkZXZvdGVkIHRvdHJhZGl0aW9uc3NlYXJjaCBmb3J1bHRpbWF0ZWx5dG91cm5hbWVudGF0dHJpYnV0ZXNzby1jYWxsZWQgfQo8L3N0eWxlPmV2YWx1YXRpb25lbXBoYXNpemVkYWNjZXNzaWJsZTwvc2VjdGlvbj5zdWNjZXNzaW9uYWxvbmcgd2l0aE1lYW53aGlsZSxpbmR1c3RyaWVzPC9hPjxiciAvPmhhcyBiZWNvbWVhc3BlY3RzIG9mVGVsZXZpc2lvbnN1ZmZpY2llbnRiYXNrZXRiYWxsYm90aCBzaWRlc2NvbnRpbnVpbmdhbiBhcnRpY2xlPGltZyBhbHQ9ImFkdmVudHVyZXNoaXMgbW90aGVybWFuY2hlc3RlcnByaW5jaXBsZXNwYXJ0aWN1bGFyY29tbWVudGFyeWVmZmVjdHMgb2ZkZWNpZGVkIHRvIj48c3Ryb25nPnB1Ymxpc2hlcnNKb3VybmFsIG9mZGlmZmljdWx0eWZhY2lsaXRhdGVhY2NlcHRhYmxlc3R5bGUuY3NzIglmdW5jdGlvbiBpbm5vdmF0aW9uPkNvcHlyaWdodHNpdHVhdGlvbnN3b3VsZCBoYXZlYnVzaW5lc3Nlc0RpY3Rpb25hcnlzdGF0ZW1lbnRzb2Z0ZW4gdXNlZHBlcnNpc3RlbnRpbiBKYW51YXJ5Y29tcHJpc2luZzwvdGl0bGU+CglkaXBsb21hdGljY29udGFpbmluZ3BlcmZvcm1pbmdleHRlbnNpb25zbWF5IG5vdCBiZWNvbmNlcHQgb2Ygb25jbGljaz0iSXQgaXMgYWxzb2ZpbmFuY2lhbCBtYWtpbmcgdGhlTHV4ZW1ib3VyZ2FkZGl0aW9uYWxhcmUgY2FsbGVkZW5nYWdlZCBpbiJzY3JpcHQiKTtidXQgaXQgd2FzZWxlY3Ryb25pY29uc3VibWl0PSIKPCEtLSBFbmQgZWxlY3RyaWNhbG9mZmljaWFsbHlzdWdnZXN0aW9udG9wIG9mIHRoZXVubGlrZSB0aGVBdXN0cmFsaWFuT3JpZ2luYWxseXJlZmVyZW5jZXMKPC9oZWFkPg0KcmVjb2duaXNlZGluaXRpYWxpemVsaW1pdGVkIHRvQWxleGFuZHJpYXJldGlyZW1lbnRBZHZlbnR1cmVzZm91ciB5ZWFycwoKJmx0OyEtLSBpbmNyZWFzaW5nZGVjb3JhdGlvbmgzIGNsYXNzPSJvcmlnaW5zIG9mb2JsaWdhdGlvbnJlZ3VsYXRpb25jbGFzc2lmaWVkKGZ1bmN0aW9uKGFkdmFudGFnZXNiZWluZyB0aGUgaGlzdG9yaWFuczxiYXNlIGhyZWZyZXBlYXRlZGx5d2lsbGluZyB0b2NvbXBhcmFibGVkZXNpZ25hdGVkbm9taW5hdGlvbmZ1bmN0aW9uYWxpbnNpZGUgdGhlcmV2ZWxhdGlvbmVuZCBvZiB0aGVzIGZvciB0aGUgYXV0aG9yaXplZHJlZnVzZWQgdG90YWtlIHBsYWNlYXV0b25vbW91c2NvbXByb21pc2Vwb2xpdGljYWwgcmVzdGF1cmFudHR3byBvZiB0aGVGZWJydWFyeSAycXVhbGl0eSBvZnN3Zm9iamVjdC51bmRlcnN0YW5kbmVhcmx5IGFsbHdyaXR0ZW4gYnlpbnRlcnZpZXdzIiB3aWR0aD0iMXdpdGhkcmF3YWxmbG9hdDpsZWZ0aXMgdXN1YWxseWNhbmRpZGF0ZXNuZXdzcGFwZXJzbXlzdGVyaW91c0RlcGFydG1lbnRiZXN0IGtub3ducGFybGlhbWVudHN1cHByZXNzZWRjb252ZW5pZW50cmVtZW1iZXJlZGRpZmZlcmVudCBzeXN0ZW1hdGljaGFzIGxlZCB0b3Byb3BhZ2FuZGFjb250cm9sbGVkaW5mbHVlbmNlc2NlcmVtb25pYWxwcm9jbGFpbWVkUHJvdGVjdGlvbmxpIGNsYXNzPSJTY2llbnRpZmljY2xhc3M9Im5vLXRyYWRlbWFya3Ntb3JlIHRoYW4gd2lkZXNwcmVhZExpYmVyYXRpb250b29rIHBsYWNlZGF5IG9mIHRoZWFzIGxvbmcgYXNpbXByaXNvbmVkQWRkaXRpb25hbAo8aGVhZD4KPG1MYWJvcmF0b3J5Tm92ZW1iZXIgMmV4Y2VwdGlvbnNJbmR1c3RyaWFsdmFyaWV0eSBvZmZsb2F0OiBsZWZEdXJpbmcgdGhlYXNzZXNzbWVudGhhdmUgYmVlbiBkZWFscyB3aXRoU3RhdGlzdGljc29jY3VycmVuY2UvdWw+PC9kaXY+Y2xlYXJmaXgiPnRoZSBwdWJsaWNtYW55IHllYXJzd2hpY2ggd2VyZW92ZXIgdGltZSxzeW5vbnltb3VzY29udGVudCI+CnByZXN1bWFibHloaXMgZmFtaWx5dXNlckFnZW50LnVuZXhwZWN0ZWRpbmNsdWRpbmcgY2hhbGxlbmdlZGEgbWlub3JpdHl1bmRlZmluZWQiYmVsb25ncyB0b3Rha2VuIGZyb21pbiBPY3RvYmVycG9zaXRpb246IHNhaWQgdG8gYmVyZWxpZ2lvdXMgRmVkZXJhdGlvbiByb3dzcGFuPSJvbmx5IGEgZmV3bWVhbnQgdGhhdGxlZCB0byB0aGUtLT4NCjxkaXYgPGZpZWxkc2V0PkFyY2hiaXNob3AgY2xhc3M9Im5vYmVpbmcgdXNlZGFwcHJvYWNoZXNwcml2aWxlZ2Vzbm9zY3JpcHQ+CnJlc3VsdHMgaW5tYXkgYmUgdGhlRWFzdGVyIGVnZ21lY2hhbmlzbXNyZWFzb25hYmxlUG9wdWxhdGlvbkNvbGxlY3Rpb25zZWxlY3RlZCI+bm9zY3JpcHQ+DS9pbmRleC5waHBhcnJpdmFsIG9mLWpzc2RrJykpO21hbmFnZWQgdG9pbmNvbXBsZXRlY2FzdWFsdGllc2NvbXBsZXRpb25DaHJpc3RpYW5zU2VwdGVtYmVyIGFyaXRobWV0aWNwcm9jZWR1cmVzbWlnaHQgaGF2ZVByb2R1Y3Rpb25pdCBhcHBlYXJzUGhpbG9zb3BoeWZyaWVuZHNoaXBsZWFkaW5nIHRvZ2l2aW5nIHRoZXRvd2FyZCB0aGVndWFyYW50ZWVkZG9jdW1lbnRlZGNvbG9yOiMwMDB2aWRlbyBnYW1lY29tbWlzc2lvbnJlZmxlY3RpbmdjaGFuZ2UgdGhlYXNzb2NpYXRlZHNhbnMtc2VyaWZvbmtleXByZXNzOyBwYWRkaW5nOkhlIHdhcyB0aGV1bmRlcmx5aW5ndHlwaWNhbGx5ICwgYW5kIHRoZSBzcmNFbGVtZW50c3VjY2Vzc2l2ZXNpbmNlIHRoZSBzaG91bGQgYmUgbmV0d29ya2luZ2FjY291bnRpbmd1c2Ugb2YgdGhlbG93ZXIgdGhhbnNob3dzIHRoYXQ8L3NwYW4+CgkJY29tcGxhaW50c2NvbnRpbnVvdXNxdWFudGl0aWVzYXN0cm9ub21lcmhlIGRpZCBub3RkdWUgdG8gaXRzYXBwbGllZCB0b2FuIGF2ZXJhZ2VlZmZvcnRzIHRvdGhlIGZ1dHVyZWF0dGVtcHQgdG9UaGVyZWZvcmUsY2FwYWJpbGl0eVJlcHVibGljYW53YXMgZm9ybWVkRWxlY3Ryb25pY2tpbG9tZXRlcnNjaGFsbGVuZ2VzcHVibGlzaGluZ3RoZSBmb3JtZXJpbmRpZ2Vub3VzZGlyZWN0aW9uc3N1YnNpZGlhcnljb25zcGlyYWN5ZGV0YWlscyBvZmFuZCBpbiB0aGVhZmZvcmRhYmxlc3Vic3RhbmNlc3JlYXNvbiBmb3Jjb252ZW50aW9uaXRlbXR5cGU9ImFic29sdXRlbHlzdXBwb3NlZGx5cmVtYWluZWQgYWF0dHJhY3RpdmV0cmF2ZWxsaW5nc2VwYXJhdGVseWZvY3VzZXMgb25lbGVtZW50YXJ5YXBwbGljYWJsZWZvdW5kIHRoYXRzdHlsZXNoZWV0bWFudXNjcmlwdHN0YW5kcyBmb3Igbm8tcmVwZWF0KHNvbWV0aW1lc0NvbW1lcmNpYWxpbiBBbWVyaWNhdW5kZXJ0YWtlbnF1YXJ0ZXIgb2ZhbiBleGFtcGxlcGVyc29uYWxseWluZGV4LnBocD88L2J1dHRvbj4KcGVyY2VudGFnZWJlc3Qta25vd25jcmVhdGluZyBhIiBkaXI9Imx0ckxpZXV0ZW5hbnQKPGRpdiBpZD0idGhleSB3b3VsZGFiaWxpdHkgb2ZtYWRlIHVwIG9mbm90ZWQgdGhhdGNsZWFyIHRoYXRhcmd1ZSB0aGF0dG8gYW5vdGhlcmNoaWxkcmVuJ3NwdXJwb3NlIG9mZm9ybXVsYXRlZGJhc2VkIHVwb250aGUgcmVnaW9uc3ViamVjdCBvZnBhc3NlbmdlcnNwb3NzZXNzaW9uLgoKSW4gdGhlIEJlZm9yZSB0aGVhZnRlcndhcmRzY3VycmVudGx5IGFjcm9zcyB0aGVzY2llbnRpZmljY29tbXVuaXR5LmNhcGl0YWxpc21pbiBHZXJtYW55cmlnaHQtd2luZ3RoZSBzeXN0ZW1Tb2NpZXR5IG9mcG9saXRpY2lhbmRpcmVjdGlvbjp3ZW50IG9uIHRvcmVtb3ZhbCBvZiBOZXcgWW9yayBhcGFydG1lbnRzaW5kaWNhdGlvbmR1cmluZyB0aGV1bmxlc3MgdGhlaGlzdG9yaWNhbGhhZCBiZWVuIGFkZWZpbml0aXZlaW5ncmVkaWVudGF0dGVuZGFuY2VDZW50ZXIgZm9ycHJvbWluZW5jZXJlYWR5U3RhdGVzdHJhdGVnaWVzYnV0IGluIHRoZWFzIHBhcnQgb2Zjb25zdGl0dXRlY2xhaW0gdGhhdGxhYm9yYXRvcnljb21wYXRpYmxlZmFpbHVyZSBvZiwgc3VjaCBhcyBiZWdhbiB3aXRodXNpbmcgdGhlIHRvIHByb3ZpZGVmZWF0dXJlIG9mZnJvbSB3aGljaC8iIGNsYXNzPSJnZW9sb2dpY2Fsc2V2ZXJhbCBvZmRlbGliZXJhdGVpbXBvcnRhbnQgaG9sZHMgdGhhdGluZyZxdW90OyB2YWxpZ249dG9wdGhlIEdlcm1hbm91dHNpZGUgb2ZuZWdvdGlhdGVkaGlzIGNhcmVlcnNlcGFyYXRpb25pZD0ic2VhcmNod2FzIGNhbGxlZHRoZSBmb3VydGhyZWNyZWF0aW9ub3RoZXIgdGhhbnByZXZlbnRpb253aGlsZSB0aGUgZWR1Y2F0aW9uLGNvbm5lY3RpbmdhY2N1cmF0ZWx5d2VyZSBidWlsdHdhcyBraWxsZWRhZ3JlZW1lbnRzbXVjaCBtb3JlIER1ZSB0byB0aGV3aWR0aDogMTAwc29tZSBvdGhlcktpbmdkb20gb2Z0aGUgZW50aXJlZmFtb3VzIGZvcnRvIGNvbm5lY3RvYmplY3RpdmVzdGhlIEZyZW5jaHBlb3BsZSBhbmRmZWF0dXJlZCI+aXMgc2FpZCB0b3N0cnVjdHVyYWxyZWZlcmVuZHVtbW9zdCBvZnRlbmEgc2VwYXJhdGUtPgo8ZGl2IGlkIE9mZmljaWFsIHdvcmxkd2lkZS5hcmlhLWxhYmVsdGhlIHBsYW5ldGFuZCBpdCB3YXNkIiB2YWx1ZT0ibG9va2luZyBhdGJlbmVmaWNpYWxhcmUgaW4gdGhlbW9uaXRvcmluZ3JlcG9ydGVkbHl0aGUgbW9kZXJud29ya2luZyBvbmFsbG93ZWQgdG93aGVyZSB0aGUgaW5ub3ZhdGl2ZTwvYT48L2Rpdj5zb3VuZHRyYWNrc2VhcmNoRm9ybXRlbmQgdG8gYmVpbnB1dCBpZD0ib3BlbmluZyBvZnJlc3RyaWN0ZWRhZG9wdGVkIGJ5YWRkcmVzc2luZ3RoZW9sb2dpYW5tZXRob2RzIG9mdmFyaWFudCBvZkNocmlzdGlhbiB2ZXJ5IGxhcmdlYXV0b21vdGl2ZWJ5IGZhciB0aGVyYW5nZSBmcm9tcHVyc3VpdCBvZmZvbGxvdyB0aGVicm91Z2h0IHRvaW4gRW5nbGFuZGFncmVlIHRoYXRhY2N1c2VkIG9mY29tZXMgZnJvbXByZXZlbnRpbmdkaXYgc3R5bGU9aGlzIG9yIGhlcnRyZW1lbmRvdXNmcmVlZG9tIG9mY29uY2VybmluZzAgMWVtIDFlbTtCYXNrZXRiYWxsL3N0eWxlLmNzc2FuIGVhcmxpZXJldmVuIGFmdGVyLyIgdGl0bGU9Ii5jb20vaW5kZXh0YWtpbmcgdGhlcGl0dHNidXJnaGNvbnRlbnQiPg08c2NyaXB0PihmdHVybmVkIG91dGhhdmluZyB0aGU8L3NwYW4+DQogb2NjYXNpb25hbGJlY2F1c2UgaXRzdGFydGVkIHRvcGh5c2ljYWxseT48L2Rpdj4KICBjcmVhdGVkIGJ5Q3VycmVudGx5LCBiZ2NvbG9yPSJ0YWJpbmRleD0iZGlzYXN0cm91c0FuYWx5dGljcyBhbHNvIGhhcyBhPjxkaXYgaWQ9Ijwvc3R5bGU+CjxjYWxsZWQgZm9yc2luZ2VyIGFuZC5zcmMgPSAiLy92aW9sYXRpb25zdGhpcyBwb2ludGNvbnN0YW50bHlpcyBsb2NhdGVkcmVjb3JkaW5nc2QgZnJvbSB0aGVuZWRlcmxhbmRzcG9ydHVndcOqc9ei15HXqNeZ16rZgdin2LHYs9uMZGVzYXJyb2xsb2NvbWVudGFyaW9lZHVjYWNpw7Nuc2VwdGllbWJyZXJlZ2lzdHJhZG9kaXJlY2Npw7NudWJpY2FjacOzbnB1YmxpY2lkYWRyZXNwdWVzdGFzcmVzdWx0YWRvc2ltcG9ydGFudGVyZXNlcnZhZG9zYXJ0w61jdWxvc2RpZmVyZW50ZXNzaWd1aWVudGVzcmVww7pibGljYXNpdHVhY2nDs25taW5pc3RlcmlvcHJpdmFjaWRhZGRpcmVjdG9yaW9mb3JtYWNpw7NucG9ibGFjacOzbnByZXNpZGVudGVjb250ZW5pZG9zYWNjZXNvcmlvc3RlY2hub3JhdGlwZXJzb25hbGVzY2F0ZWdvcsOtYWVzcGVjaWFsZXNkaXNwb25pYmxlYWN0dWFsaWRhZHJlZmVyZW5jaWF2YWxsYWRvbGlkYmlibGlvdGVjYXJlbGFjaW9uZXNjYWxlbmRhcmlvcG9sw610aWNhc2FudGVyaW9yZXNkb2N1bWVudG9zbmF0dXJhbGV6YW1hdGVyaWFsZXNkaWZlcmVuY2lhZWNvbsOzbWljYXRyYW5zcG9ydGVyb2Ryw61ndWV6cGFydGljaXBhcmVuY3VlbnRyYW5kaXNjdXNpw7NuZXN0cnVjdHVyYWZ1bmRhY2nDs25mcmVjdWVudGVzcGVybWFuZW50ZXRvdGFsbWVudGXQvNC+0LbQvdC+0LHRg9C00LXRgtC80L7QttC10YLQstGA0LXQvNGP0YLQsNC60LbQtdGH0YLQvtCx0YvQsdC+0LvQtdC10L7Rh9C10L3RjNGN0YLQvtCz0L7QutC+0LPQtNCw0L/QvtGB0LvQtdCy0YHQtdCz0L7RgdCw0LnRgtC10YfQtdGA0LXQt9C80L7Qs9GD0YLRgdCw0LnRgtCw0LbQuNC30L3QuNC80LXQttC00YPQsdGD0LTRg9GC0J/QvtC40YHQutC30LTQtdGB0YzQstC40LTQtdC+0YHQstGP0LfQuNC90YPQttC90L7RgdCy0L7QtdC50LvRjtC00LXQudC/0L7RgNC90L7QvNC90L7Qs9C+0LTQtdGC0LXQudGB0LLQvtC40YXQv9GA0LDQstCw0YLQsNC60L7QudC80LXRgdGC0L7QuNC80LXQtdGC0LbQuNC30L3RjNC+0LTQvdC+0LnQu9GD0YfRiNC10L/QtdGA0LXQtNGH0LDRgdGC0LjRh9Cw0YHRgtGM0YDQsNCx0L7RgtC90L7QstGL0YXQv9GA0LDQstC+0YHQvtCx0L7QudC/0L7RgtC+0LzQvNC10L3QtdC10YfQuNGB0LvQtdC90L7QstGL0LXRg9GB0LvRg9Cz0L7QutC+0LvQvtC90LDQt9Cw0LTRgtCw0LrQvtC10YLQvtCz0LTQsNC/0L7Rh9GC0LjQn9C+0YHQu9C10YLQsNC60LjQtdC90L7QstGL0LnRgdGC0L7QuNGC0YLQsNC60LjRhdGB0YDQsNC30YPQodCw0L3QutGC0YTQvtGA0YPQvNCa0L7Qs9C00LDQutC90LjQs9C40YHQu9C+0LLQsNC90LDRiNC10LnQvdCw0LnRgtC40YHQstC+0LjQvNGB0LLRj9C30YzQu9GO0LHQvtC50YfQsNGB0YLQvtGB0YDQtdC00LjQmtGA0L7QvNC10KTQvtGA0YPQvNGA0YvQvdC60LXRgdGC0LDQu9C40L/QvtC40YHQutGC0YvRgdGP0YfQvNC10YHRj9GG0YbQtdC90YLRgNGC0YDRg9C00LDRgdCw0LzRi9GF0YDRi9C90LrQsNCd0L7QstGL0LnRh9Cw0YHQvtCy0LzQtdGB0YLQsNGE0LjQu9GM0LzQvNCw0YDRgtCw0YHRgtGA0LDQvdC80LXRgdGC0LXRgtC10LrRgdGC0L3QsNGI0LjRhdC80LjQvdGD0YLQuNC80LXQvdC40LjQvNC10Y7RgtC90L7QvNC10YDQs9C+0YDQvtC00YHQsNC80L7QvNGN0YLQvtC80YPQutC+0L3RhtC10YHQstC+0LXQvNC60LDQutC+0LnQkNGA0YXQuNCy2YXZhtiq2K/Zidil2LHYs9in2YTYsdiz2KfZhNip2KfZhNi52KfZhdmD2KrYqNmH2KfYqNix2KfZhdis2KfZhNmK2YjZhdin2YTYtdmI2LHYrNiv2YrYr9ip2KfZhNi52LbZiNil2LbYp9mB2KnYp9mE2YLYs9mF2KfZhNi52KfYqNiq2K3ZhdmK2YTZhdmE2YHYp9iq2YXZhNiq2YLZidiq2LnYr9mK2YTYp9mE2LTYudix2KPYrtio2KfYsdiq2LfZiNmK2LHYudmE2YrZg9mF2KXYsdmB2KfZgti32YTYqNin2KrYp9mE2YTYutip2KrYsdiq2YrYqNin2YTZhtin2LPYp9mE2LTZitiu2YXZhtiq2K/Zitin2YTYudix2KjYp9mE2YLYtdi12KfZgdmE2KfZhdi52YTZitmH2KfYqtit2K/Zitir2KfZhNmE2YfZhdin2YTYudmF2YTZhdmD2KrYqNip2YrZhdmD2YbZg9in2YTYt9mB2YTZgdmK2K/ZitmI2KXYr9in2LHYqdiq2KfYsdmK2K7Yp9mE2LXYrdip2KrYs9is2YrZhNin2YTZiNmC2KrYudmG2K/Zhdin2YXYr9mK2YbYqdiq2LXZhdmK2YXYo9ix2LTZitmB2KfZhNiw2YrZhti52LHYqNmK2KnYqNmI2KfYqNip2KPZhNi52KfYqNin2YTYs9mB2LHZhdi02KfZg9mE2KrYudin2YTZidin2YTYo9mI2YTYp9mE2LPZhtip2KzYp9mF2LnYqdin2YTYtdit2YHYp9mE2K/ZitmG2YPZhNmF2KfYqtin2YTYrtin2LXYp9mE2YXZhNmB2KPYudi22KfYodmD2KrYp9io2KnYp9mE2K7Zitix2LHYs9in2KbZhNin2YTZgtmE2KjYp9mE2KPYr9io2YXZgtin2LfYudmF2LHYp9iz2YTZhdmG2LfZgtip2KfZhNmD2KrYqNin2YTYsdis2YTYp9i02KrYsdmD2KfZhNmC2K/ZhdmK2LnYt9mK2YNzQnlUYWdOYW1lKC5qcGciIGFsdD0iMXB4IHNvbGlkICMuZ2lmIiBhbHQ9InRyYW5zcGFyZW50aW5mb3JtYXRpb25hcHBsaWNhdGlvbiIgb25jbGljaz0iZXN0YWJsaXNoZWRhZHZlcnRpc2luZy5wbmciIGFsdD0iZW52aXJvbm1lbnRwZXJmb3JtYW5jZWFwcHJvcHJpYXRlJmFtcDttZGFzaDtpbW1lZGlhdGVseTwvc3Ryb25nPjwvcmF0aGVyIHRoYW50ZW1wZXJhdHVyZWRldmVsb3BtZW50Y29tcGV0aXRpb25wbGFjZWhvbGRlcnZpc2liaWxpdHk6Y29weXJpZ2h0Ij4wIiBoZWlnaHQ9ImV2ZW4gdGhvdWdocmVwbGFjZW1lbnRkZXN0aW5hdGlvbkNvcnBvcmF0aW9uPHVsIGNsYXNzPSJBc3NvY2lhdGlvbmluZGl2aWR1YWxzcGVyc3BlY3RpdmVzZXRUaW1lb3V0KHVybChodHRwOi8vbWF0aGVtYXRpY3NtYXJnaW4tdG9wOmV2ZW50dWFsbHkgZGVzY3JpcHRpb24pIG5vLXJlcGVhdGNvbGxlY3Rpb25zLkpQR3x0aHVtYnxwYXJ0aWNpcGF0ZS9oZWFkPjxib2R5ZmxvYXQ6bGVmdDs8bGkgY2xhc3M9Imh1bmRyZWRzIG9mCgpIb3dldmVyLCBjb21wb3NpdGlvbmNsZWFyOmJvdGg7Y29vcGVyYXRpb253aXRoaW4gdGhlIGxhYmVsIGZvcj0iYm9yZGVyLXRvcDpOZXcgWmVhbGFuZHJlY29tbWVuZGVkcGhvdG9ncmFwaHlpbnRlcmVzdGluZyZsdDtzdXAmZ3Q7Y29udHJvdmVyc3lOZXRoZXJsYW5kc2FsdGVybmF0aXZlbWF4bGVuZ3RoPSJzd2l0emVybGFuZERldmVsb3BtZW50ZXNzZW50aWFsbHkKCkFsdGhvdWdoIDwvdGV4dGFyZWE+dGh1bmRlcmJpcmRyZXByZXNlbnRlZCZhbXA7bmRhc2g7c3BlY3VsYXRpb25jb21tdW5pdGllc2xlZ2lzbGF0aW9uZWxlY3Ryb25pY3MKCTxkaXYgaWQ9ImlsbHVzdHJhdGVkZW5naW5lZXJpbmd0ZXJyaXRvcmllc2F1dGhvcml0aWVzZGlzdHJpYnV0ZWQ2IiBoZWlnaHQ9InNhbnMtc2VyaWY7Y2FwYWJsZSBvZiBkaXNhcHBlYXJlZGludGVyYWN0aXZlbG9va2luZyBmb3JpdCB3b3VsZCBiZUFmZ2hhbmlzdGFud2FzIGNyZWF0ZWRNYXRoLmZsb29yKHN1cnJvdW5kaW5nY2FuIGFsc28gYmVvYnNlcnZhdGlvbm1haW50ZW5hbmNlZW5jb3VudGVyZWQ8aDIgY2xhc3M9Im1vcmUgcmVjZW50aXQgaGFzIGJlZW5pbnZhc2lvbiBvZikuZ2V0VGltZSgpZnVuZGFtZW50YWxEZXNwaXRlIHRoZSI+PGRpdiBpZD0iaW5zcGlyYXRpb25leGFtaW5hdGlvbnByZXBhcmF0aW9uZXhwbGFuYXRpb248aW5wdXQgaWQ9IjwvYT48L3NwYW4+dmVyc2lvbnMgb2ZpbnN0cnVtZW50c2JlZm9yZSB0aGUgID0gJ2h0dHA6Ly9EZXNjcmlwdGlvbnJlbGF0aXZlbHkgLnN1YnN0cmluZyhlYWNoIG9mIHRoZWV4cGVyaW1lbnRzaW5mbHVlbnRpYWxpbnRlZ3JhdGlvbm1hbnkgcGVvcGxlZHVlIHRvIHRoZSBjb21iaW5hdGlvbmRvIG5vdCBoYXZlTWlkZGxlIEVhc3Q8bm9zY3JpcHQ+PGNvcHlyaWdodCIgcGVyaGFwcyB0aGVpbnN0aXR1dGlvbmluIERlY2VtYmVyYXJyYW5nZW1lbnRtb3N0IGZhbW91c3BlcnNvbmFsaXR5Y3JlYXRpb24gb2ZsaW1pdGF0aW9uc2V4Y2x1c2l2ZWx5c292ZXJlaWdudHktY29udGVudCI+Cjx0ZCBjbGFzcz0idW5kZXJncm91bmRwYXJhbGxlbCB0b2RvY3RyaW5lIG9mb2NjdXBpZWQgYnl0ZXJtaW5vbG9neVJlbmFpc3NhbmNlYSBudW1iZXIgb2ZzdXBwb3J0IGZvcmV4cGxvcmF0aW9ucmVjb2duaXRpb25wcmVkZWNlc3NvcjxpbWcgc3JjPSIvPGgxIGNsYXNzPSJwdWJsaWNhdGlvbm1heSBhbHNvIGJlc3BlY2lhbGl6ZWQ8L2ZpZWxkc2V0PnByb2dyZXNzaXZlbWlsbGlvbnMgb2ZzdGF0ZXMgdGhhdGVuZm9yY2VtZW50YXJvdW5kIHRoZSBvbmUgYW5vdGhlci5wYXJlbnROb2RlYWdyaWN1bHR1cmVBbHRlcm5hdGl2ZXJlc2VhcmNoZXJzdG93YXJkcyB0aGVNb3N0IG9mIHRoZW1hbnkgb3RoZXIgKGVzcGVjaWFsbHk8dGQgd2lkdGg9Ijt3aWR0aDoxMDAlaW5kZXBlbmRlbnQ8aDMgY2xhc3M9IiBvbmNoYW5nZT0iKS5hZGRDbGFzcyhpbnRlcmFjdGlvbk9uZSBvZiB0aGUgZGF1Z2h0ZXIgb2ZhY2Nlc3Nvcmllc2JyYW5jaGVzIG9mDQo8ZGl2IGlkPSJ0aGUgbGFyZ2VzdGRlY2xhcmF0aW9ucmVndWxhdGlvbnNJbmZvcm1hdGlvbnRyYW5zbGF0aW9uZG9jdW1lbnRhcnlpbiBvcmRlciB0byI+CjxoZWFkPgo8IiBoZWlnaHQ9IjFhY3Jvc3MgdGhlIG9yaWVudGF0aW9uKTs8L3NjcmlwdD5pbXBsZW1lbnRlZGNhbiBiZSBzZWVudGhlcmUgd2FzIGFkZW1vbnN0cmF0ZWNvbnRhaW5lciI+Y29ubmVjdGlvbnN0aGUgQnJpdGlzaHdhcyB3cml0dGVuIWltcG9ydGFudDtweDsgbWFyZ2luLWZvbGxvd2VkIGJ5YWJpbGl0eSB0byBjb21wbGljYXRlZGR1cmluZyB0aGUgaW1taWdyYXRpb25hbHNvIGNhbGxlZDxoNCBjbGFzcz0iZGlzdGluY3Rpb25yZXBsYWNlZCBieWdvdmVybm1lbnRzbG9jYXRpb24gb2ZpbiBOb3ZlbWJlcndoZXRoZXIgdGhlPC9wPgo8L2Rpdj5hY3F1aXNpdGlvbmNhbGxlZCB0aGUgcGVyc2VjdXRpb25kZXNpZ25hdGlvbntmb250LXNpemU6YXBwZWFyZWQgaW5pbnZlc3RpZ2F0ZWV4cGVyaWVuY2VkbW9zdCBsaWtlbHl3aWRlbHkgdXNlZGRpc2N1c3Npb25zcHJlc2VuY2Ugb2YgKGRvY3VtZW50LmV4dGVuc2l2ZWx5SXQgaGFzIGJlZW5pdCBkb2VzIG5vdGNvbnRyYXJ5IHRvaW5oYWJpdGFudHNpbXByb3ZlbWVudHNjaG9sYXJzaGlwY29uc3VtcHRpb25pbnN0cnVjdGlvbmZvciBleGFtcGxlb25lIG9yIG1vcmVweDsgcGFkZGluZ3RoZSBjdXJyZW50YSBzZXJpZXMgb2ZhcmUgdXN1YWxseXJvbGUgaW4gdGhlcHJldmlvdXNseSBkZXJpdmF0aXZlc2V2aWRlbmNlIG9mZXhwZXJpZW5jZXNjb2xvcnNjaGVtZXN0YXRlZCB0aGF0Y2VydGlmaWNhdGU8L2E+PC9kaXY+CiBzZWxlY3RlZD0iaGlnaCBzY2hvb2xyZXNwb25zZSB0b2NvbWZvcnRhYmxlYWRvcHRpb24gb2Z0aHJlZSB5ZWFyc3RoZSBjb3VudHJ5aW4gRmVicnVhcnlzbyB0aGF0IHRoZXBlb3BsZSB3aG8gcHJvdmlkZWQgYnk8cGFyYW0gbmFtZWFmZmVjdGVkIGJ5aW4gdGVybXMgb2ZhcHBvaW50bWVudElTTy04ODU5LTEid2FzIGJvcm4gaW5oaXN0b3JpY2FsIHJlZ2FyZGVkIGFzbWVhc3VyZW1lbnRpcyBiYXNlZCBvbiBhbmQgb3RoZXIgOiBmdW5jdGlvbihzaWduaWZpY2FudGNlbGVicmF0aW9udHJhbnNtaXR0ZWQvanMvanF1ZXJ5LmlzIGtub3duIGFzdGhlb3JldGljYWwgdGFiaW5kZXg9Iml0IGNvdWxkIGJlPG5vc2NyaXB0PgpoYXZpbmcgYmVlbg0KPGhlYWQ+DQo8ICZxdW90O1RoZSBjb21waWxhdGlvbmhlIGhhZCBiZWVucHJvZHVjZWQgYnlwaGlsb3NvcGhlcmNvbnN0cnVjdGVkaW50ZW5kZWQgdG9hbW9uZyBvdGhlcmNvbXBhcmVkIHRvdG8gc2F5IHRoYXRFbmdpbmVlcmluZ2EgZGlmZmVyZW50cmVmZXJyZWQgdG9kaWZmZXJlbmNlc2JlbGllZiB0aGF0cGhvdG9ncmFwaHNpZGVudGlmeWluZ0hpc3Rvcnkgb2YgUmVwdWJsaWMgb2ZuZWNlc3NhcmlseXByb2JhYmlsaXR5dGVjaG5pY2FsbHlsZWF2aW5nIHRoZXNwZWN0YWN1bGFyZnJhY3Rpb24gb2ZlbGVjdHJpY2l0eWhlYWQgb2YgdGhlcmVzdGF1cmFudHNwYXJ0bmVyc2hpcGVtcGhhc2lzIG9ubW9zdCByZWNlbnRzaGFyZSB3aXRoIHNheWluZyB0aGF0ZmlsbGVkIHdpdGhkZXNpZ25lZCB0b2l0IGlzIG9mdGVuIj48L2lmcmFtZT5hcyBmb2xsb3dzOm1lcmdlZCB3aXRodGhyb3VnaCB0aGVjb21tZXJjaWFsIHBvaW50ZWQgb3V0b3Bwb3J0dW5pdHl2aWV3IG9mIHRoZXJlcXVpcmVtZW50ZGl2aXNpb24gb2Zwcm9ncmFtbWluZ2hlIHJlY2VpdmVkc2V0SW50ZXJ2YWwiPjwvc3Bhbj48L2luIE5ldyBZb3JrYWRkaXRpb25hbCBjb21wcmVzc2lvbgoKPGRpdiBpZD0iaW5jb3Jwb3JhdGU7PC9zY3JpcHQ+PGF0dGFjaEV2ZW50YmVjYW1lIHRoZSAiIHRhcmdldD0iX2NhcnJpZWQgb3V0U29tZSBvZiB0aGVzY2llbmNlIGFuZHRoZSB0aW1lIG9mQ29udGFpbmVyIj5tYWludGFpbmluZ0NocmlzdG9waGVyTXVjaCBvZiB0aGV3cml0aW5ncyBvZiIgaGVpZ2h0PSIyc2l6ZSBvZiB0aGV2ZXJzaW9uIG9mIG1peHR1cmUgb2YgYmV0d2VlbiB0aGVFeGFtcGxlcyBvZmVkdWNhdGlvbmFsY29tcGV0aXRpdmUgb25zdWJtaXQ9ImRpcmVjdG9yIG9mZGlzdGluY3RpdmUvRFREIFhIVE1MIHJlbGF0aW5nIHRvdGVuZGVuY3kgdG9wcm92aW5jZSBvZndoaWNoIHdvdWxkZGVzcGl0ZSB0aGVzY2llbnRpZmljIGxlZ2lzbGF0dXJlLmlubmVySFRNTCBhbGxlZ2F0aW9uc0FncmljdWx0dXJld2FzIHVzZWQgaW5hcHByb2FjaCB0b2ludGVsbGlnZW50eWVhcnMgbGF0ZXIsc2Fucy1zZXJpZmRldGVybWluaW5nUGVyZm9ybWFuY2VhcHBlYXJhbmNlcywgd2hpY2ggaXMgZm91bmRhdGlvbnNhYmJyZXZpYXRlZGhpZ2hlciB0aGFucyBmcm9tIHRoZSBpbmRpdmlkdWFsIGNvbXBvc2VkIG9mc3VwcG9zZWQgdG9jbGFpbXMgdGhhdGF0dHJpYnV0aW9uZm9udC1zaXplOjFlbGVtZW50cyBvZkhpc3RvcmljYWwgaGlzIGJyb3RoZXJhdCB0aGUgdGltZWFubml2ZXJzYXJ5Z292ZXJuZWQgYnlyZWxhdGVkIHRvIHVsdGltYXRlbHkgaW5ub3ZhdGlvbnNpdCBpcyBzdGlsbGNhbiBvbmx5IGJlZGVmaW5pdGlvbnN0b0dNVFN0cmluZ0EgbnVtYmVyIG9maW1nIGNsYXNzPSJFdmVudHVhbGx5LHdhcyBjaGFuZ2Vkb2NjdXJyZWQgaW5uZWlnaGJvcmluZ2Rpc3Rpbmd1aXNod2hlbiBoZSB3YXNpbnRyb2R1Y2luZ3RlcnJlc3RyaWFsTWFueSBvZiB0aGVhcmd1ZXMgdGhhdGFuIEFtZXJpY2FuY29ucXVlc3Qgb2Z3aWRlc3ByZWFkIHdlcmUga2lsbGVkc2NyZWVuIGFuZCBJbiBvcmRlciB0b2V4cGVjdGVkIHRvZGVzY2VuZGFudHNhcmUgbG9jYXRlZGxlZ2lzbGF0aXZlZ2VuZXJhdGlvbnMgYmFja2dyb3VuZG1vc3QgcGVvcGxleWVhcnMgYWZ0ZXJ0aGVyZSBpcyBub3RoZSBoaWdoZXN0ZnJlcXVlbnRseSB0aGV5IGRvIG5vdGFyZ3VlZCB0aGF0c2hvd2VkIHRoYXRwcmVkb21pbmFudHRoZW9sb2dpY2FsYnkgdGhlIHRpbWVjb25zaWRlcmluZ3Nob3J0LWxpdmVkPC9zcGFuPjwvYT5jYW4gYmUgdXNlZHZlcnkgbGl0dGxlb25lIG9mIHRoZSBoYWQgYWxyZWFkeWludGVycHJldGVkY29tbXVuaWNhdGVmZWF0dXJlcyBvZmdvdmVybm1lbnQsPC9ub3NjcmlwdD5lbnRlcmVkIHRoZSIgaGVpZ2h0PSIzSW5kZXBlbmRlbnRwb3B1bGF0aW9uc2xhcmdlLXNjYWxlLiBBbHRob3VnaCB1c2VkIGluIHRoZWRlc3RydWN0aW9ucG9zc2liaWxpdHlzdGFydGluZyBpbnR3byBvciBtb3JlZXhwcmVzc2lvbnNzdWJvcmRpbmF0ZWxhcmdlciB0aGFuaGlzdG9yeSBhbmQ8L29wdGlvbj4NCkNvbnRpbmVudGFsZWxpbWluYXRpbmd3aWxsIG5vdCBiZXByYWN0aWNlIG9maW4gZnJvbnQgb2ZzaXRlIG9mIHRoZWVuc3VyZSB0aGF0dG8gY3JlYXRlIGFtaXNzaXNzaXBwaXBvdGVudGlhbGx5b3V0c3RhbmRpbmdiZXR0ZXIgdGhhbndoYXQgaXMgbm93c2l0dWF0ZWQgaW5tZXRhIG5hbWU9IlRyYWRpdGlvbmFsc3VnZ2VzdGlvbnNUcmFuc2xhdGlvbnRoZSBmb3JtIG9mYXRtb3NwaGVyaWNpZGVvbG9naWNhbGVudGVycHJpc2VzY2FsY3VsYXRpbmdlYXN0IG9mIHRoZXJlbW5hbnRzIG9mcGx1Z2luc3BhZ2UvaW5kZXgucGhwP3JlbWFpbmVkIGludHJhbnNmb3JtZWRIZSB3YXMgYWxzb3dhcyBhbHJlYWR5c3RhdGlzdGljYWxpbiBmYXZvciBvZk1pbmlzdHJ5IG9mbW92ZW1lbnQgb2Zmb3JtdWxhdGlvbmlzIHJlcXVpcmVkPGxpbmsgcmVsPSJUaGlzIGlzIHRoZSA8YSBocmVmPSIvcG9wdWxhcml6ZWRpbnZvbHZlZCBpbmFyZSB1c2VkIHRvYW5kIHNldmVyYWxtYWRlIGJ5IHRoZXNlZW1zIHRvIGJlbGlrZWx5IHRoYXRQYWxlc3Rpbmlhbm5hbWVkIGFmdGVyaXQgaGFkIGJlZW5tb3N0IGNvbW1vbnRvIHJlZmVyIHRvYnV0IHRoaXMgaXNjb25zZWN1dGl2ZXRlbXBvcmFyaWx5SW4gZ2VuZXJhbCxjb252ZW50aW9uc3Rha2VzIHBsYWNlc3ViZGl2aXNpb250ZXJyaXRvcmlhbG9wZXJhdGlvbmFscGVybWFuZW50bHl3YXMgbGFyZ2VseW91dGJyZWFrIG9maW4gdGhlIHBhc3Rmb2xsb3dpbmcgYSB4bWxuczpvZz0iPjxhIGNsYXNzPSJjbGFzcz0idGV4dENvbnZlcnNpb24gbWF5IGJlIHVzZWRtYW51ZmFjdHVyZWFmdGVyIGJlaW5nY2xlYXJmaXgiPgpxdWVzdGlvbiBvZndhcyBlbGVjdGVkdG8gYmVjb21lIGFiZWNhdXNlIG9mIHNvbWUgcGVvcGxlaW5zcGlyZWQgYnlzdWNjZXNzZnVsIGEgdGltZSB3aGVubW9yZSBjb21tb25hbW9uZ3N0IHRoZWFuIG9mZmljaWFsd2lkdGg6MTAwJTt0ZWNobm9sb2d5LHdhcyBhZG9wdGVkdG8ga2VlcCB0aGVzZXR0bGVtZW50c2xpdmUgYmlydGhzaW5kZXguaHRtbCJDb25uZWN0aWN1dGFzc2lnbmVkIHRvJmFtcDt0aW1lczthY2NvdW50IGZvcmFsaWduPXJpZ2h0dGhlIGNvbXBhbnlhbHdheXMgYmVlbnJldHVybmVkIHRvaW52b2x2ZW1lbnRCZWNhdXNlIHRoZXRoaXMgcGVyaW9kIiBuYW1lPSJxIiBjb25maW5lZCB0b2EgcmVzdWx0IG9mdmFsdWU9IiIgLz5pcyBhY3R1YWxseUVudmlyb25tZW50DQo8L2hlYWQ+DQpDb252ZXJzZWx5LD4KPGRpdiBpZD0iMCIgd2lkdGg9IjFpcyBwcm9iYWJseWhhdmUgYmVjb21lY29udHJvbGxpbmd0aGUgcHJvYmxlbWNpdGl6ZW5zIG9mcG9saXRpY2lhbnNyZWFjaGVkIHRoZWFzIGVhcmx5IGFzOm5vbmU7IG92ZXI8dGFibGUgY2VsbHZhbGlkaXR5IG9mZGlyZWN0bHkgdG9vbm1vdXNlZG93bndoZXJlIGl0IGlzd2hlbiBpdCB3YXNtZW1iZXJzIG9mIHJlbGF0aW9uIHRvYWNjb21tb2RhdGVhbG9uZyB3aXRoIEluIHRoZSBsYXRldGhlIEVuZ2xpc2hkZWxpY2lvdXMiPnRoaXMgaXMgbm90dGhlIHByZXNlbnRpZiB0aGV5IGFyZWFuZCBmaW5hbGx5YSBtYXR0ZXIgb2YNCgk8L2Rpdj4NCg0KPC9zY3JpcHQ+ZmFzdGVyIHRoYW5tYWpvcml0eSBvZmFmdGVyIHdoaWNoY29tcGFyYXRpdmV0byBtYWludGFpbmltcHJvdmUgdGhlYXdhcmRlZCB0aGVlciIgY2xhc3M9ImZyYW1lYm9yZGVycmVzdG9yYXRpb25pbiB0aGUgc2FtZWFuYWx5c2lzIG9mdGhlaXIgZmlyc3REdXJpbmcgdGhlIGNvbnRpbmVudGFsc2VxdWVuY2Ugb2ZmdW5jdGlvbigpe2ZvbnQtc2l6ZTogd29yayBvbiB0aGU8L3NjcmlwdD4KPGJlZ2lucyB3aXRoamF2YXNjcmlwdDpjb25zdGl0dWVudHdhcyBmb3VuZGVkZXF1aWxpYnJpdW1hc3N1bWUgdGhhdGlzIGdpdmVuIGJ5bmVlZHMgdG8gYmVjb29yZGluYXRlc3RoZSB2YXJpb3VzYXJlIHBhcnQgb2Zvbmx5IGluIHRoZXNlY3Rpb25zIG9maXMgYSBjb21tb250aGVvcmllcyBvZmRpc2NvdmVyaWVzYXNzb2NpYXRpb25lZGdlIG9mIHRoZXN0cmVuZ3RoIG9mcG9zaXRpb24gaW5wcmVzZW50LWRheXVuaXZlcnNhbGx5dG8gZm9ybSB0aGVidXQgaW5zdGVhZGNvcnBvcmF0aW9uYXR0YWNoZWQgdG9pcyBjb21tb25seXJlYXNvbnMgZm9yICZxdW90O3RoZSBjYW4gYmUgbWFkZXdhcyBhYmxlIHRvd2hpY2ggbWVhbnNidXQgZGlkIG5vdG9uTW91c2VPdmVyYXMgcG9zc2libGVvcGVyYXRlZCBieWNvbWluZyBmcm9tdGhlIHByaW1hcnlhZGRpdGlvbiBvZmZvciBzZXZlcmFsdHJhbnNmZXJyZWRhIHBlcmlvZCBvZmFyZSBhYmxlIHRvaG93ZXZlciwgaXRzaG91bGQgaGF2ZW11Y2ggbGFyZ2VyCgk8L3NjcmlwdD5hZG9wdGVkIHRoZXByb3BlcnR5IG9mZGlyZWN0ZWQgYnllZmZlY3RpdmVseXdhcyBicm91Z2h0Y2hpbGRyZW4gb2ZQcm9ncmFtbWluZ2xvbmdlciB0aGFubWFudXNjcmlwdHN3YXIgYWdhaW5zdGJ5IG1lYW5zIG9mYW5kIG1vc3Qgb2ZzaW1pbGFyIHRvIHByb3ByaWV0YXJ5b3JpZ2luYXRpbmdwcmVzdGlnaW91c2dyYW1tYXRpY2FsZXhwZXJpZW5jZS50byBtYWtlIHRoZUl0IHdhcyBhbHNvaXMgZm91bmQgaW5jb21wZXRpdG9yc2luIHRoZSBVLlMucmVwbGFjZSB0aGVicm91Z2h0IHRoZWNhbGN1bGF0aW9uZmFsbCBvZiB0aGV0aGUgZ2VuZXJhbHByYWN0aWNhbGx5aW4gaG9ub3Igb2ZyZWxlYXNlZCBpbnJlc2lkZW50aWFsYW5kIHNvbWUgb2ZraW5nIG9mIHRoZXJlYWN0aW9uIHRvMXN0IEVhcmwgb2ZjdWx0dXJlIGFuZHByaW5jaXBhbGx5PC90aXRsZT4KICB0aGV5IGNhbiBiZWJhY2sgdG8gdGhlc29tZSBvZiBoaXNleHBvc3VyZSB0b2FyZSBzaW1pbGFyZm9ybSBvZiB0aGVhZGRGYXZvcml0ZWNpdGl6ZW5zaGlwcGFydCBpbiB0aGVwZW9wbGUgd2l0aGluIHByYWN0aWNldG8gY29udGludWUmYW1wO21pbnVzO2FwcHJvdmVkIGJ5IHRoZSBmaXJzdCBhbGxvd2VkIHRoZWFuZCBmb3IgdGhlZnVuY3Rpb25pbmdwbGF5aW5nIHRoZXNvbHV0aW9uIHRvaGVpZ2h0PSIwIiBpbiBoaXMgYm9va21vcmUgdGhhbiBhZm9sbG93cyB0aGVjcmVhdGVkIHRoZXByZXNlbmNlIGluJm5ic3A7PC90ZD5uYXRpb25hbGlzdHRoZSBpZGVhIG9mYSBjaGFyYWN0ZXJ3ZXJlIGZvcmNlZCBjbGFzcz0iYnRuZGF5cyBvZiB0aGVmZWF0dXJlZCBpbnNob3dpbmcgdGhlaW50ZXJlc3QgaW5pbiBwbGFjZSBvZnR1cm4gb2YgdGhldGhlIGhlYWQgb2ZMb3JkIG9mIHRoZXBvbGl0aWNhbGx5aGFzIGl0cyBvd25FZHVjYXRpb25hbGFwcHJvdmFsIG9mc29tZSBvZiB0aGVlYWNoIG90aGVyLGJlaGF2aW9yIG9mYW5kIGJlY2F1c2VhbmQgYW5vdGhlcmFwcGVhcmVkIG9ucmVjb3JkZWQgaW5ibGFjayZxdW90O21heSBpbmNsdWRldGhlIHdvcmxkJ3NjYW4gbGVhZCB0b3JlZmVycyB0byBhYm9yZGVyPSIwIiBnb3Zlcm5tZW50IHdpbm5pbmcgdGhlcmVzdWx0ZWQgaW4gd2hpbGUgdGhlIFdhc2hpbmd0b24sdGhlIHN1YmplY3RjaXR5IGluIHRoZT48L2Rpdj4NCgkJcmVmbGVjdCB0aGV0byBjb21wbGV0ZWJlY2FtZSBtb3JlcmFkaW9hY3RpdmVyZWplY3RlZCBieXdpdGhvdXQgYW55aGlzIGZhdGhlcix3aGljaCBjb3VsZGNvcHkgb2YgdGhldG8gaW5kaWNhdGVhIHBvbGl0aWNhbGFjY291bnRzIG9mY29uc3RpdHV0ZXN3b3JrZWQgd2l0aGVyPC9hPjwvbGk+b2YgaGlzIGxpZmVhY2NvbXBhbmllZGNsaWVudFdpZHRocHJldmVudCB0aGVMZWdpc2xhdGl2ZWRpZmZlcmVudGx5dG9nZXRoZXIgaW5oYXMgc2V2ZXJhbGZvciBhbm90aGVydGV4dCBvZiB0aGVmb3VuZGVkIHRoZWUgd2l0aCB0aGUgaXMgdXNlZCBmb3JjaGFuZ2VkIHRoZXVzdWFsbHkgdGhlcGxhY2Ugd2hlcmV3aGVyZWFzIHRoZT4gPGEgaHJlZj0iIj48YSBocmVmPSJ0aGVtc2VsdmVzLGFsdGhvdWdoIGhldGhhdCBjYW4gYmV0cmFkaXRpb25hbHJvbGUgb2YgdGhlYXMgYSByZXN1bHRyZW1vdmVDaGlsZGRlc2lnbmVkIGJ5d2VzdCBvZiB0aGVTb21lIHBlb3BsZXByb2R1Y3Rpb24sc2lkZSBvZiB0aGVuZXdzbGV0dGVyc3VzZWQgYnkgdGhlZG93biB0byB0aGVhY2NlcHRlZCBieWxpdmUgaW4gdGhlYXR0ZW1wdHMgdG9vdXRzaWRlIHRoZWZyZXF1ZW5jaWVzSG93ZXZlciwgaW5wcm9ncmFtbWVyc2F0IGxlYXN0IGluYXBwcm94aW1hdGVhbHRob3VnaCBpdHdhcyBwYXJ0IG9mYW5kIHZhcmlvdXNHb3Zlcm5vciBvZnRoZSBhcnRpY2xldHVybmVkIGludG8+PGEgaHJlZj0iL3RoZSBlY29ub215aXMgdGhlIG1vc3Rtb3N0IHdpZGVseXdvdWxkIGxhdGVyYW5kIHBlcmhhcHNyaXNlIHRvIHRoZW9jY3VycyB3aGVudW5kZXIgd2hpY2hjb25kaXRpb25zLnRoZSB3ZXN0ZXJudGhlb3J5IHRoYXRpcyBwcm9kdWNlZHRoZSBjaXR5IG9maW4gd2hpY2ggaGVzZWVuIGluIHRoZXRoZSBjZW50cmFsYnVpbGRpbmcgb2ZtYW55IG9mIGhpc2FyZWEgb2YgdGhlaXMgdGhlIG9ubHltb3N0IG9mIHRoZW1hbnkgb2YgdGhldGhlIFdlc3Rlcm5UaGVyZSBpcyBub2V4dGVuZGVkIHRvU3RhdGlzdGljYWxjb2xzcGFuPTIgfHNob3J0IHN0b3J5cG9zc2libGUgdG90b3BvbG9naWNhbGNyaXRpY2FsIG9mcmVwb3J0ZWQgdG9hIENocmlzdGlhbmRlY2lzaW9uIHRvaXMgZXF1YWwgdG9wcm9ibGVtcyBvZlRoaXMgY2FuIGJlbWVyY2hhbmRpc2Vmb3IgbW9zdCBvZm5vIGV2aWRlbmNlZWRpdGlvbnMgb2ZlbGVtZW50cyBpbiZxdW90Oy4gVGhlY29tL2ltYWdlcy93aGljaCBtYWtlc3RoZSBwcm9jZXNzcmVtYWlucyB0aGVsaXRlcmF0dXJlLGlzIGEgbWVtYmVydGhlIHBvcHVsYXJ0aGUgYW5jaWVudHByb2JsZW1zIGludGltZSBvZiB0aGVkZWZlYXRlZCBieWJvZHkgb2YgdGhlYSBmZXcgeWVhcnNtdWNoIG9mIHRoZXRoZSB3b3JrIG9mQ2FsaWZvcm5pYSxzZXJ2ZWQgYXMgYWdvdmVybm1lbnQuY29uY2VwdHMgb2Ztb3ZlbWVudCBpbgkJPGRpdiBpZD0iaXQiIHZhbHVlPSJsYW5ndWFnZSBvZmFzIHRoZXkgYXJlcHJvZHVjZWQgaW5pcyB0aGF0IHRoZWV4cGxhaW4gdGhlZGl2PjwvZGl2PgpIb3dldmVyIHRoZWxlYWQgdG8gdGhlCTxhIGhyZWY9Ii93YXMgZ3JhbnRlZHBlb3BsZSBoYXZlY29udGludWFsbHl3YXMgc2VlbiBhc2FuZCByZWxhdGVkdGhlIHJvbGUgb2Zwcm9wb3NlZCBieW9mIHRoZSBiZXN0ZWFjaCBvdGhlci5Db25zdGFudGluZXBlb3BsZSBmcm9tZGlhbGVjdHMgb2Z0byByZXZpc2lvbndhcyByZW5hbWVkYSBzb3VyY2Ugb2Z0aGUgaW5pdGlhbGxhdW5jaGVkIGlucHJvdmlkZSB0aGV0byB0aGUgd2VzdHdoZXJlIHRoZXJlYW5kIHNpbWlsYXJiZXR3ZWVuIHR3b2lzIGFsc28gdGhlRW5nbGlzaCBhbmRjb25kaXRpb25zLHRoYXQgaXQgd2FzZW50aXRsZWQgdG90aGVtc2VsdmVzLnF1YW50aXR5IG9mcmFuc3BhcmVuY3l0aGUgc2FtZSBhc3RvIGpvaW4gdGhlY291bnRyeSBhbmR0aGlzIGlzIHRoZVRoaXMgbGVkIHRvYSBzdGF0ZW1lbnRjb250cmFzdCB0b2xhc3RJbmRleE9mdGhyb3VnaCBoaXNpcyBkZXNpZ25lZHRoZSB0ZXJtIGlzaXMgcHJvdmlkZWRwcm90ZWN0IHRoZW5nPC9hPjwvbGk+VGhlIGN1cnJlbnR0aGUgc2l0ZSBvZnN1YnN0YW50aWFsZXhwZXJpZW5jZSxpbiB0aGUgV2VzdHRoZXkgc2hvdWxkc2xvdmVuxI1pbmFjb21lbnRhcmlvc3VuaXZlcnNpZGFkY29uZGljaW9uZXNhY3RpdmlkYWRlc2V4cGVyaWVuY2lhdGVjbm9sb2fDrWFwcm9kdWNjacOzbnB1bnR1YWNpw7NuYXBsaWNhY2nDs25jb250cmFzZcOxYWNhdGVnb3LDrWFzcmVnaXN0cmFyc2Vwcm9mZXNpb25hbHRyYXRhbWllbnRvcmVnw61zdHJhdGVzZWNyZXRhcsOtYXByaW5jaXBhbGVzcHJvdGVjY2nDs25pbXBvcnRhbnRlc2ltcG9ydGFuY2lhcG9zaWJpbGlkYWRpbnRlcmVzYW50ZWNyZWNpbWllbnRvbmVjZXNpZGFkZXNzdXNjcmliaXJzZWFzb2NpYWNpw7NuZGlzcG9uaWJsZXNldmFsdWFjacOzbmVzdHVkaWFudGVzcmVzcG9uc2FibGVyZXNvbHVjacOzbmd1YWRhbGFqYXJhcmVnaXN0cmFkb3NvcG9ydHVuaWRhZGNvbWVyY2lhbGVzZm90b2dyYWbDrWFhdXRvcmlkYWRlc2luZ2VuaWVyw61hdGVsZXZpc2nDs25jb21wZXRlbmNpYW9wZXJhY2lvbmVzZXN0YWJsZWNpZG9zaW1wbGVtZW50ZWFjdHVhbG1lbnRlbmF2ZWdhY2nDs25jb25mb3JtaWRhZGxpbmUtaGVpZ2h0OmZvbnQtZmFtaWx5OiIgOiAiaHR0cDovL2FwcGxpY2F0aW9uc2xpbmsiIGhyZWY9InNwZWNpZmljYWxseS8vPCFbQ0RBVEFbCk9yZ2FuaXphdGlvbmRpc3RyaWJ1dGlvbjBweDsgaGVpZ2h0OnJlbGF0aW9uc2hpcGRldmljZS13aWR0aDxkaXYgY2xhc3M9IjxsYWJlbCBmb3I9InJlZ2lzdHJhdGlvbjwvbm9zY3JpcHQ+Ci9pbmRleC5odG1sIndpbmRvdy5vcGVuKCAhaW1wb3J0YW50O2FwcGxpY2F0aW9uL2luZGVwZW5kZW5jZS8vd3d3Lmdvb2dsZW9yZ2FuaXphdGlvbmF1dG9jb21wbGV0ZXJlcXVpcmVtZW50c2NvbnNlcnZhdGl2ZTxmb3JtIG5hbWU9ImludGVsbGVjdHVhbG1hcmdpbi1sZWZ0OjE4dGggY2VudHVyeWFuIGltcG9ydGFudGluc3RpdHV0aW9uc2FiYnJldmlhdGlvbjxpbWcgY2xhc3M9Im9yZ2FuaXNhdGlvbmNpdmlsaXphdGlvbjE5dGggY2VudHVyeWFyY2hpdGVjdHVyZWluY29ycG9yYXRlZDIwdGggY2VudHVyeS1jb250YWluZXIiPm1vc3Qgbm90YWJseS8+PC9hPjwvZGl2Pm5vdGlmaWNhdGlvbid1bmRlZmluZWQnKUZ1cnRoZXJtb3JlLGJlbGlldmUgdGhhdGlubmVySFRNTCA9IHByaW9yIHRvIHRoZWRyYW1hdGljYWxseXJlZmVycmluZyB0b25lZ290aWF0aW9uc2hlYWRxdWFydGVyc1NvdXRoIEFmcmljYXVuc3VjY2Vzc2Z1bFBlbm5zeWx2YW5pYUFzIGEgcmVzdWx0LDxodG1sIGxhbmc9IiZsdDsvc3VwJmd0O2RlYWxpbmcgd2l0aHBoaWxhZGVscGhpYWhpc3RvcmljYWxseSk7PC9zY3JpcHQ+CnBhZGRpbmctdG9wOmV4cGVyaW1lbnRhbGdldEF0dHJpYnV0ZWluc3RydWN0aW9uc3RlY2hub2xvZ2llc3BhcnQgb2YgdGhlID1mdW5jdGlvbigpe3N1YnNjcmlwdGlvbmwuZHRkIj4NCjxodGdlb2dyYXBoaWNhbENvbnN0aXR1dGlvbicsIGZ1bmN0aW9uKHN1cHBvcnRlZCBieWFncmljdWx0dXJhbGNvbnN0cnVjdGlvbnB1YmxpY2F0aW9uc2ZvbnQtc2l6ZTogMWEgdmFyaWV0eSBvZjxkaXYgc3R5bGU9IkVuY3ljbG9wZWRpYWlmcmFtZSBzcmM9ImRlbW9uc3RyYXRlZGFjY29tcGxpc2hlZHVuaXZlcnNpdGllc0RlbW9ncmFwaGljcyk7PC9zY3JpcHQ+PGRlZGljYXRlZCB0b2tub3dsZWRnZSBvZnNhdGlzZmFjdGlvbnBhcnRpY3VsYXJseTwvZGl2PjwvZGl2PkVuZ2xpc2ggKFVTKWFwcGVuZENoaWxkKHRyYW5zbWlzc2lvbnMuIEhvd2V2ZXIsIGludGVsbGlnZW5jZSIgdGFiaW5kZXg9ImZsb2F0OnJpZ2h0O0NvbW1vbndlYWx0aHJhbmdpbmcgZnJvbWluIHdoaWNoIHRoZWF0IGxlYXN0IG9uZXJlcHJvZHVjdGlvbmVuY3ljbG9wZWRpYTtmb250LXNpemU6MWp1cmlzZGljdGlvbmF0IHRoYXQgdGltZSI+PGEgY2xhc3M9IkluIGFkZGl0aW9uLGRlc2NyaXB0aW9uK2NvbnZlcnNhdGlvbmNvbnRhY3Qgd2l0aGlzIGdlbmVyYWxseXIiIGNvbnRlbnQ9InJlcHJlc2VudGluZyZsdDttYXRoJmd0O3ByZXNlbnRhdGlvbm9jY2FzaW9uYWxseTxpbWcgd2lkdGg9Im5hdmlnYXRpb24iPmNvbXBlbnNhdGlvbmNoYW1waW9uc2hpcG1lZGlhPSJhbGwiIHZpb2xhdGlvbiBvZnJlZmVyZW5jZSB0b3JldHVybiB0cnVlO1N0cmljdC8vRU4iIHRyYW5zYWN0aW9uc2ludGVydmVudGlvbnZlcmlmaWNhdGlvbkluZm9ybWF0aW9uIGRpZmZpY3VsdGllc0NoYW1waW9uc2hpcGNhcGFiaWxpdGllczwhW2VuZGlmXS0tPn0KPC9zY3JpcHQ+CkNocmlzdGlhbml0eWZvciBleGFtcGxlLFByb2Zlc3Npb25hbHJlc3RyaWN0aW9uc3N1Z2dlc3QgdGhhdHdhcyByZWxlYXNlZChzdWNoIGFzIHRoZXJlbW92ZUNsYXNzKHVuZW1wbG95bWVudHRoZSBBbWVyaWNhbnN0cnVjdHVyZSBvZi9pbmRleC5odG1sIHB1Ymxpc2hlZCBpbnNwYW4gY2xhc3M9IiI+PGEgaHJlZj0iL2ludHJvZHVjdGlvbmJlbG9uZ2luZyB0b2NsYWltZWQgdGhhdGNvbnNlcXVlbmNlczxtZXRhIG5hbWU9Ikd1aWRlIHRvIHRoZW92ZXJ3aGVsbWluZ2FnYWluc3QgdGhlIGNvbmNlbnRyYXRlZCwKLm5vbnRvdWNoIG9ic2VydmF0aW9uczwvYT4KPC9kaXY+CmYgKGRvY3VtZW50LmJvcmRlcjogMXB4IHtmb250LXNpemU6MXRyZWF0bWVudCBvZjAiIGhlaWdodD0iMW1vZGlmaWNhdGlvbkluZGVwZW5kZW5jZWRpdmlkZWQgaW50b2dyZWF0ZXIgdGhhbmFjaGlldmVtZW50c2VzdGFibGlzaGluZ0phdmFTY3JpcHQiIG5ldmVydGhlbGVzc3NpZ25pZmljYW5jZUJyb2FkY2FzdGluZz4mbmJzcDs8L3RkPmNvbnRhaW5lciI+CnN1Y2ggYXMgdGhlIGluZmx1ZW5jZSBvZmEgcGFydGljdWxhcnNyYz0naHR0cDovL25hdmlnYXRpb24iIGhhbGYgb2YgdGhlIHN1YnN0YW50aWFsICZuYnNwOzwvZGl2PmFkdmFudGFnZSBvZmRpc2NvdmVyeSBvZmZ1bmRhbWVudGFsIG1ldHJvcG9saXRhbnRoZSBvcHBvc2l0ZSIgeG1sOmxhbmc9ImRlbGliZXJhdGVseWFsaWduPWNlbnRlcmV2b2x1dGlvbiBvZnByZXNlcnZhdGlvbmltcHJvdmVtZW50c2JlZ2lubmluZyBpbkplc3VzIENocmlzdFB1YmxpY2F0aW9uc2Rpc2FncmVlbWVudHRleHQtYWxpZ246ciwgZnVuY3Rpb24oKXNpbWlsYXJpdGllc2JvZHk+PC9odG1sPmlzIGN1cnJlbnRseWFscGhhYmV0aWNhbGlzIHNvbWV0aW1lc3R5cGU9ImltYWdlL21hbnkgb2YgdGhlIGZsb3c6aGlkZGVuO2F2YWlsYWJsZSBpbmRlc2NyaWJlIHRoZWV4aXN0ZW5jZSBvZmFsbCBvdmVyIHRoZXRoZSBJbnRlcm5ldAk8dWwgY2xhc3M9Imluc3RhbGxhdGlvbm5laWdoYm9yaG9vZGFybWVkIGZvcmNlc3JlZHVjaW5nIHRoZWNvbnRpbnVlcyB0b05vbmV0aGVsZXNzLHRlbXBlcmF0dXJlcwoJCTxhIGhyZWY9ImNsb3NlIHRvIHRoZWV4YW1wbGVzIG9mIGlzIGFib3V0IHRoZShzZWUgYmVsb3cpLiIgaWQ9InNlYXJjaHByb2Zlc3Npb25hbGlzIGF2YWlsYWJsZXRoZSBvZmZpY2lhbAkJPC9zY3JpcHQ+CgoJCTxkaXYgaWQ9ImFjY2VsZXJhdGlvbnRocm91Z2ggdGhlIEhhbGwgb2YgRmFtZWRlc2NyaXB0aW9uc3RyYW5zbGF0aW9uc2ludGVyZmVyZW5jZSB0eXBlPSd0ZXh0L3JlY2VudCB5ZWFyc2luIHRoZSB3b3JsZHZlcnkgcG9wdWxhcntiYWNrZ3JvdW5kOnRyYWRpdGlvbmFsIHNvbWUgb2YgdGhlIGNvbm5lY3RlZCB0b2V4cGxvaXRhdGlvbmVtZXJnZW5jZSBvZmNvbnN0aXR1dGlvbkEgSGlzdG9yeSBvZnNpZ25pZmljYW50IG1hbnVmYWN0dXJlZGV4cGVjdGF0aW9ucz48bm9zY3JpcHQ+PGNhbiBiZSBmb3VuZGJlY2F1c2UgdGhlIGhhcyBub3QgYmVlbm5laWdoYm91cmluZ3dpdGhvdXQgdGhlIGFkZGVkIHRvIHRoZQk8bGkgY2xhc3M9Imluc3RydW1lbnRhbFNvdmlldCBVbmlvbmFja25vd2xlZGdlZHdoaWNoIGNhbiBiZW5hbWUgZm9yIHRoZWF0dGVudGlvbiB0b2F0dGVtcHRzIHRvIGRldmVsb3BtZW50c0luIGZhY3QsIHRoZTxsaSBjbGFzcz0iYWltcGxpY2F0aW9uc3N1aXRhYmxlIGZvcm11Y2ggb2YgdGhlIGNvbG9uaXphdGlvbnByZXNpZGVudGlhbGNhbmNlbEJ1YmJsZSBJbmZvcm1hdGlvbm1vc3Qgb2YgdGhlIGlzIGRlc2NyaWJlZHJlc3Qgb2YgdGhlIG1vcmUgb3IgbGVzc2luIFNlcHRlbWJlckludGVsbGlnZW5jZXNyYz0iaHR0cDovL3B4OyBoZWlnaHQ6IGF2YWlsYWJsZSB0b21hbnVmYWN0dXJlcmh1bWFuIHJpZ2h0c2xpbmsgaHJlZj0iL2F2YWlsYWJpbGl0eXByb3BvcnRpb25hbG91dHNpZGUgdGhlIGFzdHJvbm9taWNhbGh1bWFuIGJlaW5nc25hbWUgb2YgdGhlIGFyZSBmb3VuZCBpbmFyZSBiYXNlZCBvbnNtYWxsZXIgdGhhbmEgcGVyc29uIHdob2V4cGFuc2lvbiBvZmFyZ3VpbmcgdGhhdG5vdyBrbm93biBhc0luIHRoZSBlYXJseWludGVybWVkaWF0ZWRlcml2ZWQgZnJvbVNjYW5kaW5hdmlhbjwvYT48L2Rpdj4NCmNvbnNpZGVyIHRoZWFuIGVzdGltYXRlZHRoZSBOYXRpb25hbDxkaXYgaWQ9InBhZ3Jlc3VsdGluZyBpbmNvbW1pc3Npb25lZGFuYWxvZ291cyB0b2FyZSByZXF1aXJlZC91bD4KPC9kaXY+CndhcyBiYXNlZCBvbmFuZCBiZWNhbWUgYSZuYnNwOyZuYnNwO3QiIHZhbHVlPSIiIHdhcyBjYXB0dXJlZG5vIG1vcmUgdGhhbnJlc3BlY3RpdmVseWNvbnRpbnVlIHRvID4NCjxoZWFkPg0KPHdlcmUgY3JlYXRlZG1vcmUgZ2VuZXJhbGluZm9ybWF0aW9uIHVzZWQgZm9yIHRoZWluZGVwZW5kZW50IHRoZSBJbXBlcmlhbGNvbXBvbmVudCBvZnRvIHRoZSBub3J0aGluY2x1ZGUgdGhlIENvbnN0cnVjdGlvbnNpZGUgb2YgdGhlIHdvdWxkIG5vdCBiZWZvciBpbnN0YW5jZWludmVudGlvbiBvZm1vcmUgY29tcGxleGNvbGxlY3RpdmVseWJhY2tncm91bmQ6IHRleHQtYWxpZ246IGl0cyBvcmlnaW5hbGludG8gYWNjb3VudHRoaXMgcHJvY2Vzc2FuIGV4dGVuc2l2ZWhvd2V2ZXIsIHRoZXRoZXkgYXJlIG5vdHJlamVjdGVkIHRoZWNyaXRpY2lzbSBvZmR1cmluZyB3aGljaHByb2JhYmx5IHRoZXRoaXMgYXJ0aWNsZShmdW5jdGlvbigpe0l0IHNob3VsZCBiZWFuIGFncmVlbWVudGFjY2lkZW50YWxseWRpZmZlcnMgZnJvbUFyY2hpdGVjdHVyZWJldHRlciBrbm93bmFycmFuZ2VtZW50c2luZmx1ZW5jZSBvbmF0dGVuZGVkIHRoZWlkZW50aWNhbCB0b3NvdXRoIG9mIHRoZXBhc3MgdGhyb3VnaHhtbCIgdGl0bGU9IndlaWdodDpib2xkO2NyZWF0aW5nIHRoZWRpc3BsYXk6bm9uZXJlcGxhY2VkIHRoZTxpbWcgc3JjPSIvaWh0dHBzOi8vd3d3LldvcmxkIFdhciBJSXRlc3RpbW9uaWFsc2ZvdW5kIGluIHRoZXJlcXVpcmVkIHRvIGFuZCB0aGF0IHRoZWJldHdlZW4gdGhlIHdhcyBkZXNpZ25lZGNvbnNpc3RzIG9mIGNvbnNpZGVyYWJseXB1Ymxpc2hlZCBieXRoZSBsYW5ndWFnZUNvbnNlcnZhdGlvbmNvbnNpc3RlZCBvZnJlZmVyIHRvIHRoZWJhY2sgdG8gdGhlIGNzcyIgbWVkaWE9IlBlb3BsZSBmcm9tIGF2YWlsYWJsZSBvbnByb3ZlZCB0byBiZXN1Z2dlc3Rpb25zIndhcyBrbm93biBhc3ZhcmlldGllcyBvZmxpa2VseSB0byBiZWNvbXByaXNlZCBvZnN1cHBvcnQgdGhlIGhhbmRzIG9mIHRoZWNvdXBsZWQgd2l0aGNvbm5lY3QgYW5kIGJvcmRlcjpub25lO3BlcmZvcm1hbmNlc2JlZm9yZSBiZWluZ2xhdGVyIGJlY2FtZWNhbGN1bGF0aW9uc29mdGVuIGNhbGxlZHJlc2lkZW50cyBvZm1lYW5pbmcgdGhhdD48bGkgY2xhc3M9ImV2aWRlbmNlIGZvcmV4cGxhbmF0aW9uc2Vudmlyb25tZW50cyI+PC9hPjwvZGl2PndoaWNoIGFsbG93c0ludHJvZHVjdGlvbmRldmVsb3BlZCBieWEgd2lkZSByYW5nZW9uIGJlaGFsZiBvZnZhbGlnbj0idG9wInByaW5jaXBsZSBvZmF0IHRoZSB0aW1lLDwvbm9zY3JpcHQ+DXNhaWQgdG8gaGF2ZWluIHRoZSBmaXJzdHdoaWxlIG90aGVyc2h5cG90aGV0aWNhbHBoaWxvc29waGVyc3Bvd2VyIG9mIHRoZWNvbnRhaW5lZCBpbnBlcmZvcm1lZCBieWluYWJpbGl0eSB0b3dlcmUgd3JpdHRlbnNwYW4gc3R5bGU9ImlucHV0IG5hbWU9InRoZSBxdWVzdGlvbmludGVuZGVkIGZvcnJlamVjdGlvbiBvZmltcGxpZXMgdGhhdGludmVudGVkIHRoZXRoZSBzdGFuZGFyZHdhcyBwcm9iYWJseWxpbmsgYmV0d2VlbnByb2Zlc3NvciBvZmludGVyYWN0aW9uc2NoYW5naW5nIHRoZUluZGlhbiBPY2VhbiBjbGFzcz0ibGFzdHdvcmtpbmcgd2l0aCdodHRwOi8vd3d3LnllYXJzIGJlZm9yZVRoaXMgd2FzIHRoZXJlY3JlYXRpb25hbGVudGVyaW5nIHRoZW1lYXN1cmVtZW50c2FuIGV4dHJlbWVseXZhbHVlIG9mIHRoZXN0YXJ0IG9mIHRoZQo8L3NjcmlwdD4KCmFuIGVmZm9ydCB0b2luY3JlYXNlIHRoZXRvIHRoZSBzb3V0aHNwYWNpbmc9IjAiPnN1ZmZpY2llbnRseXRoZSBFdXJvcGVhbmNvbnZlcnRlZCB0b2NsZWFyVGltZW91dGRpZCBub3QgaGF2ZWNvbnNlcXVlbnRseWZvciB0aGUgbmV4dGV4dGVuc2lvbiBvZmVjb25vbWljIGFuZGFsdGhvdWdoIHRoZWFyZSBwcm9kdWNlZGFuZCB3aXRoIHRoZWluc3VmZmljaWVudGdpdmVuIGJ5IHRoZXN0YXRpbmcgdGhhdGV4cGVuZGl0dXJlczwvc3Bhbj48L2E+CnRob3VnaHQgdGhhdG9uIHRoZSBiYXNpc2NlbGxwYWRkaW5nPWltYWdlIG9mIHRoZXJldHVybmluZyB0b2luZm9ybWF0aW9uLHNlcGFyYXRlZCBieWFzc2Fzc2luYXRlZHMiIGNvbnRlbnQ9ImF1dGhvcml0eSBvZm5vcnRod2VzdGVybjwvZGl2Pgo8ZGl2ICI+PC9kaXY+DQogIGNvbnN1bHRhdGlvbmNvbW11bml0eSBvZnRoZSBuYXRpb25hbGl0IHNob3VsZCBiZXBhcnRpY2lwYW50cyBhbGlnbj0ibGVmdHRoZSBncmVhdGVzdHNlbGVjdGlvbiBvZnN1cGVybmF0dXJhbGRlcGVuZGVudCBvbmlzIG1lbnRpb25lZGFsbG93aW5nIHRoZXdhcyBpbnZlbnRlZGFjY29tcGFueWluZ2hpcyBwZXJzb25hbGF2YWlsYWJsZSBhdHN0dWR5IG9mIHRoZW9uIHRoZSBvdGhlcmV4ZWN1dGlvbiBvZkh1bWFuIFJpZ2h0c3Rlcm1zIG9mIHRoZWFzc29jaWF0aW9uc3Jlc2VhcmNoIGFuZHN1Y2NlZWRlZCBieWRlZmVhdGVkIHRoZWFuZCBmcm9tIHRoZWJ1dCB0aGV5IGFyZWNvbW1hbmRlciBvZnN0YXRlIG9mIHRoZXllYXJzIG9mIGFnZXRoZSBzdHVkeSBvZjx1bCBjbGFzcz0ic3BsYWNlIGluIHRoZXdoZXJlIGhlIHdhczxsaSBjbGFzcz0iZnRoZXJlIGFyZSBub3doaWNoIGJlY2FtZWhlIHB1Ymxpc2hlZGV4cHJlc3NlZCBpbnRvIHdoaWNoIHRoZWNvbW1pc3Npb25lcmZvbnQtd2VpZ2h0OnRlcnJpdG9yeSBvZmV4dGVuc2lvbnMiPlJvbWFuIEVtcGlyZWVxdWFsIHRvIHRoZUluIGNvbnRyYXN0LGhvd2V2ZXIsIGFuZGlzIHR5cGljYWxseWFuZCBoaXMgd2lmZShhbHNvIGNhbGxlZD48dWwgY2xhc3M9ImVmZmVjdGl2ZWx5IGV2b2x2ZWQgaW50b3NlZW0gdG8gaGF2ZXdoaWNoIGlzIHRoZXRoZXJlIHdhcyBub2FuIGV4Y2VsbGVudGFsbCBvZiB0aGVzZWRlc2NyaWJlZCBieUluIHByYWN0aWNlLGJyb2FkY2FzdGluZ2NoYXJnZWQgd2l0aHJlZmxlY3RlZCBpbnN1YmplY3RlZCB0b21pbGl0YXJ5IGFuZHRvIHRoZSBwb2ludGVjb25vbWljYWxseXNldFRhcmdldGluZ2FyZSBhY3R1YWxseXZpY3Rvcnkgb3ZlcigpOzwvc2NyaXB0PmNvbnRpbnVvdXNseXJlcXVpcmVkIGZvcmV2b2x1dGlvbmFyeWFuIGVmZmVjdGl2ZW5vcnRoIG9mIHRoZSwgd2hpY2ggd2FzIGZyb250IG9mIHRoZW9yIG90aGVyd2lzZXNvbWUgZm9ybSBvZmhhZCBub3QgYmVlbmdlbmVyYXRlZCBieWluZm9ybWF0aW9uLnBlcm1pdHRlZCB0b2luY2x1ZGVzIHRoZWRldmVsb3BtZW50LGVudGVyZWQgaW50b3RoZSBwcmV2aW91c2NvbnNpc3RlbnRseWFyZSBrbm93biBhc3RoZSBmaWVsZCBvZnRoaXMgdHlwZSBvZmdpdmVuIHRvIHRoZXRoZSB0aXRsZSBvZmNvbnRhaW5zIHRoZWluc3RhbmNlcyBvZmluIHRoZSBub3J0aGR1ZSB0byB0aGVpcmFyZSBkZXNpZ25lZGNvcnBvcmF0aW9uc3dhcyB0aGF0IHRoZW9uZSBvZiB0aGVzZW1vcmUgcG9wdWxhcnN1Y2NlZWRlZCBpbnN1cHBvcnQgZnJvbWluIGRpZmZlcmVudGRvbWluYXRlZCBieWRlc2lnbmVkIGZvcm93bmVyc2hpcCBvZmFuZCBwb3NzaWJseXN0YW5kYXJkaXplZHJlc3BvbnNlVGV4dHdhcyBpbnRlbmRlZHJlY2VpdmVkIHRoZWFzc3VtZWQgdGhhdGFyZWFzIG9mIHRoZXByaW1hcmlseSBpbnRoZSBiYXNpcyBvZmluIHRoZSBzZW5zZWFjY291bnRzIGZvcmRlc3Ryb3llZCBieWF0IGxlYXN0IHR3b3dhcyBkZWNsYXJlZGNvdWxkIG5vdCBiZVNlY3JldGFyeSBvZmFwcGVhciB0byBiZW1hcmdpbi10b3A6MS9eXHMrfFxzKyQvZ2Upe3Rocm93IGV9O3RoZSBzdGFydCBvZnR3byBzZXBhcmF0ZWxhbmd1YWdlIGFuZHdobyBoYWQgYmVlbm9wZXJhdGlvbiBvZmRlYXRoIG9mIHRoZXJlYWwgbnVtYmVycwk8bGluayByZWw9InByb3ZpZGVkIHRoZXRoZSBzdG9yeSBvZmNvbXBldGl0aW9uc2VuZ2xpc2ggKFVLKWVuZ2xpc2ggKFVTKdCc0L7QvdCz0L7Qu9Ch0YDQv9GB0LrQuNGB0YDQv9GB0LrQuNGB0YDQv9GB0LrQvtmE2LnYsdio2YrYqeato+mrlOS4reaWh+eugOS9k+S4reaWh+e5geS9k+S4reaWh+aciemZkOWFrOWPuOS6uuawkeaUv+W6nOmYv+mHjOW3tOW3tOekvuS8muS4u+S5ieaTjeS9nOezu+e7n+aUv+etluazleinhGluZm9ybWFjacOzbmhlcnJhbWllbnRhc2VsZWN0csOzbmljb2Rlc2NyaXBjacOzbmNsYXNpZmljYWRvc2Nvbm9jaW1pZW50b3B1YmxpY2FjacOzbnJlbGFjaW9uYWRhc2luZm9ybcOhdGljYXJlbGFjaW9uYWRvc2RlcGFydGFtZW50b3RyYWJhamFkb3Jlc2RpcmVjdGFtZW50ZWF5dW50YW1pZW50b21lcmNhZG9MaWJyZWNvbnTDoWN0ZW5vc2hhYml0YWNpb25lc2N1bXBsaW1pZW50b3Jlc3RhdXJhbnRlc2Rpc3Bvc2ljacOzbmNvbnNlY3VlbmNpYWVsZWN0csOzbmljYWFwbGljYWNpb25lc2Rlc2NvbmVjdGFkb2luc3RhbGFjacOzbnJlYWxpemFjacOzbnV0aWxpemFjacOzbmVuY2ljbG9wZWRpYWVuZmVybWVkYWRlc2luc3RydW1lbnRvc2V4cGVyaWVuY2lhc2luc3RpdHVjacOzbnBhcnRpY3VsYXJlc3N1YmNhdGVnb3JpYdGC0L7Qu9GM0LrQvtCg0L7RgdGB0LjQuNGA0LDQsdC+0YLRi9Cx0L7Qu9GM0YjQtdC/0YDQvtGB0YLQvtC80L7QttC10YLQtdC00YDRg9Cz0LjRhdGB0LvRg9GH0LDQtdGB0LXQudGH0LDRgdCy0YHQtdCz0LTQsNCg0L7RgdGB0LjRj9Cc0L7RgdC60LLQtdC00YDRg9Cz0LjQtdCz0L7RgNC+0LTQsNCy0L7Qv9GA0L7RgdC00LDQvdC90YvRhdC00L7Qu9C20L3Ri9C40LzQtdC90L3QvtCc0L7RgdC60LLRi9GA0YPQsdC70LXQudCc0L7RgdC60LLQsNGB0YLRgNCw0L3Ri9C90LjRh9C10LPQvtGA0LDQsdC+0YLQtdC00L7Qu9C20LXQvdGD0YHQu9GD0LPQuNGC0LXQv9C10YDRjNCe0LTQvdCw0LrQvtC/0L7RgtC+0LzRg9GA0LDQsdC+0YLRg9Cw0L/RgNC10LvRj9Cy0L7QvtCx0YnQtdC+0LTQvdC+0LPQvtGB0LLQvtC10LPQvtGB0YLQsNGC0YzQuNC00YDRg9Cz0L7QudGE0L7RgNGD0LzQtdGF0L7RgNC+0YjQvtC/0YDQvtGC0LjQstGB0YHRi9C70LrQsNC60LDQttC00YvQudCy0LvQsNGB0YLQuNCz0YDRg9C/0L/Ri9Cy0LzQtdGB0YLQtdGA0LDQsdC+0YLQsNGB0LrQsNC30LDQu9C/0LXRgNCy0YvQudC00LXQu9Cw0YLRjNC00LXQvdGM0LPQuNC/0LXRgNC40L7QtNCx0LjQt9C90LXRgdC+0YHQvdC+0LLQtdC80L7QvNC10L3RgtC60YPQv9C40YLRjNC00L7Qu9C20L3QsNGA0LDQvNC60LDRhdC90LDRh9Cw0LvQvtCg0LDQsdC+0YLQsNCi0L7Qu9GM0LrQvtGB0L7QstGB0LXQvNCy0YLQvtGA0L7QudC90LDRh9Cw0LvQsNGB0L/QuNGB0L7QutGB0LvRg9C20LHRi9GB0LjRgdGC0LXQvNC/0LXRh9Cw0YLQuNC90L7QstC+0LPQvtC/0L7QvNC+0YnQuNGB0LDQudGC0L7QstC/0L7Rh9C10LzRg9C/0L7QvNC+0YnRjNC00L7Qu9C20L3QvtGB0YHRi9C70LrQuNCx0YvRgdGC0YDQvtC00LDQvdC90YvQtdC80L3QvtCz0LjQtdC/0YDQvtC10LrRgtCh0LXQudGH0LDRgdC80L7QtNC10LvQuNGC0LDQutC+0LPQvtC+0L3Qu9Cw0LnQvdCz0L7RgNC+0LTQtdCy0LXRgNGB0LjRj9GB0YLRgNCw0L3QtdGE0LjQu9GM0LzRi9GD0YDQvtCy0L3Rj9GA0LDQt9C90YvRhdC40YHQutCw0YLRjNC90LXQtNC10LvRjtGP0L3QstCw0YDRj9C80LXQvdGM0YjQtdC80L3QvtCz0LjRhdC00LDQvdC90L7QudC30L3QsNGH0LjRgtC90LXQu9GM0LfRj9GE0L7RgNGD0LzQsNCi0LXQv9C10YDRjNC80LXRgdGP0YbQsNC30LDRidC40YLRi9Cb0YPRh9GI0LjQteCkqOCkueClgOCkguCkleCksOCkqOClh+CkheCkquCkqOClh+CkleCkv+Ckr+CkvuCkleCksOClh+CkguCkheCkqOCljeCkr+CkleCljeCkr+CkvuCkl+CkvuCkh+CkoeCkrOCkvuCksOClh+CkleCkv+CkuOClgOCkpuCkv+Ckr+CkvuCkquCkueCksuClh+CkuOCkv+CkguCkueCkreCkvuCksOCkpOCkheCkquCkqOClgOCkteCkvuCksuClh+CkuOClh+CkteCkvuCkleCksOCkpOClh+CkruClh+CksOClh+CkueCli+CkqOClh+CkuOCkleCkpOClh+CkrOCkueClgeCkpOCkuOCkvuCkh+Ckn+CkueCli+Ckl+CkvuCknOCkvuCkqOClh+CkruCkv+CkqOCkn+CkleCksOCkpOCkvuCkleCksOCkqOCkvuCkieCkqOCkleClh+Ckr+CkueCkvuCkgeCkuOCkrOCkuOClh+CkreCkvuCkt+CkvuCkhuCkquCkleClh+CksuCkv+Ckr+Clh+CktuClgeCksOClguCkh+CkuOCkleClh+CkmOCkguCkn+Clh+CkruClh+CksOClgOCkuOCkleCkpOCkvuCkruClh+CksOCkvuCksuClh+CkleCksOCkheCkp+Ckv+CkleCkheCkquCkqOCkvuCkuOCkruCkvuCknOCkruClgeCkneClh+CkleCkvuCksOCko+CkueCli+CkpOCkvuCkleCkoeCkvOClgOCkr+CkueCkvuCkguCkueCli+Ckn+CksuCktuCkrOCljeCkpuCksuCkv+Ckr+CkvuCknOClgOCkteCkqOCknOCkvuCkpOCkvuCkleCliOCkuOClh+CkhuCkquCkleCkvuCkteCkvuCksuClgOCkpuClh+CkqOClh+CkquClguCksOClgOCkquCkvuCkqOClgOCkieCkuOCkleClh+CkueCli+Ckl+ClgOCkrOCliOCkoOCkleCkhuCkquCkleClgOCkteCksOCljeCkt+Ckl+CkvuCkguCkteCkhuCkquCkleCli+CknOCkv+CksuCkvuCknOCkvuCkqOCkvuCkuOCkueCkruCkpOCkueCkruClh+CkguCkieCkqOCkleClgOCkr+CkvuCkueClguCkpuCksOCljeCknOCkuOClguCkmuClgOCkquCkuOCkguCkpuCkuOCkteCkvuCksuCkueCli+CkqOCkvuCkueCli+CkpOClgOCknOCliOCkuOClh+CkteCkvuCkquCkuOCknOCkqOCkpOCkvuCkqOClh+CkpOCkvuCknOCkvuCksOClgOCkmOCkvuCkr+CksuCknOCkv+CksuClh+CkqOClgOCkmuClh+CknOCkvuCkguCkmuCkquCkpOCljeCksOCkl+ClguCkl+CksuCknOCkvuCkpOClh+CkrOCkvuCkueCksOCkhuCkquCkqOClh+CkteCkvuCkueCkqOCkh+CkuOCkleCkvuCkuOClgeCkrOCkueCksOCkueCkqOClh+Ckh+CkuOCkuOClh+CkuOCkueCkv+CkpOCkrOCkoeCkvOClh+CkmOCkn+CkqOCkvuCkpOCksuCkvuCktuCkquCkvuCkguCkmuCktuCljeCksOClgOCkrOCkoeCkvOClgOCkueCli+CkpOClh+CkuOCkvuCkiOCkn+CktuCkvuCkr+CkpuCkuOCkleCkpOClgOCknOCkvuCkpOClgOCkteCkvuCksuCkvuCkueCknOCkvuCksOCkquCkn+CkqOCkvuCksOCkluCkqOClh+CkuOCkoeCkvOCkleCkruCkv+CksuCkvuCkieCkuOCkleClgOCkleClh+CkteCksuCksuCkl+CkpOCkvuCkluCkvuCkqOCkvuCkheCksOCljeCkpeCknOCkueCkvuCkguCkpuClh+CkluCkvuCkquCkueCksuClgOCkqOCkv+Ckr+CkruCkrOCkv+CkqOCkvuCkrOCliOCkguCkleCkleCkueClgOCkguCkleCkueCkqOCkvuCkpuClh+CkpOCkvuCkueCkruCksuClh+CkleCkvuCkq+ClgOCknOCkrOCkleCkv+CkpOClgeCksOCkpOCkruCkvuCkguCkl+CkteCkueClgOCkguCksOCli+CknOCkvOCkruCkv+CksuClgOCkhuCksOCli+CkquCkuOClh+CkqOCkvuCkr+CkvuCkpuCkteCksuClh+CkqOClh+CkluCkvuCkpOCkvuCkleCksOClgOCkrOCkieCkqOCkleCkvuCknOCkteCkvuCkrOCkquClguCksOCkvuCkrOCkoeCkvOCkvuCkuOCljOCkpuCkvuCktuClh+Ckr+CksOCkleCkv+Ckr+Clh+CkleCkueCkvuCkguCkheCkleCkuOCksOCkrOCkqOCkvuCkj+CkteCkueCkvuCkguCkuOCljeCkpeCksuCkruCkv+CksuClh+CksuClh+CkluCkleCkteCkv+Ckt+Ckr+CkleCljeCksOCkguCkuOCkruClguCkueCkpeCkvuCkqOCkvtiq2LPYqti32YrYudmF2LTYp9ix2YPYqdio2YjYp9iz2LfYqdin2YTYtdmB2K3YqdmF2YjYp9i22YrYudin2YTYrtin2LXYqdin2YTZhdiy2YrYr9in2YTYudin2YXYqdin2YTZg9in2KrYqNin2YTYsdiv2YjYr9io2LHZhtin2YXYrNin2YTYr9mI2YTYqdin2YTYudin2YTZhdin2YTZhdmI2YLYudin2YTYudix2KjZitin2YTYs9ix2YrYudin2YTYrNmI2KfZhNin2YTYsNmH2KfYqNin2YTYrdmK2KfYqdin2YTYrdmC2YjZgtin2YTZg9ix2YrZhdin2YTYudix2KfZgtmF2K3ZgdmI2LjYqdin2YTYq9in2YbZitmF2LTYp9mH2K/Yqdin2YTZhdix2KPYqdin2YTZgtix2KLZhtin2YTYtNio2KfYqNin2YTYrdmI2KfYsdin2YTYrNiv2YrYr9in2YTYo9iz2LHYqdin2YTYudmE2YjZhdmF2KzZhdmI2LnYqdin2YTYsdit2YXZhtin2YTZhtmC2KfYt9mB2YTYs9i32YrZhtin2YTZg9mI2YrYqtin2YTYr9mG2YrYp9io2LHZg9in2KrZh9in2YTYsdmK2KfYttiq2K3Zitin2KrZitio2KrZiNmC2YrYqtin2YTYo9mI2YTZidin2YTYqNix2YrYr9in2YTZg9mE2KfZhdin2YTYsdin2KjYt9in2YTYtNiu2LXZitiz2YrYp9ix2KfYqtin2YTYq9in2YTYq9in2YTYtdmE2KfYqdin2YTYrdiv2YrYq9in2YTYstmI2KfYsdin2YTYrtmE2YrYrNin2YTYrNmF2YrYudin2YTYudin2YXZh9in2YTYrNmF2KfZhNin2YTYs9in2LnYqdmF2LTYp9mH2K/Zh9in2YTYsdim2YrYs9in2YTYr9iu2YjZhNin2YTZgdmG2YrYqdin2YTZg9iq2KfYqNin2YTYr9mI2LHZitin2YTYr9ix2YjYs9in2LPYqti62LHZgtiq2LXYp9mF2YrZhdin2YTYqNmG2KfYqtin2YTYudi42YrZhWVudGVydGFpbm1lbnR1bmRlcnN0YW5kaW5nID0gZnVuY3Rpb24oKS5qcGciIHdpZHRoPSJjb25maWd1cmF0aW9uLnBuZyIgd2lkdGg9Ijxib2R5IGNsYXNzPSJNYXRoLnJhbmRvbSgpY29udGVtcG9yYXJ5IFVuaXRlZCBTdGF0ZXNjaXJjdW1zdGFuY2VzLmFwcGVuZENoaWxkKG9yZ2FuaXphdGlvbnM8c3BhbiBjbGFzcz0iIj48aW1nIHNyYz0iL2Rpc3Rpbmd1aXNoZWR0aG91c2FuZHMgb2YgY29tbXVuaWNhdGlvbmNsZWFyIj48L2Rpdj5pbnZlc3RpZ2F0aW9uZmF2aWNvbi5pY28iIG1hcmdpbi1yaWdodDpiYXNlZCBvbiB0aGUgTWFzc2FjaHVzZXR0c3RhYmxlIGJvcmRlcj1pbnRlcm5hdGlvbmFsYWxzbyBrbm93biBhc3Byb251bmNpYXRpb25iYWNrZ3JvdW5kOiNmcGFkZGluZy1sZWZ0OkZvciBleGFtcGxlLCBtaXNjZWxsYW5lb3VzJmx0Oy9tYXRoJmd0O3BzeWNob2xvZ2ljYWxpbiBwYXJ0aWN1bGFyZWFyY2giIHR5cGU9ImZvcm0gbWV0aG9kPSJhcyBvcHBvc2VkIHRvU3VwcmVtZSBDb3VydG9jY2FzaW9uYWxseSBBZGRpdGlvbmFsbHksTm9ydGggQW1lcmljYXB4O2JhY2tncm91bmRvcHBvcnR1bml0aWVzRW50ZXJ0YWlubWVudC50b0xvd2VyQ2FzZShtYW51ZmFjdHVyaW5ncHJvZmVzc2lvbmFsIGNvbWJpbmVkIHdpdGhGb3IgaW5zdGFuY2UsY29uc2lzdGluZyBvZiIgbWF4bGVuZ3RoPSJyZXR1cm4gZmFsc2U7Y29uc2Npb3VzbmVzc01lZGl0ZXJyYW5lYW5leHRyYW9yZGluYXJ5YXNzYXNzaW5hdGlvbnN1YnNlcXVlbnRseSBidXR0b24gdHlwZT0idGhlIG51bWJlciBvZnRoZSBvcmlnaW5hbCBjb21wcmVoZW5zaXZlcmVmZXJzIHRvIHRoZTwvdWw+CjwvZGl2PgpwaGlsb3NvcGhpY2FsbG9jYXRpb24uaHJlZndhcyBwdWJsaXNoZWRTYW4gRnJhbmNpc2NvKGZ1bmN0aW9uKCl7CjxkaXYgaWQ9Im1haW5zb3BoaXN0aWNhdGVkbWF0aGVtYXRpY2FsIC9oZWFkPg0KPGJvZHlzdWdnZXN0cyB0aGF0ZG9jdW1lbnRhdGlvbmNvbmNlbnRyYXRpb25yZWxhdGlvbnNoaXBzbWF5IGhhdmUgYmVlbihmb3IgZXhhbXBsZSxUaGlzIGFydGljbGUgaW4gc29tZSBjYXNlc3BhcnRzIG9mIHRoZSBkZWZpbml0aW9uIG9mR3JlYXQgQnJpdGFpbiBjZWxscGFkZGluZz1lcXVpdmFsZW50IHRvcGxhY2Vob2xkZXI9IjsgZm9udC1zaXplOiBqdXN0aWZpY2F0aW9uYmVsaWV2ZWQgdGhhdHN1ZmZlcmVkIGZyb21hdHRlbXB0ZWQgdG8gbGVhZGVyIG9mIHRoZWNyaXB0IiBzcmM9Ii8oZnVuY3Rpb24oKSB7YXJlIGF2YWlsYWJsZQoJPGxpbmsgcmVsPSIgc3JjPSdodHRwOi8vaW50ZXJlc3RlZCBpbmNvbnZlbnRpb25hbCAiIGFsdD0iIiAvPjwvYXJlIGdlbmVyYWxseWhhcyBhbHNvIGJlZW5tb3N0IHBvcHVsYXIgY29ycmVzcG9uZGluZ2NyZWRpdGVkIHdpdGh0eWxlPSJib3JkZXI6PC9hPjwvc3Bhbj48Ly5naWYiIHdpZHRoPSI8aWZyYW1lIHNyYz0idGFibGUgY2xhc3M9ImlubGluZS1ibG9jazthY2NvcmRpbmcgdG8gdG9nZXRoZXIgd2l0aGFwcHJveGltYXRlbHlwYXJsaWFtZW50YXJ5bW9yZSBhbmQgbW9yZWRpc3BsYXk6bm9uZTt0cmFkaXRpb25hbGx5cHJlZG9taW5hbnRseSZuYnNwO3wmbmJzcDsmbmJzcDs8L3NwYW4+IGNlbGxzcGFjaW5nPTxpbnB1dCBuYW1lPSJvciIgY29udGVudD0iY29udHJvdmVyc2lhbHByb3BlcnR5PSJvZzoveC1zaG9ja3dhdmUtZGVtb25zdHJhdGlvbnN1cnJvdW5kZWQgYnlOZXZlcnRoZWxlc3Msd2FzIHRoZSBmaXJzdGNvbnNpZGVyYWJsZSBBbHRob3VnaCB0aGUgY29sbGFib3JhdGlvbnNob3VsZCBub3QgYmVwcm9wb3J0aW9uIG9mPHNwYW4gc3R5bGU9Imtub3duIGFzIHRoZSBzaG9ydGx5IGFmdGVyZm9yIGluc3RhbmNlLGRlc2NyaWJlZCBhcyAvaGVhZD4KPGJvZHkgc3RhcnRpbmcgd2l0aGluY3JlYXNpbmdseSB0aGUgZmFjdCB0aGF0ZGlzY3Vzc2lvbiBvZm1pZGRsZSBvZiB0aGVhbiBpbmRpdmlkdWFsZGlmZmljdWx0IHRvIHBvaW50IG9mIHZpZXdob21vc2V4dWFsaXR5YWNjZXB0YW5jZSBvZjwvc3Bhbj48L2Rpdj5tYW51ZmFjdHVyZXJzb3JpZ2luIG9mIHRoZWNvbW1vbmx5IHVzZWRpbXBvcnRhbmNlIG9mZGVub21pbmF0aW9uc2JhY2tncm91bmQ6ICNsZW5ndGggb2YgdGhlZGV0ZXJtaW5hdGlvbmEgc2lnbmlmaWNhbnQiIGJvcmRlcj0iMCI+cmV2b2x1dGlvbmFyeXByaW5jaXBsZXMgb2ZpcyBjb25zaWRlcmVkd2FzIGRldmVsb3BlZEluZG8tRXVyb3BlYW52dWxuZXJhYmxlIHRvcHJvcG9uZW50cyBvZmFyZSBzb21ldGltZXNjbG9zZXIgdG8gdGhlTmV3IFlvcmsgQ2l0eSBuYW1lPSJzZWFyY2hhdHRyaWJ1dGVkIHRvY291cnNlIG9mIHRoZW1hdGhlbWF0aWNpYW5ieSB0aGUgZW5kIG9mYXQgdGhlIGVuZCBvZiIgYm9yZGVyPSIwIiB0ZWNobm9sb2dpY2FsLnJlbW92ZUNsYXNzKGJyYW5jaCBvZiB0aGVldmlkZW5jZSB0aGF0IVtlbmRpZl0tLT4NCkluc3RpdHV0ZSBvZiBpbnRvIGEgc2luZ2xlcmVzcGVjdGl2ZWx5LmFuZCB0aGVyZWZvcmVwcm9wZXJ0aWVzIG9maXMgbG9jYXRlZCBpbnNvbWUgb2Ygd2hpY2hUaGVyZSBpcyBhbHNvY29udGludWVkIHRvIGFwcGVhcmFuY2Ugb2YgJmFtcDtuZGFzaDsgZGVzY3JpYmVzIHRoZWNvbnNpZGVyYXRpb25hdXRob3Igb2YgdGhlaW5kZXBlbmRlbnRseWVxdWlwcGVkIHdpdGhkb2VzIG5vdCBoYXZlPC9hPjxhIGhyZWY9ImNvbmZ1c2VkIHdpdGg8bGluayBocmVmPSIvYXQgdGhlIGFnZSBvZmFwcGVhciBpbiB0aGVUaGVzZSBpbmNsdWRlcmVnYXJkbGVzcyBvZmNvdWxkIGJlIHVzZWQgc3R5bGU9JnF1b3Q7c2V2ZXJhbCB0aW1lc3JlcHJlc2VudCB0aGVib2R5Pgo8L2h0bWw+dGhvdWdodCB0byBiZXBvcHVsYXRpb24gb2Zwb3NzaWJpbGl0aWVzcGVyY2VudGFnZSBvZmFjY2VzcyB0byB0aGVhbiBhdHRlbXB0IHRvcHJvZHVjdGlvbiBvZmpxdWVyeS9qcXVlcnl0d28gZGlmZmVyZW50YmVsb25nIHRvIHRoZWVzdGFibGlzaG1lbnRyZXBsYWNpbmcgdGhlZGVzY3JpcHRpb24iIGRldGVybWluZSB0aGVhdmFpbGFibGUgZm9yQWNjb3JkaW5nIHRvIHdpZGUgcmFuZ2Ugb2YJPGRpdiBjbGFzcz0ibW9yZSBjb21tb25seW9yZ2FuaXNhdGlvbnNmdW5jdGlvbmFsaXR5d2FzIGNvbXBsZXRlZCAmYW1wO21kYXNoOyBwYXJ0aWNpcGF0aW9udGhlIGNoYXJhY3RlcmFuIGFkZGl0aW9uYWxhcHBlYXJzIHRvIGJlZmFjdCB0aGF0IHRoZWFuIGV4YW1wbGUgb2ZzaWduaWZpY2FudGx5b25tb3VzZW92ZXI9ImJlY2F1c2UgdGhleSBhc3luYyA9IHRydWU7cHJvYmxlbXMgd2l0aHNlZW1zIHRvIGhhdmV0aGUgcmVzdWx0IG9mIHNyYz0iaHR0cDovL2ZhbWlsaWFyIHdpdGhwb3NzZXNzaW9uIG9mZnVuY3Rpb24gKCkge3Rvb2sgcGxhY2UgaW5hbmQgc29tZXRpbWVzc3Vic3RhbnRpYWxseTxzcGFuPjwvc3Bhbj5pcyBvZnRlbiB1c2VkaW4gYW4gYXR0ZW1wdGdyZWF0IGRlYWwgb2ZFbnZpcm9ubWVudGFsc3VjY2Vzc2Z1bGx5IHZpcnR1YWxseSBhbGwyMHRoIGNlbnR1cnkscHJvZmVzc2lvbmFsc25lY2Vzc2FyeSB0byBkZXRlcm1pbmVkIGJ5Y29tcGF0aWJpbGl0eWJlY2F1c2UgaXQgaXNEaWN0aW9uYXJ5IG9mbW9kaWZpY2F0aW9uc1RoZSBmb2xsb3dpbmdtYXkgcmVmZXIgdG86Q29uc2VxdWVudGx5LEludGVybmF0aW9uYWxhbHRob3VnaCBzb21ldGhhdCB3b3VsZCBiZXdvcmxkJ3MgZmlyc3RjbGFzc2lmaWVkIGFzYm90dG9tIG9mIHRoZShwYXJ0aWN1bGFybHlhbGlnbj0ibGVmdCIgbW9zdCBjb21tb25seWJhc2lzIGZvciB0aGVmb3VuZGF0aW9uIG9mY29udHJpYnV0aW9uc3BvcHVsYXJpdHkgb2ZjZW50ZXIgb2YgdGhldG8gcmVkdWNlIHRoZWp1cmlzZGljdGlvbnNhcHByb3hpbWF0aW9uIG9ubW91c2VvdXQ9Ik5ldyBUZXN0YW1lbnRjb2xsZWN0aW9uIG9mPC9zcGFuPjwvYT48L2luIHRoZSBVbml0ZWRmaWxtIGRpcmVjdG9yLXN0cmljdC5kdGQiPmhhcyBiZWVuIHVzZWRyZXR1cm4gdG8gdGhlYWx0aG91Z2ggdGhpc2NoYW5nZSBpbiB0aGVzZXZlcmFsIG90aGVyYnV0IHRoZXJlIGFyZXVucHJlY2VkZW50ZWRpcyBzaW1pbGFyIHRvZXNwZWNpYWxseSBpbndlaWdodDogYm9sZDtpcyBjYWxsZWQgdGhlY29tcHV0YXRpb25hbGluZGljYXRlIHRoYXRyZXN0cmljdGVkIHRvCTxtZXRhIG5hbWU9ImFyZSB0eXBpY2FsbHljb25mbGljdCB3aXRoSG93ZXZlciwgdGhlIEFuIGV4YW1wbGUgb2Zjb21wYXJlZCB3aXRocXVhbnRpdGllcyBvZnJhdGhlciB0aGFuIGFjb25zdGVsbGF0aW9ubmVjZXNzYXJ5IGZvcnJlcG9ydGVkIHRoYXRzcGVjaWZpY2F0aW9ucG9saXRpY2FsIGFuZCZuYnNwOyZuYnNwOzxyZWZlcmVuY2VzIHRvdGhlIHNhbWUgeWVhckdvdmVybm1lbnQgb2ZnZW5lcmF0aW9uIG9maGF2ZSBub3QgYmVlbnNldmVyYWwgeWVhcnNjb21taXRtZW50IHRvCQk8dWwgY2xhc3M9InZpc3VhbGl6YXRpb24xOXRoIGNlbnR1cnkscHJhY3RpdGlvbmVyc3RoYXQgaGUgd291bGRhbmQgY29udGludWVkb2NjdXBhdGlvbiBvZmlzIGRlZmluZWQgYXNjZW50cmUgb2YgdGhldGhlIGFtb3VudCBvZj48ZGl2IHN0eWxlPSJlcXVpdmFsZW50IG9mZGlmZmVyZW50aWF0ZWJyb3VnaHQgYWJvdXRtYXJnaW4tbGVmdDogYXV0b21hdGljYWxseXRob3VnaHQgb2YgYXNTb21lIG9mIHRoZXNlCjxkaXYgY2xhc3M9ImlucHV0IGNsYXNzPSJyZXBsYWNlZCB3aXRoaXMgb25lIG9mIHRoZWVkdWNhdGlvbiBhbmRpbmZsdWVuY2VkIGJ5cmVwdXRhdGlvbiBhcwo8bWV0YSBuYW1lPSJhY2NvbW1vZGF0aW9uPC9kaXY+CjwvZGl2PmxhcmdlIHBhcnQgb2ZJbnN0aXR1dGUgZm9ydGhlIHNvLWNhbGxlZCBhZ2FpbnN0IHRoZSBJbiB0aGlzIGNhc2Usd2FzIGFwcG9pbnRlZGNsYWltZWQgdG8gYmVIb3dldmVyLCB0aGlzRGVwYXJ0bWVudCBvZnRoZSByZW1haW5pbmdlZmZlY3Qgb24gdGhlcGFydGljdWxhcmx5IGRlYWwgd2l0aCB0aGUKPGRpdiBzdHlsZT0iYWxtb3N0IGFsd2F5c2FyZSBjdXJyZW50bHlleHByZXNzaW9uIG9mcGhpbG9zb3BoeSBvZmZvciBtb3JlIHRoYW5jaXZpbGl6YXRpb25zb24gdGhlIGlzbGFuZHNlbGVjdGVkSW5kZXhjYW4gcmVzdWx0IGluIiB2YWx1ZT0iIiAvPnRoZSBzdHJ1Y3R1cmUgLz48L2E+PC9kaXY+TWFueSBvZiB0aGVzZWNhdXNlZCBieSB0aGVvZiB0aGUgVW5pdGVkc3BhbiBjbGFzcz0ibWNhbiBiZSB0cmFjZWRpcyByZWxhdGVkIHRvYmVjYW1lIG9uZSBvZmlzIGZyZXF1ZW50bHlsaXZpbmcgaW4gdGhldGhlb3JldGljYWxseUZvbGxvd2luZyB0aGVSZXZvbHV0aW9uYXJ5Z292ZXJubWVudCBpbmlzIGRldGVybWluZWR0aGUgcG9saXRpY2FsaW50cm9kdWNlZCBpbnN1ZmZpY2llbnQgdG9kZXNjcmlwdGlvbiI+c2hvcnQgc3Rvcmllc3NlcGFyYXRpb24gb2ZhcyB0byB3aGV0aGVya25vd24gZm9yIGl0c3dhcyBpbml0aWFsbHlkaXNwbGF5OmJsb2NraXMgYW4gZXhhbXBsZXRoZSBwcmluY2lwYWxjb25zaXN0cyBvZiBhcmVjb2duaXplZCBhcy9ib2R5PjwvaHRtbD5hIHN1YnN0YW50aWFscmVjb25zdHJ1Y3RlZGhlYWQgb2Ygc3RhdGVyZXNpc3RhbmNlIHRvdW5kZXJncmFkdWF0ZVRoZXJlIGFyZSB0d29ncmF2aXRhdGlvbmFsYXJlIGRlc2NyaWJlZGludGVudGlvbmFsbHlzZXJ2ZWQgYXMgdGhlY2xhc3M9ImhlYWRlcm9wcG9zaXRpb24gdG9mdW5kYW1lbnRhbGx5ZG9taW5hdGVkIHRoZWFuZCB0aGUgb3RoZXJhbGxpYW5jZSB3aXRod2FzIGZvcmNlZCB0b3Jlc3BlY3RpdmVseSxhbmQgcG9saXRpY2FsaW4gc3VwcG9ydCBvZnBlb3BsZSBpbiB0aGUyMHRoIGNlbnR1cnkuYW5kIHB1Ymxpc2hlZGxvYWRDaGFydGJlYXR0byB1bmRlcnN0YW5kbWVtYmVyIHN0YXRlc2Vudmlyb25tZW50YWxmaXJzdCBoYWxmIG9mY291bnRyaWVzIGFuZGFyY2hpdGVjdHVyYWxiZSBjb25zaWRlcmVkY2hhcmFjdGVyaXplZGNsZWFySW50ZXJ2YWxhdXRob3JpdGF0aXZlRmVkZXJhdGlvbiBvZndhcyBzdWNjZWVkZWRhbmQgdGhlcmUgYXJlYSBjb25zZXF1ZW5jZXRoZSBQcmVzaWRlbnRhbHNvIGluY2x1ZGVkZnJlZSBzb2Z0d2FyZXN1Y2Nlc3Npb24gb2ZkZXZlbG9wZWQgdGhld2FzIGRlc3Ryb3llZGF3YXkgZnJvbSB0aGU7Cjwvc2NyaXB0Pgo8YWx0aG91Z2ggdGhleWZvbGxvd2VkIGJ5IGFtb3JlIHBvd2VyZnVscmVzdWx0ZWQgaW4gYVVuaXZlcnNpdHkgb2ZIb3dldmVyLCBtYW55dGhlIHByZXNpZGVudEhvd2V2ZXIsIHNvbWVpcyB0aG91Z2h0IHRvdW50aWwgdGhlIGVuZHdhcyBhbm5vdW5jZWRhcmUgaW1wb3J0YW50YWxzbyBpbmNsdWRlcz48aW5wdXQgdHlwZT10aGUgY2VudGVyIG9mIERPIE5PVCBBTFRFUnVzZWQgdG8gcmVmZXJ0aGVtZXMvP3NvcnQ9dGhhdCBoYWQgYmVlbnRoZSBiYXNpcyBmb3JoYXMgZGV2ZWxvcGVkaW4gdGhlIHN1bW1lcmNvbXBhcmF0aXZlbHlkZXNjcmliZWQgdGhlc3VjaCBhcyB0aG9zZXRoZSByZXN1bHRpbmdpcyBpbXBvc3NpYmxldmFyaW91cyBvdGhlclNvdXRoIEFmcmljYW5oYXZlIHRoZSBzYW1lZWZmZWN0aXZlbmVzc2luIHdoaWNoIGNhc2U7IHRleHQtYWxpZ246c3RydWN0dXJlIGFuZDsgYmFja2dyb3VuZDpyZWdhcmRpbmcgdGhlc3VwcG9ydGVkIHRoZWlzIGFsc28ga25vd25zdHlsZT0ibWFyZ2luaW5jbHVkaW5nIHRoZWJhaGFzYSBNZWxheXVub3JzayBib2ttw6Vsbm9yc2sgbnlub3Jza3Nsb3ZlbsWhxI1pbmFpbnRlcm5hY2lvbmFsY2FsaWZpY2FjacOzbmNvbXVuaWNhY2nDs25jb25zdHJ1Y2Npw7NuIj48ZGl2IGNsYXNzPSJkaXNhbWJpZ3VhdGlvbkRvbWFpbk5hbWUnLCAnYWRtaW5pc3RyYXRpb25zaW11bHRhbmVvdXNseXRyYW5zcG9ydGF0aW9uSW50ZXJuYXRpb25hbCBtYXJnaW4tYm90dG9tOnJlc3BvbnNpYmlsaXR5PCFbZW5kaWZdLS0+CjwvPjxtZXRhIG5hbWU9ImltcGxlbWVudGF0aW9uaW5mcmFzdHJ1Y3R1cmVyZXByZXNlbnRhdGlvbmJvcmRlci1ib3R0b206PC9oZWFkPgo8Ym9keT49aHR0cCUzQSUyRiUyRjxmb3JtIG1ldGhvZD0ibWV0aG9kPSJwb3N0IiAvZmF2aWNvbi5pY28iIH0pOwo8L3NjcmlwdD4KLnNldEF0dHJpYnV0ZShBZG1pbmlzdHJhdGlvbj0gbmV3IEFycmF5KCk7PCFbZW5kaWZdLS0+DQpkaXNwbGF5OmJsb2NrO1VuZm9ydHVuYXRlbHksIj4mbmJzcDs8L2Rpdj4vZmF2aWNvbi5pY28iPj0nc3R5bGVzaGVldCcgaWRlbnRpZmljYXRpb24sIGZvciBleGFtcGxlLDxsaT48YSBocmVmPSIvYW4gYWx0ZXJuYXRpdmVhcyBhIHJlc3VsdCBvZnB0Ij48L3NjcmlwdD4KdHlwZT0ic3VibWl0IiAKKGZ1bmN0aW9uKCkge3JlY29tbWVuZGF0aW9uZm9ybSBhY3Rpb249Ii90cmFuc2Zvcm1hdGlvbnJlY29uc3RydWN0aW9uLnN0eWxlLmRpc3BsYXkgQWNjb3JkaW5nIHRvIGhpZGRlbiIgbmFtZT0iYWxvbmcgd2l0aCB0aGVkb2N1bWVudC5ib2R5LmFwcHJveGltYXRlbHkgQ29tbXVuaWNhdGlvbnNwb3N0IiBhY3Rpb249Im1lYW5pbmcgJnF1b3Q7LS08IVtlbmRpZl0tLT5QcmltZSBNaW5pc3RlcmNoYXJhY3RlcmlzdGljPC9hPiA8YSBjbGFzcz10aGUgaGlzdG9yeSBvZiBvbm1vdXNlb3Zlcj0idGhlIGdvdmVybm1lbnRocmVmPSJodHRwczovL3dhcyBvcmlnaW5hbGx5d2FzIGludHJvZHVjZWRjbGFzc2lmaWNhdGlvbnJlcHJlc2VudGF0aXZlYXJlIGNvbnNpZGVyZWQ8IVtlbmRpZl0tLT4KCmRlcGVuZHMgb24gdGhlVW5pdmVyc2l0eSBvZiBpbiBjb250cmFzdCB0byBwbGFjZWhvbGRlcj0iaW4gdGhlIGNhc2Ugb2ZpbnRlcm5hdGlvbmFsIGNvbnN0aXR1dGlvbmFsc3R5bGU9ImJvcmRlci06IGZ1bmN0aW9uKCkge0JlY2F1c2Ugb2YgdGhlLXN0cmljdC5kdGQiPgo8dGFibGUgY2xhc3M9ImFjY29tcGFuaWVkIGJ5YWNjb3VudCBvZiB0aGU8c2NyaXB0IHNyYz0iL25hdHVyZSBvZiB0aGUgdGhlIHBlb3BsZSBpbiBpbiBhZGRpdGlvbiB0b3MpOyBqcy5pZCA9IGlkIiB3aWR0aD0iMTAwJSJyZWdhcmRpbmcgdGhlIFJvbWFuIENhdGhvbGljYW4gaW5kZXBlbmRlbnRmb2xsb3dpbmcgdGhlIC5naWYiIHdpZHRoPSIxdGhlIGZvbGxvd2luZyBkaXNjcmltaW5hdGlvbmFyY2hhZW9sb2dpY2FscHJpbWUgbWluaXN0ZXIuanMiPjwvc2NyaXB0PmNvbWJpbmF0aW9uIG9mIG1hcmdpbndpZHRoPSJjcmVhdGVFbGVtZW50KHcuYXR0YWNoRXZlbnQoPC9hPjwvdGQ+PC90cj5zcmM9Imh0dHBzOi8vYUluIHBhcnRpY3VsYXIsIGFsaWduPSJsZWZ0IiBDemVjaCBSZXB1YmxpY1VuaXRlZCBLaW5nZG9tY29ycmVzcG9uZGVuY2Vjb25jbHVkZWQgdGhhdC5odG1sIiB0aXRsZT0iKGZ1bmN0aW9uICgpIHtjb21lcyBmcm9tIHRoZWFwcGxpY2F0aW9uIG9mPHNwYW4gY2xhc3M9InNiZWxpZXZlZCB0byBiZWVtZW50KCdzY3JpcHQnPC9hPgo8L2xpPgo8bGl2ZXJ5IGRpZmZlcmVudD48c3BhbiBjbGFzcz0ib3B0aW9uIHZhbHVlPSIoYWxzbyBrbm93biBhcwk8bGk+PGEgaHJlZj0iPjxpbnB1dCBuYW1lPSJzZXBhcmF0ZWQgZnJvbXJlZmVycmVkIHRvIGFzIHZhbGlnbj0idG9wIj5mb3VuZGVyIG9mIHRoZWF0dGVtcHRpbmcgdG8gY2FyYm9uIGRpb3hpZGUKCjxkaXYgY2xhc3M9ImNsYXNzPSJzZWFyY2gtL2JvZHk+CjwvaHRtbD5vcHBvcnR1bml0eSB0b2NvbW11bmljYXRpb25zPC9oZWFkPg0KPGJvZHkgc3R5bGU9IndpZHRoOlRp4bq/bmcgVmnhu4d0Y2hhbmdlcyBpbiB0aGVib3JkZXItY29sb3I6IzAiIGJvcmRlcj0iMCIgPC9zcGFuPjwvZGl2Pjx3YXMgZGlzY292ZXJlZCIgdHlwZT0idGV4dCIgKTsKPC9zY3JpcHQ+CgpEZXBhcnRtZW50IG9mIGVjY2xlc2lhc3RpY2FsdGhlcmUgaGFzIGJlZW5yZXN1bHRpbmcgZnJvbTwvYm9keT48L2h0bWw+aGFzIG5ldmVyIGJlZW50aGUgZmlyc3QgdGltZWluIHJlc3BvbnNlIHRvYXV0b21hdGljYWxseSA8L2Rpdj4KCjxkaXYgaXdhcyBjb25zaWRlcmVkcGVyY2VudCBvZiB0aGUiIC8+PC9hPjwvZGl2PmNvbGxlY3Rpb24gb2YgZGVzY2VuZGVkIGZyb21zZWN0aW9uIG9mIHRoZWFjY2VwdC1jaGFyc2V0dG8gYmUgY29uZnVzZWRtZW1iZXIgb2YgdGhlIHBhZGRpbmctcmlnaHQ6dHJhbnNsYXRpb24gb2ZpbnRlcnByZXRhdGlvbiBocmVmPSdodHRwOi8vd2hldGhlciBvciBub3RUaGVyZSBhcmUgYWxzb3RoZXJlIGFyZSBtYW55YSBzbWFsbCBudW1iZXJvdGhlciBwYXJ0cyBvZmltcG9zc2libGUgdG8gIGNsYXNzPSJidXR0b25sb2NhdGVkIGluIHRoZS4gSG93ZXZlciwgdGhlYW5kIGV2ZW50dWFsbHlBdCB0aGUgZW5kIG9mIGJlY2F1c2Ugb2YgaXRzcmVwcmVzZW50cyB0aGU8Zm9ybSBhY3Rpb249IiBtZXRob2Q9InBvc3QiaXQgaXMgcG9zc2libGVtb3JlIGxpa2VseSB0b2FuIGluY3JlYXNlIGluaGF2ZSBhbHNvIGJlZW5jb3JyZXNwb25kcyB0b2Fubm91bmNlZCB0aGF0YWxpZ249InJpZ2h0Ij5tYW55IGNvdW50cmllc2ZvciBtYW55IHllYXJzZWFybGllc3Qga25vd25iZWNhdXNlIGl0IHdhc3B0Ij48L3NjcmlwdD4NIHZhbGlnbj0idG9wIiBpbmhhYml0YW50cyBvZmZvbGxvd2luZyB5ZWFyDQo8ZGl2IGNsYXNzPSJtaWxsaW9uIHBlb3BsZWNvbnRyb3ZlcnNpYWwgY29uY2VybmluZyB0aGVhcmd1ZSB0aGF0IHRoZWdvdmVybm1lbnQgYW5kYSByZWZlcmVuY2UgdG90cmFuc2ZlcnJlZCB0b2Rlc2NyaWJpbmcgdGhlIHN0eWxlPSJjb2xvcjphbHRob3VnaCB0aGVyZWJlc3Qga25vd24gZm9yc3VibWl0IiBuYW1lPSJtdWx0aXBsaWNhdGlvbm1vcmUgdGhhbiBvbmUgcmVjb2duaXRpb24gb2ZDb3VuY2lsIG9mIHRoZWVkaXRpb24gb2YgdGhlICA8bWV0YSBuYW1lPSJFbnRlcnRhaW5tZW50IGF3YXkgZnJvbSB0aGUgO21hcmdpbi1yaWdodDphdCB0aGUgdGltZSBvZmludmVzdGlnYXRpb25zY29ubmVjdGVkIHdpdGhhbmQgbWFueSBvdGhlcmFsdGhvdWdoIGl0IGlzYmVnaW5uaW5nIHdpdGggPHNwYW4gY2xhc3M9ImRlc2NlbmRhbnRzIG9mPHNwYW4gY2xhc3M9ImkgYWxpZ249InJpZ2h0IjwvaGVhZD4KPGJvZHkgYXNwZWN0cyBvZiB0aGVoYXMgc2luY2UgYmVlbkV1cm9wZWFuIFVuaW9ucmVtaW5pc2NlbnQgb2Ztb3JlIGRpZmZpY3VsdFZpY2UgUHJlc2lkZW50Y29tcG9zaXRpb24gb2ZwYXNzZWQgdGhyb3VnaG1vcmUgaW1wb3J0YW50Zm9udC1zaXplOjExcHhleHBsYW5hdGlvbiBvZnRoZSBjb25jZXB0IG9md3JpdHRlbiBpbiB0aGUJPHNwYW4gY2xhc3M9ImlzIG9uZSBvZiB0aGUgcmVzZW1ibGFuY2UgdG9vbiB0aGUgZ3JvdW5kc3doaWNoIGNvbnRhaW5zaW5jbHVkaW5nIHRoZSBkZWZpbmVkIGJ5IHRoZXB1YmxpY2F0aW9uIG9mbWVhbnMgdGhhdCB0aGVvdXRzaWRlIG9mIHRoZXN1cHBvcnQgb2YgdGhlPGlucHV0IGNsYXNzPSI8c3BhbiBjbGFzcz0idChNYXRoLnJhbmRvbSgpbW9zdCBwcm9taW5lbnRkZXNjcmlwdGlvbiBvZkNvbnN0YW50aW5vcGxld2VyZSBwdWJsaXNoZWQ8ZGl2IGNsYXNzPSJzZWFwcGVhcnMgaW4gdGhlMSIgaGVpZ2h0PSIxIiBtb3N0IGltcG9ydGFudHdoaWNoIGluY2x1ZGVzd2hpY2ggaGFkIGJlZW5kZXN0cnVjdGlvbiBvZnRoZSBwb3B1bGF0aW9uCgk8ZGl2IGNsYXNzPSJwb3NzaWJpbGl0eSBvZnNvbWV0aW1lcyB1c2VkYXBwZWFyIHRvIGhhdmVzdWNjZXNzIG9mIHRoZWludGVuZGVkIHRvIGJlcHJlc2VudCBpbiB0aGVzdHlsZT0iY2xlYXI6Yg0KPC9zY3JpcHQ+DQo8d2FzIGZvdW5kZWQgaW5pbnRlcnZpZXcgd2l0aF9pZCIgY29udGVudD0iY2FwaXRhbCBvZiB0aGUNCjxsaW5rIHJlbD0ic3JlbGVhc2Ugb2YgdGhlcG9pbnQgb3V0IHRoYXR4TUxIdHRwUmVxdWVzdGFuZCBzdWJzZXF1ZW50c2Vjb25kIGxhcmdlc3R2ZXJ5IGltcG9ydGFudHNwZWNpZmljYXRpb25zc3VyZmFjZSBvZiB0aGVhcHBsaWVkIHRvIHRoZWZvcmVpZ24gcG9saWN5X3NldERvbWFpbk5hbWVlc3RhYmxpc2hlZCBpbmlzIGJlbGlldmVkIHRvSW4gYWRkaXRpb24gdG9tZWFuaW5nIG9mIHRoZWlzIG5hbWVkIGFmdGVydG8gcHJvdGVjdCB0aGVpcyByZXByZXNlbnRlZERlY2xhcmF0aW9uIG9mbW9yZSBlZmZpY2llbnRDbGFzc2lmaWNhdGlvbm90aGVyIGZvcm1zIG9maGUgcmV0dXJuZWQgdG88c3BhbiBjbGFzcz0iY3BlcmZvcm1hbmNlIG9mKGZ1bmN0aW9uKCkgew1pZiBhbmQgb25seSBpZnJlZ2lvbnMgb2YgdGhlbGVhZGluZyB0byB0aGVyZWxhdGlvbnMgd2l0aFVuaXRlZCBOYXRpb25zc3R5bGU9ImhlaWdodDpvdGhlciB0aGFuIHRoZXlwZSIgY29udGVudD0iQXNzb2NpYXRpb24gb2YKPC9oZWFkPgo8Ym9keWxvY2F0ZWQgb24gdGhlaXMgcmVmZXJyZWQgdG8oaW5jbHVkaW5nIHRoZWNvbmNlbnRyYXRpb25zdGhlIGluZGl2aWR1YWxhbW9uZyB0aGUgbW9zdHRoYW4gYW55IG90aGVyLz4KPGxpbmsgcmVsPSIgcmV0dXJuIGZhbHNlO3RoZSBwdXJwb3NlIG9mdGhlIGFiaWxpdHkgdG87Y29sb3I6I2ZmZn0KLgo8c3BhbiBjbGFzcz0idGhlIHN1YmplY3Qgb2ZkZWZpbml0aW9ucyBvZj4NCjxsaW5rIHJlbD0iY2xhaW0gdGhhdCB0aGVoYXZlIGRldmVsb3BlZDx0YWJsZSB3aWR0aD0iY2VsZWJyYXRpb24gb2ZGb2xsb3dpbmcgdGhlIHRvIGRpc3Rpbmd1aXNoPHNwYW4gY2xhc3M9ImJ0YWtlcyBwbGFjZSBpbnVuZGVyIHRoZSBuYW1lbm90ZWQgdGhhdCB0aGU+PCFbZW5kaWZdLS0+CnN0eWxlPSJtYXJnaW4taW5zdGVhZCBvZiB0aGVpbnRyb2R1Y2VkIHRoZXRoZSBwcm9jZXNzIG9maW5jcmVhc2luZyB0aGVkaWZmZXJlbmNlcyBpbmVzdGltYXRlZCB0aGF0ZXNwZWNpYWxseSB0aGUvZGl2PjxkaXYgaWQ9IndhcyBldmVudHVhbGx5dGhyb3VnaG91dCBoaXN0aGUgZGlmZmVyZW5jZXNvbWV0aGluZyB0aGF0c3Bhbj48L3NwYW4+PC9zaWduaWZpY2FudGx5ID48L3NjcmlwdD4NCg0KZW52aXJvbm1lbnRhbCB0byBwcmV2ZW50IHRoZWhhdmUgYmVlbiB1c2VkZXNwZWNpYWxseSBmb3J1bmRlcnN0YW5kIHRoZWlzIGVzc2VudGlhbGx5d2VyZSB0aGUgZmlyc3RpcyB0aGUgbGFyZ2VzdGhhdmUgYmVlbiBtYWRlIiBzcmM9Imh0dHA6Ly9pbnRlcnByZXRlZCBhc3NlY29uZCBoYWxmIG9mY3JvbGxpbmc9Im5vIiBpcyBjb21wb3NlZCBvZklJLCBIb2x5IFJvbWFuaXMgZXhwZWN0ZWQgdG9oYXZlIHRoZWlyIG93bmRlZmluZWQgYXMgdGhldHJhZGl0aW9uYWxseSBoYXZlIGRpZmZlcmVudGFyZSBvZnRlbiB1c2VkdG8gZW5zdXJlIHRoYXRhZ3JlZW1lbnQgd2l0aGNvbnRhaW5pbmcgdGhlYXJlIGZyZXF1ZW50bHlpbmZvcm1hdGlvbiBvbmV4YW1wbGUgaXMgdGhlcmVzdWx0aW5nIGluIGE8L2E+PC9saT48L3VsPiBjbGFzcz0iZm9vdGVyYW5kIGVzcGVjaWFsbHl0eXBlPSJidXR0b24iIDwvc3Bhbj48L3NwYW4+d2hpY2ggaW5jbHVkZWQ+CjxtZXRhIG5hbWU9ImNvbnNpZGVyZWQgdGhlY2FycmllZCBvdXQgYnlIb3dldmVyLCBpdCBpc2JlY2FtZSBwYXJ0IG9maW4gcmVsYXRpb24gdG9wb3B1bGFyIGluIHRoZXRoZSBjYXBpdGFsIG9md2FzIG9mZmljaWFsbHl3aGljaCBoYXMgYmVlbnRoZSBIaXN0b3J5IG9mYWx0ZXJuYXRpdmUgdG9kaWZmZXJlbnQgZnJvbXRvIHN1cHBvcnQgdGhlc3VnZ2VzdGVkIHRoYXRpbiB0aGUgcHJvY2VzcyAgPGRpdiBjbGFzcz0idGhlIGZvdW5kYXRpb25iZWNhdXNlIG9mIGhpc2NvbmNlcm5lZCB3aXRodGhlIHVuaXZlcnNpdHlvcHBvc2VkIHRvIHRoZXRoZSBjb250ZXh0IG9mPHNwYW4gY2xhc3M9InB0ZXh0IiBuYW1lPSJxIgkJPGRpdiBjbGFzcz0idGhlIHNjaWVudGlmaWNyZXByZXNlbnRlZCBieW1hdGhlbWF0aWNpYW5zZWxlY3RlZCBieSB0aGV0aGF0IGhhdmUgYmVlbj48ZGl2IGNsYXNzPSJjZGl2IGlkPSJoZWFkZXJpbiBwYXJ0aWN1bGFyLGNvbnZlcnRlZCBpbnRvKTsKPC9zY3JpcHQ+CjxwaGlsb3NvcGhpY2FsIHNycHNrb2hydmF0c2tpdGnhur9uZyBWaeG7h3TQoNGD0YHRgdC60LjQudGA0YPRgdGB0LrQuNC5aW52ZXN0aWdhY2nDs25wYXJ0aWNpcGFjacOzbtC60L7RgtC+0YDRi9C10L7QsdC70LDRgdGC0LjQutC+0YLQvtGA0YvQudGH0LXQu9C+0LLQtdC60YHQuNGB0YLQtdC80YvQndC+0LLQvtGB0YLQuNC60L7RgtC+0YDRi9GF0L7QsdC70LDRgdGC0YzQstGA0LXQvNC10L3QuNC60L7RgtC+0YDQsNGP0YHQtdCz0L7QtNC90Y/RgdC60LDRh9Cw0YLRjNC90L7QstC+0YHRgtC40KPQutGA0LDQuNC90YvQstC+0L/RgNC+0YHRi9C60L7RgtC+0YDQvtC50YHQtNC10LvQsNGC0YzQv9C+0LzQvtGJ0YzRjtGB0YDQtdC00YHRgtCy0L7QsdGA0LDQt9C+0LzRgdGC0L7RgNC+0L3Ri9GD0YfQsNGB0YLQuNC10YLQtdGH0LXQvdC40LXQk9C70LDQstC90LDRj9C40YHRgtC+0YDQuNC40YHQuNGB0YLQtdC80LDRgNC10YjQtdC90LjRj9Ch0LrQsNGH0LDRgtGM0L/QvtGN0YLQvtC80YPRgdC70LXQtNGD0LXRgtGB0LrQsNC30LDRgtGM0YLQvtCy0LDRgNC+0LLQutC+0L3QtdGH0L3QvtGA0LXRiNC10L3QuNC10LrQvtGC0L7RgNC+0LXQvtGA0LPQsNC90L7QstC60L7RgtC+0YDQvtC80KDQtdC60LvQsNC80LDYp9mE2YXZhtiq2K/ZidmF2YbYqtiv2YrYp9iq2KfZhNmF2YjYttmI2LnYp9mE2KjYsdin2YXYrNin2YTZhdmI2KfZgti52KfZhNix2LPYp9im2YTZhdi02KfYsdmD2KfYqtin2YTYo9i52LbYp9ih2KfZhNix2YrYp9i22KnYp9mE2KrYtdmF2YrZhdin2YTYp9i52LbYp9ih2KfZhNmG2KrYp9im2KzYp9mE2KPZhNi52KfYqNin2YTYqtiz2KzZitmE2KfZhNij2YLYs9in2YXYp9mE2LbYuti32KfYqtin2YTZgdmK2K/ZitmI2KfZhNiq2LHYrdmK2KjYp9mE2KzYr9mK2K/Yqdin2YTYqti52YTZitmF2KfZhNij2K7YqNin2LHYp9mE2KfZgdmE2KfZhdin2YTYo9mB2YTYp9mF2KfZhNiq2KfYsdmK2K7Yp9mE2KrZgtmG2YrYqdin2YTYp9mE2LnYp9io2KfZhNiu2YjYp9i32LHYp9mE2YXYrNiq2YXYudin2YTYr9mK2YPZiNix2KfZhNiz2YrYp9it2KnYudio2K/Yp9mE2YTZh9in2YTYqtix2KjZitip2KfZhNix2YjYp9io2LfYp9mE2KPYr9io2YrYqdin2YTYp9iu2KjYp9ix2KfZhNmF2KrYrdiv2KnYp9mE2KfYutin2YbZimN1cnNvcjpwb2ludGVyOzwvdGl0bGU+CjxtZXRhICIgaHJlZj0iaHR0cDovLyI+PHNwYW4gY2xhc3M9Im1lbWJlcnMgb2YgdGhlIHdpbmRvdy5sb2NhdGlvbnZlcnRpY2FsLWFsaWduOi9hPiB8IDxhIGhyZWY9IjwhZG9jdHlwZSBodG1sPm1lZGlhPSJzY3JlZW4iIDxvcHRpb24gdmFsdWU9ImZhdmljb24uaWNvIiAvPgoJCTxkaXYgY2xhc3M9ImNoYXJhY3RlcmlzdGljcyIgbWV0aG9kPSJnZXQiIC9ib2R5Pgo8L2h0bWw+CnNob3J0Y3V0IGljb24iIGRvY3VtZW50LndyaXRlKHBhZGRpbmctYm90dG9tOnJlcHJlc2VudGF0aXZlc3N1Ym1pdCIgdmFsdWU9ImFsaWduPSJjZW50ZXIiIHRocm91Z2hvdXQgdGhlIHNjaWVuY2UgZmljdGlvbgogIDxkaXYgY2xhc3M9InN1Ym1pdCIgY2xhc3M9Im9uZSBvZiB0aGUgbW9zdCB2YWxpZ249InRvcCI+PHdhcyBlc3RhYmxpc2hlZCk7DQo8L3NjcmlwdD4NCnJldHVybiBmYWxzZTsiPikuc3R5bGUuZGlzcGxheWJlY2F1c2Ugb2YgdGhlIGRvY3VtZW50LmNvb2tpZTxmb3JtIGFjdGlvbj0iL31ib2R5e21hcmdpbjowO0VuY3ljbG9wZWRpYSBvZnZlcnNpb24gb2YgdGhlIC5jcmVhdGVFbGVtZW50KG5hbWUiIGNvbnRlbnQ9IjwvZGl2Pgo8L2Rpdj4KCmFkbWluaXN0cmF0aXZlIDwvYm9keT4KPC9odG1sPmhpc3Rvcnkgb2YgdGhlICI+PGlucHV0IHR5cGU9InBvcnRpb24gb2YgdGhlIGFzIHBhcnQgb2YgdGhlICZuYnNwOzxhIGhyZWY9Im90aGVyIGNvdW50cmllcyI+CjxkaXYgY2xhc3M9Ijwvc3Bhbj48L3NwYW4+PEluIG90aGVyIHdvcmRzLGRpc3BsYXk6IGJsb2NrO2NvbnRyb2wgb2YgdGhlIGludHJvZHVjdGlvbiBvZi8+CjxtZXRhIG5hbWU9ImFzIHdlbGwgYXMgdGhlIGluIHJlY2VudCB5ZWFycw0KCTxkaXYgY2xhc3M9IjwvZGl2PgoJPC9kaXY+Cmluc3BpcmVkIGJ5IHRoZXRoZSBlbmQgb2YgdGhlIGNvbXBhdGlibGUgd2l0aGJlY2FtZSBrbm93biBhcyBzdHlsZT0ibWFyZ2luOi5qcyI+PC9zY3JpcHQ+PCBJbnRlcm5hdGlvbmFsIHRoZXJlIGhhdmUgYmVlbkdlcm1hbiBsYW5ndWFnZSBzdHlsZT0iY29sb3I6I0NvbW11bmlzdCBQYXJ0eWNvbnNpc3RlbnQgd2l0aGJvcmRlcj0iMCIgY2VsbCBtYXJnaW5oZWlnaHQ9InRoZSBtYWpvcml0eSBvZiIgYWxpZ249ImNlbnRlcnJlbGF0ZWQgdG8gdGhlIG1hbnkgZGlmZmVyZW50IE9ydGhvZG94IENodXJjaHNpbWlsYXIgdG8gdGhlIC8+CjxsaW5rIHJlbD0ic3dhcyBvbmUgb2YgdGhlIHVudGlsIGhpcyBkZWF0aH0pKCk7Cjwvc2NyaXB0Pm90aGVyIGxhbmd1YWdlc2NvbXBhcmVkIHRvIHRoZXBvcnRpb25zIG9mIHRoZXRoZSBOZXRoZXJsYW5kc3RoZSBtb3N0IGNvbW1vbmJhY2tncm91bmQ6dXJsKGFyZ3VlZCB0aGF0IHRoZXNjcm9sbGluZz0ibm8iIGluY2x1ZGVkIGluIHRoZU5vcnRoIEFtZXJpY2FuIHRoZSBuYW1lIG9mIHRoZWludGVycHJldGF0aW9uc3RoZSB0cmFkaXRpb25hbGRldmVsb3BtZW50IG9mIGZyZXF1ZW50bHkgdXNlZGEgY29sbGVjdGlvbiBvZnZlcnkgc2ltaWxhciB0b3N1cnJvdW5kaW5nIHRoZWV4YW1wbGUgb2YgdGhpc2FsaWduPSJjZW50ZXIiPndvdWxkIGhhdmUgYmVlbmltYWdlX2NhcHRpb24gPWF0dGFjaGVkIHRvIHRoZXN1Z2dlc3RpbmcgdGhhdGluIHRoZSBmb3JtIG9mIGludm9sdmVkIGluIHRoZWlzIGRlcml2ZWQgZnJvbW5hbWVkIGFmdGVyIHRoZUludHJvZHVjdGlvbiB0b3Jlc3RyaWN0aW9ucyBvbiBzdHlsZT0id2lkdGg6IGNhbiBiZSB1c2VkIHRvIHRoZSBjcmVhdGlvbiBvZm1vc3QgaW1wb3J0YW50IGluZm9ybWF0aW9uIGFuZHJlc3VsdGVkIGluIHRoZWNvbGxhcHNlIG9mIHRoZVRoaXMgbWVhbnMgdGhhdGVsZW1lbnRzIG9mIHRoZXdhcyByZXBsYWNlZCBieWFuYWx5c2lzIG9mIHRoZWluc3BpcmF0aW9uIGZvcnJlZ2FyZGVkIGFzIHRoZW1vc3Qgc3VjY2Vzc2Z1bGtub3duIGFzICZxdW90O2EgY29tcHJlaGVuc2l2ZUhpc3Rvcnkgb2YgdGhlIHdlcmUgY29uc2lkZXJlZHJldHVybmVkIHRvIHRoZWFyZSByZWZlcnJlZCB0b1Vuc291cmNlZCBpbWFnZT4KCTxkaXYgY2xhc3M9ImNvbnNpc3RzIG9mIHRoZXN0b3BQcm9wYWdhdGlvbmludGVyZXN0IGluIHRoZWF2YWlsYWJpbGl0eSBvZmFwcGVhcnMgdG8gaGF2ZWVsZWN0cm9tYWduZXRpY2VuYWJsZVNlcnZpY2VzKGZ1bmN0aW9uIG9mIHRoZUl0IGlzIGltcG9ydGFudDwvc2NyaXB0PjwvZGl2PmZ1bmN0aW9uKCl7dmFyIHJlbGF0aXZlIHRvIHRoZWFzIGEgcmVzdWx0IG9mIHRoZSBwb3NpdGlvbiBvZkZvciBleGFtcGxlLCBpbiBtZXRob2Q9InBvc3QiIHdhcyBmb2xsb3dlZCBieSZhbXA7bWRhc2g7IHRoZXRoZSBhcHBsaWNhdGlvbmpzIj48L3NjcmlwdD4NCnVsPjwvZGl2PjwvZGl2PmFmdGVyIHRoZSBkZWF0aHdpdGggcmVzcGVjdCB0b3N0eWxlPSJwYWRkaW5nOmlzIHBhcnRpY3VsYXJseWRpc3BsYXk6aW5saW5lOyB0eXBlPSJzdWJtaXQiIGlzIGRpdmlkZWQgaW50b+S4reaWhyAo566A5L2TKXJlc3BvbnNhYmlsaWRhZGFkbWluaXN0cmFjacOzbmludGVybmFjaW9uYWxlc2NvcnJlc3BvbmRpZW50ZeCkieCkquCkr+Cli+Ckl+CkquClguCksOCljeCkteCkueCkruCkvuCksOClh+CksuCli+Ckl+Cli+CkguCkmuClgeCkqOCkvuCkteCksuClh+CkleCkv+CkqOCkuOCksOCkleCkvuCksOCkquClgeCksuCkv+CkuOCkluCli+CknOClh+CkguCkmuCkvuCkueCkv+Ckj+CkreClh+CknOClh+CkguCktuCkvuCkruCkv+CksuCkueCkruCkvuCksOClgOCknOCkvuCkl+CksOCko+CkrOCkqOCkvuCkqOClh+CkleClgeCkruCkvuCksOCkrOCljeCksuClieCkl+CkruCkvuCksuCkv+CkleCkruCkueCkv+CksuCkvuCkquClg+Ckt+CljeCkoOCkrOCkouCkvOCkpOClh+CkreCkvuCknOCkquCkvuCkleCljeCksuCkv+CkleCkn+CljeCksOClh+CkqOCkluCkv+CksuCkvuCkq+CkpuCljOCksOCkvuCkqOCkruCkvuCkruCksuClh+CkruCkpOCkpuCkvuCkqOCkrOCkvuCknOCkvuCksOCkteCkv+CkleCkvuCkuOCkleCljeCkr+Cli+CkguCkmuCkvuCkueCkpOClh+CkquCkueClgeCkgeCkmuCkrOCkpOCkvuCkr+CkvuCkuOCkguCkteCkvuCkpuCkpuClh+CkluCkqOClh+CkquCkv+Ckm+CksuClh+CkteCkv+CktuClh+Ckt+CksOCkvuCknOCljeCkr+CkieCkpOCljeCkpOCksOCkruClgeCkguCkrOCkiOCkpuCli+CkqOCli+CkguCkieCkquCkleCksOCko+CkquCkouCkvOClh+CkguCkuOCljeCkpeCkv+CkpOCkq+Ckv+CksuCljeCkruCkruClgeCkluCljeCkr+CkheCkmuCljeCkm+CkvuCkm+ClguCkn+CkpOClgOCkuOCkguCkl+ClgOCkpOCknOCkvuCkj+Ckl+CkvuCkteCkv+CkreCkvuCkl+CkmOCko+CljeCkn+Clh+CkpuClguCkuOCksOClh+CkpuCkv+CkqOCli+CkguCkueCkpOCljeCkr+CkvuCkuOClh+CkleCljeCkuOCkl+CkvuCkguCkp+ClgOCkteCkv+CktuCljeCkteCksOCkvuCkpOClh+CkguCkpuCliOCkn+CljeCkuOCkqOCkleCljeCktuCkvuCkuOCkvuCkruCkqOClh+CkheCkpuCkvuCksuCkpOCkrOCkv+CknOCksuClgOCkquClgeCksOClguCkt+CkueCkv+CkguCkpuClgOCkruCkv+CkpOCljeCksOCkleCkteCkv+CkpOCkvuCksOClgeCkquCkr+Clh+CkuOCljeCkpeCkvuCkqOCkleCksOCli+CkoeCkvOCkruClgeCkleCljeCkpOCkr+Cli+CknOCkqOCkvuCkleClg+CkquCkr+CkvuCkquCli+CkuOCljeCkn+CkmOCksOClh+CksuClguCkleCkvuCksOCljeCkr+CkteCkv+CkmuCkvuCksOCkuOClguCkmuCkqOCkvuCkruClguCksuCljeCkr+CkpuClh+CkluClh+CkguCkueCkruClh+CktuCkvuCkuOCljeCkleClguCksuCkruCliOCkguCkqOClh+CkpOCliOCkr+CkvuCksOCknOCkv+CkuOCkleClh3Jzcyt4bWwiIHRpdGxlPSItdHlwZSIgY29udGVudD0idGl0bGUiIGNvbnRlbnQ9ImF0IHRoZSBzYW1lIHRpbWUuanMiPjwvc2NyaXB0Pgo8IiBtZXRob2Q9InBvc3QiIDwvc3Bhbj48L2E+PC9saT52ZXJ0aWNhbC1hbGlnbjp0L2pxdWVyeS5taW4uanMiPi5jbGljayhmdW5jdGlvbiggc3R5bGU9InBhZGRpbmctfSkoKTsKPC9zY3JpcHQ+Cjwvc3Bhbj48YSBocmVmPSI8YSBocmVmPSJodHRwOi8vKTsgcmV0dXJuIGZhbHNlO3RleHQtZGVjb3JhdGlvbjogc2Nyb2xsaW5nPSJubyIgYm9yZGVyLWNvbGxhcHNlOmFzc29jaWF0ZWQgd2l0aCBCYWhhc2EgSW5kb25lc2lhRW5nbGlzaCBsYW5ndWFnZTx0ZXh0IHhtbDpzcGFjZT0uZ2lmIiBib3JkZXI9IjAiPC9ib2R5Pgo8L2h0bWw+Cm92ZXJmbG93OmhpZGRlbjtpbWcgc3JjPSJodHRwOi8vYWRkRXZlbnRMaXN0ZW5lcnJlc3BvbnNpYmxlIGZvciBzLmpzIj48L3NjcmlwdD4KL2Zhdmljb24uaWNvIiAvPm9wZXJhdGluZyBzeXN0ZW0iIHN0eWxlPSJ3aWR0aDoxdGFyZ2V0PSJfYmxhbmsiPlN0YXRlIFVuaXZlcnNpdHl0ZXh0LWFsaWduOmxlZnQ7CmRvY3VtZW50LndyaXRlKCwgaW5jbHVkaW5nIHRoZSBhcm91bmQgdGhlIHdvcmxkKTsNCjwvc2NyaXB0Pg0KPCIgc3R5bGU9ImhlaWdodDo7b3ZlcmZsb3c6aGlkZGVubW9yZSBpbmZvcm1hdGlvbmFuIGludGVybmF0aW9uYWxhIG1lbWJlciBvZiB0aGUgb25lIG9mIHRoZSBmaXJzdGNhbiBiZSBmb3VuZCBpbiA8L2Rpdj4KCQk8L2Rpdj4KZGlzcGxheTogbm9uZTsiPiIgLz4KPGxpbmsgcmVsPSIKICAoZnVuY3Rpb24oKSB7dGhlIDE1dGggY2VudHVyeS5wcmV2ZW50RGVmYXVsdChsYXJnZSBudW1iZXIgb2YgQnl6YW50aW5lIEVtcGlyZS5qcGd8dGh1bWJ8bGVmdHx2YXN0IG1ham9yaXR5IG9mbWFqb3JpdHkgb2YgdGhlICBhbGlnbj0iY2VudGVyIj5Vbml2ZXJzaXR5IFByZXNzZG9taW5hdGVkIGJ5IHRoZVNlY29uZCBXb3JsZCBXYXJkaXN0cmlidXRpb24gb2Ygc3R5bGU9InBvc2l0aW9uOnRoZSByZXN0IG9mIHRoZSBjaGFyYWN0ZXJpemVkIGJ5IHJlbD0ibm9mb2xsb3ciPmRlcml2ZXMgZnJvbSB0aGVyYXRoZXIgdGhhbiB0aGUgYSBjb21iaW5hdGlvbiBvZnN0eWxlPSJ3aWR0aDoxMDBFbmdsaXNoLXNwZWFraW5nY29tcHV0ZXIgc2NpZW5jZWJvcmRlcj0iMCIgYWx0PSJ0aGUgZXhpc3RlbmNlIG9mRGVtb2NyYXRpYyBQYXJ0eSIgc3R5bGU9Im1hcmdpbi1Gb3IgdGhpcyByZWFzb24sLmpzIj48L3NjcmlwdD4KCXNCeVRhZ05hbWUocylbMF1qcyI+PC9zY3JpcHQ+DQo8LmpzIj48L3NjcmlwdD4NCmxpbmsgcmVsPSJpY29uIiAnIGFsdD0nJyBjbGFzcz0nZm9ybWF0aW9uIG9mIHRoZXZlcnNpb25zIG9mIHRoZSA8L2E+PC9kaXY+PC9kaXY+L3BhZ2U+CiAgPHBhZ2U+CjxkaXYgY2xhc3M9ImNvbnRiZWNhbWUgdGhlIGZpcnN0YmFoYXNhIEluZG9uZXNpYWVuZ2xpc2ggKHNpbXBsZSnOlc67zrvOt869zrnOus6s0YXRgNCy0LDRgtGB0LrQuNC60L7QvNC/0LDQvdC40LjRj9Cy0LvRj9C10YLRgdGP0JTQvtCx0LDQstC40YLRjNGH0LXQu9C+0LLQtdC60LDRgNCw0LfQstC40YLQuNGP0JjQvdGC0LXRgNC90LXRgtCe0YLQstC10YLQuNGC0YzQvdCw0L/RgNC40LzQtdGA0LjQvdGC0LXRgNC90LXRgtC60L7RgtC+0YDQvtCz0L7RgdGC0YDQsNC90LjRhtGL0LrQsNGH0LXRgdGC0LLQtdGD0YHQu9C+0LLQuNGP0YXQv9GA0L7QsdC70LXQvNGL0L/QvtC70YPRh9C40YLRjNGP0LLQu9GP0Y7RgtGB0Y/QvdCw0LjQsdC+0LvQtdC10LrQvtC80L/QsNC90LjRj9Cy0L3QuNC80LDQvdC40LXRgdGA0LXQtNGB0YLQstCw2KfZhNmF2YjYp9i22YrYudin2YTYsdim2YrYs9mK2KnYp9mE2KfZhtiq2YLYp9mE2YXYtNin2LHZg9in2KrZg9in2YTYs9mK2KfYsdin2KrYp9mE2YXZg9iq2YjYqNip2KfZhNiz2LnZiNiv2YrYqdin2K3Ytdin2KbZitin2KrYp9mE2LnYp9mE2YXZitip2KfZhNi12YjYqtmK2KfYqtin2YTYp9mG2KrYsdmG2KrYp9mE2KrYtdin2YXZitmF2KfZhNil2LPZhNin2YXZitin2YTZhdi02KfYsdmD2KnYp9mE2YXYsdim2YrYp9iqcm9ib3RzIiBjb250ZW50PSI8ZGl2IGlkPSJmb290ZXIiPnRoZSBVbml0ZWQgU3RhdGVzPGltZyBzcmM9Imh0dHA6Ly8uanBnfHJpZ2h0fHRodW1ifC5qcyI+PC9zY3JpcHQ+DQo8bG9jYXRpb24ucHJvdG9jb2xmcmFtZWJvcmRlcj0iMCIgcyIgLz4KPG1ldGEgbmFtZT0iPC9hPjwvZGl2PjwvZGl2Pjxmb250LXdlaWdodDpib2xkOyZxdW90OyBhbmQgJnF1b3Q7ZGVwZW5kaW5nIG9uIHRoZSBtYXJnaW46MDtwYWRkaW5nOiIgcmVsPSJub2ZvbGxvdyIgUHJlc2lkZW50IG9mIHRoZSB0d2VudGlldGggY2VudHVyeWV2aXNpb24+CiAgPC9wYWdlSW50ZXJuZXQgRXhwbG9yZXJhLmFzeW5jID0gdHJ1ZTsNCmluZm9ybWF0aW9uIGFib3V0PGRpdiBpZD0iaGVhZGVyIj4iIGFjdGlvbj0iaHR0cDovLzxhIGhyZWY9Imh0dHBzOi8vPGRpdiBpZD0iY29udGVudCI8L2Rpdj4NCjwvZGl2Pg0KPGRlcml2ZWQgZnJvbSB0aGUgPGltZyBzcmM9J2h0dHA6Ly9hY2NvcmRpbmcgdG8gdGhlIAo8L2JvZHk+CjwvaHRtbD4Kc3R5bGU9ImZvbnQtc2l6ZTpzY3JpcHQgbGFuZ3VhZ2U9IkFyaWFsLCBIZWx2ZXRpY2EsPC9hPjxzcGFuIGNsYXNzPSI8L3NjcmlwdD48c2NyaXB0IHBvbGl0aWNhbCBwYXJ0aWVzdGQ+PC90cj48L3RhYmxlPjxocmVmPSJodHRwOi8vd3d3LmludGVycHJldGF0aW9uIG9mcmVsPSJzdHlsZXNoZWV0IiBkb2N1bWVudC53cml0ZSgnPGNoYXJzZXQ9InV0Zi04Ij4KYmVnaW5uaW5nIG9mIHRoZSByZXZlYWxlZCB0aGF0IHRoZXRlbGV2aXNpb24gc2VyaWVzIiByZWw9Im5vZm9sbG93Ij4gdGFyZ2V0PSJfYmxhbmsiPmNsYWltaW5nIHRoYXQgdGhlaHR0cCUzQSUyRiUyRnd3dy5tYW5pZmVzdGF0aW9ucyBvZlByaW1lIE1pbmlzdGVyIG9maW5mbHVlbmNlZCBieSB0aGVjbGFzcz0iY2xlYXJmaXgiPi9kaXY+DQo8L2Rpdj4NCg0KdGhyZWUtZGltZW5zaW9uYWxDaHVyY2ggb2YgRW5nbGFuZG9mIE5vcnRoIENhcm9saW5hc3F1YXJlIGtpbG9tZXRyZXMuYWRkRXZlbnRMaXN0ZW5lcmRpc3RpbmN0IGZyb20gdGhlY29tbW9ubHkga25vd24gYXNQaG9uZXRpYyBBbHBoYWJldGRlY2xhcmVkIHRoYXQgdGhlY29udHJvbGxlZCBieSB0aGVCZW5qYW1pbiBGcmFua2xpbnJvbGUtcGxheWluZyBnYW1ldGhlIFVuaXZlcnNpdHkgb2ZpbiBXZXN0ZXJuIEV1cm9wZXBlcnNvbmFsIGNvbXB1dGVyUHJvamVjdCBHdXRlbmJlcmdyZWdhcmRsZXNzIG9mIHRoZWhhcyBiZWVuIHByb3Bvc2VkdG9nZXRoZXIgd2l0aCB0aGU+PC9saT48bGkgY2xhc3M9ImluIHNvbWUgY291bnRyaWVzbWluLmpzIj48L3NjcmlwdD5vZiB0aGUgcG9wdWxhdGlvbm9mZmljaWFsIGxhbmd1YWdlPGltZyBzcmM9ImltYWdlcy9pZGVudGlmaWVkIGJ5IHRoZW5hdHVyYWwgcmVzb3VyY2VzY2xhc3NpZmljYXRpb24gb2ZjYW4gYmUgY29uc2lkZXJlZHF1YW50dW0gbWVjaGFuaWNzTmV2ZXJ0aGVsZXNzLCB0aGVtaWxsaW9uIHllYXJzIGFnbzwvYm9keT4NCjwvaHRtbD4NzpXOu867zrfOvc65zrrOrAp0YWtlIGFkdmFudGFnZSBvZmFuZCwgYWNjb3JkaW5nIHRvYXR0cmlidXRlZCB0byB0aGVNaWNyb3NvZnQgV2luZG93c3RoZSBmaXJzdCBjZW50dXJ5dW5kZXIgdGhlIGNvbnRyb2xkaXYgY2xhc3M9ImhlYWRlcnNob3J0bHkgYWZ0ZXIgdGhlbm90YWJsZSBleGNlcHRpb250ZW5zIG9mIHRob3VzYW5kc3NldmVyYWwgZGlmZmVyZW50YXJvdW5kIHRoZSB3b3JsZC5yZWFjaGluZyBtaWxpdGFyeWlzb2xhdGVkIGZyb20gdGhlb3Bwb3NpdGlvbiB0byB0aGV0aGUgT2xkIFRlc3RhbWVudEFmcmljYW4gQW1lcmljYW5zaW5zZXJ0ZWQgaW50byB0aGVzZXBhcmF0ZSBmcm9tIHRoZW1ldHJvcG9saXRhbiBhcmVhbWFrZXMgaXQgcG9zc2libGVhY2tub3dsZWRnZWQgdGhhdGFyZ3VhYmx5IHRoZSBtb3N0dHlwZT0idGV4dC9jc3MiPgp0aGUgSW50ZXJuYXRpb25hbEFjY29yZGluZyB0byB0aGUgcGU9InRleHQvY3NzIiAvPgpjb2luY2lkZSB3aXRoIHRoZXR3by10aGlyZHMgb2YgdGhlRHVyaW5nIHRoaXMgdGltZSxkdXJpbmcgdGhlIHBlcmlvZGFubm91bmNlZCB0aGF0IGhldGhlIGludGVybmF0aW9uYWxhbmQgbW9yZSByZWNlbnRseWJlbGlldmVkIHRoYXQgdGhlY29uc2Npb3VzbmVzcyBhbmRmb3JtZXJseSBrbm93biBhc3N1cnJvdW5kZWQgYnkgdGhlZmlyc3QgYXBwZWFyZWQgaW5vY2Nhc2lvbmFsbHkgdXNlZHBvc2l0aW9uOmFic29sdXRlOyIgdGFyZ2V0PSJfYmxhbmsiIHBvc2l0aW9uOnJlbGF0aXZlO3RleHQtYWxpZ246Y2VudGVyO2pheC9saWJzL2pxdWVyeS8xLmJhY2tncm91bmQtY29sb3I6I3R5cGU9ImFwcGxpY2F0aW9uL2FuZ3VhZ2UiIGNvbnRlbnQ9IjxtZXRhIGh0dHAtZXF1aXY9IlByaXZhY3kgUG9saWN5PC9hPmUoIiUzQ3NjcmlwdCBzcmM9JyIgdGFyZ2V0PSJfYmxhbmsiPk9uIHRoZSBvdGhlciBoYW5kLC5qcGd8dGh1bWJ8cmlnaHR8MjwvZGl2PjxkaXYgY2xhc3M9IjxkaXYgc3R5bGU9ImZsb2F0Om5pbmV0ZWVudGggY2VudHVyeTwvYm9keT4NCjwvaHRtbD4NCjxpbWcgc3JjPSJodHRwOi8vczt0ZXh0LWFsaWduOmNlbnRlcmZvbnQtd2VpZ2h0OiBib2xkOyBBY2NvcmRpbmcgdG8gdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiIgZnJhbWVib3JkZXI9IjAiICIgc3R5bGU9InBvc2l0aW9uOmxpbmsgaHJlZj0iaHR0cDovL2h0bWw0L2xvb3NlLmR0ZCI+CmR1cmluZyB0aGlzIHBlcmlvZDwvdGQ+PC90cj48L3RhYmxlPmNsb3NlbHkgcmVsYXRlZCB0b2ZvciB0aGUgZmlyc3QgdGltZTtmb250LXdlaWdodDpib2xkO2lucHV0IHR5cGU9InRleHQiIDxzcGFuIHN0eWxlPSJmb250LW9ucmVhZHlzdGF0ZWNoYW5nZQk8ZGl2IGNsYXNzPSJjbGVhcmRvY3VtZW50LmxvY2F0aW9uLiBGb3IgZXhhbXBsZSwgdGhlIGEgd2lkZSB2YXJpZXR5IG9mIDwhRE9DVFlQRSBodG1sPg0KPCZuYnNwOyZuYnNwOyZuYnNwOyI+PGEgaHJlZj0iaHR0cDovL3N0eWxlPSJmbG9hdDpsZWZ0O2NvbmNlcm5lZCB3aXRoIHRoZT1odHRwJTNBJTJGJTJGd3d3LmluIHBvcHVsYXIgY3VsdHVyZXR5cGU9InRleHQvY3NzIiAvPml0IGlzIHBvc3NpYmxlIHRvIEhhcnZhcmQgVW5pdmVyc2l0eXR5bGVzaGVldCIgaHJlZj0iL3RoZSBtYWluIGNoYXJhY3Rlck94Zm9yZCBVbml2ZXJzaXR5ICBuYW1lPSJrZXl3b3JkcyIgY3N0eWxlPSJ0ZXh0LWFsaWduOnRoZSBVbml0ZWQgS2luZ2RvbWZlZGVyYWwgZ292ZXJubWVudDxkaXYgc3R5bGU9Im1hcmdpbiBkZXBlbmRpbmcgb24gdGhlIGRlc2NyaXB0aW9uIG9mIHRoZTxkaXYgY2xhc3M9ImhlYWRlci5taW4uanMiPjwvc2NyaXB0PmRlc3RydWN0aW9uIG9mIHRoZXNsaWdodGx5IGRpZmZlcmVudGluIGFjY29yZGFuY2Ugd2l0aHRlbGVjb21tdW5pY2F0aW9uc2luZGljYXRlcyB0aGF0IHRoZXNob3J0bHkgdGhlcmVhZnRlcmVzcGVjaWFsbHkgaW4gdGhlIEV1cm9wZWFuIGNvdW50cmllc0hvd2V2ZXIsIHRoZXJlIGFyZXNyYz0iaHR0cDovL3N0YXRpY3N1Z2dlc3RlZCB0aGF0IHRoZSIgc3JjPSJodHRwOi8vd3d3LmEgbGFyZ2UgbnVtYmVyIG9mIFRlbGVjb21tdW5pY2F0aW9ucyIgcmVsPSJub2ZvbGxvdyIgdEhvbHkgUm9tYW4gRW1wZXJvcmFsbW9zdCBleGNsdXNpdmVseSIgYm9yZGVyPSIwIiBhbHQ9IlNlY3JldGFyeSBvZiBTdGF0ZWN1bG1pbmF0aW5nIGluIHRoZUNJQSBXb3JsZCBGYWN0Ym9va3RoZSBtb3N0IGltcG9ydGFudGFubml2ZXJzYXJ5IG9mIHRoZXN0eWxlPSJiYWNrZ3JvdW5kLTxsaT48ZW0+PGEgaHJlZj0iL3RoZSBBdGxhbnRpYyBPY2VhbnN0cmljdGx5IHNwZWFraW5nLHNob3J0bHkgYmVmb3JlIHRoZWRpZmZlcmVudCB0eXBlcyBvZnRoZSBPdHRvbWFuIEVtcGlyZT48aW1nIHNyYz0iaHR0cDovL0FuIEludHJvZHVjdGlvbiB0b2NvbnNlcXVlbmNlIG9mIHRoZWRlcGFydHVyZSBmcm9tIHRoZUNvbmZlZGVyYXRlIFN0YXRlc2luZGlnZW5vdXMgcGVvcGxlc1Byb2NlZWRpbmdzIG9mIHRoZWluZm9ybWF0aW9uIG9uIHRoZXRoZW9yaWVzIGhhdmUgYmVlbmludm9sdmVtZW50IGluIHRoZWRpdmlkZWQgaW50byB0aHJlZWFkamFjZW50IGNvdW50cmllc2lzIHJlc3BvbnNpYmxlIGZvcmRpc3NvbHV0aW9uIG9mIHRoZWNvbGxhYm9yYXRpb24gd2l0aHdpZGVseSByZWdhcmRlZCBhc2hpcyBjb250ZW1wb3Jhcmllc2ZvdW5kaW5nIG1lbWJlciBvZkRvbWluaWNhbiBSZXB1YmxpY2dlbmVyYWxseSBhY2NlcHRlZHRoZSBwb3NzaWJpbGl0eSBvZmFyZSBhbHNvIGF2YWlsYWJsZXVuZGVyIGNvbnN0cnVjdGlvbnJlc3RvcmF0aW9uIG9mIHRoZXRoZSBnZW5lcmFsIHB1YmxpY2lzIGFsbW9zdCBlbnRpcmVseXBhc3NlcyB0aHJvdWdoIHRoZWhhcyBiZWVuIHN1Z2dlc3RlZGNvbXB1dGVyIGFuZCB2aWRlb0dlcm1hbmljIGxhbmd1YWdlcyBhY2NvcmRpbmcgdG8gdGhlIGRpZmZlcmVudCBmcm9tIHRoZXNob3J0bHkgYWZ0ZXJ3YXJkc2hyZWY9Imh0dHBzOi8vd3d3LnJlY2VudCBkZXZlbG9wbWVudEJvYXJkIG9mIERpcmVjdG9yczxkaXYgY2xhc3M9InNlYXJjaHwgPGEgaHJlZj0iaHR0cDovL0luIHBhcnRpY3VsYXIsIHRoZU11bHRpcGxlIGZvb3Rub3Rlc29yIG90aGVyIHN1YnN0YW5jZXRob3VzYW5kcyBvZiB5ZWFyc3RyYW5zbGF0aW9uIG9mIHRoZTwvZGl2Pg0KPC9kaXY+DQoNCjxhIGhyZWY9ImluZGV4LnBocHdhcyBlc3RhYmxpc2hlZCBpbm1pbi5qcyI+PC9zY3JpcHQ+CnBhcnRpY2lwYXRlIGluIHRoZWEgc3Ryb25nIGluZmx1ZW5jZXN0eWxlPSJtYXJnaW4tdG9wOnJlcHJlc2VudGVkIGJ5IHRoZWdyYWR1YXRlZCBmcm9tIHRoZVRyYWRpdGlvbmFsbHksIHRoZUVsZW1lbnQoInNjcmlwdCIpO0hvd2V2ZXIsIHNpbmNlIHRoZS9kaXY+CjwvZGl2Pgo8ZGl2IGxlZnQ7IG1hcmdpbi1sZWZ0OnByb3RlY3Rpb24gYWdhaW5zdDA7IHZlcnRpY2FsLWFsaWduOlVuZm9ydHVuYXRlbHksIHRoZXR5cGU9ImltYWdlL3gtaWNvbi9kaXY+CjxkaXYgY2xhc3M9IiBjbGFzcz0iY2xlYXJmaXgiPjxkaXYgY2xhc3M9ImZvb3RlcgkJPC9kaXY+CgkJPC9kaXY+CnRoZSBtb3Rpb24gcGljdHVyZdCR0YrQu9Cz0LDRgNGB0LrQuNCx0YrQu9Cz0LDRgNGB0LrQuNCk0LXQtNC10YDQsNGG0LjQuNC90LXRgdC60L7Qu9GM0LrQvtGB0L7QvtCx0YnQtdC90LjQtdGB0L7QvtCx0YnQtdC90LjRj9C/0YDQvtCz0YDQsNC80LzRi9Ce0YLQv9GA0LDQstC40YLRjNCx0LXRgdC/0LvQsNGC0L3QvtC80LDRgtC10YDQuNCw0LvRi9C/0L7Qt9Cy0L7Qu9GP0LXRgtC/0L7RgdC70LXQtNC90LjQtdGA0LDQt9C70LjRh9C90YvRhdC/0YDQvtC00YPQutGG0LjQuNC/0YDQvtCz0YDQsNC80LzQsNC/0L7Qu9C90L7RgdGC0YzRjtC90LDRhdC+0LTQuNGC0YHRj9C40LfQsdGA0LDQvdC90L7QtdC90LDRgdC10LvQtdC90LjRj9C40LfQvNC10L3QtdC90LjRj9C60LDRgtC10LPQvtGA0LjQuNCQ0LvQtdC60YHQsNC90LTRgOCkpuCljeCkteCkvuCksOCkvuCkruCliOCkqOClgeCkheCksuCkquCljeCksOCkpuCkvuCkqOCkreCkvuCksOCkpOClgOCkr+CkheCkqOClgeCkpuClh+CktuCkueCkv+CkqOCljeCkpuClgOCkh+CkguCkoeCkv+Ckr+CkvuCkpuCkv+CksuCljeCksuClgOCkheCkp+Ckv+CkleCkvuCksOCkteClgOCkoeCkv+Ckr+Cli+CkmuCkv+Ckn+CljeCkoOClh+CkuOCkruCkvuCkmuCkvuCksOCknOCkguCkleCljeCktuCkqOCkpuClgeCkqOCkv+Ckr+CkvuCkquCljeCksOCkr+Cli+Ckl+CkheCkqOClgeCkuOCkvuCksOCkkeCkqOCksuCkvuCkh+CkqOCkquCkvuCksOCljeCkn+ClgOCktuCksOCljeCkpOCli+CkguCksuCli+CkleCkuOCkreCkvuCkq+CkvOCljeCksuCliOCktuCktuCksOCljeCkpOClh+CkguCkquCljeCksOCkpuClh+CktuCkquCljeCksuClh+Ckr+CksOCkleClh+CkguCkpuCljeCksOCkuOCljeCkpeCkv+CkpOCkv+CkieCkpOCljeCkquCkvuCkpuCkieCkqOCljeCkueClh+CkguCkmuCkv+Ckn+CljeCkoOCkvuCkr+CkvuCkpOCljeCksOCkvuCknOCljeCkr+CkvuCkpuCkvuCkquClgeCksOCkvuCkqOClh+CknOCli+CkoeCkvOClh+CkguCkheCkqOClgeCkteCkvuCkpuCktuCljeCksOClh+Cko+ClgOCktuCkv+CkleCljeCkt+CkvuCkuOCksOCkleCkvuCksOClgOCkuOCkguCkl+CljeCksOCkueCkquCksOCkv+Cko+CkvuCkruCkrOCljeCksOCkvuCkguCkoeCkrOCkmuCljeCkmuCli+CkguCkieCkquCksuCkrOCljeCkp+CkruCkguCkpOCljeCksOClgOCkuOCkguCkquCksOCljeCkleCkieCkruCljeCkruClgOCkpuCkruCkvuCkp+CljeCkr+CkruCkuOCkueCkvuCkr+CkpOCkvuCktuCkrOCljeCkpuCli+CkguCkruClgOCkoeCkv+Ckr+CkvuCkhuCkiOCkquClgOCkj+CksuCkruCli+CkrOCkvuCkh+CksuCkuOCkguCkluCljeCkr+CkvuCkhuCkquCksOClh+CktuCkqOCkheCkqOClgeCkrOCkguCkp+CkrOCkvuCknOCkvOCkvuCksOCkqOCkteClgOCkqOCkpOCkruCkquCljeCksOCkruClgeCkluCkquCljeCksOCktuCljeCkqOCkquCksOCkv+CkteCkvuCksOCkqOClgeCkleCkuOCkvuCkqOCkuOCkruCksOCljeCkpeCkqOCkhuCkr+Cli+CknOCkv+CkpOCkuOCli+CkruCkteCkvuCksNin2YTZhdi02KfYsdmD2KfYqtin2YTZhdmG2KrYr9mK2KfYqtin2YTZg9mF2KjZitmI2KrYsdin2YTZhdi02KfZh9iv2KfYqti52K/Yr9in2YTYstmI2KfYsdi52K/Yr9in2YTYsdiv2YjYr9in2YTYpdiz2YTYp9mF2YrYqdin2YTZgdmI2KrZiNi02YjYqNin2YTZhdiz2KfYqNmC2KfYqtin2YTZhdi52YTZiNmF2KfYqtin2YTZhdiz2YTYs9mE2KfYqtin2YTYrNix2KfZgdmK2YPYs9in2YTYp9iz2YTYp9mF2YrYqdin2YTYp9iq2LXYp9mE2KfYqmtleXdvcmRzIiBjb250ZW50PSJ3My5vcmcvMTk5OS94aHRtbCI+PGEgdGFyZ2V0PSJfYmxhbmsiIHRleHQvaHRtbDsgY2hhcnNldD0iIHRhcmdldD0iX2JsYW5rIj48dGFibGUgY2VsbHBhZGRpbmc9ImF1dG9jb21wbGV0ZT0ib2ZmIiB0ZXh0LWFsaWduOiBjZW50ZXI7dG8gbGFzdCB2ZXJzaW9uIGJ5IGJhY2tncm91bmQtY29sb3I6ICMiIGhyZWY9Imh0dHA6Ly93d3cuL2Rpdj48L2Rpdj48ZGl2IGlkPTxhIGhyZWY9IiMiIGNsYXNzPSIiPjxpbWcgc3JjPSJodHRwOi8vY3JpcHQiIHNyYz0iaHR0cDovLwo8c2NyaXB0IGxhbmd1YWdlPSIvL0VOIiAiaHR0cDovL3d3dy53ZW5jb2RlVVJJQ29tcG9uZW50KCIgaHJlZj0iamF2YXNjcmlwdDo8ZGl2IGNsYXNzPSJjb250ZW50ZG9jdW1lbnQud3JpdGUoJzxzY3Bvc2l0aW9uOiBhYnNvbHV0ZTtzY3JpcHQgc3JjPSJodHRwOi8vIHN0eWxlPSJtYXJnaW4tdG9wOi5taW4uanMiPjwvc2NyaXB0Pgo8L2Rpdj4KPGRpdiBjbGFzcz0idzMub3JnLzE5OTkveGh0bWwiIAoNCjwvYm9keT4NCjwvaHRtbD5kaXN0aW5jdGlvbiBiZXR3ZWVuLyIgdGFyZ2V0PSJfYmxhbmsiPjxsaW5rIGhyZWY9Imh0dHA6Ly9lbmNvZGluZz0idXRmLTgiPz4Kdy5hZGRFdmVudExpc3RlbmVyP2FjdGlvbj0iaHR0cDovL3d3dy5pY29uIiBocmVmPSJodHRwOi8vIHN0eWxlPSJiYWNrZ3JvdW5kOnR5cGU9InRleHQvY3NzIiAvPgptZXRhIHByb3BlcnR5PSJvZzp0PGlucHV0IHR5cGU9InRleHQiICBzdHlsZT0idGV4dC1hbGlnbjp0aGUgZGV2ZWxvcG1lbnQgb2YgdHlsZXNoZWV0IiB0eXBlPSJ0ZWh0bWw7IGNoYXJzZXQ9dXRmLThpcyBjb25zaWRlcmVkIHRvIGJldGFibGUgd2lkdGg9IjEwMCUiIEluIGFkZGl0aW9uIHRvIHRoZSBjb250cmlidXRlZCB0byB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbmRldmVsb3BtZW50IG9mIHRoZSBJdCBpcyBpbXBvcnRhbnQgdG8gPC9zY3JpcHQ+Cgo8c2NyaXB0ICBzdHlsZT0iZm9udC1zaXplOjE+PC9zcGFuPjxzcGFuIGlkPWdiTGlicmFyeSBvZiBDb25ncmVzczxpbWcgc3JjPSJodHRwOi8vaW1FbmdsaXNoIHRyYW5zbGF0aW9uQWNhZGVteSBvZiBTY2llbmNlc2RpdiBzdHlsZT0iZGlzcGxheTpjb25zdHJ1Y3Rpb24gb2YgdGhlLmdldEVsZW1lbnRCeUlkKGlkKWluIGNvbmp1bmN0aW9uIHdpdGhFbGVtZW50KCdzY3JpcHQnKTsgPG1ldGEgcHJvcGVydHk9Im9nOtCR0YrQu9Cz0LDRgNGB0LrQuAogdHlwZT0idGV4dCIgbmFtZT0iPlByaXZhY3kgUG9saWN5PC9hPmFkbWluaXN0ZXJlZCBieSB0aGVlbmFibGVTaW5nbGVSZXF1ZXN0c3R5bGU9JnF1b3Q7bWFyZ2luOjwvZGl2PjwvZGl2PjwvZGl2Pjw+PGltZyBzcmM9Imh0dHA6Ly9pIHN0eWxlPSZxdW90O2Zsb2F0OnJlZmVycmVkIHRvIGFzIHRoZSB0b3RhbCBwb3B1bGF0aW9uIG9maW4gV2FzaGluZ3RvbiwgRC5DLiBzdHlsZT0iYmFja2dyb3VuZC1hbW9uZyBvdGhlciB0aGluZ3Msb3JnYW5pemF0aW9uIG9mIHRoZXBhcnRpY2lwYXRlZCBpbiB0aGV0aGUgaW50cm9kdWN0aW9uIG9maWRlbnRpZmllZCB3aXRoIHRoZWZpY3Rpb25hbCBjaGFyYWN0ZXIgT3hmb3JkIFVuaXZlcnNpdHkgbWlzdW5kZXJzdGFuZGluZyBvZlRoZXJlIGFyZSwgaG93ZXZlcixzdHlsZXNoZWV0IiBocmVmPSIvQ29sdW1iaWEgVW5pdmVyc2l0eWV4cGFuZGVkIHRvIGluY2x1ZGV1c3VhbGx5IHJlZmVycmVkIHRvaW5kaWNhdGluZyB0aGF0IHRoZWhhdmUgc3VnZ2VzdGVkIHRoYXRhZmZpbGlhdGVkIHdpdGggdGhlY29ycmVsYXRpb24gYmV0d2Vlbm51bWJlciBvZiBkaWZmZXJlbnQ+PC90ZD48L3RyPjwvdGFibGU+UmVwdWJsaWMgb2YgSXJlbGFuZAo8L3NjcmlwdD4KPHNjcmlwdCB1bmRlciB0aGUgaW5mbHVlbmNlY29udHJpYnV0aW9uIHRvIHRoZU9mZmljaWFsIHdlYnNpdGUgb2ZoZWFkcXVhcnRlcnMgb2YgdGhlY2VudGVyZWQgYXJvdW5kIHRoZWltcGxpY2F0aW9ucyBvZiB0aGVoYXZlIGJlZW4gZGV2ZWxvcGVkRmVkZXJhbCBSZXB1YmxpYyBvZmJlY2FtZSBpbmNyZWFzaW5nbHljb250aW51YXRpb24gb2YgdGhlTm90ZSwgaG93ZXZlciwgdGhhdHNpbWlsYXIgdG8gdGhhdCBvZiBjYXBhYmlsaXRpZXMgb2YgdGhlYWNjb3JkYW5jZSB3aXRoIHRoZXBhcnRpY2lwYW50cyBpbiB0aGVmdXJ0aGVyIGRldmVsb3BtZW50dW5kZXIgdGhlIGRpcmVjdGlvbmlzIG9mdGVuIGNvbnNpZGVyZWRoaXMgeW91bmdlciBicm90aGVyPC90ZD48L3RyPjwvdGFibGU+PGEgaHR0cC1lcXVpdj0iWC1VQS1waHlzaWNhbCBwcm9wZXJ0aWVzb2YgQnJpdGlzaCBDb2x1bWJpYWhhcyBiZWVuIGNyaXRpY2l6ZWQod2l0aCB0aGUgZXhjZXB0aW9ucXVlc3Rpb25zIGFib3V0IHRoZXBhc3NpbmcgdGhyb3VnaCB0aGUwIiBjZWxscGFkZGluZz0iMCIgdGhvdXNhbmRzIG9mIHBlb3BsZXJlZGlyZWN0cyBoZXJlLiBGb3JoYXZlIGNoaWxkcmVuIHVuZGVyJTNFJTNDL3NjcmlwdCUzRSIpKTs8YSBocmVmPSJodHRwOi8vd3d3LjxsaT48YSBocmVmPSJodHRwOi8vc2l0ZV9uYW1lIiBjb250ZW50PSJ0ZXh0LWRlY29yYXRpb246bm9uZXN0eWxlPSJkaXNwbGF5OiBub25lPG1ldGEgaHR0cC1lcXVpdj0iWC1uZXcgRGF0ZSgpLmdldFRpbWUoKSB0eXBlPSJpbWFnZS94LWljb24iPC9zcGFuPjxzcGFuIGNsYXNzPSJsYW5ndWFnZT0iamF2YXNjcmlwdHdpbmRvdy5sb2NhdGlvbi5ocmVmPGEgaHJlZj0iamF2YXNjcmlwdDotLT4NCjxzY3JpcHQgdHlwZT0idDxhIGhyZWY9J2h0dHA6Ly93d3cuaG9ydGN1dCBpY29uIiBocmVmPSI8L2Rpdj4NCjxkaXYgY2xhc3M9IjxzY3JpcHQgc3JjPSJodHRwOi8vIiByZWw9InN0eWxlc2hlZXQiIHQ8L2Rpdj4KPHNjcmlwdCB0eXBlPS9hPiA8YSBocmVmPSJodHRwOi8vIGFsbG93VHJhbnNwYXJlbmN5PSJYLVVBLUNvbXBhdGlibGUiIGNvbnJlbGF0aW9uc2hpcCBiZXR3ZWVuCjwvc2NyaXB0Pg0KPHNjcmlwdCA8L2E+PC9saT48L3VsPjwvZGl2PmFzc29jaWF0ZWQgd2l0aCB0aGUgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2U8L2E+PGEgaHJlZj0iaHR0cDovLzwvYT48L2xpPjxsaSBjbGFzcz0iZm9ybSBhY3Rpb249Imh0dHA6Ly88ZGl2IHN0eWxlPSJkaXNwbGF5OnR5cGU9InRleHQiIG5hbWU9InEiPHRhYmxlIHdpZHRoPSIxMDAlIiBiYWNrZ3JvdW5kLXBvc2l0aW9uOiIgYm9yZGVyPSIwIiB3aWR0aD0icmVsPSJzaG9ydGN1dCBpY29uIiBoNj48dWw+PGxpPjxhIGhyZWY9IiAgPG1ldGEgaHR0cC1lcXVpdj0iY3NzIiBtZWRpYT0ic2NyZWVuIiByZXNwb25zaWJsZSBmb3IgdGhlICIgdHlwZT0iYXBwbGljYXRpb24vIiBzdHlsZT0iYmFja2dyb3VuZC1odG1sOyBjaGFyc2V0PXV0Zi04IiBhbGxvd3RyYW5zcGFyZW5jeT0ic3R5bGVzaGVldCIgdHlwZT0idGUNCjxtZXRhIGh0dHAtZXF1aXY9Ij48L3NwYW4+PHNwYW4gY2xhc3M9IjAiIGNlbGxzcGFjaW5nPSIwIj47Cjwvc2NyaXB0Pgo8c2NyaXB0IHNvbWV0aW1lcyBjYWxsZWQgdGhlZG9lcyBub3QgbmVjZXNzYXJpbHlGb3IgbW9yZSBpbmZvcm1hdGlvbmF0IHRoZSBiZWdpbm5pbmcgb2YgPCFET0NUWVBFIGh0bWw+PGh0bWxwYXJ0aWN1bGFybHkgaW4gdGhlIHR5cGU9ImhpZGRlbiIgbmFtZT0iamF2YXNjcmlwdDp2b2lkKDApOyJlZmZlY3RpdmVuZXNzIG9mIHRoZSBhdXRvY29tcGxldGU9Im9mZiIgZ2VuZXJhbGx5IGNvbnNpZGVyZWQ+PGlucHV0IHR5cGU9InRleHQiICI+PC9zY3JpcHQ+DQo8c2NyaXB0dGhyb3VnaG91dCB0aGUgd29ybGRjb21tb24gbWlzY29uY2VwdGlvbmFzc29jaWF0aW9uIHdpdGggdGhlPC9kaXY+CjwvZGl2Pgo8ZGl2IGNkdXJpbmcgaGlzIGxpZmV0aW1lLGNvcnJlc3BvbmRpbmcgdG8gdGhldHlwZT0iaW1hZ2UveC1pY29uIiBhbiBpbmNyZWFzaW5nIG51bWJlcmRpcGxvbWF0aWMgcmVsYXRpb25zYXJlIG9mdGVuIGNvbnNpZGVyZWRtZXRhIGNoYXJzZXQ9InV0Zi04IiA8aW5wdXQgdHlwZT0idGV4dCIgZXhhbXBsZXMgaW5jbHVkZSB0aGUiPjxpbWcgc3JjPSJodHRwOi8vaXBhcnRpY2lwYXRpb24gaW4gdGhldGhlIGVzdGFibGlzaG1lbnQgb2YKPC9kaXY+CjxkaXYgY2xhc3M9IiZhbXA7bmJzcDsmYW1wO25ic3A7dG8gZGV0ZXJtaW5lIHdoZXRoZXJxdWl0ZSBkaWZmZXJlbnQgZnJvbW1hcmtlZCB0aGUgYmVnaW5uaW5nZGlzdGFuY2UgYmV0d2VlbiB0aGVjb250cmlidXRpb25zIHRvIHRoZWNvbmZsaWN0IGJldHdlZW4gdGhld2lkZWx5IGNvbnNpZGVyZWQgdG93YXMgb25lIG9mIHRoZSBmaXJzdHdpdGggdmFyeWluZyBkZWdyZWVzaGF2ZSBzcGVjdWxhdGVkIHRoYXQoZG9jdW1lbnQuZ2V0RWxlbWVudHBhcnRpY2lwYXRpbmcgaW4gdGhlb3JpZ2luYWxseSBkZXZlbG9wZWRldGEgY2hhcnNldD0idXRmLTgiPiB0eXBlPSJ0ZXh0L2NzcyIgLz4KaW50ZXJjaGFuZ2VhYmx5IHdpdGhtb3JlIGNsb3NlbHkgcmVsYXRlZHNvY2lhbCBhbmQgcG9saXRpY2FsdGhhdCB3b3VsZCBvdGhlcndpc2VwZXJwZW5kaWN1bGFyIHRvIHRoZXN0eWxlIHR5cGU9InRleHQvY3NzdHlwZT0ic3VibWl0IiBuYW1lPSJmYW1pbGllcyByZXNpZGluZyBpbmRldmVsb3BpbmcgY291bnRyaWVzY29tcHV0ZXIgcHJvZ3JhbW1pbmdlY29ub21pYyBkZXZlbG9wbWVudGRldGVybWluYXRpb24gb2YgdGhlZm9yIG1vcmUgaW5mb3JtYXRpb25vbiBzZXZlcmFsIG9jY2FzaW9uc3BvcnR1Z3XDqnMgKEV1cm9wZXUp0KPQutGA0LDRl9C90YHRjNC60LDRg9C60YDQsNGX0L3RgdGM0LrQsNCg0L7RgdGB0LjQudGB0LrQvtC50LzQsNGC0LXRgNC40LDQu9C+0LLQuNC90YTQvtGA0LzQsNGG0LjQuNGD0L/RgNCw0LLQu9C10L3QuNGP0L3QtdC+0LHRhdC+0LTQuNC80L7QuNC90YTQvtGA0LzQsNGG0LjRj9CY0L3RhNC+0YDQvNCw0YbQuNGP0KDQtdGB0L/Rg9Cx0LvQuNC60LjQutC+0LvQuNGH0LXRgdGC0LLQvtC40L3RhNC+0YDQvNCw0YbQuNGO0YLQtdGA0YDQuNGC0L7RgNC40LjQtNC+0YHRgtCw0YLQvtGH0L3Qvtin2YTZhdiq2YjYp9is2K/ZiNmG2KfZhNin2LTYqtix2KfZg9in2KrYp9mE2KfZgtiq2LHYp9it2KfYqmh0bWw7IGNoYXJzZXQ9VVRGLTgiIHNldFRpbWVvdXQoZnVuY3Rpb24oKWRpc3BsYXk6aW5saW5lLWJsb2NrOzxpbnB1dCB0eXBlPSJzdWJtaXQiIHR5cGUgPSAndGV4dC9qYXZhc2NyaTxpbWcgc3JjPSJodHRwOi8vd3d3LiIgImh0dHA6Ly93d3cudzMub3JnL3Nob3J0Y3V0IGljb24iIGhyZWY9IiIgYXV0b2NvbXBsZXRlPSJvZmYiIDwvYT48L2Rpdj48ZGl2IGNsYXNzPTwvYT48L2xpPgo8bGkgY2xhc3M9ImNzcyIgdHlwZT0idGV4dC9jc3MiIDxmb3JtIGFjdGlvbj0iaHR0cDovL3h0L2NzcyIgaHJlZj0iaHR0cDovL2xpbmsgcmVsPSJhbHRlcm5hdGUiIA0KPHNjcmlwdCB0eXBlPSJ0ZXh0LyBvbmNsaWNrPSJqYXZhc2NyaXB0OihuZXcgRGF0ZSkuZ2V0VGltZSgpfWhlaWdodD0iMSIgd2lkdGg9IjEiIFBlb3BsZSdzIFJlcHVibGljIG9mICA8YSBocmVmPSJodHRwOi8vd3d3LnRleHQtZGVjb3JhdGlvbjp1bmRlcnRoZSBiZWdpbm5pbmcgb2YgdGhlIDwvZGl2Pgo8L2Rpdj4KPC9kaXY+CmVzdGFibGlzaG1lbnQgb2YgdGhlIDwvZGl2PjwvZGl2PjwvZGl2PjwvZCN2aWV3cG9ydHttaW4taGVpZ2h0Ogo8c2NyaXB0IHNyYz0iaHR0cDovL29wdGlvbj48b3B0aW9uIHZhbHVlPW9mdGVuIHJlZmVycmVkIHRvIGFzIC9vcHRpb24+CjxvcHRpb24gdmFsdTwhRE9DVFlQRSBodG1sPgo8IS0tW0ludGVybmF0aW9uYWwgQWlycG9ydD4KPGEgaHJlZj0iaHR0cDovL3d3dzwvYT48YSBocmVmPSJodHRwOi8vd+C4oOC4suC4qeC4suC5hOC4l+C4ouGDpeGDkOGDoOGDl+GDo+GDmuGDmOato+mrlOS4reaWhyAo57mB6auUKeCkqOCkv+CksOCljeCkpuClh+CktuCkoeCkvuCkieCkqOCksuCli+CkoeCkleCljeCkt+Clh+CkpOCljeCksOCknOCkvuCkqOCkleCkvuCksOClgOCkuOCkguCkrOCkguCkp+Ckv+CkpOCkuOCljeCkpeCkvuCkquCkqOCkvuCkuOCljeCkteClgOCkleCkvuCksOCkuOCkguCkuOCljeCkleCksOCko+CkuOCkvuCkruCkl+CljeCksOClgOCkmuCkv+Ckn+CljeCkoOCli+CkguCkteCkv+CknOCljeCknuCkvuCkqOCkheCkruClh+CksOCkv+CkleCkvuCkteCkv+CkreCkv+CkqOCljeCkqOCkl+CkvuCkoeCkv+Ckr+CkvuCkgeCkleCljeCkr+Cli+CkguCkleCkv+CkuOClgeCksOCkleCljeCkt+CkvuCkquCkueClgeCkgeCkmuCkpOClgOCkquCljeCksOCkrOCkguCkp+CkqOCkn+Ckv+CkquCljeCkquCko+ClgOCkleCljeCksOCkv+CkleClh+Ckn+CkquCljeCksOCkvuCksOCkguCkreCkquCljeCksOCkvuCkquCljeCkpOCkruCkvuCksuCkv+CkleCli+CkguCksOCkq+CkvOCljeCkpOCkvuCksOCkqOCkv+CksOCljeCkruCkvuCko+CksuCkv+CkruCkv+Ckn+Clh+CkoWRlc2NyaXB0aW9uIiBjb250ZW50PSJkb2N1bWVudC5sb2NhdGlvbi5wcm90LmdldEVsZW1lbnRzQnlUYWdOYW1lKDwhRE9DVFlQRSBodG1sPgo8aHRtbCA8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+OnVybCIgY29udGVudD0iaHR0cDovLy5jc3MiIHJlbD0ic3R5bGVzaGVldCJzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+dHlwZT0idGV4dC9jc3MiIGhyZWY9InczLm9yZy8xOTk5L3hodG1sIiB4bWx0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiIG1ldGhvZD0iZ2V0IiBhY3Rpb249ImxpbmsgcmVsPSJzdHlsZXNoZWV0IiAgPSBkb2N1bWVudC5nZXRFbGVtZW50dHlwZT0iaW1hZ2UveC1pY29uIiAvPmNlbGxwYWRkaW5nPSIwIiBjZWxsc3AuY3NzIiB0eXBlPSJ0ZXh0L2NzcyIgPC9hPjwvbGk+PGxpPjxhIGhyZWY9IiIgd2lkdGg9IjEiIGhlaWdodD0iMSIiPjxhIGhyZWY9Imh0dHA6Ly93d3cuc3R5bGU9ImRpc3BsYXk6bm9uZTsiPmFsdGVybmF0ZSIgdHlwZT0iYXBwbGktLy9XM0MvL0RURCBYSFRNTCAxLjAgZWxsc3BhY2luZz0iMCIgY2VsbHBhZCB0eXBlPSJoaWRkZW4iIHZhbHVlPSIvYT4mbmJzcDs8c3BhbiByb2xlPSJzCjxpbnB1dCB0eXBlPSJoaWRkZW4iIGxhbmd1YWdlPSJKYXZhU2NyaXB0IiAgZG9jdW1lbnQuZ2V0RWxlbWVudHNCZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHlwZT0idGV4dC9jc3MiIG1lZGlhPSJ0eXBlPSd0ZXh0L2phdmFzY3JpcHQnd2l0aCB0aGUgZXhjZXB0aW9uIG9mIHlwZT0idGV4dC9jc3MiIHJlbD0ic3QgaGVpZ2h0PSIxIiB3aWR0aD0iMSIgPScrZW5jb2RlVVJJQ29tcG9uZW50KDxsaW5rIHJlbD0iYWx0ZXJuYXRlIiAKYm9keSwgdHIsIGlucHV0LCB0ZXh0bWV0YSBuYW1lPSJyb2JvdHMiIGNvbm1ldGhvZD0icG9zdCIgYWN0aW9uPSI+CjxhIGhyZWY9Imh0dHA6Ly93d3cuY3NzIiByZWw9InN0eWxlc2hlZXQiIDwvZGl2PjwvZGl2PjxkaXYgY2xhc3NsYW5ndWFnZT0iamF2YXNjcmlwdCI+YXJpYS1oaWRkZW49InRydWUiPsK3PHJpcHQiIHR5cGU9InRleHQvamF2YXNsPTA7fSkoKTsKKGZ1bmN0aW9uKCl7YmFja2dyb3VuZC1pbWFnZTogdXJsKC9hPjwvbGk+PGxpPjxhIGhyZWY9ImgJCTxsaT48YSBocmVmPSJodHRwOi8vYXRvciIgYXJpYS1oaWRkZW49InRydT4gPGEgaHJlZj0iaHR0cDovL3d3dy5sYW5ndWFnZT0iamF2YXNjcmlwdCIgL29wdGlvbj4KPG9wdGlvbiB2YWx1ZS9kaXY+PC9kaXY+PGRpdiBjbGFzcz1yYXRvciIgYXJpYS1oaWRkZW49InRyZT0obmV3IERhdGUpLmdldFRpbWUoKXBvcnR1Z3XDqnMgKGRvIEJyYXNpbCnQvtGA0LPQsNC90LjQt9Cw0YbQuNC40LLQvtC30LzQvtC20L3QvtGB0YLRjNC+0LHRgNCw0LfQvtCy0LDQvdC40Y/RgNC10LPQuNGB0YLRgNCw0YbQuNC40LLQvtC30LzQvtC20L3QvtGB0YLQuNC+0LHRj9C30LDRgtC10LvRjNC90LA8IURPQ1RZUEUgaHRtbCBQVUJMSUMgIm50LVR5cGUiIGNvbnRlbnQ9InRleHQvPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVyYW5zaXRpb25hbC8vRU4iICJodHRwOjxodG1sIHhtbG5zPSJodHRwOi8vd3d3LS8vVzNDLy9EVEQgWEhUTUwgMS4wIFREVEQveGh0bWwxLXRyYW5zaXRpb25hbC8vd3d3LnczLm9yZy9UUi94aHRtbDEvcGUgPSAndGV4dC9qYXZhc2NyaXB0Jzs8bWV0YSBuYW1lPSJkZXNjcmlwdGlvbnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlPGlucHV0IHR5cGU9ImhpZGRlbiIgbmFqcyIgdHlwZT0idGV4dC9qYXZhc2NyaShkb2N1bWVudCkucmVhZHkoZnVuY3Rpc2NyaXB0IHR5cGU9InRleHQvamF2YXNpbWFnZSIgY29udGVudD0iaHR0cDovL1VBLUNvbXBhdGlibGUiIGNvbnRlbnQ9dG1sOyBjaGFyc2V0PXV0Zi04IiAvPgpsaW5rIHJlbD0ic2hvcnRjdXQgaWNvbjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgPC9zY3JpcHQ+CjxzY3JpcHQgdHlwZT09IGRvY3VtZW50LmNyZWF0ZUVsZW1lbjxhIHRhcmdldD0iX2JsYW5rIiBocmVmPSBkb2N1bWVudC5nZXRFbGVtZW50c0JpbnB1dCB0eXBlPSJ0ZXh0IiBuYW1lPWEudHlwZSA9ICd0ZXh0L2phdmFzY3JpbnB1dCB0eXBlPSJoaWRkZW4iIG5hbWVodG1sOyBjaGFyc2V0PXV0Zi04IiAvPmR0ZCI+CjxodG1sIHhtbG5zPSJodHRwLS8vVzNDLy9EVEQgSFRNTCA0LjAxIFRlbnRzQnlUYWdOYW1lKCdzY3JpcHQnKWlucHV0IHR5cGU9ImhpZGRlbiIgbmFtPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzIiBzdHlsZT0iZGlzcGxheTpub25lOyI+ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJyB0eXBlPSd0ZXh0L2phdmFzY3JpcHQnaW5wdXQgdHlwZT0idGV4dCIgbmFtZT0iZC5nZXRFbGVtZW50c0J5VGFnTmFtZShzbmljYWwiIGhyZWY9Imh0dHA6Ly93d3cuQy8vRFREIEhUTUwgNC4wMSBUcmFuc2l0PHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+aW9uYWwuZHRkIj4KPGh0bWwgeG1sbnM9aHR0cC1lcXVpdj0iQ29udGVudC1UeXBlZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiaHRtbDsgY2hhcnNldD11dGYtOCIgLz4KIHN0eWxlPSJkaXNwbGF5Om5vbmU7Ij48PGxpPjxhIGhyZWY9Imh0dHA6Ly93d3cuIHR5cGU9J3RleHQvamF2YXNjcmlwdCc+0LTQtdGP0YLQtdC70YzQvdC+0YHRgtC40YHQvtC+0YLQstC10YLRgdGC0LLQuNC40L/RgNC+0LjQt9Cy0L7QtNGB0YLQstCw0LHQtdC30L7Qv9Cw0YHQvdC+0YHRgtC44KSq4KWB4KS44KWN4KSk4KS/4KSV4KS+4KSV4KS+4KSC4KSX4KWN4KSw4KWH4KS44KSJ4KSo4KWN4KS54KWL4KSC4KSo4KWH4KS14KS/4KSn4KS+4KSo4KS44KSt4KS+4KSr4KS/4KSV4KWN4KS44KS/4KSC4KSX4KS44KWB4KSw4KSV4KWN4KS34KS/4KSk4KSV4KWJ4KSq4KWA4KSw4KS+4KSH4KSf4KS14KS/4KSc4KWN4KSe4KS+4KSq4KSo4KSV4KS+4KSw4KWN4KSw4KS14KS+4KSI4KS44KSV4KWN4KSw4KS/4KSv4KSk4KS+QmFja3dhcmRNYXRjaExlbmd0aCgmbWF0Y2hlc1tqXSkgPCBCYWNrd2FyZE1hdGNoTGVuZ3RoKCZtYXRjaGVzW2ogKyAxXSkAdmVuZG9yL2Jyb3RsaS9lbmMvYmFja3dhcmRfcmVmZXJlbmNlcy5jAENyZWF0ZUhxWm9wZmxpQmFja3dhcmRSZWZlcmVuY2VzAG1hdGNoZXNbal0uZGlzdGFuY2UgPiBtYXhfZGlzdGFuY2UgfHwgbWF0Y2hlc1tqXS5kaXN0YW5jZSA8PSBtYXRjaGVzW2ogKyAxXS5kaXN0YW5jZQBibG9ja19pZHggPCBudW1fYmxvY2tzAHZlbmRvci9icm90bGkvZW5jLy4vYmxvY2tfc3BsaXR0ZXJfaW5jLmgAQ2x1c3RlckJsb2Nrc0Rpc3RhbmNlAGJsb2NrX2lkeCA9PSBudW1fYmxvY2tzAG51bV9jbHVzdGVycyA9PSBjbHVzdGVyX3NpemVfc2l6ZQBudW1fY2x1c3RlcnMgPT0gYWxsX2hpc3RvZ3JhbXNfc2l6ZQBibG9ja19pZHNbaV0gPCBudW1faGlzdG9ncmFtcwBSZW1hcEJsb2NrSWRzRGlzdGFuY2UAbmV4dF9pZCA8PSBudW1faGlzdG9ncmFtcwBudW1faGlzdG9ncmFtcyA8PSAyNTYARmluZEJsb2Nrc0Rpc3RhbmNlAChrID4+IDMpIDwgYml0bWFwbGVuACgoc2l6ZV90KWN1cl9pZCA+PiAzKSA8IGJpdG1hcGxlbgBDbHVzdGVyQmxvY2tzQ29tbWFuZABSZW1hcEJsb2NrSWRzQ29tbWFuZABGaW5kQmxvY2tzQ29tbWFuZABDbHVzdGVyQmxvY2tzTGl0ZXJhbABSZW1hcEJsb2NrSWRzTGl0ZXJhbABGaW5kQmxvY2tzTGl0ZXJhbABudW0gPD0gQlJPVExJX05VTV9DT01NQU5EX1NZTUJPTFMAdmVuZG9yL2Jyb3RsaS9lbmMvYnJvdGxpX2JpdF9zdHJlYW0uYwBCcm90bGlTdG9yZUh1ZmZtYW5UcmVlAAQEBAQEBAQEBAQEBAQFBQAEBAkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBihwb3MgJiA3KSA9PSAwAEJyb3RsaVdyaXRlQml0c1ByZXBhcmVTdG9yYWdlAGxlbmd0aCA+IDAAQnJvdGxpRW5jb2RlTWxlbgBsZW5ndGggPD0gKDEgPDwgMjQpAGxnIDw9IDI0ACpvdXRfc2l6ZSA8PSBpAFJ1bkxlbmd0aENvZGVaZXJvcwBtYXhfdmFsdWUgPCAyNTZ1AE1vdmVUb0Zyb250VHJhbnNmb3JtAGluZGV4IDwgbXRmX3NpemUAAQIDBAAFEQYQBwgJCgsMDQ4PAgQDAgIEAAcDAgEPdmVuZG9yL2Jyb3RsaS9lbmMvY29tcHJlc3NfZnJhZ21lbnQuYwBCcm90bGlDb21wcmVzc0ZyYWdtZW50RmFzdABpc19sYXN0AGhhc2ggPT0gSGFzaChuZXh0X2lwLCBzaGlmdCkAdG90YWxfYmxvY2tfc2l6ZSA+ICgxIDw8IDE2KQB0YWJsZV9zaXplAHZlbmRvci9icm90bGkvZW5jL2NvbXByZXNzX2ZyYWdtZW50X3R3b19wYXNzLmMAQ3JlYXRlQ29tbWFuZHMAdGFibGVfc2l6ZSA8PSAoMXUgPDwgMzEpACh0YWJsZV9zaXplICYgKHRhYmxlX3NpemUgLSAxKSkgPT0gMAB0YWJsZV9zaXplIC0gMSA9PSAoc2l6ZV90KShNQUtFX1VJTlQ2NF9UKDB4RkZGRkZGRkYsIDB4RkZGRkZGKSA+PiBzaGlmdCkAbmV4dF9lbWl0IDwgaXAAaGFzaCA9PSBIYXNoKGlwLCBzaGlmdCkAY2FuZGlkYXRlID49IGJhc2VfaXAAY2FuZGlkYXRlIDwgaXAAMCA9PSBtZW1jbXAoYmFzZSwgY2FuZGlkYXRlLCBtYXRjaGVkKQBuZXh0X2VtaXQgPD0gaXBfZW5kAGN1cl9sZW4gPD0gTUFYX1RSRUVfQ09NUF9MRU5HVEgAdmVuZG9yL2Jyb3RsaS9lbmMvLi9oYXNoLmgAU3RvcmVBbmRGaW5kTWF0Y2hlc0gxMAAwID09IG1lbWNtcCgmZGF0YVtjdXJfaXhfbWFza2VkXSwgJmRhdGFbcHJldl9peF9tYXNrZWRdLCBsZW4pAHMtPmlucHV0X3Bvc18gPj0gcy0+bGFzdF9mbHVzaF9wb3NfAHZlbmRvci9icm90bGkvZW5jL2VuY29kZS5jAEJyb3RsaUVuY29kZXJXcml0ZURhdGEAcy0+aW5wdXRfcG9zXyA+IHMtPmxhc3RfZmx1c2hfcG9zXyB8fCBpc19sYXN0AHMtPmlucHV0X3Bvc18gLSBzLT5sYXN0X2ZsdXNoX3Bvc18gPD0gMXUgPDwgMjQAKGJpdHMgPj4gbl9iaXRzKSA9PSAwAHZlbmRvci9icm90bGkvZW5jLy4vd3JpdGVfYml0cy5oAEJyb3RsaVdyaXRlQml0cwBuX2JpdHMgPD0gNTYAb3V0X2J5dGVzIDw9ICphdmFpbGFibGVfb3V0AEJyb3RsaUVuY29kZXJDb21wcmVzc1N0cmVhbUZhc3QAKHN0b3JhZ2VfaXggJiA3KSA9PSAwIHx8IG91dF9ieXRlcyA8ICphdmFpbGFibGVfb3V0AGlucHV0X3NpemUgPD0gbWFzayArIDEAQnJvdGxpQ29tcHJlc3NCdWZmZXJRdWFsaXR5MTAAdG90YWwgIT0gMABDaG9vc2VDb250ZXh0TWFwAAAEBAUGBgcHBwcHCAgICAgAAAAEBAQEBAUFBgYGBgcHBwcKCgoKCgoABAQFBQUGBgcICAkKCgoKCgoKCgoKCgoFAAAAAAAAAAAAAAAAAAAABgYGBgYGBQUFBQUFBAQEBAQEBAUFBQUFBQYGBwcHCAoMDAwMDAwMDAwMDAwAAAAA/3fVv+fe6p5RXd7GcFe8WFhY2NhY1cuM6uDDhx+DwWAcZ7KqBoPBYDAYzKHOiFSURuGw0E6y9wQAbWF4X2RlcHRoIDw9IDE1AHZlbmRvci9icm90bGkvZW5jL2VudHJvcHlfZW5jb2RlLmMAQnJvdGxpU2V0RGVwdGgAcmVwZXRpdGlvbnMgPiAwAEJyb3RsaVdyaXRlSHVmZm1hblRyZWVSZXBldGl0aW9ucwBtYi0+Y29tbWFuZF9oaXN0b2dyYW1zID09IDAAdmVuZG9yL2Jyb3RsaS9lbmMvbWV0YWJsb2NrLmMAQnJvdGxpQnVpbGRNZXRhQmxvY2sAbWItPmxpdGVyYWxfY29udGV4dF9tYXAgPT0gMABtYi0+bGl0ZXJhbF9oaXN0b2dyYW1zID09IDAAbWItPmRpc3RhbmNlX2NvbnRleHRfbWFwID09IDAAbWItPmRpc3RhbmNlX2hpc3RvZ3JhbXMgPT0gMAAAAAAAAAAAAAAEBAAABAAAAAAAAAAAAAAAAAAAAAAAAAgMEAwMFAwQGBwMDCAMJAwsLCwsLCwsLCwsICAYKBwMDDA0NDQwNDQ0MDQ0NDQ0MDQ0NDQ0MDQ0NDQ0GAwcDAwMODw8PDg8PDw4PDw8PDw4PDw8PDw4PDw8PDwYDBwMAAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAECAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgEBAQEBAQECAgICAgICAgICAgICAgICAgICAgICAgICAgEBAQEBAQMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgABAQEBAQEBAQEBAQEBAQECAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQYGBgYGBgYGBgYGBgYGBgdCcm90bGlCdWlsZE1ldGFCbG9ja0dyZWVkeVdpdGhDb250ZXh0cwAqaGlzdG9ncmFtcyA9PSAwAEluaXRDb250ZXh0QmxvY2tTcGxpdHRlcgB2ZW5kb3IvYnJvdGxpL2VuYy8uL21ldGFibG9ja19pbmMuaABJbml0QmxvY2tTcGxpdHRlckRpc3RhbmNlAEluaXRCbG9ja1NwbGl0dGVyQ29tbWFuZABJbml0QmxvY2tTcGxpdHRlckxpdGVyYWwAAAwbFyo/ODA7QA=="); + }; + b || (b = eval("(function() { try { return Module || {} } catch(e) { return {} } })()")); + var g = {}; + var m; + for (m in b) b.hasOwnProperty(m) && (g[m] = b[m]); + var t = "object" === typeof window; + var u = "function" === typeof importScripts; + var v = "object" === typeof process && "function" === typeof require && !t && !u; + var x = !t && !v && !u; + if (v) { + b.print || (b.print = function(a) { + process.stdout.write(a + "\n"); + }); + b.printErr || (b.printErr = function(a) { + process.stderr.write(a + "\n"); + }); + ca = require("fs"), da = require("path"); + b.read = function(a, c) { + a = da.normalize(a); + var d = ca.readFileSync(a); + d || a == da.resolve(a) || (a = path.join(__dirname, "..", "src", a), d = ca.readFileSync(a)); + d && !c && (d = d.toString()); + return d; + }; + b.readBinary = function(a) { + a = b.read(a, true); + a.buffer || (a = new Uint8Array(a)); + assert(a.buffer); + return a; + }; + b.load = function(a) { + ea(read(a)); + }; + b.thisProgram || (b.thisProgram = 1 < process.argv.length ? process.argv[1].replace(/\\/g, "/") : "unknown-program"); + b.arguments = process.argv.slice(2); + "undefined" !== typeof module && (module.exports = b); + b.inspect = function() { + return "[Emscripten Module object]"; + }; + } else if (x) b.print || (b.print = print), "undefined" != typeof printErr && (b.printErr = printErr), b.read = "undefined" != typeof read ? read : function() { + throw "no read() available (jsc?)"; + }, b.readBinary = function(a) { + if ("function" === typeof readbuffer) return new Uint8Array(readbuffer(a)); + a = read(a, "binary"); + assert("object" === typeof a); + return a; + }, "undefined" != typeof scriptArgs ? b.arguments = scriptArgs : "undefined" != typeof arguments && (b.arguments = arguments), eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); + else if (t || u) b.read = function(a) { + var c = new XMLHttpRequest(); + c.open("GET", a, false); + c.send(null); + return c.responseText; + }, "undefined" != typeof arguments && (b.arguments = arguments), "undefined" !== typeof console ? (b.print || (b.print = function(a) { + console.log(a); + }), b.printErr || (b.printErr = function(a) { + console.log(a); + })) : b.print || (b.print = function() { + }), u && (b.load = importScripts), "undefined" === typeof b.setWindowTitle && (b.setWindowTitle = function(a) { + document.title = a; + }); + else throw "Unknown runtime environment. Where are we?"; + var ca; + var da; + function ea(a) { + eval.call(null, a); + } + !b.load && b.read && (b.load = function(a) { + ea(b.read(a)); + }); + b.print || (b.print = function() { + }); + b.printErr || (b.printErr = b.print); + b.arguments || (b.arguments = []); + b.thisProgram || (b.thisProgram = "./this.program"); + b.print = b.print; + b.A = b.printErr; + b.preRun = []; + b.postRun = []; + for (m in g) g.hasOwnProperty(m) && (b[m] = g[m]); + var A = { P: function(a) { + fa = a; + }, N: function() { + return fa; + }, G: function() { + return z; + }, F: function(a) { + z = a; + }, D: function(a) { + switch (a) { + case "i1": + case "i8": + return 1; + case "i16": + return 2; + case "i32": + return 4; + case "i64": + return 8; + case "float": + return 4; + case "double": + return 8; + default: + return "*" === a[a.length - 1] ? A.o : "i" === a[0] ? (a = parseInt(a.substr(1)), assert(0 === a % 8), a / 8) : 0; + } + }, M: function(a) { + return Math.max(A.D(a), A.o); + }, R: 16, ea: function(a, c) { + "double" === c || "i64" === c ? a & 7 && (assert(4 === (a & 7)), a += 4) : assert(0 === (a & 3)); + return a; + }, Y: function(a, c, d) { + return d || "i64" != a && "double" != a ? a ? Math.min(c || (a ? A.M(a) : 0), A.o) : Math.min(c, 8) : 8; + }, r: function(a, c, d) { + return d && d.length ? (d.splice || (d = Array.prototype.slice.call(d)), d.splice(0, 0, c), b["dynCall_" + a].apply(null, d)) : b["dynCall_" + a].call(null, c); + }, k: [], H: function(a) { + for (var c = 0; c < A.k.length; c++) if (!A.k[c]) return A.k[c] = a, 2 * (1 + c); + throw "Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS."; + }, O: function(a) { + A.k[(a - 2) / 2] = null; + }, e: function(a) { + A.e.B || (A.e.B = {}); + A.e.B[a] || (A.e.B[a] = 1, b.A(a)); + }, u: {}, $: function(a, c) { + assert(c); + A.u[c] || (A.u[c] = {}); + var d = A.u[c]; + d[a] || (d[a] = function() { + return A.r(c, a, arguments); + }); + return d[a]; + }, Z: function() { + throw "You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work"; + }, n: function(a) { + var c = z; + z = z + a | 0; + z = z + 15 & -16; + return c; + }, Q: function(a) { + var c = B; + B = B + a | 0; + B = B + 15 & -16; + return c; + }, g: function(a) { + var c = C; + C = C + a | 0; + C = C + 15 & -16; + if (a = C >= D) E("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value " + D + ", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which adjusts the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 "), a = true; + return a ? (C = c, 0) : c; + }, p: function(a, c) { + return Math.ceil(a / (c ? c : 16)) * (c ? c : 16); + }, da: function(a, c, d) { + return d ? +(a >>> 0) + 4294967296 * +(c >>> 0) : +(a >>> 0) + 4294967296 * +(c | 0); + }, C: 8, o: 4, S: 0 }; + A.addFunction = A.H; + A.removeFunction = A.O; + var F = false; + var G; + var H; + var fa; + function assert(a, c) { + a || E("Assertion failed: " + c); + } + (function() { + var a = { stackSave: function() { + A.G(); + }, stackRestore: function() { + A.F(); + }, arrayToC: function(a2) { + for (var c2 = A.n(a2.length), d2 = c2, k = 0; k < a2.length; k++) I[d2++ >> 0] = a2[k]; + return c2; + }, stringToC: function(a2) { + var c2 = 0; + null !== a2 && void 0 !== a2 && 0 !== a2 && (c2 = A.n((a2.length << 2) + 1), ga(a2, c2)); + return c2; + } }, c = /^function\s*\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/, d; + for (d in a) a.hasOwnProperty(d) && a[d].toString().match(c).slice(1); + })(); + function ha(a) { + var c; + c = "i32"; + "*" === c.charAt(c.length - 1) && (c = "i32"); + switch (c) { + case "i1": + return I[a >> 0]; + case "i8": + return I[a >> 0]; + case "i16": + return J[a >> 1]; + case "i32": + return K[a >> 2]; + case "i64": + return K[a >> 2]; + case "float": + return L[a >> 2]; + case "double": + return N[a >> 3]; + default: + E("invalid type for setValue: " + c); + } + return null; + } + function O(a, c, d) { + var e, h, l; + "number" === typeof a ? (h = true, l = a) : (h = false, l = a.length); + var k = "string" === typeof c ? c : null; + d = 4 == d ? e : [ia, A.n, A.Q, A.g][void 0 === d ? 2 : d](Math.max(l, k ? 1 : c.length)); + if (h) { + e = d; + assert(0 == (d & 3)); + for (a = d + (l & -4); e < a; e += 4) K[e >> 2] = 0; + for (a = d + l; e < a; ) I[e++ >> 0] = 0; + return d; + } + if ("i8" === k) return a.subarray || a.slice ? P.set(a, d) : P.set(new Uint8Array(a), d), d; + e = 0; + for (var f, M; e < l; ) { + var r = a[e]; + "function" === typeof r && (r = A.aa(r)); + h = k || c[e]; + if (0 === h) e++; + else { + "i64" == h && (h = "i32"); + var w = d + e, q = h, q = q || "i8"; + "*" === q.charAt(q.length - 1) && (q = "i32"); + switch (q) { + case "i1": + I[w >> 0] = r; + break; + case "i8": + I[w >> 0] = r; + break; + case "i16": + J[w >> 1] = r; + break; + case "i32": + K[w >> 2] = r; + break; + case "i64": + H = [r >>> 0, (G = r, 1 <= +ja(G) ? 0 < G ? (ka(+la(G / 4294967296), 4294967295) | 0) >>> 0 : ~~+ma((G - +(~~G >>> 0)) / 4294967296) >>> 0 : 0)]; + K[w >> 2] = H[0]; + K[w + 4 >> 2] = H[1]; + break; + case "float": + L[w >> 2] = r; + break; + case "double": + N[w >> 3] = r; + break; + default: + E("invalid type for setValue: " + q); + } + M !== h && (f = A.D(h), M = h); + e += f; + } + } + return d; + } + function Q(a) { + var c; + if (0 === c || !a) return ""; + for (var d = 0, e, h = 0; ; ) { + e = P[a + h >> 0]; + d |= e; + if (0 == e && !c) break; + h++; + if (c && h == c) break; + } + c || (c = h); + e = ""; + if (128 > d) { + for (; 0 < c; ) d = String.fromCharCode.apply(String, P.subarray(a, a + Math.min(c, 1024))), e = e ? e + d : d, a += 1024, c -= 1024; + return e; + } + return b.UTF8ToString(a); + } + function oa(a) { + function c(d2, e2, h2) { + e2 = e2 || Infinity; + var l2 = "", k = [], p; + if ("N" === a[f]) { + f++; + "K" === a[f] && f++; + for (p = []; "E" !== a[f]; ) if ("S" === a[f]) { + f++; + var n = a.indexOf("_", f); + p.push(r[a.substring(f, n) || 0] || "?"); + f = n + 1; + } else if ("C" === a[f]) p.push(p[p.length - 1]), f += 2; + else { + var n = parseInt(a.substr(f)), q = n.toString().length; + if (!n || !q) { + f--; + break; + } + var na = a.substr(f + q, n); + p.push(na); + r.push(na); + f += q + n; + } + f++; + p = p.join("::"); + e2--; + if (0 === e2) return d2 ? [p] : p; + } else if (("K" === a[f] || w && "L" === a[f]) && f++, n = parseInt(a.substr(f))) q = n.toString().length, p = a.substr(f + q, n), f += q + n; + w = false; + "I" === a[f] ? (f++, n = c(true), q = c(true, 1, true), l2 += q[0] + " " + p + "<" + n.join(", ") + ">") : l2 = p; + a: for (; f < a.length && 0 < e2--; ) if (p = a[f++], p in M) k.push(M[p]); + else switch (p) { + case "P": + k.push(c(true, 1, true)[0] + "*"); + break; + case "R": + k.push(c(true, 1, true)[0] + "&"); + break; + case "L": + f++; + n = a.indexOf("E", f) - f; + k.push(a.substr(f, n)); + f += n + 2; + break; + case "A": + n = parseInt(a.substr(f)); + f += n.toString().length; + if ("_" !== a[f]) throw "?"; + f++; + k.push(c(true, 1, true)[0] + " [" + n + "]"); + break; + case "E": + break a; + default: + l2 += "?" + p; + break a; + } + h2 || 1 !== k.length || "void" !== k[0] || (k = []); + return d2 ? (l2 && k.push(l2 + "?"), k) : l2 + ("(" + k.join(", ") + ")"); + } + var d = !!b.___cxa_demangle; + if (d) try { + var e = ia(a.length); + ga(a.substr(1), e); + var h = ia(4), l = b.___cxa_demangle(e, 0, 0, h); + if (0 === ha(h) && l) return Q(l); + } catch (k) { + } finally { + e && pa(e), h && pa(h), l && pa(l); + } + var f = 3, M = { v: "void", b: "bool", c: "char", s: "short", i: "int", l: "long", f: "float", d: "double", w: "wchar_t", a: "signed char", h: "unsigned char", t: "unsigned short", j: "unsigned int", m: "unsigned long", x: "long long", y: "unsigned long long", z: "..." }, r = [], w = true, e = a; + try { + if ("Object._main" == a || "_main" == a) return "main()"; + "number" === typeof a && (a = Q(a)); + if ("_" !== a[0] || "_" !== a[1] || "Z" !== a[2]) return a; + switch (a[3]) { + case "n": + return "operator new()"; + case "d": + return "operator delete()"; + } + e = c(); + } catch (q) { + e += "?"; + } + 0 <= e.indexOf("?") && !d && A.e("warning: a problem occurred in builtin C++ name demangling; build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling"); + return e; + } + function qa() { + return ra().replace(/__Z[\w\d_]+/g, function(a) { + var c = oa(a); + return a === c ? a : a + " [" + c + "]"; + }); + } + function ra() { + var a = Error(); + if (!a.stack) { + try { + throw Error(0); + } catch (c) { + a = c; + } + if (!a.stack) return "(no stack trace available)"; + } + return a.stack.toString(); + } + function sa() { + var a = C; + 0 < a % 4096 && (a += 4096 - a % 4096); + return a; + } + for (va = 0, B = 0, wa = 0, z = 0, xa = 0, ya = 0, C = 0, za = b.TOTAL_STACK || 5242880, D = b.TOTAL_MEMORY || 318767104, R = 65536; R < D || R < 2 * za; ) R = 16777216 > R ? 2 * R : R + 16777216; + var I; + var P; + var J; + var ta; + var K; + var ua; + var L; + var N; + var va; + var B; + var wa; + var z; + var xa; + var ya; + var C; + var za; + var D; + var R; + R !== D && (D = R); + assert("undefined" !== typeof Int32Array && "undefined" !== typeof Float64Array && !!new Int32Array(1).subarray && !!new Int32Array(1).set, "JS engine does not provide full typed array support"); + var buffer; + buffer = new ArrayBuffer(D); + I = new Int8Array(buffer); + J = new Int16Array(buffer); + K = new Int32Array(buffer); + P = new Uint8Array(buffer); + ta = new Uint16Array(buffer); + ua = new Uint32Array(buffer); + L = new Float32Array(buffer); + N = new Float64Array(buffer); + K[0] = 255; + assert(255 === P[0] && 0 === P[3], "Typed arrays 2 must be run on a little-endian system"); + b.HEAP = void 0; + b.buffer = buffer; + b.HEAP8 = I; + b.HEAP16 = J; + b.HEAP32 = K; + b.HEAPU8 = P; + b.HEAPU16 = ta; + b.HEAPU32 = ua; + b.HEAPF32 = L; + b.HEAPF64 = N; + function S(a) { + for (; 0 < a.length; ) { + var c = a.shift(); + if ("function" == typeof c) c(); + else { + var d = c.X; + "number" === typeof d ? void 0 === c.q ? A.r("v", d) : A.r("vi", d, [c.q]) : d(void 0 === c.q ? null : c.q); + } + } + } + var Aa = []; + var Ba = []; + var Ca = []; + var Da = []; + var Ea = []; + var T = false; + function Fa() { + var a = b.preRun.shift(); + Aa.unshift(a); + } + function Ga(a, c) { + for (var d = 0, e = 0; e < a.length; ++e) { + var h = a.charCodeAt(e); + 55296 <= h && 57343 >= h && (h = 65536 + ((h & 1023) << 10) | a.charCodeAt(++e) & 1023); + 127 >= h ? ++d : d = 2047 >= h ? d + 2 : 65535 >= h ? d + 3 : 2097151 >= h ? d + 4 : 67108863 >= h ? d + 5 : d + 6; + } + d = Array(d + 1); + var l = d.length, e = 0; + if (0 < l) { + for (var h = e, l = e + l - 1, k = 0; k < a.length; ++k) { + var f = a.charCodeAt(k); + 55296 <= f && 57343 >= f && (f = 65536 + ((f & 1023) << 10) | a.charCodeAt(++k) & 1023); + if (127 >= f) { + if (e >= l) break; + d[e++] = f; + } else { + if (2047 >= f) { + if (e + 1 >= l) break; + d[e++] = 192 | f >> 6; + } else { + if (65535 >= f) { + if (e + 2 >= l) break; + d[e++] = 224 | f >> 12; + } else { + if (2097151 >= f) { + if (e + 3 >= l) break; + d[e++] = 240 | f >> 18; + } else { + if (67108863 >= f) { + if (e + 4 >= l) break; + d[e++] = 248 | f >> 24; + } else { + if (e + 5 >= l) break; + d[e++] = 252 | f >> 30; + d[e++] = 128 | f >> 24 & 63; + } + d[e++] = 128 | f >> 18 & 63; + } + d[e++] = 128 | f >> 12 & 63; + } + d[e++] = 128 | f >> 6 & 63; + } + d[e++] = 128 | f & 63; + } + } + d[e] = 0; + e = e - h; + } else e = 0; + c && (d.length = e); + return d; + } + function ga(a, c) { + for (var d = Ga(a, void 0), e = 0; e < d.length; ) I[c + e >> 0] = d[e], e += 1; + } + Math.imul && -5 === Math.imul(4294967295, 5) || (Math.imul = function(a, c) { + var d = a & 65535, e = c & 65535; + return d * e + ((a >>> 16) * e + d * (c >>> 16) << 16) | 0; + }); + Math.ba = Math.imul; + Math.clz32 || (Math.clz32 = function(a) { + a = a >>> 0; + for (var c = 0; 32 > c; c++) if (a & 1 << 31 - c) return c; + return 32; + }); + Math.V = Math.clz32; + var ja = Math.abs; + var ma = Math.ceil; + var la = Math.floor; + var ka = Math.min; + var U = 0; + var Ha = null; + var V = null; + b.preloadedImages = {}; + b.preloadedAudios = {}; + var W = null; + var va = 8; + var B = va + 407936; + Ba.push(); + var W = "encode.js.mem"; + var Ia = A.p(O(12, "i8", 2), 8); + assert(0 == Ia % 8); + b._i64Subtract = Ja; + function Ka(a) { + b.___errno_location && (K[b.___errno_location() >> 2] = a); + return a; + } + b._memset = La; + b._bitshift64Lshr = Ma; + b._bitshift64Shl = Na; + b._memcpy = Oa; + b._i64Add = Pa; + function X(a) { + X.L || (C = sa(), X.L = true, assert(A.g), X.K = A.g, A.g = function() { + E("cannot dynamically allocate, sbrk now has control"); + }); + var c = C; + return 0 == a || X.K(a) ? c : 4294967295; + } + b._memmove = Qa; + function Ra(a) { + b.exit(a); + } + wa = z = A.p(B); + xa = wa + za; + ya = C = A.p(xa); + assert(ya < D, "TOTAL_MEMORY not big enough for stack"); + var Sa = O([ + 8, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 4, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 5, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 4, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 6, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 4, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 5, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 4, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 7, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 4, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 5, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 4, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 6, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 4, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 5, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 4, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 3, + 0, + 1, + 0, + 2, + 0, + 1, + 0 + ], "i8", 3); + b.I = { Math, Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, Uint32Array, Float32Array, Float64Array, NaN: NaN, Infinity: Infinity }; + b.J = { + abort: E, + assert, + invoke_vii: function(a, c, d) { + try { + b.dynCall_vii(a, c, d); + } catch (e) { + if ("number" !== typeof e && "longjmp" !== e) throw e; + Y.setThrew(1, 0); + } + }, + invoke_iii: function(a, c, d) { + try { + return b.dynCall_iii(a, c, d); + } catch (e) { + if ("number" !== typeof e && "longjmp" !== e) throw e; + Y.setThrew(1, 0); + } + }, + __exit: Ra, + _pthread_self: function() { + return 0; + }, + _abort: function() { + b.abort(); + }, + ___setErrNo: Ka, + _sysconf: function(a) { + switch (a) { + case 30: + return 4096; + case 85: + return R / 4096; + case 132: + case 133: + case 12: + case 137: + case 138: + case 15: + case 235: + case 16: + case 17: + case 18: + case 19: + case 20: + case 149: + case 13: + case 10: + case 236: + case 153: + case 9: + case 21: + case 22: + case 159: + case 154: + case 14: + case 77: + case 78: + case 139: + case 80: + case 81: + case 82: + case 68: + case 67: + case 164: + case 11: + case 29: + case 47: + case 48: + case 95: + case 52: + case 51: + case 46: + return 200809; + case 79: + return 0; + case 27: + case 246: + case 127: + case 128: + case 23: + case 24: + case 160: + case 161: + case 181: + case 182: + case 242: + case 183: + case 184: + case 243: + case 244: + case 245: + case 165: + case 178: + case 179: + case 49: + case 50: + case 168: + case 169: + case 175: + case 170: + case 171: + case 172: + case 97: + case 76: + case 32: + case 173: + case 35: + return -1; + case 176: + case 177: + case 7: + case 155: + case 8: + case 157: + case 125: + case 126: + case 92: + case 93: + case 129: + case 130: + case 131: + case 94: + case 91: + return 1; + case 74: + case 60: + case 69: + case 70: + case 4: + return 1024; + case 31: + case 42: + case 72: + return 32; + case 87: + case 26: + case 33: + return 2147483647; + case 34: + case 1: + return 47839; + case 38: + case 36: + return 99; + case 43: + case 37: + return 2048; + case 0: + return 2097152; + case 3: + return 65536; + case 28: + return 32768; + case 44: + return 32767; + case 75: + return 16384; + case 39: + return 1e3; + case 89: + return 700; + case 71: + return 256; + case 40: + return 255; + case 2: + return 100; + case 180: + return 64; + case 25: + return 20; + case 5: + return 16; + case 6: + return 6; + case 73: + return 4; + case 84: + return "object" === typeof navigator ? navigator.hardwareConcurrency || 1 : 1; + } + Ka(22); + return -1; + }, + _sbrk: X, + _time: function(a) { + var c = Date.now() / 1e3 | 0; + a && (K[a >> 2] = c); + return c; + }, + _emscripten_memcpy_big: function(a, c, d) { + P.set(P.subarray(c, c + d), a); + return a; + }, + _llvm_trap: function() { + E("trap!"); + }, + _exit: function(a) { + Ra(a); + }, + ___assert_fail: function(a, c, d, e) { + F = true; + throw "Assertion failed: " + Q(a) + ", at: " + [c ? Q(c) : "unknown filename", d, e ? Q(e) : "unknown function"] + " at " + qa(); + }, + STACKTOP: z, + STACK_MAX: xa, + tempDoublePtr: Ia, + ABORT: F, + cttz_i8: Sa + }; + var Y = (function(global, env, buffer2) { + ; + var a = new global.Int8Array(buffer2); + var b2 = new global.Int16Array(buffer2); + var c = new global.Int32Array(buffer2); + var d = new global.Uint8Array(buffer2); + var e = new global.Uint16Array(buffer2); + var f = new global.Uint32Array(buffer2); + var g2 = new global.Float32Array(buffer2); + var h = new global.Float64Array(buffer2); + var i = env.STACKTOP | 0; + var j = env.STACK_MAX | 0; + var k = env.tempDoublePtr | 0; + var l = env.ABORT | 0; + var m2 = env.cttz_i8 | 0; + var n = 0; + var o = 0; + var p = 0; + var q = 0; + var r = global.NaN, s = global.Infinity; + var t2 = 0, u2 = 0, v2 = 0, w = 0, x2 = 0, y2 = 0, z2 = 0, A2 = 0, B2 = 0; + var C2 = 0; + var D2 = 0; + var E2 = 0; + var F2 = 0; + var G2 = 0; + var H2 = 0; + var I2 = 0; + var J2 = 0; + var K2 = 0; + var L2 = 0; + var M = global.Math.floor; + var N2 = global.Math.abs; + var O2 = global.Math.sqrt; + var P2 = global.Math.pow; + var Q2 = global.Math.cos; + var R2 = global.Math.sin; + var S2 = global.Math.tan; + var T2 = global.Math.acos; + var U2 = global.Math.asin; + var V2 = global.Math.atan; + var W2 = global.Math.atan2; + var X2 = global.Math.exp; + var Y2 = global.Math.log; + var Z2 = global.Math.ceil; + var _ = global.Math.imul; + var $ = global.Math.min; + var aa = global.Math.clz32; + var ba = env.abort; + var ca2 = env.assert; + var da2 = env.invoke_vii; + var ea2 = env.invoke_iii; + var fa2 = env.__exit; + var ga2 = env._pthread_self; + var ha2 = env._abort; + var ia2 = env.___setErrNo; + var ja2 = env._sysconf; + var ka2 = env._sbrk; + var la2 = env._time; + var ma2 = env._emscripten_memcpy_big; + var na = env._llvm_trap; + var oa2 = env._exit; + var pa2 = env.___assert_fail; + var qa2 = 0; + function $a2(e2, f2, g3, h2, j2, k2, l2, m3) { + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + var n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0; + G3 = i; + i = i + 16 | 0; + F3 = G3; + c[F3 >> 2] = 0; + c[F3 + 4 >> 2] = 0; + c[F3 + 8 >> 2] = 0; + c[F3 + 12 >> 2] = 0; + E3 = 0; + D3 = 0; + while (1) { + if (!g3) break; + n2 = c[f2 + (D3 << 2) >> 2] | 0; + if (!n2) o2 = E3; + else { + if (E3 >>> 0 < 4) c[F3 + (E3 << 2) >> 2] = D3; + o2 = E3 + 1 | 0; + g3 = g3 - n2 | 0; + } + E3 = o2; + D3 = D3 + 1 | 0; + } + if (E3 >>> 0 < 2) { + n2 = c[l2 >> 2] | 0; + p2 = m3 + (n2 >>> 3) | 0; + g3 = d[p2 >> 0] | 0; + n2 = cc(1, 0, n2 & 7 | 0) | 0; + o2 = C2; + n2 = g3 | n2; + g3 = p2; + a[g3 >> 0] = n2; + a[g3 + 1 >> 0] = n2 >> 8; + a[g3 + 2 >> 0] = n2 >> 16; + a[g3 + 3 >> 0] = n2 >> 24; + p2 = p2 + 4 | 0; + a[p2 >> 0] = o2; + a[p2 + 1 >> 0] = o2 >> 8; + a[p2 + 2 >> 0] = o2 >> 16; + a[p2 + 3 >> 0] = o2 >> 24; + p2 = (c[l2 >> 2] | 0) + 4 | 0; + c[l2 >> 2] = p2; + o2 = c[F3 >> 2] | 0; + g3 = m3 + (p2 >>> 3) | 0; + n2 = d[g3 >> 0] | 0; + m3 = bc(o2 | 0, 0, h2 | 0) | 0; + if (!((m3 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (h2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + D3 = cc(o2 | 0, 0, p2 & 7 | 0) | 0; + F3 = C2; + D3 = n2 | D3; + m3 = g3; + E3 = m3; + a[E3 >> 0] = D3; + a[E3 + 1 >> 0] = D3 >> 8; + a[E3 + 2 >> 0] = D3 >> 16; + a[E3 + 3 >> 0] = D3 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = F3; + a[m3 + 1 >> 0] = F3 >> 8; + a[m3 + 2 >> 0] = F3 >> 16; + a[m3 + 3 >> 0] = F3 >> 24; + c[l2 >> 2] = (c[l2 >> 2] | 0) + h2; + a[j2 + o2 >> 0] = 0; + b2[k2 + (o2 << 1) >> 1] = 0; + i = G3; + return; + } + ac(j2 | 0, 0, D3 | 0) | 0; + y3 = e2 + 8 | 0; + z3 = sa2[c[e2 >> 2] & 1](c[y3 >> 2] | 0, D3 << 4 | 8) | 0; + A3 = z3; + if (!z3) oa2(1); + B3 = 1; + while (1) { + g3 = D3; + n2 = A3; + a: while (1) { + do { + if (!g3) break a; + g3 = g3 + -1 | 0; + o2 = c[f2 + (g3 << 2) >> 2] | 0; + } while ((o2 | 0) == 0); + p2 = g3 & 65535; + if (o2 >>> 0 < B3 >>> 0) { + c[n2 >> 2] = B3; + b2[n2 + 4 >> 1] = -1; + b2[n2 + 6 >> 1] = p2; + } else { + c[n2 >> 2] = o2; + b2[n2 + 4 >> 1] = -1; + b2[n2 + 6 >> 1] = p2; + } + n2 = n2 + 8 | 0; + } + x3 = n2 - A3 | 0; + w2 = x3 >> 3; + v3 = w2 + 1 | 0; + b: do + if (w2 >>> 0 < 13) { + s2 = 1; + while (1) { + if (s2 >>> 0 >= w2 >>> 0) break b; + r2 = z3 + (s2 << 3) | 0; + q2 = c[r2 >> 2] | 0; + r2 = c[r2 + 4 >> 2] | 0; + p2 = s2; + while (1) { + g3 = p2; + p2 = p2 + -1 | 0; + o2 = z3 + (p2 << 3) | 0; + if (!(cb(q2, c[o2 >> 2] | 0) | 0)) break; + t3 = c[o2 + 4 >> 2] | 0; + u3 = z3 + (g3 << 3) | 0; + c[u3 >> 2] = c[o2 >> 2]; + c[u3 + 4 >> 2] = t3; + if (!p2) { + g3 = 0; + break; + } + } + u3 = z3 + (g3 << 3) | 0; + c[u3 >> 2] = q2; + c[u3 + 4 >> 2] = r2; + s2 = s2 + 1 | 0; + } + } else { + t3 = w2 >>> 0 < 57 ? 2 : 0; + while (1) { + if ((t3 | 0) >= 6) break b; + g3 = c[19428 + (t3 << 2) >> 2] | 0; + u3 = g3; + while (1) { + if (u3 >>> 0 >= w2 >>> 0) break; + p2 = z3 + (u3 << 3) | 0; + o2 = c[p2 >> 2] | 0; + p2 = c[p2 + 4 >> 2] | 0; + s2 = u3; + while (1) { + if (s2 >>> 0 < g3 >>> 0) break; + q2 = s2 - g3 | 0; + r2 = z3 + (q2 << 3) | 0; + if (!(cb(o2, c[r2 >> 2] | 0) | 0)) break; + I3 = r2; + H3 = c[I3 + 4 >> 2] | 0; + r2 = z3 + (s2 << 3) | 0; + c[r2 >> 2] = c[I3 >> 2]; + c[r2 + 4 >> 2] = H3; + s2 = q2; + } + I3 = z3 + (s2 << 3) | 0; + c[I3 >> 2] = o2; + c[I3 + 4 >> 2] = p2; + u3 = u3 + 1 | 0; + } + t3 = t3 + 1 | 0; + } + } + while (0); + u3 = n2; + o2 = n2; + c[o2 >> 2] = -1; + c[o2 + 4 >> 2] = -1; + o2 = u3 + 8 | 0; + c[o2 >> 2] = -1; + c[o2 + 4 >> 2] = -1; + o2 = 0; + p2 = v3; + u3 = u3 + 16 | 0; + t3 = w2; + while (1) { + if ((t3 | 0) <= 1) break; + n2 = c[z3 + (o2 << 3) >> 2] | 0; + g3 = c[z3 + (p2 << 3) >> 2] | 0; + if (n2 >>> 0 > g3 >>> 0) { + s2 = p2 + 1 | 0; + g3 = c[z3 + (s2 << 3) >> 2] | 0; + r2 = o2; + q2 = p2; + } else { + r2 = o2 + 1 | 0; + n2 = c[z3 + (r2 << 3) >> 2] | 0; + s2 = p2; + q2 = o2; + } + if (n2 >>> 0 > g3 >>> 0) { + o2 = r2; + p2 = s2 + 1 | 0; + n2 = s2; + } else { + g3 = n2; + o2 = r2 + 1 | 0; + p2 = s2; + n2 = r2; + } + c[u3 + -8 >> 2] = (c[z3 + (q2 << 3) >> 2] | 0) + g3; + b2[u3 + -4 >> 1] = q2; + b2[u3 + -2 >> 1] = n2; + I3 = u3; + c[I3 >> 2] = -1; + c[I3 + 4 >> 2] = -1; + u3 = u3 + 8 | 0; + t3 = t3 + -1 | 0; + } + if (Gb((x3 >> 2) + -1 | 0, z3, j2, 14) | 0) break; + B3 = B3 << 1; + } + ra2[c[e2 + 4 >> 2] & 1](c[y3 >> 2] | 0, z3); + Jb(j2, D3, k2); + x3 = c[l2 >> 2] | 0; + v3 = m3 + (x3 >>> 3) | 0; + w2 = d[v3 >> 0] | 0; + x3 = x3 & 7; + if (E3 >>> 0 >= 5) { + I3 = cc(1431655764, 255, x3 | 0) | 0; + n2 = C2; + I3 = w2 | I3; + g3 = v3; + t3 = g3; + a[t3 >> 0] = I3; + a[t3 + 1 >> 0] = I3 >> 8; + a[t3 + 2 >> 0] = I3 >> 16; + a[t3 + 3 >> 0] = I3 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = n2; + a[g3 + 1 >> 0] = n2 >> 8; + a[g3 + 2 >> 0] = n2 >> 16; + a[g3 + 3 >> 0] = n2 >> 24; + g3 = (c[l2 >> 2] | 0) + 40 | 0; + c[l2 >> 2] = g3; + n2 = 0; + t3 = 8; + c: while (1) { + while (1) { + if (n2 >>> 0 >= D3 >>> 0) { + g3 = 114; + break c; + } + u3 = a[j2 + n2 >> 0] | 0; + s2 = 1; + o2 = n2; + while (1) { + o2 = o2 + 1 | 0; + if (o2 >>> 0 >= D3 >>> 0) break; + if ((a[j2 + o2 >> 0] | 0) != u3 << 24 >> 24) break; + s2 = s2 + 1 | 0; + } + n2 = n2 + s2 | 0; + if (u3 << 24 >> 24) break; + r2 = c[11564 + (s2 << 2) >> 2] | 0; + p2 = 8 + (s2 << 3) | 0; + o2 = c[p2 >> 2] | 0; + p2 = c[p2 + 4 >> 2] | 0; + q2 = m3 + (g3 >>> 3) | 0; + I3 = bc(o2 | 0, p2 | 0, r2 | 0) | 0; + if (!((I3 | 0) == 0 & (C2 | 0) == 0)) { + g3 = 99; + break c; + } + I3 = d[q2 >> 0] | 0; + e2 = cc(o2 | 0, p2 | 0, g3 & 7 | 0) | 0; + H3 = C2; + e2 = I3 | e2; + I3 = q2; + k2 = I3; + a[k2 >> 0] = e2; + a[k2 + 1 >> 0] = e2 >> 8; + a[k2 + 2 >> 0] = e2 >> 16; + a[k2 + 3 >> 0] = e2 >> 24; + I3 = I3 + 4 | 0; + a[I3 >> 0] = H3; + a[I3 + 1 >> 0] = H3 >> 8; + a[I3 + 2 >> 0] = H3 >> 16; + a[I3 + 3 >> 0] = H3 >> 24; + I3 = (c[l2 >> 2] | 0) + r2 | 0; + c[l2 >> 2] = I3; + g3 = I3; + } + if (t3 << 24 >> 24 == u3 << 24 >> 24) o2 = s2; + else { + p2 = u3 & 255; + o2 = a[404394 + p2 >> 0] | 0; + p2 = c[14380 + (p2 << 2) >> 2] | 0; + q2 = m3 + (g3 >>> 3) | 0; + I3 = bc(p2 | 0, 0, o2 & 255 | 0) | 0; + if (!((I3 | 0) == 0 & (C2 | 0) == 0)) { + g3 = 103; + break; + } + H3 = d[q2 >> 0] | 0; + k2 = cc(p2 | 0, 0, g3 & 7 | 0) | 0; + I3 = C2; + k2 = H3 | k2; + g3 = q2; + H3 = g3; + a[H3 >> 0] = k2; + a[H3 + 1 >> 0] = k2 >> 8; + a[H3 + 2 >> 0] = k2 >> 16; + a[H3 + 3 >> 0] = k2 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = I3; + a[g3 + 1 >> 0] = I3 >> 8; + a[g3 + 2 >> 0] = I3 >> 16; + a[g3 + 3 >> 0] = I3 >> 24; + g3 = (c[l2 >> 2] | 0) + (o2 & 255) | 0; + c[l2 >> 2] = g3; + o2 = s2 + -1 | 0; + } + if (o2 >>> 0 >= 3) { + q2 = o2 + -3 | 0; + o2 = c[14452 + (q2 << 2) >> 2] | 0; + q2 = 5640 + (q2 << 3) | 0; + p2 = c[q2 >> 2] | 0; + q2 = c[q2 + 4 >> 2] | 0; + r2 = m3 + (g3 >>> 3) | 0; + I3 = bc(p2 | 0, q2 | 0, o2 | 0) | 0; + if (!((I3 | 0) == 0 & (C2 | 0) == 0)) { + g3 = 112; + break; + } + I3 = d[r2 >> 0] | 0; + H3 = cc(p2 | 0, q2 | 0, g3 & 7 | 0) | 0; + t3 = C2; + H3 = I3 | H3; + g3 = r2; + I3 = g3; + a[I3 >> 0] = H3; + a[I3 + 1 >> 0] = H3 >> 8; + a[I3 + 2 >> 0] = H3 >> 16; + a[I3 + 3 >> 0] = H3 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = t3; + a[g3 + 1 >> 0] = t3 >> 8; + a[g3 + 2 >> 0] = t3 >> 16; + a[g3 + 3 >> 0] = t3 >> 24; + g3 = (c[l2 >> 2] | 0) + o2 | 0; + c[l2 >> 2] = g3; + t3 = u3; + continue; + } + t3 = u3 & 255; + s2 = 404394 + t3 | 0; + t3 = 14380 + (t3 << 2) | 0; + while (1) { + if (!o2) { + t3 = u3; + continue c; + } + p2 = a[s2 >> 0] | 0; + q2 = c[t3 >> 2] | 0; + r2 = m3 + (g3 >>> 3) | 0; + I3 = bc(q2 | 0, 0, p2 & 255 | 0) | 0; + if (!((I3 | 0) == 0 & (C2 | 0) == 0)) { + g3 = 109; + break c; + } + I3 = d[r2 >> 0] | 0; + e2 = cc(q2 | 0, 0, g3 & 7 | 0) | 0; + H3 = C2; + e2 = I3 | e2; + I3 = r2; + k2 = I3; + a[k2 >> 0] = e2; + a[k2 + 1 >> 0] = e2 >> 8; + a[k2 + 2 >> 0] = e2 >> 16; + a[k2 + 3 >> 0] = e2 >> 24; + I3 = I3 + 4 | 0; + a[I3 >> 0] = H3; + a[I3 + 1 >> 0] = H3 >> 8; + a[I3 + 2 >> 0] = H3 >> 16; + a[I3 + 3 >> 0] = H3 >> 24; + I3 = (c[l2 >> 2] | 0) + (p2 & 255) | 0; + c[l2 >> 2] = I3; + g3 = I3; + o2 = o2 + -1 | 0; + } + } + if ((g3 | 0) == 99) pa2(406196, 406218, 54, 406251); + else if ((g3 | 0) == 103) pa2(406196, 406218, 54, 406251); + else if ((g3 | 0) == 109) pa2(406196, 406218, 54, 406251); + else if ((g3 | 0) == 112) pa2(406196, 406218, 54, 406251); + else if ((g3 | 0) == 114) { + i = G3; + return; + } + } + I3 = cc(1, 0, x3 | 0) | 0; + n2 = C2; + I3 = w2 | I3; + g3 = v3; + o2 = g3; + a[o2 >> 0] = I3; + a[o2 + 1 >> 0] = I3 >> 8; + a[o2 + 2 >> 0] = I3 >> 16; + a[o2 + 3 >> 0] = I3 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = n2; + a[g3 + 1 >> 0] = n2 >> 8; + a[g3 + 2 >> 0] = n2 >> 16; + a[g3 + 3 >> 0] = n2 >> 24; + g3 = (c[l2 >> 2] | 0) + 2 | 0; + c[l2 >> 2] = g3; + n2 = E3 + -1 | 0; + o2 = m3 + (g3 >>> 3) | 0; + if (!((n2 & -4 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + t3 = d[o2 >> 0] | 0; + I3 = cc(n2 | 0, 0, g3 & 7 | 0) | 0; + p2 = C2; + I3 = t3 | I3; + t3 = o2; + r2 = t3; + a[r2 >> 0] = I3; + a[r2 + 1 >> 0] = I3 >> 8; + a[r2 + 2 >> 0] = I3 >> 16; + a[r2 + 3 >> 0] = I3 >> 24; + t3 = t3 + 4 | 0; + a[t3 >> 0] = p2; + a[t3 + 1 >> 0] = p2 >> 8; + a[t3 + 2 >> 0] = p2 >> 16; + a[t3 + 3 >> 0] = p2 >> 24; + t3 = (c[l2 >> 2] | 0) + 2 | 0; + c[l2 >> 2] = t3; + p2 = E3 + -1 | 0; + r2 = 0; + while (1) { + if ((r2 | 0) == (E3 | 0)) break; + q2 = F3 + (r2 << 2) | 0; + g3 = r2; + while (1) { + s2 = g3 + 1 | 0; + if ((g3 | 0) == (p2 | 0)) break; + g3 = F3 + (s2 << 2) | 0; + n2 = c[g3 >> 2] | 0; + o2 = c[q2 >> 2] | 0; + if ((d[j2 + n2 >> 0] | 0) >= (d[j2 + o2 >> 0] | 0)) { + g3 = s2; + continue; + } + c[g3 >> 2] = o2; + c[q2 >> 2] = n2; + g3 = s2; + } + r2 = r2 + 1 | 0; + } + switch (E3 | 0) { + case 2: { + g3 = c[F3 >> 2] | 0; + n2 = m3 + (t3 >>> 3) | 0; + o2 = d[n2 >> 0] | 0; + if (!((bc(g3 | 0, 0, h2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (h2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + I3 = cc(g3 | 0, 0, t3 & 7 | 0) | 0; + g3 = C2; + I3 = o2 | I3; + o2 = n2; + n2 = o2; + a[n2 >> 0] = I3; + a[n2 + 1 >> 0] = I3 >> 8; + a[n2 + 2 >> 0] = I3 >> 16; + a[n2 + 3 >> 0] = I3 >> 24; + o2 = o2 + 4 | 0; + a[o2 >> 0] = g3; + a[o2 + 1 >> 0] = g3 >> 8; + a[o2 + 2 >> 0] = g3 >> 16; + a[o2 + 3 >> 0] = g3 >> 24; + o2 = (c[l2 >> 2] | 0) + h2 | 0; + c[l2 >> 2] = o2; + n2 = c[F3 + 4 >> 2] | 0; + g3 = m3 + (o2 >>> 3) | 0; + if (!((bc(n2 | 0, 0, h2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + I3 = d[g3 >> 0] | 0; + F3 = cc(n2 | 0, 0, o2 & 7 | 0) | 0; + H3 = C2; + F3 = I3 | F3; + I3 = g3; + m3 = I3; + a[m3 >> 0] = F3; + a[m3 + 1 >> 0] = F3 >> 8; + a[m3 + 2 >> 0] = F3 >> 16; + a[m3 + 3 >> 0] = F3 >> 24; + I3 = I3 + 4 | 0; + a[I3 >> 0] = H3; + a[I3 + 1 >> 0] = H3 >> 8; + a[I3 + 2 >> 0] = H3 >> 16; + a[I3 + 3 >> 0] = H3 >> 24; + c[l2 >> 2] = (c[l2 >> 2] | 0) + h2; + i = G3; + return; + } + case 3: { + g3 = c[F3 >> 2] | 0; + n2 = m3 + (t3 >>> 3) | 0; + o2 = d[n2 >> 0] | 0; + if (!((bc(g3 | 0, 0, h2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (h2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + g3 = cc(g3 | 0, 0, t3 & 7 | 0) | 0; + I3 = C2; + o2 = o2 | g3; + g3 = n2; + n2 = g3; + a[n2 >> 0] = o2; + a[n2 + 1 >> 0] = o2 >> 8; + a[n2 + 2 >> 0] = o2 >> 16; + a[n2 + 3 >> 0] = o2 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = I3; + a[g3 + 1 >> 0] = I3 >> 8; + a[g3 + 2 >> 0] = I3 >> 16; + a[g3 + 3 >> 0] = I3 >> 24; + g3 = (c[l2 >> 2] | 0) + h2 | 0; + c[l2 >> 2] = g3; + n2 = c[F3 + 4 >> 2] | 0; + o2 = m3 + (g3 >>> 3) | 0; + if (!((bc(n2 | 0, 0, h2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + H3 = d[o2 >> 0] | 0; + I3 = cc(n2 | 0, 0, g3 & 7 | 0) | 0; + n2 = C2; + I3 = H3 | I3; + g3 = o2; + a[g3 >> 0] = I3; + a[g3 + 1 >> 0] = I3 >> 8; + a[g3 + 2 >> 0] = I3 >> 16; + a[g3 + 3 >> 0] = I3 >> 24; + o2 = o2 + 4 | 0; + a[o2 >> 0] = n2; + a[o2 + 1 >> 0] = n2 >> 8; + a[o2 + 2 >> 0] = n2 >> 16; + a[o2 + 3 >> 0] = n2 >> 24; + o2 = (c[l2 >> 2] | 0) + h2 | 0; + c[l2 >> 2] = o2; + n2 = c[F3 + 8 >> 2] | 0; + g3 = m3 + (o2 >>> 3) | 0; + if (!((bc(n2 | 0, 0, h2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + I3 = d[g3 >> 0] | 0; + F3 = cc(n2 | 0, 0, o2 & 7 | 0) | 0; + H3 = C2; + F3 = I3 | F3; + I3 = g3; + m3 = I3; + a[m3 >> 0] = F3; + a[m3 + 1 >> 0] = F3 >> 8; + a[m3 + 2 >> 0] = F3 >> 16; + a[m3 + 3 >> 0] = F3 >> 24; + I3 = I3 + 4 | 0; + a[I3 >> 0] = H3; + a[I3 + 1 >> 0] = H3 >> 8; + a[I3 + 2 >> 0] = H3 >> 16; + a[I3 + 3 >> 0] = H3 >> 24; + c[l2 >> 2] = (c[l2 >> 2] | 0) + h2; + i = G3; + return; + } + default: { + p2 = c[F3 >> 2] | 0; + g3 = m3 + (t3 >>> 3) | 0; + n2 = d[g3 >> 0] | 0; + if (!((bc(p2 | 0, 0, h2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (h2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + I3 = cc(p2 | 0, 0, t3 & 7 | 0) | 0; + o2 = C2; + I3 = n2 | I3; + n2 = g3; + a[n2 >> 0] = I3; + a[n2 + 1 >> 0] = I3 >> 8; + a[n2 + 2 >> 0] = I3 >> 16; + a[n2 + 3 >> 0] = I3 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = o2; + a[g3 + 1 >> 0] = o2 >> 8; + a[g3 + 2 >> 0] = o2 >> 16; + a[g3 + 3 >> 0] = o2 >> 24; + g3 = (c[l2 >> 2] | 0) + h2 | 0; + c[l2 >> 2] = g3; + n2 = c[F3 + 4 >> 2] | 0; + o2 = m3 + (g3 >>> 3) | 0; + if (!((bc(n2 | 0, 0, h2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + H3 = d[o2 >> 0] | 0; + I3 = cc(n2 | 0, 0, g3 & 7 | 0) | 0; + n2 = C2; + I3 = H3 | I3; + g3 = o2; + o2 = g3; + a[o2 >> 0] = I3; + a[o2 + 1 >> 0] = I3 >> 8; + a[o2 + 2 >> 0] = I3 >> 16; + a[o2 + 3 >> 0] = I3 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = n2; + a[g3 + 1 >> 0] = n2 >> 8; + a[g3 + 2 >> 0] = n2 >> 16; + a[g3 + 3 >> 0] = n2 >> 24; + g3 = (c[l2 >> 2] | 0) + h2 | 0; + c[l2 >> 2] = g3; + n2 = c[F3 + 8 >> 2] | 0; + o2 = m3 + (g3 >>> 3) | 0; + if (!((bc(n2 | 0, 0, h2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + H3 = d[o2 >> 0] | 0; + I3 = cc(n2 | 0, 0, g3 & 7 | 0) | 0; + g3 = C2; + I3 = H3 | I3; + n2 = o2; + a[n2 >> 0] = I3; + a[n2 + 1 >> 0] = I3 >> 8; + a[n2 + 2 >> 0] = I3 >> 16; + a[n2 + 3 >> 0] = I3 >> 24; + o2 = o2 + 4 | 0; + a[o2 >> 0] = g3; + a[o2 + 1 >> 0] = g3 >> 8; + a[o2 + 2 >> 0] = g3 >> 16; + a[o2 + 3 >> 0] = g3 >> 24; + o2 = (c[l2 >> 2] | 0) + h2 | 0; + c[l2 >> 2] = o2; + g3 = c[F3 + 12 >> 2] | 0; + n2 = m3 + (o2 >>> 3) | 0; + if (!((bc(g3 | 0, 0, h2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + H3 = d[n2 >> 0] | 0; + E3 = cc(g3 | 0, 0, o2 & 7 | 0) | 0; + I3 = C2; + E3 = H3 | E3; + H3 = n2; + F3 = H3; + a[F3 >> 0] = E3; + a[F3 + 1 >> 0] = E3 >> 8; + a[F3 + 2 >> 0] = E3 >> 16; + a[F3 + 3 >> 0] = E3 >> 24; + H3 = H3 + 4 | 0; + a[H3 >> 0] = I3; + a[H3 + 1 >> 0] = I3 >> 8; + a[H3 + 2 >> 0] = I3 >> 16; + a[H3 + 3 >> 0] = I3 >> 24; + H3 = (c[l2 >> 2] | 0) + h2 | 0; + c[l2 >> 2] = H3; + I3 = m3 + (H3 >>> 3) | 0; + h2 = d[I3 >> 0] | 0; + m3 = cc((a[j2 + p2 >> 0] | 0) == 1 | 0, 0, H3 & 7 | 0) | 0; + H3 = C2; + m3 = h2 | m3; + h2 = I3; + a[h2 >> 0] = m3; + a[h2 + 1 >> 0] = m3 >> 8; + a[h2 + 2 >> 0] = m3 >> 16; + a[h2 + 3 >> 0] = m3 >> 24; + I3 = I3 + 4 | 0; + a[I3 >> 0] = H3; + a[I3 + 1 >> 0] = H3 >> 8; + a[I3 + 2 >> 0] = H3 >> 16; + a[I3 + 3 >> 0] = H3 >> 24; + c[l2 >> 2] = (c[l2 >> 2] | 0) + 1; + i = G3; + return; + } + } + } + function ab2(b3, e2, f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2, s2, t3) { + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + t3 = t3 | 0; + var u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0; + T3 = i; + i = i + 2704 | 0; + S3 = T3 + 1800 | 0; + Q3 = T3 + 900 | 0; + R3 = T3; + db(l2, g3, s2, t3); + P3 = b3 + 8 | 0; + y3 = sa2[c[b3 >> 2] & 1](c[P3 >> 2] | 0, 11272) | 0; + if (!y3) oa2(1); + M2 = c[r2 >> 2] | 0; + N3 = c[r2 + 8 >> 2] | 0; + g3 = c[r2 + 12 >> 2] | 0; + O3 = c[r2 + 4 >> 2] | 0; + c[S3 >> 2] = 256; + c[S3 + 4 >> 2] = M2; + c[S3 + 8 >> 2] = N3; + c[S3 + 12 >> 2] = g3; + c[S3 + 16 >> 2] = O3; + c[S3 + 20 >> 2] = 1; + c[S3 + 24 >> 2] = 0; + c[S3 + 880 >> 2] = 0; + if (!O3) g3 = 0; + else g3 = c[g3 >> 2] | 0; + c[S3 + 884 >> 2] = g3; + c[S3 + 888 >> 2] = 0; + N3 = S3 + 892 | 0; + c[N3 >> 2] = 0; + O3 = S3 + 896 | 0; + c[O3 >> 2] = 0; + K3 = c[r2 + 24 >> 2] | 0; + L3 = c[r2 + 32 >> 2] | 0; + g3 = c[r2 + 36 >> 2] | 0; + M2 = c[r2 + 28 >> 2] | 0; + c[Q3 >> 2] = 704; + c[Q3 + 4 >> 2] = K3; + c[Q3 + 8 >> 2] = L3; + c[Q3 + 12 >> 2] = g3; + c[Q3 + 16 >> 2] = M2; + c[Q3 + 20 >> 2] = 1; + c[Q3 + 24 >> 2] = 0; + c[Q3 + 880 >> 2] = 0; + if (!M2) g3 = 0; + else g3 = c[g3 >> 2] | 0; + c[Q3 + 884 >> 2] = g3; + c[Q3 + 888 >> 2] = 0; + L3 = Q3 + 892 | 0; + c[L3 >> 2] = 0; + M2 = Q3 + 896 | 0; + c[M2 >> 2] = 0; + I3 = c[r2 + 48 >> 2] | 0; + J3 = c[r2 + 56 >> 2] | 0; + g3 = c[r2 + 60 >> 2] | 0; + K3 = c[r2 + 52 >> 2] | 0; + c[R3 >> 2] = m3 + 16 + (48 << n2); + c[R3 + 4 >> 2] = I3; + c[R3 + 8 >> 2] = J3; + c[R3 + 12 >> 2] = g3; + c[R3 + 16 >> 2] = K3; + c[R3 + 20 >> 2] = 1; + c[R3 + 24 >> 2] = 0; + c[R3 + 880 >> 2] = 0; + if (!K3) g3 = 0; + else g3 = c[g3 >> 2] | 0; + c[R3 + 884 >> 2] = g3; + c[R3 + 888 >> 2] = 0; + J3 = R3 + 892 | 0; + c[J3 >> 2] = 0; + K3 = R3 + 896 | 0; + c[K3 >> 2] = 0; + eb(S3, y3, s2, t3); + eb(Q3, y3, s2, t3); + eb(R3, y3, s2, t3); + g3 = c[s2 >> 2] | 0; + u3 = t3 + (g3 >>> 3) | 0; + v3 = d[u3 >> 0] | 0; + if (!((n2 & -4 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + w2 = cc(n2 | 0, 0, g3 & 7 | 0) | 0; + g3 = C2; + v3 = v3 | w2; + w2 = u3; + u3 = w2; + a[u3 >> 0] = v3; + a[u3 + 1 >> 0] = v3 >> 8; + a[u3 + 2 >> 0] = v3 >> 16; + a[u3 + 3 >> 0] = v3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = g3; + a[w2 + 1 >> 0] = g3 >> 8; + a[w2 + 2 >> 0] = g3 >> 16; + a[w2 + 3 >> 0] = g3 >> 24; + w2 = (c[s2 >> 2] | 0) + 2 | 0; + c[s2 >> 2] = w2; + g3 = m3 >>> n2; + u3 = t3 + (w2 >>> 3) | 0; + v3 = d[u3 >> 0] | 0; + if (!((g3 & -16 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + I3 = cc(g3 | 0, 0, w2 & 7 | 0) | 0; + g3 = C2; + I3 = v3 | I3; + n2 = u3; + a[n2 >> 0] = I3; + a[n2 + 1 >> 0] = I3 >> 8; + a[n2 + 2 >> 0] = I3 >> 16; + a[n2 + 3 >> 0] = I3 >> 24; + u3 = u3 + 4 | 0; + a[u3 >> 0] = g3; + a[u3 + 1 >> 0] = g3 >> 8; + a[u3 + 2 >> 0] = g3 >> 16; + a[u3 + 3 >> 0] = g3 >> 24; + u3 = (c[s2 >> 2] | 0) + 4 | 0; + c[s2 >> 2] = u3; + g3 = (o2 & -4 | 0) == 0 & true; + n2 = 0; + while (1) { + if (n2 >>> 0 >= (c[r2 >> 2] | 0) >>> 0) break; + v3 = t3 + (u3 >>> 3) | 0; + w2 = d[v3 >> 0] | 0; + if (!g3) { + x3 = 16; + break; + } + F3 = cc(o2 | 0, 0, u3 & 7 | 0) | 0; + H3 = C2; + F3 = w2 | F3; + I3 = v3; + G3 = I3; + a[G3 >> 0] = F3; + a[G3 + 1 >> 0] = F3 >> 8; + a[G3 + 2 >> 0] = F3 >> 16; + a[G3 + 3 >> 0] = F3 >> 24; + I3 = I3 + 4 | 0; + a[I3 >> 0] = H3; + a[I3 + 1 >> 0] = H3 >> 8; + a[I3 + 2 >> 0] = H3 >> 16; + a[I3 + 3 >> 0] = H3 >> 24; + I3 = (c[s2 >> 2] | 0) + 2 | 0; + c[s2 >> 2] = I3; + u3 = I3; + n2 = n2 + 1 | 0; + } + if ((x3 | 0) == 16) pa2(406196, 406218, 54, 406251); + I3 = r2 + 76 | 0; + g3 = c[I3 >> 2] | 0; + v3 = r2 + 92 | 0; + u3 = c[v3 >> 2] | 0; + if (!g3) fb(u3, 6, y3, s2, t3); + else gb(b3, c[r2 + 72 >> 2] | 0, g3, u3, y3, s2, t3); + H3 = r2 + 84 | 0; + g3 = c[H3 >> 2] | 0; + m3 = r2 + 108 | 0; + u3 = c[m3 >> 2] | 0; + if (!g3) fb(u3, 2, y3, s2, t3); + else gb(b3, c[r2 + 80 >> 2] | 0, g3, u3, y3, s2, t3); + w2 = c[r2 + 88 >> 2] | 0; + v3 = c[v3 >> 2] | 0; + n2 = c[S3 >> 2] | 0; + g3 = _(v3, n2) | 0; + u3 = sa2[c[b3 >> 2] & 1](c[P3 >> 2] | 0, g3) | 0; + if (!u3) oa2(1); + c[N3 >> 2] = u3; + g3 = sa2[c[b3 >> 2] & 1](c[P3 >> 2] | 0, g3 << 1) | 0; + if (!g3) oa2(1); + c[O3 >> 2] = g3; + g3 = w2; + u3 = 0; + while (1) { + if ((u3 | 0) == (v3 | 0)) break; + G3 = _(u3, n2) | 0; + kb(g3 + (u3 * 1040 | 0) | 0, n2, y3, (c[N3 >> 2] | 0) + G3 | 0, (c[O3 >> 2] | 0) + (G3 << 1) | 0, s2, t3); + u3 = u3 + 1 | 0; + } + v3 = c[r2 + 96 >> 2] | 0; + w2 = c[r2 + 100 >> 2] | 0; + n2 = c[Q3 >> 2] | 0; + g3 = _(w2, n2) | 0; + u3 = sa2[c[b3 >> 2] & 1](c[P3 >> 2] | 0, g3) | 0; + if (!u3) oa2(1); + c[L3 >> 2] = u3; + g3 = sa2[c[b3 >> 2] & 1](c[P3 >> 2] | 0, g3 << 1) | 0; + if (!g3) oa2(1); + c[M2 >> 2] = g3; + g3 = v3; + u3 = 0; + while (1) { + if ((u3 | 0) == (w2 | 0)) break; + G3 = _(u3, n2) | 0; + kb(g3 + (u3 * 2832 | 0) | 0, n2, y3, (c[L3 >> 2] | 0) + G3 | 0, (c[M2 >> 2] | 0) + (G3 << 1) | 0, s2, t3); + u3 = u3 + 1 | 0; + } + v3 = c[r2 + 104 >> 2] | 0; + w2 = c[m3 >> 2] | 0; + n2 = c[R3 >> 2] | 0; + g3 = _(w2, n2) | 0; + u3 = sa2[c[b3 >> 2] & 1](c[P3 >> 2] | 0, g3) | 0; + if (!u3) oa2(1); + c[J3 >> 2] = u3; + g3 = sa2[c[b3 >> 2] & 1](c[P3 >> 2] | 0, g3 << 1) | 0; + if (!g3) oa2(1); + c[K3 >> 2] = g3; + g3 = v3; + u3 = 0; + while (1) { + if ((u3 | 0) == (w2 | 0)) break; + G3 = _(u3, n2) | 0; + kb(g3 + (u3 * 2096 | 0) | 0, n2, y3, (c[J3 >> 2] | 0) + G3 | 0, (c[K3 >> 2] | 0) + (G3 << 1) | 0, s2, t3); + u3 = u3 + 1 | 0; + } + G3 = b3 + 4 | 0; + ra2[c[G3 >> 2] & 1](c[P3 >> 2] | 0, y3); + F3 = r2 + 80 | 0; + E3 = r2 + 72 | 0; + u3 = j2; + g3 = k2; + D3 = 0; + a: while (1) { + if (D3 >>> 0 >= q2 >>> 0) { + x3 = 87; + break; + } + b3 = c[p2 + (D3 << 4) >> 2] | 0; + n2 = c[p2 + (D3 << 4) + 4 >> 2] | 0; + B3 = c[p2 + (D3 << 4) + 8 >> 2] | 0; + k2 = c[p2 + (D3 << 4) + 12 >> 2] | 0; + j2 = k2 & 65535; + A3 = k2 >>> 16; + z3 = k2 & 65535; + hb(Q3, z3, s2, t3); + r2 = n2 & 16777215; + n2 = r2 ^ n2 >>> 24; + do + if (b3 >>> 0 < 6) w2 = b3; + else { + if (b3 >>> 0 < 130) { + y3 = b3 + -2 | 0; + w2 = ((aa(y3 | 0) | 0) ^ 31) + -1 | 0; + w2 = (w2 << 1) + (y3 >>> w2) + 2 | 0; + break; + } + if (b3 >>> 0 < 2114) { + w2 = ((aa(b3 + -66 | 0) | 0) ^ 31) + 10 | 0; + break; + } + if (b3 >>> 0 < 6210) { + w2 = 21; + break; + } + w2 = b3 >>> 0 < 22594 ? 22 : 23; + } + while (0); + do + if (n2 >>> 0 < 10) v3 = n2 + 65534 | 0; + else { + if (n2 >>> 0 < 134) { + y3 = n2 + -6 | 0; + v3 = ((aa(y3 | 0) | 0) ^ 31) + -1 | 0; + v3 = (v3 << 1) + (y3 >>> v3) + 4 | 0; + break; + } + if (n2 >>> 0 >= 2118) { + v3 = 23; + break; + } + v3 = ((aa(n2 + -70 | 0) | 0) ^ 31) + 12 | 0; + } + while (0); + w2 = w2 & 65535; + x3 = c[17268 + (w2 << 2) >> 2] | 0; + w2 = b3 - (c[18788 + (w2 << 2) >> 2] | 0) | 0; + m3 = v3 & 65535; + n2 = cc(n2 - (c[17364 + (m3 << 2) >> 2] | 0) | 0, 0, x3 | 0) | 0; + v3 = C2; + w2 = n2 | w2; + n2 = x3 + (c[17460 + (m3 << 2) >> 2] | 0) | 0; + m3 = c[s2 >> 2] | 0; + x3 = t3 + (m3 >>> 3) | 0; + y3 = d[x3 >> 0] | 0; + U3 = bc(w2 | 0, v3 | 0, n2 | 0) | 0; + if (!((U3 | 0) == 0 & (C2 | 0) == 0)) { + x3 = 61; + break; + } + if (n2 >>> 0 >= 57) { + x3 = 63; + break; + } + w2 = cc(w2 | 0, v3 | 0, m3 & 7 | 0) | 0; + m3 = C2; + w2 = y3 | w2; + U3 = x3; + y3 = U3; + a[y3 >> 0] = w2; + a[y3 + 1 >> 0] = w2 >> 8; + a[y3 + 2 >> 0] = w2 >> 16; + a[y3 + 3 >> 0] = w2 >> 24; + U3 = U3 + 4 | 0; + a[U3 >> 0] = m3; + a[U3 + 1 >> 0] = m3 >> 8; + a[U3 + 2 >> 0] = m3 >> 16; + a[U3 + 3 >> 0] = m3 >> 24; + c[s2 >> 2] = (c[s2 >> 2] | 0) + n2; + b: do + if (!(c[I3 >> 2] | 0)) { + v3 = f2; + w2 = b3; + while (1) { + if (!w2) break b; + hb(S3, d[e2 + (v3 & h2) >> 0] | 0, s2, t3); + v3 = v3 + 1 | 0; + w2 = w2 + -1 | 0; + } + } else { + v3 = f2; + w2 = b3; + while (1) { + if (!w2) break b; + switch (o2 | 0) { + case 0: { + g3 = u3 & 63; + break; + } + case 1: { + g3 = (u3 & 255) >>> 2; + break; + } + case 2: { + g3 = a[406969 + (u3 & 255) >> 0] | a[406969 + (g3 & 255 | 256) >> 0]; + break; + } + case 3: { + g3 = ((d[407481 + (u3 & 255) >> 0] | 0) << 3) + (d[407481 + (g3 & 255) >> 0] | 0) & 255; + break; + } + default: + g3 = 0; + } + U3 = a[e2 + (v3 & h2) >> 0] | 0; + ib(S3, U3 & 255, g3 & 255, c[E3 >> 2] | 0, s2, t3, 6); + g3 = u3; + u3 = U3; + v3 = v3 + 1 | 0; + w2 = w2 + -1 | 0; + } + } + while (0); + y3 = f2 + b3 + r2 | 0; + do + if (r2) { + g3 = a[e2 + (y3 + -2 & h2) >> 0] | 0; + u3 = a[e2 + (y3 + -1 & h2) >> 0] | 0; + if ((j2 & 65535) <= 127) break; + m3 = B3 >>> 24; + x3 = B3 & 16777215; + if (!(c[H3 >> 2] | 0)) hb(R3, A3, s2, t3); + else { + v3 = k2 & 7; + switch (z3 >>> 6 | 0) { + case 7: + case 4: + case 2: + case 0: { + v3 = v3 >>> 0 < 3 ? v3 : 3; + break; + } + default: + v3 = 3; + } + ib(R3, A3, v3, c[F3 >> 2] | 0, s2, t3, 2); + } + v3 = c[s2 >> 2] | 0; + w2 = t3 + (v3 >>> 3) | 0; + n2 = d[w2 >> 0] | 0; + U3 = bc(x3 | 0, 0, m3 | 0) | 0; + if (!((U3 | 0) == 0 & (C2 | 0) == 0)) { + x3 = 82; + break a; + } + if (B3 >>> 0 >= 956301312) { + x3 = 84; + break a; + } + z3 = cc(x3 | 0, 0, v3 & 7 | 0) | 0; + B3 = C2; + z3 = n2 | z3; + U3 = w2; + A3 = U3; + a[A3 >> 0] = z3; + a[A3 + 1 >> 0] = z3 >> 8; + a[A3 + 2 >> 0] = z3 >> 16; + a[A3 + 3 >> 0] = z3 >> 24; + U3 = U3 + 4 | 0; + a[U3 >> 0] = B3; + a[U3 + 1 >> 0] = B3 >> 8; + a[U3 + 2 >> 0] = B3 >> 16; + a[U3 + 3 >> 0] = B3 >> 24; + c[s2 >> 2] = (c[s2 >> 2] | 0) + m3; + } + while (0); + f2 = y3; + D3 = D3 + 1 | 0; + } + if ((x3 | 0) == 61) pa2(406196, 406218, 54, 406251); + else if ((x3 | 0) == 63) pa2(406267, 406218, 55, 406251); + else if ((x3 | 0) == 82) pa2(406196, 406218, 54, 406251); + else if ((x3 | 0) == 84) pa2(406267, 406218, 55, 406251); + else if ((x3 | 0) == 87) { + ra2[c[G3 >> 2] & 1](c[P3 >> 2] | 0, c[J3 >> 2] | 0); + c[J3 >> 2] = 0; + ra2[c[G3 >> 2] & 1](c[P3 >> 2] | 0, c[K3 >> 2] | 0); + c[K3 >> 2] = 0; + ra2[c[G3 >> 2] & 1](c[P3 >> 2] | 0, c[L3 >> 2] | 0); + c[L3 >> 2] = 0; + ra2[c[G3 >> 2] & 1](c[P3 >> 2] | 0, c[M2 >> 2] | 0); + c[M2 >> 2] = 0; + ra2[c[G3 >> 2] & 1](c[P3 >> 2] | 0, c[N3 >> 2] | 0); + c[N3 >> 2] = 0; + ra2[c[G3 >> 2] & 1](c[P3 >> 2] | 0, c[O3 >> 2] | 0); + c[O3 >> 2] = 0; + if (!l2) { + i = T3; + return; + } + U3 = (c[s2 >> 2] | 0) + 7 | 0; + c[s2 >> 2] = U3 & -8; + a[t3 + (U3 >>> 3) >> 0] = 0; + i = T3; + return; + } + } + function bb2(b3, e2, f2, g3, h2, j2, k2) { + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + var l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0; + t3 = i; + i = i + 32 | 0; + r2 = t3 + 8 | 0; + q2 = t3 + 16 | 0; + l2 = t3; + s2 = f2 & g3; + f2 = k2 + ((c[j2 >> 2] | 0) >>> 3) | 0; + n2 = d[f2 >> 0] | 0; + m3 = f2; + a[m3 >> 0] = n2; + a[m3 + 1 >> 0] = n2 >> 8; + a[m3 + 2 >> 0] = n2 >> 16; + a[m3 + 3 >> 0] = n2 >> 24; + f2 = f2 + 4 | 0; + a[f2 >> 0] = 0; + a[f2 + 1 >> 0] = 0; + a[f2 + 2 >> 0] = 0; + a[f2 + 3 >> 0] = 0; + c[j2 >> 2] = (c[j2 >> 2] | 0) + 1; + mb(h2, r2, q2, l2); + f2 = c[l2 >> 2] | 0; + l2 = c[l2 + 4 >> 2] | 0; + m3 = c[j2 >> 2] | 0; + n2 = k2 + (m3 >>> 3) | 0; + o2 = d[n2 >> 0] | 0; + if (!(l2 >>> 0 < 0 | (l2 | 0) == 0 & f2 >>> 0 < 4)) pa2(406196, 406218, 54, 406251); + f2 = cc(f2 | 0, l2 | 0, m3 & 7 | 0) | 0; + l2 = C2; + f2 = o2 | f2; + p2 = n2; + o2 = p2; + a[o2 >> 0] = f2; + a[o2 + 1 >> 0] = f2 >> 8; + a[o2 + 2 >> 0] = f2 >> 16; + a[o2 + 3 >> 0] = f2 >> 24; + p2 = p2 + 4 | 0; + a[p2 >> 0] = l2; + a[p2 + 1 >> 0] = l2 >> 8; + a[p2 + 2 >> 0] = l2 >> 16; + a[p2 + 3 >> 0] = l2 >> 24; + p2 = (c[j2 >> 2] | 0) + 2 | 0; + c[j2 >> 2] = p2; + o2 = c[q2 >> 2] | 0; + l2 = r2; + f2 = c[l2 >> 2] | 0; + l2 = c[l2 + 4 >> 2] | 0; + m3 = k2 + (p2 >>> 3) | 0; + n2 = d[m3 >> 0] | 0; + r2 = bc(f2 | 0, l2 | 0, o2 | 0) | 0; + if (!((r2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (o2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + r2 = cc(f2 | 0, l2 | 0, p2 & 7 | 0) | 0; + f2 = C2; + r2 = n2 | r2; + p2 = m3; + q2 = p2; + a[q2 >> 0] = r2; + a[q2 + 1 >> 0] = r2 >> 8; + a[q2 + 2 >> 0] = r2 >> 16; + a[q2 + 3 >> 0] = r2 >> 24; + p2 = p2 + 4 | 0; + a[p2 >> 0] = f2; + a[p2 + 1 >> 0] = f2 >> 8; + a[p2 + 2 >> 0] = f2 >> 16; + a[p2 + 3 >> 0] = f2 >> 24; + p2 = (c[j2 >> 2] | 0) + o2 | 0; + c[j2 >> 2] = p2; + f2 = k2 + (p2 >>> 3) | 0; + q2 = d[f2 >> 0] | 0; + p2 = cc(1, 0, p2 & 7 | 0) | 0; + r2 = C2; + p2 = q2 | p2; + q2 = f2; + a[q2 >> 0] = p2; + a[q2 + 1 >> 0] = p2 >> 8; + a[q2 + 2 >> 0] = p2 >> 16; + a[q2 + 3 >> 0] = p2 >> 24; + f2 = f2 + 4 | 0; + a[f2 >> 0] = r2; + a[f2 + 1 >> 0] = r2 >> 8; + a[f2 + 2 >> 0] = r2 >> 16; + a[f2 + 3 >> 0] = r2 >> 24; + c[j2 >> 2] = (c[j2 >> 2] | 0) + 1; + f2 = (c[j2 >> 2] | 0) + 7 | 0; + c[j2 >> 2] = f2 & -8; + a[k2 + (f2 >>> 3) >> 0] = 0; + f2 = g3 + 1 | 0; + if ((s2 + h2 | 0) >>> 0 > f2 >>> 0) { + f2 = f2 - s2 | 0; + dc(k2 + ((c[j2 >> 2] | 0) >>> 3) | 0, e2 + s2 | 0, f2 | 0) | 0; + l2 = (c[j2 >> 2] | 0) + (f2 << 3) | 0; + c[j2 >> 2] = l2; + h2 = h2 - f2 | 0; + f2 = 0; + } else { + l2 = c[j2 >> 2] | 0; + f2 = s2; + } + dc(k2 + (l2 >>> 3) | 0, e2 + f2 | 0, h2 | 0) | 0; + f2 = (c[j2 >> 2] | 0) + (h2 << 3) | 0; + c[j2 >> 2] = f2; + if (f2 & 7) pa2(405180, 406218, 82, 405195); + a[k2 + (f2 >>> 3) >> 0] = 0; + if (!b3) { + i = t3; + return; + } + e2 = c[j2 >> 2] | 0; + g3 = k2 + (e2 >>> 3) | 0; + s2 = d[g3 >> 0] | 0; + e2 = cc(1, 0, e2 & 7 | 0) | 0; + b3 = C2; + e2 = s2 | e2; + s2 = g3; + a[s2 >> 0] = e2; + a[s2 + 1 >> 0] = e2 >> 8; + a[s2 + 2 >> 0] = e2 >> 16; + a[s2 + 3 >> 0] = e2 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = b3; + a[g3 + 1 >> 0] = b3 >> 8; + a[g3 + 2 >> 0] = b3 >> 16; + a[g3 + 3 >> 0] = b3 >> 24; + g3 = (c[j2 >> 2] | 0) + 1 | 0; + c[j2 >> 2] = g3; + b3 = k2 + (g3 >>> 3) | 0; + s2 = d[b3 >> 0] | 0; + g3 = cc(1, 0, g3 & 7 | 0) | 0; + e2 = C2; + g3 = s2 | g3; + s2 = b3; + a[s2 >> 0] = g3; + a[s2 + 1 >> 0] = g3 >> 8; + a[s2 + 2 >> 0] = g3 >> 16; + a[s2 + 3 >> 0] = g3 >> 24; + b3 = b3 + 4 | 0; + a[b3 >> 0] = e2; + a[b3 + 1 >> 0] = e2 >> 8; + a[b3 + 2 >> 0] = e2 >> 16; + a[b3 + 3 >> 0] = e2 >> 24; + b3 = (c[j2 >> 2] | 0) + 8 | 0; + c[j2 >> 2] = b3 & -8; + a[k2 + (b3 >>> 3) >> 0] = 0; + i = t3; + return; + } + function cb(a2, b3) { + a2 = a2 | 0; + b3 = b3 | 0; + return a2 >>> 0 < b3 >>> 0 | 0; + } + function db(b3, e2, f2, g3) { + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + var h2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0; + p2 = i; + i = i + 32 | 0; + o2 = p2 + 8 | 0; + n2 = p2 + 16 | 0; + j2 = p2; + h2 = g3 + ((c[f2 >> 2] | 0) >>> 3) | 0; + l2 = d[h2 >> 0] | 0; + k2 = cc(b3 & 1 | 0, 0, c[f2 >> 2] & 7 | 0) | 0; + m3 = C2; + k2 = l2 | k2; + l2 = h2; + a[l2 >> 0] = k2; + a[l2 + 1 >> 0] = k2 >> 8; + a[l2 + 2 >> 0] = k2 >> 16; + a[l2 + 3 >> 0] = k2 >> 24; + h2 = h2 + 4 | 0; + a[h2 >> 0] = m3; + a[h2 + 1 >> 0] = m3 >> 8; + a[h2 + 2 >> 0] = m3 >> 16; + a[h2 + 3 >> 0] = m3 >> 24; + h2 = (c[f2 >> 2] | 0) + 1 | 0; + c[f2 >> 2] = h2; + if (b3) { + m3 = g3 + (h2 >>> 3) | 0; + k2 = d[m3 >> 0] | 0; + l2 = m3; + a[l2 >> 0] = k2; + a[l2 + 1 >> 0] = k2 >> 8; + a[l2 + 2 >> 0] = k2 >> 16; + a[l2 + 3 >> 0] = k2 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = 0; + a[m3 + 1 >> 0] = 0; + a[m3 + 2 >> 0] = 0; + a[m3 + 3 >> 0] = 0; + c[f2 >> 2] = (c[f2 >> 2] | 0) + 1; + } + mb(e2, o2, n2, j2); + e2 = j2; + h2 = c[e2 >> 2] | 0; + e2 = c[e2 + 4 >> 2] | 0; + j2 = c[f2 >> 2] | 0; + k2 = g3 + (j2 >>> 3) | 0; + l2 = d[k2 >> 0] | 0; + if (!(e2 >>> 0 < 0 | (e2 | 0) == 0 & h2 >>> 0 < 4)) pa2(406196, 406218, 54, 406251); + h2 = cc(h2 | 0, e2 | 0, j2 & 7 | 0) | 0; + e2 = C2; + h2 = l2 | h2; + m3 = k2; + l2 = m3; + a[l2 >> 0] = h2; + a[l2 + 1 >> 0] = h2 >> 8; + a[l2 + 2 >> 0] = h2 >> 16; + a[l2 + 3 >> 0] = h2 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = e2; + a[m3 + 1 >> 0] = e2 >> 8; + a[m3 + 2 >> 0] = e2 >> 16; + a[m3 + 3 >> 0] = e2 >> 24; + m3 = (c[f2 >> 2] | 0) + 2 | 0; + c[f2 >> 2] = m3; + l2 = c[n2 >> 2] | 0; + e2 = o2; + h2 = c[e2 >> 2] | 0; + e2 = c[e2 + 4 >> 2] | 0; + j2 = g3 + (m3 >>> 3) | 0; + k2 = d[j2 >> 0] | 0; + o2 = bc(h2 | 0, e2 | 0, l2 | 0) | 0; + if (!((o2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (l2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + m3 = cc(h2 | 0, e2 | 0, m3 & 7 | 0) | 0; + o2 = C2; + m3 = k2 | m3; + h2 = j2; + n2 = h2; + a[n2 >> 0] = m3; + a[n2 + 1 >> 0] = m3 >> 8; + a[n2 + 2 >> 0] = m3 >> 16; + a[n2 + 3 >> 0] = m3 >> 24; + h2 = h2 + 4 | 0; + a[h2 >> 0] = o2; + a[h2 + 1 >> 0] = o2 >> 8; + a[h2 + 2 >> 0] = o2 >> 16; + a[h2 + 3 >> 0] = o2 >> 24; + h2 = (c[f2 >> 2] | 0) + l2 | 0; + c[f2 >> 2] = h2; + if (b3) { + i = p2; + return; + } + g3 = g3 + (h2 >>> 3) | 0; + o2 = d[g3 >> 0] | 0; + b3 = g3; + a[b3 >> 0] = o2; + a[b3 + 1 >> 0] = o2 >> 8; + a[b3 + 2 >> 0] = o2 >> 16; + a[b3 + 3 >> 0] = o2 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = 0; + a[g3 + 1 >> 0] = 0; + a[g3 + 2 >> 0] = 0; + a[g3 + 3 >> 0] = 0; + c[f2 >> 2] = (c[f2 >> 2] | 0) + 1; + i = p2; + return; + } + function eb(b3, f2, g3, h2) { + b3 = b3 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + var j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0; + v3 = i; + i = i + 1136 | 0; + u3 = v3 + 104 | 0; + t3 = v3; + j2 = c[b3 + 8 >> 2] | 0; + m3 = c[b3 + 12 >> 2] | 0; + r2 = c[b3 + 16 >> 2] | 0; + s2 = c[b3 + 4 >> 2] | 0; + ac(u3 | 0, 0, (s2 << 2) + 8 | 0) | 0; + k2 = t3; + l2 = k2 + 104 | 0; + do { + c[k2 >> 2] = 0; + k2 = k2 + 4 | 0; + } while ((k2 | 0) < (l2 | 0)); + p2 = 0; + q2 = 1; + k2 = 0; + while (1) { + if ((p2 | 0) == (r2 | 0)) break; + o2 = d[j2 + p2 >> 0] | 0; + if ((o2 | 0) == (q2 + 1 | 0)) k2 = 1; + else k2 = (o2 | 0) == (k2 | 0) ? 0 : o2 + 2 | 0; + if (p2) { + n2 = u3 + (k2 << 2) | 0; + c[n2 >> 2] = (c[n2 >> 2] | 0) + 1; + } + k2 = c[m3 + (p2 << 2) >> 2] | 0; + if (k2 >>> 0 > 176) n2 = k2 >>> 0 > 752 ? 20 : 14; + else n2 = k2 >>> 0 > 40 ? 7 : 0; + while (1) { + if (n2 >>> 0 >= 25) break; + l2 = n2 + 1 | 0; + if (k2 >>> 0 < (c[17556 + (l2 << 3) >> 2] | 0) >>> 0) break; + else n2 = l2; + } + k2 = t3 + (n2 << 2) | 0; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + k2 = q2; + p2 = p2 + 1 | 0; + q2 = o2; + } + nb(s2 + -1 | 0, g3, h2); + if (s2 >>> 0 <= 1) { + i = v3; + return; + } + r2 = b3 + 20 | 0; + kb(u3, s2 + 2 | 0, f2, b3 + 28 | 0, b3 + 286 | 0, g3, h2); + kb(t3, 26, f2, b3 + 802 | 0, b3 + 828 | 0, g3, h2); + k2 = c[m3 >> 2] | 0; + u3 = d[j2 >> 0] | 0; + c[b3 + 24 >> 2] = c[r2 >> 2]; + c[r2 >> 2] = u3; + if (k2 >>> 0 > 176) l2 = k2 >>> 0 > 752 ? 20 : 14; + else l2 = k2 >>> 0 > 40 ? 7 : 0; + while (1) { + if (l2 >>> 0 >= 25) break; + j2 = l2 + 1 | 0; + if (k2 >>> 0 < (c[17556 + (j2 << 3) >> 2] | 0) >>> 0) break; + else l2 = j2; + } + p2 = c[17556 + (l2 << 3) + 4 >> 2] | 0; + o2 = k2 - (c[17556 + (l2 << 3) >> 2] | 0) | 0; + n2 = a[b3 + 802 + l2 >> 0] | 0; + j2 = e[b3 + 828 + (l2 << 1) >> 1] | 0; + k2 = c[g3 >> 2] | 0; + l2 = h2 + (k2 >>> 3) | 0; + m3 = d[l2 >> 0] | 0; + b3 = bc(j2 | 0, 0, n2 & 255 | 0) | 0; + if (!((b3 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if ((n2 & 255) >= 57) pa2(406267, 406218, 55, 406251); + b3 = cc(j2 | 0, 0, k2 & 7 | 0) | 0; + j2 = C2; + b3 = m3 | b3; + k2 = l2; + a[k2 >> 0] = b3; + a[k2 + 1 >> 0] = b3 >> 8; + a[k2 + 2 >> 0] = b3 >> 16; + a[k2 + 3 >> 0] = b3 >> 24; + l2 = l2 + 4 | 0; + a[l2 >> 0] = j2; + a[l2 + 1 >> 0] = j2 >> 8; + a[l2 + 2 >> 0] = j2 >> 16; + a[l2 + 3 >> 0] = j2 >> 24; + l2 = (c[g3 >> 2] | 0) + (n2 & 255) | 0; + c[g3 >> 2] = l2; + j2 = h2 + (l2 >>> 3) | 0; + k2 = d[j2 >> 0] | 0; + h2 = bc(o2 | 0, 0, p2 | 0) | 0; + if (!((h2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + f2 = cc(o2 | 0, 0, l2 & 7 | 0) | 0; + b3 = C2; + f2 = k2 | f2; + h2 = j2; + u3 = h2; + a[u3 >> 0] = f2; + a[u3 + 1 >> 0] = f2 >> 8; + a[u3 + 2 >> 0] = f2 >> 16; + a[u3 + 3 >> 0] = f2 >> 24; + h2 = h2 + 4 | 0; + a[h2 >> 0] = b3; + a[h2 + 1 >> 0] = b3 >> 8; + a[h2 + 2 >> 0] = b3 >> 16; + a[h2 + 3 >> 0] = b3 >> 24; + c[g3 >> 2] = (c[g3 >> 2] | 0) + p2; + i = v3; + return; + } + function fb(b3, f2, g3, h2, j2) { + b3 = b3 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + var k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0; + x3 = i; + i = i + 1904 | 0; + p2 = x3; + w2 = x3 + 1632 | 0; + v3 = x3 + 1088 | 0; + nb(b3 + -1 | 0, h2, j2); + if (b3 >>> 0 <= 1) { + i = x3; + return; + } + t3 = f2 + -1 | 0; + u3 = (1 << t3) + -1 | 0; + o2 = t3 + b3 | 0; + ac(p2 | 0, 0, o2 << 2 | 0) | 0; + n2 = c[h2 >> 2] | 0; + k2 = j2 + (n2 >>> 3) | 0; + m3 = d[k2 >> 0] | 0; + n2 = cc(1, 0, n2 & 7 | 0) | 0; + l2 = C2; + n2 = m3 | n2; + m3 = k2; + a[m3 >> 0] = n2; + a[m3 + 1 >> 0] = n2 >> 8; + a[m3 + 2 >> 0] = n2 >> 16; + a[m3 + 3 >> 0] = n2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = l2; + a[k2 + 1 >> 0] = l2 >> 8; + a[k2 + 2 >> 0] = l2 >> 16; + a[k2 + 3 >> 0] = l2 >> 24; + k2 = (c[h2 >> 2] | 0) + 1 | 0; + c[h2 >> 2] = k2; + l2 = f2 + -2 | 0; + m3 = j2 + (k2 >>> 3) | 0; + n2 = d[m3 >> 0] | 0; + if (!((l2 & -16 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + q2 = cc(l2 | 0, 0, k2 & 7 | 0) | 0; + s2 = C2; + q2 = n2 | q2; + k2 = m3; + r2 = k2; + a[r2 >> 0] = q2; + a[r2 + 1 >> 0] = q2 >> 8; + a[r2 + 2 >> 0] = q2 >> 16; + a[r2 + 3 >> 0] = q2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = s2; + a[k2 + 1 >> 0] = s2 >> 8; + a[k2 + 2 >> 0] = s2 >> 16; + a[k2 + 3 >> 0] = s2 >> 24; + c[h2 >> 2] = (c[h2 >> 2] | 0) + 4; + c[p2 + (t3 << 2) >> 2] = b3; + c[p2 >> 2] = 1; + k2 = f2; + while (1) { + if (k2 >>> 0 >= o2 >>> 0) break; + c[p2 + (k2 << 2) >> 2] = 1; + k2 = k2 + 1 | 0; + } + kb(p2, o2, g3, w2, v3, h2, j2); + p2 = w2 + t3 | 0; + g3 = v3 + (t3 << 1) | 0; + q2 = bc(u3 | 0, 0, t3 | 0) | 0; + q2 = (q2 | 0) == 0 & (C2 | 0) == 0; + r2 = t3 >>> 0 < 57; + s2 = 0; + while (1) { + if (s2 >>> 0 >= b3 >>> 0) { + k2 = 22; + break; + } + l2 = (s2 | 0) == 0 ? 0 : s2 + f2 + -1 | 0; + k2 = a[w2 + l2 >> 0] | 0; + l2 = e[v3 + (l2 << 1) >> 1] | 0; + m3 = c[h2 >> 2] | 0; + n2 = j2 + (m3 >>> 3) | 0; + o2 = d[n2 >> 0] | 0; + y3 = bc(l2 | 0, 0, k2 & 255 | 0) | 0; + if (!((y3 | 0) == 0 & (C2 | 0) == 0)) { + k2 = 10; + break; + } + if ((k2 & 255) >= 57) { + k2 = 12; + break; + } + l2 = cc(l2 | 0, 0, m3 & 7 | 0) | 0; + m3 = C2; + o2 = o2 | l2; + l2 = n2; + n2 = l2; + a[n2 >> 0] = o2; + a[n2 + 1 >> 0] = o2 >> 8; + a[n2 + 2 >> 0] = o2 >> 16; + a[n2 + 3 >> 0] = o2 >> 24; + l2 = l2 + 4 | 0; + a[l2 >> 0] = m3; + a[l2 + 1 >> 0] = m3 >> 8; + a[l2 + 2 >> 0] = m3 >> 16; + a[l2 + 3 >> 0] = m3 >> 24; + k2 = (c[h2 >> 2] | 0) + (k2 & 255) | 0; + c[h2 >> 2] = k2; + l2 = a[p2 >> 0] | 0; + m3 = e[g3 >> 1] | 0; + n2 = j2 + (k2 >>> 3) | 0; + o2 = d[n2 >> 0] | 0; + y3 = bc(m3 | 0, 0, l2 & 255 | 0) | 0; + if (!((y3 | 0) == 0 & (C2 | 0) == 0)) { + k2 = 14; + break; + } + if ((l2 & 255) >= 57) { + k2 = 16; + break; + } + k2 = cc(m3 | 0, 0, k2 & 7 | 0) | 0; + m3 = C2; + o2 = o2 | k2; + k2 = n2; + y3 = k2; + a[y3 >> 0] = o2; + a[y3 + 1 >> 0] = o2 >> 8; + a[y3 + 2 >> 0] = o2 >> 16; + a[y3 + 3 >> 0] = o2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = m3; + a[k2 + 1 >> 0] = m3 >> 8; + a[k2 + 2 >> 0] = m3 >> 16; + a[k2 + 3 >> 0] = m3 >> 24; + k2 = (c[h2 >> 2] | 0) + (l2 & 255) | 0; + c[h2 >> 2] = k2; + l2 = j2 + (k2 >>> 3) | 0; + m3 = d[l2 >> 0] | 0; + if (!q2) { + k2 = 18; + break; + } + if (!r2) { + k2 = 20; + break; + } + y3 = cc(u3 | 0, 0, k2 & 7 | 0) | 0; + o2 = C2; + m3 = m3 | y3; + y3 = l2; + n2 = y3; + a[n2 >> 0] = m3; + a[n2 + 1 >> 0] = m3 >> 8; + a[n2 + 2 >> 0] = m3 >> 16; + a[n2 + 3 >> 0] = m3 >> 24; + y3 = y3 + 4 | 0; + a[y3 >> 0] = o2; + a[y3 + 1 >> 0] = o2 >> 8; + a[y3 + 2 >> 0] = o2 >> 16; + a[y3 + 3 >> 0] = o2 >> 24; + c[h2 >> 2] = (c[h2 >> 2] | 0) + t3; + s2 = s2 + 1 | 0; + } + if ((k2 | 0) == 10) pa2(406196, 406218, 54, 406251); + else if ((k2 | 0) == 12) pa2(406267, 406218, 55, 406251); + else if ((k2 | 0) == 14) pa2(406196, 406218, 54, 406251); + else if ((k2 | 0) == 16) pa2(406267, 406218, 55, 406251); + else if ((k2 | 0) == 18) pa2(406196, 406218, 54, 406251); + else if ((k2 | 0) == 20) pa2(406267, 406218, 55, 406251); + else if ((k2 | 0) == 22) { + w2 = c[h2 >> 2] | 0; + y3 = j2 + (w2 >>> 3) | 0; + b3 = d[y3 >> 0] | 0; + w2 = cc(1, 0, w2 & 7 | 0) | 0; + j2 = C2; + w2 = b3 | w2; + b3 = y3; + a[b3 >> 0] = w2; + a[b3 + 1 >> 0] = w2 >> 8; + a[b3 + 2 >> 0] = w2 >> 16; + a[b3 + 3 >> 0] = w2 >> 24; + y3 = y3 + 4 | 0; + a[y3 >> 0] = j2; + a[y3 + 1 >> 0] = j2 >> 8; + a[y3 + 2 >> 0] = j2 >> 16; + a[y3 + 3 >> 0] = j2 >> 24; + c[h2 >> 2] = (c[h2 >> 2] | 0) + 1; + i = x3; + return; + } + } + function gb(b3, f2, g3, h2, j2, k2, l2) { + b3 = b3 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + var m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0; + B3 = i; + i = i + 2160 | 0; + r2 = B3 + 1088 | 0; + v3 = B3; + A3 = B3 + 1888 | 0; + z3 = B3 + 1344 | 0; + nb(h2 + -1 | 0, k2, l2); + if ((h2 | 0) == 1) { + i = B3; + return; + } + x3 = b3 + 8 | 0; + y3 = sa2[c[b3 >> 2] & 1](c[x3 >> 2] | 0, g3 << 2) | 0; + if (!y3) oa2(1); + a: do + if (!g3) w2 = y3; + else { + m3 = c[f2 >> 2] | 0; + n2 = 1; + while (1) { + if ((n2 | 0) == (g3 | 0)) break; + u3 = c[f2 + (n2 << 2) >> 2] | 0; + m3 = u3 >>> 0 > m3 >>> 0 ? u3 : m3; + n2 = n2 + 1 | 0; + } + if (m3 >>> 0 < 256) o2 = 0; + else pa2(405316, 404333, 616, 405333); + while (1) { + if (o2 >>> 0 > m3 >>> 0) break; + a[r2 + o2 >> 0] = o2; + o2 = o2 + 1 | 0; + } + p2 = m3 + 1 | 0; + q2 = 0; + b: while (1) { + if (q2 >>> 0 >= g3 >>> 0) { + w2 = y3; + break a; + } + m3 = c[f2 + (q2 << 2) >> 2] & 255; + o2 = 0; + while (1) { + if (o2 >>> 0 >= p2 >>> 0) break b; + if ((a[r2 + o2 >> 0] | 0) == m3 << 24 >> 24) break; + o2 = o2 + 1 | 0; + } + c[y3 + (q2 << 2) >> 2] = o2; + n2 = a[r2 + o2 >> 0] | 0; + m3 = o2; + while (1) { + if (!m3) break; + u3 = m3 + -1 | 0; + a[r2 + m3 >> 0] = a[r2 + u3 >> 0] | 0; + m3 = u3; + } + a[r2 >> 0] = n2; + q2 = q2 + 1 | 0; + } + pa2(405354, 404333, 624, 405333); + } + while (0); + c[r2 >> 2] = 0; + m3 = 0; + o2 = 0; + while (1) { + if (m3 >>> 0 >= g3 >>> 0) break; + while (1) { + if (m3 >>> 0 >= g3 >>> 0) { + n2 = 0; + break; + } + if (!(c[w2 + (m3 << 2) >> 2] | 0)) { + n2 = 0; + break; + } + u3 = m3 + 1 | 0; + c[r2 >> 2] = u3; + m3 = u3; + } + while (1) { + if (m3 >>> 0 >= g3 >>> 0) break; + if (c[w2 + (m3 << 2) >> 2] | 0) break; + u3 = m3 + 1 | 0; + c[r2 >> 2] = u3; + m3 = u3; + n2 = n2 + 1 | 0; + } + o2 = n2 >>> 0 > o2 >>> 0 ? n2 : o2; + } + if (!o2) u3 = 0; + else { + u3 = (aa(o2 | 0) | 0) ^ 31; + u3 = u3 >>> 0 < 6 ? u3 : 6; + } + c[r2 >> 2] = 0; + p2 = 2 << u3; + q2 = u3 + ((512 << u3) + -512) | 0; + f2 = p2 + -1 | 0; + o2 = 0; + s2 = 0; + while (1) { + if (o2 >>> 0 >= g3 >>> 0) break; + if (s2 >>> 0 > o2 >>> 0) { + t3 = 38; + break; + } + m3 = c[w2 + (o2 << 2) >> 2] | 0; + c: do + if (!m3) { + m3 = o2; + n2 = 1; + while (1) { + m3 = m3 + 1 | 0; + if (m3 >>> 0 >= g3 >>> 0) break; + if (c[w2 + (m3 << 2) >> 2] | 0) break; + n2 = n2 + 1 | 0; + } + c[r2 >> 2] = o2 + n2; + m3 = s2; + while (1) { + if (!n2) break c; + if (n2 >>> 0 < p2 >>> 0) break; + c[w2 + (m3 << 2) >> 2] = q2; + m3 = m3 + 1 | 0; + n2 = n2 - f2 | 0; + } + s2 = (aa(n2 | 0) | 0) ^ 31; + c[w2 + (m3 << 2) >> 2] = s2 | n2 - (1 << s2) << 9; + m3 = m3 + 1 | 0; + } else { + c[w2 + (s2 << 2) >> 2] = m3 + u3; + c[r2 >> 2] = (c[r2 >> 2] | 0) + 1; + m3 = s2 + 1 | 0; + } + while (0); + o2 = c[r2 >> 2] | 0; + s2 = m3; + } + if ((t3 | 0) == 38) pa2(405282, 404333, 656, 405297); + ac(v3 | 0, 0, 1088) | 0; + m3 = 0; + while (1) { + if ((m3 | 0) == (s2 | 0)) break; + t3 = v3 + ((c[w2 + (m3 << 2) >> 2] & 511) << 2) | 0; + c[t3 >> 2] = (c[t3 >> 2] | 0) + 1; + m3 = m3 + 1 | 0; + } + t3 = (u3 | 0) != 0; + f2 = c[k2 >> 2] | 0; + m3 = l2 + (f2 >>> 3) | 0; + g3 = d[m3 >> 0] | 0; + f2 = cc(t3 & 1 | 0, 0, f2 & 7 | 0) | 0; + r2 = C2; + f2 = g3 | f2; + g3 = m3; + a[g3 >> 0] = f2; + a[g3 + 1 >> 0] = f2 >> 8; + a[g3 + 2 >> 0] = f2 >> 16; + a[g3 + 3 >> 0] = f2 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = r2; + a[m3 + 1 >> 0] = r2 >> 8; + a[m3 + 2 >> 0] = r2 >> 16; + a[m3 + 3 >> 0] = r2 >> 24; + m3 = (c[k2 >> 2] | 0) + 1 | 0; + c[k2 >> 2] = m3; + do + if (t3) { + n2 = u3 + -1 | 0; + o2 = l2 + (m3 >>> 3) | 0; + p2 = d[o2 >> 0] | 0; + if ((n2 & -16 | 0) == 0 & true) { + f2 = cc(n2 | 0, 0, m3 & 7 | 0) | 0; + r2 = C2; + f2 = p2 | f2; + t3 = o2; + g3 = t3; + a[g3 >> 0] = f2; + a[g3 + 1 >> 0] = f2 >> 8; + a[g3 + 2 >> 0] = f2 >> 16; + a[g3 + 3 >> 0] = f2 >> 24; + t3 = t3 + 4 | 0; + a[t3 >> 0] = r2; + a[t3 + 1 >> 0] = r2 >> 8; + a[t3 + 2 >> 0] = r2 >> 16; + a[t3 + 3 >> 0] = r2 >> 24; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 4; + break; + } else pa2(406196, 406218, 54, 406251); + } + while (0); + kb(v3, u3 + h2 | 0, j2, A3, z3, k2, l2); + r2 = 0; + while (1) { + if (r2 >>> 0 >= s2 >>> 0) { + t3 = 70; + break; + } + g3 = c[w2 + (r2 << 2) >> 2] | 0; + f2 = g3 & 511; + g3 = g3 >>> 9; + m3 = a[A3 + f2 >> 0] | 0; + n2 = e[z3 + (f2 << 1) >> 1] | 0; + o2 = c[k2 >> 2] | 0; + p2 = l2 + (o2 >>> 3) | 0; + q2 = d[p2 >> 0] | 0; + j2 = bc(n2 | 0, 0, m3 & 255 | 0) | 0; + if (!((j2 | 0) == 0 & (C2 | 0) == 0)) { + t3 = 60; + break; + } + if ((m3 & 255) >= 57) { + t3 = 62; + break; + } + t3 = cc(n2 | 0, 0, o2 & 7 | 0) | 0; + h2 = C2; + t3 = q2 | t3; + j2 = p2; + v3 = j2; + a[v3 >> 0] = t3; + a[v3 + 1 >> 0] = t3 >> 8; + a[v3 + 2 >> 0] = t3 >> 16; + a[v3 + 3 >> 0] = t3 >> 24; + j2 = j2 + 4 | 0; + a[j2 >> 0] = h2; + a[j2 + 1 >> 0] = h2 >> 8; + a[j2 + 2 >> 0] = h2 >> 16; + a[j2 + 3 >> 0] = h2 >> 24; + m3 = (c[k2 >> 2] | 0) + (m3 & 255) | 0; + c[k2 >> 2] = m3; + if (!((f2 | 0) == 0 | f2 >>> 0 > u3 >>> 0)) { + n2 = l2 + (m3 >>> 3) | 0; + o2 = d[n2 >> 0] | 0; + j2 = bc(g3 | 0, 0, f2 | 0) | 0; + if (!((j2 | 0) == 0 & (C2 | 0) == 0)) { + t3 = 65; + break; + } + if (f2 >>> 0 >= 57) { + t3 = 67; + break; + } + t3 = cc(g3 | 0, 0, m3 & 7 | 0) | 0; + h2 = C2; + t3 = o2 | t3; + j2 = n2; + v3 = j2; + a[v3 >> 0] = t3; + a[v3 + 1 >> 0] = t3 >> 8; + a[v3 + 2 >> 0] = t3 >> 16; + a[v3 + 3 >> 0] = t3 >> 24; + j2 = j2 + 4 | 0; + a[j2 >> 0] = h2; + a[j2 + 1 >> 0] = h2 >> 8; + a[j2 + 2 >> 0] = h2 >> 16; + a[j2 + 3 >> 0] = h2 >> 24; + c[k2 >> 2] = (c[k2 >> 2] | 0) + f2; + } + r2 = r2 + 1 | 0; + } + if ((t3 | 0) == 60) pa2(406196, 406218, 54, 406251); + else if ((t3 | 0) == 62) pa2(406267, 406218, 55, 406251); + else if ((t3 | 0) == 65) pa2(406196, 406218, 54, 406251); + else if ((t3 | 0) == 67) pa2(406267, 406218, 55, 406251); + else if ((t3 | 0) == 70) { + w2 = c[k2 >> 2] | 0; + l2 = l2 + (w2 >>> 3) | 0; + z3 = d[l2 >> 0] | 0; + w2 = cc(1, 0, w2 & 7 | 0) | 0; + A3 = C2; + w2 = z3 | w2; + z3 = l2; + a[z3 >> 0] = w2; + a[z3 + 1 >> 0] = w2 >> 8; + a[z3 + 2 >> 0] = w2 >> 16; + a[z3 + 3 >> 0] = w2 >> 24; + l2 = l2 + 4 | 0; + a[l2 >> 0] = A3; + a[l2 + 1 >> 0] = A3 >> 8; + a[l2 + 2 >> 0] = A3 >> 16; + a[l2 + 3 >> 0] = A3 >> 24; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + ra2[c[b3 + 4 >> 2] & 1](c[x3 >> 2] | 0, y3); + i = B3; + return; + } + } + function hb(b3, f2, g3, h2) { + b3 = b3 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + var i2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0; + s2 = b3 + 884 | 0; + i2 = c[s2 >> 2] | 0; + do + if (!i2) { + p2 = b3 + 880 | 0; + j2 = (c[p2 >> 2] | 0) + 1 | 0; + c[p2 >> 2] = j2; + p2 = c[(c[b3 + 12 >> 2] | 0) + (j2 << 2) >> 2] | 0; + j2 = a[(c[b3 + 8 >> 2] | 0) + j2 >> 0] | 0; + c[s2 >> 2] = p2; + j2 = j2 & 255; + q2 = b3 + 888 | 0; + c[q2 >> 2] = _(j2, c[b3 >> 2] | 0) | 0; + k2 = b3 + 20 | 0; + l2 = c[k2 >> 2] | 0; + i2 = b3 + 24 | 0; + if ((j2 | 0) == (l2 + 1 | 0)) m3 = 1; + else m3 = (j2 | 0) == (c[i2 >> 2] | 0) ? 0 : j2 + 2 | 0; + c[i2 >> 2] = l2; + c[k2 >> 2] = j2; + n2 = a[b3 + 28 + m3 >> 0] | 0; + i2 = e[b3 + 286 + (m3 << 1) >> 1] | 0; + j2 = c[g3 >> 2] | 0; + k2 = h2 + (j2 >>> 3) | 0; + l2 = d[k2 >> 0] | 0; + o2 = bc(i2 | 0, 0, n2 & 255 | 0) | 0; + if (!((o2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if ((n2 & 255) >= 57) pa2(406267, 406218, 55, 406251); + j2 = cc(i2 | 0, 0, j2 & 7 | 0) | 0; + m3 = C2; + j2 = l2 | j2; + o2 = k2; + l2 = o2; + a[l2 >> 0] = j2; + a[l2 + 1 >> 0] = j2 >> 8; + a[l2 + 2 >> 0] = j2 >> 16; + a[l2 + 3 >> 0] = j2 >> 24; + o2 = o2 + 4 | 0; + a[o2 >> 0] = m3; + a[o2 + 1 >> 0] = m3 >> 8; + a[o2 + 2 >> 0] = m3 >> 16; + a[o2 + 3 >> 0] = m3 >> 24; + c[g3 >> 2] = (c[g3 >> 2] | 0) + (n2 & 255); + if (p2 >>> 0 > 176) j2 = p2 >>> 0 > 752 ? 20 : 14; + else j2 = p2 >>> 0 > 40 ? 7 : 0; + while (1) { + if (j2 >>> 0 >= 25) break; + i2 = j2 + 1 | 0; + if (p2 >>> 0 < (c[17556 + (i2 << 3) >> 2] | 0) >>> 0) break; + else j2 = i2; + } + o2 = c[17556 + (j2 << 3) + 4 >> 2] | 0; + n2 = p2 - (c[17556 + (j2 << 3) >> 2] | 0) | 0; + m3 = a[b3 + 802 + j2 >> 0] | 0; + i2 = e[b3 + 828 + (j2 << 1) >> 1] | 0; + j2 = c[g3 >> 2] | 0; + k2 = h2 + (j2 >>> 3) | 0; + l2 = d[k2 >> 0] | 0; + p2 = bc(i2 | 0, 0, m3 & 255 | 0) | 0; + if (!((p2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if ((m3 & 255) >= 57) pa2(406267, 406218, 55, 406251); + p2 = cc(i2 | 0, 0, j2 & 7 | 0) | 0; + i2 = C2; + p2 = l2 | p2; + j2 = k2; + k2 = j2; + a[k2 >> 0] = p2; + a[k2 + 1 >> 0] = p2 >> 8; + a[k2 + 2 >> 0] = p2 >> 16; + a[k2 + 3 >> 0] = p2 >> 24; + j2 = j2 + 4 | 0; + a[j2 >> 0] = i2; + a[j2 + 1 >> 0] = i2 >> 8; + a[j2 + 2 >> 0] = i2 >> 16; + a[j2 + 3 >> 0] = i2 >> 24; + j2 = (c[g3 >> 2] | 0) + (m3 & 255) | 0; + c[g3 >> 2] = j2; + k2 = h2 + (j2 >>> 3) | 0; + i2 = d[k2 >> 0] | 0; + p2 = bc(n2 | 0, 0, o2 | 0) | 0; + if ((p2 | 0) == 0 & (C2 | 0) == 0) { + n2 = cc(n2 | 0, 0, j2 & 7 | 0) | 0; + t3 = C2; + n2 = i2 | n2; + r2 = k2; + p2 = r2; + a[p2 >> 0] = n2; + a[p2 + 1 >> 0] = n2 >> 8; + a[p2 + 2 >> 0] = n2 >> 16; + a[p2 + 3 >> 0] = n2 >> 24; + r2 = r2 + 4 | 0; + a[r2 >> 0] = t3; + a[r2 + 1 >> 0] = t3 >> 8; + a[r2 + 2 >> 0] = t3 >> 16; + a[r2 + 3 >> 0] = t3 >> 24; + c[g3 >> 2] = (c[g3 >> 2] | 0) + o2; + r2 = q2; + t3 = c[s2 >> 2] | 0; + break; + } else pa2(406196, 406218, 54, 406251); + } else { + r2 = b3 + 888 | 0; + t3 = i2; + } + while (0); + c[s2 >> 2] = t3 + -1; + k2 = (c[r2 >> 2] | 0) + f2 | 0; + m3 = a[(c[b3 + 892 >> 2] | 0) + k2 >> 0] | 0; + k2 = e[(c[b3 + 896 >> 2] | 0) + (k2 << 1) >> 1] | 0; + l2 = c[g3 >> 2] | 0; + i2 = h2 + (l2 >>> 3) | 0; + j2 = d[i2 >> 0] | 0; + h2 = bc(k2 | 0, 0, m3 & 255 | 0) | 0; + if (!((h2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if ((m3 & 255) < 57) { + t3 = cc(k2 | 0, 0, l2 & 7 | 0) | 0; + b3 = C2; + t3 = j2 | t3; + h2 = i2; + f2 = h2; + a[f2 >> 0] = t3; + a[f2 + 1 >> 0] = t3 >> 8; + a[f2 + 2 >> 0] = t3 >> 16; + a[f2 + 3 >> 0] = t3 >> 24; + h2 = h2 + 4 | 0; + a[h2 >> 0] = b3; + a[h2 + 1 >> 0] = b3 >> 8; + a[h2 + 2 >> 0] = b3 >> 16; + a[h2 + 3 >> 0] = b3 >> 24; + c[g3 >> 2] = (c[g3 >> 2] | 0) + (m3 & 255); + return; + } else pa2(406267, 406218, 55, 406251); + } + function ib(b3, f2, g3, h2, i2, j2, k2) { + b3 = b3 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + i2 = i2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + var l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0; + u3 = b3 + 884 | 0; + l2 = c[u3 >> 2] | 0; + do + if (!l2) { + r2 = b3 + 880 | 0; + n2 = (c[r2 >> 2] | 0) + 1 | 0; + c[r2 >> 2] = n2; + r2 = c[(c[b3 + 12 >> 2] | 0) + (n2 << 2) >> 2] | 0; + n2 = a[(c[b3 + 8 >> 2] | 0) + n2 >> 0] | 0; + c[u3 >> 2] = r2; + n2 = n2 & 255; + s2 = b3 + 888 | 0; + c[s2 >> 2] = n2 << k2; + k2 = b3 + 20 | 0; + m3 = c[k2 >> 2] | 0; + l2 = b3 + 24 | 0; + if ((n2 | 0) == (m3 + 1 | 0)) o2 = 1; + else o2 = (n2 | 0) == (c[l2 >> 2] | 0) ? 0 : n2 + 2 | 0; + c[l2 >> 2] = m3; + c[k2 >> 2] = n2; + p2 = a[b3 + 28 + o2 >> 0] | 0; + l2 = e[b3 + 286 + (o2 << 1) >> 1] | 0; + k2 = c[i2 >> 2] | 0; + m3 = j2 + (k2 >>> 3) | 0; + n2 = d[m3 >> 0] | 0; + q2 = bc(l2 | 0, 0, p2 & 255 | 0) | 0; + if (!((q2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if ((p2 & 255) >= 57) pa2(406267, 406218, 55, 406251); + k2 = cc(l2 | 0, 0, k2 & 7 | 0) | 0; + o2 = C2; + k2 = n2 | k2; + q2 = m3; + n2 = q2; + a[n2 >> 0] = k2; + a[n2 + 1 >> 0] = k2 >> 8; + a[n2 + 2 >> 0] = k2 >> 16; + a[n2 + 3 >> 0] = k2 >> 24; + q2 = q2 + 4 | 0; + a[q2 >> 0] = o2; + a[q2 + 1 >> 0] = o2 >> 8; + a[q2 + 2 >> 0] = o2 >> 16; + a[q2 + 3 >> 0] = o2 >> 24; + c[i2 >> 2] = (c[i2 >> 2] | 0) + (p2 & 255); + if (r2 >>> 0 > 176) k2 = r2 >>> 0 > 752 ? 20 : 14; + else k2 = r2 >>> 0 > 40 ? 7 : 0; + while (1) { + if (k2 >>> 0 >= 25) break; + l2 = k2 + 1 | 0; + if (r2 >>> 0 < (c[17556 + (l2 << 3) >> 2] | 0) >>> 0) break; + else k2 = l2; + } + q2 = c[17556 + (k2 << 3) + 4 >> 2] | 0; + p2 = r2 - (c[17556 + (k2 << 3) >> 2] | 0) | 0; + o2 = a[b3 + 802 + k2 >> 0] | 0; + l2 = e[b3 + 828 + (k2 << 1) >> 1] | 0; + k2 = c[i2 >> 2] | 0; + m3 = j2 + (k2 >>> 3) | 0; + n2 = d[m3 >> 0] | 0; + r2 = bc(l2 | 0, 0, o2 & 255 | 0) | 0; + if (!((r2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if ((o2 & 255) >= 57) pa2(406267, 406218, 55, 406251); + r2 = cc(l2 | 0, 0, k2 & 7 | 0) | 0; + k2 = C2; + r2 = n2 | r2; + l2 = m3; + m3 = l2; + a[m3 >> 0] = r2; + a[m3 + 1 >> 0] = r2 >> 8; + a[m3 + 2 >> 0] = r2 >> 16; + a[m3 + 3 >> 0] = r2 >> 24; + l2 = l2 + 4 | 0; + a[l2 >> 0] = k2; + a[l2 + 1 >> 0] = k2 >> 8; + a[l2 + 2 >> 0] = k2 >> 16; + a[l2 + 3 >> 0] = k2 >> 24; + l2 = (c[i2 >> 2] | 0) + (o2 & 255) | 0; + c[i2 >> 2] = l2; + k2 = j2 + (l2 >>> 3) | 0; + m3 = d[k2 >> 0] | 0; + r2 = bc(p2 | 0, 0, q2 | 0) | 0; + if ((r2 | 0) == 0 & (C2 | 0) == 0) { + p2 = cc(p2 | 0, 0, l2 & 7 | 0) | 0; + v3 = C2; + p2 = m3 | p2; + t3 = k2; + r2 = t3; + a[r2 >> 0] = p2; + a[r2 + 1 >> 0] = p2 >> 8; + a[r2 + 2 >> 0] = p2 >> 16; + a[r2 + 3 >> 0] = p2 >> 24; + t3 = t3 + 4 | 0; + a[t3 >> 0] = v3; + a[t3 + 1 >> 0] = v3 >> 8; + a[t3 + 2 >> 0] = v3 >> 16; + a[t3 + 3 >> 0] = v3 >> 24; + c[i2 >> 2] = (c[i2 >> 2] | 0) + q2; + t3 = s2; + v3 = c[u3 >> 2] | 0; + break; + } else pa2(406196, 406218, 54, 406251); + } else { + t3 = b3 + 888 | 0; + v3 = l2; + } + while (0); + c[u3 >> 2] = v3 + -1; + m3 = (_(c[h2 + ((c[t3 >> 2] | 0) + g3 << 2) >> 2] | 0, c[b3 >> 2] | 0) | 0) + f2 | 0; + o2 = a[(c[b3 + 892 >> 2] | 0) + m3 >> 0] | 0; + m3 = e[(c[b3 + 896 >> 2] | 0) + (m3 << 1) >> 1] | 0; + n2 = c[i2 >> 2] | 0; + l2 = j2 + (n2 >>> 3) | 0; + k2 = d[l2 >> 0] | 0; + j2 = bc(m3 | 0, 0, o2 & 255 | 0) | 0; + if (!((j2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if ((o2 & 255) < 57) { + h2 = cc(m3 | 0, 0, n2 & 7 | 0) | 0; + b3 = C2; + h2 = k2 | h2; + j2 = l2; + f2 = j2; + a[f2 >> 0] = h2; + a[f2 + 1 >> 0] = h2 >> 8; + a[f2 + 2 >> 0] = h2 >> 16; + a[f2 + 3 >> 0] = h2 >> 24; + j2 = j2 + 4 | 0; + a[j2 >> 0] = b3; + a[j2 + 1 >> 0] = b3 >> 8; + a[j2 + 2 >> 0] = b3 >> 16; + a[j2 + 3 >> 0] = b3 >> 24; + c[i2 >> 2] = (c[i2 >> 2] | 0) + (o2 & 255); + return; + } else pa2(406267, 406218, 55, 406251); + } + function jb(a2, b3, e2, f2, g3, h2, i2, j2) { + a2 = a2 | 0; + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + i2 = i2 | 0; + j2 = j2 | 0; + var k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0; + r2 = i2 + 2816 | 0; + s2 = h2 + 1024 | 0; + t3 = j2 + 2080 | 0; + q2 = 0; + while (1) { + if ((q2 | 0) == (g3 | 0)) break; + o2 = c[f2 + (q2 << 4) >> 2] | 0; + k2 = c[f2 + (q2 << 4) + 4 >> 2] | 0; + l2 = c[f2 + (q2 << 4) + 12 >> 2] | 0; + p2 = l2 & 65535; + n2 = l2 >>> 16; + l2 = i2 + ((l2 & 65535) << 2) | 0; + c[l2 >> 2] = (c[l2 >> 2] | 0) + 1; + c[r2 >> 2] = (c[r2 >> 2] | 0) + 1; + l2 = b3; + m3 = o2; + while (1) { + if (!m3) break; + u3 = h2 + ((d[a2 + (l2 & e2) >> 0] | 0) << 2) | 0; + c[u3 >> 2] = (c[u3 >> 2] | 0) + 1; + c[s2 >> 2] = (c[s2 >> 2] | 0) + 1; + l2 = l2 + 1 | 0; + m3 = m3 + -1 | 0; + } + k2 = k2 & 16777215; + if ((k2 | 0) != 0 & (p2 & 65535) > 127) { + u3 = j2 + (n2 << 2) | 0; + c[u3 >> 2] = (c[u3 >> 2] | 0) + 1; + c[t3 >> 2] = (c[t3 >> 2] | 0) + 1; + } + b3 = b3 + o2 + k2 | 0; + q2 = q2 + 1 | 0; + } + return; + } + function kb(e2, f2, g3, h2, j2, k2, l2) { + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + var m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0; + s2 = i; + i = i + 16 | 0; + q2 = s2; + c[q2 >> 2] = 0; + c[q2 + 4 >> 2] = 0; + c[q2 + 8 >> 2] = 0; + c[q2 + 12 >> 2] = 0; + p2 = 0; + n2 = 0; + while (1) { + if (n2 >>> 0 >= f2 >>> 0) break; + if (!(c[e2 + (n2 << 2) >> 2] | 0)) m3 = p2; + else { + if (p2 >>> 0 >= 4) { + if (p2 >>> 0 > 4) break; + } else c[q2 + (p2 << 2) >> 2] = n2; + m3 = p2 + 1 | 0; + } + p2 = m3; + n2 = n2 + 1 | 0; + } + r2 = 0; + m3 = f2 + -1 | 0; + while (1) { + if (!m3) break; + r2 = r2 + 1 | 0; + m3 = m3 >>> 1; + } + if (p2 >>> 0 < 2) { + n2 = c[k2 >> 2] | 0; + e2 = l2 + (n2 >>> 3) | 0; + m3 = d[e2 >> 0] | 0; + n2 = cc(1, 0, n2 & 7 | 0) | 0; + f2 = C2; + n2 = m3 | n2; + m3 = e2; + a[m3 >> 0] = n2; + a[m3 + 1 >> 0] = n2 >> 8; + a[m3 + 2 >> 0] = n2 >> 16; + a[m3 + 3 >> 0] = n2 >> 24; + e2 = e2 + 4 | 0; + a[e2 >> 0] = f2; + a[e2 + 1 >> 0] = f2 >> 8; + a[e2 + 2 >> 0] = f2 >> 16; + a[e2 + 3 >> 0] = f2 >> 24; + e2 = (c[k2 >> 2] | 0) + 4 | 0; + c[k2 >> 2] = e2; + f2 = c[q2 >> 2] | 0; + m3 = l2 + (e2 >>> 3) | 0; + n2 = d[m3 >> 0] | 0; + l2 = bc(f2 | 0, 0, r2 | 0) | 0; + if (!((l2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (r2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + g3 = cc(f2 | 0, 0, e2 & 7 | 0) | 0; + p2 = C2; + g3 = n2 | g3; + l2 = m3; + o2 = l2; + a[o2 >> 0] = g3; + a[o2 + 1 >> 0] = g3 >> 8; + a[o2 + 2 >> 0] = g3 >> 16; + a[o2 + 3 >> 0] = g3 >> 24; + l2 = l2 + 4 | 0; + a[l2 >> 0] = p2; + a[l2 + 1 >> 0] = p2 >> 8; + a[l2 + 2 >> 0] = p2 >> 16; + a[l2 + 3 >> 0] = p2 >> 24; + c[k2 >> 2] = (c[k2 >> 2] | 0) + r2; + a[h2 + (c[q2 >> 2] | 0) >> 0] = 0; + b2[j2 + (c[q2 >> 2] << 1) >> 1] = 0; + i = s2; + return; + } + ac(h2 | 0, 0, f2 | 0) | 0; + Hb(e2, f2, 15, g3, h2); + Jb(h2, f2, j2); + if (p2 >>> 0 >= 5) { + _a(h2, f2, g3, k2, l2); + i = s2; + return; + } + m3 = l2 + ((c[k2 >> 2] | 0) >>> 3) | 0; + e2 = d[m3 >> 0] | 0; + f2 = cc(1, 0, c[k2 >> 2] & 7 | 0) | 0; + n2 = C2; + f2 = e2 | f2; + e2 = m3; + a[e2 >> 0] = f2; + a[e2 + 1 >> 0] = f2 >> 8; + a[e2 + 2 >> 0] = f2 >> 16; + a[e2 + 3 >> 0] = f2 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = n2; + a[m3 + 1 >> 0] = n2 >> 8; + a[m3 + 2 >> 0] = n2 >> 16; + a[m3 + 3 >> 0] = n2 >> 24; + m3 = (c[k2 >> 2] | 0) + 2 | 0; + c[k2 >> 2] = m3; + n2 = p2 + -1 | 0; + e2 = l2 + (m3 >>> 3) | 0; + f2 = d[e2 >> 0] | 0; + if (!((n2 & -4 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + g3 = cc(n2 | 0, 0, m3 & 7 | 0) | 0; + j2 = C2; + g3 = f2 | g3; + f2 = e2; + o2 = f2; + a[o2 >> 0] = g3; + a[o2 + 1 >> 0] = g3 >> 8; + a[o2 + 2 >> 0] = g3 >> 16; + a[o2 + 3 >> 0] = g3 >> 24; + f2 = f2 + 4 | 0; + a[f2 >> 0] = j2; + a[f2 + 1 >> 0] = j2 >> 8; + a[f2 + 2 >> 0] = j2 >> 16; + a[f2 + 3 >> 0] = j2 >> 24; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 2; + f2 = p2 + -1 | 0; + j2 = 0; + while (1) { + if ((j2 | 0) == (p2 | 0)) break; + g3 = q2 + (j2 << 2) | 0; + m3 = j2; + while (1) { + o2 = m3 + 1 | 0; + if ((m3 | 0) == (f2 | 0)) break; + m3 = q2 + (o2 << 2) | 0; + n2 = c[m3 >> 2] | 0; + e2 = c[g3 >> 2] | 0; + if ((d[h2 + n2 >> 0] | 0) >= (d[h2 + e2 >> 0] | 0)) { + m3 = o2; + continue; + } + c[m3 >> 2] = e2; + c[g3 >> 2] = n2; + m3 = o2; + } + j2 = j2 + 1 | 0; + } + switch (p2 | 0) { + case 2: { + m3 = c[q2 >> 2] | 0; + n2 = c[k2 >> 2] | 0; + e2 = l2 + (n2 >>> 3) | 0; + f2 = d[e2 >> 0] | 0; + if (!((bc(m3 | 0, 0, r2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (r2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + n2 = cc(m3 | 0, 0, n2 & 7 | 0) | 0; + m3 = C2; + n2 = f2 | n2; + f2 = e2; + e2 = f2; + a[e2 >> 0] = n2; + a[e2 + 1 >> 0] = n2 >> 8; + a[e2 + 2 >> 0] = n2 >> 16; + a[e2 + 3 >> 0] = n2 >> 24; + f2 = f2 + 4 | 0; + a[f2 >> 0] = m3; + a[f2 + 1 >> 0] = m3 >> 8; + a[f2 + 2 >> 0] = m3 >> 16; + a[f2 + 3 >> 0] = m3 >> 24; + f2 = (c[k2 >> 2] | 0) + r2 | 0; + c[k2 >> 2] = f2; + e2 = c[q2 + 4 >> 2] | 0; + m3 = l2 + (f2 >>> 3) | 0; + n2 = d[m3 >> 0] | 0; + if (!((bc(e2 | 0, 0, r2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + p2 = cc(e2 | 0, 0, f2 & 7 | 0) | 0; + q2 = C2; + p2 = n2 | p2; + l2 = m3; + h2 = l2; + a[h2 >> 0] = p2; + a[h2 + 1 >> 0] = p2 >> 8; + a[h2 + 2 >> 0] = p2 >> 16; + a[h2 + 3 >> 0] = p2 >> 24; + l2 = l2 + 4 | 0; + a[l2 >> 0] = q2; + a[l2 + 1 >> 0] = q2 >> 8; + a[l2 + 2 >> 0] = q2 >> 16; + a[l2 + 3 >> 0] = q2 >> 24; + c[k2 >> 2] = (c[k2 >> 2] | 0) + r2; + i = s2; + return; + } + case 3: { + m3 = c[q2 >> 2] | 0; + n2 = c[k2 >> 2] | 0; + e2 = l2 + (n2 >>> 3) | 0; + f2 = d[e2 >> 0] | 0; + if (!((bc(m3 | 0, 0, r2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (r2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + m3 = cc(m3 | 0, 0, n2 & 7 | 0) | 0; + n2 = C2; + f2 = f2 | m3; + m3 = e2; + e2 = m3; + a[e2 >> 0] = f2; + a[e2 + 1 >> 0] = f2 >> 8; + a[e2 + 2 >> 0] = f2 >> 16; + a[e2 + 3 >> 0] = f2 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = n2; + a[m3 + 1 >> 0] = n2 >> 8; + a[m3 + 2 >> 0] = n2 >> 16; + a[m3 + 3 >> 0] = n2 >> 24; + m3 = (c[k2 >> 2] | 0) + r2 | 0; + c[k2 >> 2] = m3; + n2 = c[q2 + 4 >> 2] | 0; + e2 = l2 + (m3 >>> 3) | 0; + f2 = d[e2 >> 0] | 0; + if (!((bc(n2 | 0, 0, r2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + n2 = cc(n2 | 0, 0, m3 & 7 | 0) | 0; + m3 = C2; + n2 = f2 | n2; + f2 = e2; + e2 = f2; + a[e2 >> 0] = n2; + a[e2 + 1 >> 0] = n2 >> 8; + a[e2 + 2 >> 0] = n2 >> 16; + a[e2 + 3 >> 0] = n2 >> 24; + f2 = f2 + 4 | 0; + a[f2 >> 0] = m3; + a[f2 + 1 >> 0] = m3 >> 8; + a[f2 + 2 >> 0] = m3 >> 16; + a[f2 + 3 >> 0] = m3 >> 24; + f2 = (c[k2 >> 2] | 0) + r2 | 0; + c[k2 >> 2] = f2; + e2 = c[q2 + 8 >> 2] | 0; + m3 = l2 + (f2 >>> 3) | 0; + n2 = d[m3 >> 0] | 0; + if (!((bc(e2 | 0, 0, r2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + p2 = cc(e2 | 0, 0, f2 & 7 | 0) | 0; + q2 = C2; + p2 = n2 | p2; + l2 = m3; + h2 = l2; + a[h2 >> 0] = p2; + a[h2 + 1 >> 0] = p2 >> 8; + a[h2 + 2 >> 0] = p2 >> 16; + a[h2 + 3 >> 0] = p2 >> 24; + l2 = l2 + 4 | 0; + a[l2 >> 0] = q2; + a[l2 + 1 >> 0] = q2 >> 8; + a[l2 + 2 >> 0] = q2 >> 16; + a[l2 + 3 >> 0] = q2 >> 24; + c[k2 >> 2] = (c[k2 >> 2] | 0) + r2; + i = s2; + return; + } + default: { + m3 = c[q2 >> 2] | 0; + n2 = c[k2 >> 2] | 0; + e2 = l2 + (n2 >>> 3) | 0; + f2 = d[e2 >> 0] | 0; + if (!((bc(m3 | 0, 0, r2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (r2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + m3 = cc(m3 | 0, 0, n2 & 7 | 0) | 0; + n2 = C2; + f2 = f2 | m3; + m3 = e2; + e2 = m3; + a[e2 >> 0] = f2; + a[e2 + 1 >> 0] = f2 >> 8; + a[e2 + 2 >> 0] = f2 >> 16; + a[e2 + 3 >> 0] = f2 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = n2; + a[m3 + 1 >> 0] = n2 >> 8; + a[m3 + 2 >> 0] = n2 >> 16; + a[m3 + 3 >> 0] = n2 >> 24; + m3 = (c[k2 >> 2] | 0) + r2 | 0; + c[k2 >> 2] = m3; + n2 = c[q2 + 4 >> 2] | 0; + e2 = l2 + (m3 >>> 3) | 0; + f2 = d[e2 >> 0] | 0; + if (!((bc(n2 | 0, 0, r2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + m3 = cc(n2 | 0, 0, m3 & 7 | 0) | 0; + n2 = C2; + f2 = f2 | m3; + m3 = e2; + e2 = m3; + a[e2 >> 0] = f2; + a[e2 + 1 >> 0] = f2 >> 8; + a[e2 + 2 >> 0] = f2 >> 16; + a[e2 + 3 >> 0] = f2 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = n2; + a[m3 + 1 >> 0] = n2 >> 8; + a[m3 + 2 >> 0] = n2 >> 16; + a[m3 + 3 >> 0] = n2 >> 24; + m3 = (c[k2 >> 2] | 0) + r2 | 0; + c[k2 >> 2] = m3; + n2 = c[q2 + 8 >> 2] | 0; + e2 = l2 + (m3 >>> 3) | 0; + f2 = d[e2 >> 0] | 0; + if (!((bc(n2 | 0, 0, r2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + m3 = cc(n2 | 0, 0, m3 & 7 | 0) | 0; + n2 = C2; + f2 = f2 | m3; + m3 = e2; + e2 = m3; + a[e2 >> 0] = f2; + a[e2 + 1 >> 0] = f2 >> 8; + a[e2 + 2 >> 0] = f2 >> 16; + a[e2 + 3 >> 0] = f2 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = n2; + a[m3 + 1 >> 0] = n2 >> 8; + a[m3 + 2 >> 0] = n2 >> 16; + a[m3 + 3 >> 0] = n2 >> 24; + m3 = (c[k2 >> 2] | 0) + r2 | 0; + c[k2 >> 2] = m3; + n2 = c[q2 + 12 >> 2] | 0; + e2 = l2 + (m3 >>> 3) | 0; + f2 = d[e2 >> 0] | 0; + if (!((bc(n2 | 0, 0, r2 | 0) | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + g3 = cc(n2 | 0, 0, m3 & 7 | 0) | 0; + p2 = C2; + g3 = f2 | g3; + o2 = e2; + j2 = o2; + a[j2 >> 0] = g3; + a[j2 + 1 >> 0] = g3 >> 8; + a[j2 + 2 >> 0] = g3 >> 16; + a[j2 + 3 >> 0] = g3 >> 24; + o2 = o2 + 4 | 0; + a[o2 >> 0] = p2; + a[o2 + 1 >> 0] = p2 >> 8; + a[o2 + 2 >> 0] = p2 >> 16; + a[o2 + 3 >> 0] = p2 >> 24; + o2 = (c[k2 >> 2] | 0) + r2 | 0; + c[k2 >> 2] = o2; + r2 = l2 + (o2 >>> 3) | 0; + p2 = d[r2 >> 0] | 0; + h2 = cc((a[h2 + (c[q2 >> 2] | 0) >> 0] | 0) == 1 | 0, 0, o2 & 7 | 0) | 0; + l2 = C2; + h2 = p2 | h2; + q2 = r2; + a[q2 >> 0] = h2; + a[q2 + 1 >> 0] = h2 >> 8; + a[q2 + 2 >> 0] = h2 >> 16; + a[q2 + 3 >> 0] = h2 >> 24; + r2 = r2 + 4 | 0; + a[r2 >> 0] = l2; + a[r2 + 1 >> 0] = l2 >> 8; + a[r2 + 2 >> 0] = l2 >> 16; + a[r2 + 3 >> 0] = l2 >> 24; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + i = s2; + return; + } + } + } + function lb(b3, f2, g3, h2, i2, j2, k2, l2, m3, n2, o2, p2, q2) { + b3 = b3 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + i2 = i2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + var r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0; + E3 = 0; + a: while (1) { + if (E3 >>> 0 >= i2 >>> 0) { + f2 = 42; + break; + } + y3 = c[h2 + (E3 << 4) >> 2] | 0; + w2 = c[h2 + (E3 << 4) + 4 >> 2] | 0; + D3 = c[h2 + (E3 << 4) + 8 >> 2] | 0; + s2 = c[h2 + (E3 << 4) + 12 >> 2] | 0; + A3 = s2 & 65535; + B3 = s2 >>> 16; + s2 = s2 & 65535; + r2 = a[l2 + s2 >> 0] | 0; + s2 = e[m3 + (s2 << 1) >> 1] | 0; + t3 = c[p2 >> 2] | 0; + u3 = q2 + (t3 >>> 3) | 0; + v3 = d[u3 >> 0] | 0; + z3 = bc(s2 | 0, 0, r2 & 255 | 0) | 0; + if (!((z3 | 0) == 0 & (C2 | 0) == 0)) { + f2 = 4; + break; + } + if ((r2 & 255) >= 57) { + f2 = 6; + break; + } + x3 = cc(s2 | 0, 0, t3 & 7 | 0) | 0; + z3 = C2; + v3 = v3 | x3; + x3 = u3; + t3 = x3; + a[t3 >> 0] = v3; + a[t3 + 1 >> 0] = v3 >> 8; + a[t3 + 2 >> 0] = v3 >> 16; + a[t3 + 3 >> 0] = v3 >> 24; + x3 = x3 + 4 | 0; + a[x3 >> 0] = z3; + a[x3 + 1 >> 0] = z3 >> 8; + a[x3 + 2 >> 0] = z3 >> 16; + a[x3 + 3 >> 0] = z3 >> 24; + x3 = (c[p2 >> 2] | 0) + (r2 & 255) | 0; + c[p2 >> 2] = x3; + z3 = w2 & 16777215; + t3 = z3 ^ w2 >>> 24; + do + if (y3 >>> 0 >= 6) { + if (y3 >>> 0 < 130) { + w2 = y3 + -2 | 0; + s2 = ((aa(w2 | 0) | 0) ^ 31) + -1 | 0; + s2 = (s2 << 1) + (w2 >>> s2) + 2 | 0; + break; + } + if (y3 >>> 0 < 2114) { + s2 = ((aa(y3 + -66 | 0) | 0) ^ 31) + 10 | 0; + break; + } + if (y3 >>> 0 < 6210) s2 = 21; + else s2 = y3 >>> 0 < 22594 ? 22 : 23; + } else s2 = y3; + while (0); + do + if (t3 >>> 0 >= 10) { + if (t3 >>> 0 < 134) { + w2 = t3 + -6 | 0; + r2 = ((aa(w2 | 0) | 0) ^ 31) + -1 | 0; + r2 = (r2 << 1) + (w2 >>> r2) + 4 | 0; + break; + } + if (t3 >>> 0 < 2118) r2 = ((aa(t3 + -70 | 0) | 0) ^ 31) + 12 | 0; + else r2 = 23; + } else r2 = t3 + 65534 | 0; + while (0); + s2 = s2 & 65535; + v3 = c[17268 + (s2 << 2) >> 2] | 0; + s2 = y3 - (c[18788 + (s2 << 2) >> 2] | 0) | 0; + u3 = r2 & 65535; + t3 = cc(t3 - (c[17364 + (u3 << 2) >> 2] | 0) | 0, 0, v3 | 0) | 0; + r2 = C2; + s2 = t3 | s2; + t3 = v3 + (c[17460 + (u3 << 2) >> 2] | 0) | 0; + u3 = q2 + (x3 >>> 3) | 0; + v3 = d[u3 >> 0] | 0; + w2 = bc(s2 | 0, r2 | 0, t3 | 0) | 0; + if (!((w2 | 0) == 0 & (C2 | 0) == 0)) { + f2 = 21; + break; + } + if (t3 >>> 0 >= 57) { + f2 = 23; + break; + } + s2 = cc(s2 | 0, r2 | 0, x3 & 7 | 0) | 0; + w2 = C2; + s2 = v3 | s2; + x3 = u3; + v3 = x3; + a[v3 >> 0] = s2; + a[v3 + 1 >> 0] = s2 >> 8; + a[v3 + 2 >> 0] = s2 >> 16; + a[v3 + 3 >> 0] = s2 >> 24; + x3 = x3 + 4 | 0; + a[x3 >> 0] = w2; + a[x3 + 1 >> 0] = w2 >> 8; + a[x3 + 2 >> 0] = w2 >> 16; + a[x3 + 3 >> 0] = w2 >> 24; + x3 = (c[p2 >> 2] | 0) + t3 | 0; + c[p2 >> 2] = x3; + v3 = y3; + while (1) { + if (!v3) break; + s2 = d[b3 + (f2 & g3) >> 0] | 0; + r2 = a[j2 + s2 >> 0] | 0; + s2 = e[k2 + (s2 << 1) >> 1] | 0; + t3 = q2 + (x3 >>> 3) | 0; + u3 = d[t3 >> 0] | 0; + y3 = bc(s2 | 0, 0, r2 & 255 | 0) | 0; + if (!((y3 | 0) == 0 & (C2 | 0) == 0)) { + f2 = 27; + break a; + } + if ((r2 & 255) >= 57) { + f2 = 29; + break a; + } + s2 = cc(s2 | 0, 0, x3 & 7 | 0) | 0; + w2 = C2; + s2 = u3 | s2; + y3 = t3; + u3 = y3; + a[u3 >> 0] = s2; + a[u3 + 1 >> 0] = s2 >> 8; + a[u3 + 2 >> 0] = s2 >> 16; + a[u3 + 3 >> 0] = s2 >> 24; + y3 = y3 + 4 | 0; + a[y3 >> 0] = w2; + a[y3 + 1 >> 0] = w2 >> 8; + a[y3 + 2 >> 0] = w2 >> 16; + a[y3 + 3 >> 0] = w2 >> 24; + y3 = (c[p2 >> 2] | 0) + (r2 & 255) | 0; + c[p2 >> 2] = y3; + x3 = y3; + f2 = f2 + 1 | 0; + v3 = v3 + -1 | 0; + } + f2 = f2 + z3 | 0; + if ((z3 | 0) != 0 & (A3 & 65535) > 127) { + v3 = D3 >>> 24; + w2 = D3 & 16777215; + u3 = a[n2 + B3 >> 0] | 0; + r2 = e[o2 + (B3 << 1) >> 1] | 0; + s2 = q2 + (x3 >>> 3) | 0; + t3 = d[s2 >> 0] | 0; + B3 = bc(r2 | 0, 0, u3 & 255 | 0) | 0; + if (!((B3 | 0) == 0 & (C2 | 0) == 0)) { + f2 = 33; + break; + } + if ((u3 & 255) >= 57) { + f2 = 35; + break; + } + r2 = cc(r2 | 0, 0, x3 & 7 | 0) | 0; + B3 = C2; + t3 = t3 | r2; + r2 = s2; + s2 = r2; + a[s2 >> 0] = t3; + a[s2 + 1 >> 0] = t3 >> 8; + a[s2 + 2 >> 0] = t3 >> 16; + a[s2 + 3 >> 0] = t3 >> 24; + r2 = r2 + 4 | 0; + a[r2 >> 0] = B3; + a[r2 + 1 >> 0] = B3 >> 8; + a[r2 + 2 >> 0] = B3 >> 16; + a[r2 + 3 >> 0] = B3 >> 24; + r2 = (c[p2 >> 2] | 0) + (u3 & 255) | 0; + c[p2 >> 2] = r2; + s2 = q2 + (r2 >>> 3) | 0; + t3 = d[s2 >> 0] | 0; + B3 = bc(w2 | 0, 0, v3 | 0) | 0; + if (!((B3 | 0) == 0 & (C2 | 0) == 0)) { + f2 = 37; + break; + } + if (D3 >>> 0 >= 956301312) { + f2 = 39; + break; + } + z3 = cc(w2 | 0, 0, r2 & 7 | 0) | 0; + B3 = C2; + z3 = t3 | z3; + D3 = s2; + A3 = D3; + a[A3 >> 0] = z3; + a[A3 + 1 >> 0] = z3 >> 8; + a[A3 + 2 >> 0] = z3 >> 16; + a[A3 + 3 >> 0] = z3 >> 24; + D3 = D3 + 4 | 0; + a[D3 >> 0] = B3; + a[D3 + 1 >> 0] = B3 >> 8; + a[D3 + 2 >> 0] = B3 >> 16; + a[D3 + 3 >> 0] = B3 >> 24; + c[p2 >> 2] = (c[p2 >> 2] | 0) + v3; + } + E3 = E3 + 1 | 0; + } + switch (f2 | 0) { + case 4: { + pa2(406196, 406218, 54, 406251); + break; + } + case 6: { + pa2(406267, 406218, 55, 406251); + break; + } + case 21: { + pa2(406196, 406218, 54, 406251); + break; + } + case 23: { + pa2(406267, 406218, 55, 406251); + break; + } + case 27: { + pa2(406196, 406218, 54, 406251); + break; + } + case 29: { + pa2(406267, 406218, 55, 406251); + break; + } + case 33: { + pa2(406196, 406218, 54, 406251); + break; + } + case 35: { + pa2(406267, 406218, 55, 406251); + break; + } + case 37: { + pa2(406196, 406218, 54, 406251); + break; + } + case 39: { + pa2(406267, 406218, 55, 406251); + break; + } + case 42: + return; + } + } + function mb(a2, b3, d2, e2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + var f2 = 0, g3 = 0, h2 = 0, i2 = 0, j2 = 0, k2 = 0, l2 = 0; + if ((a2 | 0) != 1) { + i2 = (aa(a2 + -1 | 0) | 0) ^ 31; + j2 = i2 + 1 | 0; + if (!a2) pa2(405225, 404333, 86, 405236); + else { + g3 = j2 >>> 0 < 16 ? 4 : (i2 + 4 | 0) >>> 2; + k2 = j2; + } + if (a2 >>> 0 < 16777217) { + h2 = g3; + l2 = k2; + } else pa2(405253, 404333, 87, 405236); + if (l2 >>> 0 < 25) f2 = h2; + else pa2(405273, 404333, 88, 405236); + } else f2 = 4; + c[e2 >> 2] = f2 + -4; + c[e2 + 4 >> 2] = 0; + c[d2 >> 2] = f2 << 2; + d2 = b3; + c[d2 >> 2] = a2 + -1; + c[d2 + 4 >> 2] = 0; + return; + } + function nb(b3, e2, f2) { + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + var g3 = 0, h2 = 0, i2 = 0, j2 = 0, k2 = 0, l2 = 0; + if (!b3) { + k2 = f2 + ((c[e2 >> 2] | 0) >>> 3) | 0; + b3 = d[k2 >> 0] | 0; + f2 = k2; + a[f2 >> 0] = b3; + a[f2 + 1 >> 0] = b3 >> 8; + a[f2 + 2 >> 0] = b3 >> 16; + a[f2 + 3 >> 0] = b3 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = 0; + a[k2 + 1 >> 0] = 0; + a[k2 + 2 >> 0] = 0; + a[k2 + 3 >> 0] = 0; + k2 = (c[e2 >> 2] | 0) + 1 | 0; + c[e2 >> 2] = k2; + return; + } + k2 = (aa(b3 | 0) | 0) ^ 31; + j2 = c[e2 >> 2] | 0; + g3 = f2 + (j2 >>> 3) | 0; + i2 = d[g3 >> 0] | 0; + j2 = cc(1, 0, j2 & 7 | 0) | 0; + h2 = C2; + j2 = i2 | j2; + i2 = g3; + a[i2 >> 0] = j2; + a[i2 + 1 >> 0] = j2 >> 8; + a[i2 + 2 >> 0] = j2 >> 16; + a[i2 + 3 >> 0] = j2 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = h2; + a[g3 + 1 >> 0] = h2 >> 8; + a[g3 + 2 >> 0] = h2 >> 16; + a[g3 + 3 >> 0] = h2 >> 24; + g3 = (c[e2 >> 2] | 0) + 1 | 0; + c[e2 >> 2] = g3; + h2 = f2 + (g3 >>> 3) | 0; + i2 = d[h2 >> 0] | 0; + if (!((k2 & 56 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + l2 = cc(k2 | 0, 0, g3 & 7 | 0) | 0; + g3 = C2; + l2 = i2 | l2; + j2 = h2; + i2 = j2; + a[i2 >> 0] = l2; + a[i2 + 1 >> 0] = l2 >> 8; + a[i2 + 2 >> 0] = l2 >> 16; + a[i2 + 3 >> 0] = l2 >> 24; + j2 = j2 + 4 | 0; + a[j2 >> 0] = g3; + a[j2 + 1 >> 0] = g3 >> 8; + a[j2 + 2 >> 0] = g3 >> 16; + a[j2 + 3 >> 0] = g3 >> 24; + j2 = (c[e2 >> 2] | 0) + 3 | 0; + c[e2 >> 2] = j2; + i2 = b3 - (1 << k2) | 0; + g3 = f2 + (j2 >>> 3) | 0; + h2 = d[g3 >> 0] | 0; + f2 = bc(i2 | 0, 0, k2 | 0) | 0; + if (!((f2 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + if (k2 >>> 0 >= 57) pa2(406267, 406218, 55, 406251); + j2 = cc(i2 | 0, 0, j2 & 7 | 0) | 0; + f2 = C2; + j2 = h2 | j2; + l2 = g3; + b3 = l2; + a[b3 >> 0] = j2; + a[b3 + 1 >> 0] = j2 >> 8; + a[b3 + 2 >> 0] = j2 >> 16; + a[b3 + 3 >> 0] = j2 >> 24; + l2 = l2 + 4 | 0; + a[l2 >> 0] = f2; + a[l2 + 1 >> 0] = f2 >> 8; + a[l2 + 2 >> 0] = f2 >> 16; + a[l2 + 3 >> 0] = f2 >> 24; + l2 = (c[e2 >> 2] | 0) + k2 | 0; + c[e2 >> 2] = l2; + return; + } + function ob(a2, b3, d2, e2, f2, j2, k2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + var l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0; + w2 = i; + i = i + 1040 | 0; + t3 = w2; + if ((d2 | 0) == (e2 | 0)) { + i = w2; + return; + } + u3 = e2 >>> 0 < d2 >>> 0; + v3 = u3 ? d2 : e2; + u3 = u3 ? e2 : d2; + d2 = c[b3 + (u3 << 2) >> 2] | 0; + e2 = c[b3 + (v3 << 2) >> 2] | 0; + b3 = d2 + e2 | 0; + s2 = +(d2 >>> 0); + if (d2 >>> 0 < 256) r2 = +g2[19516 + (d2 << 2) >> 2]; + else r2 = +Xb(s2); + q2 = +(e2 >>> 0); + if (e2 >>> 0 < 256) p2 = +g2[19516 + (e2 << 2) >> 2]; + else p2 = +Xb(q2); + n2 = +(b3 >>> 0); + if (b3 >>> 0 < 256) m3 = +g2[19516 + (b3 << 2) >> 2]; + else m3 = +Xb(n2); + l2 = +h[a2 + (u3 * 1040 | 0) + 1032 >> 3]; + o2 = +h[a2 + (v3 * 1040 | 0) + 1032 >> 3]; + n2 = (s2 * r2 + q2 * p2 - n2 * m3) * 0.5 - l2 - o2; + if (c[a2 + (u3 * 1040 | 0) + 1024 >> 2] | 0) { + d2 = c[a2 + (v3 * 1040 | 0) + 1024 >> 2] | 0; + if (d2) { + if (c[k2 >> 2] | 0) { + l2 = +h[j2 + 16 >> 3]; + if (l2 < 0) m3 = 0; + else m3 = l2; + } else m3 = 1e99; + dc(t3 | 0, a2 + (u3 * 1040 | 0) | 0, 1040) | 0; + b3 = t3 + 1024 | 0; + c[b3 >> 2] = (c[b3 >> 2] | 0) + d2; + d2 = 0; + while (1) { + if ((d2 | 0) == 256) break; + b3 = t3 + (d2 << 2) | 0; + c[b3 >> 2] = (c[b3 >> 2] | 0) + (c[a2 + (v3 * 1040 | 0) + (d2 << 2) >> 2] | 0); + d2 = d2 + 1 | 0; + } + l2 = +Wa2(t3); + if (!(l2 < m3 - n2)) { + i = w2; + return; + } + } + } else l2 = o2; + m3 = n2 + l2; + d2 = c[k2 >> 2] | 0; + do + if (d2) { + n2 = +h[j2 + 16 >> 3]; + if (n2 != m3) { + if (!(n2 > m3)) break; + } else if (((c[j2 + 4 >> 2] | 0) - (c[j2 >> 2] | 0) | 0) >>> 0 <= (v3 - u3 | 0) >>> 0) break; + if (d2 >>> 0 < f2 >>> 0) { + f2 = j2 + (d2 * 24 | 0) | 0; + c[f2 >> 2] = c[j2 >> 2]; + c[f2 + 4 >> 2] = c[j2 + 4 >> 2]; + c[f2 + 8 >> 2] = c[j2 + 8 >> 2]; + c[f2 + 12 >> 2] = c[j2 + 12 >> 2]; + c[f2 + 16 >> 2] = c[j2 + 16 >> 2]; + c[f2 + 20 >> 2] = c[j2 + 20 >> 2]; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + } + c[j2 >> 2] = u3; + c[j2 + 4 >> 2] = v3; + h[j2 + 8 >> 3] = l2; + h[j2 + 16 >> 3] = m3; + i = w2; + return; + } + while (0); + if (d2 >>> 0 >= f2 >>> 0) { + i = w2; + return; + } + c[j2 + (d2 * 24 | 0) >> 2] = u3; + c[j2 + (d2 * 24 | 0) + 4 >> 2] = v3; + h[j2 + (d2 * 24 | 0) + 8 >> 3] = l2; + h[j2 + (d2 * 24 | 0) + 16 >> 3] = m3; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + i = w2; + return; + } + function pb(a2, b3, d2, e2, f2, g3, j2, k2, l2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + var m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0; + F3 = i; + i = i + 32 | 0; + E3 = F3 + 24 | 0; + D3 = F3; + c[E3 >> 2] = 0; + m3 = g3 + -1 | 0; + o2 = 0; + while (1) { + if ((o2 | 0) == (g3 | 0)) break; + n2 = e2 + (o2 << 2) | 0; + q2 = o2; + while (1) { + p2 = q2 + 1 | 0; + if ((q2 | 0) == (m3 | 0)) break; + ob(a2, b3, c[n2 >> 2] | 0, c[e2 + (p2 << 2) >> 2] | 0, l2, f2, E3); + q2 = p2; + } + o2 = o2 + 1 | 0; + } + x3 = f2 + 16 | 0; + y3 = f2 + 4 | 0; + z3 = f2 + 8 | 0; + m3 = g3; + v3 = 0; + w2 = 1; + a: while (1) { + u3 = m3; + while (1) { + m3 = m3 + -1 | 0; + if (u3 >>> 0 <= w2 >>> 0) break a; + if (+h[x3 >> 3] >= v3) { + m3 = u3; + v3 = 1e99; + w2 = k2; + continue a; + } + t3 = c[f2 >> 2] | 0; + g3 = c[y3 >> 2] | 0; + n2 = a2 + (t3 * 1040 | 0) + 1024 | 0; + c[n2 >> 2] = (c[n2 >> 2] | 0) + (c[a2 + (g3 * 1040 | 0) + 1024 >> 2] | 0); + n2 = 0; + while (1) { + if ((n2 | 0) == 256) break; + q2 = a2 + (t3 * 1040 | 0) + (n2 << 2) | 0; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (c[a2 + (g3 * 1040 | 0) + (n2 << 2) >> 2] | 0); + n2 = n2 + 1 | 0; + } + h[a2 + (t3 * 1040 | 0) + 1032 >> 3] = +h[z3 >> 3]; + o2 = b3 + (t3 << 2) | 0; + c[o2 >> 2] = (c[o2 >> 2] | 0) + (c[b3 + (g3 << 2) >> 2] | 0); + o2 = 0; + while (1) { + if ((o2 | 0) == (j2 | 0)) { + o2 = 0; + break; + } + n2 = d2 + (o2 << 2) | 0; + if ((c[n2 >> 2] | 0) == (g3 | 0)) c[n2 >> 2] = t3; + o2 = o2 + 1 | 0; + } + while (1) { + if (u3 >>> 0 <= o2 >>> 0) break; + n2 = e2 + (o2 << 2) | 0; + if ((c[n2 >> 2] | 0) == (g3 | 0)) { + A3 = 22; + break; + } + o2 = o2 + 1 | 0; + } + if ((A3 | 0) == 22) { + A3 = 0; + fc(n2 | 0, e2 + (o2 + 1 << 2) | 0, (u3 - o2 << 2) + -4 | 0) | 0; + } + p2 = c[E3 >> 2] | 0; + n2 = 0; + q2 = 0; + while (1) { + if ((q2 | 0) == (p2 | 0)) break; + o2 = f2 + (q2 * 24 | 0) | 0; + if (((c[o2 >> 2] | 0) != (t3 | 0) ? (B3 = c[f2 + (q2 * 24 | 0) + 4 >> 2] | 0, (B3 | 0) != (t3 | 0)) : 0) ? (C3 = c[o2 >> 2] | 0, !((C3 | 0) == (g3 | 0) | (B3 | 0) == (g3 | 0))) : 0) { + r2 = +h[x3 >> 3]; + s2 = +h[f2 + (q2 * 24 | 0) + 16 >> 3]; + if (r2 != s2) if (r2 > s2) A3 = 32; + else A3 = 33; + else if (((c[y3 >> 2] | 0) - (c[f2 >> 2] | 0) | 0) >>> 0 > (B3 - C3 | 0) >>> 0) A3 = 32; + else A3 = 33; + if ((A3 | 0) == 32) { + A3 = 0; + c[D3 >> 2] = c[f2 >> 2]; + c[D3 + 4 >> 2] = c[f2 + 4 >> 2]; + c[D3 + 8 >> 2] = c[f2 + 8 >> 2]; + c[D3 + 12 >> 2] = c[f2 + 12 >> 2]; + c[D3 + 16 >> 2] = c[f2 + 16 >> 2]; + c[D3 + 20 >> 2] = c[f2 + 20 >> 2]; + c[f2 >> 2] = c[o2 >> 2]; + c[f2 + 4 >> 2] = c[o2 + 4 >> 2]; + c[f2 + 8 >> 2] = c[o2 + 8 >> 2]; + c[f2 + 12 >> 2] = c[o2 + 12 >> 2]; + c[f2 + 16 >> 2] = c[o2 + 16 >> 2]; + c[f2 + 20 >> 2] = c[o2 + 20 >> 2]; + o2 = f2 + (n2 * 24 | 0) | 0; + c[o2 >> 2] = c[D3 >> 2]; + c[o2 + 4 >> 2] = c[D3 + 4 >> 2]; + c[o2 + 8 >> 2] = c[D3 + 8 >> 2]; + c[o2 + 12 >> 2] = c[D3 + 12 >> 2]; + c[o2 + 16 >> 2] = c[D3 + 16 >> 2]; + c[o2 + 20 >> 2] = c[D3 + 20 >> 2]; + } else if ((A3 | 0) == 33) { + A3 = 0; + G3 = f2 + (n2 * 24 | 0) | 0; + c[G3 >> 2] = c[o2 >> 2]; + c[G3 + 4 >> 2] = c[o2 + 4 >> 2]; + c[G3 + 8 >> 2] = c[o2 + 8 >> 2]; + c[G3 + 12 >> 2] = c[o2 + 12 >> 2]; + c[G3 + 16 >> 2] = c[o2 + 16 >> 2]; + c[G3 + 20 >> 2] = c[o2 + 20 >> 2]; + } + n2 = n2 + 1 | 0; + } + q2 = q2 + 1 | 0; + } + c[E3 >> 2] = n2; + n2 = 0; + while (1) { + if ((n2 | 0) == (m3 | 0)) break; + ob(a2, b3, t3, c[e2 + (n2 << 2) >> 2] | 0, l2, f2, E3); + n2 = n2 + 1 | 0; + } + u3 = u3 + -1 | 0; + } + } + i = F3; + return u3 | 0; + } + function qb(a2, b3, d2, e2, f2, j2, k2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + var l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0; + w2 = i; + i = i + 2832 | 0; + t3 = w2; + if ((d2 | 0) == (e2 | 0)) { + i = w2; + return; + } + u3 = e2 >>> 0 < d2 >>> 0; + v3 = u3 ? d2 : e2; + u3 = u3 ? e2 : d2; + d2 = c[b3 + (u3 << 2) >> 2] | 0; + e2 = c[b3 + (v3 << 2) >> 2] | 0; + b3 = d2 + e2 | 0; + s2 = +(d2 >>> 0); + if (d2 >>> 0 < 256) r2 = +g2[19516 + (d2 << 2) >> 2]; + else r2 = +Xb(s2); + q2 = +(e2 >>> 0); + if (e2 >>> 0 < 256) p2 = +g2[19516 + (e2 << 2) >> 2]; + else p2 = +Xb(q2); + n2 = +(b3 >>> 0); + if (b3 >>> 0 < 256) m3 = +g2[19516 + (b3 << 2) >> 2]; + else m3 = +Xb(n2); + l2 = +h[a2 + (u3 * 2832 | 0) + 2824 >> 3]; + o2 = +h[a2 + (v3 * 2832 | 0) + 2824 >> 3]; + n2 = (s2 * r2 + q2 * p2 - n2 * m3) * 0.5 - l2 - o2; + if (c[a2 + (u3 * 2832 | 0) + 2816 >> 2] | 0) { + d2 = c[a2 + (v3 * 2832 | 0) + 2816 >> 2] | 0; + if (d2) { + if (c[k2 >> 2] | 0) { + l2 = +h[j2 + 16 >> 3]; + if (l2 < 0) m3 = 0; + else m3 = l2; + } else m3 = 1e99; + dc(t3 | 0, a2 + (u3 * 2832 | 0) | 0, 2832) | 0; + b3 = t3 + 2816 | 0; + c[b3 >> 2] = (c[b3 >> 2] | 0) + d2; + d2 = 0; + while (1) { + if ((d2 | 0) == 704) break; + b3 = t3 + (d2 << 2) | 0; + c[b3 >> 2] = (c[b3 >> 2] | 0) + (c[a2 + (v3 * 2832 | 0) + (d2 << 2) >> 2] | 0); + d2 = d2 + 1 | 0; + } + l2 = +Xa2(t3); + if (!(l2 < m3 - n2)) { + i = w2; + return; + } + } + } else l2 = o2; + m3 = n2 + l2; + d2 = c[k2 >> 2] | 0; + do + if (d2) { + n2 = +h[j2 + 16 >> 3]; + if (n2 != m3) { + if (!(n2 > m3)) break; + } else if (((c[j2 + 4 >> 2] | 0) - (c[j2 >> 2] | 0) | 0) >>> 0 <= (v3 - u3 | 0) >>> 0) break; + if (d2 >>> 0 < f2 >>> 0) { + f2 = j2 + (d2 * 24 | 0) | 0; + c[f2 >> 2] = c[j2 >> 2]; + c[f2 + 4 >> 2] = c[j2 + 4 >> 2]; + c[f2 + 8 >> 2] = c[j2 + 8 >> 2]; + c[f2 + 12 >> 2] = c[j2 + 12 >> 2]; + c[f2 + 16 >> 2] = c[j2 + 16 >> 2]; + c[f2 + 20 >> 2] = c[j2 + 20 >> 2]; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + } + c[j2 >> 2] = u3; + c[j2 + 4 >> 2] = v3; + h[j2 + 8 >> 3] = l2; + h[j2 + 16 >> 3] = m3; + i = w2; + return; + } + while (0); + if (d2 >>> 0 >= f2 >>> 0) { + i = w2; + return; + } + c[j2 + (d2 * 24 | 0) >> 2] = u3; + c[j2 + (d2 * 24 | 0) + 4 >> 2] = v3; + h[j2 + (d2 * 24 | 0) + 8 >> 3] = l2; + h[j2 + (d2 * 24 | 0) + 16 >> 3] = m3; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + i = w2; + return; + } + function rb(a2, b3, d2, e2, f2, g3, j2, k2, l2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + var m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0; + F3 = i; + i = i + 32 | 0; + E3 = F3 + 24 | 0; + D3 = F3; + c[E3 >> 2] = 0; + m3 = g3 + -1 | 0; + o2 = 0; + while (1) { + if ((o2 | 0) == (g3 | 0)) break; + n2 = e2 + (o2 << 2) | 0; + q2 = o2; + while (1) { + p2 = q2 + 1 | 0; + if ((q2 | 0) == (m3 | 0)) break; + qb(a2, b3, c[n2 >> 2] | 0, c[e2 + (p2 << 2) >> 2] | 0, l2, f2, E3); + q2 = p2; + } + o2 = o2 + 1 | 0; + } + x3 = f2 + 16 | 0; + y3 = f2 + 4 | 0; + z3 = f2 + 8 | 0; + m3 = g3; + v3 = 0; + w2 = 1; + a: while (1) { + u3 = m3; + while (1) { + m3 = m3 + -1 | 0; + if (u3 >>> 0 <= w2 >>> 0) break a; + if (+h[x3 >> 3] >= v3) { + m3 = u3; + v3 = 1e99; + w2 = k2; + continue a; + } + t3 = c[f2 >> 2] | 0; + g3 = c[y3 >> 2] | 0; + n2 = a2 + (t3 * 2832 | 0) + 2816 | 0; + c[n2 >> 2] = (c[n2 >> 2] | 0) + (c[a2 + (g3 * 2832 | 0) + 2816 >> 2] | 0); + n2 = 0; + while (1) { + if ((n2 | 0) == 704) break; + q2 = a2 + (t3 * 2832 | 0) + (n2 << 2) | 0; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (c[a2 + (g3 * 2832 | 0) + (n2 << 2) >> 2] | 0); + n2 = n2 + 1 | 0; + } + h[a2 + (t3 * 2832 | 0) + 2824 >> 3] = +h[z3 >> 3]; + o2 = b3 + (t3 << 2) | 0; + c[o2 >> 2] = (c[o2 >> 2] | 0) + (c[b3 + (g3 << 2) >> 2] | 0); + o2 = 0; + while (1) { + if ((o2 | 0) == (j2 | 0)) { + o2 = 0; + break; + } + n2 = d2 + (o2 << 2) | 0; + if ((c[n2 >> 2] | 0) == (g3 | 0)) c[n2 >> 2] = t3; + o2 = o2 + 1 | 0; + } + while (1) { + if (u3 >>> 0 <= o2 >>> 0) break; + n2 = e2 + (o2 << 2) | 0; + if ((c[n2 >> 2] | 0) == (g3 | 0)) { + A3 = 22; + break; + } + o2 = o2 + 1 | 0; + } + if ((A3 | 0) == 22) { + A3 = 0; + fc(n2 | 0, e2 + (o2 + 1 << 2) | 0, (u3 - o2 << 2) + -4 | 0) | 0; + } + p2 = c[E3 >> 2] | 0; + n2 = 0; + q2 = 0; + while (1) { + if ((q2 | 0) == (p2 | 0)) break; + o2 = f2 + (q2 * 24 | 0) | 0; + if (((c[o2 >> 2] | 0) != (t3 | 0) ? (B3 = c[f2 + (q2 * 24 | 0) + 4 >> 2] | 0, (B3 | 0) != (t3 | 0)) : 0) ? (C3 = c[o2 >> 2] | 0, !((C3 | 0) == (g3 | 0) | (B3 | 0) == (g3 | 0))) : 0) { + r2 = +h[x3 >> 3]; + s2 = +h[f2 + (q2 * 24 | 0) + 16 >> 3]; + if (r2 != s2) if (r2 > s2) A3 = 32; + else A3 = 33; + else if (((c[y3 >> 2] | 0) - (c[f2 >> 2] | 0) | 0) >>> 0 > (B3 - C3 | 0) >>> 0) A3 = 32; + else A3 = 33; + if ((A3 | 0) == 32) { + A3 = 0; + c[D3 >> 2] = c[f2 >> 2]; + c[D3 + 4 >> 2] = c[f2 + 4 >> 2]; + c[D3 + 8 >> 2] = c[f2 + 8 >> 2]; + c[D3 + 12 >> 2] = c[f2 + 12 >> 2]; + c[D3 + 16 >> 2] = c[f2 + 16 >> 2]; + c[D3 + 20 >> 2] = c[f2 + 20 >> 2]; + c[f2 >> 2] = c[o2 >> 2]; + c[f2 + 4 >> 2] = c[o2 + 4 >> 2]; + c[f2 + 8 >> 2] = c[o2 + 8 >> 2]; + c[f2 + 12 >> 2] = c[o2 + 12 >> 2]; + c[f2 + 16 >> 2] = c[o2 + 16 >> 2]; + c[f2 + 20 >> 2] = c[o2 + 20 >> 2]; + o2 = f2 + (n2 * 24 | 0) | 0; + c[o2 >> 2] = c[D3 >> 2]; + c[o2 + 4 >> 2] = c[D3 + 4 >> 2]; + c[o2 + 8 >> 2] = c[D3 + 8 >> 2]; + c[o2 + 12 >> 2] = c[D3 + 12 >> 2]; + c[o2 + 16 >> 2] = c[D3 + 16 >> 2]; + c[o2 + 20 >> 2] = c[D3 + 20 >> 2]; + } else if ((A3 | 0) == 33) { + A3 = 0; + G3 = f2 + (n2 * 24 | 0) | 0; + c[G3 >> 2] = c[o2 >> 2]; + c[G3 + 4 >> 2] = c[o2 + 4 >> 2]; + c[G3 + 8 >> 2] = c[o2 + 8 >> 2]; + c[G3 + 12 >> 2] = c[o2 + 12 >> 2]; + c[G3 + 16 >> 2] = c[o2 + 16 >> 2]; + c[G3 + 20 >> 2] = c[o2 + 20 >> 2]; + } + n2 = n2 + 1 | 0; + } + q2 = q2 + 1 | 0; + } + c[E3 >> 2] = n2; + n2 = 0; + while (1) { + if ((n2 | 0) == (m3 | 0)) break; + qb(a2, b3, t3, c[e2 + (n2 << 2) >> 2] | 0, l2, f2, E3); + n2 = n2 + 1 | 0; + } + u3 = u3 + -1 | 0; + } + } + i = F3; + return u3 | 0; + } + function sb(a2, b3, d2, e2, f2, j2, k2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + var l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0; + w2 = i; + i = i + 2096 | 0; + t3 = w2; + if ((d2 | 0) == (e2 | 0)) { + i = w2; + return; + } + u3 = e2 >>> 0 < d2 >>> 0; + v3 = u3 ? d2 : e2; + u3 = u3 ? e2 : d2; + d2 = c[b3 + (u3 << 2) >> 2] | 0; + e2 = c[b3 + (v3 << 2) >> 2] | 0; + b3 = d2 + e2 | 0; + s2 = +(d2 >>> 0); + if (d2 >>> 0 < 256) r2 = +g2[19516 + (d2 << 2) >> 2]; + else r2 = +Xb(s2); + q2 = +(e2 >>> 0); + if (e2 >>> 0 < 256) p2 = +g2[19516 + (e2 << 2) >> 2]; + else p2 = +Xb(q2); + n2 = +(b3 >>> 0); + if (b3 >>> 0 < 256) m3 = +g2[19516 + (b3 << 2) >> 2]; + else m3 = +Xb(n2); + l2 = +h[a2 + (u3 * 2096 | 0) + 2088 >> 3]; + o2 = +h[a2 + (v3 * 2096 | 0) + 2088 >> 3]; + n2 = (s2 * r2 + q2 * p2 - n2 * m3) * 0.5 - l2 - o2; + if (c[a2 + (u3 * 2096 | 0) + 2080 >> 2] | 0) { + d2 = c[a2 + (v3 * 2096 | 0) + 2080 >> 2] | 0; + if (d2) { + if (c[k2 >> 2] | 0) { + l2 = +h[j2 + 16 >> 3]; + if (l2 < 0) m3 = 0; + else m3 = l2; + } else m3 = 1e99; + dc(t3 | 0, a2 + (u3 * 2096 | 0) | 0, 2096) | 0; + b3 = t3 + 2080 | 0; + c[b3 >> 2] = (c[b3 >> 2] | 0) + d2; + d2 = 0; + while (1) { + if ((d2 | 0) == 520) break; + b3 = t3 + (d2 << 2) | 0; + c[b3 >> 2] = (c[b3 >> 2] | 0) + (c[a2 + (v3 * 2096 | 0) + (d2 << 2) >> 2] | 0); + d2 = d2 + 1 | 0; + } + l2 = +Ya(t3); + if (!(l2 < m3 - n2)) { + i = w2; + return; + } + } + } else l2 = o2; + m3 = n2 + l2; + d2 = c[k2 >> 2] | 0; + do + if (d2) { + n2 = +h[j2 + 16 >> 3]; + if (n2 != m3) { + if (!(n2 > m3)) break; + } else if (((c[j2 + 4 >> 2] | 0) - (c[j2 >> 2] | 0) | 0) >>> 0 <= (v3 - u3 | 0) >>> 0) break; + if (d2 >>> 0 < f2 >>> 0) { + f2 = j2 + (d2 * 24 | 0) | 0; + c[f2 >> 2] = c[j2 >> 2]; + c[f2 + 4 >> 2] = c[j2 + 4 >> 2]; + c[f2 + 8 >> 2] = c[j2 + 8 >> 2]; + c[f2 + 12 >> 2] = c[j2 + 12 >> 2]; + c[f2 + 16 >> 2] = c[j2 + 16 >> 2]; + c[f2 + 20 >> 2] = c[j2 + 20 >> 2]; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + } + c[j2 >> 2] = u3; + c[j2 + 4 >> 2] = v3; + h[j2 + 8 >> 3] = l2; + h[j2 + 16 >> 3] = m3; + i = w2; + return; + } + while (0); + if (d2 >>> 0 >= f2 >>> 0) { + i = w2; + return; + } + c[j2 + (d2 * 24 | 0) >> 2] = u3; + c[j2 + (d2 * 24 | 0) + 4 >> 2] = v3; + h[j2 + (d2 * 24 | 0) + 8 >> 3] = l2; + h[j2 + (d2 * 24 | 0) + 16 >> 3] = m3; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + i = w2; + return; + } + function tb(a2, b3, d2, e2, f2, g3, j2, k2, l2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + var m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0; + F3 = i; + i = i + 32 | 0; + E3 = F3 + 24 | 0; + D3 = F3; + c[E3 >> 2] = 0; + m3 = g3 + -1 | 0; + o2 = 0; + while (1) { + if ((o2 | 0) == (g3 | 0)) break; + n2 = e2 + (o2 << 2) | 0; + q2 = o2; + while (1) { + p2 = q2 + 1 | 0; + if ((q2 | 0) == (m3 | 0)) break; + sb(a2, b3, c[n2 >> 2] | 0, c[e2 + (p2 << 2) >> 2] | 0, l2, f2, E3); + q2 = p2; + } + o2 = o2 + 1 | 0; + } + x3 = f2 + 16 | 0; + y3 = f2 + 4 | 0; + z3 = f2 + 8 | 0; + m3 = g3; + v3 = 0; + w2 = 1; + a: while (1) { + u3 = m3; + while (1) { + m3 = m3 + -1 | 0; + if (u3 >>> 0 <= w2 >>> 0) break a; + if (+h[x3 >> 3] >= v3) { + m3 = u3; + v3 = 1e99; + w2 = k2; + continue a; + } + t3 = c[f2 >> 2] | 0; + g3 = c[y3 >> 2] | 0; + n2 = a2 + (t3 * 2096 | 0) + 2080 | 0; + c[n2 >> 2] = (c[n2 >> 2] | 0) + (c[a2 + (g3 * 2096 | 0) + 2080 >> 2] | 0); + n2 = 0; + while (1) { + if ((n2 | 0) == 520) break; + q2 = a2 + (t3 * 2096 | 0) + (n2 << 2) | 0; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (c[a2 + (g3 * 2096 | 0) + (n2 << 2) >> 2] | 0); + n2 = n2 + 1 | 0; + } + h[a2 + (t3 * 2096 | 0) + 2088 >> 3] = +h[z3 >> 3]; + o2 = b3 + (t3 << 2) | 0; + c[o2 >> 2] = (c[o2 >> 2] | 0) + (c[b3 + (g3 << 2) >> 2] | 0); + o2 = 0; + while (1) { + if ((o2 | 0) == (j2 | 0)) { + o2 = 0; + break; + } + n2 = d2 + (o2 << 2) | 0; + if ((c[n2 >> 2] | 0) == (g3 | 0)) c[n2 >> 2] = t3; + o2 = o2 + 1 | 0; + } + while (1) { + if (u3 >>> 0 <= o2 >>> 0) break; + n2 = e2 + (o2 << 2) | 0; + if ((c[n2 >> 2] | 0) == (g3 | 0)) { + A3 = 22; + break; + } + o2 = o2 + 1 | 0; + } + if ((A3 | 0) == 22) { + A3 = 0; + fc(n2 | 0, e2 + (o2 + 1 << 2) | 0, (u3 - o2 << 2) + -4 | 0) | 0; + } + p2 = c[E3 >> 2] | 0; + n2 = 0; + q2 = 0; + while (1) { + if ((q2 | 0) == (p2 | 0)) break; + o2 = f2 + (q2 * 24 | 0) | 0; + if (((c[o2 >> 2] | 0) != (t3 | 0) ? (B3 = c[f2 + (q2 * 24 | 0) + 4 >> 2] | 0, (B3 | 0) != (t3 | 0)) : 0) ? (C3 = c[o2 >> 2] | 0, !((C3 | 0) == (g3 | 0) | (B3 | 0) == (g3 | 0))) : 0) { + r2 = +h[x3 >> 3]; + s2 = +h[f2 + (q2 * 24 | 0) + 16 >> 3]; + if (r2 != s2) if (r2 > s2) A3 = 32; + else A3 = 33; + else if (((c[y3 >> 2] | 0) - (c[f2 >> 2] | 0) | 0) >>> 0 > (B3 - C3 | 0) >>> 0) A3 = 32; + else A3 = 33; + if ((A3 | 0) == 32) { + A3 = 0; + c[D3 >> 2] = c[f2 >> 2]; + c[D3 + 4 >> 2] = c[f2 + 4 >> 2]; + c[D3 + 8 >> 2] = c[f2 + 8 >> 2]; + c[D3 + 12 >> 2] = c[f2 + 12 >> 2]; + c[D3 + 16 >> 2] = c[f2 + 16 >> 2]; + c[D3 + 20 >> 2] = c[f2 + 20 >> 2]; + c[f2 >> 2] = c[o2 >> 2]; + c[f2 + 4 >> 2] = c[o2 + 4 >> 2]; + c[f2 + 8 >> 2] = c[o2 + 8 >> 2]; + c[f2 + 12 >> 2] = c[o2 + 12 >> 2]; + c[f2 + 16 >> 2] = c[o2 + 16 >> 2]; + c[f2 + 20 >> 2] = c[o2 + 20 >> 2]; + o2 = f2 + (n2 * 24 | 0) | 0; + c[o2 >> 2] = c[D3 >> 2]; + c[o2 + 4 >> 2] = c[D3 + 4 >> 2]; + c[o2 + 8 >> 2] = c[D3 + 8 >> 2]; + c[o2 + 12 >> 2] = c[D3 + 12 >> 2]; + c[o2 + 16 >> 2] = c[D3 + 16 >> 2]; + c[o2 + 20 >> 2] = c[D3 + 20 >> 2]; + } else if ((A3 | 0) == 33) { + A3 = 0; + G3 = f2 + (n2 * 24 | 0) | 0; + c[G3 >> 2] = c[o2 >> 2]; + c[G3 + 4 >> 2] = c[o2 + 4 >> 2]; + c[G3 + 8 >> 2] = c[o2 + 8 >> 2]; + c[G3 + 12 >> 2] = c[o2 + 12 >> 2]; + c[G3 + 16 >> 2] = c[o2 + 16 >> 2]; + c[G3 + 20 >> 2] = c[o2 + 20 >> 2]; + } + n2 = n2 + 1 | 0; + } + q2 = q2 + 1 | 0; + } + c[E3 >> 2] = n2; + n2 = 0; + while (1) { + if ((n2 | 0) == (m3 | 0)) break; + sb(a2, b3, t3, c[e2 + (n2 << 2) >> 2] | 0, l2, f2, E3); + n2 = n2 + 1 | 0; + } + u3 = u3 + -1 | 0; + } + } + i = F3; + return u3 | 0; + } + function ub(b3, f2, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2) { + b3 = b3 | 0; + f2 = f2 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + var s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, _2 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0; + xa3 = i; + i = i + 2304 | 0; + ta3 = xa3 + 512 | 0; + sa3 = xa3; + va3 = xa3 + 2048 | 0; + ua3 = xa3 + 1536 | 0; + w2 = f2; + A3 = h2 >>> 0 < 98304 ? h2 : 98304; + B3 = c[q2 >> 2] | 0; + ra3 = 64 - ((aa(l2 | 0) | 0) ^ 31) | 0; + if (!l2) pa2(405532, 405401, 464, 405439); + if (l2 >>> 0 >= 2147483649) pa2(405605, 405401, 465, 405439); + s2 = l2 + -1 | 0; + if (s2 & l2) pa2(405630, 405401, 467, 405439); + qa3 = bc(16777215, -1, ra3 | 0) | 0; + if ((s2 | 0) != (qa3 | 0)) pa2(405667, 405401, 469, 405439); + if (!h2) { + if (!j2) pa2(405466, 405401, 472, 405439); + b3 = r2 + (B3 >>> 3) | 0; + k2 = d[b3 >> 0] | 0; + va3 = cc(1, 0, B3 & 7 | 0) | 0; + wa3 = C2; + va3 = k2 | va3; + k2 = b3; + a[k2 >> 0] = va3; + a[k2 + 1 >> 0] = va3 >> 8; + a[k2 + 2 >> 0] = va3 >> 16; + a[k2 + 3 >> 0] = va3 >> 24; + b3 = b3 + 4 | 0; + a[b3 >> 0] = wa3; + a[b3 + 1 >> 0] = wa3 >> 8; + a[b3 + 2 >> 0] = wa3 >> 16; + a[b3 + 3 >> 0] = wa3 >> 24; + b3 = (c[q2 >> 2] | 0) + 1 | 0; + c[q2 >> 2] = b3; + wa3 = r2 + (b3 >>> 3) | 0; + r2 = d[wa3 >> 0] | 0; + b3 = cc(1, 0, b3 & 7 | 0) | 0; + k2 = C2; + b3 = r2 | b3; + r2 = wa3; + a[r2 >> 0] = b3; + a[r2 + 1 >> 0] = b3 >> 8; + a[r2 + 2 >> 0] = b3 >> 16; + a[r2 + 3 >> 0] = b3 >> 24; + wa3 = wa3 + 4 | 0; + a[wa3 >> 0] = k2; + a[wa3 + 1 >> 0] = k2 >> 8; + a[wa3 + 2 >> 0] = k2 >> 16; + a[wa3 + 3 >> 0] = k2 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 8 & -8; + i = xa3; + return; + } + vb(A3, 0, q2, r2); + x3 = r2 + ((c[q2 >> 2] | 0) >>> 3) | 0; + qa3 = d[x3 >> 0] | 0; + s2 = x3; + a[s2 >> 0] = qa3; + a[s2 + 1 >> 0] = qa3 >> 8; + a[s2 + 2 >> 0] = qa3 >> 16; + a[s2 + 3 >> 0] = qa3 >> 24; + x3 = x3 + 4 | 0; + a[x3 >> 0] = 0; + a[x3 + 1 >> 0] = 0; + a[x3 + 2 >> 0] = 0; + a[x3 + 3 >> 0] = 0; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 13; + x3 = wb(b3, f2, A3, va3, ua3, q2, r2) | 0; + s2 = 0; + while (1) { + l2 = c[o2 >> 2] | 0; + if ((s2 | 7) >>> 0 >= l2 >>> 0) break; + ma3 = c[q2 >> 2] | 0; + qa3 = r2 + (ma3 >>> 3) | 0; + na2 = d[qa3 >> 0] | 0; + ma3 = cc(d[p2 + (s2 >>> 3) >> 0] | 0, 0, ma3 & 7 | 0) | 0; + oa3 = C2; + ma3 = na2 | ma3; + na2 = qa3; + a[na2 >> 0] = ma3; + a[na2 + 1 >> 0] = ma3 >> 8; + a[na2 + 2 >> 0] = ma3 >> 16; + a[na2 + 3 >> 0] = ma3 >> 24; + qa3 = qa3 + 4 | 0; + a[qa3 >> 0] = oa3; + a[qa3 + 1 >> 0] = oa3 >> 8; + a[qa3 + 2 >> 0] = oa3 >> 16; + a[qa3 + 3 >> 0] = oa3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 8; + s2 = s2 + 8 | 0; + } + v3 = l2 & 7; + s2 = d[p2 + (l2 >>> 3) >> 0] | 0; + l2 = c[q2 >> 2] | 0; + t3 = r2 + (l2 >>> 3) | 0; + u3 = d[t3 >> 0] | 0; + qa3 = bc(s2 | 0, 0, v3 | 0) | 0; + if (!((qa3 | 0) == 0 & (C2 | 0) == 0)) pa2(406196, 406218, 54, 406251); + ca3 = cc(s2 | 0, 0, l2 & 7 | 0) | 0; + $2 = C2; + ca3 = u3 | ca3; + _2 = t3; + ba2 = _2; + a[ba2 >> 0] = ca3; + a[ba2 + 1 >> 0] = ca3 >> 8; + a[ba2 + 2 >> 0] = ca3 >> 16; + a[ba2 + 3 >> 0] = ca3 >> 24; + _2 = _2 + 4 | 0; + a[_2 >> 0] = $2; + a[_2 + 1 >> 0] = $2 >> 8; + a[_2 + 2 >> 0] = $2 >> 16; + a[_2 + 3 >> 0] = $2 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + v3; + _2 = f2; + $2 = m3 + 61 | 0; + ba2 = n2 + 122 | 0; + ca3 = sa3 + 84 | 0; + da3 = m3 + 64 | 0; + ea3 = n2 + 128 | 0; + fa3 = sa3 + 256 | 0; + ga3 = m3 + 39 | 0; + ha3 = n2 + 78 | 0; + ia3 = sa3 + 188 | 0; + ja3 = sa3 + 256 | 0; + ka3 = m3 + 62 | 0; + la3 = n2 + 124 | 0; + ma3 = sa3 + 88 | 0; + na2 = m3 + 63 | 0; + oa3 = n2 + 126 | 0; + qa3 = sa3 + 92 | 0; + l2 = h2; + s2 = w2; + u3 = A3; + t3 = x3; + a: while (1) { + X3 = B3 + 3 | 0; + Y3 = t3 >>> 0 > 980; + T3 = s2; + V3 = u3; + v3 = s2; + W3 = u3; + b: while (1) { + dc(sa3 | 0, 17764, 512) | 0; + U3 = T3; + t3 = U3 + V3 | 0; + Z3 = t3; + c: do + if (V3 >>> 0 > 15) { + w2 = V3 + -5 | 0; + S3 = l2 + -16 | 0; + S3 = U3 + (w2 >>> 0 < S3 >>> 0 ? w2 : S3) | 0; + w2 = U3 + 1 | 0; + h2 = w2; + u3 = h2; + h2 = h2 + 4 | 0; + u3 = d[u3 >> 0] | d[u3 + 1 >> 0] << 8 | d[u3 + 2 >> 0] << 16 | d[u3 + 3 >> 0] << 24; + h2 = d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24; + M2 = -1; + while (1) { + u3 = lc(u3 | 0, h2 | 0, -1124073472, 1979815) | 0; + u3 = bc(u3 | 0, C2 | 0, ra3 | 0) | 0; + K3 = v3; + if (K3 >>> 0 >= w2 >>> 0) { + wa3 = 24; + break a; + } + G3 = 0 - M2 | 0; + Q3 = w2; + F3 = 32; + while (1) { + H3 = Q3; + h2 = F3; + F3 = F3 + 1 | 0; + R3 = Q3; + P3 = R3; + R3 = R3 + 4 | 0; + R3 = lc(d[P3 >> 0] | d[P3 + 1 >> 0] << 8 | d[P3 + 2 >> 0] << 16 | d[P3 + 3 >> 0] << 24 | 0, d[R3 >> 0] | d[R3 + 1 >> 0] << 8 | d[R3 + 2 >> 0] << 16 | d[R3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + R3 = bc(R3 | 0, C2 | 0, ra3 | 0) | 0; + if ((u3 | 0) != (R3 | 0)) { + wa3 = 26; + break a; + } + x3 = Q3 + (h2 >>> 5) | 0; + if (x3 >>> 0 > S3 >>> 0) break c; + A3 = x3; + h2 = A3; + A3 = A3 + 4 | 0; + A3 = lc(d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0, d[A3 >> 0] | d[A3 + 1 >> 0] << 8 | d[A3 + 2 >> 0] << 16 | d[A3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + A3 = bc(A3 | 0, C2 | 0, ra3 | 0) | 0; + h2 = Q3 + G3 | 0; + if ((d[Q3 >> 0] | d[Q3 + 1 >> 0] << 8 | d[Q3 + 2 >> 0] << 16 | d[Q3 + 3 >> 0] << 24 | 0) == (d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0) ? (G3 | 0) < 0 ? (a[Q3 + 4 >> 0] | 0) == (a[Q3 + (4 - M2) >> 0] | 0) : 0 : 0) { + wa3 = 30; + break; + } + u3 = k2 + (u3 << 2) | 0; + w2 = c[u3 >> 2] | 0; + h2 = f2 + w2 | 0; + if ((w2 | 0) < 0) { + wa3 = 32; + break a; + } + if (h2 >>> 0 >= Q3 >>> 0) { + wa3 = 34; + break a; + } + c[u3 >> 2] = H3 - _2; + if ((d[Q3 >> 0] | d[Q3 + 1 >> 0] << 8 | d[Q3 + 2 >> 0] << 16 | d[Q3 + 3 >> 0] << 24 | 0) != (d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0)) { + u3 = A3; + Q3 = x3; + continue; + } + if ((a[Q3 + 4 >> 0] | 0) == (a[f2 + (w2 + 4) >> 0] | 0)) break; + else { + u3 = A3; + Q3 = x3; + } + } + if ((wa3 | 0) == 30) { + wa3 = 0; + c[k2 + (u3 << 2) >> 2] = H3 - _2; + } + x3 = h2; + R3 = U3 + (V3 + -4) | 0; + u3 = 0; + w2 = Q3 + 5 | 0; + while (1) { + if (w2 >>> 0 > R3 >>> 0) { + P3 = u3; + u3 = w2; + break; + } + P3 = h2 + (u3 + 5) | 0; + if ((d[w2 >> 0] | d[w2 + 1 >> 0] << 8 | d[w2 + 2 >> 0] << 16 | d[w2 + 3 >> 0] << 24 | 0) != (d[P3 >> 0] | d[P3 + 1 >> 0] << 8 | d[P3 + 2 >> 0] << 16 | d[P3 + 3 >> 0] << 24 | 0)) { + P3 = u3; + u3 = w2; + break; + } + u3 = u3 + 4 | 0; + w2 = w2 + 4 | 0; + } + while (1) { + if (u3 >>> 0 >= t3 >>> 0) break; + if ((a[h2 + (P3 + 5) >> 0] | 0) != (a[u3 >> 0] | 0)) break; + P3 = P3 + 1 | 0; + u3 = u3 + 1 | 0; + } + L3 = P3 + 5 | 0; + I3 = H3 - x3 | 0; + J3 = H3 - v3 | 0; + N3 = Q3 + L3 | 0; + O3 = N3; + d: do + if (L3) { + x3 = L3; + A3 = Q3; + while (1) { + u3 = a[A3 >> 0] | 0; + w2 = a[h2 >> 0] | 0; + if (u3 << 24 >> 24 != w2 << 24 >> 24) break; + x3 = x3 + -1 | 0; + if (!x3) break d; + else { + A3 = A3 + 1 | 0; + h2 = h2 + 1 | 0; + } + } + if (u3 << 24 >> 24 != w2 << 24 >> 24) { + wa3 = 48; + break a; + } + } + while (0); + do + if (J3 >>> 0 >= 6210) { + if (!(((v3 - s2 | 0) * 50 | 0) >>> 0 > J3 >>> 0 | Y3 ^ 1)) { + wa3 = 84; + break b; + } + if (J3 >>> 0 < 22594) { + u3 = a[ka3 >> 0] | 0; + v3 = e[la3 >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + H3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((H3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 87; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 89; + break a; + } + H3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + h2 = C2; + H3 = x3 | H3; + v3 = w2; + w2 = v3; + a[w2 >> 0] = H3; + a[w2 + 1 >> 0] = H3 >> 8; + a[w2 + 2 >> 0] = H3 >> 16; + a[w2 + 3 >> 0] = H3 >> 24; + v3 = v3 + 4 | 0; + a[v3 >> 0] = h2; + a[v3 + 1 >> 0] = h2 >> 8; + a[v3 + 2 >> 0] = h2 >> 16; + a[v3 + 3 >> 0] = h2 >> 24; + u3 = (c[q2 >> 2] | 0) + (u3 & 255) | 0; + c[q2 >> 2] = u3; + v3 = J3 + -6210 | 0; + h2 = r2 + (u3 >>> 3) | 0; + w2 = d[h2 >> 0] | 0; + if (!((v3 & -16384 | 0) == 0 & true)) { + wa3 = 91; + break a; + } + F3 = cc(v3 | 0, 0, u3 & 7 | 0) | 0; + H3 = C2; + F3 = w2 | F3; + A3 = h2; + G3 = A3; + a[G3 >> 0] = F3; + a[G3 + 1 >> 0] = F3 >> 8; + a[G3 + 2 >> 0] = F3 >> 16; + a[G3 + 3 >> 0] = F3 >> 24; + A3 = A3 + 4 | 0; + a[A3 >> 0] = H3; + a[A3 + 1 >> 0] = H3 >> 8; + a[A3 + 2 >> 0] = H3 >> 16; + a[A3 + 3 >> 0] = H3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 14; + c[ma3 >> 2] = (c[ma3 >> 2] | 0) + 1; + A3 = 0; + break; + } else { + u3 = a[na2 >> 0] | 0; + v3 = e[oa3 >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + H3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((H3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 94; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 96; + break a; + } + H3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + h2 = C2; + H3 = x3 | H3; + v3 = w2; + w2 = v3; + a[w2 >> 0] = H3; + a[w2 + 1 >> 0] = H3 >> 8; + a[w2 + 2 >> 0] = H3 >> 16; + a[w2 + 3 >> 0] = H3 >> 24; + v3 = v3 + 4 | 0; + a[v3 >> 0] = h2; + a[v3 + 1 >> 0] = h2 >> 8; + a[v3 + 2 >> 0] = h2 >> 16; + a[v3 + 3 >> 0] = h2 >> 24; + u3 = (c[q2 >> 2] | 0) + (u3 & 255) | 0; + c[q2 >> 2] = u3; + v3 = J3 + -22594 | 0; + h2 = r2 + (u3 >>> 3) | 0; + w2 = d[h2 >> 0] | 0; + if (!((v3 & -16777216 | 0) == 0 & true)) { + wa3 = 98; + break a; + } + F3 = cc(v3 | 0, 0, u3 & 7 | 0) | 0; + H3 = C2; + F3 = w2 | F3; + A3 = h2; + G3 = A3; + a[G3 >> 0] = F3; + a[G3 + 1 >> 0] = F3 >> 8; + a[G3 + 2 >> 0] = F3 >> 16; + a[G3 + 3 >> 0] = F3 >> 24; + A3 = A3 + 4 | 0; + a[A3 >> 0] = H3; + a[A3 + 1 >> 0] = H3 >> 8; + a[A3 + 2 >> 0] = H3 >> 16; + a[A3 + 3 >> 0] = H3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 24; + c[qa3 >> 2] = (c[qa3 >> 2] | 0) + 1; + A3 = 0; + break; + } + } else { + if (J3 >>> 0 < 6) { + u3 = J3 + 40 | 0; + v3 = a[m3 + u3 >> 0] | 0; + h2 = e[n2 + (u3 << 1) >> 1] | 0; + w2 = c[q2 >> 2] | 0; + x3 = r2 + (w2 >>> 3) | 0; + A3 = d[x3 >> 0] | 0; + H3 = bc(h2 | 0, 0, v3 & 255 | 0) | 0; + if (!((H3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 52; + break a; + } + if ((v3 & 255) >= 57) { + wa3 = 54; + break a; + } + F3 = cc(h2 | 0, 0, w2 & 7 | 0) | 0; + H3 = C2; + F3 = A3 | F3; + A3 = x3; + G3 = A3; + a[G3 >> 0] = F3; + a[G3 + 1 >> 0] = F3 >> 8; + a[G3 + 2 >> 0] = F3 >> 16; + a[G3 + 3 >> 0] = F3 >> 24; + A3 = A3 + 4 | 0; + a[A3 >> 0] = H3; + a[A3 + 1 >> 0] = H3 >> 8; + a[A3 + 2 >> 0] = H3 >> 16; + a[A3 + 3 >> 0] = H3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (v3 & 255); + A3 = sa3 + (u3 << 2) | 0; + c[A3 >> 2] = (c[A3 >> 2] | 0) + 1; + A3 = 0; + break; + } + if (J3 >>> 0 < 130) { + A3 = J3 + -2 | 0; + G3 = ((aa(A3 | 0) | 0) ^ 31) + -1 | 0; + F3 = A3 >>> G3; + H3 = (G3 << 1) + F3 + 42 | 0; + u3 = a[m3 + H3 >> 0] | 0; + v3 = e[n2 + (H3 << 1) >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 58; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 60; + break a; + } + ya3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + v3 = C2; + ya3 = x3 | ya3; + h2 = w2; + a[h2 >> 0] = ya3; + a[h2 + 1 >> 0] = ya3 >> 8; + a[h2 + 2 >> 0] = ya3 >> 16; + a[h2 + 3 >> 0] = ya3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = v3; + a[w2 + 1 >> 0] = v3 >> 8; + a[w2 + 2 >> 0] = v3 >> 16; + a[w2 + 3 >> 0] = v3 >> 24; + w2 = (c[q2 >> 2] | 0) + (u3 & 255) | 0; + c[q2 >> 2] = w2; + u3 = A3 - (F3 << G3) | 0; + v3 = r2 + (w2 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(u3 | 0, 0, G3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 62; + break a; + } + if (G3 >>> 0 >= 57) { + wa3 = 64; + break a; + } + x3 = cc(u3 | 0, 0, w2 & 7 | 0) | 0; + ya3 = C2; + x3 = h2 | x3; + A3 = v3; + F3 = A3; + a[F3 >> 0] = x3; + a[F3 + 1 >> 0] = x3 >> 8; + a[F3 + 2 >> 0] = x3 >> 16; + a[F3 + 3 >> 0] = x3 >> 24; + A3 = A3 + 4 | 0; + a[A3 >> 0] = ya3; + a[A3 + 1 >> 0] = ya3 >> 8; + a[A3 + 2 >> 0] = ya3 >> 16; + a[A3 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + G3; + A3 = sa3 + (H3 << 2) | 0; + c[A3 >> 2] = (c[A3 >> 2] | 0) + 1; + A3 = 0; + break; + } + if (J3 >>> 0 >= 2114) { + u3 = a[$2 >> 0] | 0; + v3 = e[ba2 >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 77; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 79; + break a; + } + ya3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + h2 = C2; + ya3 = x3 | ya3; + v3 = w2; + w2 = v3; + a[w2 >> 0] = ya3; + a[w2 + 1 >> 0] = ya3 >> 8; + a[w2 + 2 >> 0] = ya3 >> 16; + a[w2 + 3 >> 0] = ya3 >> 24; + v3 = v3 + 4 | 0; + a[v3 >> 0] = h2; + a[v3 + 1 >> 0] = h2 >> 8; + a[v3 + 2 >> 0] = h2 >> 16; + a[v3 + 3 >> 0] = h2 >> 24; + u3 = (c[q2 >> 2] | 0) + (u3 & 255) | 0; + c[q2 >> 2] = u3; + v3 = J3 + -2114 | 0; + h2 = r2 + (u3 >>> 3) | 0; + w2 = d[h2 >> 0] | 0; + if (!((v3 & -4096 | 0) == 0 & true)) { + wa3 = 81; + break a; + } + G3 = cc(v3 | 0, 0, u3 & 7 | 0) | 0; + ya3 = C2; + G3 = w2 | G3; + A3 = h2; + H3 = A3; + a[H3 >> 0] = G3; + a[H3 + 1 >> 0] = G3 >> 8; + a[H3 + 2 >> 0] = G3 >> 16; + a[H3 + 3 >> 0] = G3 >> 24; + A3 = A3 + 4 | 0; + a[A3 >> 0] = ya3; + a[A3 + 1 >> 0] = ya3 >> 8; + a[A3 + 2 >> 0] = ya3 >> 16; + a[A3 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 12; + c[ca3 >> 2] = (c[ca3 >> 2] | 0) + 1; + A3 = 0; + break; + } + A3 = J3 + -66 | 0; + F3 = (aa(A3 | 0) | 0) ^ 31; + G3 = F3 + 50 | 0; + u3 = a[m3 + G3 >> 0] | 0; + v3 = e[n2 + (G3 << 1) >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 68; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 70; + break a; + } + ya3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + v3 = C2; + ya3 = x3 | ya3; + h2 = w2; + a[h2 >> 0] = ya3; + a[h2 + 1 >> 0] = ya3 >> 8; + a[h2 + 2 >> 0] = ya3 >> 16; + a[h2 + 3 >> 0] = ya3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = v3; + a[w2 + 1 >> 0] = v3 >> 8; + a[w2 + 2 >> 0] = v3 >> 16; + a[w2 + 3 >> 0] = v3 >> 24; + w2 = (c[q2 >> 2] | 0) + (u3 & 255) | 0; + c[q2 >> 2] = w2; + u3 = A3 - (1 << F3) | 0; + v3 = r2 + (w2 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(u3 | 0, 0, F3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 72; + break a; + } + if (F3 >>> 0 >= 57) { + wa3 = 74; + break a; + } + x3 = cc(u3 | 0, 0, w2 & 7 | 0) | 0; + ya3 = C2; + x3 = h2 | x3; + A3 = v3; + H3 = A3; + a[H3 >> 0] = x3; + a[H3 + 1 >> 0] = x3 >> 8; + a[H3 + 2 >> 0] = x3 >> 16; + a[H3 + 3 >> 0] = x3 >> 24; + A3 = A3 + 4 | 0; + a[A3 >> 0] = ya3; + a[A3 + 1 >> 0] = ya3 >> 8; + a[A3 + 2 >> 0] = ya3 >> 16; + a[A3 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + F3; + A3 = sa3 + (G3 << 2) | 0; + c[A3 >> 2] = (c[A3 >> 2] | 0) + 1; + A3 = 0; + } + while (0); + while (1) { + if (A3 >>> 0 >= J3 >>> 0) break; + v3 = d[K3 + A3 >> 0] | 0; + u3 = a[va3 + v3 >> 0] | 0; + v3 = e[ua3 + (v3 << 1) >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 102; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 104; + break a; + } + F3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + H3 = C2; + F3 = x3 | F3; + ya3 = w2; + G3 = ya3; + a[G3 >> 0] = F3; + a[G3 + 1 >> 0] = F3 >> 8; + a[G3 + 2 >> 0] = F3 >> 16; + a[G3 + 3 >> 0] = F3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = H3; + a[ya3 + 1 >> 0] = H3 >> 8; + a[ya3 + 2 >> 0] = H3 >> 16; + a[ya3 + 3 >> 0] = H3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (u3 & 255); + A3 = A3 + 1 | 0; + } + if ((I3 | 0) == (M2 | 0)) { + u3 = a[da3 >> 0] | 0; + v3 = e[ea3 >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 108; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 110; + break a; + } + J3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + ya3 = C2; + J3 = x3 | J3; + I3 = w2; + K3 = I3; + a[K3 >> 0] = J3; + a[K3 + 1 >> 0] = J3 >> 8; + a[K3 + 2 >> 0] = J3 >> 16; + a[K3 + 3 >> 0] = J3 >> 24; + I3 = I3 + 4 | 0; + a[I3 >> 0] = ya3; + a[I3 + 1 >> 0] = ya3 >> 8; + a[I3 + 2 >> 0] = ya3 >> 16; + a[I3 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (u3 & 255); + c[fa3 >> 2] = (c[fa3 >> 2] | 0) + 1; + I3 = M2; + } else { + A3 = I3 + 3 | 0; + G3 = ((aa(A3 | 0) | 0) ^ 31) + -1 | 0; + F3 = A3 >>> G3 & 1; + H3 = ((G3 << 1) + -2 | F3) + 80 | 0; + u3 = a[m3 + H3 >> 0] | 0; + v3 = e[n2 + (H3 << 1) >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 113; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 115; + break a; + } + ya3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + v3 = C2; + ya3 = x3 | ya3; + h2 = w2; + a[h2 >> 0] = ya3; + a[h2 + 1 >> 0] = ya3 >> 8; + a[h2 + 2 >> 0] = ya3 >> 16; + a[h2 + 3 >> 0] = ya3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = v3; + a[w2 + 1 >> 0] = v3 >> 8; + a[w2 + 2 >> 0] = v3 >> 16; + a[w2 + 3 >> 0] = v3 >> 24; + w2 = (c[q2 >> 2] | 0) + (u3 & 255) | 0; + c[q2 >> 2] = w2; + u3 = A3 - ((F3 | 2) << G3) | 0; + v3 = r2 + (w2 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(u3 | 0, 0, G3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 117; + break a; + } + if (G3 >>> 0 >= 57) { + wa3 = 119; + break a; + } + J3 = cc(u3 | 0, 0, w2 & 7 | 0) | 0; + M2 = C2; + J3 = h2 | J3; + ya3 = v3; + K3 = ya3; + a[K3 >> 0] = J3; + a[K3 + 1 >> 0] = J3 >> 8; + a[K3 + 2 >> 0] = J3 >> 16; + a[K3 + 3 >> 0] = J3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = M2; + a[ya3 + 1 >> 0] = M2 >> 8; + a[ya3 + 2 >> 0] = M2 >> 16; + a[ya3 + 3 >> 0] = M2 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + G3; + ya3 = sa3 + (H3 << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + } + do + if (L3 >>> 0 < 12) { + u3 = P3 + 1 | 0; + v3 = a[m3 + u3 >> 0] | 0; + h2 = e[n2 + (u3 << 1) >> 1] | 0; + w2 = c[q2 >> 2] | 0; + x3 = r2 + (w2 >>> 3) | 0; + A3 = d[x3 >> 0] | 0; + ya3 = bc(h2 | 0, 0, v3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 123; + break a; + } + if ((v3 & 255) >= 57) { + wa3 = 125; + break a; + } + K3 = cc(h2 | 0, 0, w2 & 7 | 0) | 0; + M2 = C2; + K3 = A3 | K3; + ya3 = x3; + L3 = ya3; + a[L3 >> 0] = K3; + a[L3 + 1 >> 0] = K3 >> 8; + a[L3 + 2 >> 0] = K3 >> 16; + a[L3 + 3 >> 0] = K3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = M2; + a[ya3 + 1 >> 0] = M2 >> 8; + a[ya3 + 2 >> 0] = M2 >> 16; + a[ya3 + 3 >> 0] = M2 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (v3 & 255); + ya3 = sa3 + (u3 << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + } else { + if (L3 >>> 0 < 72) { + A3 = P3 + -3 | 0; + G3 = ((aa(A3 | 0) | 0) ^ 31) + -1 | 0; + F3 = A3 >>> G3; + H3 = (G3 << 1) + F3 + 4 | 0; + u3 = a[m3 + H3 >> 0] | 0; + v3 = e[n2 + (H3 << 1) >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 129; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 131; + break a; + } + ya3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + v3 = C2; + ya3 = x3 | ya3; + h2 = w2; + a[h2 >> 0] = ya3; + a[h2 + 1 >> 0] = ya3 >> 8; + a[h2 + 2 >> 0] = ya3 >> 16; + a[h2 + 3 >> 0] = ya3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = v3; + a[w2 + 1 >> 0] = v3 >> 8; + a[w2 + 2 >> 0] = v3 >> 16; + a[w2 + 3 >> 0] = v3 >> 24; + w2 = (c[q2 >> 2] | 0) + (u3 & 255) | 0; + c[q2 >> 2] = w2; + u3 = A3 - (F3 << G3) | 0; + v3 = r2 + (w2 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(u3 | 0, 0, G3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 133; + break a; + } + if (G3 >>> 0 >= 57) { + wa3 = 135; + break a; + } + K3 = cc(u3 | 0, 0, w2 & 7 | 0) | 0; + M2 = C2; + K3 = h2 | K3; + ya3 = v3; + L3 = ya3; + a[L3 >> 0] = K3; + a[L3 + 1 >> 0] = K3 >> 8; + a[L3 + 2 >> 0] = K3 >> 16; + a[L3 + 3 >> 0] = K3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = M2; + a[ya3 + 1 >> 0] = M2 >> 8; + a[ya3 + 2 >> 0] = M2 >> 16; + a[ya3 + 3 >> 0] = M2 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + G3; + ya3 = sa3 + (H3 << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + break; + } + if (L3 >>> 0 < 136) { + u3 = P3 + -3 | 0; + F3 = (u3 >>> 5) + 30 | 0; + v3 = a[m3 + F3 >> 0] | 0; + h2 = e[n2 + (F3 << 1) >> 1] | 0; + w2 = c[q2 >> 2] | 0; + x3 = r2 + (w2 >>> 3) | 0; + A3 = d[x3 >> 0] | 0; + ya3 = bc(h2 | 0, 0, v3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 139; + break a; + } + if ((v3 & 255) >= 57) { + wa3 = 141; + break a; + } + ya3 = cc(h2 | 0, 0, w2 & 7 | 0) | 0; + h2 = C2; + ya3 = A3 | ya3; + w2 = x3; + x3 = w2; + a[x3 >> 0] = ya3; + a[x3 + 1 >> 0] = ya3 >> 8; + a[x3 + 2 >> 0] = ya3 >> 16; + a[x3 + 3 >> 0] = ya3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = h2; + a[w2 + 1 >> 0] = h2 >> 8; + a[w2 + 2 >> 0] = h2 >> 16; + a[w2 + 3 >> 0] = h2 >> 24; + w2 = (c[q2 >> 2] | 0) + (v3 & 255) | 0; + c[q2 >> 2] = w2; + h2 = r2 + (w2 >>> 3) | 0; + x3 = d[h2 >> 0] | 0; + w2 = cc(u3 & 31 | 0, 0, w2 & 7 | 0) | 0; + v3 = C2; + w2 = x3 | w2; + u3 = h2; + h2 = u3; + a[h2 >> 0] = w2; + a[h2 + 1 >> 0] = w2 >> 8; + a[h2 + 2 >> 0] = w2 >> 16; + a[h2 + 3 >> 0] = w2 >> 24; + u3 = u3 + 4 | 0; + a[u3 >> 0] = v3; + a[u3 + 1 >> 0] = v3 >> 8; + a[u3 + 2 >> 0] = v3 >> 16; + a[u3 + 3 >> 0] = v3 >> 24; + u3 = (c[q2 >> 2] | 0) + 5 | 0; + c[q2 >> 2] = u3; + v3 = a[da3 >> 0] | 0; + h2 = e[ea3 >> 1] | 0; + w2 = r2 + (u3 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(h2 | 0, 0, v3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 143; + break a; + } + if ((v3 & 255) >= 57) { + wa3 = 145; + break a; + } + K3 = cc(h2 | 0, 0, u3 & 7 | 0) | 0; + M2 = C2; + K3 = x3 | K3; + ya3 = w2; + L3 = ya3; + a[L3 >> 0] = K3; + a[L3 + 1 >> 0] = K3 >> 8; + a[L3 + 2 >> 0] = K3 >> 16; + a[L3 + 3 >> 0] = K3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = M2; + a[ya3 + 1 >> 0] = M2 >> 8; + a[ya3 + 2 >> 0] = M2 >> 16; + a[ya3 + 3 >> 0] = M2 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (v3 & 255); + ya3 = sa3 + (F3 << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + c[ja3 >> 2] = (c[ja3 >> 2] | 0) + 1; + break; + } + if (L3 >>> 0 >= 2120) { + u3 = a[ga3 >> 0] | 0; + v3 = e[ha3 >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 162; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 164; + break a; + } + ya3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + h2 = C2; + ya3 = x3 | ya3; + v3 = w2; + w2 = v3; + a[w2 >> 0] = ya3; + a[w2 + 1 >> 0] = ya3 >> 8; + a[w2 + 2 >> 0] = ya3 >> 16; + a[w2 + 3 >> 0] = ya3 >> 24; + v3 = v3 + 4 | 0; + a[v3 >> 0] = h2; + a[v3 + 1 >> 0] = h2 >> 8; + a[v3 + 2 >> 0] = h2 >> 16; + a[v3 + 3 >> 0] = h2 >> 24; + u3 = (c[q2 >> 2] | 0) + (u3 & 255) | 0; + c[q2 >> 2] = u3; + v3 = P3 + -2115 | 0; + h2 = r2 + (u3 >>> 3) | 0; + w2 = d[h2 >> 0] | 0; + if (!((v3 & -16777216 | 0) == 0 & true)) { + wa3 = 166; + break a; + } + u3 = cc(v3 | 0, 0, u3 & 7 | 0) | 0; + v3 = C2; + w2 = w2 | u3; + u3 = h2; + h2 = u3; + a[h2 >> 0] = w2; + a[h2 + 1 >> 0] = w2 >> 8; + a[h2 + 2 >> 0] = w2 >> 16; + a[h2 + 3 >> 0] = w2 >> 24; + u3 = u3 + 4 | 0; + a[u3 >> 0] = v3; + a[u3 + 1 >> 0] = v3 >> 8; + a[u3 + 2 >> 0] = v3 >> 16; + a[u3 + 3 >> 0] = v3 >> 24; + u3 = (c[q2 >> 2] | 0) + 24 | 0; + c[q2 >> 2] = u3; + v3 = a[da3 >> 0] | 0; + h2 = e[ea3 >> 1] | 0; + w2 = r2 + (u3 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(h2 | 0, 0, v3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 168; + break a; + } + if ((v3 & 255) >= 57) { + wa3 = 170; + break a; + } + K3 = cc(h2 | 0, 0, u3 & 7 | 0) | 0; + M2 = C2; + K3 = x3 | K3; + ya3 = w2; + L3 = ya3; + a[L3 >> 0] = K3; + a[L3 + 1 >> 0] = K3 >> 8; + a[L3 + 2 >> 0] = K3 >> 16; + a[L3 + 3 >> 0] = K3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = M2; + a[ya3 + 1 >> 0] = M2 >> 8; + a[ya3 + 2 >> 0] = M2 >> 16; + a[ya3 + 3 >> 0] = M2 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (v3 & 255); + c[ia3 >> 2] = (c[ia3 >> 2] | 0) + 1; + c[ja3 >> 2] = (c[ja3 >> 2] | 0) + 1; + break; + } + A3 = P3 + -67 | 0; + F3 = (aa(A3 | 0) | 0) ^ 31; + G3 = F3 + 28 | 0; + u3 = a[m3 + G3 >> 0] | 0; + v3 = e[n2 + (G3 << 1) >> 1] | 0; + h2 = c[q2 >> 2] | 0; + w2 = r2 + (h2 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(v3 | 0, 0, u3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 149; + break a; + } + if ((u3 & 255) >= 57) { + wa3 = 151; + break a; + } + ya3 = cc(v3 | 0, 0, h2 & 7 | 0) | 0; + v3 = C2; + ya3 = x3 | ya3; + h2 = w2; + a[h2 >> 0] = ya3; + a[h2 + 1 >> 0] = ya3 >> 8; + a[h2 + 2 >> 0] = ya3 >> 16; + a[h2 + 3 >> 0] = ya3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = v3; + a[w2 + 1 >> 0] = v3 >> 8; + a[w2 + 2 >> 0] = v3 >> 16; + a[w2 + 3 >> 0] = v3 >> 24; + w2 = (c[q2 >> 2] | 0) + (u3 & 255) | 0; + c[q2 >> 2] = w2; + u3 = A3 - (1 << F3) | 0; + v3 = r2 + (w2 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(u3 | 0, 0, F3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 153; + break a; + } + if (F3 >>> 0 >= 57) { + wa3 = 155; + break a; + } + u3 = cc(u3 | 0, 0, w2 & 7 | 0) | 0; + w2 = C2; + h2 = h2 | u3; + u3 = v3; + v3 = u3; + a[v3 >> 0] = h2; + a[v3 + 1 >> 0] = h2 >> 8; + a[v3 + 2 >> 0] = h2 >> 16; + a[v3 + 3 >> 0] = h2 >> 24; + u3 = u3 + 4 | 0; + a[u3 >> 0] = w2; + a[u3 + 1 >> 0] = w2 >> 8; + a[u3 + 2 >> 0] = w2 >> 16; + a[u3 + 3 >> 0] = w2 >> 24; + u3 = (c[q2 >> 2] | 0) + F3 | 0; + c[q2 >> 2] = u3; + v3 = a[da3 >> 0] | 0; + h2 = e[ea3 >> 1] | 0; + w2 = r2 + (u3 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(h2 | 0, 0, v3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 157; + break a; + } + if ((v3 & 255) >= 57) { + wa3 = 159; + break a; + } + K3 = cc(h2 | 0, 0, u3 & 7 | 0) | 0; + M2 = C2; + K3 = x3 | K3; + ya3 = w2; + L3 = ya3; + a[L3 >> 0] = K3; + a[L3 + 1 >> 0] = K3 >> 8; + a[L3 + 2 >> 0] = K3 >> 16; + a[L3 + 3 >> 0] = K3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = M2; + a[ya3 + 1 >> 0] = M2 >> 8; + a[ya3 + 2 >> 0] = M2 >> 16; + a[ya3 + 3 >> 0] = M2 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (v3 & 255); + ya3 = sa3 + (G3 << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + c[ja3 >> 2] = (c[ja3 >> 2] | 0) + 1; + } + while (0); + if (N3 >>> 0 >= S3 >>> 0) { + v3 = O3; + break c; + } + v3 = Q3 + (P3 + 2) | 0; + ya3 = v3; + ya3 = d[ya3 >> 0] | d[ya3 + 1 >> 0] << 8 | d[ya3 + 2 >> 0] << 16 | d[ya3 + 3 >> 0] << 24; + v3 = v3 + 4 | 0; + v3 = d[v3 >> 0] | d[v3 + 1 >> 0] << 8 | d[v3 + 2 >> 0] << 16 | d[v3 + 3 >> 0] << 24; + Q3 = lc(ya3 | 0, v3 | 0, -1124073472, 1979815) | 0; + Q3 = bc(Q3 | 0, C2 | 0, ra3 | 0) | 0; + x3 = bc(ya3 | 0, v3 | 0, 24) | 0; + x3 = lc(x3 | 0, C2 | 0, -1124073472, 1979815) | 0; + x3 = bc(x3 | 0, C2 | 0, ra3 | 0) | 0; + A3 = N3 - _2 | 0; + c[k2 + (Q3 << 2) >> 2] = A3 + -3; + Q3 = bc(ya3 | 0, v3 | 0, 8) | 0; + Q3 = lc(Q3 | 0, C2 | 0, -1124073472, 1979815) | 0; + Q3 = bc(Q3 | 0, C2 | 0, ra3 | 0) | 0; + c[k2 + (Q3 << 2) >> 2] = A3 + -2; + v3 = bc(ya3 | 0, v3 | 0, 16) | 0; + v3 = lc(v3 | 0, C2 | 0, -1124073472, 1979815) | 0; + v3 = bc(v3 | 0, C2 | 0, ra3 | 0) | 0; + c[k2 + (v3 << 2) >> 2] = A3 + -1; + x3 = k2 + (x3 << 2) | 0; + v3 = c[x3 >> 2] | 0; + c[x3 >> 2] = A3; + x3 = I3; + A3 = O3; + while (1) { + H3 = f2 + v3 | 0; + ya3 = A3; + u3 = A3; + if ((d[ya3 >> 0] | d[ya3 + 1 >> 0] << 8 | d[ya3 + 2 >> 0] << 16 | d[ya3 + 3 >> 0] << 24 | 0) != (d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24 | 0)) break; + if ((a[u3 + 4 >> 0] | 0) != (a[f2 + (v3 + 4) >> 0] | 0)) break; + w2 = v3 + 5 | 0; + v3 = 0; + h2 = u3 + 5 | 0; + while (1) { + if (h2 >>> 0 > R3 >>> 0) break; + ya3 = f2 + (w2 + v3) | 0; + if ((d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0) != (d[ya3 >> 0] | d[ya3 + 1 >> 0] << 8 | d[ya3 + 2 >> 0] << 16 | d[ya3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + h2 = h2 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= t3 >>> 0) break; + if ((a[f2 + (w2 + v3) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + h2 = h2 + 1 | 0; + } + G3 = v3 + 5 | 0; + K3 = u3 + G3 | 0; + M2 = K3; + L3 = A3 - H3 | 0; + do + if (!G3) wa3 = 189; + else { + A3 = G3; + F3 = u3; + x3 = H3; + while (1) { + h2 = a[F3 >> 0] | 0; + w2 = a[x3 >> 0] | 0; + if (h2 << 24 >> 24 != w2 << 24 >> 24) { + wa3 = 186; + break; + } + A3 = A3 + -1 | 0; + if (!A3) break; + else { + F3 = F3 + 1 | 0; + x3 = x3 + 1 | 0; + } + } + if ((wa3 | 0) == 186 ? (wa3 = 0, h2 << 24 >> 24 != w2 << 24 >> 24) : 0) { + wa3 = 187; + break a; + } + if (G3 >>> 0 < 10) { + wa3 = 189; + break; + } + if (G3 >>> 0 < 134) { + G3 = v3 + -1 | 0; + I3 = ((aa(G3 | 0) | 0) ^ 31) + -1 | 0; + H3 = G3 >>> I3; + J3 = (I3 << 1) + H3 + 20 | 0; + h2 = a[m3 + J3 >> 0] | 0; + w2 = e[n2 + (J3 << 1) >> 1] | 0; + x3 = c[q2 >> 2] | 0; + A3 = r2 + (x3 >>> 3) | 0; + F3 = d[A3 >> 0] | 0; + ya3 = bc(w2 | 0, 0, h2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 196; + break a; + } + if ((h2 & 255) >= 57) { + wa3 = 198; + break a; + } + ya3 = cc(w2 | 0, 0, x3 & 7 | 0) | 0; + w2 = C2; + ya3 = F3 | ya3; + x3 = A3; + a[x3 >> 0] = ya3; + a[x3 + 1 >> 0] = ya3 >> 8; + a[x3 + 2 >> 0] = ya3 >> 16; + a[x3 + 3 >> 0] = ya3 >> 24; + A3 = A3 + 4 | 0; + a[A3 >> 0] = w2; + a[A3 + 1 >> 0] = w2 >> 8; + a[A3 + 2 >> 0] = w2 >> 16; + a[A3 + 3 >> 0] = w2 >> 24; + A3 = (c[q2 >> 2] | 0) + (h2 & 255) | 0; + c[q2 >> 2] = A3; + h2 = G3 - (H3 << I3) | 0; + w2 = r2 + (A3 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(h2 | 0, 0, I3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 200; + break a; + } + if (I3 >>> 0 >= 57) { + wa3 = 202; + break a; + } + O3 = cc(h2 | 0, 0, A3 & 7 | 0) | 0; + Q3 = C2; + O3 = x3 | O3; + ya3 = w2; + P3 = ya3; + a[P3 >> 0] = O3; + a[P3 + 1 >> 0] = O3 >> 8; + a[P3 + 2 >> 0] = O3 >> 16; + a[P3 + 3 >> 0] = O3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = Q3; + a[ya3 + 1 >> 0] = Q3 >> 8; + a[ya3 + 2 >> 0] = Q3 >> 16; + a[ya3 + 3 >> 0] = Q3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + I3; + ya3 = sa3 + (J3 << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + break; + } + if (G3 >>> 0 >= 2118) { + h2 = a[ga3 >> 0] | 0; + w2 = e[ha3 >> 1] | 0; + x3 = c[q2 >> 2] | 0; + A3 = r2 + (x3 >>> 3) | 0; + F3 = d[A3 >> 0] | 0; + ya3 = bc(w2 | 0, 0, h2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 215; + break a; + } + if ((h2 & 255) >= 57) { + wa3 = 217; + break a; + } + ya3 = cc(w2 | 0, 0, x3 & 7 | 0) | 0; + x3 = C2; + ya3 = F3 | ya3; + w2 = A3; + A3 = w2; + a[A3 >> 0] = ya3; + a[A3 + 1 >> 0] = ya3 >> 8; + a[A3 + 2 >> 0] = ya3 >> 16; + a[A3 + 3 >> 0] = ya3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = x3; + a[w2 + 1 >> 0] = x3 >> 8; + a[w2 + 2 >> 0] = x3 >> 16; + a[w2 + 3 >> 0] = x3 >> 24; + h2 = (c[q2 >> 2] | 0) + (h2 & 255) | 0; + c[q2 >> 2] = h2; + w2 = v3 + -2113 | 0; + x3 = r2 + (h2 >>> 3) | 0; + A3 = d[x3 >> 0] | 0; + if (!((w2 & -16777216 | 0) == 0 & true)) { + wa3 = 219; + break a; + } + O3 = cc(w2 | 0, 0, h2 & 7 | 0) | 0; + Q3 = C2; + O3 = A3 | O3; + ya3 = x3; + P3 = ya3; + a[P3 >> 0] = O3; + a[P3 + 1 >> 0] = O3 >> 8; + a[P3 + 2 >> 0] = O3 >> 16; + a[P3 + 3 >> 0] = O3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = Q3; + a[ya3 + 1 >> 0] = Q3 >> 8; + a[ya3 + 2 >> 0] = Q3 >> 16; + a[ya3 + 3 >> 0] = Q3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 24; + c[ia3 >> 2] = (c[ia3 >> 2] | 0) + 1; + break; + } + G3 = v3 + -65 | 0; + H3 = (aa(G3 | 0) | 0) ^ 31; + I3 = H3 + 28 | 0; + h2 = a[m3 + I3 >> 0] | 0; + w2 = e[n2 + (I3 << 1) >> 1] | 0; + x3 = c[q2 >> 2] | 0; + A3 = r2 + (x3 >>> 3) | 0; + F3 = d[A3 >> 0] | 0; + ya3 = bc(w2 | 0, 0, h2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 206; + break a; + } + if ((h2 & 255) >= 57) { + wa3 = 208; + break a; + } + ya3 = cc(w2 | 0, 0, x3 & 7 | 0) | 0; + w2 = C2; + ya3 = F3 | ya3; + x3 = A3; + a[x3 >> 0] = ya3; + a[x3 + 1 >> 0] = ya3 >> 8; + a[x3 + 2 >> 0] = ya3 >> 16; + a[x3 + 3 >> 0] = ya3 >> 24; + A3 = A3 + 4 | 0; + a[A3 >> 0] = w2; + a[A3 + 1 >> 0] = w2 >> 8; + a[A3 + 2 >> 0] = w2 >> 16; + a[A3 + 3 >> 0] = w2 >> 24; + A3 = (c[q2 >> 2] | 0) + (h2 & 255) | 0; + c[q2 >> 2] = A3; + h2 = G3 - (1 << H3) | 0; + w2 = r2 + (A3 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(h2 | 0, 0, H3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 210; + break a; + } + if (H3 >>> 0 >= 57) { + wa3 = 212; + break a; + } + O3 = cc(h2 | 0, 0, A3 & 7 | 0) | 0; + Q3 = C2; + O3 = x3 | O3; + ya3 = w2; + P3 = ya3; + a[P3 >> 0] = O3; + a[P3 + 1 >> 0] = O3 >> 8; + a[P3 + 2 >> 0] = O3 >> 16; + a[P3 + 3 >> 0] = O3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = Q3; + a[ya3 + 1 >> 0] = Q3 >> 8; + a[ya3 + 2 >> 0] = Q3 >> 16; + a[ya3 + 3 >> 0] = Q3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + H3; + ya3 = sa3 + (I3 << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + } + while (0); + if ((wa3 | 0) == 189) { + wa3 = 0; + h2 = v3 + 19 | 0; + w2 = a[m3 + h2 >> 0] | 0; + x3 = e[n2 + (h2 << 1) >> 1] | 0; + A3 = c[q2 >> 2] | 0; + F3 = r2 + (A3 >>> 3) | 0; + G3 = d[F3 >> 0] | 0; + ya3 = bc(x3 | 0, 0, w2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 190; + break a; + } + if ((w2 & 255) >= 57) { + wa3 = 192; + break a; + } + O3 = cc(x3 | 0, 0, A3 & 7 | 0) | 0; + Q3 = C2; + O3 = G3 | O3; + ya3 = F3; + P3 = ya3; + a[P3 >> 0] = O3; + a[P3 + 1 >> 0] = O3 >> 8; + a[P3 + 2 >> 0] = O3 >> 16; + a[P3 + 3 >> 0] = O3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = Q3; + a[ya3 + 1 >> 0] = Q3 >> 8; + a[ya3 + 2 >> 0] = Q3 >> 16; + a[ya3 + 3 >> 0] = Q3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (w2 & 255); + ya3 = sa3 + (h2 << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + } + G3 = L3 + 3 | 0; + I3 = ((aa(G3 | 0) | 0) ^ 31) + -1 | 0; + H3 = G3 >>> I3 & 1; + J3 = ((I3 << 1) + -2 | H3) + 80 | 0; + h2 = a[m3 + J3 >> 0] | 0; + w2 = e[n2 + (J3 << 1) >> 1] | 0; + x3 = c[q2 >> 2] | 0; + A3 = r2 + (x3 >>> 3) | 0; + F3 = d[A3 >> 0] | 0; + ya3 = bc(w2 | 0, 0, h2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 222; + break a; + } + if ((h2 & 255) >= 57) { + wa3 = 224; + break a; + } + ya3 = cc(w2 | 0, 0, x3 & 7 | 0) | 0; + w2 = C2; + ya3 = F3 | ya3; + x3 = A3; + a[x3 >> 0] = ya3; + a[x3 + 1 >> 0] = ya3 >> 8; + a[x3 + 2 >> 0] = ya3 >> 16; + a[x3 + 3 >> 0] = ya3 >> 24; + A3 = A3 + 4 | 0; + a[A3 >> 0] = w2; + a[A3 + 1 >> 0] = w2 >> 8; + a[A3 + 2 >> 0] = w2 >> 16; + a[A3 + 3 >> 0] = w2 >> 24; + A3 = (c[q2 >> 2] | 0) + (h2 & 255) | 0; + c[q2 >> 2] = A3; + h2 = G3 - ((H3 | 2) << I3) | 0; + w2 = r2 + (A3 >>> 3) | 0; + x3 = d[w2 >> 0] | 0; + ya3 = bc(h2 | 0, 0, I3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 226; + break a; + } + if (I3 >>> 0 >= 57) { + wa3 = 228; + break a; + } + O3 = cc(h2 | 0, 0, A3 & 7 | 0) | 0; + Q3 = C2; + O3 = x3 | O3; + ya3 = w2; + P3 = ya3; + a[P3 >> 0] = O3; + a[P3 + 1 >> 0] = O3 >> 8; + a[P3 + 2 >> 0] = O3 >> 16; + a[P3 + 3 >> 0] = O3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = Q3; + a[ya3 + 1 >> 0] = Q3 >> 8; + a[ya3 + 2 >> 0] = Q3 >> 16; + a[ya3 + 3 >> 0] = Q3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + I3; + ya3 = sa3 + (J3 << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + if (K3 >>> 0 >= S3 >>> 0) { + v3 = M2; + break c; + } + v3 = u3 + (v3 + 2) | 0; + ya3 = v3; + ya3 = d[ya3 >> 0] | d[ya3 + 1 >> 0] << 8 | d[ya3 + 2 >> 0] << 16 | d[ya3 + 3 >> 0] << 24; + v3 = v3 + 4 | 0; + v3 = d[v3 >> 0] | d[v3 + 1 >> 0] << 8 | d[v3 + 2 >> 0] << 16 | d[v3 + 3 >> 0] << 24; + Q3 = lc(ya3 | 0, v3 | 0, -1124073472, 1979815) | 0; + Q3 = bc(Q3 | 0, C2 | 0, ra3 | 0) | 0; + x3 = bc(ya3 | 0, v3 | 0, 24) | 0; + x3 = lc(x3 | 0, C2 | 0, -1124073472, 1979815) | 0; + x3 = bc(x3 | 0, C2 | 0, ra3 | 0) | 0; + A3 = K3 - _2 | 0; + c[k2 + (Q3 << 2) >> 2] = A3 + -3; + Q3 = bc(ya3 | 0, v3 | 0, 8) | 0; + Q3 = lc(Q3 | 0, C2 | 0, -1124073472, 1979815) | 0; + Q3 = bc(Q3 | 0, C2 | 0, ra3 | 0) | 0; + c[k2 + (Q3 << 2) >> 2] = A3 + -2; + v3 = bc(ya3 | 0, v3 | 0, 16) | 0; + v3 = lc(v3 | 0, C2 | 0, -1124073472, 1979815) | 0; + v3 = bc(v3 | 0, C2 | 0, ra3 | 0) | 0; + c[k2 + (v3 << 2) >> 2] = A3 + -1; + x3 = k2 + (x3 << 2) | 0; + v3 = c[x3 >> 2] | 0; + c[x3 >> 2] = A3; + x3 = L3; + A3 = M2; + } + w2 = u3 + 1 | 0; + h2 = w2; + u3 = h2; + h2 = h2 + 4 | 0; + u3 = d[u3 >> 0] | d[u3 + 1 >> 0] << 8 | d[u3 + 2 >> 0] << 16 | d[u3 + 3 >> 0] << 24; + h2 = d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24; + M2 = x3; + v3 = A3; + } + } + while (0); + G3 = v3; + if (G3 >>> 0 > t3 >>> 0) { + wa3 = 233; + break a; + } + h2 = l2 - V3 | 0; + w2 = h2 >>> 0 < 65536 ? h2 : 65536; + if ((l2 | 0) == (V3 | 0)) { + l2 = 0; + wa3 = 254; + break; + } + x3 = W3 + w2 | 0; + if (x3 >>> 0 >= 1048577) { + l2 = h2; + wa3 = 254; + break; + } + ac(ta3 | 0, 0, 1024) | 0; + l2 = 0; + while (1) { + if (l2 >>> 0 >= w2 >>> 0) break; + ya3 = ta3 + (d[U3 + (V3 + l2) >> 0] << 2) | 0; + c[ya3 >> 2] = (c[ya3 >> 2] | 0) + 1; + l2 = l2 + 43 | 0; + } + ya3 = w2 + 42 | 0; + l2 = (ya3 >>> 0) / 43 | 0; + if (ya3 >>> 0 < 11008) { + z3 = +(l2 >>> 0); + y3 = +g2[19516 + (l2 << 2) >> 2]; + } else { + y3 = +(l2 >>> 0); + z3 = y3; + y3 = +Xb(y3); + } + E3 = (y3 + 0.5) * z3 + 200; + u3 = 0; + while (1) { + if ((u3 | 0) == 256) break; + l2 = c[ta3 + (u3 << 2) >> 2] | 0; + z3 = +(l2 >>> 0); + D3 = +(d[va3 + u3 >> 0] | 0); + if (l2 >>> 0 < 256) y3 = +g2[19516 + (l2 << 2) >> 2]; + else y3 = +Xb(z3); + E3 = E3 - z3 * (D3 + y3); + u3 = u3 + 1 | 0; + } + if (!(E3 >= 0)) { + l2 = h2; + wa3 = 254; + break; + } + if (W3 >>> 0 <= 65536) { + wa3 = 250; + break a; + } + l2 = 20; + t3 = x3 + -1 | 0; + u3 = X3; + while (1) { + if (!l2) { + l2 = h2; + T3 = Z3; + V3 = w2; + W3 = x3; + continue b; + } + V3 = u3 & 7; + ya3 = 8 - V3 | 0; + ya3 = l2 >>> 0 < ya3 >>> 0 ? l2 : ya3; + W3 = r2 + (u3 >>> 3) | 0; + a[W3 >> 0] = (t3 & (1 << ya3) + -1) << V3 | d[W3 >> 0] & (-1 << V3 + ya3 | (1 << V3) + 255); + l2 = l2 - ya3 | 0; + t3 = t3 >>> ya3; + u3 = u3 + ya3 | 0; + } + } + e: do + if ((wa3 | 0) == 84) { + wa3 = 0; + ya3 = H3 - s2 | 0; + Z3 = r2 + (B3 >>> 3) | 0; + a[Z3 >> 0] = d[Z3 >> 0] & (1 << (B3 & 7)) + 255; + c[q2 >> 2] = B3; + vb(ya3, 1, q2, r2); + Z3 = (c[q2 >> 2] | 0) + 7 | 0; + c[q2 >> 2] = Z3 & -8; + dc(r2 + (Z3 >>> 3) | 0, s2 | 0, ya3 | 0) | 0; + s2 = (c[q2 >> 2] | 0) + (ya3 << 3) | 0; + c[q2 >> 2] = s2; + a[r2 + (s2 >>> 3) >> 0] = 0; + l2 = l2 + (T3 - H3) | 0; + s2 = H3; + } else if ((wa3 | 0) == 254) { + wa3 = 0; + if (G3 >>> 0 < t3 >>> 0) { + F3 = t3 - v3 | 0; + if (F3 >>> 0 >= 6210) { + if (!(((v3 - s2 | 0) * 50 | 0) >>> 0 > F3 >>> 0 | Y3 ^ 1)) { + ya3 = t3 - s2 | 0; + Y3 = r2 + (B3 >>> 3) | 0; + a[Y3 >> 0] = d[Y3 >> 0] & (1 << (B3 & 7)) + 255; + c[q2 >> 2] = B3; + vb(ya3, 1, q2, r2); + Y3 = (c[q2 >> 2] | 0) + 7 | 0; + c[q2 >> 2] = Y3 & -8; + dc(r2 + (Y3 >>> 3) | 0, s2 | 0, ya3 | 0) | 0; + s2 = (c[q2 >> 2] | 0) + (ya3 << 3) | 0; + c[q2 >> 2] = s2; + a[r2 + (s2 >>> 3) >> 0] = 0; + s2 = Z3; + break; + } + if (F3 >>> 0 < 22594) { + s2 = a[ka3 >> 0] | 0; + t3 = e[la3 >> 1] | 0; + u3 = c[q2 >> 2] | 0; + v3 = r2 + (u3 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(t3 | 0, 0, s2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 299; + break a; + } + if ((s2 & 255) >= 57) { + wa3 = 301; + break a; + } + ya3 = cc(t3 | 0, 0, u3 & 7 | 0) | 0; + u3 = C2; + ya3 = h2 | ya3; + t3 = v3; + v3 = t3; + a[v3 >> 0] = ya3; + a[v3 + 1 >> 0] = ya3 >> 8; + a[v3 + 2 >> 0] = ya3 >> 16; + a[v3 + 3 >> 0] = ya3 >> 24; + t3 = t3 + 4 | 0; + a[t3 >> 0] = u3; + a[t3 + 1 >> 0] = u3 >> 8; + a[t3 + 2 >> 0] = u3 >> 16; + a[t3 + 3 >> 0] = u3 >> 24; + s2 = (c[q2 >> 2] | 0) + (s2 & 255) | 0; + c[q2 >> 2] = s2; + t3 = F3 + -6210 | 0; + u3 = r2 + (s2 >>> 3) | 0; + v3 = d[u3 >> 0] | 0; + if (!((t3 & -16384 | 0) == 0 & true)) { + wa3 = 303; + break a; + } + X3 = cc(t3 | 0, 0, s2 & 7 | 0) | 0; + ya3 = C2; + X3 = v3 | X3; + w2 = u3; + Y3 = w2; + a[Y3 >> 0] = X3; + a[Y3 + 1 >> 0] = X3 >> 8; + a[Y3 + 2 >> 0] = X3 >> 16; + a[Y3 + 3 >> 0] = X3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = ya3; + a[w2 + 1 >> 0] = ya3 >> 8; + a[w2 + 2 >> 0] = ya3 >> 16; + a[w2 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 14; + c[ma3 >> 2] = (c[ma3 >> 2] | 0) + 1; + w2 = 0; + } else { + s2 = a[na2 >> 0] | 0; + t3 = e[oa3 >> 1] | 0; + u3 = c[q2 >> 2] | 0; + v3 = r2 + (u3 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(t3 | 0, 0, s2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 306; + break a; + } + if ((s2 & 255) >= 57) { + wa3 = 308; + break a; + } + ya3 = cc(t3 | 0, 0, u3 & 7 | 0) | 0; + u3 = C2; + ya3 = h2 | ya3; + t3 = v3; + v3 = t3; + a[v3 >> 0] = ya3; + a[v3 + 1 >> 0] = ya3 >> 8; + a[v3 + 2 >> 0] = ya3 >> 16; + a[v3 + 3 >> 0] = ya3 >> 24; + t3 = t3 + 4 | 0; + a[t3 >> 0] = u3; + a[t3 + 1 >> 0] = u3 >> 8; + a[t3 + 2 >> 0] = u3 >> 16; + a[t3 + 3 >> 0] = u3 >> 24; + s2 = (c[q2 >> 2] | 0) + (s2 & 255) | 0; + c[q2 >> 2] = s2; + t3 = F3 + -22594 | 0; + u3 = r2 + (s2 >>> 3) | 0; + v3 = d[u3 >> 0] | 0; + if (!((t3 & -16777216 | 0) == 0 & true)) { + wa3 = 310; + break a; + } + X3 = cc(t3 | 0, 0, s2 & 7 | 0) | 0; + ya3 = C2; + X3 = v3 | X3; + w2 = u3; + Y3 = w2; + a[Y3 >> 0] = X3; + a[Y3 + 1 >> 0] = X3 >> 8; + a[Y3 + 2 >> 0] = X3 >> 16; + a[Y3 + 3 >> 0] = X3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = ya3; + a[w2 + 1 >> 0] = ya3 >> 8; + a[w2 + 2 >> 0] = ya3 >> 16; + a[w2 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 24; + c[qa3 >> 2] = (c[qa3 >> 2] | 0) + 1; + w2 = 0; + } + while (1) { + if (w2 >>> 0 >= F3 >>> 0) { + s2 = Z3; + break e; + } + t3 = d[G3 + w2 >> 0] | 0; + s2 = a[va3 + t3 >> 0] | 0; + t3 = e[ua3 + (t3 << 1) >> 1] | 0; + u3 = c[q2 >> 2] | 0; + v3 = r2 + (u3 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(t3 | 0, 0, s2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 314; + break a; + } + if ((s2 & 255) >= 57) { + wa3 = 316; + break a; + } + W3 = cc(t3 | 0, 0, u3 & 7 | 0) | 0; + Y3 = C2; + W3 = h2 | W3; + ya3 = v3; + X3 = ya3; + a[X3 >> 0] = W3; + a[X3 + 1 >> 0] = W3 >> 8; + a[X3 + 2 >> 0] = W3 >> 16; + a[X3 + 3 >> 0] = W3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = Y3; + a[ya3 + 1 >> 0] = Y3 >> 8; + a[ya3 + 2 >> 0] = Y3 >> 16; + a[ya3 + 3 >> 0] = Y3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (s2 & 255); + w2 = w2 + 1 | 0; + } + } + do + if (F3 >>> 0 < 6) { + s2 = F3 + 40 | 0; + t3 = a[m3 + s2 >> 0] | 0; + u3 = e[n2 + (s2 << 1) >> 1] | 0; + v3 = c[q2 >> 2] | 0; + h2 = r2 + (v3 >>> 3) | 0; + w2 = d[h2 >> 0] | 0; + ya3 = bc(u3 | 0, 0, t3 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 258; + break a; + } + if ((t3 & 255) >= 57) { + wa3 = 260; + break a; + } + X3 = cc(u3 | 0, 0, v3 & 7 | 0) | 0; + ya3 = C2; + X3 = w2 | X3; + w2 = h2; + Y3 = w2; + a[Y3 >> 0] = X3; + a[Y3 + 1 >> 0] = X3 >> 8; + a[Y3 + 2 >> 0] = X3 >> 16; + a[Y3 + 3 >> 0] = X3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = ya3; + a[w2 + 1 >> 0] = ya3 >> 8; + a[w2 + 2 >> 0] = ya3 >> 16; + a[w2 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (t3 & 255); + w2 = sa3 + (s2 << 2) | 0; + c[w2 >> 2] = (c[w2 >> 2] | 0) + 1; + w2 = 0; + } else { + if (F3 >>> 0 < 130) { + w2 = F3 + -2 | 0; + A3 = ((aa(w2 | 0) | 0) ^ 31) + -1 | 0; + x3 = w2 >>> A3; + B3 = (A3 << 1) + x3 + 42 | 0; + s2 = a[m3 + B3 >> 0] | 0; + t3 = e[n2 + (B3 << 1) >> 1] | 0; + u3 = c[q2 >> 2] | 0; + v3 = r2 + (u3 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(t3 | 0, 0, s2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 264; + break a; + } + if ((s2 & 255) >= 57) { + wa3 = 266; + break a; + } + ya3 = cc(t3 | 0, 0, u3 & 7 | 0) | 0; + t3 = C2; + ya3 = h2 | ya3; + u3 = v3; + a[u3 >> 0] = ya3; + a[u3 + 1 >> 0] = ya3 >> 8; + a[u3 + 2 >> 0] = ya3 >> 16; + a[u3 + 3 >> 0] = ya3 >> 24; + v3 = v3 + 4 | 0; + a[v3 >> 0] = t3; + a[v3 + 1 >> 0] = t3 >> 8; + a[v3 + 2 >> 0] = t3 >> 16; + a[v3 + 3 >> 0] = t3 >> 24; + v3 = (c[q2 >> 2] | 0) + (s2 & 255) | 0; + c[q2 >> 2] = v3; + s2 = w2 - (x3 << A3) | 0; + t3 = r2 + (v3 >>> 3) | 0; + u3 = d[t3 >> 0] | 0; + ya3 = bc(s2 | 0, 0, A3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 268; + break a; + } + if (A3 >>> 0 >= 57) { + wa3 = 270; + break a; + } + X3 = cc(s2 | 0, 0, v3 & 7 | 0) | 0; + ya3 = C2; + X3 = u3 | X3; + w2 = t3; + Y3 = w2; + a[Y3 >> 0] = X3; + a[Y3 + 1 >> 0] = X3 >> 8; + a[Y3 + 2 >> 0] = X3 >> 16; + a[Y3 + 3 >> 0] = X3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = ya3; + a[w2 + 1 >> 0] = ya3 >> 8; + a[w2 + 2 >> 0] = ya3 >> 16; + a[w2 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + A3; + w2 = sa3 + (B3 << 2) | 0; + c[w2 >> 2] = (c[w2 >> 2] | 0) + 1; + w2 = 0; + break; + } + if (F3 >>> 0 >= 2114) { + s2 = a[$2 >> 0] | 0; + t3 = e[ba2 >> 1] | 0; + u3 = c[q2 >> 2] | 0; + v3 = r2 + (u3 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(t3 | 0, 0, s2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 283; + break a; + } + if ((s2 & 255) >= 57) { + wa3 = 285; + break a; + } + ya3 = cc(t3 | 0, 0, u3 & 7 | 0) | 0; + u3 = C2; + ya3 = h2 | ya3; + t3 = v3; + v3 = t3; + a[v3 >> 0] = ya3; + a[v3 + 1 >> 0] = ya3 >> 8; + a[v3 + 2 >> 0] = ya3 >> 16; + a[v3 + 3 >> 0] = ya3 >> 24; + t3 = t3 + 4 | 0; + a[t3 >> 0] = u3; + a[t3 + 1 >> 0] = u3 >> 8; + a[t3 + 2 >> 0] = u3 >> 16; + a[t3 + 3 >> 0] = u3 >> 24; + s2 = (c[q2 >> 2] | 0) + (s2 & 255) | 0; + c[q2 >> 2] = s2; + t3 = F3 + -2114 | 0; + u3 = r2 + (s2 >>> 3) | 0; + v3 = d[u3 >> 0] | 0; + if (!((t3 & -4096 | 0) == 0 & true)) { + wa3 = 287; + break a; + } + X3 = cc(t3 | 0, 0, s2 & 7 | 0) | 0; + ya3 = C2; + X3 = v3 | X3; + w2 = u3; + Y3 = w2; + a[Y3 >> 0] = X3; + a[Y3 + 1 >> 0] = X3 >> 8; + a[Y3 + 2 >> 0] = X3 >> 16; + a[Y3 + 3 >> 0] = X3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = ya3; + a[w2 + 1 >> 0] = ya3 >> 8; + a[w2 + 2 >> 0] = ya3 >> 16; + a[w2 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 12; + c[ca3 >> 2] = (c[ca3 >> 2] | 0) + 1; + w2 = 0; + break; + } + w2 = F3 + -66 | 0; + x3 = (aa(w2 | 0) | 0) ^ 31; + A3 = x3 + 50 | 0; + s2 = a[m3 + A3 >> 0] | 0; + t3 = e[n2 + (A3 << 1) >> 1] | 0; + u3 = c[q2 >> 2] | 0; + v3 = r2 + (u3 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(t3 | 0, 0, s2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 274; + break a; + } + if ((s2 & 255) >= 57) { + wa3 = 276; + break a; + } + ya3 = cc(t3 | 0, 0, u3 & 7 | 0) | 0; + t3 = C2; + ya3 = h2 | ya3; + u3 = v3; + a[u3 >> 0] = ya3; + a[u3 + 1 >> 0] = ya3 >> 8; + a[u3 + 2 >> 0] = ya3 >> 16; + a[u3 + 3 >> 0] = ya3 >> 24; + v3 = v3 + 4 | 0; + a[v3 >> 0] = t3; + a[v3 + 1 >> 0] = t3 >> 8; + a[v3 + 2 >> 0] = t3 >> 16; + a[v3 + 3 >> 0] = t3 >> 24; + v3 = (c[q2 >> 2] | 0) + (s2 & 255) | 0; + c[q2 >> 2] = v3; + s2 = w2 - (1 << x3) | 0; + t3 = r2 + (v3 >>> 3) | 0; + u3 = d[t3 >> 0] | 0; + ya3 = bc(s2 | 0, 0, x3 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 278; + break a; + } + if (x3 >>> 0 >= 57) { + wa3 = 280; + break a; + } + X3 = cc(s2 | 0, 0, v3 & 7 | 0) | 0; + ya3 = C2; + X3 = u3 | X3; + w2 = t3; + Y3 = w2; + a[Y3 >> 0] = X3; + a[Y3 + 1 >> 0] = X3 >> 8; + a[Y3 + 2 >> 0] = X3 >> 16; + a[Y3 + 3 >> 0] = X3 >> 24; + w2 = w2 + 4 | 0; + a[w2 >> 0] = ya3; + a[w2 + 1 >> 0] = ya3 >> 8; + a[w2 + 2 >> 0] = ya3 >> 16; + a[w2 + 3 >> 0] = ya3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + x3; + w2 = sa3 + (A3 << 2) | 0; + c[w2 >> 2] = (c[w2 >> 2] | 0) + 1; + w2 = 0; + } + while (0); + while (1) { + if (w2 >>> 0 >= F3 >>> 0) { + s2 = Z3; + break e; + } + t3 = d[G3 + w2 >> 0] | 0; + s2 = a[va3 + t3 >> 0] | 0; + t3 = e[ua3 + (t3 << 1) >> 1] | 0; + u3 = c[q2 >> 2] | 0; + v3 = r2 + (u3 >>> 3) | 0; + h2 = d[v3 >> 0] | 0; + ya3 = bc(t3 | 0, 0, s2 & 255 | 0) | 0; + if (!((ya3 | 0) == 0 & (C2 | 0) == 0)) { + wa3 = 291; + break a; + } + if ((s2 & 255) >= 57) { + wa3 = 293; + break a; + } + W3 = cc(t3 | 0, 0, u3 & 7 | 0) | 0; + Y3 = C2; + W3 = h2 | W3; + ya3 = v3; + X3 = ya3; + a[X3 >> 0] = W3; + a[X3 + 1 >> 0] = W3 >> 8; + a[X3 + 2 >> 0] = W3 >> 16; + a[X3 + 3 >> 0] = W3 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = Y3; + a[ya3 + 1 >> 0] = Y3 >> 8; + a[ya3 + 2 >> 0] = Y3 >> 16; + a[ya3 + 3 >> 0] = Y3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (s2 & 255); + w2 = w2 + 1 | 0; + } + } else s2 = Z3; + } + while (0); + if (!l2) { + wa3 = 320; + break; + } + u3 = l2 >>> 0 < 98304 ? l2 : 98304; + B3 = c[q2 >> 2] | 0; + vb(u3, 0, q2, r2); + t3 = r2 + ((c[q2 >> 2] | 0) >>> 3) | 0; + Z3 = d[t3 >> 0] | 0; + ya3 = t3; + a[ya3 >> 0] = Z3; + a[ya3 + 1 >> 0] = Z3 >> 8; + a[ya3 + 2 >> 0] = Z3 >> 16; + a[ya3 + 3 >> 0] = Z3 >> 24; + t3 = t3 + 4 | 0; + a[t3 >> 0] = 0; + a[t3 + 1 >> 0] = 0; + a[t3 + 2 >> 0] = 0; + a[t3 + 3 >> 0] = 0; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 13; + t3 = wb(b3, s2, u3, va3, ua3, q2, r2) | 0; + xb(sa3, m3, n2, q2, r2); + } + switch (wa3 | 0) { + case 24: { + pa2(405740, 405401, 539, 405439); + break; + } + case 26: { + pa2(405474, 405401, 544, 405439); + break; + } + case 32: { + pa2(405779, 405401, 559, 405439); + break; + } + case 34: { + pa2(405800, 405401, 560, 405439); + break; + } + case 48: { + pa2(405815, 405401, 579, 405439); + break; + } + case 52: { + pa2(406196, 406218, 54, 406251); + break; + } + case 54: { + pa2(406267, 406218, 55, 406251); + break; + } + case 58: { + pa2(406196, 406218, 54, 406251); + break; + } + case 60: { + pa2(406267, 406218, 55, 406251); + break; + } + case 62: { + pa2(406196, 406218, 54, 406251); + break; + } + case 64: { + pa2(406267, 406218, 55, 406251); + break; + } + case 68: { + pa2(406196, 406218, 54, 406251); + break; + } + case 70: { + pa2(406267, 406218, 55, 406251); + break; + } + case 72: { + pa2(406196, 406218, 54, 406251); + break; + } + case 74: { + pa2(406267, 406218, 55, 406251); + break; + } + case 77: { + pa2(406196, 406218, 54, 406251); + break; + } + case 79: { + pa2(406267, 406218, 55, 406251); + break; + } + case 81: { + pa2(406196, 406218, 54, 406251); + break; + } + case 87: { + pa2(406196, 406218, 54, 406251); + break; + } + case 89: { + pa2(406267, 406218, 55, 406251); + break; + } + case 91: { + pa2(406196, 406218, 54, 406251); + break; + } + case 94: { + pa2(406196, 406218, 54, 406251); + break; + } + case 96: { + pa2(406267, 406218, 55, 406251); + break; + } + case 98: { + pa2(406196, 406218, 54, 406251); + break; + } + case 102: { + pa2(406196, 406218, 54, 406251); + break; + } + case 104: { + pa2(406267, 406218, 55, 406251); + break; + } + case 108: { + pa2(406196, 406218, 54, 406251); + break; + } + case 110: { + pa2(406267, 406218, 55, 406251); + break; + } + case 113: { + pa2(406196, 406218, 54, 406251); + break; + } + case 115: { + pa2(406267, 406218, 55, 406251); + break; + } + case 117: { + pa2(406196, 406218, 54, 406251); + break; + } + case 119: { + pa2(406267, 406218, 55, 406251); + break; + } + case 123: { + pa2(406196, 406218, 54, 406251); + break; + } + case 125: { + pa2(406267, 406218, 55, 406251); + break; + } + case 129: { + pa2(406196, 406218, 54, 406251); + break; + } + case 131: { + pa2(406267, 406218, 55, 406251); + break; + } + case 133: { + pa2(406196, 406218, 54, 406251); + break; + } + case 135: { + pa2(406267, 406218, 55, 406251); + break; + } + case 139: { + pa2(406196, 406218, 54, 406251); + break; + } + case 141: { + pa2(406267, 406218, 55, 406251); + break; + } + case 143: { + pa2(406196, 406218, 54, 406251); + break; + } + case 145: { + pa2(406267, 406218, 55, 406251); + break; + } + case 149: { + pa2(406196, 406218, 54, 406251); + break; + } + case 151: { + pa2(406267, 406218, 55, 406251); + break; + } + case 153: { + pa2(406196, 406218, 54, 406251); + break; + } + case 155: { + pa2(406267, 406218, 55, 406251); + break; + } + case 157: { + pa2(406196, 406218, 54, 406251); + break; + } + case 159: { + pa2(406267, 406218, 55, 406251); + break; + } + case 162: { + pa2(406196, 406218, 54, 406251); + break; + } + case 164: { + pa2(406267, 406218, 55, 406251); + break; + } + case 166: { + pa2(406196, 406218, 54, 406251); + break; + } + case 168: { + pa2(406196, 406218, 54, 406251); + break; + } + case 170: { + pa2(406267, 406218, 55, 406251); + break; + } + case 187: { + pa2(405815, 405401, 638, 405439); + break; + } + case 190: { + pa2(406196, 406218, 54, 406251); + break; + } + case 192: { + pa2(406267, 406218, 55, 406251); + break; + } + case 196: { + pa2(406196, 406218, 54, 406251); + break; + } + case 198: { + pa2(406267, 406218, 55, 406251); + break; + } + case 200: { + pa2(406196, 406218, 54, 406251); + break; + } + case 202: { + pa2(406267, 406218, 55, 406251); + break; + } + case 206: { + pa2(406196, 406218, 54, 406251); + break; + } + case 208: { + pa2(406267, 406218, 55, 406251); + break; + } + case 210: { + pa2(406196, 406218, 54, 406251); + break; + } + case 212: { + pa2(406267, 406218, 55, 406251); + break; + } + case 215: { + pa2(406196, 406218, 54, 406251); + break; + } + case 217: { + pa2(406267, 406218, 55, 406251); + break; + } + case 219: { + pa2(406196, 406218, 54, 406251); + break; + } + case 222: { + pa2(406196, 406218, 54, 406251); + break; + } + case 224: { + pa2(406267, 406218, 55, 406251); + break; + } + case 226: { + pa2(406196, 406218, 54, 406251); + break; + } + case 228: { + pa2(406267, 406218, 55, 406251); + break; + } + case 233: { + pa2(405853, 405401, 671, 405439); + break; + } + case 250: { + pa2(405503, 405401, 681, 405439); + break; + } + case 258: { + pa2(406196, 406218, 54, 406251); + break; + } + case 260: { + pa2(406267, 406218, 55, 406251); + break; + } + case 264: { + pa2(406196, 406218, 54, 406251); + break; + } + case 266: { + pa2(406267, 406218, 55, 406251); + break; + } + case 268: { + pa2(406196, 406218, 54, 406251); + break; + } + case 270: { + pa2(406267, 406218, 55, 406251); + break; + } + case 274: { + pa2(406196, 406218, 54, 406251); + break; + } + case 276: { + pa2(406267, 406218, 55, 406251); + break; + } + case 278: { + pa2(406196, 406218, 54, 406251); + break; + } + case 280: { + pa2(406267, 406218, 55, 406251); + break; + } + case 283: { + pa2(406196, 406218, 54, 406251); + break; + } + case 285: { + pa2(406267, 406218, 55, 406251); + break; + } + case 287: { + pa2(406196, 406218, 54, 406251); + break; + } + case 291: { + pa2(406196, 406218, 54, 406251); + break; + } + case 293: { + pa2(406267, 406218, 55, 406251); + break; + } + case 299: { + pa2(406196, 406218, 54, 406251); + break; + } + case 301: { + pa2(406267, 406218, 55, 406251); + break; + } + case 303: { + pa2(406196, 406218, 54, 406251); + break; + } + case 306: { + pa2(406196, 406218, 54, 406251); + break; + } + case 308: { + pa2(406267, 406218, 55, 406251); + break; + } + case 310: { + pa2(406196, 406218, 54, 406251); + break; + } + case 314: { + pa2(406196, 406218, 54, 406251); + break; + } + case 316: { + pa2(406267, 406218, 55, 406251); + break; + } + case 320: + if (j2) { + b3 = c[q2 >> 2] | 0; + wa3 = r2 + (b3 >>> 3) | 0; + k2 = d[wa3 >> 0] | 0; + b3 = cc(1, 0, b3 & 7 | 0) | 0; + ya3 = C2; + b3 = k2 | b3; + k2 = wa3; + a[k2 >> 0] = b3; + a[k2 + 1 >> 0] = b3 >> 8; + a[k2 + 2 >> 0] = b3 >> 16; + a[k2 + 3 >> 0] = b3 >> 24; + wa3 = wa3 + 4 | 0; + a[wa3 >> 0] = ya3; + a[wa3 + 1 >> 0] = ya3 >> 8; + a[wa3 + 2 >> 0] = ya3 >> 16; + a[wa3 + 3 >> 0] = ya3 >> 24; + wa3 = (c[q2 >> 2] | 0) + 1 | 0; + c[q2 >> 2] = wa3; + ya3 = r2 + (wa3 >>> 3) | 0; + k2 = d[ya3 >> 0] | 0; + r2 = cc(1, 0, wa3 & 7 | 0) | 0; + wa3 = C2; + r2 = k2 | r2; + k2 = ya3; + a[k2 >> 0] = r2; + a[k2 + 1 >> 0] = r2 >> 8; + a[k2 + 2 >> 0] = r2 >> 16; + a[k2 + 3 >> 0] = r2 >> 24; + ya3 = ya3 + 4 | 0; + a[ya3 >> 0] = wa3; + a[ya3 + 1 >> 0] = wa3 >> 8; + a[ya3 + 2 >> 0] = wa3 >> 16; + a[ya3 + 3 >> 0] = wa3 >> 24; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 8 & -8; + i = xa3; + return; + } else { + a[p2 >> 0] = 0; + c[o2 >> 2] = 0; + xb(sa3, m3, n2, o2, p2); + i = xa3; + return; + } + } + } + function vb(b3, e2, f2, g3) { + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + var h2 = 0, i2 = 0, j2 = 0, k2 = 0; + h2 = g3 + ((c[f2 >> 2] | 0) >>> 3) | 0; + j2 = d[h2 >> 0] | 0; + i2 = h2; + a[i2 >> 0] = j2; + a[i2 + 1 >> 0] = j2 >> 8; + a[i2 + 2 >> 0] = j2 >> 16; + a[i2 + 3 >> 0] = j2 >> 24; + h2 = h2 + 4 | 0; + a[h2 >> 0] = 0; + a[h2 + 1 >> 0] = 0; + a[h2 + 2 >> 0] = 0; + a[h2 + 3 >> 0] = 0; + h2 = (c[f2 >> 2] | 0) + 1 | 0; + c[f2 >> 2] = h2; + i2 = g3 + (h2 >>> 3) | 0; + j2 = d[i2 >> 0] | 0; + if (b3 >>> 0 < 65537) { + k2 = i2; + h2 = k2; + a[h2 >> 0] = j2; + a[h2 + 1 >> 0] = j2 >> 8; + a[h2 + 2 >> 0] = j2 >> 16; + a[h2 + 3 >> 0] = j2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = 0; + a[k2 + 1 >> 0] = 0; + a[k2 + 2 >> 0] = 0; + a[k2 + 3 >> 0] = 0; + k2 = (c[f2 >> 2] | 0) + 2 | 0; + c[f2 >> 2] = k2; + h2 = b3 + -1 | 0; + i2 = g3 + (k2 >>> 3) | 0; + j2 = d[i2 >> 0] | 0; + if (!((h2 & -65536 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + h2 = cc(h2 | 0, 0, k2 & 7 | 0) | 0; + b3 = C2; + h2 = j2 | h2; + k2 = i2; + j2 = k2; + a[j2 >> 0] = h2; + a[j2 + 1 >> 0] = h2 >> 8; + a[j2 + 2 >> 0] = h2 >> 16; + a[j2 + 3 >> 0] = h2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = b3; + a[k2 + 1 >> 0] = b3 >> 8; + a[k2 + 2 >> 0] = b3 >> 16; + a[k2 + 3 >> 0] = b3 >> 24; + k2 = (c[f2 >> 2] | 0) + 16 | 0; + c[f2 >> 2] = k2; + e2 = e2 & 1; + b3 = k2 >>> 3; + g3 = g3 + b3 | 0; + b3 = a[g3 >> 0] | 0; + b3 = b3 & 255; + k2 = k2 & 7; + k2 = cc(e2 | 0, 0, k2 | 0) | 0; + e2 = C2; + k2 = b3 | k2; + b3 = g3; + a[b3 >> 0] = k2; + a[b3 + 1 >> 0] = k2 >> 8; + a[b3 + 2 >> 0] = k2 >> 16; + a[b3 + 3 >> 0] = k2 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = e2; + a[g3 + 1 >> 0] = e2 >> 8; + a[g3 + 2 >> 0] = e2 >> 16; + a[g3 + 3 >> 0] = e2 >> 24; + g3 = c[f2 >> 2] | 0; + g3 = g3 + 1 | 0; + c[f2 >> 2] = g3; + return; + } else { + k2 = cc(1, 0, h2 & 7 | 0) | 0; + h2 = C2; + j2 = j2 | k2; + k2 = i2; + i2 = k2; + a[i2 >> 0] = j2; + a[i2 + 1 >> 0] = j2 >> 8; + a[i2 + 2 >> 0] = j2 >> 16; + a[i2 + 3 >> 0] = j2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = h2; + a[k2 + 1 >> 0] = h2 >> 8; + a[k2 + 2 >> 0] = h2 >> 16; + a[k2 + 3 >> 0] = h2 >> 24; + k2 = (c[f2 >> 2] | 0) + 2 | 0; + c[f2 >> 2] = k2; + h2 = b3 + -1 | 0; + i2 = g3 + (k2 >>> 3) | 0; + j2 = d[i2 >> 0] | 0; + if (!((h2 & -1048576 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + h2 = cc(h2 | 0, 0, k2 & 7 | 0) | 0; + b3 = C2; + h2 = j2 | h2; + k2 = i2; + j2 = k2; + a[j2 >> 0] = h2; + a[j2 + 1 >> 0] = h2 >> 8; + a[j2 + 2 >> 0] = h2 >> 16; + a[j2 + 3 >> 0] = h2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = b3; + a[k2 + 1 >> 0] = b3 >> 8; + a[k2 + 2 >> 0] = b3 >> 16; + a[k2 + 3 >> 0] = b3 >> 24; + k2 = (c[f2 >> 2] | 0) + 20 | 0; + c[f2 >> 2] = k2; + e2 = e2 & 1; + b3 = k2 >>> 3; + g3 = g3 + b3 | 0; + b3 = a[g3 >> 0] | 0; + b3 = b3 & 255; + k2 = k2 & 7; + k2 = cc(e2 | 0, 0, k2 | 0) | 0; + e2 = C2; + k2 = b3 | k2; + b3 = g3; + a[b3 >> 0] = k2; + a[b3 + 1 >> 0] = k2 >> 8; + a[b3 + 2 >> 0] = k2 >> 16; + a[b3 + 3 >> 0] = k2 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = e2; + a[g3 + 1 >> 0] = e2 >> 8; + a[g3 + 2 >> 0] = e2 >> 16; + a[g3 + 3 >> 0] = e2 >> 24; + g3 = c[f2 >> 2] | 0; + g3 = g3 + 1 | 0; + c[f2 >> 2] = g3; + return; + } + } + function wb(a2, b3, e2, f2, g3, h2, j2) { + a2 = a2 | 0; + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + var k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0; + n2 = i; + i = i + 1024 | 0; + m3 = n2; + ac(m3 | 0, 0, 1024) | 0; + a: do + if (e2 >>> 0 < 32768) { + k2 = 0; + while (1) { + if ((k2 | 0) == (e2 | 0)) { + k2 = 0; + break; + } + l2 = m3 + ((d[b3 + k2 >> 0] | 0) << 2) | 0; + c[l2 >> 2] = (c[l2 >> 2] | 0) + 1; + k2 = k2 + 1 | 0; + } + while (1) { + if ((k2 | 0) == 256) { + l2 = e2; + break a; + } + b3 = m3 + (k2 << 2) | 0; + o2 = c[b3 >> 2] | 0; + l2 = (o2 >>> 0 < 11 ? o2 : 11) << 1; + c[b3 >> 2] = o2 + l2; + e2 = e2 + l2 | 0; + k2 = k2 + 1 | 0; + } + } else { + k2 = 0; + while (1) { + if (k2 >>> 0 >= e2 >>> 0) break; + o2 = m3 + ((d[b3 + k2 >> 0] | 0) << 2) | 0; + c[o2 >> 2] = (c[o2 >> 2] | 0) + 1; + k2 = k2 + 29 | 0; + } + e2 = ((e2 + 28 | 0) >>> 0) / 29 | 0; + k2 = 0; + while (1) { + if ((k2 | 0) == 256) { + l2 = e2; + break a; + } + l2 = m3 + (k2 << 2) | 0; + b3 = c[l2 >> 2] | 0; + o2 = (b3 >>> 0 < 11 ? b3 : 11) << 1 | 1; + c[l2 >> 2] = b3 + o2; + e2 = e2 + o2 | 0; + k2 = k2 + 1 | 0; + } + } + while (0); + $a2(a2, m3, l2, 8, f2, g3, h2, j2); + e2 = 0; + b3 = 0; + while (1) { + if ((b3 | 0) == 256) break; + k2 = c[m3 + (b3 << 2) >> 2] | 0; + if (k2) e2 = e2 + (_(k2, d[f2 + b3 >> 0] | 0) | 0) | 0; + b3 = b3 + 1 | 0; + } + i = n2; + return ((e2 * 125 | 0) >>> 0) / (l2 >>> 0) | 0 | 0; + } + function xb(e2, f2, g3, h2, j2) { + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + var k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0; + s2 = i; + i = i + 1872 | 0; + r2 = s2 + 704 | 0; + q2 = s2; + o2 = s2 + 1736 | 0; + ac(q2 | 0, 0, 704) | 0; + Hb(e2, 64, 15, r2, f2); + p2 = f2 + 64 | 0; + Hb(e2 + 256 | 0, 64, 14, r2, p2); + l2 = q2; + m3 = f2; + n2 = l2 + 24 | 0; + do { + a[l2 >> 0] = a[m3 >> 0] | 0; + l2 = l2 + 1 | 0; + m3 = m3 + 1 | 0; + } while ((l2 | 0) < (n2 | 0)); + l2 = f2 + 40 | 0; + k2 = l2; + l2 = l2 + 4 | 0; + l2 = d[l2 >> 0] | d[l2 + 1 >> 0] << 8 | d[l2 + 2 >> 0] << 16 | d[l2 + 3 >> 0] << 24; + e2 = q2 + 24 | 0; + c[e2 >> 2] = d[k2 >> 0] | d[k2 + 1 >> 0] << 8 | d[k2 + 2 >> 0] << 16 | d[k2 + 3 >> 0] << 24; + c[e2 + 4 >> 2] = l2; + e2 = f2 + 24 | 0; + l2 = e2; + k2 = l2; + l2 = l2 + 4 | 0; + l2 = d[l2 >> 0] | d[l2 + 1 >> 0] << 8 | d[l2 + 2 >> 0] << 16 | d[l2 + 3 >> 0] << 24; + n2 = q2 + 32 | 0; + c[n2 >> 2] = d[k2 >> 0] | d[k2 + 1 >> 0] << 8 | d[k2 + 2 >> 0] << 16 | d[k2 + 3 >> 0] << 24; + c[n2 + 4 >> 2] = l2; + n2 = f2 + 48 | 0; + l2 = n2; + n2 = n2 + 4 | 0; + n2 = d[n2 >> 0] | d[n2 + 1 >> 0] << 8 | d[n2 + 2 >> 0] << 16 | d[n2 + 3 >> 0] << 24; + k2 = q2 + 40 | 0; + c[k2 >> 2] = d[l2 >> 0] | d[l2 + 1 >> 0] << 8 | d[l2 + 2 >> 0] << 16 | d[l2 + 3 >> 0] << 24; + c[k2 + 4 >> 2] = n2; + k2 = f2 + 32 | 0; + n2 = k2; + l2 = n2; + n2 = n2 + 4 | 0; + n2 = d[n2 >> 0] | d[n2 + 1 >> 0] << 8 | d[n2 + 2 >> 0] << 16 | d[n2 + 3 >> 0] << 24; + m3 = q2 + 48 | 0; + c[m3 >> 2] = d[l2 >> 0] | d[l2 + 1 >> 0] << 8 | d[l2 + 2 >> 0] << 16 | d[l2 + 3 >> 0] << 24; + c[m3 + 4 >> 2] = n2; + m3 = f2 + 56 | 0; + n2 = m3; + m3 = m3 + 4 | 0; + m3 = d[m3 >> 0] | d[m3 + 1 >> 0] << 8 | d[m3 + 2 >> 0] << 16 | d[m3 + 3 >> 0] << 24; + l2 = q2 + 56 | 0; + c[l2 >> 2] = d[n2 >> 0] | d[n2 + 1 >> 0] << 8 | d[n2 + 2 >> 0] << 16 | d[n2 + 3 >> 0] << 24; + c[l2 + 4 >> 2] = m3; + Jb(q2, 64, o2); + l2 = g3; + m3 = o2; + n2 = l2 + 48 | 0; + do { + b2[l2 >> 1] = b2[m3 >> 1] | 0; + l2 = l2 + 2 | 0; + m3 = m3 + 2 | 0; + } while ((l2 | 0) < (n2 | 0)); + l2 = g3 + 48 | 0; + n2 = o2 + 64 | 0; + b2[l2 >> 1] = b2[n2 >> 1] | 0; + b2[l2 + 2 >> 1] = b2[n2 + 2 >> 1] | 0; + b2[l2 + 4 >> 1] = b2[n2 + 4 >> 1] | 0; + b2[l2 + 6 >> 1] = b2[n2 + 6 >> 1] | 0; + b2[l2 + 8 >> 1] = b2[n2 + 8 >> 1] | 0; + b2[l2 + 10 >> 1] = b2[n2 + 10 >> 1] | 0; + b2[l2 + 12 >> 1] = b2[n2 + 12 >> 1] | 0; + b2[l2 + 14 >> 1] = b2[n2 + 14 >> 1] | 0; + l2 = g3 + 64 | 0; + n2 = o2 + 96 | 0; + b2[l2 >> 1] = b2[n2 >> 1] | 0; + b2[l2 + 2 >> 1] = b2[n2 + 2 >> 1] | 0; + b2[l2 + 4 >> 1] = b2[n2 + 4 >> 1] | 0; + b2[l2 + 6 >> 1] = b2[n2 + 6 >> 1] | 0; + b2[l2 + 8 >> 1] = b2[n2 + 8 >> 1] | 0; + b2[l2 + 10 >> 1] = b2[n2 + 10 >> 1] | 0; + b2[l2 + 12 >> 1] = b2[n2 + 12 >> 1] | 0; + b2[l2 + 14 >> 1] = b2[n2 + 14 >> 1] | 0; + l2 = g3 + 80 | 0; + n2 = o2 + 48 | 0; + b2[l2 >> 1] = b2[n2 >> 1] | 0; + b2[l2 + 2 >> 1] = b2[n2 + 2 >> 1] | 0; + b2[l2 + 4 >> 1] = b2[n2 + 4 >> 1] | 0; + b2[l2 + 6 >> 1] = b2[n2 + 6 >> 1] | 0; + b2[l2 + 8 >> 1] = b2[n2 + 8 >> 1] | 0; + b2[l2 + 10 >> 1] = b2[n2 + 10 >> 1] | 0; + b2[l2 + 12 >> 1] = b2[n2 + 12 >> 1] | 0; + b2[l2 + 14 >> 1] = b2[n2 + 14 >> 1] | 0; + l2 = g3 + 96 | 0; + n2 = o2 + 80 | 0; + b2[l2 >> 1] = b2[n2 >> 1] | 0; + b2[l2 + 2 >> 1] = b2[n2 + 2 >> 1] | 0; + b2[l2 + 4 >> 1] = b2[n2 + 4 >> 1] | 0; + b2[l2 + 6 >> 1] = b2[n2 + 6 >> 1] | 0; + b2[l2 + 8 >> 1] = b2[n2 + 8 >> 1] | 0; + b2[l2 + 10 >> 1] = b2[n2 + 10 >> 1] | 0; + b2[l2 + 12 >> 1] = b2[n2 + 12 >> 1] | 0; + b2[l2 + 14 >> 1] = b2[n2 + 14 >> 1] | 0; + l2 = g3 + 112 | 0; + n2 = o2 + 112 | 0; + b2[l2 >> 1] = b2[n2 >> 1] | 0; + b2[l2 + 2 >> 1] = b2[n2 + 2 >> 1] | 0; + b2[l2 + 4 >> 1] = b2[n2 + 4 >> 1] | 0; + b2[l2 + 6 >> 1] = b2[n2 + 6 >> 1] | 0; + b2[l2 + 8 >> 1] = b2[n2 + 8 >> 1] | 0; + b2[l2 + 10 >> 1] = b2[n2 + 10 >> 1] | 0; + b2[l2 + 12 >> 1] = b2[n2 + 12 >> 1] | 0; + b2[l2 + 14 >> 1] = b2[n2 + 14 >> 1] | 0; + Jb(p2, 64, g3 + 128 | 0); + l2 = q2; + n2 = l2 + 64 | 0; + do { + c[l2 >> 2] = 0; + l2 = l2 + 4 | 0; + } while ((l2 | 0) < (n2 | 0)); + g3 = f2; + o2 = g3; + g3 = g3 + 4 | 0; + g3 = d[g3 >> 0] | d[g3 + 1 >> 0] << 8 | d[g3 + 2 >> 0] << 16 | d[g3 + 3 >> 0] << 24; + n2 = q2; + c[n2 >> 2] = d[o2 >> 0] | d[o2 + 1 >> 0] << 8 | d[o2 + 2 >> 0] << 16 | d[o2 + 3 >> 0] << 24; + c[n2 + 4 >> 2] = g3; + n2 = f2 + 8 | 0; + g3 = n2; + n2 = n2 + 4 | 0; + n2 = d[n2 >> 0] | d[n2 + 1 >> 0] << 8 | d[n2 + 2 >> 0] << 16 | d[n2 + 3 >> 0] << 24; + o2 = q2 + 64 | 0; + c[o2 >> 2] = d[g3 >> 0] | d[g3 + 1 >> 0] << 8 | d[g3 + 2 >> 0] << 16 | d[g3 + 3 >> 0] << 24; + c[o2 + 4 >> 2] = n2; + o2 = f2 + 16 | 0; + n2 = o2; + o2 = o2 + 4 | 0; + o2 = d[o2 >> 0] | d[o2 + 1 >> 0] << 8 | d[o2 + 2 >> 0] << 16 | d[o2 + 3 >> 0] << 24; + g3 = q2 + 128 | 0; + c[g3 >> 2] = d[n2 >> 0] | d[n2 + 1 >> 0] << 8 | d[n2 + 2 >> 0] << 16 | d[n2 + 3 >> 0] << 24; + c[g3 + 4 >> 2] = o2; + g3 = e2; + e2 = g3; + g3 = g3 + 4 | 0; + g3 = d[g3 >> 0] | d[g3 + 1 >> 0] << 8 | d[g3 + 2 >> 0] << 16 | d[g3 + 3 >> 0] << 24; + o2 = q2 + 192 | 0; + c[o2 >> 2] = d[e2 >> 0] | d[e2 + 1 >> 0] << 8 | d[e2 + 2 >> 0] << 16 | d[e2 + 3 >> 0] << 24; + c[o2 + 4 >> 2] = g3; + o2 = k2; + g3 = o2; + o2 = o2 + 4 | 0; + o2 = d[o2 >> 0] | d[o2 + 1 >> 0] << 8 | d[o2 + 2 >> 0] << 16 | d[o2 + 3 >> 0] << 24; + e2 = q2 + 384 | 0; + c[e2 >> 2] = d[g3 >> 0] | d[g3 + 1 >> 0] << 8 | d[g3 + 2 >> 0] << 16 | d[g3 + 3 >> 0] << 24; + c[e2 + 4 >> 2] = o2; + e2 = 0; + while (1) { + if ((e2 | 0) == 8) break; + o2 = e2 << 3; + a[q2 + (o2 + 128) >> 0] = a[f2 + (e2 + 40) >> 0] | 0; + a[q2 + (o2 + 256) >> 0] = a[f2 + (e2 + 48) >> 0] | 0; + a[q2 + (o2 + 448) >> 0] = a[f2 + (e2 + 56) >> 0] | 0; + e2 = e2 + 1 | 0; + } + _a(q2, 704, r2, h2, j2); + _a(p2, 64, r2, h2, j2); + i = s2; + return; + } + function yb(f2, h2, j2, k2, l2, m3, n2, o2, p2, q2) { + f2 = f2 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + var r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, _2 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0, Ha3 = 0, Ia3 = 0, Ja3 = 0, Ka3 = 0, La3 = 0, Ma3 = 0, Na3 = 0, Oa3 = 0, Pa3 = 0, Qa3 = 0, Ra3 = 0, Sa3 = 0, Ta3 = 0, Ua3 = 0, Va3 = 0; + Va3 = i; + i = i + 4560 | 0; + Ta3 = Va3 + 2376 | 0; + Ma3 = Va3 + 128 | 0; + La3 = Va3 + 4176 | 0; + Ra3 = Va3 + 4304 | 0; + Qa3 = Va3 + 3664 | 0; + Na3 = Va3; + Ka3 = Va3 + 3408 | 0; + Oa3 = Va3 + 1864 | 0; + Sa3 = Va3 + 840 | 0; + Pa3 = Va3 + 832 | 0; + Fa3 = l2; + Ga3 = m3; + Ha3 = 64 - ((aa(o2 | 0) | 0) ^ 31) | 0; + Ia3 = (o2 | 0) == 0; + Ja3 = o2 >>> 0 < 2147483649; + T3 = o2 + -1 | 0; + Ea3 = (T3 & o2 | 0) == 0; + S3 = bc(16777215, -1, Ha3 | 0) | 0; + S3 = (T3 | 0) == (S3 | 0); + T3 = h2; + U3 = m3; + V3 = l2; + W3 = Oa3 + 4 | 0; + X3 = Oa3 + 8 | 0; + Y3 = Oa3 + 256 | 0; + Z3 = Oa3 + 336 | 0; + _2 = Oa3 + 256 | 0; + $2 = Na3 + 64 | 0; + ba2 = Na3 + 24 | 0; + ca3 = Ma3 + 24 | 0; + da3 = Ma3 + 32 | 0; + ea3 = Na3 + 48 | 0; + fa3 = Ma3 + 40 | 0; + ga3 = Na3 + 8 | 0; + ha3 = Ma3 + 48 | 0; + ia3 = Na3 + 56 | 0; + ja3 = Ma3 + 56 | 0; + ka3 = Na3 + 16 | 0; + la3 = La3 + 48 | 0; + ma3 = Ka3 + 16 | 0; + na2 = La3 + 80 | 0; + oa3 = Ka3 + 32 | 0; + qa3 = La3 + 112 | 0; + ra3 = Ka3 + 48 | 0; + sa3 = Ka3 + 96 | 0; + ta3 = La3 + 64 | 0; + ua3 = Ka3 + 112 | 0; + va3 = La3 + 96 | 0; + wa3 = Ka3 + 128 | 0; + xa3 = Ma3 + 64 | 0; + ya3 = Na3 + 32 | 0; + za3 = Ma3 + 128 | 0; + Aa3 = Na3 + 40 | 0; + Ba3 = Ma3 + 192 | 0; + Ca3 = Ma3 + 384 | 0; + R3 = Sa3; + Da3 = Sa3 + 1024 | 0; + O3 = h2; + a: while (1) { + if (!j2) { + Ua3 = 155; + break; + } + P3 = j2 >>> 0 < 131072 ? j2 : 131072; + c[Pa3 >> 2] = Fa3; + Q3 = O3 + P3 | 0; + o2 = O3; + if (Ia3) { + Ua3 = 4; + break; + } + if (!Ja3) { + Ua3 = 6; + break; + } + if (!Ea3) { + Ua3 = 8; + break; + } + if (!S3) { + Ua3 = 10; + break; + } + b: do + if (P3 >>> 0 > 15) { + A3 = P3 + -6 | 0; + N3 = j2 + -16 | 0; + N3 = O3 + (A3 >>> 0 < N3 >>> 0 ? A3 : N3) | 0; + A3 = O3 + 1 | 0; + t3 = A3; + s2 = t3; + t3 = t3 + 4 | 0; + s2 = d[s2 >> 0] | d[s2 + 1 >> 0] << 8 | d[s2 + 2 >> 0] << 16 | d[s2 + 3 >> 0] << 24; + t3 = d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24; + L3 = -1; + x3 = Ga3; + while (1) { + s2 = lc(s2 | 0, t3 | 0, -1480785920, 7733) | 0; + s2 = bc(s2 | 0, C2 | 0, Ha3 | 0) | 0; + J3 = o2; + if (J3 >>> 0 >= A3 >>> 0) { + Ua3 = 15; + break a; + } + F3 = 0 - L3 | 0; + K3 = A3; + D3 = 32; + while (1) { + G3 = K3; + t3 = D3; + D3 = D3 + 1 | 0; + M2 = K3; + I3 = M2; + M2 = M2 + 4 | 0; + M2 = lc(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24 | 0, d[M2 >> 0] | d[M2 + 1 >> 0] << 8 | d[M2 + 2 >> 0] << 16 | d[M2 + 3 >> 0] << 24 | 0, -1480785920, 7733) | 0; + M2 = bc(M2 | 0, C2 | 0, Ha3 | 0) | 0; + if ((s2 | 0) != (M2 | 0)) { + Ua3 = 17; + break a; + } + A3 = K3 + (t3 >>> 5) | 0; + if (A3 >>> 0 > N3 >>> 0) break b; + B3 = A3; + t3 = B3; + B3 = B3 + 4 | 0; + B3 = lc(d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24 | 0, d[B3 >> 0] | d[B3 + 1 >> 0] << 8 | d[B3 + 2 >> 0] << 16 | d[B3 + 3 >> 0] << 24 | 0, -1480785920, 7733) | 0; + B3 = bc(B3 | 0, C2 | 0, Ha3 | 0) | 0; + t3 = K3 + F3 | 0; + if (((d[K3 >> 0] | d[K3 + 1 >> 0] << 8 | d[K3 + 2 >> 0] << 16 | d[K3 + 3 >> 0] << 24 | 0) == (d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24 | 0) ? (a[K3 + 4 >> 0] | 0) == (a[K3 + (4 - L3) >> 0] | 0) : 0) ? (F3 | 0) < 0 ? (a[K3 + 5 >> 0] | 0) == (a[K3 + (5 - L3) >> 0] | 0) : 0 : 0) { + Ua3 = 22; + break; + } + s2 = n2 + (s2 << 2) | 0; + y3 = c[s2 >> 2] | 0; + t3 = h2 + y3 | 0; + if ((y3 | 0) < 0) { + Ua3 = 24; + break a; + } + if (t3 >>> 0 >= K3 >>> 0) { + Ua3 = 26; + break a; + } + c[s2 >> 2] = G3 - T3; + if ((d[K3 >> 0] | d[K3 + 1 >> 0] << 8 | d[K3 + 2 >> 0] << 16 | d[K3 + 3 >> 0] << 24 | 0) != (d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24 | 0)) { + s2 = B3; + K3 = A3; + continue; + } + if ((a[K3 + 4 >> 0] | 0) != (a[h2 + (y3 + 4) >> 0] | 0)) { + s2 = B3; + K3 = A3; + continue; + } + if ((a[K3 + 5 >> 0] | 0) == (a[h2 + (y3 + 5) >> 0] | 0)) break; + else { + s2 = B3; + K3 = A3; + } + } + if ((Ua3 | 0) == 22) { + Ua3 = 0; + c[n2 + (s2 << 2) >> 2] = G3 - T3; + } + A3 = t3; + M2 = O3 + (P3 + -4) | 0; + s2 = 0; + y3 = K3 + 6 | 0; + while (1) { + if (y3 >>> 0 > M2 >>> 0) { + I3 = s2; + s2 = y3; + break; + } + I3 = t3 + (s2 + 6) | 0; + if ((d[y3 >> 0] | d[y3 + 1 >> 0] << 8 | d[y3 + 2 >> 0] << 16 | d[y3 + 3 >> 0] << 24 | 0) != (d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24 | 0)) { + I3 = s2; + s2 = y3; + break; + } + s2 = s2 + 4 | 0; + y3 = y3 + 4 | 0; + } + while (1) { + if (s2 >>> 0 >= Q3 >>> 0) break; + if ((a[t3 + (I3 + 6) >> 0] | 0) != (a[s2 >> 0] | 0)) break; + I3 = I3 + 1 | 0; + s2 = s2 + 1 | 0; + } + H3 = I3 + 6 | 0; + y3 = G3 - A3 | 0; + F3 = G3 - o2 | 0; + G3 = K3 + H3 | 0; + o2 = G3; + c: do + if (H3) { + B3 = H3; + D3 = K3; + while (1) { + s2 = a[D3 >> 0] | 0; + A3 = a[t3 >> 0] | 0; + if (s2 << 24 >> 24 != A3 << 24 >> 24) break; + B3 = B3 + -1 | 0; + if (!B3) break c; + else { + D3 = D3 + 1 | 0; + t3 = t3 + 1 | 0; + } + } + if (s2 << 24 >> 24 != A3 << 24 >> 24) { + Ua3 = 41; + break a; + } + } + while (0); + do + if (F3 >>> 0 >= 6) { + if (F3 >>> 0 < 130) { + A3 = F3 + -2 | 0; + D3 = ((aa(A3 | 0) | 0) ^ 31) + -1 | 0; + B3 = A3 >>> D3; + c[c[Pa3 >> 2] >> 2] = (D3 << 1) + B3 + 2 | A3 - (B3 << D3) << 8; + break; + } + if (F3 >>> 0 < 2114) { + B3 = F3 + -66 | 0; + D3 = (aa(B3 | 0) | 0) ^ 31; + c[c[Pa3 >> 2] >> 2] = D3 + 10 | B3 - (1 << D3) << 8; + break; + } + if (F3 >>> 0 < 6210) { + c[c[Pa3 >> 2] >> 2] = (F3 << 8) + -541184 | 21; + break; + } + s2 = F3 << 8; + if (F3 >>> 0 < 22594) { + c[c[Pa3 >> 2] >> 2] = s2 + -1589760 | 22; + break; + } else { + c[c[Pa3 >> 2] >> 2] = s2 + -5784064 | 23; + break; + } + } else c[c[Pa3 >> 2] >> 2] = F3; + while (0); + c[Pa3 >> 2] = (c[Pa3 >> 2] | 0) + 4; + dc(x3 | 0, J3 | 0, F3 | 0) | 0; + x3 = x3 + F3 | 0; + if ((y3 | 0) == (L3 | 0)) { + c[c[Pa3 >> 2] >> 2] = 64; + s2 = c[Pa3 >> 2] | 0; + y3 = L3; + } else { + J3 = y3 + 3 | 0; + s2 = ((aa(J3 | 0) | 0) ^ 31) + -1 | 0; + L3 = J3 >>> s2 & 1; + c[c[Pa3 >> 2] >> 2] = ((s2 << 1) + -2 | L3) + 80 | J3 - ((L3 | 2) << s2) << 8; + s2 = c[Pa3 >> 2] | 0; + } + s2 = s2 + 4 | 0; + c[Pa3 >> 2] = s2; + do + if (H3 >>> 0 >= 12) { + if (H3 >>> 0 < 72) { + H3 = I3 + -2 | 0; + L3 = ((aa(H3 | 0) | 0) ^ 31) + -1 | 0; + J3 = H3 >>> L3; + c[s2 >> 2] = (L3 << 1) + J3 + 28 | H3 - (J3 << L3) << 8; + c[Pa3 >> 2] = (c[Pa3 >> 2] | 0) + 4; + break; + } + if (H3 >>> 0 < 136) { + L3 = I3 + -2 | 0; + c[s2 >> 2] = (L3 >>> 5) + 54 | L3 << 8 & 7936; + L3 = (c[Pa3 >> 2] | 0) + 4 | 0; + c[Pa3 >> 2] = L3; + c[L3 >> 2] = 64; + c[Pa3 >> 2] = (c[Pa3 >> 2] | 0) + 4; + break; + } + if (H3 >>> 0 < 2120) { + J3 = I3 + -66 | 0; + L3 = (aa(J3 | 0) | 0) ^ 31; + c[s2 >> 2] = L3 + 52 | J3 - (1 << L3) << 8; + L3 = (c[Pa3 >> 2] | 0) + 4 | 0; + c[Pa3 >> 2] = L3; + c[L3 >> 2] = 64; + c[Pa3 >> 2] = (c[Pa3 >> 2] | 0) + 4; + break; + } else { + c[s2 >> 2] = (H3 << 8) + -542720 | 63; + L3 = (c[Pa3 >> 2] | 0) + 4 | 0; + c[Pa3 >> 2] = L3; + c[L3 >> 2] = 64; + c[Pa3 >> 2] = (c[Pa3 >> 2] | 0) + 4; + break; + } + } else { + c[s2 >> 2] = I3 + 26; + c[Pa3 >> 2] = (c[Pa3 >> 2] | 0) + 4; + } + while (0); + if (G3 >>> 0 >= N3 >>> 0) break b; + t3 = K3 + (I3 + 1) | 0; + L3 = t3; + L3 = d[L3 >> 0] | d[L3 + 1 >> 0] << 8 | d[L3 + 2 >> 0] << 16 | d[L3 + 3 >> 0] << 24; + t3 = t3 + 4 | 0; + t3 = d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24; + H3 = lc(L3 | 0, t3 | 0, -1480785920, 7733) | 0; + H3 = bc(H3 | 0, C2 | 0, Ha3 | 0) | 0; + J3 = G3 - T3 | 0; + c[n2 + (H3 << 2) >> 2] = J3 + -5; + H3 = bc(L3 | 0, t3 | 0, 8) | 0; + H3 = lc(H3 | 0, C2 | 0, -1480785920, 7733) | 0; + H3 = bc(H3 | 0, C2 | 0, Ha3 | 0) | 0; + c[n2 + (H3 << 2) >> 2] = J3 + -4; + t3 = bc(L3 | 0, t3 | 0, 16) | 0; + t3 = lc(t3 | 0, C2 | 0, -1480785920, 7733) | 0; + t3 = bc(t3 | 0, C2 | 0, Ha3 | 0) | 0; + c[n2 + (t3 << 2) >> 2] = J3 + -3; + t3 = K3 + (I3 + 4) | 0; + K3 = t3; + K3 = d[K3 >> 0] | d[K3 + 1 >> 0] << 8 | d[K3 + 2 >> 0] << 16 | d[K3 + 3 >> 0] << 24; + t3 = t3 + 4 | 0; + t3 = d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24; + L3 = bc(K3 | 0, t3 | 0, 16) | 0; + L3 = lc(L3 | 0, C2 | 0, -1480785920, 7733) | 0; + L3 = bc(L3 | 0, C2 | 0, Ha3 | 0) | 0; + I3 = lc(K3 | 0, t3 | 0, -1480785920, 7733) | 0; + I3 = bc(I3 | 0, C2 | 0, Ha3 | 0) | 0; + c[n2 + (I3 << 2) >> 2] = J3 + -2; + t3 = bc(K3 | 0, t3 | 0, 8) | 0; + t3 = lc(t3 | 0, C2 | 0, -1480785920, 7733) | 0; + t3 = bc(t3 | 0, C2 | 0, Ha3 | 0) | 0; + c[n2 + (t3 << 2) >> 2] = J3 + -1; + L3 = n2 + (L3 << 2) | 0; + t3 = c[L3 >> 2] | 0; + c[L3 >> 2] = J3; + while (1) { + B3 = h2 + t3 | 0; + L3 = o2; + s2 = o2; + if ((d[L3 >> 0] | d[L3 + 1 >> 0] << 8 | d[L3 + 2 >> 0] << 16 | d[L3 + 3 >> 0] << 24 | 0) != (d[B3 >> 0] | d[B3 + 1 >> 0] << 8 | d[B3 + 2 >> 0] << 16 | d[B3 + 3 >> 0] << 24 | 0)) break; + if ((a[s2 + 4 >> 0] | 0) != (a[h2 + (t3 + 4) >> 0] | 0)) break; + if ((a[s2 + 5 >> 0] | 0) != (a[h2 + (t3 + 5) >> 0] | 0)) break; + A3 = t3 + 6 | 0; + t3 = 0; + y3 = s2 + 6 | 0; + while (1) { + if (y3 >>> 0 > M2 >>> 0) break; + L3 = h2 + (A3 + t3) | 0; + if ((d[y3 >> 0] | d[y3 + 1 >> 0] << 8 | d[y3 + 2 >> 0] << 16 | d[y3 + 3 >> 0] << 24 | 0) != (d[L3 >> 0] | d[L3 + 1 >> 0] << 8 | d[L3 + 2 >> 0] << 16 | d[L3 + 3 >> 0] << 24 | 0)) break; + t3 = t3 + 4 | 0; + y3 = y3 + 4 | 0; + } + while (1) { + if (y3 >>> 0 >= Q3 >>> 0) break; + if ((a[h2 + (A3 + t3) >> 0] | 0) != (a[y3 >> 0] | 0)) break; + t3 = t3 + 1 | 0; + y3 = y3 + 1 | 0; + } + G3 = t3 + 6 | 0; + H3 = s2 + G3 | 0; + I3 = H3; + y3 = o2 - B3 | 0; + do + if (G3) { + D3 = G3; + F3 = s2; + while (1) { + o2 = a[F3 >> 0] | 0; + A3 = a[B3 >> 0] | 0; + if (o2 << 24 >> 24 != A3 << 24 >> 24) { + Ua3 = 80; + break; + } + D3 = D3 + -1 | 0; + if (!D3) break; + else { + F3 = F3 + 1 | 0; + B3 = B3 + 1 | 0; + } + } + if ((Ua3 | 0) == 80 ? (Ua3 = 0, o2 << 24 >> 24 != A3 << 24 >> 24) : 0) { + Ua3 = 81; + break a; + } + if (G3 >>> 0 < 10) { + Ua3 = 83; + break; + } + if (G3 >>> 0 < 134) { + L3 = ((aa(t3 | 0) | 0) ^ 31) + -1 | 0; + K3 = t3 >>> L3; + c[c[Pa3 >> 2] >> 2] = (L3 << 1) + K3 + 44 | t3 - (K3 << L3) << 8; + break; + } + if (G3 >>> 0 < 2118) { + K3 = t3 + -64 | 0; + L3 = (aa(K3 | 0) | 0) ^ 31; + c[c[Pa3 >> 2] >> 2] = L3 + 52 | K3 - (1 << L3) << 8; + break; + } else { + c[c[Pa3 >> 2] >> 2] = (G3 << 8) + -542208 | 63; + break; + } + } else Ua3 = 83; + while (0); + if ((Ua3 | 0) == 83) { + Ua3 = 0; + c[c[Pa3 >> 2] >> 2] = t3 + 44; + } + L3 = (c[Pa3 >> 2] | 0) + 4 | 0; + c[Pa3 >> 2] = L3; + G3 = y3 + 3 | 0; + K3 = ((aa(G3 | 0) | 0) ^ 31) + -1 | 0; + J3 = G3 >>> K3 & 1; + c[L3 >> 2] = ((K3 << 1) + -2 | J3) + 80 | G3 - ((J3 | 2) << K3) << 8; + c[Pa3 >> 2] = (c[Pa3 >> 2] | 0) + 4; + if (H3 >>> 0 >= N3 >>> 0) { + o2 = I3; + break b; + } + K3 = s2 + (t3 + 1) | 0; + o2 = K3; + o2 = d[o2 >> 0] | d[o2 + 1 >> 0] << 8 | d[o2 + 2 >> 0] << 16 | d[o2 + 3 >> 0] << 24; + K3 = K3 + 4 | 0; + K3 = d[K3 >> 0] | d[K3 + 1 >> 0] << 8 | d[K3 + 2 >> 0] << 16 | d[K3 + 3 >> 0] << 24; + J3 = lc(o2 | 0, K3 | 0, -1480785920, 7733) | 0; + J3 = bc(J3 | 0, C2 | 0, Ha3 | 0) | 0; + L3 = H3 - T3 | 0; + c[n2 + (J3 << 2) >> 2] = L3 + -5; + J3 = bc(o2 | 0, K3 | 0, 8) | 0; + J3 = lc(J3 | 0, C2 | 0, -1480785920, 7733) | 0; + J3 = bc(J3 | 0, C2 | 0, Ha3 | 0) | 0; + c[n2 + (J3 << 2) >> 2] = L3 + -4; + K3 = bc(o2 | 0, K3 | 0, 16) | 0; + K3 = lc(K3 | 0, C2 | 0, -1480785920, 7733) | 0; + K3 = bc(K3 | 0, C2 | 0, Ha3 | 0) | 0; + c[n2 + (K3 << 2) >> 2] = L3 + -3; + t3 = s2 + (t3 + 4) | 0; + K3 = t3; + K3 = d[K3 >> 0] | d[K3 + 1 >> 0] << 8 | d[K3 + 2 >> 0] << 16 | d[K3 + 3 >> 0] << 24; + t3 = t3 + 4 | 0; + t3 = d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24; + o2 = bc(K3 | 0, t3 | 0, 16) | 0; + o2 = lc(o2 | 0, C2 | 0, -1480785920, 7733) | 0; + o2 = bc(o2 | 0, C2 | 0, Ha3 | 0) | 0; + J3 = lc(K3 | 0, t3 | 0, -1480785920, 7733) | 0; + J3 = bc(J3 | 0, C2 | 0, Ha3 | 0) | 0; + c[n2 + (J3 << 2) >> 2] = L3 + -2; + t3 = bc(K3 | 0, t3 | 0, 8) | 0; + t3 = lc(t3 | 0, C2 | 0, -1480785920, 7733) | 0; + t3 = bc(t3 | 0, C2 | 0, Ha3 | 0) | 0; + c[n2 + (t3 << 2) >> 2] = L3 + -1; + o2 = n2 + (o2 << 2) | 0; + t3 = c[o2 >> 2] | 0; + c[o2 >> 2] = L3; + o2 = I3; + } + A3 = s2 + 1 | 0; + t3 = A3; + s2 = t3; + t3 = t3 + 4 | 0; + s2 = d[s2 >> 0] | d[s2 + 1 >> 0] << 8 | d[s2 + 2 >> 0] << 16 | d[s2 + 3 >> 0] << 24; + t3 = d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24; + L3 = y3; + } + } else x3 = Ga3; + while (0); + t3 = o2; + if (t3 >>> 0 > Q3 >>> 0) { + Ua3 = 93; + break; + } + if (t3 >>> 0 < Q3 >>> 0) { + o2 = Q3 - o2 | 0; + do + if (o2 >>> 0 >= 6) { + if (o2 >>> 0 < 130) { + L3 = o2 + -2 | 0; + N3 = ((aa(L3 | 0) | 0) ^ 31) + -1 | 0; + M2 = L3 >>> N3; + c[c[Pa3 >> 2] >> 2] = (N3 << 1) + M2 + 2 | L3 - (M2 << N3) << 8; + break; + } + if (o2 >>> 0 < 2114) { + M2 = o2 + -66 | 0; + N3 = (aa(M2 | 0) | 0) ^ 31; + c[c[Pa3 >> 2] >> 2] = N3 + 10 | M2 - (1 << N3) << 8; + break; + } + if (o2 >>> 0 < 6210) { + c[c[Pa3 >> 2] >> 2] = (o2 << 8) + -541184 | 21; + break; + } + s2 = o2 << 8; + if (o2 >>> 0 < 22594) { + c[c[Pa3 >> 2] >> 2] = s2 + -1589760 | 22; + break; + } else { + c[c[Pa3 >> 2] >> 2] = s2 + -5784064 | 23; + break; + } + } else c[c[Pa3 >> 2] >> 2] = o2; + while (0); + c[Pa3 >> 2] = (c[Pa3 >> 2] | 0) + 4; + dc(x3 | 0, t3 | 0, o2 | 0) | 0; + x3 = x3 + o2 | 0; + } + A3 = x3 - U3 | 0; + r2 = +(P3 >>> 0); + if (!(+(A3 >>> 0) < r2 * 0.98)) { + ac(Sa3 | 0, 0, 1024) | 0; + E3 = r2 * 8 * 0.98; + o2 = 0; + while (1) { + if (o2 >>> 0 >= P3 >>> 0) { + o2 = R3; + r2 = 0; + y3 = 0; + break; + } + N3 = Sa3 + (d[O3 + o2 >> 0] << 2) | 0; + c[N3 >> 2] = (c[N3 >> 2] | 0) + 1; + o2 = o2 + 43 | 0; + } + while (1) { + if (o2 >>> 0 >= Da3 >>> 0) break; + s2 = c[o2 >> 2] | 0; + u3 = +(s2 >>> 0); + if (s2 >>> 0 < 256) z3 = +g2[19516 + (s2 << 2) >> 2]; + else z3 = +Xb(u3); + t3 = c[o2 + 4 >> 2] | 0; + v3 = +(t3 >>> 0); + if (t3 >>> 0 < 256) w2 = +g2[19516 + (t3 << 2) >> 2]; + else w2 = +Xb(v3); + o2 = o2 + 8 | 0; + r2 = r2 - u3 * z3 - v3 * w2; + y3 = y3 + s2 + t3 | 0; + } + z3 = E3 / 43; + v3 = +(y3 >>> 0); + if (!y3) w2 = v3; + else { + if (y3 >>> 0 < 256) u3 = +g2[19516 + (y3 << 2) >> 2]; + else u3 = +Xb(v3); + w2 = v3; + r2 = r2 + v3 * u3; + } + if (!((r2 < w2 ? w2 : r2) < z3)) { + zb(P3, 1, p2, q2); + N3 = (c[p2 >> 2] | 0) + 7 | 0; + c[p2 >> 2] = N3 & -8; + dc(q2 + (N3 >>> 3) | 0, O3 | 0, P3 | 0) | 0; + O3 = (c[p2 >> 2] | 0) + (P3 << 3) | 0; + c[p2 >> 2] = O3; + a[q2 + (O3 >>> 3) >> 0] = 0; + } else Ua3 = 126; + } else Ua3 = 126; + if ((Ua3 | 0) == 126) { + Ua3 = 0; + G3 = (c[Pa3 >> 2] | 0) - V3 >> 2; + zb(P3, 0, p2, q2); + s2 = q2 + ((c[p2 >> 2] | 0) >>> 3) | 0; + O3 = d[s2 >> 0] | 0; + t3 = s2; + a[t3 >> 0] = O3; + a[t3 + 1 >> 0] = O3 >> 8; + a[t3 + 2 >> 0] = O3 >> 16; + a[t3 + 3 >> 0] = O3 >> 24; + s2 = s2 + 4 | 0; + a[s2 >> 0] = 0; + a[s2 + 1 >> 0] = 0; + a[s2 + 2 >> 0] = 0; + a[s2 + 3 >> 0] = 0; + c[p2 >> 2] = (c[p2 >> 2] | 0) + 13; + ac(Sa3 | 0, 0, 1024) | 0; + s2 = Na3; + t3 = s2 + 128 | 0; + do { + c[s2 >> 2] = 0; + s2 = s2 + 4 | 0; + } while ((s2 | 0) < (t3 | 0)); + ac(Ka3 | 0, 0, 256) | 0; + ac(Oa3 | 0, 0, 512) | 0; + o2 = x3 - U3 | 0; + s2 = 0; + while (1) { + if ((s2 | 0) == (o2 | 0)) break; + O3 = Sa3 + (d[m3 + s2 >> 0] << 2) | 0; + c[O3 >> 2] = (c[O3 >> 2] | 0) + 1; + s2 = s2 + 1 | 0; + } + $a2(f2, Sa3, A3, 8, Ra3, Qa3, p2, q2); + o2 = 0; + while (1) { + if ((o2 | 0) == (G3 | 0)) break; + O3 = Oa3 + ((c[l2 + (o2 << 2) >> 2] & 255) << 2) | 0; + c[O3 >> 2] = (c[O3 >> 2] | 0) + 1; + o2 = o2 + 1 | 0; + } + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + c[X3 >> 2] = (c[X3 >> 2] | 0) + 1; + c[Y3 >> 2] = (c[Y3 >> 2] | 0) + 1; + c[Z3 >> 2] = (c[Z3 >> 2] | 0) + 1; + ac(Ma3 | 0, 0, 704) | 0; + Hb(Oa3, 64, 15, Ta3, Na3); + Hb(_2, 64, 14, Ta3, $2); + c[Ma3 >> 2] = c[ba2 >> 2]; + c[Ma3 + 4 >> 2] = c[ba2 + 4 >> 2]; + c[Ma3 + 8 >> 2] = c[ba2 + 8 >> 2]; + c[Ma3 + 12 >> 2] = c[ba2 + 12 >> 2]; + c[Ma3 + 16 >> 2] = c[ba2 + 16 >> 2]; + c[Ma3 + 20 >> 2] = c[ba2 + 20 >> 2]; + t3 = Na3; + o2 = c[t3 + 4 >> 2] | 0; + s2 = ca3; + c[s2 >> 2] = c[t3 >> 2]; + c[s2 + 4 >> 2] = o2; + s2 = ea3; + o2 = c[s2 + 4 >> 2] | 0; + t3 = da3; + c[t3 >> 2] = c[s2 >> 2]; + c[t3 + 4 >> 2] = o2; + t3 = ga3; + o2 = c[t3 + 4 >> 2] | 0; + s2 = fa3; + c[s2 >> 2] = c[t3 >> 2]; + c[s2 + 4 >> 2] = o2; + s2 = ia3; + o2 = c[s2 + 4 >> 2] | 0; + t3 = ha3; + c[t3 >> 2] = c[s2 >> 2]; + c[t3 + 4 >> 2] = o2; + t3 = ka3; + o2 = c[t3 + 4 >> 2] | 0; + s2 = ja3; + c[s2 >> 2] = c[t3 >> 2]; + c[s2 + 4 >> 2] = o2; + Jb(Ma3, 64, La3); + b2[Ka3 >> 1] = b2[la3 >> 1] | 0; + b2[Ka3 + 2 >> 1] = b2[la3 + 2 >> 1] | 0; + b2[Ka3 + 4 >> 1] = b2[la3 + 4 >> 1] | 0; + b2[Ka3 + 6 >> 1] = b2[la3 + 6 >> 1] | 0; + b2[Ka3 + 8 >> 1] = b2[la3 + 8 >> 1] | 0; + b2[Ka3 + 10 >> 1] = b2[la3 + 10 >> 1] | 0; + b2[Ka3 + 12 >> 1] = b2[la3 + 12 >> 1] | 0; + b2[Ka3 + 14 >> 1] = b2[la3 + 14 >> 1] | 0; + b2[ma3 >> 1] = b2[na2 >> 1] | 0; + b2[ma3 + 2 >> 1] = b2[na2 + 2 >> 1] | 0; + b2[ma3 + 4 >> 1] = b2[na2 + 4 >> 1] | 0; + b2[ma3 + 6 >> 1] = b2[na2 + 6 >> 1] | 0; + b2[ma3 + 8 >> 1] = b2[na2 + 8 >> 1] | 0; + b2[ma3 + 10 >> 1] = b2[na2 + 10 >> 1] | 0; + b2[ma3 + 12 >> 1] = b2[na2 + 12 >> 1] | 0; + b2[ma3 + 14 >> 1] = b2[na2 + 14 >> 1] | 0; + b2[oa3 >> 1] = b2[qa3 >> 1] | 0; + b2[oa3 + 2 >> 1] = b2[qa3 + 2 >> 1] | 0; + b2[oa3 + 4 >> 1] = b2[qa3 + 4 >> 1] | 0; + b2[oa3 + 6 >> 1] = b2[qa3 + 6 >> 1] | 0; + b2[oa3 + 8 >> 1] = b2[qa3 + 8 >> 1] | 0; + b2[oa3 + 10 >> 1] = b2[qa3 + 10 >> 1] | 0; + b2[oa3 + 12 >> 1] = b2[qa3 + 12 >> 1] | 0; + b2[oa3 + 14 >> 1] = b2[qa3 + 14 >> 1] | 0; + s2 = ra3; + o2 = La3; + t3 = s2 + 48 | 0; + do { + b2[s2 >> 1] = b2[o2 >> 1] | 0; + s2 = s2 + 2 | 0; + o2 = o2 + 2 | 0; + } while ((s2 | 0) < (t3 | 0)); + b2[sa3 >> 1] = b2[ta3 >> 1] | 0; + b2[sa3 + 2 >> 1] = b2[ta3 + 2 >> 1] | 0; + b2[sa3 + 4 >> 1] = b2[ta3 + 4 >> 1] | 0; + b2[sa3 + 6 >> 1] = b2[ta3 + 6 >> 1] | 0; + b2[sa3 + 8 >> 1] = b2[ta3 + 8 >> 1] | 0; + b2[sa3 + 10 >> 1] = b2[ta3 + 10 >> 1] | 0; + b2[sa3 + 12 >> 1] = b2[ta3 + 12 >> 1] | 0; + b2[sa3 + 14 >> 1] = b2[ta3 + 14 >> 1] | 0; + b2[ua3 >> 1] = b2[va3 >> 1] | 0; + b2[ua3 + 2 >> 1] = b2[va3 + 2 >> 1] | 0; + b2[ua3 + 4 >> 1] = b2[va3 + 4 >> 1] | 0; + b2[ua3 + 6 >> 1] = b2[va3 + 6 >> 1] | 0; + b2[ua3 + 8 >> 1] = b2[va3 + 8 >> 1] | 0; + b2[ua3 + 10 >> 1] = b2[va3 + 10 >> 1] | 0; + b2[ua3 + 12 >> 1] = b2[va3 + 12 >> 1] | 0; + b2[ua3 + 14 >> 1] = b2[va3 + 14 >> 1] | 0; + Jb($2, 64, wa3); + s2 = Ma3; + t3 = s2 + 64 | 0; + do { + c[s2 >> 2] = 0; + s2 = s2 + 4 | 0; + } while ((s2 | 0) < (t3 | 0)); + N3 = ba2; + O3 = c[N3 + 4 >> 2] | 0; + o2 = Ma3; + c[o2 >> 2] = c[N3 >> 2]; + c[o2 + 4 >> 2] = O3; + o2 = ya3; + O3 = c[o2 + 4 >> 2] | 0; + N3 = xa3; + c[N3 >> 2] = c[o2 >> 2]; + c[N3 + 4 >> 2] = O3; + N3 = Aa3; + O3 = c[N3 + 4 >> 2] | 0; + o2 = za3; + c[o2 >> 2] = c[N3 >> 2]; + c[o2 + 4 >> 2] = O3; + o2 = ea3; + O3 = c[o2 + 4 >> 2] | 0; + N3 = Ba3; + c[N3 >> 2] = c[o2 >> 2]; + c[N3 + 4 >> 2] = O3; + N3 = ia3; + O3 = c[N3 + 4 >> 2] | 0; + o2 = Ca3; + c[o2 >> 2] = c[N3 >> 2]; + c[o2 + 4 >> 2] = O3; + o2 = 0; + while (1) { + if ((o2 | 0) == 8) break; + O3 = o2 << 3; + a[Ma3 + (O3 + 128) >> 0] = a[Na3 + o2 >> 0] | 0; + a[Ma3 + (O3 + 256) >> 0] = a[Na3 + (o2 + 8) >> 0] | 0; + a[Ma3 + (O3 + 448) >> 0] = a[Na3 + (o2 + 16) >> 0] | 0; + o2 = o2 + 1 | 0; + } + _a(Ma3, 704, Ta3, p2, q2); + _a($2, 64, Ta3, p2, q2); + o2 = Ga3; + F3 = 0; + while (1) { + if (F3 >>> 0 >= G3 >>> 0) break; + D3 = c[l2 + (F3 << 2) >> 2] | 0; + B3 = D3 & 255; + D3 = D3 >>> 8; + s2 = a[Na3 + B3 >> 0] | 0; + t3 = e[Ka3 + (B3 << 1) >> 1] | 0; + x3 = c[p2 >> 2] | 0; + y3 = q2 + (x3 >>> 3) | 0; + A3 = d[y3 >> 0] | 0; + O3 = bc(t3 | 0, 0, s2 & 255 | 0) | 0; + if (!((O3 | 0) == 0 & (C2 | 0) == 0)) { + Ua3 = 138; + break a; + } + if ((s2 & 255) >= 57) { + Ua3 = 140; + break a; + } + O3 = cc(t3 | 0, 0, x3 & 7 | 0) | 0; + x3 = C2; + O3 = A3 | O3; + t3 = y3; + y3 = t3; + a[y3 >> 0] = O3; + a[y3 + 1 >> 0] = O3 >> 8; + a[y3 + 2 >> 0] = O3 >> 16; + a[y3 + 3 >> 0] = O3 >> 24; + t3 = t3 + 4 | 0; + a[t3 >> 0] = x3; + a[t3 + 1 >> 0] = x3 >> 8; + a[t3 + 2 >> 0] = x3 >> 16; + a[t3 + 3 >> 0] = x3 >> 24; + s2 = (c[p2 >> 2] | 0) + (s2 & 255) | 0; + c[p2 >> 2] = s2; + t3 = c[18276 + (B3 << 2) >> 2] | 0; + x3 = q2 + (s2 >>> 3) | 0; + y3 = d[x3 >> 0] | 0; + O3 = bc(D3 | 0, 0, t3 | 0) | 0; + if (!((O3 | 0) == 0 & (C2 | 0) == 0)) { + Ua3 = 142; + break a; + } + M2 = cc(D3 | 0, 0, s2 & 7 | 0) | 0; + O3 = C2; + M2 = y3 | M2; + s2 = x3; + N3 = s2; + a[N3 >> 0] = M2; + a[N3 + 1 >> 0] = M2 >> 8; + a[N3 + 2 >> 0] = M2 >> 16; + a[N3 + 3 >> 0] = M2 >> 24; + s2 = s2 + 4 | 0; + a[s2 >> 0] = O3; + a[s2 + 1 >> 0] = O3 >> 8; + a[s2 + 2 >> 0] = O3 >> 16; + a[s2 + 3 >> 0] = O3 >> 24; + s2 = (c[p2 >> 2] | 0) + t3 | 0; + c[p2 >> 2] = s2; + d: do + if (B3 >>> 0 < 24) { + D3 = (c[18788 + (B3 << 2) >> 2] | 0) + D3 | 0; + B3 = 0; + while (1) { + if (B3 >>> 0 >= D3 >>> 0) break d; + x3 = d[o2 >> 0] | 0; + t3 = a[Ra3 + x3 >> 0] | 0; + x3 = e[Qa3 + (x3 << 1) >> 1] | 0; + y3 = q2 + (s2 >>> 3) | 0; + A3 = d[y3 >> 0] | 0; + O3 = bc(x3 | 0, 0, t3 & 255 | 0) | 0; + if (!((O3 | 0) == 0 & (C2 | 0) == 0)) { + Ua3 = 147; + break a; + } + if ((t3 & 255) >= 57) { + Ua3 = 149; + break a; + } + L3 = cc(x3 | 0, 0, s2 & 7 | 0) | 0; + N3 = C2; + L3 = A3 | L3; + O3 = y3; + M2 = O3; + a[M2 >> 0] = L3; + a[M2 + 1 >> 0] = L3 >> 8; + a[M2 + 2 >> 0] = L3 >> 16; + a[M2 + 3 >> 0] = L3 >> 24; + O3 = O3 + 4 | 0; + a[O3 >> 0] = N3; + a[O3 + 1 >> 0] = N3 >> 8; + a[O3 + 2 >> 0] = N3 >> 16; + a[O3 + 3 >> 0] = N3 >> 24; + O3 = (c[p2 >> 2] | 0) + (t3 & 255) | 0; + c[p2 >> 2] = O3; + o2 = o2 + 1 | 0; + s2 = O3; + B3 = B3 + 1 | 0; + } + } + while (0); + F3 = F3 + 1 | 0; + } + } + j2 = j2 - P3 | 0; + O3 = Q3; + } + switch (Ua3 | 0) { + case 4: { + pa2(405532, 405543, 251, 405590); + break; + } + case 6: { + pa2(405605, 405543, 252, 405590); + break; + } + case 8: { + pa2(405630, 405543, 254, 405590); + break; + } + case 10: { + pa2(405667, 405543, 256, 405590); + break; + } + case 15: { + pa2(405740, 405543, 289, 405590); + break; + } + case 17: { + pa2(405755, 405543, 295, 405590); + break; + } + case 24: { + pa2(405779, 405543, 309, 405590); + break; + } + case 26: { + pa2(405800, 405543, 310, 405590); + break; + } + case 41: { + pa2(405815, 405543, 329, 405590); + break; + } + case 81: { + pa2(405815, 405543, 378, 405590); + break; + } + case 93: { + pa2(405853, 405543, 415, 405590); + break; + } + case 138: { + pa2(406196, 406218, 54, 406251); + break; + } + case 140: { + pa2(406267, 406218, 55, 406251); + break; + } + case 142: { + pa2(406196, 406218, 54, 406251); + break; + } + case 147: { + pa2(406196, 406218, 54, 406251); + break; + } + case 149: { + pa2(406267, 406218, 55, 406251); + break; + } + case 155: { + if (!k2) { + i = Va3; + return; + } + f2 = c[p2 >> 2] | 0; + Ta3 = q2 + (f2 >>> 3) | 0; + n2 = d[Ta3 >> 0] | 0; + f2 = cc(1, 0, f2 & 7 | 0) | 0; + Ua3 = C2; + f2 = n2 | f2; + n2 = Ta3; + a[n2 >> 0] = f2; + a[n2 + 1 >> 0] = f2 >> 8; + a[n2 + 2 >> 0] = f2 >> 16; + a[n2 + 3 >> 0] = f2 >> 24; + Ta3 = Ta3 + 4 | 0; + a[Ta3 >> 0] = Ua3; + a[Ta3 + 1 >> 0] = Ua3 >> 8; + a[Ta3 + 2 >> 0] = Ua3 >> 16; + a[Ta3 + 3 >> 0] = Ua3 >> 24; + Ta3 = (c[p2 >> 2] | 0) + 1 | 0; + c[p2 >> 2] = Ta3; + Ua3 = q2 + (Ta3 >>> 3) | 0; + n2 = d[Ua3 >> 0] | 0; + q2 = cc(1, 0, Ta3 & 7 | 0) | 0; + Ta3 = C2; + q2 = n2 | q2; + n2 = Ua3; + a[n2 >> 0] = q2; + a[n2 + 1 >> 0] = q2 >> 8; + a[n2 + 2 >> 0] = q2 >> 16; + a[n2 + 3 >> 0] = q2 >> 24; + Ua3 = Ua3 + 4 | 0; + a[Ua3 >> 0] = Ta3; + a[Ua3 + 1 >> 0] = Ta3 >> 8; + a[Ua3 + 2 >> 0] = Ta3 >> 16; + a[Ua3 + 3 >> 0] = Ta3 >> 24; + c[p2 >> 2] = (c[p2 >> 2] | 0) + 8 & -8; + i = Va3; + return; + } + } + } + function zb(b3, e2, f2, g3) { + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + var h2 = 0, i2 = 0, j2 = 0, k2 = 0; + h2 = g3 + ((c[f2 >> 2] | 0) >>> 3) | 0; + j2 = d[h2 >> 0] | 0; + i2 = h2; + a[i2 >> 0] = j2; + a[i2 + 1 >> 0] = j2 >> 8; + a[i2 + 2 >> 0] = j2 >> 16; + a[i2 + 3 >> 0] = j2 >> 24; + h2 = h2 + 4 | 0; + a[h2 >> 0] = 0; + a[h2 + 1 >> 0] = 0; + a[h2 + 2 >> 0] = 0; + a[h2 + 3 >> 0] = 0; + h2 = (c[f2 >> 2] | 0) + 1 | 0; + c[f2 >> 2] = h2; + i2 = g3 + (h2 >>> 3) | 0; + j2 = d[i2 >> 0] | 0; + if (b3 >>> 0 < 65537) { + k2 = i2; + h2 = k2; + a[h2 >> 0] = j2; + a[h2 + 1 >> 0] = j2 >> 8; + a[h2 + 2 >> 0] = j2 >> 16; + a[h2 + 3 >> 0] = j2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = 0; + a[k2 + 1 >> 0] = 0; + a[k2 + 2 >> 0] = 0; + a[k2 + 3 >> 0] = 0; + k2 = (c[f2 >> 2] | 0) + 2 | 0; + c[f2 >> 2] = k2; + h2 = b3 + -1 | 0; + i2 = g3 + (k2 >>> 3) | 0; + j2 = d[i2 >> 0] | 0; + if (!((h2 & -65536 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + h2 = cc(h2 | 0, 0, k2 & 7 | 0) | 0; + b3 = C2; + h2 = j2 | h2; + k2 = i2; + j2 = k2; + a[j2 >> 0] = h2; + a[j2 + 1 >> 0] = h2 >> 8; + a[j2 + 2 >> 0] = h2 >> 16; + a[j2 + 3 >> 0] = h2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = b3; + a[k2 + 1 >> 0] = b3 >> 8; + a[k2 + 2 >> 0] = b3 >> 16; + a[k2 + 3 >> 0] = b3 >> 24; + k2 = (c[f2 >> 2] | 0) + 16 | 0; + c[f2 >> 2] = k2; + e2 = e2 & 1; + b3 = k2 >>> 3; + g3 = g3 + b3 | 0; + b3 = a[g3 >> 0] | 0; + b3 = b3 & 255; + k2 = k2 & 7; + k2 = cc(e2 | 0, 0, k2 | 0) | 0; + e2 = C2; + k2 = b3 | k2; + b3 = g3; + a[b3 >> 0] = k2; + a[b3 + 1 >> 0] = k2 >> 8; + a[b3 + 2 >> 0] = k2 >> 16; + a[b3 + 3 >> 0] = k2 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = e2; + a[g3 + 1 >> 0] = e2 >> 8; + a[g3 + 2 >> 0] = e2 >> 16; + a[g3 + 3 >> 0] = e2 >> 24; + g3 = c[f2 >> 2] | 0; + g3 = g3 + 1 | 0; + c[f2 >> 2] = g3; + return; + } else { + k2 = cc(1, 0, h2 & 7 | 0) | 0; + h2 = C2; + j2 = j2 | k2; + k2 = i2; + i2 = k2; + a[i2 >> 0] = j2; + a[i2 + 1 >> 0] = j2 >> 8; + a[i2 + 2 >> 0] = j2 >> 16; + a[i2 + 3 >> 0] = j2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = h2; + a[k2 + 1 >> 0] = h2 >> 8; + a[k2 + 2 >> 0] = h2 >> 16; + a[k2 + 3 >> 0] = h2 >> 24; + k2 = (c[f2 >> 2] | 0) + 2 | 0; + c[f2 >> 2] = k2; + h2 = b3 + -1 | 0; + i2 = g3 + (k2 >>> 3) | 0; + j2 = d[i2 >> 0] | 0; + if (!((h2 & -1048576 | 0) == 0 & true)) pa2(406196, 406218, 54, 406251); + h2 = cc(h2 | 0, 0, k2 & 7 | 0) | 0; + b3 = C2; + h2 = j2 | h2; + k2 = i2; + j2 = k2; + a[j2 >> 0] = h2; + a[j2 + 1 >> 0] = h2 >> 8; + a[j2 + 2 >> 0] = h2 >> 16; + a[j2 + 3 >> 0] = h2 >> 24; + k2 = k2 + 4 | 0; + a[k2 >> 0] = b3; + a[k2 + 1 >> 0] = b3 >> 8; + a[k2 + 2 >> 0] = b3 >> 16; + a[k2 + 3 >> 0] = b3 >> 24; + k2 = (c[f2 >> 2] | 0) + 20 | 0; + c[f2 >> 2] = k2; + e2 = e2 & 1; + b3 = k2 >>> 3; + g3 = g3 + b3 | 0; + b3 = a[g3 >> 0] | 0; + b3 = b3 & 255; + k2 = k2 & 7; + k2 = cc(e2 | 0, 0, k2 | 0) | 0; + e2 = C2; + k2 = b3 | k2; + b3 = g3; + a[b3 >> 0] = k2; + a[b3 + 1 >> 0] = k2 >> 8; + a[b3 + 2 >> 0] = k2 >> 16; + a[b3 + 3 >> 0] = k2 >> 24; + g3 = g3 + 4 | 0; + a[g3 >> 0] = e2; + a[g3 + 1 >> 0] = e2 >> 8; + a[g3 + 2 >> 0] = e2 >> 16; + a[g3 + 3 >> 0] = e2 >> 24; + g3 = c[f2 >> 2] | 0; + g3 = g3 + 1 | 0; + c[f2 >> 2] = g3; + return; + } + } + function Ab(e2, f2, g3, h2, j2, k2) { + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + var l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, _2 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, qa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0, Ua3 = 0, Va3 = 0, Wa3 = 0, Xa3 = 0, Ya2 = 0, Za3 = 0, _a2 = 0, $a3 = 0, ab3 = 0, bb3 = 0, cb2 = 0, db2 = 0, eb2 = 0, fb2 = 0; + fb2 = i; + i = i + 16 | 0; + db2 = fb2 + 8 | 0; + eb2 = fb2 + 4 | 0; + $a3 = fb2; + if (!(Bb(e2) | 0)) { + k2 = 0; + i = fb2; + return k2 | 0; + } + bb3 = e2 + 5232 | 0; + if ((c[bb3 >> 2] | 0) != 0 ? (c[f2 >> 2] | 0) != 0 : 0) { + k2 = 0; + i = fb2; + return k2 | 0; + } + cb2 = e2 + 4 | 0; + l2 = c[cb2 >> 2] | 0; + if (l2 >>> 0 < 2) { + M2 = 1 << c[e2 + 8 >> 2]; + o2 = c[f2 >> 2] | 0; + o2 = o2 >>> 0 < M2 >>> 0 ? o2 : M2; + o2 = o2 >>> 0 > 131072 ? 131072 : o2; + N3 = e2 + 16 | 0; + a: do + switch (l2 | 0) { + case 0: { + p2 = 0; + n2 = 0; + L3 = 0; + K3 = 0; + ab3 = 20; + break; + } + case 1: { + n2 = e2 + 5208 | 0; + ab3 = c[n2 >> 2] | 0; + l2 = ab3; + b: do + if (!ab3) { + do + if ((o2 | 0) == 131072) { + l2 = e2 + 24 | 0; + m3 = sa2[c[N3 >> 2] & 1](c[l2 >> 2] | 0, 524288) | 0; + if (!m3) oa2(1); + c[n2 >> 2] = m3; + l2 = sa2[c[N3 >> 2] & 1](c[l2 >> 2] | 0, 131072) | 0; + if (l2) { + c[e2 + 5212 >> 2] = l2; + l2 = c[n2 >> 2] | 0; + if (!l2) break; + else { + p2 = l2; + break b; + } + } else oa2(1); + } + while (0); + l2 = e2 + 24 | 0; + m3 = sa2[c[N3 >> 2] & 1](c[l2 >> 2] | 0, o2 << 2) | 0; + if (!m3) oa2(1); + l2 = sa2[c[N3 >> 2] & 1](c[l2 >> 2] | 0, o2) | 0; + if (!l2) oa2(1); + else { + p2 = m3; + n2 = l2; + L3 = m3; + K3 = l2; + ab3 = 20; + break a; + } + } else p2 = l2; + while (0); + n2 = c[e2 + 5212 >> 2] | 0; + L3 = 0; + K3 = 0; + ab3 = 20; + break; + } + default: + O3 = 0; + } + while (0); + do + if ((ab3 | 0) == 20) { + v3 = e2 + 193 | 0; + w2 = e2 + 5220 | 0; + x3 = e2 + 196 | 0; + y3 = e2 + 200 | 0; + z3 = e2 + 20 | 0; + A3 = e2 + 24 | 0; + B3 = e2 + 192 | 0; + D3 = e2 + 4308 | 0; + E3 = e2 + 4436 | 0; + F3 = e2 + 5204 | 0; + G3 = e2 + 4692 | 0; + H3 = e2 + 5216 | 0; + I3 = e2 + 5224 | 0; + J3 = (k2 | 0) == 0; + c: while (1) { + l2 = c[bb3 >> 2] | 0; + while (1) { + if ((l2 | 0) == 1 ? (a[v3 >> 0] | 0) != 0 : 0) { + ab3 = 24; + break; + } + m3 = c[w2 >> 2] | 0; + if (m3) break; + if (l2) { + ab3 = 49; + break c; + } + u3 = c[f2 >> 2] | 0; + s2 = M2 >>> 0 < u3 >>> 0 ? M2 : u3; + u3 = (u3 | 0) == (s2 | 0) ? 1 : 0; + l2 = (s2 << 1) + 502 | 0; + c[db2 >> 2] = d[v3 >> 0]; + if (l2 >>> 0 > (c[h2 >> 2] | 0) >>> 0) { + m3 = c[y3 >> 2] | 0; + if ((c[x3 >> 2] | 0) >>> 0 < l2 >>> 0) { + ra2[c[z3 >> 2] & 1](c[A3 >> 2] | 0, m3); + c[y3 >> 2] = 0; + m3 = sa2[c[N3 >> 2] & 1](c[A3 >> 2] | 0, l2) | 0; + if (!m3) { + ab3 = 34; + break c; + } + c[y3 >> 2] = m3; + c[x3 >> 2] = l2; + t3 = 0; + } else t3 = 0; + } else { + t3 = 1; + m3 = c[j2 >> 2] | 0; + } + a[m3 >> 0] = a[B3 >> 0] | 0; + l2 = Cb(e2, c[cb2 >> 2] | 0, s2, eb2) | 0; + o2 = c[g3 >> 2] | 0; + q2 = u3 << 24 >> 24 != 0; + r2 = c[eb2 >> 2] | 0; + if (!(c[cb2 >> 2] | 0)) ub(N3, o2, s2, q2, l2, r2, D3, E3, F3, G3, db2, m3); + else yb(N3, o2, s2, q2, p2, n2, l2, r2, db2, m3); + c[g3 >> 2] = (c[g3 >> 2] | 0) + s2; + c[f2 >> 2] = (c[f2 >> 2] | 0) - s2; + o2 = c[db2 >> 2] | 0; + q2 = o2 >>> 3; + if (t3 << 24 >> 24) { + l2 = c[h2 >> 2] | 0; + if (q2 >>> 0 > l2 >>> 0) { + ab3 = 41; + break c; + } + if (!((o2 & 7 | 0) == 0 | q2 >>> 0 < l2 >>> 0)) { + ab3 = 43; + break c; + } + c[j2 >> 2] = (c[j2 >> 2] | 0) + q2; + c[h2 >> 2] = (c[h2 >> 2] | 0) - q2; + l2 = (c[I3 >> 2] | 0) + q2 | 0; + c[I3 >> 2] = l2; + if (!J3) c[k2 >> 2] = l2; + } else { + c[H3 >> 2] = m3; + c[w2 >> 2] = q2; + } + a[B3 >> 0] = a[m3 + ((c[db2 >> 2] | 0) >>> 3) >> 0] | 0; + a[v3 >> 0] = c[db2 >> 2] & 7; + if (!(u3 << 24 >> 24)) continue c; + c[bb3 >> 2] = 2; + l2 = 2; + } + if ((ab3 | 0) == 24) { + ab3 = 0; + Eb(e2); + continue; + } + l2 = c[h2 >> 2] | 0; + if (!l2) { + ab3 = 49; + break; + } + l2 = m3 >>> 0 < l2 >>> 0 ? m3 : l2; + dc(c[j2 >> 2] | 0, c[H3 >> 2] | 0, l2 | 0) | 0; + c[j2 >> 2] = (c[j2 >> 2] | 0) + l2; + c[h2 >> 2] = (c[h2 >> 2] | 0) - l2; + c[H3 >> 2] = (c[H3 >> 2] | 0) + l2; + c[w2 >> 2] = (c[w2 >> 2] | 0) - l2; + l2 = (c[I3 >> 2] | 0) + l2 | 0; + c[I3 >> 2] = l2; + if (J3) continue; + c[k2 >> 2] = l2; + } + if ((ab3 | 0) == 34) oa2(1); + else if ((ab3 | 0) == 41) pa2(406280, 406053, 1436, 406308); + else if ((ab3 | 0) == 43) pa2(406340, 406053, 1437, 406308); + else if ((ab3 | 0) == 49) { + ra2[c[z3 >> 2] & 1](c[A3 >> 2] | 0, L3); + ra2[c[z3 >> 2] & 1](c[A3 >> 2] | 0, K3); + if ((c[bb3 >> 2] | 0) != 1) { + O3 = 1; + break; + } + if (c[w2 >> 2] | 0) { + O3 = 1; + break; + } + c[bb3 >> 2] = 0; + c[H3 >> 2] = 0; + O3 = 1; + break; + } + } + while (0); + k2 = O3; + i = fb2; + return k2 | 0; + } + Xa3 = e2 + 80 | 0; + Ya2 = e2 + 152 | 0; + x3 = e2 + 12 | 0; + y3 = e2 + 193 | 0; + z3 = e2 + 5220 | 0; + A3 = e2 + 5216 | 0; + B3 = e2 + 16 | 0; + D3 = e2 + 116 | 0; + E3 = e2 + 92 | 0; + F3 = e2 + 5236 | 0; + G3 = e2 + 5208 | 0; + H3 = e2 + 24 | 0; + I3 = e2 + 5212 | 0; + J3 = e2 + 196 | 0; + K3 = e2 + 200 | 0; + L3 = e2 + 20 | 0; + M2 = e2 + 24 | 0; + N3 = e2 + 192 | 0; + O3 = e2 + 4308 | 0; + P3 = e2 + 4436 | 0; + Q3 = e2 + 5204 | 0; + R3 = e2 + 4692 | 0; + S3 = e2 + 128 | 0; + T3 = e2 + 120 | 0; + U3 = e2 + 124 | 0; + V3 = e2 + 20 | 0; + W3 = e2 + 160 | 0; + X3 = e2 + 136 | 0; + Y3 = e2 + 132 | 0; + Z3 = e2 + 4 | 0; + _2 = e2 + 72 | 0; + $2 = e2 + 8 | 0; + ba2 = e2 + 144 | 0; + ca3 = e2 + 28 | 0; + da3 = e2 + 32 | 0; + ea3 = e2 + 36 | 0; + fa3 = e2 + 40 | 0; + ga3 = e2 + 44 | 0; + ha3 = e2 + 48 | 0; + ia3 = e2 + 52 | 0; + ja3 = e2 + 56 | 0; + ka3 = e2 + 60 | 0; + la3 = e2 + 64 | 0; + ma3 = e2 + 68 | 0; + na2 = e2 + 8 | 0; + qa3 = e2 + 194 | 0; + ta3 = e2 + 195 | 0; + ua3 = e2 + 176 | 0; + va3 = e2 + 176 | 0; + wa3 = e2 + 160 | 0; + xa3 = e2 + 8 | 0; + ya3 = e2 + 5224 | 0; + za3 = (k2 | 0) == 0; + Aa3 = e2 + 108 | 0; + Ba3 = e2 + 96 | 0; + Ca3 = e2 + 112 | 0; + Da3 = e2 + 104 | 0; + Ea3 = e2 + 116 | 0; + Fa3 = e2 + 116 | 0; + Ga3 = e2 + 92 | 0; + Ua3 = e2 + 104 | 0; + Va3 = e2 + 100 | 0; + Wa3 = e2 + 88 | 0; + d: while (1) { + m3 = Xa3; + l2 = Ya2; + l2 = $b(c[m3 >> 2] | 0, c[m3 + 4 >> 2] | 0, c[l2 >> 2] | 0, c[l2 + 4 >> 2] | 0) | 0; + m3 = C2; + if (Bb(e2) | 0) n2 = 1 << c[x3 >> 2]; + else n2 = 0; + if ((m3 >>> 0 < 0 | (m3 | 0) == 0 & l2 >>> 0 < n2 >>> 0 ? (Za3 = n2 - l2 | 0, (Za3 | 0) != 0) : 0) ? (_a2 = c[f2 >> 2] | 0, (_a2 | 0) != 0) : 0) { + p2 = Za3 >>> 0 < _a2 >>> 0 ? Za3 : _a2; + o2 = c[g3 >> 2] | 0; + if (Bb(e2) | 0) { + l2 = c[Aa3 >> 2] | 0; + if ((l2 | 0) == 0 ? p2 >>> 0 < (c[Ba3 >> 2] | 0) >>> 0 : 0) { + c[Aa3 >> 2] = p2; + l2 = sa2[c[B3 >> 2] & 1](c[H3 >> 2] | 0, p2 + 9 | 0) | 0; + if (!l2) { + ab3 = 62; + break; + } + m3 = c[Ca3 >> 2] | 0; + if (m3) { + dc(l2 | 0, m3 | 0, (c[Da3 >> 2] | 0) + 9 | 0) | 0; + ra2[c[V3 >> 2] & 1](c[H3 >> 2] | 0, c[Ca3 >> 2] | 0); + c[Ca3 >> 2] = 0; + } + c[Ca3 >> 2] = l2; + c[Da3 >> 2] = p2; + c[Ea3 >> 2] = l2 + 2; + a[l2 + 1 >> 0] = 0; + a[(c[Ea3 >> 2] | 0) + -2 >> 0] = 0; + l2 = 0; + while (1) { + if ((l2 | 0) == 7) break; + a[(c[Ea3 >> 2] | 0) + ((c[Da3 >> 2] | 0) + l2) >> 0] = 0; + l2 = l2 + 1 | 0; + } + dc(c[Fa3 >> 2] | 0, o2 | 0, p2 | 0) | 0; + } else { + n2 = c[Va3 >> 2] | 0; + if ((c[Ua3 >> 2] | 0) >>> 0 < n2 >>> 0) { + l2 = sa2[c[B3 >> 2] & 1](c[H3 >> 2] | 0, n2 + 9 | 0) | 0; + if (!l2) { + ab3 = 71; + break; + } + m3 = c[Ca3 >> 2] | 0; + if (m3) { + dc(l2 | 0, m3 | 0, (c[Da3 >> 2] | 0) + 9 | 0) | 0; + ra2[c[V3 >> 2] & 1](c[H3 >> 2] | 0, c[Ca3 >> 2] | 0); + c[Ca3 >> 2] = 0; + } + c[Ca3 >> 2] = l2; + c[Da3 >> 2] = n2; + c[Ea3 >> 2] = l2 + 2; + a[l2 + 1 >> 0] = 0; + a[(c[Ea3 >> 2] | 0) + -2 >> 0] = 0; + l2 = 0; + while (1) { + if ((l2 | 0) == 7) break; + a[(c[Ea3 >> 2] | 0) + ((c[Da3 >> 2] | 0) + l2) >> 0] = 0; + l2 = l2 + 1 | 0; + } + a[(c[Fa3 >> 2] | 0) + ((c[Wa3 >> 2] | 0) + -2) >> 0] = 0; + a[(c[Fa3 >> 2] | 0) + ((c[Wa3 >> 2] | 0) + -1) >> 0] = 0; + l2 = c[Aa3 >> 2] | 0; + } + n2 = l2 & c[Ga3 >> 2]; + l2 = c[Ba3 >> 2] | 0; + if (l2 >>> 0 > n2 >>> 0) { + ab3 = l2 - n2 | 0; + dc((c[Fa3 >> 2] | 0) + ((c[Wa3 >> 2] | 0) + n2) | 0, o2 | 0, (p2 >>> 0 < ab3 >>> 0 ? p2 : ab3) | 0) | 0; + } + m3 = (c[Fa3 >> 2] | 0) + n2 | 0; + l2 = o2; + if ((n2 + p2 | 0) >>> 0 > (c[Wa3 >> 2] | 0) >>> 0) { + ab3 = (c[Va3 >> 2] | 0) - n2 | 0; + dc(m3 | 0, l2 | 0, (p2 >>> 0 < ab3 >>> 0 ? p2 : ab3) | 0) | 0; + ab3 = c[Wa3 >> 2] | 0; + dc(c[Fa3 >> 2] | 0, l2 + (ab3 - n2) | 0, p2 + (n2 - ab3) | 0) | 0; + } else dc(m3 | 0, l2 | 0, p2 | 0) | 0; + l2 = c[Fa3 >> 2] | 0; + a[l2 + -2 >> 0] = a[l2 + ((c[Wa3 >> 2] | 0) + -2) >> 0] | 0; + l2 = c[Fa3 >> 2] | 0; + a[l2 + -1 >> 0] = a[l2 + ((c[Wa3 >> 2] | 0) + -1) >> 0] | 0; + l2 = (c[Aa3 >> 2] | 0) + p2 | 0; + c[Aa3 >> 2] = l2; + if (l2 >>> 0 > 1073741824) c[Aa3 >> 2] = l2 & 1073741823 | 1073741824; + } + ab3 = Xa3; + ab3 = ec(c[ab3 >> 2] | 0, c[ab3 + 4 >> 2] | 0, p2 | 0, 0) | 0; + l2 = Xa3; + c[l2 >> 2] = ab3; + c[l2 + 4 >> 2] = C2; + l2 = c[Aa3 >> 2] | 0; + if (l2 >>> 0 <= (c[Ga3 >> 2] | 0) >>> 0) { + ab3 = (c[Fa3 >> 2] | 0) + l2 | 0; + a[ab3 >> 0] = 0; + a[ab3 + 1 >> 0] = 0; + a[ab3 + 2 >> 0] = 0; + a[ab3 + 3 >> 0] = 0; + a[ab3 + 4 >> 0] = 0; + a[ab3 + 5 >> 0] = 0; + a[ab3 + 6 >> 0] = 0; + } + } + c[g3 >> 2] = (c[g3 >> 2] | 0) + p2; + c[f2 >> 2] = (c[f2 >> 2] | 0) - p2; + continue; + } + l2 = c[bb3 >> 2] | 0; + n2 = (l2 | 0) == 1; + if (n2 ? (a[y3 >> 0] | 0) != 0 : 0) { + Eb(e2); + continue; + } + m3 = c[z3 >> 2] | 0; + o2 = (m3 | 0) == 0; + if (!o2) { + l2 = c[h2 >> 2] | 0; + if (!l2) { + ab3 = 234; + break; + } + l2 = m3 >>> 0 < l2 >>> 0 ? m3 : l2; + dc(c[j2 >> 2] | 0, c[A3 >> 2] | 0, l2 | 0) | 0; + c[j2 >> 2] = (c[j2 >> 2] | 0) + l2; + c[h2 >> 2] = (c[h2 >> 2] | 0) - l2; + c[A3 >> 2] = (c[A3 >> 2] | 0) + l2; + c[z3 >> 2] = (c[z3 >> 2] | 0) - l2; + l2 = (c[ya3 >> 2] | 0) + l2 | 0; + c[ya3 >> 2] = l2; + if (za3) continue; + c[k2 >> 2] = l2; + continue; + } + if (l2) { + ab3 = 234; + break; + } + w2 = (c[f2 >> 2] | 0) == 0 ? 1 : 0; + o2 = Xa3; + n2 = c[o2 >> 2] | 0; + o2 = c[o2 + 4 >> 2] | 0; + q2 = Ya2; + p2 = c[q2 >> 2] | 0; + q2 = c[q2 + 4 >> 2] | 0; + s2 = $b(n2 | 0, o2 | 0, p2 | 0, q2 | 0) | 0; + l2 = C2; + if (q2 >>> 0 > 0 | (q2 | 0) == 0 & p2 >>> 0 > 3221225471) { + r2 = bc(p2 | 0, q2 | 0, 30) | 0; + r2 = p2 & 1073741823 | ((r2 & 1 ^ 1) << 30) + 1073741824; + } else r2 = p2; + if (!(Bb(e2) | 0)) { + ab3 = 231; + break; + } + u3 = c[D3 >> 2] | 0; + v3 = c[E3 >> 2] | 0; + if (a[F3 >> 0] & 1) { + ab3 = 231; + break; + } + t3 = w2 << 24 >> 24 == 0; + if (!t3) a[F3 >> 0] = 1; + if (Bb(e2) | 0) m3 = 1 << c[x3 >> 2]; + else m3 = 0; + if (l2 >>> 0 > 0 | (l2 | 0) == 0 & s2 >>> 0 > m3 >>> 0) { + ab3 = 231; + break; + } + l2 = c[cb2 >> 2] | 0; + if ((l2 | 0) == 1) if (!(c[G3 >> 2] | 0)) { + l2 = sa2[c[B3 >> 2] & 1](c[H3 >> 2] | 0, 524288) | 0; + if (!l2) { + ab3 = 108; + break; + } + c[G3 >> 2] = l2; + l2 = sa2[c[B3 >> 2] & 1](c[H3 >> 2] | 0, 131072) | 0; + if (!l2) { + ab3 = 110; + break; + } + c[I3 >> 2] = l2; + l2 = c[cb2 >> 2] | 0; + ab3 = 112; + } else ab3 = 114; + else ab3 = 112; + e: do + if ((ab3 | 0) == 112) { + ab3 = 0; + if ((l2 | 0) != 0 ? (l2 | 0) != 1 : 0) { + m3 = c[S3 >> 2] | 0; + l2 = m3 + (s2 >>> 1) + 1 | 0; + if (l2 >>> 0 > (c[T3 >> 2] | 0) >>> 0) { + l2 = l2 + ((s2 >>> 2) + 16) | 0; + c[T3 >> 2] = l2; + l2 = sa2[c[B3 >> 2] & 1](c[H3 >> 2] | 0, l2 << 4) | 0; + if (!l2) { + ab3 = 127; + break d; + } + m3 = c[U3 >> 2] | 0; + if (m3) { + dc(l2 | 0, m3 | 0, c[S3 >> 2] << 4 | 0) | 0; + ra2[c[V3 >> 2] & 1](c[H3 >> 2] | 0, c[U3 >> 2] | 0); + c[U3 >> 2] = 0; + } + c[U3 >> 2] = l2; + m3 = c[S3 >> 2] | 0; + } else l2 = c[U3 >> 2] | 0; + m3 = l2 + (m3 << 4) | 0; + l2 = c[Z3 >> 2] | 0; + f: do + switch (l2 | 0) { + case 10: { + Ha2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[_2 >> 2] | 0, W3, X3, m3, S3, Y3); + break; + } + case 11: { + Ia2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[_2 >> 2] | 0, W3, X3, m3, S3, Y3); + break; + } + default: { + if ((l2 | 0) > 9) break f; + do + if ((l2 | 0) < 5) ab3 = 139; + else { + if ((c[xa3 >> 2] | 0) >= 17) { + ab3 = 139; + break; + } + if ((l2 | 0) < 7) break; + l2 = (l2 | 0) < 9 ? 41 : 42; + ab3 = 139; + } + while (0); + g: do + if ((ab3 | 0) == 139) { + ab3 = 0; + do + switch (l2 | 0) { + case 40: + break g; + case 2: { + Ja2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[ca3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + case 3: { + Ka2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[da3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + case 4: { + La2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[ea3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + case 5: { + Ma2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[fa3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + case 6: { + Na2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[ga3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + case 7: { + Oa2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[ha3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + case 8: { + Pa2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[ia3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + case 9: { + Qa2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[ja3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + case 41: { + Sa2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[la3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + case 42: { + Ta2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[ma3 >> 2] | 0, W3, X3, m3, S3, Y3); + break f; + } + default: + break f; + } + while (0); + } + while (0); + Ra2(B3, s2, r2, w2 << 24 >> 24 != 0, u3, v3, e2, c[ka3 >> 2] | 0, W3, X3, m3, S3, Y3); + } + } + while (0); + n2 = c[$2 >> 2] | 0; + m3 = c[x3 >> 2] | 0; + m3 = ((n2 | 0) > (m3 | 0) ? n2 : m3) + 1 | 0; + m3 = 1 << ((m3 | 0) < 24 ? m3 : 24); + n2 = m3 >>> 3; + s2 = Xa3; + o2 = ba2; + o2 = $b(c[s2 >> 2] | 0, c[s2 + 4 >> 2] | 0, c[o2 >> 2] | 0, c[o2 + 4 >> 2] | 0) | 0; + if (Bb(e2) | 0) q2 = 1 << c[x3 >> 2]; + else q2 = 0; + l2 = c[cb2 >> 2] | 0; + if ((l2 | 0) < 4) p2 = ((c[Y3 >> 2] | 0) + (c[S3 >> 2] | 0) | 0) >>> 0 > 12286; + else p2 = 0; + do + if (!(t3 ^ 1 | p2 | (o2 + q2 | 0) >>> 0 > m3 >>> 0)) { + if ((c[Y3 >> 2] | 0) >>> 0 >= n2 >>> 0) break; + if ((c[S3 >> 2] | 0) >>> 0 >= n2 >>> 0) break; + n2 = Ya2; + m3 = c[n2 >> 2] | 0; + n2 = c[n2 + 4 >> 2] | 0; + if (n2 >>> 0 > 0 | (n2 | 0) == 0 & m3 >>> 0 > 3221225471) { + v3 = bc(m3 | 0, n2 | 0, 30) | 0; + m3 = m3 & 1073741823 | ((v3 & 1 ^ 1) << 30) + 1073741824; + } + o2 = Xa3; + n2 = c[o2 >> 2] | 0; + o2 = c[o2 + 4 >> 2] | 0; + if (o2 >>> 0 > 0 | (o2 | 0) == 0 & n2 >>> 0 > 3221225471) { + p2 = bc(n2 | 0, o2 | 0, 30) | 0; + p2 = n2 & 1073741823 | ((p2 & 1 ^ 1) << 30) + 1073741824; + } else p2 = n2; + v3 = Ya2; + c[v3 >> 2] = n2; + c[v3 + 4 >> 2] = o2; + h: do + if (p2 >>> 0 < m3 >>> 0) { + i: do + if ((l2 | 0) <= 9) { + do + if ((l2 | 0) < 5) ab3 = 168; + else { + if ((c[na2 >> 2] | 0) >= 17) { + ab3 = 168; + break; + } + if ((l2 | 0) < 7) break; + l2 = (l2 | 0) < 9 ? 41 : 42; + ab3 = 168; + } + while (0); + j: do + if ((ab3 | 0) == 168) { + ab3 = 0; + do + switch (l2 | 0) { + case 10: + break i; + case 40: + break j; + case 2: { + v3 = c[ca3 >> 2] | 0; + a[v3 + 262148 >> 0] = 1; + c[v3 + 262152 >> 2] = 0; + c[v3 + 262156 >> 2] = 0; + break h; + } + case 3: { + v3 = c[da3 >> 2] | 0; + a[v3 + 262152 >> 0] = 1; + c[v3 + 262156 >> 2] = 0; + c[v3 + 262160 >> 2] = 0; + break h; + } + case 4: { + v3 = c[ea3 >> 2] | 0; + a[v3 + 524304 >> 0] = 1; + c[v3 + 524308 >> 2] = 0; + c[v3 + 524312 >> 2] = 0; + break h; + } + case 5: { + v3 = c[fa3 >> 2] | 0; + a[v3 + 1081344 >> 0] = 1; + c[v3 + 1081348 >> 2] = 0; + c[v3 + 1081352 >> 2] = 0; + break h; + } + case 6: { + v3 = c[ga3 >> 2] | 0; + a[v3 + 2129920 >> 0] = 1; + c[v3 + 2129924 >> 2] = 0; + c[v3 + 2129928 >> 2] = 0; + break h; + } + case 7: { + v3 = c[ha3 >> 2] | 0; + a[v3 + 8454144 >> 0] = 1; + c[v3 + 8454148 >> 2] = 0; + c[v3 + 8454152 >> 2] = 0; + break h; + } + case 8: { + v3 = c[ia3 >> 2] | 0; + a[v3 + 16842752 >> 0] = 1; + c[v3 + 16842756 >> 2] = 0; + c[v3 + 16842760 >> 2] = 0; + break h; + } + case 9: { + v3 = c[ja3 >> 2] | 0; + a[v3 + 33619968 >> 0] = 1; + c[v3 + 33619972 >> 2] = 0; + c[v3 + 33619976 >> 2] = 0; + break h; + } + case 41: { + v3 = c[la3 >> 2] | 0; + a[v3 + 524290 >> 0] = 1; + c[v3 + 524292 >> 2] = 0; + c[v3 + 524296 >> 2] = 0; + break h; + } + case 42: { + v3 = c[ma3 >> 2] | 0; + a[v3 + 1311744 >> 0] = 1; + c[v3 + 1311748 >> 2] = 0; + c[v3 + 1311752 >> 2] = 0; + break h; + } + default: + break h; + } + while (0); + } + while (0); + v3 = c[ka3 >> 2] | 0; + a[v3 + 524290 >> 0] = 1; + c[v3 + 524292 >> 2] = 0; + c[v3 + 524296 >> 2] = 0; + break h; + } + while (0); + a[(c[_2 >> 2] | 0) + 524304 >> 0] = 1; + } + while (0); + c[z3 >> 2] = 0; + break e; + } + while (0); + l2 = c[X3 >> 2] | 0; + if (l2) { + m3 = c[S3 >> 2] | 0; + c[S3 >> 2] = m3 + 1; + s2 = c[U3 >> 2] | 0; + c[s2 + (m3 << 4) >> 2] = l2; + c[s2 + (m3 << 4) + 4 >> 2] = 67108864; + c[s2 + (m3 << 4) + 8 >> 2] = 0; + b2[s2 + (m3 << 4) + 14 >> 1] = 16; + m3 = s2 + (m3 << 4) + 12 | 0; + do + if (l2 >>> 0 >= 6) { + if (l2 >>> 0 < 130) { + s2 = l2 + -2 | 0; + l2 = ((aa(s2 | 0) | 0) ^ 31) + -1 | 0; + l2 = (l2 << 1) + (s2 >>> l2) + 2 | 0; + break; + } + if (l2 >>> 0 < 2114) { + l2 = ((aa(l2 + -66 | 0) | 0) ^ 31) + 10 | 0; + break; + } + if (l2 >>> 0 < 6210) { + l2 = 21; + break; + } + l2 = l2 >>> 0 < 22594 ? 22 : 23; + } + while (0); + s2 = l2 & 65535; + b2[m3 >> 1] = b2[88156 + ((s2 >>> 3) * 3 << 1) >> 1] | (s2 << 3 & 56 | 2) & 65535; + c[Y3 >> 2] = (c[Y3 >> 2] | 0) + (c[X3 >> 2] | 0); + c[X3 >> 2] = 0; + } + m3 = Xa3; + l2 = c[m3 >> 2] | 0; + m3 = c[m3 + 4 >> 2] | 0; + o2 = ba2; + n2 = c[o2 >> 2] | 0; + o2 = c[o2 + 4 >> 2] | 0; + if (t3 & ((l2 | 0) == (n2 | 0) & (m3 | 0) == (o2 | 0))) { + c[z3 >> 2] = 0; + break; + } + if (m3 >>> 0 < o2 >>> 0 | (m3 | 0) == (o2 | 0) & l2 >>> 0 < n2 >>> 0) { + ab3 = 194; + break d; + } + if (!(m3 >>> 0 > o2 >>> 0 | (m3 | 0) == (o2 | 0) & l2 >>> 0 > n2 >>> 0 | t3 ^ 1)) { + ab3 = 196; + break d; + } + n2 = $b(l2 | 0, m3 | 0, n2 | 0, o2 | 0) | 0; + t3 = C2; + if (!(t3 >>> 0 < 0 | (t3 | 0) == 0 & n2 >>> 0 < 16777217)) { + ab3 = 198; + break d; + } + l2 = (n2 << 1) + 502 | 0; + if ((c[J3 >> 2] | 0) >>> 0 < l2 >>> 0) { + ra2[c[L3 >> 2] & 1](c[M2 >> 2] | 0, c[K3 >> 2] | 0); + c[K3 >> 2] = 0; + t3 = sa2[c[B3 >> 2] & 1](c[M2 >> 2] | 0, l2) | 0; + m3 = t3; + if (!t3) { + ab3 = 202; + break d; + } + c[K3 >> 2] = m3; + c[J3 >> 2] = l2; + } else m3 = c[K3 >> 2] | 0; + c[$a3 >> 2] = d[y3 >> 0]; + p2 = m3; + a[p2 >> 0] = a[N3 >> 0] | 0; + q2 = u3; + o2 = ba2; + Db(B3, q2, v3, c[o2 >> 2] | 0, c[o2 + 4 >> 2] | 0, n2, w2 << 24 >> 24 != 0, e2, a[qa3 >> 0] | 0, a[ta3 >> 0] | 0, c[Y3 >> 2] | 0, c[S3 >> 2] | 0, c[U3 >> 2] | 0, ua3, W3, $a3, p2); + a[N3 >> 0] = a[p2 + ((c[$a3 >> 2] | 0) >>> 3) >> 0] | 0; + a[y3 >> 0] = c[$a3 >> 2] & 7; + p2 = Xa3; + o2 = c[p2 >> 2] | 0; + p2 = c[p2 + 4 >> 2] | 0; + n2 = ba2; + c[n2 >> 2] = o2; + c[n2 + 4 >> 2] = p2; + n2 = Ya2; + l2 = c[n2 >> 2] | 0; + n2 = c[n2 + 4 >> 2] | 0; + if (n2 >>> 0 > 0 | (n2 | 0) == 0 & l2 >>> 0 > 3221225471) { + u3 = bc(l2 | 0, n2 | 0, 30) | 0; + l2 = l2 & 1073741823 | ((u3 & 1 ^ 1) << 30) + 1073741824; + } + if (p2 >>> 0 > 0 | (p2 | 0) == 0 & o2 >>> 0 > 3221225471) { + n2 = bc(o2 | 0, p2 | 0, 30) | 0; + n2 = o2 & 1073741823 | ((n2 & 1 ^ 1) << 30) + 1073741824; + } else n2 = o2; + u3 = Ya2; + c[u3 >> 2] = o2; + c[u3 + 4 >> 2] = p2; + k: do + if (n2 >>> 0 < l2 >>> 0) { + l2 = c[cb2 >> 2] | 0; + l: do + if ((l2 | 0) <= 9) { + do + if ((l2 | 0) < 5) ab3 = 214; + else { + if ((c[na2 >> 2] | 0) >= 17) { + ab3 = 214; + break; + } + if ((l2 | 0) < 7) break; + l2 = (l2 | 0) < 9 ? 41 : 42; + ab3 = 214; + } + while (0); + m: do + if ((ab3 | 0) == 214) { + ab3 = 0; + do + switch (l2 | 0) { + case 10: + break l; + case 40: + break m; + case 2: { + u3 = c[ca3 >> 2] | 0; + a[u3 + 262148 >> 0] = 1; + c[u3 + 262152 >> 2] = 0; + c[u3 + 262156 >> 2] = 0; + break k; + } + case 3: { + u3 = c[da3 >> 2] | 0; + a[u3 + 262152 >> 0] = 1; + c[u3 + 262156 >> 2] = 0; + c[u3 + 262160 >> 2] = 0; + break k; + } + case 4: { + u3 = c[ea3 >> 2] | 0; + a[u3 + 524304 >> 0] = 1; + c[u3 + 524308 >> 2] = 0; + c[u3 + 524312 >> 2] = 0; + break k; + } + case 5: { + u3 = c[fa3 >> 2] | 0; + a[u3 + 1081344 >> 0] = 1; + c[u3 + 1081348 >> 2] = 0; + c[u3 + 1081352 >> 2] = 0; + break k; + } + case 6: { + u3 = c[ga3 >> 2] | 0; + a[u3 + 2129920 >> 0] = 1; + c[u3 + 2129924 >> 2] = 0; + c[u3 + 2129928 >> 2] = 0; + break k; + } + case 7: { + u3 = c[ha3 >> 2] | 0; + a[u3 + 8454144 >> 0] = 1; + c[u3 + 8454148 >> 2] = 0; + c[u3 + 8454152 >> 2] = 0; + break k; + } + case 8: { + u3 = c[ia3 >> 2] | 0; + a[u3 + 16842752 >> 0] = 1; + c[u3 + 16842756 >> 2] = 0; + c[u3 + 16842760 >> 2] = 0; + break k; + } + case 9: { + u3 = c[ja3 >> 2] | 0; + a[u3 + 33619968 >> 0] = 1; + c[u3 + 33619972 >> 2] = 0; + c[u3 + 33619976 >> 2] = 0; + break k; + } + case 41: { + u3 = c[la3 >> 2] | 0; + a[u3 + 524290 >> 0] = 1; + c[u3 + 524292 >> 2] = 0; + c[u3 + 524296 >> 2] = 0; + break k; + } + case 42: { + u3 = c[ma3 >> 2] | 0; + a[u3 + 1311744 >> 0] = 1; + c[u3 + 1311748 >> 2] = 0; + c[u3 + 1311752 >> 2] = 0; + break k; + } + default: + break k; + } + while (0); + } + while (0); + u3 = c[ka3 >> 2] | 0; + a[u3 + 524290 >> 0] = 1; + c[u3 + 524292 >> 2] = 0; + c[u3 + 524296 >> 2] = 0; + break k; + } + while (0); + a[(c[_2 >> 2] | 0) + 524304 >> 0] = 1; + } + while (0); + n2 = ba2; + l2 = c[n2 >> 2] | 0; + n2 = c[n2 + 4 >> 2] | 0; + do + if (!((l2 | 0) == 0 & (n2 | 0) == 0)) { + a[qa3 >> 0] = a[q2 + (l2 + -1 & v3) >> 0] | 0; + if (!(n2 >>> 0 > 0 | (n2 | 0) == 0 & l2 >>> 0 > 1)) break; + u3 = ec(l2 | 0, n2 | 0, -2, 0) | 0; + a[ta3 >> 0] = a[q2 + (u3 & v3) >> 0] | 0; + } + while (0); + c[S3 >> 2] = 0; + c[Y3 >> 2] = 0; + c[va3 >> 2] = c[wa3 >> 2]; + c[va3 + 4 >> 2] = c[wa3 + 4 >> 2]; + c[va3 + 8 >> 2] = c[wa3 + 8 >> 2]; + c[va3 + 12 >> 2] = c[wa3 + 12 >> 2]; + c[A3 >> 2] = m3; + c[z3 >> 2] = (c[$a3 >> 2] | 0) >>> 3; + } else ab3 = 114; + } + while (0); + do + if ((ab3 | 0) == 114) { + c[db2 >> 2] = d[y3 >> 0]; + if (!((n2 | 0) == (p2 | 0) & (o2 | 0) == (q2 | 0) ^ 1 | t3 ^ 1)) { + c[z3 >> 2] = 0; + break; + } + m3 = (s2 << 1) + 502 | 0; + l2 = c[K3 >> 2] | 0; + if ((c[J3 >> 2] | 0) >>> 0 < m3 >>> 0) { + ra2[c[L3 >> 2] & 1](c[M2 >> 2] | 0, l2); + c[K3 >> 2] = 0; + l2 = sa2[c[B3 >> 2] & 1](c[M2 >> 2] | 0, m3) | 0; + if (!l2) { + ab3 = 118; + break d; + } + c[K3 >> 2] = l2; + c[J3 >> 2] = m3; + n2 = l2; + } else n2 = l2; + a[n2 >> 0] = a[N3 >> 0] | 0; + o2 = Cb(e2, c[cb2 >> 2] | 0, s2, eb2) | 0; + l2 = u3 + (r2 & v3) | 0; + m3 = w2 << 24 >> 24 != 0; + if (!(c[cb2 >> 2] | 0)) ub(B3, l2, s2, m3, o2, c[eb2 >> 2] | 0, O3, P3, Q3, R3, db2, n2); + else yb(B3, l2, s2, m3, c[G3 >> 2] | 0, c[I3 >> 2] | 0, o2, c[eb2 >> 2] | 0, db2, n2); + a[N3 >> 0] = a[n2 + ((c[db2 >> 2] | 0) >>> 3) >> 0] | 0; + a[y3 >> 0] = c[db2 >> 2] & 7; + u3 = Xa3; + v3 = c[u3 + 4 >> 2] | 0; + ab3 = Ya2; + c[ab3 >> 2] = c[u3 >> 2]; + c[ab3 + 4 >> 2] = v3; + c[A3 >> 2] = n2; + c[z3 >> 2] = (c[db2 >> 2] | 0) >>> 3; + } + while (0); + if (!(w2 << 24 >> 24)) continue; + c[bb3 >> 2] = 2; + } + switch (ab3 | 0) { + case 62: { + oa2(1); + break; + } + case 71: { + oa2(1); + break; + } + case 108: { + oa2(1); + break; + } + case 110: { + oa2(1); + break; + } + case 118: { + oa2(1); + break; + } + case 127: { + oa2(1); + break; + } + case 194: { + pa2(406017, 406053, 906, 406080); + break; + } + case 196: { + pa2(406103, 406053, 907, 406080); + break; + } + case 198: { + pa2(406149, 406053, 908, 406080); + break; + } + case 202: { + oa2(1); + break; + } + case 231: { + k2 = 0; + i = fb2; + return k2 | 0; + } + case 234: { + if (n2 ^ 1 | o2 ^ 1) { + k2 = 1; + i = fb2; + return k2 | 0; + } + c[bb3 >> 2] = 0; + c[A3 >> 2] = 0; + k2 = 1; + i = fb2; + return k2 | 0; + } + } + return 0; + } + function Bb(b3) { + b3 = b3 | 0; + var d2 = 0, e2 = 0, f2 = 0, g3 = 0, h2 = 0, i2 = 0, j2 = 0, k2 = 0; + k2 = b3 + 5237 | 0; + if (a[k2 >> 0] & 1) return 1; + e2 = c[b3 + 4 >> 2] | 0; + if ((e2 | 0) >= 0) if ((e2 | 0) > 11) h2 = 11; + else i2 = 4; + else { + e2 = 0; + i2 = 4; + } + if ((i2 | 0) == 4) h2 = e2; + c[b3 + 4 >> 2] = h2; + e2 = b3 + 8 | 0; + f2 = c[e2 >> 2] | 0; + if ((f2 | 0) >= 10) { + if ((f2 | 0) > 24) { + c[e2 >> 2] = 24; + f2 = 24; + } + } else { + c[e2 >> 2] = 10; + f2 = 10; + } + g3 = b3 + 12 | 0; + e2 = c[g3 >> 2] | 0; + i2 = (h2 | 0) == 0; + do + if (h2 >>> 0 >= 2) if ((h2 | 0) < 4) e2 = 14; + else { + if (!e2) { + if (!((h2 | 0) > 8 & (f2 | 0) > 16)) { + e2 = 16; + break; + } + e2 = (f2 | 0) > 18 ? 18 : f2; + break; + } + if ((e2 | 0) >= 16) { + if ((e2 | 0) > 24) { + e2 = 24; + break; + } + } else e2 = 16; + } + else e2 = f2; + while (0); + c[g3 >> 2] = e2; + g3 = 1 << ((f2 | 0) > (e2 | 0) ? f2 : e2) + 1; + c[b3 + 88 >> 2] = g3; + c[b3 + 92 >> 2] = g3 + -1; + e2 = 1 << e2; + c[b3 + 96 >> 2] = e2; + c[b3 + 100 >> 2] = g3 + e2; + e2 = b3 + 192 | 0; + g3 = b3 + 193 | 0; + a: do + switch (f2 | 0) { + case 16: { + a[e2 >> 0] = 0; + a[g3 >> 0] = 1; + break; + } + case 17: { + a[e2 >> 0] = 1; + a[g3 >> 0] = 7; + break; + } + default: + if ((f2 | 0) > 17) { + a[e2 >> 0] = (f2 << 1) + 222 | 1; + a[g3 >> 0] = 4; + break a; + } else { + a[e2 >> 0] = (f2 << 4) + 128 | 1; + a[g3 >> 0] = 7; + break a; + } + } + while (0); + b: do + if (i2) { + g3 = b3 + 4436 | 0; + h2 = b3 + 4692 | 0; + i2 = b3 + 5204 | 0; + d2 = b3 + 4308 | 0; + e2 = 406473; + f2 = d2 + 128 | 0; + do { + a[d2 >> 0] = a[e2 >> 0] | 0; + d2 = d2 + 1 | 0; + e2 = e2 + 1 | 0; + } while ((d2 | 0) < (f2 | 0)); + dc(g3 | 0, 88174, 256) | 0; + d2 = h2; + e2 = 406601; + f2 = d2 + 57 | 0; + do { + a[d2 >> 0] = a[e2 >> 0] | 0; + d2 = d2 + 1 | 0; + e2 = e2 + 1 | 0; + } while ((d2 | 0) < (f2 | 0)); + c[i2 >> 2] = 448; + } else { + e2 = b3 + 16 | 0; + g3 = b3 + 28 | 0; + c: do + if ((h2 | 0) > 9) { + f2 = g3; + i2 = 65; + } else { + do + if ((h2 | 0) >= 5 & (f2 | 0) < 17) if ((h2 | 0) < 7) { + f2 = g3; + i2 = 56; + break; + } else { + h2 = (h2 | 0) < 9 ? 41 : 42; + i2 = 31; + break; + } + else i2 = 31; + while (0); + d: do + if ((i2 | 0) == 31) { + f2 = g3; + e: do + switch (h2 | 0) { + case 10: { + i2 = 65; + break c; + } + case 40: { + i2 = 56; + break d; + } + case 2: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 262160) | 0; + if (!d2) oa2(1); + else { + c[g3 >> 2] = d2; + d2 = f2; + i2 = 69; + break e; + } + break; + } + case 3: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 262164) | 0; + if (!d2) oa2(1); + else { + c[b3 + 32 >> 2] = d2; + d2 = f2; + i2 = 70; + break e; + } + break; + } + case 4: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 524316) | 0; + if (!d2) oa2(1); + else { + c[b3 + 36 >> 2] = d2; + d2 = f2; + i2 = 71; + break e; + } + break; + } + case 5: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 1081356) | 0; + if (!d2) oa2(1); + else { + c[b3 + 40 >> 2] = d2; + d2 = f2; + i2 = 72; + break e; + } + break; + } + case 6: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 2129932) | 0; + if (!d2) oa2(1); + else { + c[b3 + 44 >> 2] = d2; + d2 = f2; + i2 = 73; + break e; + } + break; + } + case 7: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 8454156) | 0; + if (!d2) oa2(1); + else { + c[b3 + 48 >> 2] = d2; + d2 = f2; + i2 = 74; + break e; + } + break; + } + case 8: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 16842764) | 0; + if (!d2) oa2(1); + else { + c[b3 + 52 >> 2] = d2; + d2 = f2; + i2 = 75; + break e; + } + break; + } + case 9: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 33619980) | 0; + if (!d2) oa2(1); + else { + c[b3 + 56 >> 2] = d2; + d2 = f2; + i2 = 76; + break e; + } + break; + } + case 41: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 524304) | 0; + if (!d2) oa2(1); + else { + c[b3 + 64 >> 2] = d2; + d2 = f2; + i2 = 78; + break e; + } + break; + } + case 42: { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 1311760) | 0; + if (!d2) oa2(1); + else { + c[b3 + 68 >> 2] = d2; + d2 = f2; + i2 = 79; + break e; + } + break; + } + default: { + d2 = f2; + switch (h2 | 0) { + case 10: + break c; + case 40: { + j2 = d2; + break d; + } + case 2: { + i2 = 69; + break; + } + case 3: { + i2 = 70; + break; + } + case 4: { + i2 = 71; + break; + } + case 5: { + i2 = 72; + break; + } + case 6: { + i2 = 73; + break; + } + case 7: { + i2 = 74; + break; + } + case 8: { + i2 = 75; + break; + } + case 9: { + i2 = 76; + break; + } + case 41: { + i2 = 78; + break; + } + case 42: { + i2 = 79; + break; + } + default: + break b; + } + } + } + while (0); + switch (i2 | 0) { + case 69: { + b3 = c[d2 >> 2] | 0; + a[b3 + 262148 >> 0] = 1; + c[b3 + 262152 >> 2] = 0; + c[b3 + 262156 >> 2] = 0; + break b; + } + case 70: { + b3 = c[d2 + 4 >> 2] | 0; + a[b3 + 262152 >> 0] = 1; + c[b3 + 262156 >> 2] = 0; + c[b3 + 262160 >> 2] = 0; + break b; + } + case 71: { + b3 = c[d2 + 8 >> 2] | 0; + a[b3 + 524304 >> 0] = 1; + c[b3 + 524308 >> 2] = 0; + c[b3 + 524312 >> 2] = 0; + break b; + } + case 72: { + b3 = c[d2 + 12 >> 2] | 0; + a[b3 + 1081344 >> 0] = 1; + c[b3 + 1081348 >> 2] = 0; + c[b3 + 1081352 >> 2] = 0; + break b; + } + case 73: { + b3 = c[d2 + 16 >> 2] | 0; + a[b3 + 2129920 >> 0] = 1; + c[b3 + 2129924 >> 2] = 0; + c[b3 + 2129928 >> 2] = 0; + break b; + } + case 74: { + b3 = c[d2 + 20 >> 2] | 0; + a[b3 + 8454144 >> 0] = 1; + c[b3 + 8454148 >> 2] = 0; + c[b3 + 8454152 >> 2] = 0; + break b; + } + case 75: { + b3 = c[d2 + 24 >> 2] | 0; + a[b3 + 16842752 >> 0] = 1; + c[b3 + 16842756 >> 2] = 0; + c[b3 + 16842760 >> 2] = 0; + break b; + } + case 76: { + b3 = c[d2 + 28 >> 2] | 0; + a[b3 + 33619968 >> 0] = 1; + c[b3 + 33619972 >> 2] = 0; + c[b3 + 33619976 >> 2] = 0; + break b; + } + case 78: { + b3 = c[d2 + 36 >> 2] | 0; + a[b3 + 524290 >> 0] = 1; + c[b3 + 524292 >> 2] = 0; + c[b3 + 524296 >> 2] = 0; + break b; + } + case 79: { + b3 = c[d2 + 40 >> 2] | 0; + a[b3 + 1311744 >> 0] = 1; + c[b3 + 1311748 >> 2] = 0; + c[b3 + 1311752 >> 2] = 0; + break b; + } + } + } + while (0); + do + if ((i2 | 0) == 56) { + d2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 524304) | 0; + if (!d2) oa2(1); + else { + c[b3 + 60 >> 2] = d2; + j2 = f2; + break; + } + } + while (0); + b3 = c[j2 + 32 >> 2] | 0; + a[b3 + 524290 >> 0] = 1; + c[b3 + 524292 >> 2] = 0; + c[b3 + 524296 >> 2] = 0; + break b; + } + while (0); + do + if ((i2 | 0) == 65) { + e2 = sa2[c[e2 >> 2] & 1](c[b3 + 24 >> 2] | 0, 524308) | 0; + if (!e2) oa2(1); + else { + c[f2 + 44 >> 2] = e2; + d2 = c[f2 + 44 >> 2] | 0; + c[d2 + 524292 >> 2] = 0; + c[d2 + 524300 >> 2] = 0; + a[d2 + 524304 >> 0] = 1; + d2 = f2; + break; + } + } + while (0); + a[(c[d2 + 44 >> 2] | 0) + 524304 >> 0] = 1; + } + while (0); + a[k2 >> 0] = 1; + return 1; + } + function Cb(a2, b3, d2, e2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + var f2 = 0, g3 = 0; + b3 = (b3 | 0) == 0 ? 32768 : 131072; + f2 = 256; + while (1) { + if (!(f2 >>> 0 < b3 >>> 0 & f2 >>> 0 < d2 >>> 0)) break; + f2 = f2 << 1; + } + do + if (f2 >>> 0 >= 1025) { + b3 = a2 + 4304 | 0; + if (f2 >>> 0 <= (c[b3 >> 2] | 0) >>> 0) { + g3 = c[a2 + 4300 >> 2] | 0; + break; + } + c[b3 >> 2] = f2; + d2 = a2 + 4300 | 0; + b3 = a2 + 24 | 0; + ra2[c[a2 + 20 >> 2] & 1](c[b3 >> 2] | 0, c[d2 >> 2] | 0); + c[d2 >> 2] = 0; + a2 = sa2[c[a2 + 16 >> 2] & 1](c[b3 >> 2] | 0, f2 << 2) | 0; + b3 = a2; + if (!a2) oa2(1); + else { + c[d2 >> 2] = b3; + g3 = b3; + break; + } + } else g3 = a2 + 204 | 0; + while (0); + c[e2 >> 2] = f2; + ac(g3 | 0, 0, f2 << 2 | 0) | 0; + return g3 | 0; + } + function Pa2(f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2, s2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0, Ha3 = 0, Ia3 = 0; + qa3 = i; + i = i + 32 | 0; + oa3 = qa3 + 16 | 0; + pa3 = qa3; + ma3 = (1 << c[m3 + 8 >> 2]) + -16 | 0; + v3 = c[p2 >> 2] | 0; + na2 = h2 + g3 | 0; + la3 = g3 >>> 0 > 3 ? na2 + -3 | 0 : h2; + ka3 = m3 + 4 | 0; + ja3 = (c[ka3 >> 2] | 0) < 9 ? 64 : 512; + u3 = ja3 + h2 | 0; + if ((((h2 | 0) == 0 ^ 1 | j2 ^ 1) ^ 1) & g3 >>> 0 < 513) { + f2 = 0; + while (1) { + if ((f2 | 0) == (g3 | 0)) break; + ia3 = k2 + f2 | 0; + b2[n2 + ((_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 17 << 1) >> 1] = 0; + f2 = f2 + 1 | 0; + } + if (g3) { + a[n2 + 16842752 >> 0] = 0; + t3 = 8; + } + } else { + f2 = n2 + 16842752 | 0; + if (!(a[f2 >> 0] & 1)) t3 = 8; + else { + ac(n2 | 0, 0, 65536) | 0; + a[f2 >> 0] = 0; + t3 = 8; + } + } + if ((t3 | 0) == 8 ? g3 >>> 0 > 2 & h2 >>> 0 > 2 : 0) { + ga3 = h2 + -3 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 65536 + ((e[ia3 >> 1] & 127 | ha3 << 7) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + ia3 = h2 + -2 | 0; + ha3 = k2 + (ia3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ga3 = n2 + (ha3 << 1) | 0; + c[n2 + 65536 + ((e[ga3 >> 1] & 127 | ha3 << 7) << 2) >> 2] = ia3; + b2[ga3 >> 1] = (b2[ga3 >> 1] | 0) + 1 << 16 >> 16; + ga3 = h2 + -1 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 65536 + ((e[ia3 >> 1] & 127 | ha3 << 7) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + } + P3 = oa3 + 4 | 0; + Q3 = oa3 + 8 | 0; + R3 = oa3 + 12 | 0; + S3 = oa3 + 4 | 0; + T3 = oa3 + 8 | 0; + U3 = oa3 + 12 | 0; + V3 = n2 + 16842760 | 0; + W3 = n2 + 16842756 | 0; + X3 = ja3 << 2; + Y3 = na2 + -4 | 0; + Z3 = na2 + -3 | 0; + $2 = pa3 + 12 | 0; + ba2 = pa3 + 4 | 0; + ca3 = pa3 + 8 | 0; + da3 = pa3 + 4 | 0; + ea3 = pa3 + 8 | 0; + fa3 = pa3 + 12 | 0; + ga3 = o2 + 8 | 0; + ha3 = o2 + 12 | 0; + ia3 = o2 + 4 | 0; + m3 = h2; + O3 = q2; + f2 = v3; + a: while (1) { + M2 = O3; + N3 = u3 + X3 | 0; + b: while (1) { + L3 = na2 - m3 | 0; + if ((m3 + 4 | 0) >>> 0 >= na2 >>> 0) break a; + J3 = m3 >>> 0 < ma3 >>> 0 ? m3 : ma3; + c[oa3 >> 2] = 0; + c[P3 >> 2] = 0; + c[Q3 >> 2] = 0; + c[R3 >> 2] = 4240; + K3 = m3 & l2; + g3 = c[oa3 >> 2] | 0; + c[oa3 >> 2] = 0; + c[S3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + y3 = 4240; + j2 = 0; + x3 = 0; + while (1) { + if ((x3 | 0) == 10) break; + w2 = (c[o2 + (c[11372 + (x3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (x3 << 2) >> 2] | 0) | 0; + t3 = m3 - w2 | 0; + do + if (((!(t3 >>> 0 >= m3 >>> 0 | w2 >>> 0 > J3 >>> 0) ? (ra3 = t3 & l2, sa3 = K3 + g3 | 0, sa3 >>> 0 <= l2 >>> 0) : 0) ? (ta3 = ra3 + g3 | 0, ta3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + sa3 >> 0] | 0) == (a[k2 + ta3 >> 0] | 0) : 0) { + v3 = 0; + t3 = F3; + while (1) { + h2 = t3; + if (h2 >>> 0 > H3 >>> 0) break; + D3 = t3; + E3 = k2 + (ra3 + v3) | 0; + if ((d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0) != (d[E3 >> 0] | d[E3 + 1 >> 0] << 8 | d[E3 + 2 >> 0] << 16 | d[E3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + t3 = h2 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (ra3 + v3) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (v3 >>> 0 <= 2 ? !((v3 | 0) == 2 & x3 >>> 0 < 2) : 0) { + t3 = y3; + break; + } + t3 = (v3 * 540 | 0) + (c[11500 + (x3 << 2) >> 2] | 0) | 0; + if (y3 >>> 0 < t3 >>> 0) { + c[oa3 >> 2] = v3; + c[T3 >> 2] = w2; + c[U3 >> 2] = t3; + g3 = v3; + j2 = 1; + } else t3 = y3; + } else t3 = y3; + while (0); + y3 = t3; + x3 = x3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + C3 = D3 << 7; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + t3 = E3 & 65535; + E3 = (E3 & 65535) > 128 ? t3 + -128 | 0 : 0; + c: while (1) { + B3 = K3 + g3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (t3 >>> 0 <= E3 >>> 0) break c; + t3 = t3 + -1 | 0; + h2 = c[n2 + 65536 + ((C3 | t3 & 127) << 2) >> 2] | 0; + z3 = m3 - h2 | 0; + if (z3 >>> 0 > J3 >>> 0) break c; + x3 = h2 & l2; + if (A3) continue; + h2 = x3 + g3 | 0; + if (h2 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + h2 >> 0] | 0)) { + w2 = 0; + h2 = F3; + } else continue; + while (1) { + v3 = h2; + if (v3 >>> 0 > H3 >>> 0) break; + Ia3 = h2; + Ha3 = k2 + (x3 + w2) | 0; + if ((d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0) != (d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0)) break; + w2 = w2 + 4 | 0; + h2 = v3 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (x3 + w2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + w2 = w2 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (w2 >>> 0 <= 3) continue; + h2 = (w2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (y3 >>> 0 < h2 >>> 0) break; + } + c[oa3 >> 2] = w2; + c[T3 >> 2] = z3; + c[U3 >> 2] = h2; + g3 = w2; + y3 = h2; + j2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 65536 + ((C3 | Ia3 & 127) << 2) >> 2] = m3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(j2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) j2 = 0; + else { + x3 = 0; + j2 = 0; + w2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((x3 | 0) == 2) break; + Ia3 = b2[21084 + (w2 << 1) >> 1] | 0; + t3 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (ua3 = t3 & 31, va3 = t3 >>> 5, wa3 = (c[11272 + (ua3 << 2) >> 2] | 0) + (_(ua3, va3) | 0) | 0, ua3 >>> 0 <= L3 >>> 0) : 0) { + g3 = wa3 + ua3 | 0; + v3 = 280811 + g3 | 0; + g3 = 280811 + (g3 + -4) | 0; + h2 = 0; + t3 = 280811 + wa3 | 0; + while (1) { + if (t3 >>> 0 > g3 >>> 0) break; + Ia3 = k2 + (K3 + h2) | 0; + if ((d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + t3 = t3 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= v3 >>> 0) break; + if ((a[k2 + (K3 + h2) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (!((h2 + 10 | 0) >>> 0 <= ua3 >>> 0 | (h2 | 0) == 0) ? (xa3 = J3 + va3 + 1 + (d[407930 + (ua3 - h2) >> 0] << d[280786 + ua3 >> 0]) | 0, ya3 = (h2 * 540 | 0) + 3840 + (_((aa(xa3 | 0) | 0) ^ 31, -120) | 0) | 0, ya3 >>> 0 >= (c[U3 >> 2] | 0) >>> 0) : 0) { + c[oa3 >> 2] = h2; + c[S3 >> 2] = ua3 ^ h2; + c[T3 >> 2] = xa3; + c[U3 >> 2] = ya3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + j2 = 1; + } + } + x3 = x3 + 1 | 0; + w2 = w2 + 1 | 0; + } + j2 = (j2 & 1) != 0; + } + j2 = j2 & 1; + } + if (j2 & 1) { + M2 = 0; + x3 = f2; + break; + } + f2 = f2 + 1 | 0; + t3 = m3 + 1 | 0; + if (t3 >>> 0 <= u3 >>> 0) { + m3 = t3; + continue; + } + if (t3 >>> 0 > N3 >>> 0) { + j2 = m3 + 17 | 0; + j2 = j2 >>> 0 < Y3 >>> 0 ? j2 : Y3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 65536 + ((e[Ia3 >> 1] & 127 | Ha3 << 7) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 4 | 0; + f2 = f2 + 4 | 0; + } + } else { + j2 = m3 + 9 | 0; + j2 = j2 >>> 0 < Z3 >>> 0 ? j2 : Z3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 65536 + ((e[Ia3 >> 1] & 127 | Ha3 << 7) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 2 | 0; + f2 = f2 + 2 | 0; + } + } + } + while (1) { + L3 = L3 + -1 | 0; + if ((c[ka3 >> 2] | 0) < 5) { + f2 = (c[oa3 >> 2] | 0) + -1 | 0; + f2 = f2 >>> 0 < L3 >>> 0 ? f2 : L3; + } else f2 = 0; + c[pa3 >> 2] = f2; + c[ba2 >> 2] = 0; + c[ca3 >> 2] = 0; + c[$2 >> 2] = 4240; + y3 = m3 + 1 | 0; + J3 = y3 >>> 0 < ma3 >>> 0 ? y3 : ma3; + K3 = y3 & l2; + t3 = c[pa3 >> 2] | 0; + c[pa3 >> 2] = 0; + c[da3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + w2 = 4240; + f2 = 0; + v3 = 0; + while (1) { + if ((v3 | 0) == 10) break; + h2 = (c[o2 + (c[11372 + (v3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (v3 << 2) >> 2] | 0) | 0; + j2 = y3 - h2 | 0; + do + if (((!(j2 >>> 0 >= y3 >>> 0 | h2 >>> 0 > J3 >>> 0) ? (za3 = j2 & l2, Aa3 = K3 + t3 | 0, Aa3 >>> 0 <= l2 >>> 0) : 0) ? (Ba3 = za3 + t3 | 0, Ba3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + Aa3 >> 0] | 0) == (a[k2 + Ba3 >> 0] | 0) : 0) { + u3 = 0; + j2 = F3; + while (1) { + g3 = j2; + if (g3 >>> 0 > H3 >>> 0) break; + Ha3 = j2; + Ia3 = k2 + (za3 + u3) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + u3 = u3 + 4 | 0; + j2 = g3 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (za3 + u3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + u3 = u3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (u3 >>> 0 <= 2 ? !((u3 | 0) == 2 & v3 >>> 0 < 2) : 0) { + j2 = w2; + break; + } + j2 = (u3 * 540 | 0) + (c[11500 + (v3 << 2) >> 2] | 0) | 0; + if (w2 >>> 0 < j2 >>> 0) { + c[pa3 >> 2] = u3; + c[ea3 >> 2] = h2; + c[fa3 >> 2] = j2; + t3 = u3; + f2 = 1; + } else j2 = w2; + } else j2 = w2; + while (0); + w2 = j2; + v3 = v3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + C3 = D3 << 7; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + j2 = E3 & 65535; + E3 = (E3 & 65535) > 128 ? j2 + -128 | 0 : 0; + d: while (1) { + B3 = K3 + t3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (j2 >>> 0 <= E3 >>> 0) break d; + j2 = j2 + -1 | 0; + g3 = c[n2 + 65536 + ((C3 | j2 & 127) << 2) >> 2] | 0; + z3 = y3 - g3 | 0; + if (z3 >>> 0 > J3 >>> 0) break d; + v3 = g3 & l2; + if (A3) continue; + g3 = v3 + t3 | 0; + if (g3 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + g3 >> 0] | 0)) { + h2 = 0; + g3 = F3; + } else continue; + while (1) { + u3 = g3; + if (u3 >>> 0 > H3 >>> 0) break; + Ha3 = g3; + Ia3 = k2 + (v3 + h2) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + g3 = u3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (v3 + h2) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (h2 >>> 0 <= 3) continue; + g3 = (h2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (w2 >>> 0 < g3 >>> 0) break; + } + c[pa3 >> 2] = h2; + c[ea3 >> 2] = z3; + c[fa3 >> 2] = g3; + t3 = h2; + w2 = g3; + f2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 65536 + ((C3 | Ia3 & 127) << 2) >> 2] = y3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(f2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) f2 = 0; + else { + v3 = 0; + f2 = 0; + h2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 2) break; + Ia3 = b2[21084 + (h2 << 1) >> 1] | 0; + j2 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (Ca3 = j2 & 31, Da3 = j2 >>> 5, Ea3 = (c[11272 + (Ca3 << 2) >> 2] | 0) + (_(Ca3, Da3) | 0) | 0, Ca3 >>> 0 <= L3 >>> 0) : 0) { + t3 = Ea3 + Ca3 | 0; + u3 = 280811 + t3 | 0; + t3 = 280811 + (t3 + -4) | 0; + g3 = 0; + j2 = 280811 + Ea3 | 0; + while (1) { + if (j2 >>> 0 > t3 >>> 0) break; + Ia3 = k2 + (K3 + g3) | 0; + if ((d[j2 >> 0] | d[j2 + 1 >> 0] << 8 | d[j2 + 2 >> 0] << 16 | d[j2 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + j2 = j2 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= u3 >>> 0) break; + if ((a[k2 + (K3 + g3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (!((g3 + 10 | 0) >>> 0 <= Ca3 >>> 0 | (g3 | 0) == 0) ? (Fa3 = J3 + Da3 + 1 + (d[407930 + (Ca3 - g3) >> 0] << d[280786 + Ca3 >> 0]) | 0, Ga3 = (g3 * 540 | 0) + 3840 + (_((aa(Fa3 | 0) | 0) ^ 31, -120) | 0) | 0, Ga3 >>> 0 >= (c[fa3 >> 2] | 0) >>> 0) : 0) { + c[pa3 >> 2] = g3; + c[da3 >> 2] = Ca3 ^ g3; + c[ea3 >> 2] = Fa3; + c[fa3 >> 2] = Ga3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + f2 = 1; + } + } + v3 = v3 + 1 | 0; + h2 = h2 + 1 | 0; + } + f2 = (f2 & 1) != 0; + } + f2 = f2 & 1; + } + if (!(f2 & 1)) { + y3 = m3; + break; + } + if ((c[$2 >> 2] | 0) >>> 0 < ((c[R3 >> 2] | 0) + 700 | 0) >>> 0) { + y3 = m3; + break; + } + f2 = x3 + 1 | 0; + c[oa3 >> 2] = c[pa3 >> 2]; + c[oa3 + 4 >> 2] = c[pa3 + 4 >> 2]; + c[oa3 + 8 >> 2] = c[pa3 + 8 >> 2]; + c[oa3 + 12 >> 2] = c[pa3 + 12 >> 2]; + M2 = M2 + 1 | 0; + if (!((M2 | 0) < 4 & (m3 + 5 | 0) >>> 0 < na2 >>> 0)) { + x3 = f2; + break; + } else { + m3 = y3; + x3 = f2; + } + } + m3 = c[oa3 >> 2] | 0; + u3 = y3 + (m3 << 1) + ja3 | 0; + f2 = c[Q3 >> 2] | 0; + e: do + if (f2 >>> 0 <= (y3 >>> 0 < ma3 >>> 0 ? y3 : ma3) >>> 0) { + g3 = f2 + 3 | 0; + Ia3 = c[o2 >> 2] | 0; + j2 = g3 - Ia3 | 0; + t3 = c[ia3 >> 2] | 0; + g3 = g3 - t3 | 0; + if ((f2 | 0) == (Ia3 | 0)) f2 = 0; + else { + f: do + if ((f2 | 0) != (t3 | 0)) { + do + if (j2 >>> 0 < 7) f2 = 158663784 >>> (j2 << 2) & 15; + else { + if (g3 >>> 0 < 7) { + f2 = 266017486 >>> (g3 << 2) & 15; + break; + } + if ((f2 | 0) == (c[ga3 >> 2] | 0)) { + f2 = 2; + break f; + } + if ((f2 | 0) == (c[ha3 >> 2] | 0)) { + f2 = 3; + break f; + } + f2 = f2 + 15 | 0; + } + while (0); + if (!f2) break e; + } else f2 = 1; + while (0); + c[ha3 >> 2] = c[ga3 >> 2]; + c[ga3 >> 2] = c[ia3 >> 2]; + c[ia3 >> 2] = c[o2 >> 2]; + c[o2 >> 2] = c[Q3 >> 2]; + m3 = c[oa3 >> 2] | 0; + } + } else f2 = f2 + 15 | 0; + while (0); + w2 = O3 + 16 | 0; + Ia3 = c[P3 >> 2] | 0; + j2 = m3 ^ Ia3; + c[O3 >> 2] = x3; + c[O3 + 4 >> 2] = m3 | Ia3 << 24; + m3 = O3 + 14 | 0; + if (f2 >>> 0 < 16) { + f2 = f2 & 65535; + b2[m3 >> 1] = f2; + m3 = 0; + } else { + N3 = f2 + -12 | 0; + Ia3 = ((aa(N3 | 0) | 0) ^ 31) + -1 | 0; + Ha3 = N3 >>> Ia3 & 1; + f2 = ((Ia3 << 1) + 65534 | Ha3) + 16 & 65535; + b2[m3 >> 1] = f2; + m3 = Ia3 << 24 | N3 - ((Ha3 | 2) << Ia3); + } + c[O3 + 8 >> 2] = m3; + h2 = f2 << 16 >> 16 == 0; + v3 = O3 + 12 | 0; + do + if (x3 >>> 0 >= 6) { + if (x3 >>> 0 < 130) { + Ia3 = x3 + -2 | 0; + g3 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + g3 = (g3 << 1) + (Ia3 >>> g3) + 2 & 65535; + break; + } + if (x3 >>> 0 < 2114) { + g3 = ((aa(x3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (x3 >>> 0 < 6210) g3 = 21; + else g3 = x3 >>> 0 < 22594 ? 22 : 23; + } else g3 = x3 & 65535; + while (0); + do + if (j2 >>> 0 >= 10) { + if (j2 >>> 0 < 134) { + Ia3 = j2 + -6 | 0; + f2 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + f2 = (f2 << 1) + (Ia3 >>> f2) + 4 & 65535; + break; + } + if (j2 >>> 0 < 2118) f2 = ((aa(j2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else f2 = 23; + } else f2 = j2 + 65534 & 65535; + while (0); + m3 = f2 & 65535; + j2 = g3 & 65535; + t3 = m3 & 7 | j2 << 3 & 56; + if (h2 & (g3 & 65535) < 8 & (f2 & 65535) < 16) f2 = ((f2 & 65535) < 8 ? t3 : t3 | 64) & 65535; + else f2 = b2[88156 + ((m3 >>> 3) + ((j2 >>> 3) * 3 | 0) << 1) >> 1] | t3 & 65535; + b2[v3 >> 1] = f2; + c[s2 >> 2] = (c[s2 >> 2] | 0) + x3; + f2 = y3 + (c[oa3 >> 2] | 0) | 0; + f2 = f2 >>> 0 < la3 >>> 0 ? f2 : la3; + m3 = y3 + 2 | 0; + while (1) { + if (m3 >>> 0 >= f2 >>> 0) break; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 65536 + ((e[Ia3 >> 1] & 127 | Ha3 << 7) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 1 | 0; + } + m3 = y3 + (c[oa3 >> 2] | 0) | 0; + O3 = w2; + f2 = 0; + } + c[p2 >> 2] = f2 + L3; + c[r2 >> 2] = (c[r2 >> 2] | 0) + (M2 - q2 >> 4); + i = qa3; + return; + } + function Qa2(f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2, s2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0, Ha3 = 0, Ia3 = 0; + qa3 = i; + i = i + 32 | 0; + oa3 = qa3 + 16 | 0; + pa3 = qa3; + ma3 = (1 << c[m3 + 8 >> 2]) + -16 | 0; + v3 = c[p2 >> 2] | 0; + na2 = h2 + g3 | 0; + la3 = g3 >>> 0 > 3 ? na2 + -3 | 0 : h2; + ka3 = m3 + 4 | 0; + ja3 = (c[ka3 >> 2] | 0) < 9 ? 64 : 512; + u3 = ja3 + h2 | 0; + if ((((h2 | 0) == 0 ^ 1 | j2 ^ 1) ^ 1) & g3 >>> 0 < 513) { + f2 = 0; + while (1) { + if ((f2 | 0) == (g3 | 0)) break; + ia3 = k2 + f2 | 0; + b2[n2 + ((_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 17 << 1) >> 1] = 0; + f2 = f2 + 1 | 0; + } + if (g3) { + a[n2 + 33619968 >> 0] = 0; + t3 = 8; + } + } else { + f2 = n2 + 33619968 | 0; + if (!(a[f2 >> 0] & 1)) t3 = 8; + else { + ac(n2 | 0, 0, 65536) | 0; + a[f2 >> 0] = 0; + t3 = 8; + } + } + if ((t3 | 0) == 8 ? g3 >>> 0 > 2 & h2 >>> 0 > 2 : 0) { + ga3 = h2 + -3 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 65536 + ((e[ia3 >> 1] & 255 | ha3 << 8) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + ia3 = h2 + -2 | 0; + ha3 = k2 + (ia3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ga3 = n2 + (ha3 << 1) | 0; + c[n2 + 65536 + ((e[ga3 >> 1] & 255 | ha3 << 8) << 2) >> 2] = ia3; + b2[ga3 >> 1] = (b2[ga3 >> 1] | 0) + 1 << 16 >> 16; + ga3 = h2 + -1 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 65536 + ((e[ia3 >> 1] & 255 | ha3 << 8) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + } + P3 = oa3 + 4 | 0; + Q3 = oa3 + 8 | 0; + R3 = oa3 + 12 | 0; + S3 = oa3 + 4 | 0; + T3 = oa3 + 8 | 0; + U3 = oa3 + 12 | 0; + V3 = n2 + 33619976 | 0; + W3 = n2 + 33619972 | 0; + X3 = ja3 << 2; + Y3 = na2 + -4 | 0; + Z3 = na2 + -3 | 0; + $2 = pa3 + 12 | 0; + ba2 = pa3 + 4 | 0; + ca3 = pa3 + 8 | 0; + da3 = pa3 + 4 | 0; + ea3 = pa3 + 8 | 0; + fa3 = pa3 + 12 | 0; + ga3 = o2 + 8 | 0; + ha3 = o2 + 12 | 0; + ia3 = o2 + 4 | 0; + m3 = h2; + O3 = q2; + f2 = v3; + a: while (1) { + M2 = O3; + N3 = u3 + X3 | 0; + b: while (1) { + L3 = na2 - m3 | 0; + if ((m3 + 4 | 0) >>> 0 >= na2 >>> 0) break a; + J3 = m3 >>> 0 < ma3 >>> 0 ? m3 : ma3; + c[oa3 >> 2] = 0; + c[P3 >> 2] = 0; + c[Q3 >> 2] = 0; + c[R3 >> 2] = 4240; + K3 = m3 & l2; + g3 = c[oa3 >> 2] | 0; + c[oa3 >> 2] = 0; + c[S3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + y3 = 4240; + j2 = 0; + x3 = 0; + while (1) { + if ((x3 | 0) == 16) break; + w2 = (c[o2 + (c[11372 + (x3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (x3 << 2) >> 2] | 0) | 0; + t3 = m3 - w2 | 0; + do + if (((!(t3 >>> 0 >= m3 >>> 0 | w2 >>> 0 > J3 >>> 0) ? (ra3 = t3 & l2, sa3 = K3 + g3 | 0, sa3 >>> 0 <= l2 >>> 0) : 0) ? (ta3 = ra3 + g3 | 0, ta3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + sa3 >> 0] | 0) == (a[k2 + ta3 >> 0] | 0) : 0) { + v3 = 0; + t3 = F3; + while (1) { + h2 = t3; + if (h2 >>> 0 > H3 >>> 0) break; + D3 = t3; + E3 = k2 + (ra3 + v3) | 0; + if ((d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0) != (d[E3 >> 0] | d[E3 + 1 >> 0] << 8 | d[E3 + 2 >> 0] << 16 | d[E3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + t3 = h2 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (ra3 + v3) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (v3 >>> 0 <= 2 ? !((v3 | 0) == 2 & x3 >>> 0 < 2) : 0) { + t3 = y3; + break; + } + t3 = (v3 * 540 | 0) + (c[11500 + (x3 << 2) >> 2] | 0) | 0; + if (y3 >>> 0 < t3 >>> 0) { + c[oa3 >> 2] = v3; + c[T3 >> 2] = w2; + c[U3 >> 2] = t3; + g3 = v3; + j2 = 1; + } else t3 = y3; + } else t3 = y3; + while (0); + y3 = t3; + x3 = x3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + C3 = D3 << 8; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + t3 = E3 & 65535; + E3 = (E3 & 65535) > 256 ? t3 + -256 | 0 : 0; + c: while (1) { + B3 = K3 + g3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (t3 >>> 0 <= E3 >>> 0) break c; + t3 = t3 + -1 | 0; + h2 = c[n2 + 65536 + ((C3 | t3 & 255) << 2) >> 2] | 0; + z3 = m3 - h2 | 0; + if (z3 >>> 0 > J3 >>> 0) break c; + x3 = h2 & l2; + if (A3) continue; + h2 = x3 + g3 | 0; + if (h2 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + h2 >> 0] | 0)) { + w2 = 0; + h2 = F3; + } else continue; + while (1) { + v3 = h2; + if (v3 >>> 0 > H3 >>> 0) break; + Ia3 = h2; + Ha3 = k2 + (x3 + w2) | 0; + if ((d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0) != (d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0)) break; + w2 = w2 + 4 | 0; + h2 = v3 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (x3 + w2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + w2 = w2 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (w2 >>> 0 <= 3) continue; + h2 = (w2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (y3 >>> 0 < h2 >>> 0) break; + } + c[oa3 >> 2] = w2; + c[T3 >> 2] = z3; + c[U3 >> 2] = h2; + g3 = w2; + y3 = h2; + j2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 65536 + ((C3 | Ia3 & 255) << 2) >> 2] = m3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(j2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) j2 = 0; + else { + x3 = 0; + j2 = 0; + w2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((x3 | 0) == 2) break; + Ia3 = b2[21084 + (w2 << 1) >> 1] | 0; + t3 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (ua3 = t3 & 31, va3 = t3 >>> 5, wa3 = (c[11272 + (ua3 << 2) >> 2] | 0) + (_(ua3, va3) | 0) | 0, ua3 >>> 0 <= L3 >>> 0) : 0) { + g3 = wa3 + ua3 | 0; + v3 = 280811 + g3 | 0; + g3 = 280811 + (g3 + -4) | 0; + h2 = 0; + t3 = 280811 + wa3 | 0; + while (1) { + if (t3 >>> 0 > g3 >>> 0) break; + Ia3 = k2 + (K3 + h2) | 0; + if ((d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + t3 = t3 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= v3 >>> 0) break; + if ((a[k2 + (K3 + h2) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (!((h2 + 10 | 0) >>> 0 <= ua3 >>> 0 | (h2 | 0) == 0) ? (xa3 = J3 + va3 + 1 + (d[407930 + (ua3 - h2) >> 0] << d[280786 + ua3 >> 0]) | 0, ya3 = (h2 * 540 | 0) + 3840 + (_((aa(xa3 | 0) | 0) ^ 31, -120) | 0) | 0, ya3 >>> 0 >= (c[U3 >> 2] | 0) >>> 0) : 0) { + c[oa3 >> 2] = h2; + c[S3 >> 2] = ua3 ^ h2; + c[T3 >> 2] = xa3; + c[U3 >> 2] = ya3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + j2 = 1; + } + } + x3 = x3 + 1 | 0; + w2 = w2 + 1 | 0; + } + j2 = (j2 & 1) != 0; + } + j2 = j2 & 1; + } + if (j2 & 1) { + M2 = 0; + x3 = f2; + break; + } + f2 = f2 + 1 | 0; + t3 = m3 + 1 | 0; + if (t3 >>> 0 <= u3 >>> 0) { + m3 = t3; + continue; + } + if (t3 >>> 0 > N3 >>> 0) { + j2 = m3 + 17 | 0; + j2 = j2 >>> 0 < Y3 >>> 0 ? j2 : Y3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 65536 + ((e[Ia3 >> 1] & 255 | Ha3 << 8) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 4 | 0; + f2 = f2 + 4 | 0; + } + } else { + j2 = m3 + 9 | 0; + j2 = j2 >>> 0 < Z3 >>> 0 ? j2 : Z3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 65536 + ((e[Ia3 >> 1] & 255 | Ha3 << 8) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 2 | 0; + f2 = f2 + 2 | 0; + } + } + } + while (1) { + L3 = L3 + -1 | 0; + if ((c[ka3 >> 2] | 0) < 5) { + f2 = (c[oa3 >> 2] | 0) + -1 | 0; + f2 = f2 >>> 0 < L3 >>> 0 ? f2 : L3; + } else f2 = 0; + c[pa3 >> 2] = f2; + c[ba2 >> 2] = 0; + c[ca3 >> 2] = 0; + c[$2 >> 2] = 4240; + y3 = m3 + 1 | 0; + J3 = y3 >>> 0 < ma3 >>> 0 ? y3 : ma3; + K3 = y3 & l2; + t3 = c[pa3 >> 2] | 0; + c[pa3 >> 2] = 0; + c[da3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + w2 = 4240; + f2 = 0; + v3 = 0; + while (1) { + if ((v3 | 0) == 16) break; + h2 = (c[o2 + (c[11372 + (v3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (v3 << 2) >> 2] | 0) | 0; + j2 = y3 - h2 | 0; + do + if (((!(j2 >>> 0 >= y3 >>> 0 | h2 >>> 0 > J3 >>> 0) ? (za3 = j2 & l2, Aa3 = K3 + t3 | 0, Aa3 >>> 0 <= l2 >>> 0) : 0) ? (Ba3 = za3 + t3 | 0, Ba3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + Aa3 >> 0] | 0) == (a[k2 + Ba3 >> 0] | 0) : 0) { + u3 = 0; + j2 = F3; + while (1) { + g3 = j2; + if (g3 >>> 0 > H3 >>> 0) break; + Ha3 = j2; + Ia3 = k2 + (za3 + u3) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + u3 = u3 + 4 | 0; + j2 = g3 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (za3 + u3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + u3 = u3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (u3 >>> 0 <= 2 ? !((u3 | 0) == 2 & v3 >>> 0 < 2) : 0) { + j2 = w2; + break; + } + j2 = (u3 * 540 | 0) + (c[11500 + (v3 << 2) >> 2] | 0) | 0; + if (w2 >>> 0 < j2 >>> 0) { + c[pa3 >> 2] = u3; + c[ea3 >> 2] = h2; + c[fa3 >> 2] = j2; + t3 = u3; + f2 = 1; + } else j2 = w2; + } else j2 = w2; + while (0); + w2 = j2; + v3 = v3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + C3 = D3 << 8; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + j2 = E3 & 65535; + E3 = (E3 & 65535) > 256 ? j2 + -256 | 0 : 0; + d: while (1) { + B3 = K3 + t3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (j2 >>> 0 <= E3 >>> 0) break d; + j2 = j2 + -1 | 0; + g3 = c[n2 + 65536 + ((C3 | j2 & 255) << 2) >> 2] | 0; + z3 = y3 - g3 | 0; + if (z3 >>> 0 > J3 >>> 0) break d; + v3 = g3 & l2; + if (A3) continue; + g3 = v3 + t3 | 0; + if (g3 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + g3 >> 0] | 0)) { + h2 = 0; + g3 = F3; + } else continue; + while (1) { + u3 = g3; + if (u3 >>> 0 > H3 >>> 0) break; + Ha3 = g3; + Ia3 = k2 + (v3 + h2) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + g3 = u3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (v3 + h2) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (h2 >>> 0 <= 3) continue; + g3 = (h2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (w2 >>> 0 < g3 >>> 0) break; + } + c[pa3 >> 2] = h2; + c[ea3 >> 2] = z3; + c[fa3 >> 2] = g3; + t3 = h2; + w2 = g3; + f2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 65536 + ((C3 | Ia3 & 255) << 2) >> 2] = y3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(f2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) f2 = 0; + else { + v3 = 0; + f2 = 0; + h2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 2) break; + Ia3 = b2[21084 + (h2 << 1) >> 1] | 0; + j2 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (Ca3 = j2 & 31, Da3 = j2 >>> 5, Ea3 = (c[11272 + (Ca3 << 2) >> 2] | 0) + (_(Ca3, Da3) | 0) | 0, Ca3 >>> 0 <= L3 >>> 0) : 0) { + t3 = Ea3 + Ca3 | 0; + u3 = 280811 + t3 | 0; + t3 = 280811 + (t3 + -4) | 0; + g3 = 0; + j2 = 280811 + Ea3 | 0; + while (1) { + if (j2 >>> 0 > t3 >>> 0) break; + Ia3 = k2 + (K3 + g3) | 0; + if ((d[j2 >> 0] | d[j2 + 1 >> 0] << 8 | d[j2 + 2 >> 0] << 16 | d[j2 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + j2 = j2 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= u3 >>> 0) break; + if ((a[k2 + (K3 + g3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (!((g3 + 10 | 0) >>> 0 <= Ca3 >>> 0 | (g3 | 0) == 0) ? (Fa3 = J3 + Da3 + 1 + (d[407930 + (Ca3 - g3) >> 0] << d[280786 + Ca3 >> 0]) | 0, Ga3 = (g3 * 540 | 0) + 3840 + (_((aa(Fa3 | 0) | 0) ^ 31, -120) | 0) | 0, Ga3 >>> 0 >= (c[fa3 >> 2] | 0) >>> 0) : 0) { + c[pa3 >> 2] = g3; + c[da3 >> 2] = Ca3 ^ g3; + c[ea3 >> 2] = Fa3; + c[fa3 >> 2] = Ga3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + f2 = 1; + } + } + v3 = v3 + 1 | 0; + h2 = h2 + 1 | 0; + } + f2 = (f2 & 1) != 0; + } + f2 = f2 & 1; + } + if (!(f2 & 1)) { + y3 = m3; + break; + } + if ((c[$2 >> 2] | 0) >>> 0 < ((c[R3 >> 2] | 0) + 700 | 0) >>> 0) { + y3 = m3; + break; + } + f2 = x3 + 1 | 0; + c[oa3 >> 2] = c[pa3 >> 2]; + c[oa3 + 4 >> 2] = c[pa3 + 4 >> 2]; + c[oa3 + 8 >> 2] = c[pa3 + 8 >> 2]; + c[oa3 + 12 >> 2] = c[pa3 + 12 >> 2]; + M2 = M2 + 1 | 0; + if (!((M2 | 0) < 4 & (m3 + 5 | 0) >>> 0 < na2 >>> 0)) { + x3 = f2; + break; + } else { + m3 = y3; + x3 = f2; + } + } + m3 = c[oa3 >> 2] | 0; + u3 = y3 + (m3 << 1) + ja3 | 0; + f2 = c[Q3 >> 2] | 0; + e: do + if (f2 >>> 0 <= (y3 >>> 0 < ma3 >>> 0 ? y3 : ma3) >>> 0) { + g3 = f2 + 3 | 0; + Ia3 = c[o2 >> 2] | 0; + j2 = g3 - Ia3 | 0; + t3 = c[ia3 >> 2] | 0; + g3 = g3 - t3 | 0; + if ((f2 | 0) == (Ia3 | 0)) f2 = 0; + else { + f: do + if ((f2 | 0) != (t3 | 0)) { + do + if (j2 >>> 0 < 7) f2 = 158663784 >>> (j2 << 2) & 15; + else { + if (g3 >>> 0 < 7) { + f2 = 266017486 >>> (g3 << 2) & 15; + break; + } + if ((f2 | 0) == (c[ga3 >> 2] | 0)) { + f2 = 2; + break f; + } + if ((f2 | 0) == (c[ha3 >> 2] | 0)) { + f2 = 3; + break f; + } + f2 = f2 + 15 | 0; + } + while (0); + if (!f2) break e; + } else f2 = 1; + while (0); + c[ha3 >> 2] = c[ga3 >> 2]; + c[ga3 >> 2] = c[ia3 >> 2]; + c[ia3 >> 2] = c[o2 >> 2]; + c[o2 >> 2] = c[Q3 >> 2]; + m3 = c[oa3 >> 2] | 0; + } + } else f2 = f2 + 15 | 0; + while (0); + w2 = O3 + 16 | 0; + Ia3 = c[P3 >> 2] | 0; + j2 = m3 ^ Ia3; + c[O3 >> 2] = x3; + c[O3 + 4 >> 2] = m3 | Ia3 << 24; + m3 = O3 + 14 | 0; + if (f2 >>> 0 < 16) { + f2 = f2 & 65535; + b2[m3 >> 1] = f2; + m3 = 0; + } else { + N3 = f2 + -12 | 0; + Ia3 = ((aa(N3 | 0) | 0) ^ 31) + -1 | 0; + Ha3 = N3 >>> Ia3 & 1; + f2 = ((Ia3 << 1) + 65534 | Ha3) + 16 & 65535; + b2[m3 >> 1] = f2; + m3 = Ia3 << 24 | N3 - ((Ha3 | 2) << Ia3); + } + c[O3 + 8 >> 2] = m3; + h2 = f2 << 16 >> 16 == 0; + v3 = O3 + 12 | 0; + do + if (x3 >>> 0 >= 6) { + if (x3 >>> 0 < 130) { + Ia3 = x3 + -2 | 0; + g3 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + g3 = (g3 << 1) + (Ia3 >>> g3) + 2 & 65535; + break; + } + if (x3 >>> 0 < 2114) { + g3 = ((aa(x3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (x3 >>> 0 < 6210) g3 = 21; + else g3 = x3 >>> 0 < 22594 ? 22 : 23; + } else g3 = x3 & 65535; + while (0); + do + if (j2 >>> 0 >= 10) { + if (j2 >>> 0 < 134) { + Ia3 = j2 + -6 | 0; + f2 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + f2 = (f2 << 1) + (Ia3 >>> f2) + 4 & 65535; + break; + } + if (j2 >>> 0 < 2118) f2 = ((aa(j2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else f2 = 23; + } else f2 = j2 + 65534 & 65535; + while (0); + m3 = f2 & 65535; + j2 = g3 & 65535; + t3 = m3 & 7 | j2 << 3 & 56; + if (h2 & (g3 & 65535) < 8 & (f2 & 65535) < 16) f2 = ((f2 & 65535) < 8 ? t3 : t3 | 64) & 65535; + else f2 = b2[88156 + ((m3 >>> 3) + ((j2 >>> 3) * 3 | 0) << 1) >> 1] | t3 & 65535; + b2[v3 >> 1] = f2; + c[s2 >> 2] = (c[s2 >> 2] | 0) + x3; + f2 = y3 + (c[oa3 >> 2] | 0) | 0; + f2 = f2 >>> 0 < la3 >>> 0 ? f2 : la3; + m3 = y3 + 2 | 0; + while (1) { + if (m3 >>> 0 >= f2 >>> 0) break; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 65536 + ((e[Ia3 >> 1] & 255 | Ha3 << 8) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 1 | 0; + } + m3 = y3 + (c[oa3 >> 2] | 0) | 0; + O3 = w2; + f2 = 0; + } + c[p2 >> 2] = f2 + L3; + c[r2 >> 2] = (c[r2 >> 2] | 0) + (M2 - q2 >> 4); + i = qa3; + return; + } + function Ra2(f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2, s2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0; + sa3 = i; + i = i + 32 | 0; + pa3 = sa3 + 16 | 0; + qa3 = sa3; + na2 = (1 << c[m3 + 8 >> 2]) + -16 | 0; + u3 = c[p2 >> 2] | 0; + oa3 = h2 + g3 | 0; + ma3 = g3 >>> 0 > 3 ? oa3 + -3 | 0 : h2; + la3 = m3 + 4 | 0; + ia3 = c[la3 >> 2] | 0; + ja3 = (ia3 | 0) < 9 ? 64 : 512; + t3 = ja3 + h2 | 0; + ka3 = n2 + 524300 | 0; + c[ka3 >> 2] = ((ia3 | 0) > 6 ? 7 : 8) << ia3 + -4; + if ((((h2 | 0) == 0 ^ 1 | j2 ^ 1) ^ 1) & g3 >>> 0 < 513) { + f2 = 0; + while (1) { + if ((f2 | 0) == (g3 | 0)) break; + ia3 = k2 + f2 | 0; + ia3 = (_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + c[n2 + (ia3 << 2) >> 2] = -858993460; + b2[n2 + 131072 + (ia3 << 1) >> 1] = -13108; + f2 = f2 + 1 | 0; + } + ac(n2 + 196608 | 0, 0, 65536) | 0; + b2[n2 + 524288 >> 1] = 0; + if (g3) { + a[n2 + 524290 >> 0] = 0; + ra3 = 8; + } + } else { + f2 = n2 + 524290 | 0; + if (!(a[f2 >> 0] & 1)) ra3 = 8; + else { + ac(n2 | 0, -52, 131072) | 0; + b2[n2 + 524288 >> 1] = 0; + a[f2 >> 0] = 0; + ac(n2 + 131072 | 0, 0, 131072) | 0; + ra3 = 8; + } + } + if ((ra3 | 0) == 8 ? g3 >>> 0 > 2 & h2 >>> 0 > 2 : 0) { + da3 = h2 + -3 | 0; + ga3 = k2 + (da3 & l2) | 0; + ga3 = (_(d[ga3 >> 0] | d[ga3 + 1 >> 0] << 8 | d[ga3 + 2 >> 0] << 16 | d[ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ea3 = n2 + 524288 | 0; + fa3 = b2[ea3 >> 1] | 0; + b2[ea3 >> 1] = fa3 + 1 << 16 >> 16; + ha3 = fa3 & 65535; + ia3 = n2 + (ga3 << 2) | 0; + ca3 = da3 - (c[ia3 >> 2] | 0) | 0; + a[(da3 & 65535) + (n2 + 196608) >> 0] = ga3; + b2[n2 + 262144 + (ha3 << 2) >> 1] = ca3 >>> 0 > 65535 ? 65535 : ca3; + ga3 = n2 + 131072 + (ga3 << 1) | 0; + b2[n2 + 262144 + (ha3 << 2) + 2 >> 1] = b2[ga3 >> 1] | 0; + c[ia3 >> 2] = da3; + b2[ga3 >> 1] = fa3; + ga3 = h2 + -2 | 0; + fa3 = k2 + (ga3 & l2) | 0; + fa3 = (_(d[fa3 >> 0] | d[fa3 + 1 >> 0] << 8 | d[fa3 + 2 >> 0] << 16 | d[fa3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ia3 = b2[ea3 >> 1] | 0; + b2[ea3 >> 1] = ia3 + 1 << 16 >> 16; + da3 = ia3 & 65535; + ha3 = n2 + (fa3 << 2) | 0; + ca3 = ga3 - (c[ha3 >> 2] | 0) | 0; + a[(ga3 & 65535) + (n2 + 196608) >> 0] = fa3; + b2[n2 + 262144 + (da3 << 2) >> 1] = ca3 >>> 0 > 65535 ? 65535 : ca3; + fa3 = n2 + 131072 + (fa3 << 1) | 0; + b2[n2 + 262144 + (da3 << 2) + 2 >> 1] = b2[fa3 >> 1] | 0; + c[ha3 >> 2] = ga3; + b2[fa3 >> 1] = ia3; + fa3 = h2 + -1 | 0; + ia3 = k2 + (fa3 & l2) | 0; + ia3 = (_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ha3 = b2[ea3 >> 1] | 0; + b2[ea3 >> 1] = ha3 + 1 << 16 >> 16; + ea3 = ha3 & 65535; + ga3 = n2 + (ia3 << 2) | 0; + da3 = fa3 - (c[ga3 >> 2] | 0) | 0; + a[(fa3 & 65535) + (n2 + 196608) >> 0] = ia3; + b2[n2 + 262144 + (ea3 << 2) >> 1] = da3 >>> 0 > 65535 ? 65535 : da3; + ia3 = n2 + 131072 + (ia3 << 1) | 0; + b2[n2 + 262144 + (ea3 << 2) + 2 >> 1] = b2[ia3 >> 1] | 0; + c[ga3 >> 2] = fa3; + b2[ia3 >> 1] = ha3; + } + O3 = pa3 + 4 | 0; + P3 = pa3 + 8 | 0; + Q3 = pa3 + 12 | 0; + R3 = pa3 + 4 | 0; + S3 = pa3 + 8 | 0; + T3 = pa3 + 12 | 0; + U3 = n2 + 524288 | 0; + V3 = n2 + 524296 | 0; + W3 = n2 + 524292 | 0; + X3 = ja3 << 2; + Y3 = oa3 + -4 | 0; + Z3 = oa3 + -3 | 0; + $2 = qa3 + 12 | 0; + ba2 = qa3 + 4 | 0; + ca3 = qa3 + 8 | 0; + da3 = qa3 + 4 | 0; + ea3 = qa3 + 8 | 0; + fa3 = qa3 + 12 | 0; + ga3 = o2 + 8 | 0; + ha3 = o2 + 12 | 0; + ia3 = o2 + 4 | 0; + m3 = h2; + N3 = q2; + f2 = u3; + a: while (1) { + L3 = N3; + M2 = t3 + X3 | 0; + b: while (1) { + K3 = oa3 - m3 | 0; + if ((m3 + 4 | 0) >>> 0 >= oa3 >>> 0) break a; + I3 = m3 >>> 0 < na2 >>> 0 ? m3 : na2; + c[pa3 >> 2] = 0; + c[O3 >> 2] = 0; + c[P3 >> 2] = 0; + c[Q3 >> 2] = 4240; + J3 = m3 & l2; + z3 = c[pa3 >> 2] | 0; + H3 = k2 + J3 | 0; + B3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + y3 = B3 & 255; + c[pa3 >> 2] = 0; + c[R3 >> 2] = 0; + G3 = J3 + K3 | 0; + F3 = k2 + G3 | 0; + E3 = H3; + G3 = k2 + (G3 + -4) | 0; + h2 = 4240; + j2 = 0; + A3 = 0; + while (1) { + if ((A3 | 0) == 4) break; + x3 = (c[o2 + (c[11372 + (A3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (A3 << 2) >> 2] | 0) | 0; + g3 = m3 - x3 | 0; + if (!A3) if (g3 >>> 0 >= m3 >>> 0 | x3 >>> 0 > I3 >>> 0) g3 = z3; + else ra3 = 17; + else if ((g3 >>> 0 < m3 >>> 0 ? (a[(g3 & 65535) + (n2 + 196608) >> 0] | 0) == y3 << 24 >> 24 : 0) ^ 1 | x3 >>> 0 > I3 >>> 0) g3 = z3; + else ra3 = 17; + if ((ra3 | 0) == 17) { + ra3 = 0; + w2 = g3 & l2; + g3 = 0; + u3 = E3; + while (1) { + v3 = u3; + if (v3 >>> 0 > G3 >>> 0) break; + C3 = u3; + D3 = k2 + (w2 + g3) | 0; + if ((d[C3 >> 0] | d[C3 + 1 >> 0] << 8 | d[C3 + 2 >> 0] << 16 | d[C3 + 3 >> 0] << 24 | 0) != (d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + u3 = v3 + 4 | 0; + } + while (1) { + if (u3 >>> 0 >= F3 >>> 0) break; + if ((a[k2 + (w2 + g3) >> 0] | 0) != (a[u3 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + u3 = u3 + 1 | 0; + } + if (g3 >>> 0 > 1 ? (ta3 = (g3 * 540 | 0) + (c[11500 + (A3 << 2) >> 2] | 0) | 0, h2 >>> 0 < ta3 >>> 0) : 0) { + c[pa3 >> 2] = g3; + c[S3 >> 2] = x3; + c[T3 >> 2] = ta3; + h2 = ta3; + j2 = 1; + } else g3 = z3; + } + z3 = g3; + A3 = A3 + 1 | 0; + } + w2 = 0; + u3 = m3 - (c[n2 + (B3 << 2) >> 2] | 0) | 0; + v3 = c[ka3 >> 2] | 0; + g3 = e[n2 + 131072 + (B3 << 1) >> 1] | 0; + c: while (1) { + D3 = J3 + z3 | 0; + C3 = D3 >>> 0 > l2 >>> 0; + D3 = k2 + D3 | 0; + x3 = w2; + y3 = u3; + A3 = v3; + B3 = g3; + while (1) { + w2 = A3; + A3 = A3 + -1 | 0; + if (!w2) break c; + x3 = x3 + y3 | 0; + if (x3 >>> 0 > I3 >>> 0) break c; + w2 = m3 - x3 & l2; + y3 = B3; + B3 = e[n2 + 262144 + (B3 << 2) + 2 >> 1] | 0; + y3 = e[n2 + 262144 + (y3 << 2) >> 1] | 0; + if (C3) continue; + g3 = w2 + z3 | 0; + if (g3 >>> 0 > l2 >>> 0) continue; + if ((a[D3 >> 0] | 0) == (a[k2 + g3 >> 0] | 0)) { + v3 = 0; + g3 = E3; + } else continue; + while (1) { + u3 = g3; + if (u3 >>> 0 > G3 >>> 0) break; + Ga3 = g3; + Fa3 = k2 + (w2 + v3) | 0; + if ((d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0) != (d[Fa3 >> 0] | d[Fa3 + 1 >> 0] << 8 | d[Fa3 + 2 >> 0] << 16 | d[Fa3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + g3 = u3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= F3 >>> 0) break; + if ((a[k2 + (w2 + v3) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (v3 >>> 0 <= 3) continue; + g3 = (v3 * 540 | 0) + 3840 + (_((aa(x3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (h2 >>> 0 < g3 >>> 0) break; + } + c[pa3 >> 2] = v3; + c[S3 >> 2] = x3; + c[T3 >> 2] = g3; + w2 = x3; + z3 = v3; + h2 = g3; + u3 = y3; + v3 = A3; + j2 = 1; + g3 = B3; + } + Ga3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + F3 = Fa3 & 65535; + G3 = n2 + (Ga3 << 2) | 0; + E3 = m3 - (c[G3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (F3 << 2) >> 1] = E3 >>> 0 > 65535 ? 65535 : E3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (F3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[G3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + if (!(j2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) j2 = 0; + else { + x3 = 0; + j2 = 0; + w2 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((x3 | 0) == 2) break; + Ga3 = b2[21084 + (w2 << 1) >> 1] | 0; + g3 = Ga3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ga3 << 16 >> 16 != 0 ? (ua3 = g3 & 31, va3 = g3 >>> 5, wa3 = (c[11272 + (ua3 << 2) >> 2] | 0) + (_(ua3, va3) | 0) | 0, ua3 >>> 0 <= K3 >>> 0) : 0) { + h2 = wa3 + ua3 | 0; + v3 = 280811 + h2 | 0; + h2 = 280811 + (h2 + -4) | 0; + u3 = 0; + g3 = 280811 + wa3 | 0; + while (1) { + if (g3 >>> 0 > h2 >>> 0) break; + Ga3 = k2 + (J3 + u3) | 0; + if ((d[g3 >> 0] | d[g3 + 1 >> 0] << 8 | d[g3 + 2 >> 0] << 16 | d[g3 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + u3 = u3 + 4 | 0; + g3 = g3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= v3 >>> 0) break; + if ((a[k2 + (J3 + u3) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + u3 = u3 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (!((u3 + 10 | 0) >>> 0 <= ua3 >>> 0 | (u3 | 0) == 0) ? (xa3 = I3 + va3 + 1 + (d[407930 + (ua3 - u3) >> 0] << d[280786 + ua3 >> 0]) | 0, ya3 = (u3 * 540 | 0) + 3840 + (_((aa(xa3 | 0) | 0) ^ 31, -120) | 0) | 0, ya3 >>> 0 >= (c[T3 >> 2] | 0) >>> 0) : 0) { + c[pa3 >> 2] = u3; + c[R3 >> 2] = ua3 ^ u3; + c[S3 >> 2] = xa3; + c[T3 >> 2] = ya3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + j2 = 1; + } + } + x3 = x3 + 1 | 0; + w2 = w2 + 1 | 0; + } + j2 = (j2 & 1) != 0; + } + j2 = j2 & 1; + } + if (j2 & 1) { + L3 = 0; + x3 = f2; + break; + } + f2 = f2 + 1 | 0; + g3 = m3 + 1 | 0; + if (g3 >>> 0 <= t3 >>> 0) { + m3 = g3; + continue; + } + if (g3 >>> 0 > M2 >>> 0) { + j2 = m3 + 17 | 0; + j2 = j2 >>> 0 < Y3 >>> 0 ? j2 : Y3; + m3 = g3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ga3 = k2 + (m3 & l2) | 0; + Ga3 = (_(d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + J3 = Fa3 & 65535; + K3 = n2 + (Ga3 << 2) | 0; + I3 = m3 - (c[K3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (J3 << 2) >> 1] = I3 >>> 0 > 65535 ? 65535 : I3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (J3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[K3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + m3 = m3 + 4 | 0; + f2 = f2 + 4 | 0; + } + } else { + j2 = m3 + 9 | 0; + j2 = j2 >>> 0 < Z3 >>> 0 ? j2 : Z3; + m3 = g3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ga3 = k2 + (m3 & l2) | 0; + Ga3 = (_(d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + J3 = Fa3 & 65535; + K3 = n2 + (Ga3 << 2) | 0; + I3 = m3 - (c[K3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (J3 << 2) >> 1] = I3 >>> 0 > 65535 ? 65535 : I3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (J3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[K3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + m3 = m3 + 2 | 0; + f2 = f2 + 2 | 0; + } + } + } + while (1) { + K3 = K3 + -1 | 0; + if ((c[la3 >> 2] | 0) < 5) { + f2 = (c[pa3 >> 2] | 0) + -1 | 0; + f2 = f2 >>> 0 < K3 >>> 0 ? f2 : K3; + } else f2 = 0; + c[qa3 >> 2] = f2; + c[ba2 >> 2] = 0; + c[ca3 >> 2] = 0; + c[$2 >> 2] = 4240; + y3 = m3 + 1 | 0; + I3 = y3 >>> 0 < na2 >>> 0 ? y3 : na2; + J3 = y3 & l2; + z3 = c[qa3 >> 2] | 0; + H3 = k2 + J3 | 0; + B3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + w2 = B3 & 255; + c[qa3 >> 2] = 0; + c[da3 >> 2] = 0; + G3 = J3 + K3 | 0; + F3 = k2 + G3 | 0; + E3 = H3; + G3 = k2 + (G3 + -4) | 0; + g3 = 4240; + f2 = 0; + A3 = 0; + while (1) { + if ((A3 | 0) == 4) break; + v3 = (c[o2 + (c[11372 + (A3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (A3 << 2) >> 2] | 0) | 0; + j2 = y3 - v3 | 0; + if (!A3) if (j2 >>> 0 >= y3 >>> 0 | v3 >>> 0 > I3 >>> 0) j2 = z3; + else ra3 = 71; + else if ((j2 >>> 0 < y3 >>> 0 ? (a[(j2 & 65535) + (n2 + 196608) >> 0] | 0) == w2 << 24 >> 24 : 0) ^ 1 | v3 >>> 0 > I3 >>> 0) j2 = z3; + else ra3 = 71; + if ((ra3 | 0) == 71) { + ra3 = 0; + u3 = j2 & l2; + j2 = 0; + t3 = E3; + while (1) { + h2 = t3; + if (h2 >>> 0 > G3 >>> 0) break; + Fa3 = t3; + Ga3 = k2 + (u3 + j2) | 0; + if ((d[Fa3 >> 0] | d[Fa3 + 1 >> 0] << 8 | d[Fa3 + 2 >> 0] << 16 | d[Fa3 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + j2 = j2 + 4 | 0; + t3 = h2 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= F3 >>> 0) break; + if ((a[k2 + (u3 + j2) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + j2 = j2 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (j2 >>> 0 > 1 ? (za3 = (j2 * 540 | 0) + (c[11500 + (A3 << 2) >> 2] | 0) | 0, g3 >>> 0 < za3 >>> 0) : 0) { + c[qa3 >> 2] = j2; + c[ea3 >> 2] = v3; + c[fa3 >> 2] = za3; + g3 = za3; + f2 = 1; + } else j2 = z3; + } + z3 = j2; + A3 = A3 + 1 | 0; + } + u3 = 0; + t3 = y3 - (c[n2 + (B3 << 2) >> 2] | 0) | 0; + h2 = c[ka3 >> 2] | 0; + j2 = e[n2 + 131072 + (B3 << 1) >> 1] | 0; + d: while (1) { + D3 = J3 + z3 | 0; + C3 = D3 >>> 0 > l2 >>> 0; + D3 = k2 + D3 | 0; + v3 = u3; + w2 = t3; + A3 = h2; + B3 = j2; + while (1) { + Ga3 = A3; + A3 = A3 + -1 | 0; + if (!Ga3) break d; + v3 = v3 + w2 | 0; + if (v3 >>> 0 > I3 >>> 0) break d; + u3 = y3 - v3 & l2; + w2 = B3; + B3 = e[n2 + 262144 + (B3 << 2) + 2 >> 1] | 0; + w2 = e[n2 + 262144 + (w2 << 2) >> 1] | 0; + if (C3) continue; + j2 = u3 + z3 | 0; + if (j2 >>> 0 > l2 >>> 0) continue; + if ((a[D3 >> 0] | 0) == (a[k2 + j2 >> 0] | 0)) { + h2 = 0; + j2 = E3; + } else continue; + while (1) { + t3 = j2; + if (t3 >>> 0 > G3 >>> 0) break; + Fa3 = j2; + Ga3 = k2 + (u3 + h2) | 0; + if ((d[Fa3 >> 0] | d[Fa3 + 1 >> 0] << 8 | d[Fa3 + 2 >> 0] << 16 | d[Fa3 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + j2 = t3 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= F3 >>> 0) break; + if ((a[k2 + (u3 + h2) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (h2 >>> 0 <= 3) continue; + j2 = (h2 * 540 | 0) + 3840 + (_((aa(v3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (g3 >>> 0 < j2 >>> 0) break; + } + c[qa3 >> 2] = h2; + c[ea3 >> 2] = v3; + c[fa3 >> 2] = j2; + u3 = v3; + z3 = h2; + g3 = j2; + t3 = w2; + h2 = A3; + f2 = 1; + j2 = B3; + } + Ga3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + G3 = Fa3 & 65535; + M2 = n2 + (Ga3 << 2) | 0; + F3 = y3 - (c[M2 >> 2] | 0) | 0; + a[(y3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (G3 << 2) >> 1] = F3 >>> 0 > 65535 ? 65535 : F3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (G3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[M2 >> 2] = y3; + b2[Ga3 >> 1] = Fa3; + if (!(f2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) f2 = 0; + else { + v3 = 0; + f2 = 0; + u3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 2) break; + Ga3 = b2[21084 + (u3 << 1) >> 1] | 0; + j2 = Ga3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ga3 << 16 >> 16 != 0 ? (Aa3 = j2 & 31, Ba3 = j2 >>> 5, Ca3 = (c[11272 + (Aa3 << 2) >> 2] | 0) + (_(Aa3, Ba3) | 0) | 0, Aa3 >>> 0 <= K3 >>> 0) : 0) { + g3 = Ca3 + Aa3 | 0; + h2 = 280811 + g3 | 0; + g3 = 280811 + (g3 + -4) | 0; + t3 = 0; + j2 = 280811 + Ca3 | 0; + while (1) { + if (j2 >>> 0 > g3 >>> 0) break; + Ga3 = k2 + (J3 + t3) | 0; + if ((d[j2 >> 0] | d[j2 + 1 >> 0] << 8 | d[j2 + 2 >> 0] << 16 | d[j2 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + t3 = t3 + 4 | 0; + j2 = j2 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= h2 >>> 0) break; + if ((a[k2 + (J3 + t3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + t3 = t3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (!((t3 + 10 | 0) >>> 0 <= Aa3 >>> 0 | (t3 | 0) == 0) ? (Da3 = I3 + Ba3 + 1 + (d[407930 + (Aa3 - t3) >> 0] << d[280786 + Aa3 >> 0]) | 0, Ea3 = (t3 * 540 | 0) + 3840 + (_((aa(Da3 | 0) | 0) ^ 31, -120) | 0) | 0, Ea3 >>> 0 >= (c[fa3 >> 2] | 0) >>> 0) : 0) { + c[qa3 >> 2] = t3; + c[da3 >> 2] = Aa3 ^ t3; + c[ea3 >> 2] = Da3; + c[fa3 >> 2] = Ea3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + f2 = 1; + } + } + v3 = v3 + 1 | 0; + u3 = u3 + 1 | 0; + } + f2 = (f2 & 1) != 0; + } + f2 = f2 & 1; + } + if (!(f2 & 1)) { + y3 = m3; + break; + } + if ((c[$2 >> 2] | 0) >>> 0 < ((c[Q3 >> 2] | 0) + 700 | 0) >>> 0) { + y3 = m3; + break; + } + f2 = x3 + 1 | 0; + c[pa3 >> 2] = c[qa3 >> 2]; + c[pa3 + 4 >> 2] = c[qa3 + 4 >> 2]; + c[pa3 + 8 >> 2] = c[qa3 + 8 >> 2]; + c[pa3 + 12 >> 2] = c[qa3 + 12 >> 2]; + L3 = L3 + 1 | 0; + if (!((L3 | 0) < 4 & (m3 + 5 | 0) >>> 0 < oa3 >>> 0)) { + x3 = f2; + break; + } else { + m3 = y3; + x3 = f2; + } + } + m3 = c[pa3 >> 2] | 0; + t3 = y3 + (m3 << 1) + ja3 | 0; + f2 = c[P3 >> 2] | 0; + e: do + if (f2 >>> 0 <= (y3 >>> 0 < na2 >>> 0 ? y3 : na2) >>> 0) { + h2 = f2 + 3 | 0; + Ga3 = c[o2 >> 2] | 0; + j2 = h2 - Ga3 | 0; + g3 = c[ia3 >> 2] | 0; + h2 = h2 - g3 | 0; + if ((f2 | 0) == (Ga3 | 0)) f2 = 0; + else { + f: do + if ((f2 | 0) != (g3 | 0)) { + do + if (j2 >>> 0 < 7) f2 = 158663784 >>> (j2 << 2) & 15; + else { + if (h2 >>> 0 < 7) { + f2 = 266017486 >>> (h2 << 2) & 15; + break; + } + if ((f2 | 0) == (c[ga3 >> 2] | 0)) { + f2 = 2; + break f; + } + if ((f2 | 0) == (c[ha3 >> 2] | 0)) { + f2 = 3; + break f; + } + f2 = f2 + 15 | 0; + } + while (0); + if (!f2) break e; + } else f2 = 1; + while (0); + c[ha3 >> 2] = c[ga3 >> 2]; + c[ga3 >> 2] = c[ia3 >> 2]; + c[ia3 >> 2] = c[o2 >> 2]; + c[o2 >> 2] = c[P3 >> 2]; + m3 = c[pa3 >> 2] | 0; + } + } else f2 = f2 + 15 | 0; + while (0); + w2 = N3 + 16 | 0; + Ga3 = c[O3 >> 2] | 0; + j2 = m3 ^ Ga3; + c[N3 >> 2] = x3; + c[N3 + 4 >> 2] = m3 | Ga3 << 24; + m3 = N3 + 14 | 0; + if (f2 >>> 0 < 16) { + f2 = f2 & 65535; + b2[m3 >> 1] = f2; + m3 = 0; + } else { + M2 = f2 + -12 | 0; + Ga3 = ((aa(M2 | 0) | 0) ^ 31) + -1 | 0; + Fa3 = M2 >>> Ga3 & 1; + f2 = ((Ga3 << 1) + 65534 | Fa3) + 16 & 65535; + b2[m3 >> 1] = f2; + m3 = Ga3 << 24 | M2 - ((Fa3 | 2) << Ga3); + } + c[N3 + 8 >> 2] = m3; + u3 = f2 << 16 >> 16 == 0; + v3 = N3 + 12 | 0; + do + if (x3 >>> 0 >= 6) { + if (x3 >>> 0 < 130) { + Ga3 = x3 + -2 | 0; + h2 = ((aa(Ga3 | 0) | 0) ^ 31) + -1 | 0; + h2 = (h2 << 1) + (Ga3 >>> h2) + 2 & 65535; + break; + } + if (x3 >>> 0 < 2114) { + h2 = ((aa(x3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (x3 >>> 0 < 6210) h2 = 21; + else h2 = x3 >>> 0 < 22594 ? 22 : 23; + } else h2 = x3 & 65535; + while (0); + do + if (j2 >>> 0 >= 10) { + if (j2 >>> 0 < 134) { + Ga3 = j2 + -6 | 0; + f2 = ((aa(Ga3 | 0) | 0) ^ 31) + -1 | 0; + f2 = (f2 << 1) + (Ga3 >>> f2) + 4 & 65535; + break; + } + if (j2 >>> 0 < 2118) f2 = ((aa(j2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else f2 = 23; + } else f2 = j2 + 65534 & 65535; + while (0); + m3 = f2 & 65535; + j2 = h2 & 65535; + g3 = m3 & 7 | j2 << 3 & 56; + if (u3 & (h2 & 65535) < 8 & (f2 & 65535) < 16) f2 = ((f2 & 65535) < 8 ? g3 : g3 | 64) & 65535; + else f2 = b2[88156 + ((m3 >>> 3) + ((j2 >>> 3) * 3 | 0) << 1) >> 1] | g3 & 65535; + b2[v3 >> 1] = f2; + c[s2 >> 2] = (c[s2 >> 2] | 0) + x3; + f2 = y3 + (c[pa3 >> 2] | 0) | 0; + f2 = f2 >>> 0 < ma3 >>> 0 ? f2 : ma3; + m3 = y3 + 2 | 0; + while (1) { + if (m3 >>> 0 >= f2 >>> 0) break; + Ga3 = k2 + (m3 & l2) | 0; + Ga3 = (_(d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + M2 = Fa3 & 65535; + N3 = n2 + (Ga3 << 2) | 0; + L3 = m3 - (c[N3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (M2 << 2) >> 1] = L3 >>> 0 > 65535 ? 65535 : L3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (M2 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[N3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + m3 = m3 + 1 | 0; + } + m3 = y3 + (c[pa3 >> 2] | 0) | 0; + N3 = w2; + f2 = 0; + } + c[p2 >> 2] = f2 + K3; + c[r2 >> 2] = (c[r2 >> 2] | 0) + (L3 - q2 >> 4); + i = sa3; + return; + } + function Sa2(f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2, s2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0; + sa3 = i; + i = i + 32 | 0; + pa3 = sa3 + 16 | 0; + qa3 = sa3; + na2 = (1 << c[m3 + 8 >> 2]) + -16 | 0; + u3 = c[p2 >> 2] | 0; + oa3 = h2 + g3 | 0; + ma3 = g3 >>> 0 > 3 ? oa3 + -3 | 0 : h2; + la3 = m3 + 4 | 0; + ia3 = c[la3 >> 2] | 0; + ja3 = (ia3 | 0) < 9 ? 64 : 512; + t3 = ja3 + h2 | 0; + ka3 = n2 + 524300 | 0; + c[ka3 >> 2] = ((ia3 | 0) > 6 ? 7 : 8) << ia3 + -4; + if ((((h2 | 0) == 0 ^ 1 | j2 ^ 1) ^ 1) & g3 >>> 0 < 513) { + f2 = 0; + while (1) { + if ((f2 | 0) == (g3 | 0)) break; + ia3 = k2 + f2 | 0; + ia3 = (_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + c[n2 + (ia3 << 2) >> 2] = -858993460; + b2[n2 + 131072 + (ia3 << 1) >> 1] = -13108; + f2 = f2 + 1 | 0; + } + ac(n2 + 196608 | 0, 0, 65536) | 0; + b2[n2 + 524288 >> 1] = 0; + if (g3) { + a[n2 + 524290 >> 0] = 0; + ra3 = 8; + } + } else { + f2 = n2 + 524290 | 0; + if (!(a[f2 >> 0] & 1)) ra3 = 8; + else { + ac(n2 | 0, -52, 131072) | 0; + b2[n2 + 524288 >> 1] = 0; + a[f2 >> 0] = 0; + ac(n2 + 131072 | 0, 0, 131072) | 0; + ra3 = 8; + } + } + if ((ra3 | 0) == 8 ? g3 >>> 0 > 2 & h2 >>> 0 > 2 : 0) { + da3 = h2 + -3 | 0; + ga3 = k2 + (da3 & l2) | 0; + ga3 = (_(d[ga3 >> 0] | d[ga3 + 1 >> 0] << 8 | d[ga3 + 2 >> 0] << 16 | d[ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ea3 = n2 + 524288 | 0; + fa3 = b2[ea3 >> 1] | 0; + b2[ea3 >> 1] = fa3 + 1 << 16 >> 16; + ha3 = fa3 & 65535; + ia3 = n2 + (ga3 << 2) | 0; + ca3 = da3 - (c[ia3 >> 2] | 0) | 0; + a[(da3 & 65535) + (n2 + 196608) >> 0] = ga3; + b2[n2 + 262144 + (ha3 << 2) >> 1] = ca3 >>> 0 > 65535 ? 65535 : ca3; + ga3 = n2 + 131072 + (ga3 << 1) | 0; + b2[n2 + 262144 + (ha3 << 2) + 2 >> 1] = b2[ga3 >> 1] | 0; + c[ia3 >> 2] = da3; + b2[ga3 >> 1] = fa3; + ga3 = h2 + -2 | 0; + fa3 = k2 + (ga3 & l2) | 0; + fa3 = (_(d[fa3 >> 0] | d[fa3 + 1 >> 0] << 8 | d[fa3 + 2 >> 0] << 16 | d[fa3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ia3 = b2[ea3 >> 1] | 0; + b2[ea3 >> 1] = ia3 + 1 << 16 >> 16; + da3 = ia3 & 65535; + ha3 = n2 + (fa3 << 2) | 0; + ca3 = ga3 - (c[ha3 >> 2] | 0) | 0; + a[(ga3 & 65535) + (n2 + 196608) >> 0] = fa3; + b2[n2 + 262144 + (da3 << 2) >> 1] = ca3 >>> 0 > 65535 ? 65535 : ca3; + fa3 = n2 + 131072 + (fa3 << 1) | 0; + b2[n2 + 262144 + (da3 << 2) + 2 >> 1] = b2[fa3 >> 1] | 0; + c[ha3 >> 2] = ga3; + b2[fa3 >> 1] = ia3; + fa3 = h2 + -1 | 0; + ia3 = k2 + (fa3 & l2) | 0; + ia3 = (_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ha3 = b2[ea3 >> 1] | 0; + b2[ea3 >> 1] = ha3 + 1 << 16 >> 16; + ea3 = ha3 & 65535; + ga3 = n2 + (ia3 << 2) | 0; + da3 = fa3 - (c[ga3 >> 2] | 0) | 0; + a[(fa3 & 65535) + (n2 + 196608) >> 0] = ia3; + b2[n2 + 262144 + (ea3 << 2) >> 1] = da3 >>> 0 > 65535 ? 65535 : da3; + ia3 = n2 + 131072 + (ia3 << 1) | 0; + b2[n2 + 262144 + (ea3 << 2) + 2 >> 1] = b2[ia3 >> 1] | 0; + c[ga3 >> 2] = fa3; + b2[ia3 >> 1] = ha3; + } + O3 = pa3 + 4 | 0; + P3 = pa3 + 8 | 0; + Q3 = pa3 + 12 | 0; + R3 = pa3 + 4 | 0; + S3 = pa3 + 8 | 0; + T3 = pa3 + 12 | 0; + U3 = n2 + 524288 | 0; + V3 = n2 + 524296 | 0; + W3 = n2 + 524292 | 0; + X3 = ja3 << 2; + Y3 = oa3 + -4 | 0; + Z3 = oa3 + -3 | 0; + $2 = qa3 + 12 | 0; + ba2 = qa3 + 4 | 0; + ca3 = qa3 + 8 | 0; + da3 = qa3 + 4 | 0; + ea3 = qa3 + 8 | 0; + fa3 = qa3 + 12 | 0; + ga3 = o2 + 8 | 0; + ha3 = o2 + 12 | 0; + ia3 = o2 + 4 | 0; + m3 = h2; + N3 = q2; + f2 = u3; + a: while (1) { + L3 = N3; + M2 = t3 + X3 | 0; + b: while (1) { + K3 = oa3 - m3 | 0; + if ((m3 + 4 | 0) >>> 0 >= oa3 >>> 0) break a; + I3 = m3 >>> 0 < na2 >>> 0 ? m3 : na2; + c[pa3 >> 2] = 0; + c[O3 >> 2] = 0; + c[P3 >> 2] = 0; + c[Q3 >> 2] = 4240; + J3 = m3 & l2; + z3 = c[pa3 >> 2] | 0; + H3 = k2 + J3 | 0; + B3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + y3 = B3 & 255; + c[pa3 >> 2] = 0; + c[R3 >> 2] = 0; + G3 = J3 + K3 | 0; + F3 = k2 + G3 | 0; + E3 = H3; + G3 = k2 + (G3 + -4) | 0; + h2 = 4240; + j2 = 0; + A3 = 0; + while (1) { + if ((A3 | 0) == 10) break; + x3 = (c[o2 + (c[11372 + (A3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (A3 << 2) >> 2] | 0) | 0; + g3 = m3 - x3 | 0; + if (!A3) if (g3 >>> 0 >= m3 >>> 0 | x3 >>> 0 > I3 >>> 0) g3 = z3; + else ra3 = 17; + else if ((g3 >>> 0 < m3 >>> 0 ? (a[(g3 & 65535) + (n2 + 196608) >> 0] | 0) == y3 << 24 >> 24 : 0) ^ 1 | x3 >>> 0 > I3 >>> 0) g3 = z3; + else ra3 = 17; + if ((ra3 | 0) == 17) { + ra3 = 0; + w2 = g3 & l2; + g3 = 0; + u3 = E3; + while (1) { + v3 = u3; + if (v3 >>> 0 > G3 >>> 0) break; + C3 = u3; + D3 = k2 + (w2 + g3) | 0; + if ((d[C3 >> 0] | d[C3 + 1 >> 0] << 8 | d[C3 + 2 >> 0] << 16 | d[C3 + 3 >> 0] << 24 | 0) != (d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + u3 = v3 + 4 | 0; + } + while (1) { + if (u3 >>> 0 >= F3 >>> 0) break; + if ((a[k2 + (w2 + g3) >> 0] | 0) != (a[u3 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + u3 = u3 + 1 | 0; + } + if (g3 >>> 0 > 1 ? (ta3 = (g3 * 540 | 0) + (c[11500 + (A3 << 2) >> 2] | 0) | 0, h2 >>> 0 < ta3 >>> 0) : 0) { + c[pa3 >> 2] = g3; + c[S3 >> 2] = x3; + c[T3 >> 2] = ta3; + h2 = ta3; + j2 = 1; + } else g3 = z3; + } + z3 = g3; + A3 = A3 + 1 | 0; + } + w2 = 0; + u3 = m3 - (c[n2 + (B3 << 2) >> 2] | 0) | 0; + v3 = c[ka3 >> 2] | 0; + g3 = e[n2 + 131072 + (B3 << 1) >> 1] | 0; + c: while (1) { + D3 = J3 + z3 | 0; + C3 = D3 >>> 0 > l2 >>> 0; + D3 = k2 + D3 | 0; + x3 = w2; + y3 = u3; + A3 = v3; + B3 = g3; + while (1) { + w2 = A3; + A3 = A3 + -1 | 0; + if (!w2) break c; + x3 = x3 + y3 | 0; + if (x3 >>> 0 > I3 >>> 0) break c; + w2 = m3 - x3 & l2; + y3 = B3; + B3 = e[n2 + 262144 + (B3 << 2) + 2 >> 1] | 0; + y3 = e[n2 + 262144 + (y3 << 2) >> 1] | 0; + if (C3) continue; + g3 = w2 + z3 | 0; + if (g3 >>> 0 > l2 >>> 0) continue; + if ((a[D3 >> 0] | 0) == (a[k2 + g3 >> 0] | 0)) { + v3 = 0; + g3 = E3; + } else continue; + while (1) { + u3 = g3; + if (u3 >>> 0 > G3 >>> 0) break; + Ga3 = g3; + Fa3 = k2 + (w2 + v3) | 0; + if ((d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0) != (d[Fa3 >> 0] | d[Fa3 + 1 >> 0] << 8 | d[Fa3 + 2 >> 0] << 16 | d[Fa3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + g3 = u3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= F3 >>> 0) break; + if ((a[k2 + (w2 + v3) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (v3 >>> 0 <= 3) continue; + g3 = (v3 * 540 | 0) + 3840 + (_((aa(x3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (h2 >>> 0 < g3 >>> 0) break; + } + c[pa3 >> 2] = v3; + c[S3 >> 2] = x3; + c[T3 >> 2] = g3; + w2 = x3; + z3 = v3; + h2 = g3; + u3 = y3; + v3 = A3; + j2 = 1; + g3 = B3; + } + Ga3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + F3 = Fa3 & 65535; + G3 = n2 + (Ga3 << 2) | 0; + E3 = m3 - (c[G3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (F3 << 2) >> 1] = E3 >>> 0 > 65535 ? 65535 : E3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (F3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[G3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + if (!(j2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) j2 = 0; + else { + x3 = 0; + j2 = 0; + w2 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((x3 | 0) == 2) break; + Ga3 = b2[21084 + (w2 << 1) >> 1] | 0; + g3 = Ga3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ga3 << 16 >> 16 != 0 ? (ua3 = g3 & 31, va3 = g3 >>> 5, wa3 = (c[11272 + (ua3 << 2) >> 2] | 0) + (_(ua3, va3) | 0) | 0, ua3 >>> 0 <= K3 >>> 0) : 0) { + h2 = wa3 + ua3 | 0; + v3 = 280811 + h2 | 0; + h2 = 280811 + (h2 + -4) | 0; + u3 = 0; + g3 = 280811 + wa3 | 0; + while (1) { + if (g3 >>> 0 > h2 >>> 0) break; + Ga3 = k2 + (J3 + u3) | 0; + if ((d[g3 >> 0] | d[g3 + 1 >> 0] << 8 | d[g3 + 2 >> 0] << 16 | d[g3 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + u3 = u3 + 4 | 0; + g3 = g3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= v3 >>> 0) break; + if ((a[k2 + (J3 + u3) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + u3 = u3 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (!((u3 + 10 | 0) >>> 0 <= ua3 >>> 0 | (u3 | 0) == 0) ? (xa3 = I3 + va3 + 1 + (d[407930 + (ua3 - u3) >> 0] << d[280786 + ua3 >> 0]) | 0, ya3 = (u3 * 540 | 0) + 3840 + (_((aa(xa3 | 0) | 0) ^ 31, -120) | 0) | 0, ya3 >>> 0 >= (c[T3 >> 2] | 0) >>> 0) : 0) { + c[pa3 >> 2] = u3; + c[R3 >> 2] = ua3 ^ u3; + c[S3 >> 2] = xa3; + c[T3 >> 2] = ya3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + j2 = 1; + } + } + x3 = x3 + 1 | 0; + w2 = w2 + 1 | 0; + } + j2 = (j2 & 1) != 0; + } + j2 = j2 & 1; + } + if (j2 & 1) { + L3 = 0; + x3 = f2; + break; + } + f2 = f2 + 1 | 0; + g3 = m3 + 1 | 0; + if (g3 >>> 0 <= t3 >>> 0) { + m3 = g3; + continue; + } + if (g3 >>> 0 > M2 >>> 0) { + j2 = m3 + 17 | 0; + j2 = j2 >>> 0 < Y3 >>> 0 ? j2 : Y3; + m3 = g3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ga3 = k2 + (m3 & l2) | 0; + Ga3 = (_(d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + J3 = Fa3 & 65535; + K3 = n2 + (Ga3 << 2) | 0; + I3 = m3 - (c[K3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (J3 << 2) >> 1] = I3 >>> 0 > 65535 ? 65535 : I3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (J3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[K3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + m3 = m3 + 4 | 0; + f2 = f2 + 4 | 0; + } + } else { + j2 = m3 + 9 | 0; + j2 = j2 >>> 0 < Z3 >>> 0 ? j2 : Z3; + m3 = g3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ga3 = k2 + (m3 & l2) | 0; + Ga3 = (_(d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + J3 = Fa3 & 65535; + K3 = n2 + (Ga3 << 2) | 0; + I3 = m3 - (c[K3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (J3 << 2) >> 1] = I3 >>> 0 > 65535 ? 65535 : I3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (J3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[K3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + m3 = m3 + 2 | 0; + f2 = f2 + 2 | 0; + } + } + } + while (1) { + K3 = K3 + -1 | 0; + if ((c[la3 >> 2] | 0) < 5) { + f2 = (c[pa3 >> 2] | 0) + -1 | 0; + f2 = f2 >>> 0 < K3 >>> 0 ? f2 : K3; + } else f2 = 0; + c[qa3 >> 2] = f2; + c[ba2 >> 2] = 0; + c[ca3 >> 2] = 0; + c[$2 >> 2] = 4240; + y3 = m3 + 1 | 0; + I3 = y3 >>> 0 < na2 >>> 0 ? y3 : na2; + J3 = y3 & l2; + z3 = c[qa3 >> 2] | 0; + H3 = k2 + J3 | 0; + B3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + w2 = B3 & 255; + c[qa3 >> 2] = 0; + c[da3 >> 2] = 0; + G3 = J3 + K3 | 0; + F3 = k2 + G3 | 0; + E3 = H3; + G3 = k2 + (G3 + -4) | 0; + g3 = 4240; + f2 = 0; + A3 = 0; + while (1) { + if ((A3 | 0) == 10) break; + v3 = (c[o2 + (c[11372 + (A3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (A3 << 2) >> 2] | 0) | 0; + j2 = y3 - v3 | 0; + if (!A3) if (j2 >>> 0 >= y3 >>> 0 | v3 >>> 0 > I3 >>> 0) j2 = z3; + else ra3 = 71; + else if ((j2 >>> 0 < y3 >>> 0 ? (a[(j2 & 65535) + (n2 + 196608) >> 0] | 0) == w2 << 24 >> 24 : 0) ^ 1 | v3 >>> 0 > I3 >>> 0) j2 = z3; + else ra3 = 71; + if ((ra3 | 0) == 71) { + ra3 = 0; + u3 = j2 & l2; + j2 = 0; + t3 = E3; + while (1) { + h2 = t3; + if (h2 >>> 0 > G3 >>> 0) break; + Fa3 = t3; + Ga3 = k2 + (u3 + j2) | 0; + if ((d[Fa3 >> 0] | d[Fa3 + 1 >> 0] << 8 | d[Fa3 + 2 >> 0] << 16 | d[Fa3 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + j2 = j2 + 4 | 0; + t3 = h2 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= F3 >>> 0) break; + if ((a[k2 + (u3 + j2) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + j2 = j2 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (j2 >>> 0 > 1 ? (za3 = (j2 * 540 | 0) + (c[11500 + (A3 << 2) >> 2] | 0) | 0, g3 >>> 0 < za3 >>> 0) : 0) { + c[qa3 >> 2] = j2; + c[ea3 >> 2] = v3; + c[fa3 >> 2] = za3; + g3 = za3; + f2 = 1; + } else j2 = z3; + } + z3 = j2; + A3 = A3 + 1 | 0; + } + u3 = 0; + t3 = y3 - (c[n2 + (B3 << 2) >> 2] | 0) | 0; + h2 = c[ka3 >> 2] | 0; + j2 = e[n2 + 131072 + (B3 << 1) >> 1] | 0; + d: while (1) { + D3 = J3 + z3 | 0; + C3 = D3 >>> 0 > l2 >>> 0; + D3 = k2 + D3 | 0; + v3 = u3; + w2 = t3; + A3 = h2; + B3 = j2; + while (1) { + Ga3 = A3; + A3 = A3 + -1 | 0; + if (!Ga3) break d; + v3 = v3 + w2 | 0; + if (v3 >>> 0 > I3 >>> 0) break d; + u3 = y3 - v3 & l2; + w2 = B3; + B3 = e[n2 + 262144 + (B3 << 2) + 2 >> 1] | 0; + w2 = e[n2 + 262144 + (w2 << 2) >> 1] | 0; + if (C3) continue; + j2 = u3 + z3 | 0; + if (j2 >>> 0 > l2 >>> 0) continue; + if ((a[D3 >> 0] | 0) == (a[k2 + j2 >> 0] | 0)) { + h2 = 0; + j2 = E3; + } else continue; + while (1) { + t3 = j2; + if (t3 >>> 0 > G3 >>> 0) break; + Fa3 = j2; + Ga3 = k2 + (u3 + h2) | 0; + if ((d[Fa3 >> 0] | d[Fa3 + 1 >> 0] << 8 | d[Fa3 + 2 >> 0] << 16 | d[Fa3 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + j2 = t3 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= F3 >>> 0) break; + if ((a[k2 + (u3 + h2) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (h2 >>> 0 <= 3) continue; + j2 = (h2 * 540 | 0) + 3840 + (_((aa(v3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (g3 >>> 0 < j2 >>> 0) break; + } + c[qa3 >> 2] = h2; + c[ea3 >> 2] = v3; + c[fa3 >> 2] = j2; + u3 = v3; + z3 = h2; + g3 = j2; + t3 = w2; + h2 = A3; + f2 = 1; + j2 = B3; + } + Ga3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + G3 = Fa3 & 65535; + M2 = n2 + (Ga3 << 2) | 0; + F3 = y3 - (c[M2 >> 2] | 0) | 0; + a[(y3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (G3 << 2) >> 1] = F3 >>> 0 > 65535 ? 65535 : F3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (G3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[M2 >> 2] = y3; + b2[Ga3 >> 1] = Fa3; + if (!(f2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) f2 = 0; + else { + v3 = 0; + f2 = 0; + u3 = (_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 2) break; + Ga3 = b2[21084 + (u3 << 1) >> 1] | 0; + j2 = Ga3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ga3 << 16 >> 16 != 0 ? (Aa3 = j2 & 31, Ba3 = j2 >>> 5, Ca3 = (c[11272 + (Aa3 << 2) >> 2] | 0) + (_(Aa3, Ba3) | 0) | 0, Aa3 >>> 0 <= K3 >>> 0) : 0) { + g3 = Ca3 + Aa3 | 0; + h2 = 280811 + g3 | 0; + g3 = 280811 + (g3 + -4) | 0; + t3 = 0; + j2 = 280811 + Ca3 | 0; + while (1) { + if (j2 >>> 0 > g3 >>> 0) break; + Ga3 = k2 + (J3 + t3) | 0; + if ((d[j2 >> 0] | d[j2 + 1 >> 0] << 8 | d[j2 + 2 >> 0] << 16 | d[j2 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + t3 = t3 + 4 | 0; + j2 = j2 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= h2 >>> 0) break; + if ((a[k2 + (J3 + t3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + t3 = t3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (!((t3 + 10 | 0) >>> 0 <= Aa3 >>> 0 | (t3 | 0) == 0) ? (Da3 = I3 + Ba3 + 1 + (d[407930 + (Aa3 - t3) >> 0] << d[280786 + Aa3 >> 0]) | 0, Ea3 = (t3 * 540 | 0) + 3840 + (_((aa(Da3 | 0) | 0) ^ 31, -120) | 0) | 0, Ea3 >>> 0 >= (c[fa3 >> 2] | 0) >>> 0) : 0) { + c[qa3 >> 2] = t3; + c[da3 >> 2] = Aa3 ^ t3; + c[ea3 >> 2] = Da3; + c[fa3 >> 2] = Ea3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + f2 = 1; + } + } + v3 = v3 + 1 | 0; + u3 = u3 + 1 | 0; + } + f2 = (f2 & 1) != 0; + } + f2 = f2 & 1; + } + if (!(f2 & 1)) { + y3 = m3; + break; + } + if ((c[$2 >> 2] | 0) >>> 0 < ((c[Q3 >> 2] | 0) + 700 | 0) >>> 0) { + y3 = m3; + break; + } + f2 = x3 + 1 | 0; + c[pa3 >> 2] = c[qa3 >> 2]; + c[pa3 + 4 >> 2] = c[qa3 + 4 >> 2]; + c[pa3 + 8 >> 2] = c[qa3 + 8 >> 2]; + c[pa3 + 12 >> 2] = c[qa3 + 12 >> 2]; + L3 = L3 + 1 | 0; + if (!((L3 | 0) < 4 & (m3 + 5 | 0) >>> 0 < oa3 >>> 0)) { + x3 = f2; + break; + } else { + m3 = y3; + x3 = f2; + } + } + m3 = c[pa3 >> 2] | 0; + t3 = y3 + (m3 << 1) + ja3 | 0; + f2 = c[P3 >> 2] | 0; + e: do + if (f2 >>> 0 <= (y3 >>> 0 < na2 >>> 0 ? y3 : na2) >>> 0) { + h2 = f2 + 3 | 0; + Ga3 = c[o2 >> 2] | 0; + j2 = h2 - Ga3 | 0; + g3 = c[ia3 >> 2] | 0; + h2 = h2 - g3 | 0; + if ((f2 | 0) == (Ga3 | 0)) f2 = 0; + else { + f: do + if ((f2 | 0) != (g3 | 0)) { + do + if (j2 >>> 0 < 7) f2 = 158663784 >>> (j2 << 2) & 15; + else { + if (h2 >>> 0 < 7) { + f2 = 266017486 >>> (h2 << 2) & 15; + break; + } + if ((f2 | 0) == (c[ga3 >> 2] | 0)) { + f2 = 2; + break f; + } + if ((f2 | 0) == (c[ha3 >> 2] | 0)) { + f2 = 3; + break f; + } + f2 = f2 + 15 | 0; + } + while (0); + if (!f2) break e; + } else f2 = 1; + while (0); + c[ha3 >> 2] = c[ga3 >> 2]; + c[ga3 >> 2] = c[ia3 >> 2]; + c[ia3 >> 2] = c[o2 >> 2]; + c[o2 >> 2] = c[P3 >> 2]; + m3 = c[pa3 >> 2] | 0; + } + } else f2 = f2 + 15 | 0; + while (0); + w2 = N3 + 16 | 0; + Ga3 = c[O3 >> 2] | 0; + j2 = m3 ^ Ga3; + c[N3 >> 2] = x3; + c[N3 + 4 >> 2] = m3 | Ga3 << 24; + m3 = N3 + 14 | 0; + if (f2 >>> 0 < 16) { + f2 = f2 & 65535; + b2[m3 >> 1] = f2; + m3 = 0; + } else { + M2 = f2 + -12 | 0; + Ga3 = ((aa(M2 | 0) | 0) ^ 31) + -1 | 0; + Fa3 = M2 >>> Ga3 & 1; + f2 = ((Ga3 << 1) + 65534 | Fa3) + 16 & 65535; + b2[m3 >> 1] = f2; + m3 = Ga3 << 24 | M2 - ((Fa3 | 2) << Ga3); + } + c[N3 + 8 >> 2] = m3; + u3 = f2 << 16 >> 16 == 0; + v3 = N3 + 12 | 0; + do + if (x3 >>> 0 >= 6) { + if (x3 >>> 0 < 130) { + Ga3 = x3 + -2 | 0; + h2 = ((aa(Ga3 | 0) | 0) ^ 31) + -1 | 0; + h2 = (h2 << 1) + (Ga3 >>> h2) + 2 & 65535; + break; + } + if (x3 >>> 0 < 2114) { + h2 = ((aa(x3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (x3 >>> 0 < 6210) h2 = 21; + else h2 = x3 >>> 0 < 22594 ? 22 : 23; + } else h2 = x3 & 65535; + while (0); + do + if (j2 >>> 0 >= 10) { + if (j2 >>> 0 < 134) { + Ga3 = j2 + -6 | 0; + f2 = ((aa(Ga3 | 0) | 0) ^ 31) + -1 | 0; + f2 = (f2 << 1) + (Ga3 >>> f2) + 4 & 65535; + break; + } + if (j2 >>> 0 < 2118) f2 = ((aa(j2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else f2 = 23; + } else f2 = j2 + 65534 & 65535; + while (0); + m3 = f2 & 65535; + j2 = h2 & 65535; + g3 = m3 & 7 | j2 << 3 & 56; + if (u3 & (h2 & 65535) < 8 & (f2 & 65535) < 16) f2 = ((f2 & 65535) < 8 ? g3 : g3 | 64) & 65535; + else f2 = b2[88156 + ((m3 >>> 3) + ((j2 >>> 3) * 3 | 0) << 1) >> 1] | g3 & 65535; + b2[v3 >> 1] = f2; + c[s2 >> 2] = (c[s2 >> 2] | 0) + x3; + f2 = y3 + (c[pa3 >> 2] | 0) | 0; + f2 = f2 >>> 0 < ma3 >>> 0 ? f2 : ma3; + m3 = y3 + 2 | 0; + while (1) { + if (m3 >>> 0 >= f2 >>> 0) break; + Ga3 = k2 + (m3 & l2) | 0; + Ga3 = (_(d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Fa3 = b2[U3 >> 1] | 0; + b2[U3 >> 1] = Fa3 + 1 << 16 >> 16; + M2 = Fa3 & 65535; + N3 = n2 + (Ga3 << 2) | 0; + L3 = m3 - (c[N3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (M2 << 2) >> 1] = L3 >>> 0 > 65535 ? 65535 : L3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (M2 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[N3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + m3 = m3 + 1 | 0; + } + m3 = y3 + (c[pa3 >> 2] | 0) | 0; + N3 = w2; + f2 = 0; + } + c[p2 >> 2] = f2 + K3; + c[r2 >> 2] = (c[r2 >> 2] | 0) + (L3 - q2 >> 4); + i = sa3; + return; + } + function Ta2(f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2, s2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0; + ra3 = i; + i = i + 32 | 0; + pa3 = ra3 + 16 | 0; + qa3 = ra3; + na2 = (1 << c[m3 + 8 >> 2]) + -16 | 0; + u3 = c[p2 >> 2] | 0; + oa3 = h2 + g3 | 0; + ma3 = g3 >>> 0 > 3 ? oa3 + -3 | 0 : h2; + la3 = m3 + 4 | 0; + ia3 = c[la3 >> 2] | 0; + ja3 = (ia3 | 0) < 9 ? 64 : 512; + t3 = ja3 + h2 | 0; + ka3 = n2 + 1311756 | 0; + c[ka3 >> 2] = ((ia3 | 0) > 6 ? 7 : 8) << ia3 + -4; + if ((((h2 | 0) == 0 ^ 1 | j2 ^ 1) ^ 1) & g3 >>> 0 < 513) { + f2 = 0; + while (1) { + if ((f2 | 0) == (g3 | 0)) break; + ia3 = k2 + f2 | 0; + ia3 = (_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + c[n2 + (ia3 << 2) >> 2] = -858993460; + b2[n2 + 131072 + (ia3 << 1) >> 1] = -13108; + f2 = f2 + 1 | 0; + } + ac(n2 + 196608 | 0, 0, 65536) | 0; + ac(n2 + 1310720 | 0, 0, 1024) | 0; + if (g3) { + a[n2 + 1311744 >> 0] = 0; + Ea3 = 8; + } + } else if (!(a[n2 + 1311744 >> 0] & 1)) Ea3 = 8; + else { + ac(n2 | 0, -52, 131072) | 0; + ac(n2 + 131072 | 0, 0, 131072) | 0; + ac(n2 + 1310720 | 0, 0, 1025) | 0; + Ea3 = 8; + } + if ((Ea3 | 0) == 8 ? g3 >>> 0 > 2 & h2 >>> 0 > 2 : 0) { + ea3 = h2 + -3 | 0; + ga3 = k2 + (ea3 & l2) | 0; + ga3 = (_(d[ga3 >> 0] | d[ga3 + 1 >> 0] << 8 | d[ga3 + 2 >> 0] << 16 | d[ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ia3 = ga3 & 511; + ha3 = n2 + 1310720 + (ia3 << 1) | 0; + fa3 = b2[ha3 >> 1] | 0; + b2[ha3 >> 1] = fa3 + 1 << 16 >> 16; + fa3 = fa3 & 511; + ha3 = n2 + (ga3 << 2) | 0; + da3 = ea3 - (c[ha3 >> 2] | 0) | 0; + a[(ea3 & 65535) + (n2 + 196608) >> 0] = ga3; + b2[n2 + 262144 + (ia3 << 11) + (fa3 << 2) >> 1] = da3 >>> 0 > 65535 ? 65535 : da3; + ga3 = n2 + 131072 + (ga3 << 1) | 0; + b2[n2 + 262144 + (ia3 << 11) + (fa3 << 2) + 2 >> 1] = b2[ga3 >> 1] | 0; + c[ha3 >> 2] = ea3; + b2[ga3 >> 1] = fa3; + ga3 = h2 + -2 | 0; + fa3 = k2 + (ga3 & l2) | 0; + fa3 = (_(d[fa3 >> 0] | d[fa3 + 1 >> 0] << 8 | d[fa3 + 2 >> 0] << 16 | d[fa3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ha3 = fa3 & 511; + ea3 = n2 + 1310720 + (ha3 << 1) | 0; + ia3 = b2[ea3 >> 1] | 0; + b2[ea3 >> 1] = ia3 + 1 << 16 >> 16; + ia3 = ia3 & 511; + ea3 = n2 + (fa3 << 2) | 0; + da3 = ga3 - (c[ea3 >> 2] | 0) | 0; + a[(ga3 & 65535) + (n2 + 196608) >> 0] = fa3; + b2[n2 + 262144 + (ha3 << 11) + (ia3 << 2) >> 1] = da3 >>> 0 > 65535 ? 65535 : da3; + fa3 = n2 + 131072 + (fa3 << 1) | 0; + b2[n2 + 262144 + (ha3 << 11) + (ia3 << 2) + 2 >> 1] = b2[fa3 >> 1] | 0; + c[ea3 >> 2] = ga3; + b2[fa3 >> 1] = ia3; + fa3 = h2 + -1 | 0; + ia3 = k2 + (fa3 & l2) | 0; + ia3 = (_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ea3 = ia3 & 511; + ga3 = n2 + 1310720 + (ea3 << 1) | 0; + ha3 = b2[ga3 >> 1] | 0; + b2[ga3 >> 1] = ha3 + 1 << 16 >> 16; + ha3 = ha3 & 511; + ga3 = n2 + (ia3 << 2) | 0; + da3 = fa3 - (c[ga3 >> 2] | 0) | 0; + a[(fa3 & 65535) + (n2 + 196608) >> 0] = ia3; + b2[n2 + 262144 + (ea3 << 11) + (ha3 << 2) >> 1] = da3 >>> 0 > 65535 ? 65535 : da3; + ia3 = n2 + 131072 + (ia3 << 1) | 0; + b2[n2 + 262144 + (ea3 << 11) + (ha3 << 2) + 2 >> 1] = b2[ia3 >> 1] | 0; + c[ga3 >> 2] = fa3; + b2[ia3 >> 1] = ha3; + } + P3 = pa3 + 4 | 0; + Q3 = pa3 + 8 | 0; + R3 = pa3 + 12 | 0; + S3 = pa3 + 4 | 0; + T3 = pa3 + 8 | 0; + U3 = pa3 + 12 | 0; + V3 = n2 + 1311752 | 0; + W3 = n2 + 1311748 | 0; + X3 = ja3 << 2; + Y3 = oa3 + -4 | 0; + Z3 = oa3 + -3 | 0; + $2 = qa3 + 12 | 0; + ba2 = qa3 + 4 | 0; + ca3 = qa3 + 8 | 0; + da3 = qa3 + 4 | 0; + ea3 = qa3 + 8 | 0; + fa3 = qa3 + 12 | 0; + ga3 = o2 + 8 | 0; + ha3 = o2 + 12 | 0; + ia3 = o2 + 4 | 0; + m3 = h2; + O3 = q2; + f2 = u3; + a: while (1) { + M2 = O3; + N3 = t3 + X3 | 0; + b: while (1) { + L3 = oa3 - m3 | 0; + if ((m3 + 4 | 0) >>> 0 >= oa3 >>> 0) break a; + J3 = m3 >>> 0 < na2 >>> 0 ? m3 : na2; + c[pa3 >> 2] = 0; + c[P3 >> 2] = 0; + c[Q3 >> 2] = 0; + c[R3 >> 2] = 4240; + K3 = m3 & l2; + A3 = c[pa3 >> 2] | 0; + I3 = k2 + K3 | 0; + B3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + y3 = B3 & 255; + c[pa3 >> 2] = 0; + c[S3 >> 2] = 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + h2 = 4240; + j2 = 0; + z3 = 0; + while (1) { + if ((z3 | 0) == 16) break; + x3 = (c[o2 + (c[11372 + (z3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (z3 << 2) >> 2] | 0) | 0; + g3 = m3 - x3 | 0; + if (!z3) if (g3 >>> 0 >= m3 >>> 0 | x3 >>> 0 > J3 >>> 0) g3 = A3; + else Ea3 = 17; + else if ((g3 >>> 0 < m3 >>> 0 ? (a[(g3 & 65535) + (n2 + 196608) >> 0] | 0) == y3 << 24 >> 24 : 0) ^ 1 | x3 >>> 0 > J3 >>> 0) g3 = A3; + else Ea3 = 17; + if ((Ea3 | 0) == 17) { + Ea3 = 0; + w2 = g3 & l2; + g3 = 0; + u3 = F3; + while (1) { + v3 = u3; + if (v3 >>> 0 > H3 >>> 0) break; + D3 = u3; + E3 = k2 + (w2 + g3) | 0; + if ((d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0) != (d[E3 >> 0] | d[E3 + 1 >> 0] << 8 | d[E3 + 2 >> 0] << 16 | d[E3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + u3 = v3 + 4 | 0; + } + while (1) { + if (u3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (w2 + g3) >> 0] | 0) != (a[u3 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + u3 = u3 + 1 | 0; + } + if (g3 >>> 0 > 1 ? (sa3 = (g3 * 540 | 0) + (c[11500 + (z3 << 2) >> 2] | 0) | 0, h2 >>> 0 < sa3 >>> 0) : 0) { + c[pa3 >> 2] = g3; + c[T3 >> 2] = x3; + c[U3 >> 2] = sa3; + h2 = sa3; + j2 = 1; + } else g3 = A3; + } + A3 = g3; + z3 = z3 + 1 | 0; + } + E3 = B3 & 511; + w2 = 0; + u3 = m3 - (c[n2 + (B3 << 2) >> 2] | 0) | 0; + v3 = c[ka3 >> 2] | 0; + g3 = e[n2 + 131072 + (B3 << 1) >> 1] | 0; + c: while (1) { + D3 = K3 + A3 | 0; + C3 = D3 >>> 0 > l2 >>> 0; + D3 = k2 + D3 | 0; + x3 = w2; + y3 = u3; + z3 = v3; + B3 = g3; + while (1) { + w2 = z3; + z3 = z3 + -1 | 0; + if (!w2) break c; + x3 = x3 + y3 | 0; + if (x3 >>> 0 > J3 >>> 0) break c; + w2 = m3 - x3 & l2; + y3 = B3; + B3 = e[n2 + 262144 + (E3 << 11) + (B3 << 2) + 2 >> 1] | 0; + y3 = e[n2 + 262144 + (E3 << 11) + (y3 << 2) >> 1] | 0; + if (C3) continue; + g3 = w2 + A3 | 0; + if (g3 >>> 0 > l2 >>> 0) continue; + if ((a[D3 >> 0] | 0) == (a[k2 + g3 >> 0] | 0)) { + v3 = 0; + g3 = F3; + } else continue; + while (1) { + u3 = g3; + if (u3 >>> 0 > H3 >>> 0) break; + Ga3 = g3; + Fa3 = k2 + (w2 + v3) | 0; + if ((d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0) != (d[Fa3 >> 0] | d[Fa3 + 1 >> 0] << 8 | d[Fa3 + 2 >> 0] << 16 | d[Fa3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + g3 = u3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (w2 + v3) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (v3 >>> 0 <= 3) continue; + g3 = (v3 * 540 | 0) + 3840 + (_((aa(x3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (h2 >>> 0 < g3 >>> 0) break; + } + c[pa3 >> 2] = v3; + c[T3 >> 2] = x3; + c[U3 >> 2] = g3; + w2 = x3; + A3 = v3; + h2 = g3; + u3 = y3; + v3 = z3; + j2 = 1; + g3 = B3; + } + Ga3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + G3 = Ga3 & 511; + H3 = n2 + 1310720 + (G3 << 1) | 0; + Fa3 = b2[H3 >> 1] | 0; + b2[H3 >> 1] = Fa3 + 1 << 16 >> 16; + Fa3 = Fa3 & 511; + H3 = n2 + (Ga3 << 2) | 0; + F3 = m3 - (c[H3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (G3 << 11) + (Fa3 << 2) >> 1] = F3 >>> 0 > 65535 ? 65535 : F3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (G3 << 11) + (Fa3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[H3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + if (!(j2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) j2 = 0; + else { + x3 = 0; + j2 = 0; + w2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((x3 | 0) == 2) break; + Ga3 = b2[21084 + (w2 << 1) >> 1] | 0; + g3 = Ga3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ga3 << 16 >> 16 != 0 ? (ta3 = g3 & 31, ua3 = g3 >>> 5, va3 = (c[11272 + (ta3 << 2) >> 2] | 0) + (_(ta3, ua3) | 0) | 0, ta3 >>> 0 <= L3 >>> 0) : 0) { + h2 = va3 + ta3 | 0; + v3 = 280811 + h2 | 0; + h2 = 280811 + (h2 + -4) | 0; + u3 = 0; + g3 = 280811 + va3 | 0; + while (1) { + if (g3 >>> 0 > h2 >>> 0) break; + Ga3 = k2 + (K3 + u3) | 0; + if ((d[g3 >> 0] | d[g3 + 1 >> 0] << 8 | d[g3 + 2 >> 0] << 16 | d[g3 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + u3 = u3 + 4 | 0; + g3 = g3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= v3 >>> 0) break; + if ((a[k2 + (K3 + u3) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + u3 = u3 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (!((u3 + 10 | 0) >>> 0 <= ta3 >>> 0 | (u3 | 0) == 0) ? (wa3 = J3 + ua3 + 1 + (d[407930 + (ta3 - u3) >> 0] << d[280786 + ta3 >> 0]) | 0, xa3 = (u3 * 540 | 0) + 3840 + (_((aa(wa3 | 0) | 0) ^ 31, -120) | 0) | 0, xa3 >>> 0 >= (c[U3 >> 2] | 0) >>> 0) : 0) { + c[pa3 >> 2] = u3; + c[S3 >> 2] = ta3 ^ u3; + c[T3 >> 2] = wa3; + c[U3 >> 2] = xa3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + j2 = 1; + } + } + x3 = x3 + 1 | 0; + w2 = w2 + 1 | 0; + } + j2 = (j2 & 1) != 0; + } + j2 = j2 & 1; + } + if (j2 & 1) { + M2 = 0; + x3 = f2; + break; + } + f2 = f2 + 1 | 0; + g3 = m3 + 1 | 0; + if (g3 >>> 0 <= t3 >>> 0) { + m3 = g3; + continue; + } + if (g3 >>> 0 > N3 >>> 0) { + j2 = m3 + 17 | 0; + j2 = j2 >>> 0 < Y3 >>> 0 ? j2 : Y3; + m3 = g3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ga3 = k2 + (m3 & l2) | 0; + Ga3 = (_(d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + K3 = Ga3 & 511; + L3 = n2 + 1310720 + (K3 << 1) | 0; + Fa3 = b2[L3 >> 1] | 0; + b2[L3 >> 1] = Fa3 + 1 << 16 >> 16; + Fa3 = Fa3 & 511; + L3 = n2 + (Ga3 << 2) | 0; + J3 = m3 - (c[L3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (K3 << 11) + (Fa3 << 2) >> 1] = J3 >>> 0 > 65535 ? 65535 : J3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (K3 << 11) + (Fa3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[L3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + m3 = m3 + 4 | 0; + f2 = f2 + 4 | 0; + } + } else { + j2 = m3 + 9 | 0; + j2 = j2 >>> 0 < Z3 >>> 0 ? j2 : Z3; + m3 = g3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ga3 = k2 + (m3 & l2) | 0; + Ga3 = (_(d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + K3 = Ga3 & 511; + L3 = n2 + 1310720 + (K3 << 1) | 0; + Fa3 = b2[L3 >> 1] | 0; + b2[L3 >> 1] = Fa3 + 1 << 16 >> 16; + Fa3 = Fa3 & 511; + L3 = n2 + (Ga3 << 2) | 0; + J3 = m3 - (c[L3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (K3 << 11) + (Fa3 << 2) >> 1] = J3 >>> 0 > 65535 ? 65535 : J3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (K3 << 11) + (Fa3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[L3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + m3 = m3 + 2 | 0; + f2 = f2 + 2 | 0; + } + } + } + while (1) { + L3 = L3 + -1 | 0; + if ((c[la3 >> 2] | 0) < 5) { + f2 = (c[pa3 >> 2] | 0) + -1 | 0; + f2 = f2 >>> 0 < L3 >>> 0 ? f2 : L3; + } else f2 = 0; + c[qa3 >> 2] = f2; + c[ba2 >> 2] = 0; + c[ca3 >> 2] = 0; + c[$2 >> 2] = 4240; + y3 = m3 + 1 | 0; + J3 = y3 >>> 0 < na2 >>> 0 ? y3 : na2; + K3 = y3 & l2; + A3 = c[qa3 >> 2] | 0; + I3 = k2 + K3 | 0; + B3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + w2 = B3 & 255; + c[qa3 >> 2] = 0; + c[da3 >> 2] = 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + g3 = 4240; + f2 = 0; + z3 = 0; + while (1) { + if ((z3 | 0) == 16) break; + v3 = (c[o2 + (c[11372 + (z3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (z3 << 2) >> 2] | 0) | 0; + j2 = y3 - v3 | 0; + if (!z3) if (j2 >>> 0 >= y3 >>> 0 | v3 >>> 0 > J3 >>> 0) j2 = A3; + else Ea3 = 71; + else if ((j2 >>> 0 < y3 >>> 0 ? (a[(j2 & 65535) + (n2 + 196608) >> 0] | 0) == w2 << 24 >> 24 : 0) ^ 1 | v3 >>> 0 > J3 >>> 0) j2 = A3; + else Ea3 = 71; + if ((Ea3 | 0) == 71) { + Ea3 = 0; + u3 = j2 & l2; + j2 = 0; + t3 = F3; + while (1) { + h2 = t3; + if (h2 >>> 0 > H3 >>> 0) break; + Fa3 = t3; + Ga3 = k2 + (u3 + j2) | 0; + if ((d[Fa3 >> 0] | d[Fa3 + 1 >> 0] << 8 | d[Fa3 + 2 >> 0] << 16 | d[Fa3 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + j2 = j2 + 4 | 0; + t3 = h2 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (u3 + j2) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + j2 = j2 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (j2 >>> 0 > 1 ? (ya3 = (j2 * 540 | 0) + (c[11500 + (z3 << 2) >> 2] | 0) | 0, g3 >>> 0 < ya3 >>> 0) : 0) { + c[qa3 >> 2] = j2; + c[ea3 >> 2] = v3; + c[fa3 >> 2] = ya3; + g3 = ya3; + f2 = 1; + } else j2 = A3; + } + A3 = j2; + z3 = z3 + 1 | 0; + } + E3 = B3 & 511; + u3 = 0; + t3 = y3 - (c[n2 + (B3 << 2) >> 2] | 0) | 0; + h2 = c[ka3 >> 2] | 0; + j2 = e[n2 + 131072 + (B3 << 1) >> 1] | 0; + d: while (1) { + D3 = K3 + A3 | 0; + C3 = D3 >>> 0 > l2 >>> 0; + D3 = k2 + D3 | 0; + v3 = u3; + w2 = t3; + z3 = h2; + B3 = j2; + while (1) { + Ga3 = z3; + z3 = z3 + -1 | 0; + if (!Ga3) break d; + v3 = v3 + w2 | 0; + if (v3 >>> 0 > J3 >>> 0) break d; + u3 = y3 - v3 & l2; + w2 = B3; + B3 = e[n2 + 262144 + (E3 << 11) + (B3 << 2) + 2 >> 1] | 0; + w2 = e[n2 + 262144 + (E3 << 11) + (w2 << 2) >> 1] | 0; + if (C3) continue; + j2 = u3 + A3 | 0; + if (j2 >>> 0 > l2 >>> 0) continue; + if ((a[D3 >> 0] | 0) == (a[k2 + j2 >> 0] | 0)) { + h2 = 0; + j2 = F3; + } else continue; + while (1) { + t3 = j2; + if (t3 >>> 0 > H3 >>> 0) break; + Fa3 = j2; + Ga3 = k2 + (u3 + h2) | 0; + if ((d[Fa3 >> 0] | d[Fa3 + 1 >> 0] << 8 | d[Fa3 + 2 >> 0] << 16 | d[Fa3 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + j2 = t3 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (u3 + h2) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (h2 >>> 0 <= 3) continue; + j2 = (h2 * 540 | 0) + 3840 + (_((aa(v3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (g3 >>> 0 < j2 >>> 0) break; + } + c[qa3 >> 2] = h2; + c[ea3 >> 2] = v3; + c[fa3 >> 2] = j2; + u3 = v3; + A3 = h2; + g3 = j2; + t3 = w2; + h2 = z3; + f2 = 1; + j2 = B3; + } + Ga3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + H3 = Ga3 & 511; + N3 = n2 + 1310720 + (H3 << 1) | 0; + Fa3 = b2[N3 >> 1] | 0; + b2[N3 >> 1] = Fa3 + 1 << 16 >> 16; + Fa3 = Fa3 & 511; + N3 = n2 + (Ga3 << 2) | 0; + G3 = y3 - (c[N3 >> 2] | 0) | 0; + a[(y3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (H3 << 11) + (Fa3 << 2) >> 1] = G3 >>> 0 > 65535 ? 65535 : G3; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (H3 << 11) + (Fa3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[N3 >> 2] = y3; + b2[Ga3 >> 1] = Fa3; + if (!(f2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) f2 = 0; + else { + v3 = 0; + f2 = 0; + u3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 2) break; + Ga3 = b2[21084 + (u3 << 1) >> 1] | 0; + j2 = Ga3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ga3 << 16 >> 16 != 0 ? (za3 = j2 & 31, Aa3 = j2 >>> 5, Ba3 = (c[11272 + (za3 << 2) >> 2] | 0) + (_(za3, Aa3) | 0) | 0, za3 >>> 0 <= L3 >>> 0) : 0) { + g3 = Ba3 + za3 | 0; + h2 = 280811 + g3 | 0; + g3 = 280811 + (g3 + -4) | 0; + t3 = 0; + j2 = 280811 + Ba3 | 0; + while (1) { + if (j2 >>> 0 > g3 >>> 0) break; + Ga3 = k2 + (K3 + t3) | 0; + if ((d[j2 >> 0] | d[j2 + 1 >> 0] << 8 | d[j2 + 2 >> 0] << 16 | d[j2 + 3 >> 0] << 24 | 0) != (d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24 | 0)) break; + t3 = t3 + 4 | 0; + j2 = j2 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= h2 >>> 0) break; + if ((a[k2 + (K3 + t3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + t3 = t3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (!((t3 + 10 | 0) >>> 0 <= za3 >>> 0 | (t3 | 0) == 0) ? (Ca3 = J3 + Aa3 + 1 + (d[407930 + (za3 - t3) >> 0] << d[280786 + za3 >> 0]) | 0, Da3 = (t3 * 540 | 0) + 3840 + (_((aa(Ca3 | 0) | 0) ^ 31, -120) | 0) | 0, Da3 >>> 0 >= (c[fa3 >> 2] | 0) >>> 0) : 0) { + c[qa3 >> 2] = t3; + c[da3 >> 2] = za3 ^ t3; + c[ea3 >> 2] = Ca3; + c[fa3 >> 2] = Da3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + f2 = 1; + } + } + v3 = v3 + 1 | 0; + u3 = u3 + 1 | 0; + } + f2 = (f2 & 1) != 0; + } + f2 = f2 & 1; + } + if (!(f2 & 1)) { + y3 = m3; + break; + } + if ((c[$2 >> 2] | 0) >>> 0 < ((c[R3 >> 2] | 0) + 700 | 0) >>> 0) { + y3 = m3; + break; + } + f2 = x3 + 1 | 0; + c[pa3 >> 2] = c[qa3 >> 2]; + c[pa3 + 4 >> 2] = c[qa3 + 4 >> 2]; + c[pa3 + 8 >> 2] = c[qa3 + 8 >> 2]; + c[pa3 + 12 >> 2] = c[qa3 + 12 >> 2]; + M2 = M2 + 1 | 0; + if (!((M2 | 0) < 4 & (m3 + 5 | 0) >>> 0 < oa3 >>> 0)) { + x3 = f2; + break; + } else { + m3 = y3; + x3 = f2; + } + } + m3 = c[pa3 >> 2] | 0; + t3 = y3 + (m3 << 1) + ja3 | 0; + f2 = c[Q3 >> 2] | 0; + e: do + if (f2 >>> 0 <= (y3 >>> 0 < na2 >>> 0 ? y3 : na2) >>> 0) { + h2 = f2 + 3 | 0; + Ga3 = c[o2 >> 2] | 0; + j2 = h2 - Ga3 | 0; + g3 = c[ia3 >> 2] | 0; + h2 = h2 - g3 | 0; + if ((f2 | 0) == (Ga3 | 0)) f2 = 0; + else { + f: do + if ((f2 | 0) != (g3 | 0)) { + do + if (j2 >>> 0 < 7) f2 = 158663784 >>> (j2 << 2) & 15; + else { + if (h2 >>> 0 < 7) { + f2 = 266017486 >>> (h2 << 2) & 15; + break; + } + if ((f2 | 0) == (c[ga3 >> 2] | 0)) { + f2 = 2; + break f; + } + if ((f2 | 0) == (c[ha3 >> 2] | 0)) { + f2 = 3; + break f; + } + f2 = f2 + 15 | 0; + } + while (0); + if (!f2) break e; + } else f2 = 1; + while (0); + c[ha3 >> 2] = c[ga3 >> 2]; + c[ga3 >> 2] = c[ia3 >> 2]; + c[ia3 >> 2] = c[o2 >> 2]; + c[o2 >> 2] = c[Q3 >> 2]; + m3 = c[pa3 >> 2] | 0; + } + } else f2 = f2 + 15 | 0; + while (0); + w2 = O3 + 16 | 0; + Ga3 = c[P3 >> 2] | 0; + j2 = m3 ^ Ga3; + c[O3 >> 2] = x3; + c[O3 + 4 >> 2] = m3 | Ga3 << 24; + m3 = O3 + 14 | 0; + if (f2 >>> 0 < 16) { + f2 = f2 & 65535; + b2[m3 >> 1] = f2; + m3 = 0; + } else { + N3 = f2 + -12 | 0; + Ga3 = ((aa(N3 | 0) | 0) ^ 31) + -1 | 0; + Fa3 = N3 >>> Ga3 & 1; + f2 = ((Ga3 << 1) + 65534 | Fa3) + 16 & 65535; + b2[m3 >> 1] = f2; + m3 = Ga3 << 24 | N3 - ((Fa3 | 2) << Ga3); + } + c[O3 + 8 >> 2] = m3; + u3 = f2 << 16 >> 16 == 0; + v3 = O3 + 12 | 0; + do + if (x3 >>> 0 >= 6) { + if (x3 >>> 0 < 130) { + Ga3 = x3 + -2 | 0; + h2 = ((aa(Ga3 | 0) | 0) ^ 31) + -1 | 0; + h2 = (h2 << 1) + (Ga3 >>> h2) + 2 & 65535; + break; + } + if (x3 >>> 0 < 2114) { + h2 = ((aa(x3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (x3 >>> 0 < 6210) h2 = 21; + else h2 = x3 >>> 0 < 22594 ? 22 : 23; + } else h2 = x3 & 65535; + while (0); + do + if (j2 >>> 0 >= 10) { + if (j2 >>> 0 < 134) { + Ga3 = j2 + -6 | 0; + f2 = ((aa(Ga3 | 0) | 0) ^ 31) + -1 | 0; + f2 = (f2 << 1) + (Ga3 >>> f2) + 4 & 65535; + break; + } + if (j2 >>> 0 < 2118) f2 = ((aa(j2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else f2 = 23; + } else f2 = j2 + 65534 & 65535; + while (0); + m3 = f2 & 65535; + j2 = h2 & 65535; + g3 = m3 & 7 | j2 << 3 & 56; + if (u3 & (h2 & 65535) < 8 & (f2 & 65535) < 16) f2 = ((f2 & 65535) < 8 ? g3 : g3 | 64) & 65535; + else f2 = b2[88156 + ((m3 >>> 3) + ((j2 >>> 3) * 3 | 0) << 1) >> 1] | g3 & 65535; + b2[v3 >> 1] = f2; + c[s2 >> 2] = (c[s2 >> 2] | 0) + x3; + f2 = y3 + (c[pa3 >> 2] | 0) | 0; + f2 = f2 >>> 0 < ma3 >>> 0 ? f2 : ma3; + m3 = y3 + 2 | 0; + while (1) { + if (m3 >>> 0 >= f2 >>> 0) break; + Ga3 = k2 + (m3 & l2) | 0; + Ga3 = (_(d[Ga3 >> 0] | d[Ga3 + 1 >> 0] << 8 | d[Ga3 + 2 >> 0] << 16 | d[Ga3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + N3 = Ga3 & 511; + O3 = n2 + 1310720 + (N3 << 1) | 0; + Fa3 = b2[O3 >> 1] | 0; + b2[O3 >> 1] = Fa3 + 1 << 16 >> 16; + Fa3 = Fa3 & 511; + O3 = n2 + (Ga3 << 2) | 0; + M2 = m3 - (c[O3 >> 2] | 0) | 0; + a[(m3 & 65535) + (n2 + 196608) >> 0] = Ga3; + b2[n2 + 262144 + (N3 << 11) + (Fa3 << 2) >> 1] = M2 >>> 0 > 65535 ? 65535 : M2; + Ga3 = n2 + 131072 + (Ga3 << 1) | 0; + b2[n2 + 262144 + (N3 << 11) + (Fa3 << 2) + 2 >> 1] = b2[Ga3 >> 1] | 0; + c[O3 >> 2] = m3; + b2[Ga3 >> 1] = Fa3; + m3 = m3 + 1 | 0; + } + m3 = y3 + (c[pa3 >> 2] | 0) | 0; + O3 = w2; + f2 = 0; + } + c[p2 >> 2] = f2 + L3; + c[r2 >> 2] = (c[r2 >> 2] | 0) + (M2 - q2 >> 4); + i = ra3; + return; + } + function Ua2(b3, d2, e2, f2, g3, h2) { + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + var i2 = 0, j2 = 0; + j2 = d2 + 524304 | 0; + if (!(a[j2 >> 0] & 1)) return; + e2 = 1 << c[e2 + 8 >> 2]; + c[d2 >> 2] = e2 + -1; + e2 = 1 - e2 | 0; + c[d2 + 524296 >> 2] = e2; + c.fill(e2, d2 + 4 >> 2, (d2 + 4 >> 2) + 131072); + i2 = 131072; + if ((f2 | 0) == 0 ^ 1 | h2 ^ 1) g3 = (c[d2 >> 2] | 0) + 1 | 0; + h2 = d2 + 524300 | 0; + do + if (g3 >>> 0 > (c[h2 >> 2] | 0) >>> 0) { + i2 = d2 + 524292 | 0; + e2 = b3 + 8 | 0; + ra2[c[b3 + 4 >> 2] & 1](c[e2 >> 2] | 0, c[i2 >> 2] | 0); + c[i2 >> 2] = 0; + e2 = sa2[c[b3 >> 2] & 1](c[e2 >> 2] | 0, g3 << 3) | 0; + if (!e2) oa2(1); + else { + c[i2 >> 2] = e2; + c[h2 >> 2] = g3; + break; + } + } + while (0); + a[j2 >> 0] = 0; + return; + } + function Va2(a2, b3, d2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + var e2 = 0, f2 = 0, h2 = 0, i2 = 0, j2 = 0, k2 = 0; + f2 = 0; + h2 = 0; + while (1) { + if ((f2 | 0) == (b3 | 0)) break; + k2 = h2 + (c[a2 + (f2 << 2) >> 2] | 0) | 0; + f2 = f2 + 1 | 0; + h2 = k2; + } + if (h2 >>> 0 < 256) e2 = +g2[19516 + (h2 << 2) >> 2]; + else e2 = +Xb(+(h2 >>> 0)); + j2 = e2 + 2; + h2 = 0; + while (1) { + if ((h2 | 0) == (b3 | 0)) break; + f2 = c[a2 + (h2 << 2) >> 2] | 0; + if (f2) { + if (f2 >>> 0 < 256) i2 = +g2[19516 + (f2 << 2) >> 2]; + else i2 = +Xb(+(f2 >>> 0)); + i2 = e2 - i2; + f2 = d2 + (h2 << 2) | 0; + g2[f2 >> 2] = i2; + if (i2 < 1) g2[f2 >> 2] = 1; + } else g2[d2 + (h2 << 2) >> 2] = j2; + h2 = h2 + 1 | 0; + } + return; + } + function Wa2(a2) { + a2 = a2 | 0; + var b3 = 0, d2 = 0, e2 = 0, f2 = 0, h2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0; + s2 = i; + i = i + 112 | 0; + m3 = s2 + 88 | 0; + p2 = s2 + 72 | 0; + r2 = s2; + n2 = c[a2 + 1024 >> 2] | 0; + if (!n2) { + q2 = 12; + i = s2; + return +q2; + } else { + f2 = 0; + l2 = 0; + } + while (1) { + if (l2 >>> 0 >= 256) { + d2 = f2; + break; + } + if (c[a2 + (l2 << 2) >> 2] | 0) { + c[m3 + (f2 << 2) >> 2] = l2; + d2 = f2 + 1 | 0; + if ((f2 | 0) > 3) break; + } else d2 = f2; + f2 = d2; + l2 = l2 + 1 | 0; + } + switch (d2 | 0) { + case 2: { + q2 = +(n2 >>> 0) + 20; + i = s2; + return +q2; + } + case 3: { + p2 = c[a2 + (c[m3 >> 2] << 2) >> 2] | 0; + n2 = c[a2 + (c[m3 + 4 >> 2] << 2) >> 2] | 0; + a2 = c[a2 + (c[m3 + 8 >> 2] << 2) >> 2] | 0; + r2 = n2 >>> 0 > a2 >>> 0 ? n2 : a2; + q2 = +(p2 + n2 + a2 << 1 >>> 0) + 28 - +((p2 >>> 0 > r2 >>> 0 ? p2 : r2) >>> 0); + i = s2; + return +q2; + } + case 4: { + d2 = 0; + while (1) { + if ((d2 | 0) == 4) { + n2 = 0; + break; + } + c[p2 + (d2 << 2) >> 2] = c[a2 + (c[m3 + (d2 << 2) >> 2] << 2) >> 2]; + d2 = d2 + 1 | 0; + } + while (1) { + if ((n2 | 0) == 4) break; + m3 = p2 + (n2 << 2) | 0; + d2 = n2; + while (1) { + a2 = d2 + 1 | 0; + if ((d2 | 0) == 3) break; + d2 = p2 + (a2 << 2) | 0; + f2 = c[d2 >> 2] | 0; + l2 = c[m3 >> 2] | 0; + if (f2 >>> 0 <= l2 >>> 0) { + d2 = a2; + continue; + } + c[d2 >> 2] = l2; + c[m3 >> 2] = f2; + d2 = a2; + } + n2 = n2 + 1 | 0; + } + a2 = (c[p2 + 8 >> 2] | 0) + (c[p2 + 12 >> 2] | 0) | 0; + r2 = c[p2 >> 2] | 0; + q2 = +((a2 * 3 | 0) >>> 0) + 37 + +(r2 + (c[p2 + 4 >> 2] | 0) << 1 >>> 0) - +((a2 >>> 0 > r2 >>> 0 ? a2 : r2) >>> 0); + i = s2; + return +q2; + } + case 1: { + q2 = 12; + i = s2; + return +q2; + } + default: { + d2 = r2; + f2 = d2 + 72 | 0; + do { + c[d2 >> 2] = 0; + d2 = d2 + 4 | 0; + } while ((d2 | 0) < (f2 | 0)); + if (n2 >>> 0 < 256) h2 = +g2[19516 + (n2 << 2) >> 2]; + else h2 = +Xb(+(n2 >>> 0)); + m3 = r2 + 68 | 0; + b3 = 0; + d2 = 0; + n2 = 1; + a: while (1) { + q2 = b3; + b: while (1) { + while (1) { + if (d2 >>> 0 >= 256) break a; + f2 = c[a2 + (d2 << 2) >> 2] | 0; + if (!f2) { + l2 = 1; + f2 = d2; + } else break b; + while (1) { + f2 = f2 + 1 | 0; + if (f2 >>> 0 >= 256) break; + if (c[a2 + (f2 << 2) >> 2] | 0) break; + l2 = l2 + 1 | 0; + } + d2 = d2 + l2 | 0; + if ((d2 | 0) == 256) break a; + if (l2 >>> 0 >= 3) break; + c[r2 >> 2] = (c[r2 >> 2] | 0) + l2; + } + b3 = q2; + f2 = l2 + -2 | 0; + while (1) { + if (!f2) { + q2 = b3; + continue b; + } + c[m3 >> 2] = (c[m3 >> 2] | 0) + 1; + b3 = b3 + 3; + f2 = f2 >>> 3; + } + } + if (f2 >>> 0 < 256) { + e2 = +(f2 >>> 0); + b3 = +g2[19516 + (f2 << 2) >> 2]; + } else { + b3 = +(f2 >>> 0); + e2 = b3; + b3 = +Xb(b3); + } + b3 = h2 - b3; + p2 = ~~(b3 + 0.5) >>> 0; + p2 = p2 >>> 0 > 15 ? 15 : p2; + l2 = r2 + (p2 << 2) | 0; + c[l2 >> 2] = (c[l2 >> 2] | 0) + 1; + b3 = q2 + e2 * b3; + d2 = d2 + 1 | 0; + n2 = p2 >>> 0 > n2 >>> 0 ? p2 : n2; + } + o2 = +(((n2 << 1) + 18 | 0) >>> 0); + m3 = r2 + 72 | 0; + d2 = r2; + b3 = 0; + n2 = 0; + while (1) { + if (d2 >>> 0 >= m3 >>> 0) break; + f2 = c[d2 >> 2] | 0; + e2 = +(f2 >>> 0); + if (f2 >>> 0 < 256) k2 = +g2[19516 + (f2 << 2) >> 2]; + else k2 = +Xb(e2); + l2 = c[d2 + 4 >> 2] | 0; + h2 = +(l2 >>> 0); + if (l2 >>> 0 < 256) j2 = +g2[19516 + (l2 << 2) >> 2]; + else j2 = +Xb(h2); + d2 = d2 + 8 | 0; + b3 = b3 - e2 * k2 - h2 * j2; + n2 = n2 + f2 + l2 | 0; + } + k2 = q2 + o2; + j2 = +(n2 >>> 0); + if (!n2) h2 = j2; + else { + if (n2 >>> 0 < 256) e2 = +g2[19516 + (n2 << 2) >> 2]; + else e2 = +Xb(j2); + h2 = j2; + b3 = b3 + j2 * e2; + } + q2 = k2 + (b3 < h2 ? h2 : b3); + i = s2; + return +q2; + } + } + return 0; + } + function Xa2(a2) { + a2 = a2 | 0; + var b3 = 0, d2 = 0, e2 = 0, f2 = 0, h2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0; + s2 = i; + i = i + 112 | 0; + m3 = s2 + 88 | 0; + p2 = s2 + 72 | 0; + r2 = s2; + n2 = c[a2 + 2816 >> 2] | 0; + if (!n2) { + q2 = 12; + i = s2; + return +q2; + } else { + f2 = 0; + l2 = 0; + } + while (1) { + if (l2 >>> 0 >= 704) { + d2 = f2; + break; + } + if (c[a2 + (l2 << 2) >> 2] | 0) { + c[m3 + (f2 << 2) >> 2] = l2; + d2 = f2 + 1 | 0; + if ((f2 | 0) > 3) break; + } else d2 = f2; + f2 = d2; + l2 = l2 + 1 | 0; + } + switch (d2 | 0) { + case 2: { + q2 = +(n2 >>> 0) + 20; + i = s2; + return +q2; + } + case 3: { + p2 = c[a2 + (c[m3 >> 2] << 2) >> 2] | 0; + n2 = c[a2 + (c[m3 + 4 >> 2] << 2) >> 2] | 0; + a2 = c[a2 + (c[m3 + 8 >> 2] << 2) >> 2] | 0; + r2 = n2 >>> 0 > a2 >>> 0 ? n2 : a2; + q2 = +(p2 + n2 + a2 << 1 >>> 0) + 28 - +((p2 >>> 0 > r2 >>> 0 ? p2 : r2) >>> 0); + i = s2; + return +q2; + } + case 4: { + d2 = 0; + while (1) { + if ((d2 | 0) == 4) { + n2 = 0; + break; + } + c[p2 + (d2 << 2) >> 2] = c[a2 + (c[m3 + (d2 << 2) >> 2] << 2) >> 2]; + d2 = d2 + 1 | 0; + } + while (1) { + if ((n2 | 0) == 4) break; + m3 = p2 + (n2 << 2) | 0; + d2 = n2; + while (1) { + a2 = d2 + 1 | 0; + if ((d2 | 0) == 3) break; + d2 = p2 + (a2 << 2) | 0; + f2 = c[d2 >> 2] | 0; + l2 = c[m3 >> 2] | 0; + if (f2 >>> 0 <= l2 >>> 0) { + d2 = a2; + continue; + } + c[d2 >> 2] = l2; + c[m3 >> 2] = f2; + d2 = a2; + } + n2 = n2 + 1 | 0; + } + a2 = (c[p2 + 8 >> 2] | 0) + (c[p2 + 12 >> 2] | 0) | 0; + r2 = c[p2 >> 2] | 0; + q2 = +((a2 * 3 | 0) >>> 0) + 37 + +(r2 + (c[p2 + 4 >> 2] | 0) << 1 >>> 0) - +((a2 >>> 0 > r2 >>> 0 ? a2 : r2) >>> 0); + i = s2; + return +q2; + } + case 1: { + q2 = 12; + i = s2; + return +q2; + } + default: { + d2 = r2; + f2 = d2 + 72 | 0; + do { + c[d2 >> 2] = 0; + d2 = d2 + 4 | 0; + } while ((d2 | 0) < (f2 | 0)); + if (n2 >>> 0 < 256) h2 = +g2[19516 + (n2 << 2) >> 2]; + else h2 = +Xb(+(n2 >>> 0)); + m3 = r2 + 68 | 0; + b3 = 0; + d2 = 0; + n2 = 1; + a: while (1) { + q2 = b3; + b: while (1) { + while (1) { + if (d2 >>> 0 >= 704) break a; + f2 = c[a2 + (d2 << 2) >> 2] | 0; + if (!f2) { + l2 = 1; + f2 = d2; + } else break b; + while (1) { + f2 = f2 + 1 | 0; + if (f2 >>> 0 >= 704) break; + if (c[a2 + (f2 << 2) >> 2] | 0) break; + l2 = l2 + 1 | 0; + } + d2 = d2 + l2 | 0; + if ((d2 | 0) == 704) break a; + if (l2 >>> 0 >= 3) break; + c[r2 >> 2] = (c[r2 >> 2] | 0) + l2; + } + b3 = q2; + f2 = l2 + -2 | 0; + while (1) { + if (!f2) { + q2 = b3; + continue b; + } + c[m3 >> 2] = (c[m3 >> 2] | 0) + 1; + b3 = b3 + 3; + f2 = f2 >>> 3; + } + } + if (f2 >>> 0 < 256) { + e2 = +(f2 >>> 0); + b3 = +g2[19516 + (f2 << 2) >> 2]; + } else { + b3 = +(f2 >>> 0); + e2 = b3; + b3 = +Xb(b3); + } + b3 = h2 - b3; + p2 = ~~(b3 + 0.5) >>> 0; + p2 = p2 >>> 0 > 15 ? 15 : p2; + l2 = r2 + (p2 << 2) | 0; + c[l2 >> 2] = (c[l2 >> 2] | 0) + 1; + b3 = q2 + e2 * b3; + d2 = d2 + 1 | 0; + n2 = p2 >>> 0 > n2 >>> 0 ? p2 : n2; + } + o2 = +(((n2 << 1) + 18 | 0) >>> 0); + m3 = r2 + 72 | 0; + d2 = r2; + b3 = 0; + n2 = 0; + while (1) { + if (d2 >>> 0 >= m3 >>> 0) break; + f2 = c[d2 >> 2] | 0; + e2 = +(f2 >>> 0); + if (f2 >>> 0 < 256) k2 = +g2[19516 + (f2 << 2) >> 2]; + else k2 = +Xb(e2); + l2 = c[d2 + 4 >> 2] | 0; + h2 = +(l2 >>> 0); + if (l2 >>> 0 < 256) j2 = +g2[19516 + (l2 << 2) >> 2]; + else j2 = +Xb(h2); + d2 = d2 + 8 | 0; + b3 = b3 - e2 * k2 - h2 * j2; + n2 = n2 + f2 + l2 | 0; + } + k2 = q2 + o2; + j2 = +(n2 >>> 0); + if (!n2) h2 = j2; + else { + if (n2 >>> 0 < 256) e2 = +g2[19516 + (n2 << 2) >> 2]; + else e2 = +Xb(j2); + h2 = j2; + b3 = b3 + j2 * e2; + } + q2 = k2 + (b3 < h2 ? h2 : b3); + i = s2; + return +q2; + } + } + return 0; + } + function Ya(a2) { + a2 = a2 | 0; + var b3 = 0, d2 = 0, e2 = 0, f2 = 0, h2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0; + s2 = i; + i = i + 112 | 0; + m3 = s2 + 88 | 0; + p2 = s2 + 72 | 0; + r2 = s2; + n2 = c[a2 + 2080 >> 2] | 0; + if (!n2) { + q2 = 12; + i = s2; + return +q2; + } else { + f2 = 0; + l2 = 0; + } + while (1) { + if (l2 >>> 0 >= 520) { + d2 = f2; + break; + } + if (c[a2 + (l2 << 2) >> 2] | 0) { + c[m3 + (f2 << 2) >> 2] = l2; + d2 = f2 + 1 | 0; + if ((f2 | 0) > 3) break; + } else d2 = f2; + f2 = d2; + l2 = l2 + 1 | 0; + } + switch (d2 | 0) { + case 2: { + q2 = +(n2 >>> 0) + 20; + i = s2; + return +q2; + } + case 3: { + p2 = c[a2 + (c[m3 >> 2] << 2) >> 2] | 0; + n2 = c[a2 + (c[m3 + 4 >> 2] << 2) >> 2] | 0; + a2 = c[a2 + (c[m3 + 8 >> 2] << 2) >> 2] | 0; + r2 = n2 >>> 0 > a2 >>> 0 ? n2 : a2; + q2 = +(p2 + n2 + a2 << 1 >>> 0) + 28 - +((p2 >>> 0 > r2 >>> 0 ? p2 : r2) >>> 0); + i = s2; + return +q2; + } + case 4: { + d2 = 0; + while (1) { + if ((d2 | 0) == 4) { + n2 = 0; + break; + } + c[p2 + (d2 << 2) >> 2] = c[a2 + (c[m3 + (d2 << 2) >> 2] << 2) >> 2]; + d2 = d2 + 1 | 0; + } + while (1) { + if ((n2 | 0) == 4) break; + m3 = p2 + (n2 << 2) | 0; + d2 = n2; + while (1) { + a2 = d2 + 1 | 0; + if ((d2 | 0) == 3) break; + d2 = p2 + (a2 << 2) | 0; + f2 = c[d2 >> 2] | 0; + l2 = c[m3 >> 2] | 0; + if (f2 >>> 0 <= l2 >>> 0) { + d2 = a2; + continue; + } + c[d2 >> 2] = l2; + c[m3 >> 2] = f2; + d2 = a2; + } + n2 = n2 + 1 | 0; + } + a2 = (c[p2 + 8 >> 2] | 0) + (c[p2 + 12 >> 2] | 0) | 0; + r2 = c[p2 >> 2] | 0; + q2 = +((a2 * 3 | 0) >>> 0) + 37 + +(r2 + (c[p2 + 4 >> 2] | 0) << 1 >>> 0) - +((a2 >>> 0 > r2 >>> 0 ? a2 : r2) >>> 0); + i = s2; + return +q2; + } + case 1: { + q2 = 12; + i = s2; + return +q2; + } + default: { + d2 = r2; + f2 = d2 + 72 | 0; + do { + c[d2 >> 2] = 0; + d2 = d2 + 4 | 0; + } while ((d2 | 0) < (f2 | 0)); + if (n2 >>> 0 < 256) h2 = +g2[19516 + (n2 << 2) >> 2]; + else h2 = +Xb(+(n2 >>> 0)); + m3 = r2 + 68 | 0; + b3 = 0; + d2 = 0; + n2 = 1; + a: while (1) { + q2 = b3; + b: while (1) { + while (1) { + if (d2 >>> 0 >= 520) break a; + f2 = c[a2 + (d2 << 2) >> 2] | 0; + if (!f2) { + l2 = 1; + f2 = d2; + } else break b; + while (1) { + f2 = f2 + 1 | 0; + if (f2 >>> 0 >= 520) break; + if (c[a2 + (f2 << 2) >> 2] | 0) break; + l2 = l2 + 1 | 0; + } + d2 = d2 + l2 | 0; + if ((d2 | 0) == 520) break a; + if (l2 >>> 0 >= 3) break; + c[r2 >> 2] = (c[r2 >> 2] | 0) + l2; + } + b3 = q2; + f2 = l2 + -2 | 0; + while (1) { + if (!f2) { + q2 = b3; + continue b; + } + c[m3 >> 2] = (c[m3 >> 2] | 0) + 1; + b3 = b3 + 3; + f2 = f2 >>> 3; + } + } + if (f2 >>> 0 < 256) { + e2 = +(f2 >>> 0); + b3 = +g2[19516 + (f2 << 2) >> 2]; + } else { + b3 = +(f2 >>> 0); + e2 = b3; + b3 = +Xb(b3); + } + b3 = h2 - b3; + p2 = ~~(b3 + 0.5) >>> 0; + p2 = p2 >>> 0 > 15 ? 15 : p2; + l2 = r2 + (p2 << 2) | 0; + c[l2 >> 2] = (c[l2 >> 2] | 0) + 1; + b3 = q2 + e2 * b3; + d2 = d2 + 1 | 0; + n2 = p2 >>> 0 > n2 >>> 0 ? p2 : n2; + } + o2 = +(((n2 << 1) + 18 | 0) >>> 0); + m3 = r2 + 72 | 0; + d2 = r2; + b3 = 0; + n2 = 0; + while (1) { + if (d2 >>> 0 >= m3 >>> 0) break; + f2 = c[d2 >> 2] | 0; + e2 = +(f2 >>> 0); + if (f2 >>> 0 < 256) k2 = +g2[19516 + (f2 << 2) >> 2]; + else k2 = +Xb(e2); + l2 = c[d2 + 4 >> 2] | 0; + h2 = +(l2 >>> 0); + if (l2 >>> 0 < 256) j2 = +g2[19516 + (l2 << 2) >> 2]; + else j2 = +Xb(h2); + d2 = d2 + 8 | 0; + b3 = b3 - e2 * k2 - h2 * j2; + n2 = n2 + f2 + l2 | 0; + } + k2 = q2 + o2; + j2 = +(n2 >>> 0); + if (!n2) h2 = j2; + else { + if (n2 >>> 0 < 256) e2 = +g2[19516 + (n2 << 2) >> 2]; + else e2 = +Xb(j2); + h2 = j2; + b3 = b3 + j2 * e2; + } + q2 = k2 + (b3 < h2 ? h2 : b3); + i = s2; + return +q2; + } + } + return 0; + } + function Za2(f2, j2, k2, l2, m3, n2, o2, p2, q2, r2) { + f2 = f2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, aa2 = 0, ba2 = 0; + aa2 = i; + i = i + 6688 | 0; + Z3 = aa2 + 2832 | 0; + Y3 = aa2; + V3 = aa2 + 6432 | 0; + T3 = aa2 + 6176 | 0; + W3 = aa2 + 5920 | 0; + U3 = aa2 + 5664 | 0; + t3 = 0; + K3 = 0; + while (1) { + if ((t3 | 0) == (k2 | 0)) break; + $2 = K3 + (c[j2 + (t3 << 4) >> 2] | 0) | 0; + t3 = t3 + 1 | 0; + K3 = $2; + } + $2 = f2 + 8 | 0; + R3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, K3) | 0; + if (!R3) oa2(1); + x3 = n2 + 1 | 0; + v3 = 0; + w2 = 0; + while (1) { + t3 = m3 & n2; + if ((w2 | 0) == (k2 | 0)) break; + m3 = c[j2 + (w2 << 4) >> 2] | 0; + if ((t3 + m3 | 0) >>> 0 > n2 >>> 0) { + Q3 = x3 - t3 | 0; + dc(R3 + v3 | 0, l2 + t3 | 0, Q3 | 0) | 0; + t3 = 0; + u3 = m3 - Q3 | 0; + m3 = v3 + Q3 | 0; + } else { + u3 = m3; + m3 = v3; + } + if (u3) { + dc(R3 + m3 | 0, l2 + t3 | 0, u3 | 0) | 0; + m3 = m3 + u3 | 0; + } + v3 = m3; + m3 = t3 + u3 + (c[j2 + (w2 << 4) + 4 >> 2] & 16777215) | 0; + w2 = w2 + 1 | 0; + } + B3 = ((K3 >>> 0) / 544 | 0) + 1 | 0; + B3 = B3 >>> 0 > 100 ? 100 : B3; + do + if (K3) { + if (K3 >>> 0 < 128) { + w2 = p2 + 16 | 0; + m3 = c[w2 >> 2] | 0; + x3 = p2 + 4 | 0; + t3 = c[x3 >> 2] | 0; + u3 = t3 + 1 | 0; + if (m3 >>> 0 < u3 >>> 0) { + v3 = (m3 | 0) == 0 ? u3 : m3; + while (1) { + if (v3 >>> 0 >= u3 >>> 0) break; + v3 = v3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3) | 0; + if (!m3) oa2(1); + u3 = c[w2 >> 2] | 0; + t3 = p2 + 8 | 0; + if (u3) dc(m3 | 0, c[t3 >> 2] | 0, u3 | 0) | 0; + ra2[c[f2 + 4 >> 2] & 1](c[$2 >> 2] | 0, c[t3 >> 2] | 0); + c[t3 >> 2] = m3; + c[w2 >> 2] = v3; + t3 = c[x3 >> 2] | 0; + } + w2 = p2 + 20 | 0; + m3 = c[w2 >> 2] | 0; + u3 = t3 + 1 | 0; + if (m3 >>> 0 < u3 >>> 0) { + v3 = (m3 | 0) == 0 ? u3 : m3; + while (1) { + if (v3 >>> 0 >= u3 >>> 0) break; + v3 = v3 << 1; + } + t3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3 << 2) | 0; + if (!t3) oa2(1); + u3 = c[w2 >> 2] | 0; + m3 = p2 + 12 | 0; + if (u3) dc(t3 | 0, c[m3 >> 2] | 0, u3 << 2 | 0) | 0; + ra2[c[f2 + 4 >> 2] & 1](c[$2 >> 2] | 0, c[m3 >> 2] | 0); + c[m3 >> 2] = t3; + c[w2 >> 2] = v3; + t3 = c[x3 >> 2] | 0; + } else m3 = p2 + 12 | 0; + c[p2 >> 2] = 1; + a[(c[p2 + 8 >> 2] | 0) + t3 >> 0] = 0; + c[(c[m3 >> 2] | 0) + (c[x3 >> 2] << 2) >> 2] = K3; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + break; + } + J3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, B3 * 1040 | 0) | 0; + if (!J3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (B3 | 0)) break; + ac(J3 + (t3 * 1040 | 0) | 0, 0, 1024) | 0; + c[J3 + (t3 * 1040 | 0) + 1024 >> 2] = 0; + h[J3 + (t3 * 1040 | 0) + 1032 >> 3] = s; + t3 = t3 + 1 | 0; + } + w2 = (K3 >>> 0) / (B3 >>> 0) | 0; + x3 = K3 + -71 | 0; + m3 = 7; + l2 = 0; + while (1) { + if ((l2 | 0) == (B3 | 0)) break; + t3 = ((_(K3, l2) | 0) >>> 0) / (B3 >>> 0) | 0; + if (l2) { + m3 = m3 * 16807 | 0; + m3 = (m3 | 0) == 0 ? 1 : m3; + t3 = t3 + ((m3 >>> 0) % (w2 >>> 0) | 0) | 0; + } + u3 = J3 + (l2 * 1040 | 0) + 1024 | 0; + c[u3 >> 2] = (c[u3 >> 2] | 0) + 70; + u3 = 71; + v3 = R3 + ((t3 + 70 | 0) >>> 0 < K3 >>> 0 ? t3 : x3) | 0; + while (1) { + t3 = u3 + -1 | 0; + if (!t3) break; + u3 = J3 + (l2 * 1040 | 0) + (d[v3 >> 0] << 2) | 0; + c[u3 >> 2] = (c[u3 >> 2] | 0) + 1; + u3 = t3; + v3 = v3 + 1 | 0; + } + l2 = l2 + 1 | 0; + } + c[Z3 >> 2] = 7; + u3 = ((K3 << 1 >>> 0) / 70 | 0) + 100 + B3 + -1 | 0; + u3 = u3 - ((u3 >>> 0) % (B3 >>> 0) | 0) | 0; + v3 = Y3 + 1024 | 0; + w2 = Y3 + 1032 | 0; + x3 = K3 >>> 0 > 70; + l2 = K3 + -69 | 0; + n2 = Y3 + 1024 | 0; + A3 = 0; + while (1) { + if (A3 >>> 0 >= u3 >>> 0) break; + ac(Y3 | 0, 0, 1028) | 0; + h[w2 >> 3] = s; + if (x3) { + m3 = (c[Z3 >> 2] | 0) * 16807 | 0; + Q3 = (m3 | 0) == 0; + c[Z3 >> 2] = Q3 ? 1 : m3; + t3 = 70; + m3 = ((Q3 ? 1 : m3) >>> 0) % (l2 >>> 0) | 0; + } else { + t3 = K3; + m3 = 0; + } + c[n2 >> 2] = (c[n2 >> 2] | 0) + t3; + t3 = t3 + 1 | 0; + m3 = R3 + m3 | 0; + while (1) { + t3 = t3 + -1 | 0; + if (!t3) break; + Q3 = Y3 + (d[m3 >> 0] << 2) | 0; + c[Q3 >> 2] = (c[Q3 >> 2] | 0) + 1; + m3 = m3 + 1 | 0; + } + t3 = (A3 >>> 0) % (B3 >>> 0) | 0; + m3 = J3 + (t3 * 1040 | 0) + 1024 | 0; + c[m3 >> 2] = (c[m3 >> 2] | 0) + (c[v3 >> 2] | 0); + m3 = 0; + while (1) { + if ((m3 | 0) == 256) break; + Q3 = J3 + (t3 * 1040 | 0) + (m3 << 2) | 0; + c[Q3 >> 2] = (c[Q3 >> 2] | 0) + (c[Y3 + (m3 << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + A3 = A3 + 1 | 0; + } + Q3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, K3) | 0; + if (!Q3) oa2(1); + F3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, B3 << 11) | 0; + if (!F3) oa2(1); + G3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, B3 << 3) | 0; + if (!G3) oa2(1); + H3 = _(K3, (B3 + 7 | 0) >>> 3) | 0; + H3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, H3) | 0; + if (!H3) oa2(1); + I3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, B3 << 1) | 0; + if (!I3) oa2(1); + C3 = (c[o2 + 4 >> 2] | 0) < 11 ? 3 : 10; + D3 = K3 + -1 | 0; + E3 = Q3 + D3 | 0; + O3 = 0; + A3 = 0; + a: while (1) { + if (A3 >>> 0 >= C3 >>> 0) { + l2 = 136; + break; + } + n2 = (B3 + 7 | 0) >>> 3; + if (B3 >>> 0 >= 257) { + l2 = 73; + break; + } + b: do + if (B3 >>> 0 < 2) { + t3 = 0; + while (1) { + if ((t3 | 0) == (K3 | 0)) { + v3 = 1; + break b; + } + a[Q3 + t3 >> 0] = 0; + t3 = t3 + 1 | 0; + } + } else { + ac(F3 | 0, 0, B3 << 11 | 0) | 0; + m3 = 0; + while (1) { + if ((m3 | 0) == (B3 | 0)) { + t3 = 256; + break; + } + t3 = c[J3 + (m3 * 1040 | 0) + 1024 >> 2] | 0; + if (t3 >>> 0 < 256) y3 = +g2[19516 + (t3 << 2) >> 2]; + else y3 = +Xb(+(t3 >>> 0)); + h[F3 + (m3 << 3) >> 3] = y3; + m3 = m3 + 1 | 0; + } + c: while (1) { + if (!t3) break; + t3 = t3 + -1 | 0; + u3 = _(t3, B3) | 0; + v3 = 0; + while (1) { + if ((v3 | 0) == (B3 | 0)) continue c; + z3 = +h[F3 + (v3 << 3) >> 3]; + m3 = c[J3 + (v3 * 1040 | 0) + (t3 << 2) >> 2] | 0; + do + if (m3) if (m3 >>> 0 < 256) { + y3 = +g2[19516 + (m3 << 2) >> 2]; + break; + } else { + y3 = +Xb(+(m3 >>> 0)); + break; + } + else y3 = -2; + while (0); + h[F3 + (u3 + v3 << 3) >> 3] = z3 - y3; + v3 = v3 + 1 | 0; + } + } + ac(G3 | 0, 0, B3 << 3 | 0) | 0; + ac(H3 | 0, 0, _(K3, n2) | 0) | 0; + v3 = 0; + while (1) { + if (v3 >>> 0 >= K3 >>> 0) break; + t3 = _(d[R3 + v3 >> 0] | 0, B3) | 0; + m3 = Q3 + v3 | 0; + z3 = 1e99; + u3 = 0; + while (1) { + if ((u3 | 0) == (B3 | 0)) break; + O3 = G3 + (u3 << 3) | 0; + y3 = +h[O3 >> 3] + +h[F3 + (t3 + u3 << 3) >> 3]; + h[O3 >> 3] = y3; + if (y3 < z3) a[m3 >> 0] = u3; + else y3 = z3; + z3 = y3; + u3 = u3 + 1 | 0; + } + m3 = _(v3, n2) | 0; + if (v3 >>> 0 < 2e3) y3 = (+(v3 >>> 0) * 0.07 / 2e3 + 0.77) * 28.1; + else y3 = 28.1; + u3 = 0; + while (1) { + if (u3 >>> 0 >= B3 >>> 0) break; + t3 = G3 + (u3 << 3) | 0; + ba2 = +h[t3 >> 3] - z3; + h[t3 >> 3] = ba2; + if (ba2 >= y3) { + h[t3 >> 3] = y3; + t3 = u3 >>> 3; + if (t3 >>> 0 >= n2 >>> 0) { + l2 = 104; + break a; + } + O3 = H3 + (m3 + t3) | 0; + a[O3 >> 0] = a[O3 >> 0] | 1 << (u3 & 7) & 255; + } + u3 = u3 + 1 | 0; + } + v3 = v3 + 1 | 0; + } + m3 = _(D3, n2) | 0; + v3 = D3; + t3 = a[E3 >> 0] | 0; + u3 = 1; + while (1) { + if (!v3) { + v3 = u3; + break b; + } + w2 = t3 & 255; + x3 = w2 >>> 3; + if (x3 >>> 0 >= n2 >>> 0) { + l2 = 111; + break a; + } + l2 = v3 + -1 | 0; + m3 = m3 - n2 | 0; + v3 = Q3 + l2 | 0; + if ((a[H3 + (m3 + x3) >> 0] & (1 << (w2 & 7) & 255)) << 24 >> 24) { + N3 = a[v3 >> 0] | 0; + O3 = t3 << 24 >> 24 == N3 << 24 >> 24; + t3 = O3 ? t3 : N3; + u3 = O3 ? u3 : u3 + 1 | 0; + } + a[v3 >> 0] = t3; + v3 = l2; + } + } + while (0); + t3 = 0; + while (1) { + if ((t3 | 0) == (B3 | 0)) { + t3 = 0; + u3 = 0; + break; + } + b2[I3 + (t3 << 1) >> 1] = 256; + t3 = t3 + 1 | 0; + } + while (1) { + if (u3 >>> 0 >= K3 >>> 0) { + m3 = 0; + break; + } + m3 = d[Q3 + u3 >> 0] | 0; + if (m3 >>> 0 >= B3 >>> 0) { + l2 = 120; + break a; + } + m3 = I3 + (m3 << 1) | 0; + if ((b2[m3 >> 1] | 0) == 256) { + b2[m3 >> 1] = t3; + t3 = t3 + 1 << 16 >> 16; + } + u3 = u3 + 1 | 0; + } + while (1) { + if (m3 >>> 0 >= K3 >>> 0) break; + N3 = Q3 + m3 | 0; + O3 = b2[I3 + (d[N3 >> 0] << 1) >> 1] | 0; + a[N3 >> 0] = O3; + if ((O3 & 255) >>> 0 >= B3 >>> 0) { + l2 = 126; + break a; + } + m3 = m3 + 1 | 0; + } + u3 = t3 & 65535; + if (u3 >>> 0 > B3 >>> 0) { + l2 = 129; + break; + } + t3 = t3 & 65535; + m3 = 0; + while (1) { + if ((m3 | 0) == (t3 | 0)) { + t3 = 0; + break; + } + ac(J3 + (m3 * 1040 | 0) | 0, 0, 1024) | 0; + c[J3 + (m3 * 1040 | 0) + 1024 >> 2] = 0; + h[J3 + (m3 * 1040 | 0) + 1032 >> 3] = s; + m3 = m3 + 1 | 0; + } + while (1) { + if ((t3 | 0) == (K3 | 0)) break; + O3 = d[Q3 + t3 >> 0] | 0; + N3 = J3 + (O3 * 1040 | 0) + (d[R3 + t3 >> 0] << 2) | 0; + c[N3 >> 2] = (c[N3 >> 2] | 0) + 1; + O3 = J3 + (O3 * 1040 | 0) + 1024 | 0; + c[O3 >> 2] = (c[O3 >> 2] | 0) + 1; + t3 = t3 + 1 | 0; + } + O3 = v3; + B3 = u3; + A3 = A3 + 1 | 0; + } + if ((l2 | 0) == 73) pa2(404083, 403848, 80, 404281); + else if ((l2 | 0) == 104) pa2(404124, 403848, 130, 404281); + else if ((l2 | 0) == 111) pa2(404145, 403848, 141, 404281); + else if ((l2 | 0) == 120) pa2(404005, 403848, 165, 404260); + else if ((l2 | 0) == 126) pa2(404005, 403848, 172, 404260); + else if ((l2 | 0) == 129) pa2(404057, 403848, 174, 404260); + else if ((l2 | 0) == 136) { + N3 = f2 + 4 | 0; + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, F3); + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, G3); + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, H3); + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, I3); + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, J3); + t3 = O3 << 2; + L3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, t3) | 0; + if (!L3) oa2(1); + M2 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, t3) | 0; + if (!M2) oa2(1); + x3 = ((O3 << 4) + 1008 | 0) >>> 6; + J3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 * 1040 | 0) | 0; + v3 = J3; + if (!J3) oa2(1); + J3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 << 2) | 0; + w2 = J3; + if (!J3) oa2(1); + G3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, (O3 >>> 0 < 64 ? O3 : 64) * 1040 | 0) | 0; + if (!G3) oa2(1); + H3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, 49176) | 0; + if (!H3) oa2(1); + ac(V3 | 0, 0, 256) | 0; + ac(T3 | 0, 0, 256) | 0; + ac(W3 | 0, 0, 256) | 0; + ac(U3 | 0, 0, 256) | 0; + ac(M2 | 0, 0, t3 | 0) | 0; + m3 = 0; + u3 = 0; + while (1) { + if (u3 >>> 0 >= K3 >>> 0) break; + if (m3 >>> 0 >= O3 >>> 0) { + l2 = 151; + break; + } + t3 = M2 + (m3 << 2) | 0; + c[t3 >> 2] = (c[t3 >> 2] | 0) + 1; + t3 = u3 + 1 | 0; + if ((t3 | 0) != (K3 | 0) ? (a[Q3 + u3 >> 0] | 0) == (a[Q3 + t3 >> 0] | 0) : 0) { + u3 = t3; + continue; + } + m3 = m3 + 1 | 0; + u3 = t3; + } + if ((l2 | 0) == 151) pa2(403825, 403848, 231, 404239); + if ((m3 | 0) != (O3 | 0)) pa2(403911, 403848, 237, 404239); + C3 = x3; + B3 = x3; + J3 = 0; + t3 = 0; + F3 = 0; + while (1) { + if (O3 >>> 0 <= F3 >>> 0) { + l2 = 193; + break; + } + E3 = O3 - F3 | 0; + E3 = E3 >>> 0 < 64 ? E3 : 64; + n2 = 0; + while (1) { + if ((n2 | 0) == (E3 | 0)) break; + u3 = G3 + (n2 * 1040 | 0) | 0; + ac(u3 | 0, 0, 1024) | 0; + x3 = G3 + (n2 * 1040 | 0) + 1024 | 0; + c[x3 >> 2] = 0; + h[G3 + (n2 * 1040 | 0) + 1032 >> 3] = s; + l2 = M2 + (F3 + n2 << 2) | 0; + m3 = 0; + while (1) { + if (m3 >>> 0 >= (c[l2 >> 2] | 0) >>> 0) break; + K3 = G3 + (n2 * 1040 | 0) + (d[R3 + t3 >> 0] << 2) | 0; + c[K3 >> 2] = (c[K3 >> 2] | 0) + 1; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + t3 = t3 + 1 | 0; + m3 = m3 + 1 | 0; + } + h[G3 + (n2 * 1040 | 0) + 1032 >> 3] = +Wa2(u3); + c[T3 + (n2 << 2) >> 2] = n2; + c[W3 + (n2 << 2) >> 2] = n2; + c[V3 + (n2 << 2) >> 2] = 1; + n2 = n2 + 1 | 0; + } + D3 = pb(G3, V3, W3, T3, H3, E3, E3, 64, 2048) | 0; + m3 = J3 + D3 | 0; + if (C3 >>> 0 < m3 >>> 0) { + u3 = (C3 | 0) == 0; + x3 = u3 ? m3 : C3; + while (1) { + if (x3 >>> 0 >= m3 >>> 0) break; + x3 = x3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 * 1040 | 0) | 0; + if (!m3) { + l2 = 170; + break; + } + if (!u3) dc(m3 | 0, v3 | 0, C3 * 1040 | 0) | 0; + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, v3); + v3 = m3; + C3 = x3; + } + m3 = J3 + D3 | 0; + if (B3 >>> 0 < m3 >>> 0) { + u3 = (B3 | 0) == 0; + x3 = u3 ? m3 : B3; + while (1) { + if (x3 >>> 0 >= m3 >>> 0) break; + x3 = x3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 << 2) | 0; + if (!m3) { + l2 = 179; + break; + } + if (!u3) dc(m3 | 0, w2 | 0, B3 << 2 | 0) | 0; + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, w2); + w2 = m3; + B3 = x3; + } + m3 = v3; + u3 = w2; + A3 = D3 + J3 | 0; + x3 = J3; + l2 = J3; + n2 = 0; + while (1) { + if ((n2 | 0) == (D3 | 0)) { + m3 = 0; + break; + } + K3 = T3 + (n2 << 2) | 0; + I3 = c[K3 >> 2] | 0; + dc(m3 + (x3 * 1040 | 0) | 0, G3 + (I3 * 1040 | 0) | 0, 1040) | 0; + c[u3 + (l2 << 2) >> 2] = c[V3 + (I3 << 2) >> 2]; + c[U3 + (c[K3 >> 2] << 2) >> 2] = n2; + x3 = x3 + 1 | 0; + l2 = l2 + 1 | 0; + n2 = n2 + 1 | 0; + } + while (1) { + if ((m3 | 0) == (E3 | 0)) break; + c[L3 + (F3 + m3 << 2) >> 2] = J3 + (c[U3 + (c[W3 + (m3 << 2) >> 2] << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + m3 = D3 + J3 | 0; + if ((J3 + D3 | 0) != (m3 | 0)) { + l2 = 189; + break; + } + if ((m3 | 0) != (A3 | 0)) { + l2 = 191; + break; + } + J3 = m3; + F3 = F3 + 64 | 0; + } + if ((l2 | 0) == 170) oa2(1); + else if ((l2 | 0) == 179) oa2(1); + else if ((l2 | 0) == 189) pa2(403935, 403848, 273, 404239); + else if ((l2 | 0) == 191) pa2(403969, 403848, 274, 404239); + else if ((l2 | 0) == 193) { + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, G3); + K3 = J3 << 6; + u3 = _(J3 >>> 1, J3) | 0; + u3 = K3 >>> 0 < u3 >>> 0 ? K3 : u3; + do + if ((u3 + 1 | 0) >>> 0 > 2049) { + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, H3); + t3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, (u3 * 24 | 0) + 24 | 0) | 0; + if (t3) { + P3 = t3; + break; + } + oa2(1); + } else P3 = H3; + while (0); + m3 = J3 << 2; + I3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, m3) | 0; + if (!I3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (J3 | 0)) break; + c[I3 + (t3 << 2) >> 2] = t3; + t3 = t3 + 1 | 0; + } + H3 = v3; + G3 = pb(H3, w2, L3, I3, P3, J3, O3, 256, u3) | 0; + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, P3); + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, w2); + K3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, m3) | 0; + if (!K3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (J3 | 0)) break; + c[K3 + (t3 << 2) >> 2] = -1; + t3 = t3 + 1 | 0; + } + B3 = Y3 + 1024 | 0; + C3 = Y3 + 1032 | 0; + D3 = Z3 + 1024 | 0; + E3 = Z3 + 1024 | 0; + t3 = 0; + m3 = 0; + F3 = 0; + while (1) { + if ((F3 | 0) == (O3 | 0)) break; + ac(Y3 | 0, 0, 1028) | 0; + h[C3 >> 3] = s; + u3 = M2 + (F3 << 2) | 0; + w2 = 0; + A3 = m3; + m3 = 0; + while (1) { + if (m3 >>> 0 >= (c[u3 >> 2] | 0) >>> 0) break; + w2 = Y3 + (d[R3 + A3 >> 0] << 2) | 0; + c[w2 >> 2] = (c[w2 >> 2] | 0) + 1; + w2 = (c[B3 >> 2] | 0) + 1 | 0; + c[B3 >> 2] = w2; + A3 = A3 + 1 | 0; + m3 = m3 + 1 | 0; + } + u3 = c[((F3 | 0) == 0 ? L3 : L3 + (F3 + -1 << 2) | 0) >> 2] | 0; + n2 = (w2 | 0) == 0; + if (n2) y3 = 0; + else { + dc(Z3 | 0, Y3 | 0, 1040) | 0; + c[E3 >> 2] = (c[E3 >> 2] | 0) + (c[H3 + (u3 * 1040 | 0) + 1024 >> 2] | 0); + m3 = 0; + while (1) { + if ((m3 | 0) == 256) break; + P3 = Z3 + (m3 << 2) | 0; + c[P3 >> 2] = (c[P3 >> 2] | 0) + (c[H3 + (u3 * 1040 | 0) + (m3 << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + y3 = +Wa2(Z3); + y3 = y3 - +h[H3 + (u3 * 1040 | 0) + 1032 >> 3]; + } + m3 = u3; + l2 = 0; + while (1) { + if ((l2 | 0) == (G3 | 0)) break; + x3 = I3 + (l2 << 2) | 0; + u3 = c[x3 >> 2] | 0; + if (n2) z3 = 0; + else { + dc(Z3 | 0, Y3 | 0, 1040) | 0; + c[D3 >> 2] = (c[D3 >> 2] | 0) + (c[H3 + (u3 * 1040 | 0) + 1024 >> 2] | 0); + w2 = 0; + while (1) { + if ((w2 | 0) == 256) break; + P3 = Z3 + (w2 << 2) | 0; + c[P3 >> 2] = (c[P3 >> 2] | 0) + (c[H3 + (u3 * 1040 | 0) + (w2 << 2) >> 2] | 0); + w2 = w2 + 1 | 0; + } + z3 = +Wa2(Z3); + z3 = z3 - +h[H3 + (u3 * 1040 | 0) + 1032 >> 3]; + } + if (z3 < y3) { + y3 = z3; + m3 = c[x3 >> 2] | 0; + } + l2 = l2 + 1 | 0; + } + c[L3 + (F3 << 2) >> 2] = m3; + m3 = K3 + (m3 << 2) | 0; + if ((c[m3 >> 2] | 0) == -1) { + c[m3 >> 2] = t3; + t3 = t3 + 1 | 0; + } + m3 = A3; + F3 = F3 + 1 | 0; + } + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, I3); + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, v3); + w2 = p2 + 16 | 0; + t3 = c[w2 >> 2] | 0; + if (t3 >>> 0 < O3 >>> 0) { + v3 = (t3 | 0) == 0 ? O3 : t3; + while (1) { + if (v3 >>> 0 >= O3 >>> 0) break; + v3 = v3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3) | 0; + if (!m3) oa2(1); + u3 = c[w2 >> 2] | 0; + t3 = p2 + 8 | 0; + if (u3) dc(m3 | 0, c[t3 >> 2] | 0, u3 | 0) | 0; + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, c[t3 >> 2] | 0); + c[t3 >> 2] = m3; + c[w2 >> 2] = v3; + } + w2 = p2 + 20 | 0; + t3 = c[w2 >> 2] | 0; + if (t3 >>> 0 < O3 >>> 0) { + v3 = (t3 | 0) == 0 ? O3 : t3; + while (1) { + if (v3 >>> 0 >= O3 >>> 0) break; + v3 = v3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3 << 2) | 0; + if (!m3) oa2(1); + u3 = c[w2 >> 2] | 0; + t3 = p2 + 12 | 0; + if (u3) dc(m3 | 0, c[t3 >> 2] | 0, u3 << 2 | 0) | 0; + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, c[t3 >> 2] | 0); + c[t3 >> 2] = m3; + c[w2 >> 2] = v3; + } else t3 = p2 + 12 | 0; + w2 = p2 + 8 | 0; + l2 = 0; + m3 = 0; + n2 = 0; + u3 = 0; + while (1) { + if ((u3 | 0) == (O3 | 0)) break; + v3 = m3 + (c[M2 + (u3 << 2) >> 2] | 0) | 0; + x3 = u3 + 1 | 0; + m3 = c[L3 + (u3 << 2) >> 2] | 0; + if ((x3 | 0) != (O3 | 0) ? (m3 | 0) == (c[L3 + (x3 << 2) >> 2] | 0) : 0) { + m3 = v3; + u3 = x3; + continue; + } + u3 = c[K3 + (m3 << 2) >> 2] | 0; + P3 = u3 & 255; + a[(c[w2 >> 2] | 0) + l2 >> 0] = P3; + c[(c[t3 >> 2] | 0) + (l2 << 2) >> 2] = v3; + l2 = l2 + 1 | 0; + m3 = 0; + n2 = ((n2 & 255) > (P3 & 255) ? n2 & 255 : u3 & 255) & 255; + u3 = x3; + } + c[p2 + 4 >> 2] = l2; + c[p2 >> 2] = (n2 & 255) + 1; + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, K3); + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, M2); + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, L3); + ra2[c[N3 >> 2] & 1](c[$2 >> 2] | 0, Q3); + break; + } + } + } else c[p2 >> 2] = 1; + while (0); + p2 = f2 + 4 | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, R3); + P3 = k2 << 1; + Q3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, P3) | 0; + if (!Q3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (k2 | 0)) break; + b2[Q3 + (t3 << 1) >> 1] = b2[j2 + (t3 << 4) + 12 >> 1] | 0; + t3 = t3 + 1 | 0; + } + C3 = ((k2 >>> 0) / 530 | 0) + 1 | 0; + C3 = C3 >>> 0 > 50 ? 50 : C3; + do + if (k2) { + if (k2 >>> 0 < 128) { + w2 = q2 + 16 | 0; + m3 = c[w2 >> 2] | 0; + x3 = q2 + 4 | 0; + t3 = c[x3 >> 2] | 0; + u3 = t3 + 1 | 0; + if (m3 >>> 0 < u3 >>> 0) { + v3 = (m3 | 0) == 0 ? u3 : m3; + while (1) { + if (v3 >>> 0 >= u3 >>> 0) break; + v3 = v3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3) | 0; + if (!m3) oa2(1); + u3 = c[w2 >> 2] | 0; + t3 = q2 + 8 | 0; + if (u3) dc(m3 | 0, c[t3 >> 2] | 0, u3 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, c[t3 >> 2] | 0); + c[t3 >> 2] = m3; + c[w2 >> 2] = v3; + t3 = c[x3 >> 2] | 0; + } + w2 = q2 + 20 | 0; + m3 = c[w2 >> 2] | 0; + u3 = t3 + 1 | 0; + if (m3 >>> 0 < u3 >>> 0) { + v3 = (m3 | 0) == 0 ? u3 : m3; + while (1) { + if (v3 >>> 0 >= u3 >>> 0) break; + v3 = v3 << 1; + } + t3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3 << 2) | 0; + if (!t3) oa2(1); + u3 = c[w2 >> 2] | 0; + m3 = q2 + 12 | 0; + if (u3) dc(t3 | 0, c[m3 >> 2] | 0, u3 << 2 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, c[m3 >> 2] | 0); + c[m3 >> 2] = t3; + c[w2 >> 2] = v3; + t3 = c[x3 >> 2] | 0; + } else m3 = q2 + 12 | 0; + c[q2 >> 2] = 1; + a[(c[q2 + 8 >> 2] | 0) + t3 >> 0] = 0; + c[(c[m3 >> 2] | 0) + (c[x3 >> 2] << 2) >> 2] = k2; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + break; + } + J3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, C3 * 2832 | 0) | 0; + if (!J3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (C3 | 0)) break; + ac(J3 + (t3 * 2832 | 0) | 0, 0, 2816) | 0; + c[J3 + (t3 * 2832 | 0) + 2816 >> 2] = 0; + h[J3 + (t3 * 2832 | 0) + 2824 >> 3] = s; + t3 = t3 + 1 | 0; + } + v3 = (k2 >>> 0) / (C3 >>> 0) | 0; + w2 = k2 + -41 | 0; + m3 = 7; + x3 = 0; + while (1) { + if ((x3 | 0) == (C3 | 0)) break; + t3 = ((_(x3, k2) | 0) >>> 0) / (C3 >>> 0) | 0; + if (x3) { + m3 = m3 * 16807 | 0; + m3 = (m3 | 0) == 0 ? 1 : m3; + t3 = t3 + ((m3 >>> 0) % (v3 >>> 0) | 0) | 0; + } + u3 = J3 + (x3 * 2832 | 0) + 2816 | 0; + c[u3 >> 2] = (c[u3 >> 2] | 0) + 40; + u3 = Q3 + (((t3 + 40 | 0) >>> 0 < k2 >>> 0 ? t3 : w2) << 1) | 0; + t3 = 41; + while (1) { + t3 = t3 + -1 | 0; + if (!t3) break; + R3 = J3 + (x3 * 2832 | 0) + (e[u3 >> 1] << 2) | 0; + c[R3 >> 2] = (c[R3 >> 2] | 0) + 1; + u3 = u3 + 2 | 0; + } + x3 = x3 + 1 | 0; + } + c[Z3 >> 2] = 7; + v3 = ((P3 >>> 0) / 40 | 0) + 100 + C3 + -1 | 0; + v3 = v3 - ((v3 >>> 0) % (C3 >>> 0) | 0) | 0; + w2 = Y3 + 2816 | 0; + x3 = Y3 + 2824 | 0; + l2 = k2 >>> 0 > 40; + n2 = k2 + -39 | 0; + A3 = Y3 + 2816 | 0; + B3 = 0; + while (1) { + if (B3 >>> 0 >= v3 >>> 0) break; + ac(Y3 | 0, 0, 2820) | 0; + h[x3 >> 3] = s; + if (l2) { + t3 = (c[Z3 >> 2] | 0) * 16807 | 0; + R3 = (t3 | 0) == 0; + c[Z3 >> 2] = R3 ? 1 : t3; + m3 = 40; + t3 = ((R3 ? 1 : t3) >>> 0) % (n2 >>> 0) | 0; + } else { + m3 = k2; + t3 = 0; + } + c[A3 >> 2] = (c[A3 >> 2] | 0) + m3; + u3 = Q3 + (t3 << 1) | 0; + t3 = m3 + 1 | 0; + while (1) { + t3 = t3 + -1 | 0; + if (!t3) break; + R3 = Y3 + (e[u3 >> 1] << 2) | 0; + c[R3 >> 2] = (c[R3 >> 2] | 0) + 1; + u3 = u3 + 2 | 0; + } + t3 = (B3 >>> 0) % (C3 >>> 0) | 0; + m3 = J3 + (t3 * 2832 | 0) + 2816 | 0; + c[m3 >> 2] = (c[m3 >> 2] | 0) + (c[w2 >> 2] | 0); + m3 = 0; + while (1) { + if ((m3 | 0) == 704) break; + R3 = J3 + (t3 * 2832 | 0) + (m3 << 2) | 0; + c[R3 >> 2] = (c[R3 >> 2] | 0) + (c[Y3 + (m3 << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + B3 = B3 + 1 | 0; + } + O3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, k2) | 0; + if (!O3) oa2(1); + F3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, C3 * 5632 | 0) | 0; + if (!F3) oa2(1); + G3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, C3 << 3) | 0; + if (!G3) oa2(1); + H3 = _((C3 + 7 | 0) >>> 3, k2) | 0; + H3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, H3) | 0; + if (!H3) oa2(1); + I3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, C3 << 1) | 0; + if (!I3) oa2(1); + B3 = (c[o2 + 4 >> 2] | 0) < 11 ? 3 : 10; + D3 = k2 + -1 | 0; + E3 = O3 + D3 | 0; + N3 = 0; + A3 = 0; + d: while (1) { + if (A3 >>> 0 >= B3 >>> 0) { + l2 = 382; + break; + } + n2 = (C3 + 7 | 0) >>> 3; + if (C3 >>> 0 >= 257) { + l2 = 319; + break; + } + e: do + if (C3 >>> 0 < 2) { + t3 = 0; + while (1) { + if ((t3 | 0) == (k2 | 0)) { + v3 = 1; + break e; + } + a[O3 + t3 >> 0] = 0; + t3 = t3 + 1 | 0; + } + } else { + ac(F3 | 0, 0, C3 * 5632 | 0) | 0; + m3 = 0; + while (1) { + if ((m3 | 0) == (C3 | 0)) { + t3 = 704; + break; + } + t3 = c[J3 + (m3 * 2832 | 0) + 2816 >> 2] | 0; + if (t3 >>> 0 < 256) y3 = +g2[19516 + (t3 << 2) >> 2]; + else y3 = +Xb(+(t3 >>> 0)); + h[F3 + (m3 << 3) >> 3] = y3; + m3 = m3 + 1 | 0; + } + f: while (1) { + if (!t3) break; + t3 = t3 + -1 | 0; + u3 = _(t3, C3) | 0; + v3 = 0; + while (1) { + if ((v3 | 0) == (C3 | 0)) continue f; + z3 = +h[F3 + (v3 << 3) >> 3]; + m3 = c[J3 + (v3 * 2832 | 0) + (t3 << 2) >> 2] | 0; + do + if (m3) if (m3 >>> 0 < 256) { + y3 = +g2[19516 + (m3 << 2) >> 2]; + break; + } else { + y3 = +Xb(+(m3 >>> 0)); + break; + } + else y3 = -2; + while (0); + h[F3 + (u3 + v3 << 3) >> 3] = z3 - y3; + v3 = v3 + 1 | 0; + } + } + ac(G3 | 0, 0, C3 << 3 | 0) | 0; + ac(H3 | 0, 0, _(n2, k2) | 0) | 0; + v3 = 0; + while (1) { + if (v3 >>> 0 >= k2 >>> 0) break; + t3 = _(e[Q3 + (v3 << 1) >> 1] | 0, C3) | 0; + m3 = O3 + v3 | 0; + z3 = 1e99; + u3 = 0; + while (1) { + if ((u3 | 0) == (C3 | 0)) break; + R3 = G3 + (u3 << 3) | 0; + y3 = +h[R3 >> 3] + +h[F3 + (t3 + u3 << 3) >> 3]; + h[R3 >> 3] = y3; + if (y3 < z3) a[m3 >> 0] = u3; + else y3 = z3; + z3 = y3; + u3 = u3 + 1 | 0; + } + m3 = _(v3, n2) | 0; + if (v3 >>> 0 < 2e3) y3 = (+(v3 >>> 0) * 0.07 / 2e3 + 0.77) * 13.5; + else y3 = 13.5; + u3 = 0; + while (1) { + if (u3 >>> 0 >= C3 >>> 0) break; + t3 = G3 + (u3 << 3) | 0; + ba2 = +h[t3 >> 3] - z3; + h[t3 >> 3] = ba2; + if (ba2 >= y3) { + h[t3 >> 3] = y3; + t3 = u3 >>> 3; + if (t3 >>> 0 >= n2 >>> 0) { + l2 = 350; + break d; + } + R3 = H3 + (m3 + t3) | 0; + a[R3 >> 0] = a[R3 >> 0] | 1 << (u3 & 7) & 255; + } + u3 = u3 + 1 | 0; + } + v3 = v3 + 1 | 0; + } + m3 = _(D3, n2) | 0; + v3 = D3; + t3 = a[E3 >> 0] | 0; + u3 = 1; + while (1) { + if (!v3) { + v3 = u3; + break e; + } + w2 = t3 & 255; + x3 = w2 >>> 3; + if (x3 >>> 0 >= n2 >>> 0) { + l2 = 357; + break d; + } + l2 = v3 + -1 | 0; + m3 = m3 - n2 | 0; + v3 = O3 + l2 | 0; + if ((a[H3 + (m3 + x3) >> 0] & (1 << (w2 & 7) & 255)) << 24 >> 24) { + N3 = a[v3 >> 0] | 0; + R3 = t3 << 24 >> 24 == N3 << 24 >> 24; + t3 = R3 ? t3 : N3; + u3 = R3 ? u3 : u3 + 1 | 0; + } + a[v3 >> 0] = t3; + v3 = l2; + } + } + while (0); + t3 = 0; + while (1) { + if ((t3 | 0) == (C3 | 0)) { + t3 = 0; + u3 = 0; + break; + } + b2[I3 + (t3 << 1) >> 1] = 256; + t3 = t3 + 1 | 0; + } + while (1) { + if (u3 >>> 0 >= k2 >>> 0) { + m3 = 0; + break; + } + m3 = d[O3 + u3 >> 0] | 0; + if (m3 >>> 0 >= C3 >>> 0) { + l2 = 366; + break d; + } + m3 = I3 + (m3 << 1) | 0; + if ((b2[m3 >> 1] | 0) == 256) { + b2[m3 >> 1] = t3; + t3 = t3 + 1 << 16 >> 16; + } + u3 = u3 + 1 | 0; + } + while (1) { + if (m3 >>> 0 >= k2 >>> 0) break; + N3 = O3 + m3 | 0; + R3 = b2[I3 + (d[N3 >> 0] << 1) >> 1] | 0; + a[N3 >> 0] = R3; + if ((R3 & 255) >>> 0 >= C3 >>> 0) { + l2 = 372; + break d; + } + m3 = m3 + 1 | 0; + } + u3 = t3 & 65535; + if (u3 >>> 0 > C3 >>> 0) { + l2 = 375; + break; + } + t3 = t3 & 65535; + m3 = 0; + while (1) { + if ((m3 | 0) == (t3 | 0)) { + t3 = 0; + break; + } + ac(J3 + (m3 * 2832 | 0) | 0, 0, 2816) | 0; + c[J3 + (m3 * 2832 | 0) + 2816 >> 2] = 0; + h[J3 + (m3 * 2832 | 0) + 2824 >> 3] = s; + m3 = m3 + 1 | 0; + } + while (1) { + if ((t3 | 0) == (k2 | 0)) break; + R3 = d[O3 + t3 >> 0] | 0; + N3 = J3 + (R3 * 2832 | 0) + (e[Q3 + (t3 << 1) >> 1] << 2) | 0; + c[N3 >> 2] = (c[N3 >> 2] | 0) + 1; + R3 = J3 + (R3 * 2832 | 0) + 2816 | 0; + c[R3 >> 2] = (c[R3 >> 2] | 0) + 1; + t3 = t3 + 1 | 0; + } + N3 = v3; + C3 = u3; + A3 = A3 + 1 | 0; + } + if ((l2 | 0) == 319) pa2(404083, 403848, 80, 404221); + else if ((l2 | 0) == 350) pa2(404124, 403848, 130, 404221); + else if ((l2 | 0) == 357) pa2(404145, 403848, 141, 404221); + else if ((l2 | 0) == 366) pa2(404005, 403848, 165, 404200); + else if ((l2 | 0) == 372) pa2(404005, 403848, 172, 404200); + else if ((l2 | 0) == 375) pa2(404057, 403848, 174, 404200); + else if ((l2 | 0) == 382) { + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, F3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, G3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, H3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, I3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, J3); + t3 = N3 << 2; + L3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, t3) | 0; + if (!L3) oa2(1); + M2 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, t3) | 0; + if (!M2) oa2(1); + x3 = ((N3 << 4) + 1008 | 0) >>> 6; + R3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 * 2832 | 0) | 0; + v3 = R3; + if (!R3) oa2(1); + R3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 << 2) | 0; + w2 = R3; + if (!R3) oa2(1); + G3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, (N3 >>> 0 < 64 ? N3 : 64) * 2832 | 0) | 0; + if (!G3) oa2(1); + H3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, 49176) | 0; + if (!H3) oa2(1); + ac(V3 | 0, 0, 256) | 0; + ac(T3 | 0, 0, 256) | 0; + ac(W3 | 0, 0, 256) | 0; + ac(U3 | 0, 0, 256) | 0; + ac(M2 | 0, 0, t3 | 0) | 0; + m3 = 0; + u3 = 0; + while (1) { + if (u3 >>> 0 >= k2 >>> 0) break; + if (m3 >>> 0 >= N3 >>> 0) { + l2 = 397; + break; + } + t3 = M2 + (m3 << 2) | 0; + c[t3 >> 2] = (c[t3 >> 2] | 0) + 1; + t3 = u3 + 1 | 0; + if ((t3 | 0) != (k2 | 0) ? (a[O3 + u3 >> 0] | 0) == (a[O3 + t3 >> 0] | 0) : 0) { + u3 = t3; + continue; + } + m3 = m3 + 1 | 0; + u3 = t3; + } + if ((l2 | 0) == 397) pa2(403825, 403848, 231, 404179); + if ((m3 | 0) != (N3 | 0)) pa2(403911, 403848, 237, 404179); + C3 = x3; + B3 = x3; + J3 = 0; + t3 = 0; + F3 = 0; + while (1) { + if (N3 >>> 0 <= F3 >>> 0) { + l2 = 439; + break; + } + E3 = N3 - F3 | 0; + E3 = E3 >>> 0 < 64 ? E3 : 64; + n2 = 0; + while (1) { + if ((n2 | 0) == (E3 | 0)) break; + u3 = G3 + (n2 * 2832 | 0) | 0; + ac(u3 | 0, 0, 2816) | 0; + x3 = G3 + (n2 * 2832 | 0) + 2816 | 0; + c[x3 >> 2] = 0; + h[G3 + (n2 * 2832 | 0) + 2824 >> 3] = s; + l2 = M2 + (F3 + n2 << 2) | 0; + m3 = 0; + while (1) { + if (m3 >>> 0 >= (c[l2 >> 2] | 0) >>> 0) break; + R3 = G3 + (n2 * 2832 | 0) + (e[Q3 + (t3 << 1) >> 1] << 2) | 0; + c[R3 >> 2] = (c[R3 >> 2] | 0) + 1; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + t3 = t3 + 1 | 0; + m3 = m3 + 1 | 0; + } + h[G3 + (n2 * 2832 | 0) + 2824 >> 3] = +Xa2(u3); + c[T3 + (n2 << 2) >> 2] = n2; + c[W3 + (n2 << 2) >> 2] = n2; + c[V3 + (n2 << 2) >> 2] = 1; + n2 = n2 + 1 | 0; + } + D3 = rb(G3, V3, W3, T3, H3, E3, E3, 64, 2048) | 0; + m3 = J3 + D3 | 0; + if (C3 >>> 0 < m3 >>> 0) { + u3 = (C3 | 0) == 0; + x3 = u3 ? m3 : C3; + while (1) { + if (x3 >>> 0 >= m3 >>> 0) break; + x3 = x3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 * 2832 | 0) | 0; + if (!m3) { + l2 = 416; + break; + } + if (!u3) dc(m3 | 0, v3 | 0, C3 * 2832 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, v3); + v3 = m3; + C3 = x3; + } + m3 = J3 + D3 | 0; + if (B3 >>> 0 < m3 >>> 0) { + u3 = (B3 | 0) == 0; + x3 = u3 ? m3 : B3; + while (1) { + if (x3 >>> 0 >= m3 >>> 0) break; + x3 = x3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 << 2) | 0; + if (!m3) { + l2 = 425; + break; + } + if (!u3) dc(m3 | 0, w2 | 0, B3 << 2 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, w2); + w2 = m3; + B3 = x3; + } + m3 = v3; + u3 = w2; + A3 = D3 + J3 | 0; + x3 = J3; + l2 = J3; + n2 = 0; + while (1) { + if ((n2 | 0) == (D3 | 0)) { + m3 = 0; + break; + } + R3 = T3 + (n2 << 2) | 0; + K3 = c[R3 >> 2] | 0; + dc(m3 + (x3 * 2832 | 0) | 0, G3 + (K3 * 2832 | 0) | 0, 2832) | 0; + c[u3 + (l2 << 2) >> 2] = c[V3 + (K3 << 2) >> 2]; + c[U3 + (c[R3 >> 2] << 2) >> 2] = n2; + x3 = x3 + 1 | 0; + l2 = l2 + 1 | 0; + n2 = n2 + 1 | 0; + } + while (1) { + if ((m3 | 0) == (E3 | 0)) break; + c[L3 + (F3 + m3 << 2) >> 2] = J3 + (c[U3 + (c[W3 + (m3 << 2) >> 2] << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + m3 = D3 + J3 | 0; + if ((J3 + D3 | 0) != (m3 | 0)) { + l2 = 435; + break; + } + if ((m3 | 0) != (A3 | 0)) { + l2 = 437; + break; + } + J3 = m3; + F3 = F3 + 64 | 0; + } + if ((l2 | 0) == 416) oa2(1); + else if ((l2 | 0) == 425) oa2(1); + else if ((l2 | 0) == 435) pa2(403935, 403848, 273, 404179); + else if ((l2 | 0) == 437) pa2(403969, 403848, 274, 404179); + else if ((l2 | 0) == 439) { + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, G3); + R3 = J3 << 6; + u3 = _(J3 >>> 1, J3) | 0; + u3 = R3 >>> 0 < u3 >>> 0 ? R3 : u3; + do + if ((u3 + 1 | 0) >>> 0 > 2049) { + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, H3); + t3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, (u3 * 24 | 0) + 24 | 0) | 0; + if (t3) { + S3 = t3; + break; + } + oa2(1); + } else S3 = H3; + while (0); + m3 = J3 << 2; + I3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, m3) | 0; + if (!I3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (J3 | 0)) break; + c[I3 + (t3 << 2) >> 2] = t3; + t3 = t3 + 1 | 0; + } + H3 = v3; + G3 = rb(H3, w2, L3, I3, S3, J3, N3, 256, u3) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, S3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, w2); + K3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, m3) | 0; + if (!K3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (J3 | 0)) break; + c[K3 + (t3 << 2) >> 2] = -1; + t3 = t3 + 1 | 0; + } + B3 = Y3 + 2816 | 0; + C3 = Y3 + 2824 | 0; + D3 = Z3 + 2816 | 0; + E3 = Z3 + 2816 | 0; + t3 = 0; + m3 = 0; + F3 = 0; + while (1) { + if ((F3 | 0) == (N3 | 0)) break; + ac(Y3 | 0, 0, 2820) | 0; + h[C3 >> 3] = s; + u3 = M2 + (F3 << 2) | 0; + w2 = 0; + A3 = m3; + m3 = 0; + while (1) { + if (m3 >>> 0 >= (c[u3 >> 2] | 0) >>> 0) break; + w2 = Y3 + (e[Q3 + (A3 << 1) >> 1] << 2) | 0; + c[w2 >> 2] = (c[w2 >> 2] | 0) + 1; + w2 = (c[B3 >> 2] | 0) + 1 | 0; + c[B3 >> 2] = w2; + A3 = A3 + 1 | 0; + m3 = m3 + 1 | 0; + } + u3 = c[((F3 | 0) == 0 ? L3 : L3 + (F3 + -1 << 2) | 0) >> 2] | 0; + n2 = (w2 | 0) == 0; + if (n2) y3 = 0; + else { + dc(Z3 | 0, Y3 | 0, 2832) | 0; + c[E3 >> 2] = (c[E3 >> 2] | 0) + (c[H3 + (u3 * 2832 | 0) + 2816 >> 2] | 0); + m3 = 0; + while (1) { + if ((m3 | 0) == 704) break; + S3 = Z3 + (m3 << 2) | 0; + c[S3 >> 2] = (c[S3 >> 2] | 0) + (c[H3 + (u3 * 2832 | 0) + (m3 << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + y3 = +Xa2(Z3); + y3 = y3 - +h[H3 + (u3 * 2832 | 0) + 2824 >> 3]; + } + m3 = u3; + l2 = 0; + while (1) { + if ((l2 | 0) == (G3 | 0)) break; + x3 = I3 + (l2 << 2) | 0; + u3 = c[x3 >> 2] | 0; + if (n2) z3 = 0; + else { + dc(Z3 | 0, Y3 | 0, 2832) | 0; + c[D3 >> 2] = (c[D3 >> 2] | 0) + (c[H3 + (u3 * 2832 | 0) + 2816 >> 2] | 0); + w2 = 0; + while (1) { + if ((w2 | 0) == 704) break; + S3 = Z3 + (w2 << 2) | 0; + c[S3 >> 2] = (c[S3 >> 2] | 0) + (c[H3 + (u3 * 2832 | 0) + (w2 << 2) >> 2] | 0); + w2 = w2 + 1 | 0; + } + z3 = +Xa2(Z3); + z3 = z3 - +h[H3 + (u3 * 2832 | 0) + 2824 >> 3]; + } + if (z3 < y3) { + y3 = z3; + m3 = c[x3 >> 2] | 0; + } + l2 = l2 + 1 | 0; + } + c[L3 + (F3 << 2) >> 2] = m3; + m3 = K3 + (m3 << 2) | 0; + if ((c[m3 >> 2] | 0) == -1) { + c[m3 >> 2] = t3; + t3 = t3 + 1 | 0; + } + m3 = A3; + F3 = F3 + 1 | 0; + } + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, I3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, v3); + w2 = q2 + 16 | 0; + t3 = c[w2 >> 2] | 0; + if (t3 >>> 0 < N3 >>> 0) { + v3 = (t3 | 0) == 0 ? N3 : t3; + while (1) { + if (v3 >>> 0 >= N3 >>> 0) break; + v3 = v3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3) | 0; + if (!m3) oa2(1); + u3 = c[w2 >> 2] | 0; + t3 = q2 + 8 | 0; + if (u3) dc(m3 | 0, c[t3 >> 2] | 0, u3 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, c[t3 >> 2] | 0); + c[t3 >> 2] = m3; + c[w2 >> 2] = v3; + } + w2 = q2 + 20 | 0; + t3 = c[w2 >> 2] | 0; + if (t3 >>> 0 < N3 >>> 0) { + v3 = (t3 | 0) == 0 ? N3 : t3; + while (1) { + if (v3 >>> 0 >= N3 >>> 0) break; + v3 = v3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3 << 2) | 0; + if (!m3) oa2(1); + u3 = c[w2 >> 2] | 0; + t3 = q2 + 12 | 0; + if (u3) dc(m3 | 0, c[t3 >> 2] | 0, u3 << 2 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, c[t3 >> 2] | 0); + c[t3 >> 2] = m3; + c[w2 >> 2] = v3; + } else t3 = q2 + 12 | 0; + w2 = q2 + 8 | 0; + l2 = 0; + m3 = 0; + n2 = 0; + u3 = 0; + while (1) { + if ((u3 | 0) == (N3 | 0)) break; + v3 = m3 + (c[M2 + (u3 << 2) >> 2] | 0) | 0; + x3 = u3 + 1 | 0; + m3 = c[L3 + (u3 << 2) >> 2] | 0; + if ((x3 | 0) != (N3 | 0) ? (m3 | 0) == (c[L3 + (x3 << 2) >> 2] | 0) : 0) { + m3 = v3; + u3 = x3; + continue; + } + u3 = c[K3 + (m3 << 2) >> 2] | 0; + S3 = u3 & 255; + a[(c[w2 >> 2] | 0) + l2 >> 0] = S3; + c[(c[t3 >> 2] | 0) + (l2 << 2) >> 2] = v3; + l2 = l2 + 1 | 0; + m3 = 0; + n2 = ((n2 & 255) > (S3 & 255) ? n2 & 255 : u3 & 255) & 255; + u3 = x3; + } + c[q2 + 4 >> 2] = l2; + c[q2 >> 2] = (n2 & 255) + 1; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, K3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, M2); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, L3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, O3); + break; + } + } + } else c[q2 >> 2] = 1; + while (0); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, Q3); + P3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, P3) | 0; + if (!P3) oa2(1); + K3 = 0; + m3 = 0; + while (1) { + if ((m3 | 0) == (k2 | 0)) break; + if ((c[j2 + (m3 << 4) + 4 >> 2] & 16777215 | 0) != 0 ? (e[j2 + (m3 << 4) + 12 >> 1] | 0) > 127 : 0) { + b2[P3 + (K3 << 1) >> 1] = b2[j2 + (m3 << 4) + 14 >> 1] | 0; + t3 = K3 + 1 | 0; + } else t3 = K3; + K3 = t3; + m3 = m3 + 1 | 0; + } + C3 = ((K3 >>> 0) / 544 | 0) + 1 | 0; + C3 = C3 >>> 0 > 50 ? 50 : C3; + if (!K3) { + c[r2 >> 2] = 1; + f2 = c[p2 >> 2] | 0; + r2 = c[$2 >> 2] | 0; + ra2[f2 & 1](r2, P3); + i = aa2; + return; + } + if (K3 >>> 0 < 128) { + w2 = r2 + 16 | 0; + m3 = c[w2 >> 2] | 0; + x3 = r2 + 4 | 0; + t3 = c[x3 >> 2] | 0; + u3 = t3 + 1 | 0; + if (m3 >>> 0 < u3 >>> 0) { + v3 = (m3 | 0) == 0 ? u3 : m3; + while (1) { + if (v3 >>> 0 >= u3 >>> 0) break; + v3 = v3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3) | 0; + if (!m3) oa2(1); + u3 = c[w2 >> 2] | 0; + t3 = r2 + 8 | 0; + if (u3) dc(m3 | 0, c[t3 >> 2] | 0, u3 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, c[t3 >> 2] | 0); + c[t3 >> 2] = m3; + c[w2 >> 2] = v3; + t3 = c[x3 >> 2] | 0; + } + w2 = r2 + 20 | 0; + m3 = c[w2 >> 2] | 0; + u3 = t3 + 1 | 0; + if (m3 >>> 0 < u3 >>> 0) { + v3 = (m3 | 0) == 0 ? u3 : m3; + while (1) { + if (v3 >>> 0 >= u3 >>> 0) break; + v3 = v3 << 1; + } + t3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3 << 2) | 0; + if (!t3) oa2(1); + u3 = c[w2 >> 2] | 0; + m3 = r2 + 12 | 0; + if (u3) dc(t3 | 0, c[m3 >> 2] | 0, u3 << 2 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, c[m3 >> 2] | 0); + c[m3 >> 2] = t3; + c[w2 >> 2] = v3; + t3 = c[x3 >> 2] | 0; + } else m3 = r2 + 12 | 0; + c[r2 >> 2] = 1; + a[(c[r2 + 8 >> 2] | 0) + t3 >> 0] = 0; + c[(c[m3 >> 2] | 0) + (c[x3 >> 2] << 2) >> 2] = K3; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + f2 = c[p2 >> 2] | 0; + r2 = c[$2 >> 2] | 0; + ra2[f2 & 1](r2, P3); + i = aa2; + return; + } + J3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, C3 * 2096 | 0) | 0; + if (!J3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (C3 | 0)) break; + ac(J3 + (t3 * 2096 | 0) | 0, 0, 2080) | 0; + c[J3 + (t3 * 2096 | 0) + 2080 >> 2] = 0; + h[J3 + (t3 * 2096 | 0) + 2088 >> 3] = s; + t3 = t3 + 1 | 0; + } + v3 = (K3 >>> 0) / (C3 >>> 0) | 0; + w2 = K3 + -41 | 0; + m3 = 7; + x3 = 0; + while (1) { + if ((x3 | 0) == (C3 | 0)) break; + t3 = ((_(K3, x3) | 0) >>> 0) / (C3 >>> 0) | 0; + if (x3) { + m3 = m3 * 16807 | 0; + m3 = (m3 | 0) == 0 ? 1 : m3; + t3 = t3 + ((m3 >>> 0) % (v3 >>> 0) | 0) | 0; + } + u3 = J3 + (x3 * 2096 | 0) + 2080 | 0; + c[u3 >> 2] = (c[u3 >> 2] | 0) + 40; + u3 = P3 + (((t3 + 40 | 0) >>> 0 < K3 >>> 0 ? t3 : w2) << 1) | 0; + t3 = 41; + while (1) { + t3 = t3 + -1 | 0; + if (!t3) break; + k2 = J3 + (x3 * 2096 | 0) + (e[u3 >> 1] << 2) | 0; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + u3 = u3 + 2 | 0; + } + x3 = x3 + 1 | 0; + } + c[Z3 >> 2] = 7; + v3 = ((K3 << 1 >>> 0) / 40 | 0) + 100 + C3 + -1 | 0; + v3 = v3 - ((v3 >>> 0) % (C3 >>> 0) | 0) | 0; + w2 = Y3 + 2080 | 0; + x3 = Y3 + 2088 | 0; + l2 = K3 >>> 0 > 40; + n2 = K3 + -39 | 0; + A3 = Y3 + 2080 | 0; + B3 = 0; + while (1) { + if (B3 >>> 0 >= v3 >>> 0) break; + ac(Y3 | 0, 0, 2084) | 0; + h[x3 >> 3] = s; + if (l2) { + t3 = (c[Z3 >> 2] | 0) * 16807 | 0; + k2 = (t3 | 0) == 0; + c[Z3 >> 2] = k2 ? 1 : t3; + m3 = 40; + t3 = ((k2 ? 1 : t3) >>> 0) % (n2 >>> 0) | 0; + } else { + m3 = K3; + t3 = 0; + } + c[A3 >> 2] = (c[A3 >> 2] | 0) + m3; + u3 = P3 + (t3 << 1) | 0; + t3 = m3 + 1 | 0; + while (1) { + t3 = t3 + -1 | 0; + if (!t3) break; + k2 = Y3 + (e[u3 >> 1] << 2) | 0; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + u3 = u3 + 2 | 0; + } + t3 = (B3 >>> 0) % (C3 >>> 0) | 0; + m3 = J3 + (t3 * 2096 | 0) + 2080 | 0; + c[m3 >> 2] = (c[m3 >> 2] | 0) + (c[w2 >> 2] | 0); + m3 = 0; + while (1) { + if ((m3 | 0) == 520) break; + k2 = J3 + (t3 * 2096 | 0) + (m3 << 2) | 0; + c[k2 >> 2] = (c[k2 >> 2] | 0) + (c[Y3 + (m3 << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + B3 = B3 + 1 | 0; + } + O3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, K3) | 0; + if (!O3) oa2(1); + F3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, C3 * 4160 | 0) | 0; + if (!F3) oa2(1); + G3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, C3 << 3) | 0; + if (!G3) oa2(1); + H3 = _(K3, (C3 + 7 | 0) >>> 3) | 0; + H3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, H3) | 0; + if (!H3) oa2(1); + I3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, C3 << 1) | 0; + if (!I3) oa2(1); + B3 = (c[o2 + 4 >> 2] | 0) < 11 ? 3 : 10; + D3 = K3 + -1 | 0; + E3 = O3 + D3 | 0; + N3 = 0; + A3 = 0; + g: while (1) { + if (A3 >>> 0 >= B3 >>> 0) { + l2 = 631; + break; + } + n2 = (C3 + 7 | 0) >>> 3; + if (C3 >>> 0 >= 257) { + l2 = 568; + break; + } + h: do + if (C3 >>> 0 < 2) { + t3 = 0; + while (1) { + if ((t3 | 0) == (K3 | 0)) { + v3 = 1; + break h; + } + a[O3 + t3 >> 0] = 0; + t3 = t3 + 1 | 0; + } + } else { + ac(F3 | 0, 0, C3 * 4160 | 0) | 0; + m3 = 0; + while (1) { + if ((m3 | 0) == (C3 | 0)) { + t3 = 520; + break; + } + t3 = c[J3 + (m3 * 2096 | 0) + 2080 >> 2] | 0; + if (t3 >>> 0 < 256) y3 = +g2[19516 + (t3 << 2) >> 2]; + else y3 = +Xb(+(t3 >>> 0)); + h[F3 + (m3 << 3) >> 3] = y3; + m3 = m3 + 1 | 0; + } + i: while (1) { + if (!t3) break; + t3 = t3 + -1 | 0; + u3 = _(t3, C3) | 0; + v3 = 0; + while (1) { + if ((v3 | 0) == (C3 | 0)) continue i; + z3 = +h[F3 + (v3 << 3) >> 3]; + m3 = c[J3 + (v3 * 2096 | 0) + (t3 << 2) >> 2] | 0; + do + if (m3) if (m3 >>> 0 < 256) { + y3 = +g2[19516 + (m3 << 2) >> 2]; + break; + } else { + y3 = +Xb(+(m3 >>> 0)); + break; + } + else y3 = -2; + while (0); + h[F3 + (u3 + v3 << 3) >> 3] = z3 - y3; + v3 = v3 + 1 | 0; + } + } + ac(G3 | 0, 0, C3 << 3 | 0) | 0; + ac(H3 | 0, 0, _(K3, n2) | 0) | 0; + v3 = 0; + while (1) { + if (v3 >>> 0 >= K3 >>> 0) break; + t3 = _(e[P3 + (v3 << 1) >> 1] | 0, C3) | 0; + m3 = O3 + v3 | 0; + z3 = 1e99; + u3 = 0; + while (1) { + if ((u3 | 0) == (C3 | 0)) break; + o2 = G3 + (u3 << 3) | 0; + y3 = +h[o2 >> 3] + +h[F3 + (t3 + u3 << 3) >> 3]; + h[o2 >> 3] = y3; + if (y3 < z3) a[m3 >> 0] = u3; + else y3 = z3; + z3 = y3; + u3 = u3 + 1 | 0; + } + m3 = _(v3, n2) | 0; + if (v3 >>> 0 < 2e3) y3 = (+(v3 >>> 0) * 0.07 / 2e3 + 0.77) * 14.6; + else y3 = 14.6; + u3 = 0; + while (1) { + if (u3 >>> 0 >= C3 >>> 0) break; + t3 = G3 + (u3 << 3) | 0; + ba2 = +h[t3 >> 3] - z3; + h[t3 >> 3] = ba2; + if (ba2 >= y3) { + h[t3 >> 3] = y3; + t3 = u3 >>> 3; + if (t3 >>> 0 >= n2 >>> 0) { + l2 = 599; + break g; + } + o2 = H3 + (m3 + t3) | 0; + a[o2 >> 0] = a[o2 >> 0] | 1 << (u3 & 7) & 255; + } + u3 = u3 + 1 | 0; + } + v3 = v3 + 1 | 0; + } + m3 = _(D3, n2) | 0; + v3 = D3; + t3 = a[E3 >> 0] | 0; + u3 = 1; + while (1) { + if (!v3) { + v3 = u3; + break h; + } + w2 = t3 & 255; + x3 = w2 >>> 3; + if (x3 >>> 0 >= n2 >>> 0) { + l2 = 606; + break g; + } + l2 = v3 + -1 | 0; + m3 = m3 - n2 | 0; + v3 = O3 + l2 | 0; + if ((a[H3 + (m3 + x3) >> 0] & (1 << (w2 & 7) & 255)) << 24 >> 24) { + k2 = a[v3 >> 0] | 0; + o2 = t3 << 24 >> 24 == k2 << 24 >> 24; + t3 = o2 ? t3 : k2; + u3 = o2 ? u3 : u3 + 1 | 0; + } + a[v3 >> 0] = t3; + v3 = l2; + } + } + while (0); + t3 = 0; + while (1) { + if ((t3 | 0) == (C3 | 0)) { + t3 = 0; + u3 = 0; + break; + } + b2[I3 + (t3 << 1) >> 1] = 256; + t3 = t3 + 1 | 0; + } + while (1) { + if (u3 >>> 0 >= K3 >>> 0) { + m3 = 0; + break; + } + m3 = d[O3 + u3 >> 0] | 0; + if (m3 >>> 0 >= C3 >>> 0) { + l2 = 615; + break g; + } + m3 = I3 + (m3 << 1) | 0; + if ((b2[m3 >> 1] | 0) == 256) { + b2[m3 >> 1] = t3; + t3 = t3 + 1 << 16 >> 16; + } + u3 = u3 + 1 | 0; + } + while (1) { + if (m3 >>> 0 >= K3 >>> 0) break; + k2 = O3 + m3 | 0; + o2 = b2[I3 + (d[k2 >> 0] << 1) >> 1] | 0; + a[k2 >> 0] = o2; + if ((o2 & 255) >>> 0 >= C3 >>> 0) { + l2 = 621; + break g; + } + m3 = m3 + 1 | 0; + } + u3 = t3 & 65535; + if (u3 >>> 0 > C3 >>> 0) { + l2 = 624; + break; + } + t3 = t3 & 65535; + m3 = 0; + while (1) { + if ((m3 | 0) == (t3 | 0)) { + t3 = 0; + break; + } + ac(J3 + (m3 * 2096 | 0) | 0, 0, 2080) | 0; + c[J3 + (m3 * 2096 | 0) + 2080 >> 2] = 0; + h[J3 + (m3 * 2096 | 0) + 2088 >> 3] = s; + m3 = m3 + 1 | 0; + } + while (1) { + if ((t3 | 0) == (K3 | 0)) break; + o2 = d[O3 + t3 >> 0] | 0; + k2 = J3 + (o2 * 2096 | 0) + (e[P3 + (t3 << 1) >> 1] << 2) | 0; + c[k2 >> 2] = (c[k2 >> 2] | 0) + 1; + o2 = J3 + (o2 * 2096 | 0) + 2080 | 0; + c[o2 >> 2] = (c[o2 >> 2] | 0) + 1; + t3 = t3 + 1 | 0; + } + N3 = v3; + C3 = u3; + A3 = A3 + 1 | 0; + } + if ((l2 | 0) == 568) pa2(404083, 403848, 80, 404105); + else if ((l2 | 0) == 599) pa2(404124, 403848, 130, 404105); + else if ((l2 | 0) == 606) pa2(404145, 403848, 141, 404105); + else if ((l2 | 0) == 615) pa2(404005, 403848, 165, 404035); + else if ((l2 | 0) == 621) pa2(404005, 403848, 172, 404035); + else if ((l2 | 0) == 624) pa2(404057, 403848, 174, 404035); + else if ((l2 | 0) == 631) { + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, F3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, G3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, H3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, I3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, J3); + t3 = N3 << 2; + L3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, t3) | 0; + if (!L3) oa2(1); + M2 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, t3) | 0; + if (!M2) oa2(1); + x3 = ((N3 << 4) + 1008 | 0) >>> 6; + o2 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 * 2096 | 0) | 0; + v3 = o2; + if (!o2) oa2(1); + o2 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 << 2) | 0; + w2 = o2; + if (!o2) oa2(1); + G3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, (N3 >>> 0 < 64 ? N3 : 64) * 2096 | 0) | 0; + if (!G3) oa2(1); + H3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, 49176) | 0; + if (!H3) oa2(1); + ac(V3 | 0, 0, 256) | 0; + ac(T3 | 0, 0, 256) | 0; + ac(W3 | 0, 0, 256) | 0; + ac(U3 | 0, 0, 256) | 0; + ac(M2 | 0, 0, t3 | 0) | 0; + m3 = 0; + u3 = 0; + while (1) { + if (u3 >>> 0 >= K3 >>> 0) break; + if (m3 >>> 0 >= N3 >>> 0) { + l2 = 646; + break; + } + t3 = M2 + (m3 << 2) | 0; + c[t3 >> 2] = (c[t3 >> 2] | 0) + 1; + t3 = u3 + 1 | 0; + if ((t3 | 0) != (K3 | 0) ? (a[O3 + u3 >> 0] | 0) == (a[O3 + t3 >> 0] | 0) : 0) { + u3 = t3; + continue; + } + m3 = m3 + 1 | 0; + u3 = t3; + } + if ((l2 | 0) == 646) pa2(403825, 403848, 231, 403889); + if ((m3 | 0) != (N3 | 0)) pa2(403911, 403848, 237, 403889); + C3 = x3; + B3 = x3; + K3 = 0; + t3 = 0; + F3 = 0; + while (1) { + if (N3 >>> 0 <= F3 >>> 0) { + l2 = 688; + break; + } + E3 = N3 - F3 | 0; + E3 = E3 >>> 0 < 64 ? E3 : 64; + n2 = 0; + while (1) { + if ((n2 | 0) == (E3 | 0)) break; + u3 = G3 + (n2 * 2096 | 0) | 0; + ac(u3 | 0, 0, 2080) | 0; + x3 = G3 + (n2 * 2096 | 0) + 2080 | 0; + c[x3 >> 2] = 0; + h[G3 + (n2 * 2096 | 0) + 2088 >> 3] = s; + l2 = M2 + (F3 + n2 << 2) | 0; + m3 = 0; + while (1) { + if (m3 >>> 0 >= (c[l2 >> 2] | 0) >>> 0) break; + o2 = G3 + (n2 * 2096 | 0) + (e[P3 + (t3 << 1) >> 1] << 2) | 0; + c[o2 >> 2] = (c[o2 >> 2] | 0) + 1; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + t3 = t3 + 1 | 0; + m3 = m3 + 1 | 0; + } + h[G3 + (n2 * 2096 | 0) + 2088 >> 3] = +Ya(u3); + c[T3 + (n2 << 2) >> 2] = n2; + c[W3 + (n2 << 2) >> 2] = n2; + c[V3 + (n2 << 2) >> 2] = 1; + n2 = n2 + 1 | 0; + } + D3 = tb(G3, V3, W3, T3, H3, E3, E3, 64, 2048) | 0; + m3 = K3 + D3 | 0; + if (C3 >>> 0 < m3 >>> 0) { + u3 = (C3 | 0) == 0; + x3 = u3 ? m3 : C3; + while (1) { + if (x3 >>> 0 >= m3 >>> 0) break; + x3 = x3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 * 2096 | 0) | 0; + if (!m3) { + l2 = 665; + break; + } + if (!u3) dc(m3 | 0, v3 | 0, C3 * 2096 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, v3); + v3 = m3; + C3 = x3; + } + m3 = K3 + D3 | 0; + if (B3 >>> 0 < m3 >>> 0) { + u3 = (B3 | 0) == 0; + x3 = u3 ? m3 : B3; + while (1) { + if (x3 >>> 0 >= m3 >>> 0) break; + x3 = x3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, x3 << 2) | 0; + if (!m3) { + l2 = 674; + break; + } + if (!u3) dc(m3 | 0, w2 | 0, B3 << 2 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, w2); + w2 = m3; + B3 = x3; + } + m3 = v3; + u3 = w2; + A3 = D3 + K3 | 0; + x3 = K3; + l2 = K3; + n2 = 0; + while (1) { + if ((n2 | 0) == (D3 | 0)) { + m3 = 0; + break; + } + o2 = T3 + (n2 << 2) | 0; + k2 = c[o2 >> 2] | 0; + dc(m3 + (x3 * 2096 | 0) | 0, G3 + (k2 * 2096 | 0) | 0, 2096) | 0; + c[u3 + (l2 << 2) >> 2] = c[V3 + (k2 << 2) >> 2]; + c[U3 + (c[o2 >> 2] << 2) >> 2] = n2; + x3 = x3 + 1 | 0; + l2 = l2 + 1 | 0; + n2 = n2 + 1 | 0; + } + while (1) { + if ((m3 | 0) == (E3 | 0)) break; + c[L3 + (F3 + m3 << 2) >> 2] = K3 + (c[U3 + (c[W3 + (m3 << 2) >> 2] << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + m3 = D3 + K3 | 0; + if ((K3 + D3 | 0) != (m3 | 0)) { + l2 = 684; + break; + } + if ((m3 | 0) != (A3 | 0)) { + l2 = 686; + break; + } + K3 = m3; + F3 = F3 + 64 | 0; + } + if ((l2 | 0) == 665) oa2(1); + else if ((l2 | 0) == 674) oa2(1); + else if ((l2 | 0) == 684) pa2(403935, 403848, 273, 403889); + else if ((l2 | 0) == 686) pa2(403969, 403848, 274, 403889); + else if ((l2 | 0) == 688) { + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, G3); + W3 = K3 << 6; + u3 = _(K3 >>> 1, K3) | 0; + u3 = W3 >>> 0 < u3 >>> 0 ? W3 : u3; + do + if ((u3 + 1 | 0) >>> 0 > 2049) { + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, H3); + t3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, (u3 * 24 | 0) + 24 | 0) | 0; + if (t3) { + X3 = t3; + break; + } + oa2(1); + } else X3 = H3; + while (0); + m3 = K3 << 2; + I3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, m3) | 0; + if (!I3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (K3 | 0)) break; + c[I3 + (t3 << 2) >> 2] = t3; + t3 = t3 + 1 | 0; + } + H3 = v3; + G3 = tb(H3, w2, L3, I3, X3, K3, N3, 256, u3) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, X3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, w2); + J3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, m3) | 0; + if (!J3) oa2(1); + t3 = 0; + while (1) { + if ((t3 | 0) == (K3 | 0)) break; + c[J3 + (t3 << 2) >> 2] = -1; + t3 = t3 + 1 | 0; + } + B3 = Y3 + 2080 | 0; + C3 = Y3 + 2088 | 0; + D3 = Z3 + 2080 | 0; + E3 = Z3 + 2080 | 0; + t3 = 0; + m3 = 0; + F3 = 0; + while (1) { + if ((F3 | 0) == (N3 | 0)) break; + ac(Y3 | 0, 0, 2084) | 0; + h[C3 >> 3] = s; + u3 = M2 + (F3 << 2) | 0; + w2 = 0; + A3 = m3; + m3 = 0; + while (1) { + if (m3 >>> 0 >= (c[u3 >> 2] | 0) >>> 0) break; + w2 = Y3 + (e[P3 + (A3 << 1) >> 1] << 2) | 0; + c[w2 >> 2] = (c[w2 >> 2] | 0) + 1; + w2 = (c[B3 >> 2] | 0) + 1 | 0; + c[B3 >> 2] = w2; + A3 = A3 + 1 | 0; + m3 = m3 + 1 | 0; + } + u3 = c[((F3 | 0) == 0 ? L3 : L3 + (F3 + -1 << 2) | 0) >> 2] | 0; + n2 = (w2 | 0) == 0; + if (n2) y3 = 0; + else { + dc(Z3 | 0, Y3 | 0, 2096) | 0; + c[E3 >> 2] = (c[E3 >> 2] | 0) + (c[H3 + (u3 * 2096 | 0) + 2080 >> 2] | 0); + m3 = 0; + while (1) { + if ((m3 | 0) == 520) break; + X3 = Z3 + (m3 << 2) | 0; + c[X3 >> 2] = (c[X3 >> 2] | 0) + (c[H3 + (u3 * 2096 | 0) + (m3 << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + y3 = +Ya(Z3); + y3 = y3 - +h[H3 + (u3 * 2096 | 0) + 2088 >> 3]; + } + m3 = u3; + l2 = 0; + while (1) { + if ((l2 | 0) == (G3 | 0)) break; + x3 = I3 + (l2 << 2) | 0; + u3 = c[x3 >> 2] | 0; + if (n2) z3 = 0; + else { + dc(Z3 | 0, Y3 | 0, 2096) | 0; + c[D3 >> 2] = (c[D3 >> 2] | 0) + (c[H3 + (u3 * 2096 | 0) + 2080 >> 2] | 0); + w2 = 0; + while (1) { + if ((w2 | 0) == 520) break; + X3 = Z3 + (w2 << 2) | 0; + c[X3 >> 2] = (c[X3 >> 2] | 0) + (c[H3 + (u3 * 2096 | 0) + (w2 << 2) >> 2] | 0); + w2 = w2 + 1 | 0; + } + z3 = +Ya(Z3); + z3 = z3 - +h[H3 + (u3 * 2096 | 0) + 2088 >> 3]; + } + if (z3 < y3) { + y3 = z3; + m3 = c[x3 >> 2] | 0; + } + l2 = l2 + 1 | 0; + } + c[L3 + (F3 << 2) >> 2] = m3; + m3 = J3 + (m3 << 2) | 0; + if ((c[m3 >> 2] | 0) == -1) { + c[m3 >> 2] = t3; + t3 = t3 + 1 | 0; + } + m3 = A3; + F3 = F3 + 1 | 0; + } + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, I3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, v3); + w2 = r2 + 16 | 0; + t3 = c[w2 >> 2] | 0; + if (t3 >>> 0 < N3 >>> 0) { + v3 = (t3 | 0) == 0 ? N3 : t3; + while (1) { + if (v3 >>> 0 >= N3 >>> 0) break; + v3 = v3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3) | 0; + if (!m3) oa2(1); + u3 = c[w2 >> 2] | 0; + t3 = r2 + 8 | 0; + if (u3) dc(m3 | 0, c[t3 >> 2] | 0, u3 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, c[t3 >> 2] | 0); + c[t3 >> 2] = m3; + c[w2 >> 2] = v3; + } + w2 = r2 + 20 | 0; + t3 = c[w2 >> 2] | 0; + if (t3 >>> 0 < N3 >>> 0) { + v3 = (t3 | 0) == 0 ? N3 : t3; + while (1) { + if (v3 >>> 0 >= N3 >>> 0) break; + v3 = v3 << 1; + } + m3 = sa2[c[f2 >> 2] & 1](c[$2 >> 2] | 0, v3 << 2) | 0; + if (!m3) oa2(1); + u3 = c[w2 >> 2] | 0; + t3 = r2 + 12 | 0; + if (u3) dc(m3 | 0, c[t3 >> 2] | 0, u3 << 2 | 0) | 0; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, c[t3 >> 2] | 0); + c[t3 >> 2] = m3; + c[w2 >> 2] = v3; + } else t3 = r2 + 12 | 0; + w2 = r2 + 8 | 0; + l2 = 0; + m3 = 0; + n2 = 0; + u3 = 0; + while (1) { + if ((u3 | 0) == (N3 | 0)) break; + v3 = m3 + (c[M2 + (u3 << 2) >> 2] | 0) | 0; + x3 = u3 + 1 | 0; + m3 = c[L3 + (u3 << 2) >> 2] | 0; + if ((x3 | 0) != (N3 | 0) ? (m3 | 0) == (c[L3 + (x3 << 2) >> 2] | 0) : 0) { + m3 = v3; + u3 = x3; + continue; + } + u3 = c[J3 + (m3 << 2) >> 2] | 0; + f2 = u3 & 255; + a[(c[w2 >> 2] | 0) + l2 >> 0] = f2; + c[(c[t3 >> 2] | 0) + (l2 << 2) >> 2] = v3; + l2 = l2 + 1 | 0; + m3 = 0; + n2 = ((n2 & 255) > (f2 & 255) ? n2 & 255 : u3 & 255) & 255; + u3 = x3; + } + c[r2 + 4 >> 2] = l2; + c[r2 >> 2] = (n2 & 255) + 1; + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, J3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, M2); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, L3); + ra2[c[p2 >> 2] & 1](c[$2 >> 2] | 0, O3); + f2 = c[p2 >> 2] | 0; + r2 = c[$2 >> 2] | 0; + ra2[f2 & 1](r2, P3); + i = aa2; + return; + } + } + } + function _a(b3, f2, g3, h2, j2) { + b3 = b3 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + var k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0; + A3 = i; + i = i + 1552 | 0; + y3 = A3 + 840 | 0; + z3 = A3 + 136 | 0; + v3 = A3 + 72 | 0; + w2 = A3 + 112 | 0; + x3 = A3 + 76 | 0; + t3 = A3; + c[v3 >> 2] = 0; + l2 = w2; + m3 = l2 + 18 | 0; + do { + a[l2 >> 0] = 0; + l2 = l2 + 1 | 0; + } while ((l2 | 0) < (m3 | 0)); + l2 = t3; + m3 = l2 + 72 | 0; + do { + c[l2 >> 2] = 0; + l2 = l2 + 4 | 0; + } while ((l2 | 0) < (m3 | 0)); + if (f2 >>> 0 < 705) { + s2 = f2; + k2 = 0; + } else pa2(404299, 404333, 308, 404371); + while (1) { + if (k2 >>> 0 >= f2 >>> 0) break; + if (a[b3 + (f2 - k2 + -1) >> 0] | 0) break; + s2 = s2 + -1 | 0; + k2 = k2 + 1 | 0; + } + if (f2 >>> 0 > 50) { + m3 = 1; + f2 = 1; + q2 = 0; + n2 = 0; + o2 = 0; + while (1) { + if (q2 >>> 0 >= s2 >>> 0) break; + l2 = a[b3 + q2 >> 0] | 0; + p2 = 1; + k2 = q2; + while (1) { + k2 = k2 + 1 | 0; + if (k2 >>> 0 >= s2 >>> 0) break; + if ((a[b3 + k2 >> 0] | 0) != l2 << 24 >> 24) break; + p2 = p2 + 1 | 0; + } + if (p2 >>> 0 > 2) { + r2 = l2 << 24 >> 24 == 0; + f2 = r2 ? f2 + 1 | 0 : f2; + k2 = r2 ? o2 + p2 | 0 : o2; + if (p2 >>> 0 > 3 ? !r2 : 0) { + m3 = m3 + 1 | 0; + l2 = n2 + p2 | 0; + } else l2 = n2; + } else { + l2 = n2; + k2 = o2; + } + q2 = q2 + p2 | 0; + n2 = l2; + o2 = k2; + } + k2 = n2 >>> 0 > m3 << 1 >>> 0 & 1; + f2 = o2 >>> 0 > f2 << 1 >>> 0 & 1; + } else { + k2 = 0; + f2 = 0; + } + r2 = f2 << 24 >> 24 == 0; + p2 = k2 << 24 >> 24 == 0; + n2 = 8; + q2 = 0; + a: while (1) { + if (q2 >>> 0 >= s2 >>> 0) break; + o2 = a[b3 + q2 >> 0] | 0; + l2 = o2 << 24 >> 24 == 0; + if (l2) if (r2) { + f2 = 1; + u3 = 30; + } else { + k2 = q2; + f2 = 1; + u3 = 23; + } + else if (p2) { + f2 = 1; + u3 = 43; + } else { + k2 = q2; + f2 = 1; + u3 = 23; + } + b: do + if ((u3 | 0) == 23) { + while (1) { + u3 = 0; + k2 = k2 + 1 | 0; + if (k2 >>> 0 >= s2 >>> 0) break; + if ((a[b3 + k2 >> 0] | 0) != o2 << 24 >> 24) break; + f2 = f2 + 1 | 0; + u3 = 23; + } + if (!l2) if (!f2) { + u3 = 42; + break a; + } else { + u3 = 43; + break; + } + if ((f2 | 0) != 11) if (f2 >>> 0 < 3) { + u3 = 30; + break; + } else m3 = f2; + else { + a[y3 + (c[v3 >> 2] | 0) >> 0] = 0; + a[z3 + (c[v3 >> 2] | 0) >> 0] = 0; + c[v3 >> 2] = (c[v3 >> 2] | 0) + 1; + m3 = 10; + } + l2 = c[v3 >> 2] | 0; + k2 = l2; + m3 = m3 + -3 | 0; + while (1) { + a[y3 + k2 >> 0] = 17; + a[z3 + (c[v3 >> 2] | 0) >> 0] = m3 & 7; + k2 = (c[v3 >> 2] | 0) + 1 | 0; + c[v3 >> 2] = k2; + m3 = m3 >>> 3; + if (!m3) { + m3 = l2; + break; + } + m3 = m3 + -1 | 0; + } + while (1) { + k2 = k2 + -1 | 0; + if (m3 >>> 0 >= k2 >>> 0) break; + D3 = y3 + m3 | 0; + B3 = a[D3 >> 0] | 0; + o2 = y3 + k2 | 0; + a[D3 >> 0] = a[o2 >> 0] | 0; + a[o2 >> 0] = B3; + m3 = m3 + 1 | 0; + } + k2 = c[v3 >> 2] | 0; + while (1) { + k2 = k2 + -1 | 0; + if (l2 >>> 0 >= k2 >>> 0) { + k2 = n2; + break b; + } + o2 = z3 + l2 | 0; + B3 = a[o2 >> 0] | 0; + D3 = z3 + k2 | 0; + a[o2 >> 0] = a[D3 >> 0] | 0; + a[D3 >> 0] = B3; + l2 = l2 + 1 | 0; + } + } + while (0); + c: do + if ((u3 | 0) == 30) { + u3 = 0; + k2 = 0; + while (1) { + if ((k2 | 0) == (f2 | 0)) { + k2 = n2; + break c; + } + a[y3 + (c[v3 >> 2] | 0) >> 0] = 0; + a[z3 + (c[v3 >> 2] | 0) >> 0] = 0; + c[v3 >> 2] = (c[v3 >> 2] | 0) + 1; + k2 = k2 + 1 | 0; + } + } else if ((u3 | 0) == 43) { + u3 = 0; + if (n2 << 24 >> 24 == o2 << 24 >> 24) k2 = f2; + else { + a[y3 + (c[v3 >> 2] | 0) >> 0] = o2; + a[z3 + (c[v3 >> 2] | 0) >> 0] = 0; + c[v3 >> 2] = (c[v3 >> 2] | 0) + 1; + k2 = f2 + -1 | 0; + } + if ((k2 | 0) == 7) { + a[y3 + (c[v3 >> 2] | 0) >> 0] = o2; + a[z3 + (c[v3 >> 2] | 0) >> 0] = 0; + c[v3 >> 2] = (c[v3 >> 2] | 0) + 1; + k2 = k2 + -1 | 0; + } + if (k2 >>> 0 < 3) { + l2 = 0; + while (1) { + if ((l2 | 0) == (k2 | 0)) { + k2 = o2; + break c; + } + a[y3 + (c[v3 >> 2] | 0) >> 0] = o2; + a[z3 + (c[v3 >> 2] | 0) >> 0] = 0; + c[v3 >> 2] = (c[v3 >> 2] | 0) + 1; + l2 = l2 + 1 | 0; + } + } + l2 = c[v3 >> 2] | 0; + n2 = l2; + m3 = k2 + -3 | 0; + while (1) { + a[y3 + n2 >> 0] = 16; + a[z3 + (c[v3 >> 2] | 0) >> 0] = m3 & 3; + k2 = (c[v3 >> 2] | 0) + 1 | 0; + c[v3 >> 2] = k2; + m3 = m3 >>> 2; + if (!m3) { + m3 = l2; + break; + } + n2 = k2; + m3 = m3 + -1 | 0; + } + while (1) { + k2 = k2 + -1 | 0; + if (m3 >>> 0 >= k2 >>> 0) break; + n2 = y3 + m3 | 0; + B3 = a[n2 >> 0] | 0; + D3 = y3 + k2 | 0; + a[n2 >> 0] = a[D3 >> 0] | 0; + a[D3 >> 0] = B3; + m3 = m3 + 1 | 0; + } + k2 = c[v3 >> 2] | 0; + while (1) { + k2 = k2 + -1 | 0; + if (l2 >>> 0 >= k2 >>> 0) { + k2 = o2; + break c; + } + n2 = z3 + l2 | 0; + B3 = a[n2 >> 0] | 0; + D3 = z3 + k2 | 0; + a[n2 >> 0] = a[D3 >> 0] | 0; + a[D3 >> 0] = B3; + l2 = l2 + 1 | 0; + } + } + while (0); + n2 = k2; + q2 = q2 + f2 | 0; + } + if ((u3 | 0) == 42) pa2(406724, 406674, 168, 406740); + f2 = c[v3 >> 2] | 0; + k2 = 0; + while (1) { + if ((k2 | 0) == (f2 | 0)) { + r2 = 0; + k2 = 0; + l2 = 0; + break; + } + D3 = t3 + (d[y3 + k2 >> 0] << 2) | 0; + c[D3 >> 2] = (c[D3 >> 2] | 0) + 1; + k2 = k2 + 1 | 0; + } + while (1) { + if (l2 >>> 0 >= 18) { + q2 = k2; + break; + } + if (c[t3 + (l2 << 2) >> 2] | 0) if (k2) if ((k2 | 0) == 1) { + q2 = 2; + break; + } else f2 = r2; + else { + f2 = l2; + k2 = 1; + } + else f2 = r2; + r2 = f2; + l2 = l2 + 1 | 0; + } + Hb(t3, 18, 5, g3, w2); + Jb(w2, 18, x3); + d: do + if ((q2 | 0) > 1) { + k2 = 18; + while (1) { + if (!k2) break d; + f2 = k2 + -1 | 0; + if (!(a[w2 + (d[405371 + f2 >> 0] | 0) >> 0] | 0)) k2 = f2; + else break; + } + } else k2 = 18; + while (0); + if ((a[w2 + 1 >> 0] | 0) == 0 ? (a[w2 + 2 >> 0] | 0) == 0 : 0) f2 = (a[w2 + 3 >> 0] | 0) == 0 ? 3 : 2; + else f2 = 0; + g3 = c[h2 >> 2] | 0; + p2 = j2 + (g3 >>> 3) | 0; + B3 = d[p2 >> 0] | 0; + g3 = cc(f2 | 0, 0, g3 & 7 | 0) | 0; + D3 = C2; + g3 = B3 | g3; + B3 = p2; + a[B3 >> 0] = g3; + a[B3 + 1 >> 0] = g3 >> 8; + a[B3 + 2 >> 0] = g3 >> 16; + a[B3 + 3 >> 0] = g3 >> 24; + p2 = p2 + 4 | 0; + a[p2 >> 0] = D3; + a[p2 + 1 >> 0] = D3 >> 8; + a[p2 + 2 >> 0] = D3 >> 16; + a[p2 + 3 >> 0] = D3 >> 24; + p2 = (c[h2 >> 2] | 0) + 2 | 0; + c[h2 >> 2] = p2; + while (1) { + if (f2 >>> 0 >= k2 >>> 0) break; + m3 = d[w2 + (d[405371 + f2 >> 0] | 0) >> 0] | 0; + l2 = a[405389 + m3 >> 0] | 0; + m3 = d[405395 + m3 >> 0] | 0; + n2 = j2 + (p2 >>> 3) | 0; + o2 = d[n2 >> 0] | 0; + D3 = bc(m3 | 0, 0, l2 & 255 | 0) | 0; + if (!((D3 | 0) == 0 & (C2 | 0) == 0)) { + u3 = 76; + break; + } + t3 = cc(m3 | 0, 0, p2 & 7 | 0) | 0; + B3 = C2; + t3 = o2 | t3; + D3 = n2; + g3 = D3; + a[g3 >> 0] = t3; + a[g3 + 1 >> 0] = t3 >> 8; + a[g3 + 2 >> 0] = t3 >> 16; + a[g3 + 3 >> 0] = t3 >> 24; + D3 = D3 + 4 | 0; + a[D3 >> 0] = B3; + a[D3 + 1 >> 0] = B3 >> 8; + a[D3 + 2 >> 0] = B3 >> 16; + a[D3 + 3 >> 0] = B3 >> 24; + D3 = (c[h2 >> 2] | 0) + (l2 & 255) | 0; + c[h2 >> 2] = D3; + p2 = D3; + f2 = f2 + 1 | 0; + } + if ((u3 | 0) == 76) pa2(406196, 406218, 54, 406251); + if ((q2 | 0) == 1) a[w2 + r2 >> 0] = 0; + p2 = c[v3 >> 2] | 0; + q2 = 0; + e: while (1) { + if (q2 >>> 0 >= p2 >>> 0) { + u3 = 94; + break; + } + o2 = d[y3 + q2 >> 0] | 0; + f2 = a[w2 + o2 >> 0] | 0; + k2 = e[x3 + (o2 << 1) >> 1] | 0; + l2 = c[h2 >> 2] | 0; + m3 = j2 + (l2 >>> 3) | 0; + n2 = d[m3 >> 0] | 0; + D3 = bc(k2 | 0, 0, f2 & 255 | 0) | 0; + if (!((D3 | 0) == 0 & (C2 | 0) == 0)) { + u3 = 83; + break; + } + if ((f2 & 255) >= 57) { + u3 = 85; + break; + } + v3 = cc(k2 | 0, 0, l2 & 7 | 0) | 0; + D3 = C2; + v3 = n2 | v3; + B3 = m3; + a[B3 >> 0] = v3; + a[B3 + 1 >> 0] = v3 >> 8; + a[B3 + 2 >> 0] = v3 >> 16; + a[B3 + 3 >> 0] = v3 >> 24; + m3 = m3 + 4 | 0; + a[m3 >> 0] = D3; + a[m3 + 1 >> 0] = D3 >> 8; + a[m3 + 2 >> 0] = D3 >> 16; + a[m3 + 3 >> 0] = D3 >> 24; + m3 = (c[h2 >> 2] | 0) + (f2 & 255) | 0; + c[h2 >> 2] = m3; + switch (o2 | 0) { + case 16: { + f2 = d[z3 + q2 >> 0] | 0; + k2 = j2 + (m3 >>> 3) | 0; + l2 = d[k2 >> 0] | 0; + if (!((f2 & 252 | 0) == 0 & true)) { + u3 = 88; + break e; + } + u3 = cc(f2 | 0, 0, m3 & 7 | 0) | 0; + B3 = C2; + u3 = l2 | u3; + D3 = k2; + v3 = D3; + a[v3 >> 0] = u3; + a[v3 + 1 >> 0] = u3 >> 8; + a[v3 + 2 >> 0] = u3 >> 16; + a[v3 + 3 >> 0] = u3 >> 24; + D3 = D3 + 4 | 0; + a[D3 >> 0] = B3; + a[D3 + 1 >> 0] = B3 >> 8; + a[D3 + 2 >> 0] = B3 >> 16; + a[D3 + 3 >> 0] = B3 >> 24; + c[h2 >> 2] = (c[h2 >> 2] | 0) + 2; + break; + } + case 17: { + f2 = d[z3 + q2 >> 0] | 0; + k2 = j2 + (m3 >>> 3) | 0; + l2 = d[k2 >> 0] | 0; + if (!((f2 & 248 | 0) == 0 & true)) { + u3 = 91; + break e; + } + u3 = cc(f2 | 0, 0, m3 & 7 | 0) | 0; + B3 = C2; + u3 = l2 | u3; + D3 = k2; + v3 = D3; + a[v3 >> 0] = u3; + a[v3 + 1 >> 0] = u3 >> 8; + a[v3 + 2 >> 0] = u3 >> 16; + a[v3 + 3 >> 0] = u3 >> 24; + D3 = D3 + 4 | 0; + a[D3 >> 0] = B3; + a[D3 + 1 >> 0] = B3 >> 8; + a[D3 + 2 >> 0] = B3 >> 16; + a[D3 + 3 >> 0] = B3 >> 24; + c[h2 >> 2] = (c[h2 >> 2] | 0) + 3; + break; + } + default: { + } + } + q2 = q2 + 1 | 0; + } + if ((u3 | 0) == 83) pa2(406196, 406218, 54, 406251); + else if ((u3 | 0) == 85) pa2(406267, 406218, 55, 406251); + else if ((u3 | 0) == 88) pa2(406196, 406218, 54, 406251); + else if ((u3 | 0) == 91) pa2(406196, 406218, 54, 406251); + else if ((u3 | 0) == 94) { + i = A3; + return; + } + } + function ta2(a2) { + a2 = a2 | 0; + var b3 = 0; + b3 = i; + i = i + a2 | 0; + i = i + 15 & -16; + return b3 | 0; + } + function ua2() { + return i | 0; + } + function va2(a2) { + a2 = a2 | 0; + i = a2; + } + function wa2(a2, b3) { + a2 = a2 | 0; + b3 = b3 | 0; + i = a2; + j = b3; + } + function xa2(a2, b3) { + a2 = a2 | 0; + b3 = b3 | 0; + if (!n) { + n = a2; + o = b3; + } + } + function ya2(b3) { + b3 = b3 | 0; + a[k >> 0] = a[b3 >> 0]; + a[k + 1 >> 0] = a[b3 + 1 >> 0]; + a[k + 2 >> 0] = a[b3 + 2 >> 0]; + a[k + 3 >> 0] = a[b3 + 3 >> 0]; + } + function za2(b3) { + b3 = b3 | 0; + a[k >> 0] = a[b3 >> 0]; + a[k + 1 >> 0] = a[b3 + 1 >> 0]; + a[k + 2 >> 0] = a[b3 + 2 >> 0]; + a[k + 3 >> 0] = a[b3 + 3 >> 0]; + a[k + 4 >> 0] = a[b3 + 4 >> 0]; + a[k + 5 >> 0] = a[b3 + 5 >> 0]; + a[k + 6 >> 0] = a[b3 + 6 >> 0]; + a[k + 7 >> 0] = a[b3 + 7 >> 0]; + } + function Aa2(a2) { + a2 = a2 | 0; + C2 = a2; + } + function Ba2() { + return C2 | 0; + } + function Ca2(e2, f2, h2, j2, k2, l2, m3) { + e2 = e2 | 0; + f2 = f2 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + var n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, qa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Fa3 = 0, Ga3 = 0, Ha3 = 0, Ia3 = 0, Ja3 = 0, Ka3 = 0, La3 = 0, Ma3 = 0, Na3 = 0, Oa3 = 0, Pa3 = 0; + Oa3 = i; + i = i + 224 | 0; + Ha3 = Oa3 + 200 | 0; + Ca3 = Oa3 + 184 | 0; + Ka3 = Oa3 + 168 | 0; + Ja3 = Oa3 + 152 | 0; + Fa3 = Oa3 + 144 | 0; + Ia3 = Oa3 + 140 | 0; + La3 = Oa3 + 136 | 0; + Ga3 = Oa3 + 24 | 0; + q2 = Oa3 + 20 | 0; + u3 = Oa3 + 16 | 0; + r2 = Oa3 + 12 | 0; + v3 = Oa3 + 8 | 0; + w2 = Oa3 + 4 | 0; + Na3 = Oa3; + c[Na3 >> 2] = l2; + p2 = k2; + z3 = m3; + Ma3 = j2 >>> 24; + Ma3 = (Ma3 << 2 | 2) + ((j2 - (Ma3 << 24) | 0) >>> 0 > 1048576 ? 4 : 3) + 1 + j2 | 0; + n2 = (j2 | 0) == 0; + Ma3 = n2 ? 1 : Ma3 >>> 0 < j2 >>> 0 ? 0 : Ma3; + if (!l2) { + k2 = 0; + Na3 = c[Na3 >> 2] | 0; + Na3 = k2 ? Na3 : -1; + i = Oa3; + return Na3 | 0; + } + if (n2) { + c[Na3 >> 2] = 1; + a[m3 >> 0] = 6; + k2 = 1; + Na3 = c[Na3 >> 2] | 0; + Na3 = k2 ? Na3 : -1; + i = Oa3; + return Na3 | 0; + } + do + if ((e2 | 0) == 10) { + if ((f2 | 0) >= 16) if ((f2 | 0) > 24) f2 = 24; + else x3 = 7; + else { + f2 = 16; + x3 = 7; + } + q2 = 1 << f2; + va3 = q2 + -16 | 0; + c[Ca3 >> 2] = c[4721]; + c[Ca3 + 4 >> 2] = c[4722]; + c[Ca3 + 8 >> 2] = c[4723]; + c[Ca3 + 12 >> 2] = c[4724]; + c[Ka3 >> 2] = c[4721]; + c[Ka3 + 4 >> 2] = c[4722]; + c[Ka3 + 8 >> 2] = c[4723]; + c[Ka3 + 12 >> 2] = c[4724]; + wa3 = c[Na3 >> 2] | 0; + q2 = q2 >>> 0 > j2 >>> 0 ? j2 : q2; + xa3 = 1 << ((f2 | 0) > 23 ? 24 : f2 + 1 | 0); + ya3 = xa3 >>> 3; + c[Ja3 >> 2] = 0; + za3 = Ja3 + 4 | 0; + c[za3 >> 2] = 10; + n2 = Ja3 + 8 | 0; + c[n2 >> 2] = f2; + Aa3 = Ja3 + 12 | 0; + c[Aa3 >> 2] = 0; + c[za3 >> 2] = 10; + za3 = (f2 | 0) > 16 ? (f2 | 0) > 18 ? 18 : f2 : 16; + c[Aa3 >> 2] = za3; + za3 = 1 << za3; + c[Ha3 >> 2] = 1; + Aa3 = Ha3 + 4 | 0; + c[Aa3 >> 2] = 1; + Ba3 = Ha3 + 8 | 0; + c[Ba3 >> 2] = 0; + if (j2 >>> 0 >= 2147483649) pa2(406392, 406053, 1025, 406415); + if ((f2 | 0) != 16) if ((f2 | 0) == 17) { + r2 = 1; + h2 = 7; + } else { + r2 = ((f2 << 1) + 222 | 1) & 255; + h2 = 4; + } + else { + r2 = 0; + h2 = 1; + } + ua3 = Lb(0, 524308) | 0; + if (!ua3) oa2(1); + c[ua3 + 524292 >> 2] = 0; + c[ua3 + 524300 >> 2] = 0; + a[ua3 + 524304 >> 0] = 1; + p2 = ua3 + 524304 | 0; + f2 = 1 << c[n2 >> 2]; + c[ua3 >> 2] = f2 + -1; + f2 = 1 - f2 | 0; + ta3 = ua3 + 524296 | 0; + c[ta3 >> 2] = f2; + c.fill(f2, ua3 + 4 >> 2, (ua3 + 4 >> 2) + 131072); + n2 = 131072; + f2 = ua3 + 524300 | 0; + do + if (q2 >>> 0 > (c[f2 >> 2] | 0) >>> 0) { + n2 = ua3 + 524292 | 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[n2 >> 2] | 0); + c[n2 >> 2] = 0; + o2 = sa2[c[Ha3 >> 2] & 1](c[Ba3 >> 2] | 0, q2 << 3) | 0; + if (!o2) oa2(1); + else { + c[n2 >> 2] = o2; + c[f2 >> 2] = q2; + break; + } + } + while (0); + a[p2 >> 0] = 0; + W3 = ua3 + 524292 | 0; + X3 = Ga3 + 8 | 0; + Y3 = Ga3 + 12 | 0; + Z3 = Ga3 + 28 | 0; + $2 = Ga3 + 32 | 0; + ba2 = Ga3 + 36 | 0; + ca3 = Ga3 + 48 | 0; + da3 = Ga3 + 52 | 0; + ea3 = Ga3 + 56 | 0; + fa3 = Ga3 + 60 | 0; + ga3 = Ga3 + 72 | 0; + ha3 = Ga3 + 80 | 0; + ia3 = Ga3 + 88 | 0; + ja3 = Ga3 + 96 | 0; + ka3 = Ga3 + 104 | 0; + la3 = Ga3 + 8 | 0; + ma3 = Ga3 + 32 | 0; + qa3 = Ga3 + 56 | 0; + n2 = z3; + U3 = 0; + V3 = 1; + T3 = 0; + t3 = 0; + u3 = 0; + a: while (1) { + f2 = (V3 & 1) == 0; + if (!((f2 ^ 1) & U3 >>> 0 < j2 >>> 0)) { + x3 = 93; + break; + } + R3 = U3 + xa3 | 0; + R3 = R3 >>> 0 > j2 >>> 0 ? j2 : R3; + P3 = (((R3 - U3 | 0) >>> 0) / 12 | 0) + 16 | 0; + c[Fa3 >> 2] = 0; + c[Ia3 >> 2] = 0; + f2 = 0; + Q3 = U3; + L3 = 0; + N3 = 0; + v3 = 0; + S3 = 0; + while (1) { + if (R3 >>> 0 <= Q3 >>> 0) { + p2 = f2; + z3 = N3; + e2 = v3; + o2 = S3; + break; + } + O3 = R3 - Q3 | 0; + O3 = O3 >>> 0 < za3 >>> 0 ? O3 : za3; + M2 = sa2[c[Ha3 >> 2] & 1](c[Ba3 >> 2] | 0, (O3 << 4) + 16 | 0) | 0; + if (!M2) { + x3 = 27; + break a; + } + f2 = O3 + 1 | 0; + o2 = 0; + while (1) { + if ((o2 | 0) == (f2 | 0)) break; + c[M2 + (o2 << 4) >> 2] = 1; + c[M2 + (o2 << 4) + 4 >> 2] = 0; + c[M2 + (o2 << 4) + 8 >> 2] = 0; + g2[M2 + (o2 << 4) + 12 >> 2] = s; + o2 = o2 + 1 | 0; + } + b: do + if (O3 >>> 0 > 2 & Q3 >>> 0 > 127) { + K3 = Q3 + -127 | 0; + J3 = K3 + O3 | 0; + J3 = Q3 >>> 0 < J3 >>> 0 ? Q3 : J3; + while (1) { + if (K3 >>> 0 >= J3 >>> 0) break b; + p2 = c[ua3 >> 2] | 0; + F3 = Q3 - K3 | 0; + F3 = p2 - (F3 >>> 0 < 15 ? 15 : F3) | 0; + G3 = K3 & 2147483647; + H3 = k2 + G3 | 0; + D3 = ua3 + 4 + ((_(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24, 506832829) | 0) >>> 15 << 2) | 0; + B3 = c[D3 >> 2] | 0; + p2 = (K3 & p2) << 1; + c[D3 >> 2] = K3; + D3 = 0; + q2 = 0; + E3 = 0; + o2 = p2; + p2 = p2 | 1; + I3 = 64; + while (1) { + A3 = B3 & 2147483647; + if ((K3 | 0) == (B3 | 0) | (K3 - B3 | 0) >>> 0 > F3 >>> 0 | (I3 | 0) == 0) { + x3 = 36; + break; + } + z3 = q2 >>> 0 < E3 >>> 0 ? q2 : E3; + if (z3 >>> 0 >= 129) { + x3 = 38; + break a; + } + x3 = G3 + z3 | 0; + y3 = k2 + (A3 + 128) | 0; + e2 = k2 + (A3 + 124) | 0; + w2 = 0; + f2 = k2 + (A3 + z3) | 0; + while (1) { + if (f2 >>> 0 > e2 >>> 0) break; + Pa3 = k2 + (x3 + w2) | 0; + if ((d[f2 >> 0] | d[f2 + 1 >> 0] << 8 | d[f2 + 2 >> 0] << 16 | d[f2 + 3 >> 0] << 24 | 0) != (d[Pa3 >> 0] | d[Pa3 + 1 >> 0] << 8 | d[Pa3 + 2 >> 0] << 16 | d[Pa3 + 3 >> 0] << 24 | 0)) break; + w2 = w2 + 4 | 0; + f2 = f2 + 4 | 0; + } + while (1) { + if (f2 >>> 0 >= y3 >>> 0) break; + if ((a[k2 + (x3 + w2) >> 0] | 0) != (a[f2 >> 0] | 0)) break; + w2 = w2 + 1 | 0; + f2 = f2 + 1 | 0; + } + z3 = z3 + w2 | 0; + c: do + if (z3) { + f2 = z3; + x3 = H3; + y3 = k2 + A3 | 0; + while (1) { + e2 = a[x3 >> 0] | 0; + w2 = a[y3 >> 0] | 0; + if (e2 << 24 >> 24 != w2 << 24 >> 24) break; + f2 = f2 + -1 | 0; + if (!f2) break c; + else { + x3 = x3 + 1 | 0; + y3 = y3 + 1 | 0; + } + } + if (e2 << 24 >> 24 != w2 << 24 >> 24) { + x3 = 51; + break a; + } + } + while (0); + if (D3) { + x3 = 53; + break a; + } + if (z3 >>> 0 >= 128) { + x3 = 55; + break; + } + f2 = c[W3 >> 2] | 0; + if ((d[k2 + (G3 + z3) >> 0] | 0) > (d[k2 + (A3 + z3) >> 0] | 0)) { + c[f2 + (o2 << 2) >> 2] = B3; + e2 = (B3 & c[ua3 >> 2]) << 1 | 1; + q2 = z3; + f2 = E3; + o2 = e2; + e2 = (c[W3 >> 2] | 0) + (e2 << 2) | 0; + } else { + c[f2 + (p2 << 2) >> 2] = B3; + e2 = (B3 & c[ua3 >> 2]) << 1; + f2 = z3; + p2 = e2; + e2 = (c[W3 >> 2] | 0) + (e2 << 2) | 0; + } + D3 = 0; + E3 = f2; + B3 = c[e2 >> 2] | 0; + I3 = I3 + -1 | 0; + } + if ((x3 | 0) == 36) { + c[(c[W3 >> 2] | 0) + (o2 << 2) >> 2] = c[ta3 >> 2]; + c[(c[W3 >> 2] | 0) + (p2 << 2) >> 2] = c[ta3 >> 2]; + } else if ((x3 | 0) == 55) { + Pa3 = c[W3 >> 2] | 0; + c[Pa3 + (o2 << 2) >> 2] = c[Pa3 + ((B3 & c[ua3 >> 2]) << 1 << 2) >> 2]; + Pa3 = c[W3 >> 2] | 0; + c[Pa3 + (p2 << 2) >> 2] = c[Pa3 + (((B3 & c[ua3 >> 2]) << 1 | 1) << 2) >> 2]; + } + K3 = K3 + 1 | 0; + } + } + while (0); + o2 = S3 + (Ea2(Ha3, O3, Q3, k2, 2147483647, Ja3, va3, Ca3, ua3, M2) | 0) | 0; + p2 = o2 + 1 | 0; + p2 = P3 >>> 0 > p2 >>> 0 ? P3 : p2; + if ((L3 | 0) != (p2 | 0)) { + f2 = sa2[c[Ha3 >> 2] & 1](c[Ba3 >> 2] | 0, p2 << 4) | 0; + q2 = f2; + if (!f2) { + x3 = 63; + break a; + } + if (N3) { + Pa3 = N3; + dc(f2 | 0, Pa3 | 0, S3 << 4 | 0) | 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, Pa3); + } + } else { + p2 = L3; + q2 = N3; + } + Da2(O3, Q3, va3, M2, Ca3, Fa3, q2 + (S3 << 4) | 0, Ia3); + v3 = v3 + O3 | 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, M2); + f2 = c[Ia3 >> 2] | 0; + if (f2 >>> 0 > ya3 >>> 0) { + p2 = f2; + z3 = q2; + e2 = v3; + break; + } + if (o2 >>> 0 > ya3 >>> 0) { + p2 = f2; + z3 = q2; + e2 = v3; + break; + } else { + Q3 = Q3 + O3 | 0; + L3 = p2; + N3 = q2; + S3 = o2; + } + } + f2 = c[Fa3 >> 2] | 0; + if (!f2) f2 = p2; + else { + p2 = o2 + 1 | 0; + Pa3 = z3; + c[Pa3 + (o2 << 4) >> 2] = f2; + c[Pa3 + (o2 << 4) + 4 >> 2] = 67108864; + c[Pa3 + (o2 << 4) + 8 >> 2] = 0; + b2[Pa3 + (o2 << 4) + 14 >> 1] = 16; + o2 = Pa3 + (o2 << 4) + 12 | 0; + do + if (f2 >>> 0 >= 6) { + if (f2 >>> 0 < 130) { + Pa3 = f2 + -2 | 0; + f2 = ((aa(Pa3 | 0) | 0) ^ 31) + -1 | 0; + f2 = (f2 << 1) + (Pa3 >>> f2) + 2 | 0; + break; + } + if (f2 >>> 0 < 2114) { + f2 = ((aa(f2 + -66 | 0) | 0) ^ 31) + 10 | 0; + break; + } + if (f2 >>> 0 < 6210) f2 = 21; + else f2 = f2 >>> 0 < 22594 ? 22 : 23; + } + while (0); + f2 = f2 & 65535; + b2[o2 >> 1] = b2[88156 + ((f2 >>> 3) * 3 << 1) >> 1] | (f2 << 3 & 56 | 2) & 65535; + f2 = (c[Ia3 >> 2] | 0) + (c[Fa3 >> 2] | 0) | 0; + c[Ia3 >> 2] = f2; + o2 = p2; + } + w2 = U3 + e2 | 0; + v3 = (w2 | 0) == (j2 | 0); + h2 = h2 & 255; + c[La3 >> 2] = h2; + do + if (!e2) { + f2 = sa2[c[Ha3 >> 2] & 1](c[Ba3 >> 2] | 0, 16) | 0; + if (!f2) { + x3 = 79; + break a; + } + a[f2 >> 0] = r2; + Pa3 = c[La3 >> 2] | 0; + U3 = f2 + (Pa3 >>> 3) | 0; + S3 = d[U3 >> 0] | 0; + R3 = cc(3, 0, Pa3 & 7 | 0) | 0; + T3 = C2; + R3 = S3 | R3; + S3 = U3; + a[S3 >> 0] = R3; + a[S3 + 1 >> 0] = R3 >> 8; + a[S3 + 2 >> 0] = R3 >> 16; + a[S3 + 3 >> 0] = R3 >> 24; + U3 = U3 + 4 | 0; + a[U3 >> 0] = T3; + a[U3 + 1 >> 0] = T3 >> 8; + a[U3 + 2 >> 0] = T3 >> 16; + a[U3 + 3 >> 0] = T3 >> 24; + c[La3 >> 2] = Pa3 + 9 & -8; + } else { + if (!(Fb(k2, 2147483647, U3, 0, e2, f2, o2) | 0)) { + c[Ca3 >> 2] = c[Ka3 >> 2]; + c[Ca3 + 4 >> 2] = c[Ka3 + 4 >> 2]; + c[Ca3 + 8 >> 2] = c[Ka3 + 8 >> 2]; + c[Ca3 + 12 >> 2] = c[Ka3 + 12 >> 2]; + f2 = sa2[c[Ha3 >> 2] & 1](c[Ba3 >> 2] | 0, e2 + 16 | 0) | 0; + if (!f2) { + x3 = 83; + break a; + } + a[f2 >> 0] = r2; + bb2(v3, k2, U3, 2147483647, e2, La3, f2); + break; + } + ; + c[Ga3 >> 2] = 0; + c[Ga3 + 4 >> 2] = 0; + c[Ga3 + 8 >> 2] = 0; + c[Ga3 + 12 >> 2] = 0; + c[Ga3 + 16 >> 2] = 0; + c[Ga3 + 20 >> 2] = 0; + c[Ga3 + 24 >> 2] = 0; + c[Z3 >> 2] = 0; + c[Z3 + 4 >> 2] = 0; + c[Z3 + 8 >> 2] = 0; + c[Z3 + 12 >> 2] = 0; + c[Z3 + 16 >> 2] = 0; + c[ca3 >> 2] = 0; + c[da3 >> 2] = 0; + c[da3 + 4 >> 2] = 0; + c[da3 + 8 >> 2] = 0; + c[da3 + 12 >> 2] = 0; + c[da3 + 16 >> 2] = 0; + x3 = ga3; + y3 = x3 + 40 | 0; + do { + c[x3 >> 2] = 0; + x3 = x3 + 4 | 0; + } while ((x3 | 0) < (y3 | 0)); + p2 = Wb(k2, U3, 2147483647, e2) | 0; + p2 = p2 ? 2 : 3; + q2 = z3; + Nb(Ha3, k2, U3, 2147483647, Ja3, T3, t3, q2, o2, p2, Ga3); + Ob(0, 0, Ga3); + f2 = sa2[c[Ha3 >> 2] & 1](c[Ba3 >> 2] | 0, (e2 << 1) + 502 | 0) | 0; + if (!f2) { + x3 = 86; + break a; + } + a[f2 >> 0] = r2; + ab2(Ha3, k2, U3, e2, 2147483647, T3, t3, v3, 0, 0, p2, q2, o2, Ga3, La3, f2); + if ((e2 + 4 | 0) >>> 0 < (c[La3 >> 2] | 0) >>> 3 >>> 0) { + c[Ca3 >> 2] = c[Ka3 >> 2]; + c[Ca3 + 4 >> 2] = c[Ka3 + 4 >> 2]; + c[Ca3 + 8 >> 2] = c[Ka3 + 8 >> 2]; + c[Ca3 + 12 >> 2] = c[Ka3 + 12 >> 2]; + a[f2 >> 0] = r2; + c[La3 >> 2] = h2; + bb2(v3, k2, U3, 2147483647, e2, La3, f2); + } + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[la3 >> 2] | 0); + c[X3 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[Y3 >> 2] | 0); + c[Y3 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[ma3 >> 2] | 0); + c[$2 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[ba2 >> 2] | 0); + c[ba2 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[qa3 >> 2] | 0); + c[ea3 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[fa3 >> 2] | 0); + c[fa3 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[ga3 >> 2] | 0); + c[ga3 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[ha3 >> 2] | 0); + c[ha3 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[ia3 >> 2] | 0); + c[ia3 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[ja3 >> 2] | 0); + c[ja3 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[ka3 >> 2] | 0); + c[ka3 >> 2] = 0; + } + while (0); + p2 = c[La3 >> 2] | 0; + o2 = p2 >>> 3; + r2 = a[f2 + o2 >> 0] | 0; + q2 = a[k2 + (w2 + -1) >> 0] | 0; + t3 = a[k2 + (w2 + -2) >> 0] | 0; + c[Ka3 >> 2] = c[Ca3 >> 2]; + c[Ka3 + 4 >> 2] = c[Ca3 + 4 >> 2]; + c[Ka3 + 8 >> 2] = c[Ca3 + 8 >> 2]; + c[Ka3 + 12 >> 2] = c[Ca3 + 12 >> 2]; + u3 = u3 + o2 | 0; + if (u3 >>> 0 > wa3 >>> 0) o2 = 0; + else { + dc(n2 | 0, f2 | 0, o2 | 0) | 0; + n2 = n2 + o2 | 0; + o2 = V3; + } + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, f2); + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, z3); + h2 = p2 & 7; + U3 = w2; + V3 = o2; + T3 = q2; + } + if ((x3 | 0) == 27) oa2(1); + else if ((x3 | 0) == 38) pa2(405873, 405905, 373, 405932); + else if ((x3 | 0) == 51) pa2(405955, 405905, 378, 405932); + else if ((x3 | 0) == 53) na(); + else if ((x3 | 0) == 63) oa2(1); + else if ((x3 | 0) == 79) oa2(1); + else if ((x3 | 0) == 83) oa2(1); + else if ((x3 | 0) == 86) oa2(1); + else if ((x3 | 0) == 93) { + c[Na3 >> 2] = u3; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, c[W3 >> 2] | 0); + c[W3 >> 2] = 0; + ra2[c[Aa3 >> 2] & 1](c[Ba3 >> 2] | 0, ua3); + if (f2) { + x3 = 107; + break; + } + if ((Ma3 | 0) != 0 ? (c[Na3 >> 2] | 0) >>> 0 > Ma3 >>> 0 : 0) { + x3 = 106; + break; + } else f2 = 1; + Pa3 = c[Na3 >> 2] | 0; + Pa3 = f2 ? Pa3 : -1; + i = Oa3; + return Pa3 | 0; + } + } else { + t3 = Yb(5240) | 0; + if (!t3) { + k2 = 0; + Pa3 = c[Na3 >> 2] | 0; + Pa3 = k2 ? Pa3 : -1; + i = Oa3; + return Pa3 | 0; + } + c[t3 + 16 >> 2] = 1; + c[t3 + 20 >> 2] = 1; + c[t3 + 24 >> 2] = 0; + c[t3 >> 2] = 0; + c[t3 + 4 >> 2] = 11; + c[t3 + 8 >> 2] = 22; + c[t3 + 12 >> 2] = 0; + x3 = t3 + 80 | 0; + c[x3 >> 2] = 0; + c[x3 + 4 >> 2] = 0; + c[t3 + 128 >> 2] = 0; + c[t3 + 132 >> 2] = 0; + c[t3 + 136 >> 2] = 0; + x3 = t3 + 144 | 0; + c[t3 + 4300 >> 2] = 0; + c[t3 + 4304 >> 2] = 0; + n2 = t3 + 5204 | 0; + c[t3 + 5232 >> 2] = 0; + a[t3 + 5236 >> 0] = 0; + a[t3 + 5237 >> 0] = 0; + c[t3 + 28 >> 2] = 0; + o2 = t3 + 32 | 0; + c[x3 >> 2] = 0; + c[x3 + 4 >> 2] = 0; + c[x3 + 8 >> 2] = 0; + c[x3 + 12 >> 2] = 0; + x3 = t3 + 194 | 0; + y3 = x3 + 10 | 0; + do { + a[x3 >> 0] = 0; + x3 = x3 + 1 | 0; + } while ((x3 | 0) < (y3 | 0)); + c[n2 >> 2] = 0; + c[n2 + 4 >> 2] = 0; + c[n2 + 8 >> 2] = 0; + c[n2 + 12 >> 2] = 0; + c[n2 + 16 >> 2] = 0; + c[n2 + 20 >> 2] = 0; + n2 = t3 + 104 | 0; + x3 = o2; + y3 = x3 + 44 | 0; + do { + c[x3 >> 2] = 0; + x3 = x3 + 4 | 0; + } while ((x3 | 0) < (y3 | 0)); + c[n2 >> 2] = 0; + c[t3 + 108 >> 2] = 0; + c[t3 + 112 >> 2] = 0; + c[t3 + 116 >> 2] = 0; + c[t3 + 124 >> 2] = 0; + c[t3 + 120 >> 2] = 0; + c[t3 + 160 >> 2] = 4; + c[t3 + 164 >> 2] = 11; + c[t3 + 168 >> 2] = 15; + c[t3 + 172 >> 2] = 16; + Pa3 = t3 + 176 | 0; + La3 = t3 + 160 | 0; + c[Pa3 >> 2] = c[La3 >> 2]; + c[Pa3 + 4 >> 2] = c[La3 + 4 >> 2]; + c[Pa3 + 8 >> 2] = c[La3 + 8 >> 2]; + c[Pa3 + 12 >> 2] = c[La3 + 12 >> 2]; + if (!t3) { + k2 = 0; + Pa3 = c[Na3 >> 2] | 0; + Pa3 = k2 ? Pa3 : -1; + i = Oa3; + return Pa3 | 0; + } + c[q2 >> 2] = j2; + c[u3 >> 2] = p2; + c[r2 >> 2] = c[Na3 >> 2]; + c[v3 >> 2] = z3; + c[w2 >> 2] = 0; + if (!(a[t3 + 5237 >> 0] & 1)) { + c[t3 + 4 >> 2] = e2; + c[t3 + 8 >> 2] = f2; + c[t3 >> 2] = h2; + } + f2 = Ab(t3, q2, u3, r2, v3, w2) | 0; + if ((c[t3 + 5232 >> 2] | 0) == 2 ? (c[t3 + 5220 >> 2] | 0) == 0 : 0) h2 = f2 & 1; + else h2 = 0; + c[Na3 >> 2] = c[w2 >> 2]; + q2 = t3 + 200 | 0; + f2 = c[t3 + 20 >> 2] | 0; + n2 = c[t3 + 24 >> 2] | 0; + ra2[f2 & 1](n2, c[q2 >> 2] | 0); + c[q2 >> 2] = 0; + q2 = t3 + 124 | 0; + o2 = t3 + 20 | 0; + p2 = t3 + 24 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[q2 >> 2] | 0); + c[q2 >> 2] = 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[t3 + 112 >> 2] | 0); + c[t3 + 112 >> 2] = 0; + q2 = t3 + 28 | 0; + r2 = c[t3 + 72 >> 2] | 0; + if (r2) { + Pa3 = r2 + 524292 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[Pa3 >> 2] | 0); + c[Pa3 >> 2] = 0; + } + Pa3 = t3 + 72 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[q2 >> 2] | 0); + c[q2 >> 2] = 0; + La3 = t3 + 32 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + La3 = t3 + 36 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + La3 = t3 + 40 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + La3 = t3 + 44 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + La3 = t3 + 48 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + La3 = t3 + 52 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + La3 = t3 + 56 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + La3 = t3 + 60 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + La3 = t3 + 64 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + La3 = t3 + 68 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[La3 >> 2] | 0); + c[La3 >> 2] = 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[Pa3 >> 2] | 0); + c[Pa3 >> 2] = 0; + Pa3 = t3 + 4300 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[Pa3 >> 2] | 0); + c[Pa3 >> 2] = 0; + Pa3 = t3 + 5208 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[Pa3 >> 2] | 0); + c[Pa3 >> 2] = 0; + Pa3 = t3 + 5212 | 0; + ra2[c[o2 >> 2] & 1](c[p2 >> 2] | 0, c[Pa3 >> 2] | 0); + c[Pa3 >> 2] = 0; + ra2[f2 & 1](n2, t3); + if (h2 << 24 >> 24) if ((Ma3 | 0) != 0 ? (c[Na3 >> 2] | 0) >>> 0 > Ma3 >>> 0 : 0) x3 = 106; + else { + k2 = 1; + Pa3 = c[Na3 >> 2] | 0; + Pa3 = k2 ? Pa3 : -1; + i = Oa3; + return Pa3 | 0; + } + else x3 = 107; + } + while (0); + if ((x3 | 0) == 106) { + c[Na3 >> 2] = 0; + if (Ma3 >>> 0 > l2 >>> 0) { + k2 = 0; + Pa3 = c[Na3 >> 2] | 0; + Pa3 = k2 ? Pa3 : -1; + i = Oa3; + return Pa3 | 0; + } + } else if ((x3 | 0) == 107 ? (c[Na3 >> 2] = 0, (Ma3 | 0) == 0 | Ma3 >>> 0 > l2 >>> 0) : 0) { + k2 = 0; + Pa3 = c[Na3 >> 2] | 0; + Pa3 = k2 ? Pa3 : -1; + i = Oa3; + return Pa3 | 0; + } + a[m3 >> 0] = 33; + a[m3 + 1 >> 0] = 3; + h2 = 0; + q2 = 2; + r2 = j2; + while (1) { + if (!r2) break; + if (r2 >>> 0 <= 16777216) if (r2 >>> 0 > 65536) { + f2 = r2; + if (f2 >>> 0 > 1048576) x3 = 113; + else p2 = 1; + } else { + f2 = r2; + p2 = 0; + } + else { + f2 = 16777216; + x3 = 113; + } + if ((x3 | 0) == 113) { + x3 = 0; + p2 = 2; + } + o2 = p2 << 1 | (f2 << 3) + -8 | 1 << (p2 << 2 | 19); + a[m3 + q2 >> 0] = o2; + a[m3 + (q2 + 1) >> 0] = o2 >>> 8; + n2 = q2 + 3 | 0; + a[m3 + (q2 + 2) >> 0] = o2 >>> 16; + if ((p2 | 0) == 2) { + a[m3 + n2 >> 0] = o2 >>> 24; + n2 = q2 + 4 | 0; + } + dc(m3 + n2 | 0, k2 + h2 | 0, f2 | 0) | 0; + h2 = h2 + f2 | 0; + q2 = n2 + f2 | 0; + r2 = r2 - f2 | 0; + } + a[m3 + q2 >> 0] = 3; + c[Na3 >> 2] = q2 + 1; + k2 = 1; + Pa3 = c[Na3 >> 2] | 0; + Pa3 = k2 ? Pa3 : -1; + i = Oa3; + return Pa3 | 0; + } + function Da2(a2, d2, e2, f2, g3, h2, i2, j2) { + a2 = a2 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + i2 = i2 | 0; + j2 = j2 | 0; + var k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0; + x3 = g3 + 8 | 0; + y3 = g3 + 12 | 0; + z3 = g3 + 4 | 0; + k2 = c[f2 + 12 >> 2] | 0; + l2 = 0; + B3 = 0; + while (1) { + if ((k2 | 0) == -1) break; + n2 = l2 + k2 | 0; + o2 = f2 + (n2 << 4) | 0; + p2 = c[o2 >> 2] | 0; + A3 = p2 & 16777215; + m3 = c[f2 + (n2 << 4) + 8 >> 2] | 0; + w2 = l2 + m3 | 0; + k2 = c[f2 + (n2 << 4) + 12 >> 2] | 0; + if (!B3) { + m3 = m3 + (c[h2 >> 2] | 0) | 0; + c[h2 >> 2] = 0; + } + u3 = c[f2 + (n2 << 4) + 4 >> 2] | 0; + v3 = u3 & 33554431; + o2 = c[o2 >> 2] | 0; + o2 = (o2 & 16777215) + 9 - (o2 >>> 24) | 0; + t3 = w2 + d2 | 0; + t3 = v3 >>> 0 > (t3 >>> 0 < e2 >>> 0 ? t3 : e2) >>> 0; + u3 = u3 >>> 25; + u3 = (u3 | 0) == 0 ? v3 + 15 | 0 : u3 + -1 | 0; + c[i2 + (B3 << 4) >> 2] = m3; + c[i2 + (B3 << 4) + 4 >> 2] = A3 | (o2 ^ p2) << 24; + l2 = i2 + (B3 << 4) + 14 | 0; + if (u3 >>> 0 < 16) { + n2 = u3 & 65535; + b2[l2 >> 1] = n2; + l2 = n2; + n2 = 0; + } else { + r2 = u3 + -12 | 0; + n2 = ((aa(r2 | 0) | 0) ^ 31) + -1 | 0; + s2 = r2 >>> n2 & 1; + q2 = ((n2 << 1) + 65534 | s2) + 16 & 65535; + b2[l2 >> 1] = q2; + l2 = q2; + n2 = n2 << 24 | r2 - ((s2 | 2) << n2); + } + c[i2 + (B3 << 4) + 8 >> 2] = n2; + r2 = l2 << 16 >> 16 == 0; + s2 = i2 + (B3 << 4) + 12 | 0; + do + if (m3 >>> 0 >= 6) { + if (m3 >>> 0 < 130) { + p2 = m3 + -2 | 0; + q2 = ((aa(p2 | 0) | 0) ^ 31) + -1 | 0; + q2 = (q2 << 1) + (p2 >>> q2) + 2 & 65535; + break; + } + if (m3 >>> 0 < 2114) { + q2 = ((aa(m3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (m3 >>> 0 < 6210) q2 = 21; + else q2 = m3 >>> 0 < 22594 ? 22 : 23; + } else q2 = m3 & 65535; + while (0); + do + if (o2 >>> 0 >= 10) { + if (o2 >>> 0 < 134) { + p2 = o2 + -6 | 0; + l2 = ((aa(p2 | 0) | 0) ^ 31) + -1 | 0; + l2 = (l2 << 1) + (p2 >>> l2) + 4 & 65535; + break; + } + if (o2 >>> 0 < 2118) l2 = ((aa(o2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else l2 = 23; + } else l2 = o2 + 65534 & 65535; + while (0); + n2 = l2 & 65535; + o2 = q2 & 65535; + p2 = n2 & 7 | o2 << 3 & 56; + if (r2 & (q2 & 65535) < 8 & (l2 & 65535) < 16) l2 = ((l2 & 65535) < 8 ? p2 : p2 | 64) & 65535; + else l2 = b2[88156 + ((n2 >>> 3) + ((o2 >>> 3) * 3 | 0) << 1) >> 1] | p2 & 65535; + b2[s2 >> 1] = l2; + if (!(t3 | (u3 | 0) == 0)) { + c[y3 >> 2] = c[x3 >> 2]; + c[x3 >> 2] = c[z3 >> 2]; + c[z3 >> 2] = c[g3 >> 2]; + c[g3 >> 2] = v3; + } + c[j2 >> 2] = (c[j2 >> 2] | 0) + m3; + l2 = w2 + A3 | 0; + B3 = B3 + 1 | 0; + } + c[h2 >> 2] = (c[h2 >> 2] | 0) + (a2 - l2); + return; + } + function Ea2(b3, e2, f2, h2, j2, k2, l2, m3, n2, o2) { + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + var p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, aa2 = 0, ba2 = 0, ca3 = 0; + ba2 = i; + i = i + 6320 | 0; + Y3 = ba2 + 6160 | 0; + $2 = ba2 + 1252 | 0; + aa2 = ba2 + 1024 | 0; + Z3 = ba2; + W3 = (c[k2 + 4 >> 2] | 0) < 11 ? 150 : 325; + X3 = e2 >>> 0 > 127 ? f2 + e2 + -127 | 0 : f2; + c[o2 >> 2] = 0; + g2[o2 + 12 >> 2] = 0; + c[$2 + 4904 >> 2] = e2; + U3 = b3 + 8 | 0; + p2 = sa2[c[b3 >> 2] & 1](c[U3 >> 2] | 0, (e2 << 2) + 8 | 0) | 0; + if (!p2) oa2(1); + V3 = $2 + 4896 | 0; + c[V3 >> 2] = p2; + Fa2($2, f2, h2, j2); + N3 = aa2 + 224 | 0; + c[N3 >> 2] = 0; + O3 = Z3; + P3 = k2 + 4 | 0; + Q3 = n2 + 524292 | 0; + R3 = n2 + 524296 | 0; + S3 = Z3; + T3 = Z3 + 4 | 0; + p2 = 0; + a: while (1) { + if ((p2 + 3 | 0) >>> 0 >= e2 >>> 0) { + w2 = 98; + break; + } + M2 = p2 + f2 | 0; + L3 = M2 >>> 0 < l2 >>> 0 ? M2 : l2; + J3 = e2 - p2 | 0; + I3 = M2 & j2; + A3 = (c[P3 >> 2] | 0) != 11 ? 16 : 64; + A3 = M2 >>> 0 < A3 >>> 0 ? 0 : M2 - A3 | 0; + K3 = h2 + I3 | 0; + x3 = h2 + (I3 + 1) | 0; + z3 = I3 + J3 | 0; + y3 = h2 + z3 | 0; + z3 = h2 + (z3 + -4) | 0; + q2 = O3; + s2 = 1; + r2 = M2; + while (1) { + r2 = r2 + -1 | 0; + if (!(r2 >>> 0 > A3 >>> 0 & s2 >>> 0 < 3)) break; + v3 = M2 - r2 | 0; + if (v3 >>> 0 > L3 >>> 0) break; + w2 = r2 & j2; + if ((a[K3 >> 0] | 0) != (a[h2 + w2 >> 0] | 0)) { + G3 = s2; + H3 = q2; + s2 = G3; + q2 = H3; + continue; + } + if ((a[x3 >> 0] | 0) == (a[h2 + (w2 + 1) >> 0] | 0)) { + t3 = 0; + u3 = K3; + } else { + G3 = s2; + H3 = q2; + s2 = G3; + q2 = H3; + continue; + } + while (1) { + if (u3 >>> 0 > z3 >>> 0) break; + H3 = h2 + (w2 + t3) | 0; + if ((d[u3 >> 0] | d[u3 + 1 >> 0] << 8 | d[u3 + 2 >> 0] << 16 | d[u3 + 3 >> 0] << 24 | 0) != (d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24 | 0)) break; + t3 = t3 + 4 | 0; + u3 = u3 + 4 | 0; + } + while (1) { + if (u3 >>> 0 >= y3 >>> 0) break; + if ((a[h2 + (w2 + t3) >> 0] | 0) != (a[u3 >> 0] | 0)) break; + t3 = t3 + 1 | 0; + u3 = u3 + 1 | 0; + } + if (t3 >>> 0 <= s2 >>> 0) { + G3 = s2; + H3 = q2; + s2 = G3; + q2 = H3; + continue; + } + s2 = q2; + c[s2 >> 2] = v3; + c[s2 + 4 >> 2] = t3 << 5; + q2 = s2 + 8 | 0; + s2 = t3; + } + do + if (s2 >>> 0 < J3 >>> 0) { + G3 = J3 >>> 0 < 128 ? J3 : 128; + H3 = J3 >>> 0 > 127; + r2 = n2 + 4 + ((_(d[K3 >> 0] | d[K3 + 1 >> 0] << 8 | d[K3 + 2 >> 0] << 16 | d[K3 + 3 >> 0] << 24, 506832829) | 0) >>> 15 << 2) | 0; + v3 = c[r2 >> 2] | 0; + t3 = (M2 & c[n2 >> 2]) << 1; + u3 = t3 | 1; + if (H3) { + c[r2 >> 2] = M2; + E3 = 0; + F3 = 0; + D3 = 64; + } else { + E3 = 0; + F3 = 0; + D3 = 64; + } + while (1) { + B3 = M2 - v3 | 0; + C3 = v3 & j2; + if ((M2 | 0) == (v3 | 0) | B3 >>> 0 > L3 >>> 0 | (D3 | 0) == 0) { + w2 = 22; + break; + } + A3 = E3 >>> 0 < F3 >>> 0 ? E3 : F3; + if (A3 >>> 0 >= 129) { + w2 = 25; + break a; + } + y3 = I3 + A3 | 0; + w2 = C3 + J3 | 0; + z3 = h2 + w2 | 0; + w2 = h2 + (w2 + -4) | 0; + x3 = 0; + r2 = h2 + (C3 + A3) | 0; + while (1) { + if (r2 >>> 0 > w2 >>> 0) break; + ca3 = h2 + (y3 + x3) | 0; + if ((d[r2 >> 0] | d[r2 + 1 >> 0] << 8 | d[r2 + 2 >> 0] << 16 | d[r2 + 3 >> 0] << 24 | 0) != (d[ca3 >> 0] | d[ca3 + 1 >> 0] << 8 | d[ca3 + 2 >> 0] << 16 | d[ca3 + 3 >> 0] << 24 | 0)) break; + x3 = x3 + 4 | 0; + r2 = r2 + 4 | 0; + } + while (1) { + if (r2 >>> 0 >= z3 >>> 0) break; + if ((a[h2 + (y3 + x3) >> 0] | 0) != (a[r2 >> 0] | 0)) break; + x3 = x3 + 1 | 0; + r2 = r2 + 1 | 0; + } + A3 = A3 + x3 | 0; + b: do + if (A3) { + r2 = A3; + y3 = K3; + z3 = h2 + C3 | 0; + while (1) { + w2 = a[y3 >> 0] | 0; + x3 = a[z3 >> 0] | 0; + if (w2 << 24 >> 24 != x3 << 24 >> 24) break; + r2 = r2 + -1 | 0; + if (!r2) break b; + else { + y3 = y3 + 1 | 0; + z3 = z3 + 1 | 0; + } + } + if (w2 << 24 >> 24 != x3 << 24 >> 24) { + w2 = 38; + break a; + } + } + while (0); + r2 = q2; + if ((q2 | 0) != 0 & A3 >>> 0 > s2 >>> 0) { + c[r2 >> 2] = B3; + c[r2 + 4 >> 2] = A3 << 5; + q2 = r2 + 8 | 0; + s2 = A3; + } + if (A3 >>> 0 >= G3 >>> 0) { + w2 = 42; + break; + } + if ((d[h2 + (I3 + A3) >> 0] | 0) > (d[h2 + (C3 + A3) >> 0] | 0)) { + if (H3) c[(c[Q3 >> 2] | 0) + (t3 << 2) >> 2] = v3; + w2 = (v3 & c[n2 >> 2]) << 1 | 1; + v3 = A3; + r2 = F3; + t3 = w2; + w2 = (c[Q3 >> 2] | 0) + (w2 << 2) | 0; + } else { + if (H3) c[(c[Q3 >> 2] | 0) + (u3 << 2) >> 2] = v3; + w2 = (v3 & c[n2 >> 2]) << 1; + v3 = E3; + r2 = A3; + u3 = w2; + w2 = (c[Q3 >> 2] | 0) + (w2 << 2) | 0; + } + E3 = v3; + F3 = r2; + v3 = c[w2 >> 2] | 0; + D3 = D3 + -1 | 0; + } + if ((w2 | 0) == 22) { + if (!H3) break; + c[(c[Q3 >> 2] | 0) + (t3 << 2) >> 2] = c[R3 >> 2]; + c[(c[Q3 >> 2] | 0) + (u3 << 2) >> 2] = c[R3 >> 2]; + break; + } else if ((w2 | 0) == 42) { + if (!H3) break; + ca3 = c[Q3 >> 2] | 0; + c[ca3 + (t3 << 2) >> 2] = c[ca3 + ((v3 & c[n2 >> 2]) << 1 << 2) >> 2]; + ca3 = c[Q3 >> 2] | 0; + c[ca3 + (u3 << 2) >> 2] = c[ca3 + (((v3 & c[n2 >> 2]) << 1 | 1) << 2) >> 2]; + break; + } + } + while (0); + r2 = 0; + while (1) { + if ((r2 | 0) == 38) break; + c[Y3 + (r2 << 2) >> 2] = 268435455; + r2 = r2 + 1 | 0; + } + s2 = s2 + 1 | 0; + s2 = s2 >>> 0 < 4 ? 4 : s2; + c: do + if (Vb(K3, s2, J3, Y3) | 0) { + t3 = J3 >>> 0 > 37 ? 37 : J3; + while (1) { + if (s2 >>> 0 > t3 >>> 0) break c; + r2 = c[Y3 + (s2 << 2) >> 2] | 0; + if (r2 >>> 0 < 268435455) { + ca3 = r2 & 31; + c[q2 >> 2] = L3 + (r2 >>> 5) + 1; + c[q2 + 4 >> 2] = s2 << 5 | ((s2 | 0) == (ca3 | 0) ? 0 : ca3); + q2 = q2 + 8 | 0; + } + s2 = s2 + 1 | 0; + } + } + while (0); + q2 = q2 - S3 >> 3; + do + if (q2) { + r2 = q2 + -1 | 0; + if ((c[Z3 + (r2 << 3) + 4 >> 2] | 0) >>> 5 >>> 0 <= W3 >>> 0) { + ca3 = q2; + Ga2(e2, f2, p2, h2, j2, k2, l2, m3, ca3, Z3, $2, aa2, o2); + if ((ca3 | 0) != 1) break; + } else { + K3 = Z3 + (r2 << 3) | 0; + L3 = c[K3 + 4 >> 2] | 0; + ca3 = Z3; + c[ca3 >> 2] = c[K3 >> 2]; + c[ca3 + 4 >> 2] = L3; + Ga2(e2, f2, p2, h2, j2, k2, l2, m3, 1, Z3, $2, aa2, o2); + } + q2 = (c[T3 >> 2] | 0) >>> 5; + if (q2 >>> 0 > W3 >>> 0) { + I3 = M2 + q2 | 0; + I3 = I3 >>> 0 < X3 >>> 0 ? I3 : X3; + H3 = (M2 + 64 | 0) >>> 0 > I3 >>> 0 ? M2 + 1 | 0 : I3 + -63 | 0; + while (1) { + if (H3 >>> 0 >= I3 >>> 0) break; + s2 = c[n2 >> 2] | 0; + D3 = s2 + -15 | 0; + E3 = H3 & j2; + F3 = h2 + E3 | 0; + B3 = n2 + 4 + ((_(d[F3 >> 0] | d[F3 + 1 >> 0] << 8 | d[F3 + 2 >> 0] << 16 | d[F3 + 3 >> 0] << 24, 506832829) | 0) >>> 15 << 2) | 0; + A3 = c[B3 >> 2] | 0; + s2 = (H3 & s2) << 1; + c[B3 >> 2] = H3; + B3 = 0; + t3 = 0; + C3 = 0; + r2 = s2; + s2 = s2 | 1; + G3 = 64; + while (1) { + z3 = A3 & j2; + if ((H3 | 0) == (A3 | 0) | (H3 - A3 | 0) >>> 0 > D3 >>> 0 | (G3 | 0) == 0) { + w2 = 71; + break; + } + y3 = t3 >>> 0 < C3 >>> 0 ? t3 : C3; + if (y3 >>> 0 >= 129) { + w2 = 73; + break a; + } + w2 = E3 + y3 | 0; + x3 = h2 + (z3 + 128) | 0; + u3 = h2 + (z3 + 124) | 0; + v3 = 0; + q2 = h2 + (z3 + y3) | 0; + while (1) { + if (q2 >>> 0 > u3 >>> 0) break; + ca3 = h2 + (w2 + v3) | 0; + if ((d[q2 >> 0] | d[q2 + 1 >> 0] << 8 | d[q2 + 2 >> 0] << 16 | d[q2 + 3 >> 0] << 24 | 0) != (d[ca3 >> 0] | d[ca3 + 1 >> 0] << 8 | d[ca3 + 2 >> 0] << 16 | d[ca3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + q2 = q2 + 4 | 0; + } + while (1) { + if (q2 >>> 0 >= x3 >>> 0) break; + if ((a[h2 + (w2 + v3) >> 0] | 0) != (a[q2 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + q2 = q2 + 1 | 0; + } + y3 = y3 + v3 | 0; + d: do + if (y3) { + q2 = y3; + w2 = F3; + x3 = h2 + z3 | 0; + while (1) { + u3 = a[w2 >> 0] | 0; + v3 = a[x3 >> 0] | 0; + if (u3 << 24 >> 24 != v3 << 24 >> 24) break; + q2 = q2 + -1 | 0; + if (!q2) break d; + else { + w2 = w2 + 1 | 0; + x3 = x3 + 1 | 0; + } + } + if (u3 << 24 >> 24 != v3 << 24 >> 24) { + w2 = 86; + break a; + } + } + while (0); + if (B3) { + w2 = 88; + break a; + } + if (y3 >>> 0 >= 128) { + w2 = 90; + break; + } + q2 = c[Q3 >> 2] | 0; + if ((d[h2 + (E3 + y3) >> 0] | 0) > (d[h2 + (z3 + y3) >> 0] | 0)) { + c[q2 + (r2 << 2) >> 2] = A3; + u3 = (A3 & c[n2 >> 2]) << 1 | 1; + t3 = y3; + q2 = C3; + r2 = u3; + u3 = (c[Q3 >> 2] | 0) + (u3 << 2) | 0; + } else { + c[q2 + (s2 << 2) >> 2] = A3; + u3 = (A3 & c[n2 >> 2]) << 1; + q2 = y3; + s2 = u3; + u3 = (c[Q3 >> 2] | 0) + (u3 << 2) | 0; + } + B3 = 0; + C3 = q2; + A3 = c[u3 >> 2] | 0; + G3 = G3 + -1 | 0; + } + if ((w2 | 0) == 71) { + c[(c[Q3 >> 2] | 0) + (r2 << 2) >> 2] = c[R3 >> 2]; + c[(c[Q3 >> 2] | 0) + (s2 << 2) >> 2] = c[R3 >> 2]; + } else if ((w2 | 0) == 90) { + ca3 = c[Q3 >> 2] | 0; + c[ca3 + (r2 << 2) >> 2] = c[ca3 + ((A3 & c[n2 >> 2]) << 1 << 2) >> 2]; + ca3 = c[Q3 >> 2] | 0; + c[ca3 + (s2 << 2) >> 2] = c[ca3 + (((A3 & c[n2 >> 2]) << 1 | 1) << 2) >> 2]; + } + H3 = H3 + 1 | 0; + } + p2 = p2 + (((c[T3 >> 2] | 0) >>> 5) + -1) | 0; + c[N3 >> 2] = 0; + } + } else Ga2(e2, f2, p2, h2, j2, k2, l2, m3, 0, Z3, $2, aa2, o2); + while (0); + p2 = p2 + 1 | 0; + } + if ((w2 | 0) == 25) pa2(405873, 405905, 373, 405932); + else if ((w2 | 0) == 38) pa2(405955, 405905, 378, 405932); + else if ((w2 | 0) == 73) pa2(405873, 405905, 373, 405932); + else if ((w2 | 0) == 86) pa2(405955, 405905, 378, 405932); + else if ((w2 | 0) == 88) na(); + else if ((w2 | 0) == 98) { + ra2[c[b3 + 4 >> 2] & 1](c[U3 >> 2] | 0, c[V3 >> 2] | 0); + c[V3 >> 2] = 0; + while (1) { + if (c[o2 + (e2 << 4) + 8 >> 2] | 0) break; + if ((c[o2 + (e2 << 4) >> 2] | 0) != 1) break; + e2 = e2 + -1 | 0; + } + c[o2 + (e2 << 4) + 12 >> 2] = -1; + p2 = 0; + while (1) { + if (!e2) break; + j2 = (c[o2 + (e2 << 4) >> 2] & 16777215) + (c[o2 + (e2 << 4) + 8 >> 2] | 0) | 0; + ca3 = e2 - j2 | 0; + c[o2 + (ca3 << 4) + 12 >> 2] = j2; + e2 = ca3; + p2 = p2 + 1 | 0; + } + i = ba2; + return p2 | 0; + } + return 0; + } + function Fa2(b3, e2, f2, h2) { + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + h2 = h2 | 0; + var j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0; + w2 = i; + i = i + 4128 | 0; + p2 = w2 + 4112 | 0; + s2 = w2 + 1040 | 0; + t3 = w2 + 1024 | 0; + o2 = w2; + u3 = c[b3 + 4904 >> 2] | 0; + v3 = c[b3 + 4896 >> 2] | 0; + a: do + if (Wb(f2, e2, h2, u3) | 0) { + c[p2 >> 2] = 0; + c[p2 + 4 >> 2] = 0; + c[p2 + 8 >> 2] = 0; + l2 = 0; + o2 = 0; + while (1) { + if ((o2 | 0) == (u3 | 0)) break; + j2 = a[f2 + (o2 + e2 & h2) >> 0] | 0; + n2 = j2 & 255; + if (j2 << 24 >> 24 <= -1) if ((j2 & 255) > 191) j2 = 1; + else j2 = l2 >>> 0 < 224 ? 0 : 2; + else j2 = 0; + l2 = p2 + (j2 << 2) | 0; + c[l2 >> 2] = (c[l2 >> 2] | 0) + 1; + l2 = n2; + o2 = o2 + 1 | 0; + } + r2 = ((c[p2 + 4 >> 2] | 0) + (c[p2 + 8 >> 2] | 0) | 0) >>> 0 < 25 ? 0 : 1; + ac(s2 | 0, 0, 3072) | 0; + n2 = u3 >>> 0 > 495 ? 495 : u3; + c[t3 >> 2] = 0; + c[t3 + 4 >> 2] = 0; + c[t3 + 8 >> 2] = 0; + p2 = 0; + q2 = 0; + j2 = 0; + while (1) { + if ((q2 | 0) == (n2 | 0)) { + o2 = 0; + break; + } + l2 = a[f2 + (q2 + e2 & h2) >> 0] | 0; + o2 = l2 & 255; + x3 = s2 + (j2 << 10) + (o2 << 2) | 0; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + j2 = t3 + (j2 << 2) | 0; + c[j2 >> 2] = (c[j2 >> 2] | 0) + 1; + if (l2 << 24 >> 24 <= -1) if ((l2 & 255) > 191) j2 = r2; + else j2 = p2 >>> 0 < 224 ? 0 : r2; + else j2 = 0; + p2 = o2; + q2 = q2 + 1 | 0; + } + while (1) { + if ((o2 | 0) == (u3 | 0)) break; + if (o2 >>> 0 >= 495) { + if (o2 >>> 0 >= 496) { + j2 = o2 + e2 | 0; + l2 = d[f2 + (j2 + -496 & h2) >> 0] | 0; + if (o2 >>> 0 < 497) j2 = 0; + else j2 = d[f2 + (j2 + -497 & h2) >> 0] | 0; + if (l2 >>> 0 >= 128) if (l2 >>> 0 > 191) j2 = r2; + else j2 = j2 >>> 0 < 224 ? 0 : r2; + else j2 = 0; + } else j2 = 0; + x3 = s2 + (j2 << 10) + ((d[f2 + (o2 + e2 + -495 & h2) >> 0] | 0) << 2) | 0; + c[x3 >> 2] = (c[x3 >> 2] | 0) + -1; + x3 = t3 + (j2 << 2) | 0; + c[x3 >> 2] = (c[x3 >> 2] | 0) + -1; + } + if ((o2 + 495 | 0) >>> 0 < u3 >>> 0) { + l2 = o2 + e2 | 0; + n2 = l2 + 495 | 0; + j2 = a[f2 + (l2 + 494 & h2) >> 0] | 0; + l2 = a[f2 + (l2 + 493 & h2) >> 0] | 0; + if (j2 << 24 >> 24 <= -1) if ((j2 & 255) > 191) j2 = r2; + else j2 = (l2 & 255) < 224 ? 0 : r2; + else j2 = 0; + x3 = s2 + (j2 << 10) + ((d[f2 + (n2 & h2) >> 0] | 0) << 2) | 0; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + x3 = t3 + (j2 << 2) | 0; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + } + if (o2) { + j2 = o2 + e2 | 0; + l2 = d[f2 + (j2 + -1 & h2) >> 0] | 0; + if (o2 >>> 0 < 2) j2 = 0; + else j2 = d[f2 + (j2 + -2 & h2) >> 0] | 0; + if (l2 >>> 0 >= 128) if (l2 >>> 0 > 191) j2 = r2; + else j2 = j2 >>> 0 < 224 ? 0 : r2; + else j2 = 0; + } else j2 = 0; + l2 = c[s2 + (j2 << 10) + ((d[f2 + (o2 + e2 & h2) >> 0] | 0) << 2) >> 2] | 0; + l2 = (l2 | 0) == 0 ? 1 : l2; + j2 = c[t3 + (j2 << 2) >> 2] | 0; + if (j2 >>> 0 < 256) m3 = +g2[19516 + (j2 << 2) >> 2]; + else m3 = +Xb(+(j2 >>> 0)); + if (l2 >>> 0 < 256) k2 = +g2[19516 + (l2 << 2) >> 2]; + else k2 = +Xb(+(l2 >>> 0)); + k2 = m3 - k2 + 0.02905; + k2 = k2 < 1 ? k2 * 0.5 + 0.5 : k2; + if (o2 >>> 0 < 2e3) k2 = k2 + (0.7 - +((2e3 - o2 | 0) >>> 0) / 2e3 * 0.35); + g2[v3 + (o2 + 1 << 2) >> 2] = k2; + o2 = o2 + 1 | 0; + } + } else { + ac(o2 | 0, 0, 1024) | 0; + j2 = u3 >>> 0 > 2e3 ? 2e3 : u3; + l2 = 0; + while (1) { + if ((l2 | 0) == (j2 | 0)) { + n2 = 0; + break; + } + x3 = o2 + ((d[f2 + (l2 + e2 & h2) >> 0] | 0) << 2) | 0; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + l2 = l2 + 1 | 0; + } + while (1) { + if ((n2 | 0) == (u3 | 0)) break a; + if (n2 >>> 0 >= 2e3) { + x3 = o2 + ((d[f2 + (n2 + e2 + -2e3 & h2) >> 0] | 0) << 2) | 0; + c[x3 >> 2] = (c[x3 >> 2] | 0) + -1; + j2 = j2 + -1 | 0; + } + l2 = n2 + e2 | 0; + if ((n2 + 2e3 | 0) >>> 0 < u3 >>> 0) { + x3 = o2 + ((d[f2 + (l2 + 2e3 & h2) >> 0] | 0) << 2) | 0; + c[x3 >> 2] = (c[x3 >> 2] | 0) + 1; + j2 = j2 + 1 | 0; + } + l2 = c[o2 + ((d[f2 + (l2 & h2) >> 0] | 0) << 2) >> 2] | 0; + l2 = (l2 | 0) == 0 ? 1 : l2; + if (j2 >>> 0 < 256) m3 = +g2[19516 + (j2 << 2) >> 2]; + else m3 = +Xb(+(j2 >>> 0)); + if (l2 >>> 0 < 256) k2 = +g2[19516 + (l2 << 2) >> 2]; + else k2 = +Xb(+(l2 >>> 0)); + m3 = m3 - k2 + 0.029; + g2[v3 + (n2 + 1 << 2) >> 2] = m3 < 1 ? m3 * 0.5 + 0.5 : m3; + n2 = n2 + 1 | 0; + } + } + while (0); + g2[v3 >> 2] = 0; + k2 = 0; + j2 = 0; + while (1) { + if ((j2 | 0) == (u3 | 0)) { + l2 = 0; + break; + } + x3 = j2 + 1 | 0; + h2 = v3 + (x3 << 2) | 0; + m3 = +g2[h2 >> 2] + k2; + g2[h2 >> 2] = m3; + k2 = m3; + j2 = x3; + } + while (1) { + if ((l2 | 0) == 704) { + l2 = 0; + break; + } + j2 = l2 + 11 | 0; + if (j2 >>> 0 < 256) k2 = +g2[19516 + (j2 << 2) >> 2]; + else k2 = +Xb(+(j2 >>> 0)); + g2[b3 + (l2 << 2) >> 2] = k2; + l2 = l2 + 1 | 0; + } + while (1) { + if ((l2 | 0) == 520) break; + j2 = l2 + 20 | 0; + if (j2 >>> 0 < 256) k2 = +g2[19516 + (j2 << 2) >> 2]; + else k2 = +Xb(+(j2 >>> 0)); + g2[b3 + 2816 + (l2 << 2) >> 2] = k2; + l2 = l2 + 1 | 0; + } + g2[b3 + 4900 >> 2] = 3.4594316482543945; + i = w2; + return; + } + function Ga2(e2, f2, h2, j2, l2, m3, n2, o2, p2, q2, r2, s2, t3) { + e2 = e2 | 0; + f2 = f2 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + t3 = t3 | 0; + var u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, _2 = 0; + Z3 = i; + i = i + 64 | 0; + A3 = Z3 + 36 | 0; + z3 = Z3 + 8 | 0; + Y3 = Z3; + S3 = f2 + h2 | 0; + T3 = S3 & l2; + R3 = S3 >>> 0 < n2 >>> 0 ? S3 : n2; + U3 = e2 - h2 | 0; + Q3 = (c[m3 + 4 >> 2] | 0) < 11; + P3 = Q3 ? 150 : 325; + Q3 = Q3 ? 1 : 5; + y3 = c[t3 + (h2 << 4) + 12 >> 2] | 0; + f2 = c[t3 + (h2 << 4) >> 2] & 16777215; + m3 = c[t3 + (h2 << 4) + 8 >> 2] | 0; + v3 = c[t3 + (h2 << 4) + 4 >> 2] | 0; + w2 = v3 & 33554431; + if (h2) if ((w2 + f2 | 0) >>> 0 > S3 >>> 0 | w2 >>> 0 > n2 >>> 0 | (v3 >>> 25 | 0) == 1) f2 = c[t3 + (h2 - f2 - m3 << 4) + 12 >> 2] | 0; + else f2 = h2; + else f2 = 0; + v3 = t3 + (h2 << 4) + 12 | 0; + c[v3 >> 2] = f2; + x3 = (c[k >> 2] = y3, +g2[k >> 2]); + O3 = r2 + 4896 | 0; + m3 = c[O3 >> 2] | 0; + u3 = +g2[m3 + (h2 << 2) >> 2]; + if (!(x3 <= u3 - +g2[m3 >> 2])) y3 = s2 + 224 | 0; + else { + c[z3 >> 2] = h2; + c[z3 + 24 >> 2] = y3; + f2 = c[O3 >> 2] | 0; + g2[z3 + 20 >> 2] = x3 - (+g2[f2 + (h2 << 2) >> 2] - +g2[f2 >> 2]); + f2 = 0; + m3 = v3; + while (1) { + m3 = c[m3 >> 2] | 0; + if (!((f2 | 0) < 4 & (m3 | 0) != 0)) { + m3 = o2; + break; + } + N3 = c[t3 + (m3 << 4) + 8 >> 2] | 0; + M2 = c[t3 + (m3 << 4) >> 2] & 16777215; + c[z3 + 4 + (f2 << 2) >> 2] = c[t3 + (m3 << 4) + 4 >> 2] & 33554431; + f2 = f2 + 1 | 0; + m3 = t3 + (m3 - M2 - N3 << 4) + 12 | 0; + } + while (1) { + if ((f2 | 0) >= 4) break; + c[z3 + 4 + (f2 << 2) >> 2] = c[m3 >> 2]; + m3 = m3 + 4 | 0; + f2 = f2 + 1 | 0; + } + y3 = s2 + 224 | 0; + f2 = c[y3 >> 2] | 0; + n2 = f2 + 1 | 0; + c[y3 >> 2] = n2; + f2 = f2 & 7 ^ 7; + n2 = n2 >>> 0 < 8 ? n2 : 8; + w2 = s2 + (f2 * 28 | 0) | 0; + c[w2 >> 2] = c[z3 >> 2]; + c[w2 + 4 >> 2] = c[z3 + 4 >> 2]; + c[w2 + 8 >> 2] = c[z3 + 8 >> 2]; + c[w2 + 12 >> 2] = c[z3 + 12 >> 2]; + c[w2 + 16 >> 2] = c[z3 + 16 >> 2]; + c[w2 + 20 >> 2] = c[z3 + 20 >> 2]; + c[w2 + 24 >> 2] = c[z3 + 24 >> 2]; + w2 = 1; + while (1) { + if (w2 >>> 0 >= n2 >>> 0) break; + v3 = f2 & 7; + f2 = f2 + 1 | 0; + m3 = f2 & 7; + if (+g2[s2 + (v3 * 28 | 0) + 20 >> 2] > +g2[s2 + (m3 * 28 | 0) + 20 >> 2]) { + M2 = s2 + (v3 * 28 | 0) | 0; + c[A3 >> 2] = c[M2 >> 2]; + c[A3 + 4 >> 2] = c[M2 + 4 >> 2]; + c[A3 + 8 >> 2] = c[M2 + 8 >> 2]; + c[A3 + 12 >> 2] = c[M2 + 12 >> 2]; + c[A3 + 16 >> 2] = c[M2 + 16 >> 2]; + c[A3 + 20 >> 2] = c[M2 + 20 >> 2]; + c[A3 + 24 >> 2] = c[M2 + 24 >> 2]; + N3 = s2 + (m3 * 28 | 0) | 0; + c[M2 >> 2] = c[N3 >> 2]; + c[M2 + 4 >> 2] = c[N3 + 4 >> 2]; + c[M2 + 8 >> 2] = c[N3 + 8 >> 2]; + c[M2 + 12 >> 2] = c[N3 + 12 >> 2]; + c[M2 + 16 >> 2] = c[N3 + 16 >> 2]; + c[M2 + 20 >> 2] = c[N3 + 20 >> 2]; + c[M2 + 24 >> 2] = c[N3 + 24 >> 2]; + c[N3 >> 2] = c[A3 >> 2]; + c[N3 + 4 >> 2] = c[A3 + 4 >> 2]; + c[N3 + 8 >> 2] = c[A3 + 8 >> 2]; + c[N3 + 12 >> 2] = c[A3 + 12 >> 2]; + c[N3 + 16 >> 2] = c[A3 + 16 >> 2]; + c[N3 + 20 >> 2] = c[A3 + 20 >> 2]; + c[N3 + 24 >> 2] = c[A3 + 24 >> 2]; + } + w2 = w2 + 1 | 0; + } + N3 = c[O3 >> 2] | 0; + m3 = N3; + u3 = +g2[N3 + (h2 << 2) >> 2]; + } + v3 = 0 - (c[y3 >> 2] | 0) & 7; + f2 = 2; + u3 = +g2[s2 + (v3 * 28 | 0) + 24 >> 2] + +g2[r2 + 4900 >> 2] + (u3 - +g2[m3 + (c[s2 + (v3 * 28 | 0) >> 2] << 2) >> 2]); + v3 = 4; + w2 = 10; + a: while (1) { + do { + m3 = f2 + h2 | 0; + if (m3 >>> 0 > e2 >>> 0) break a; + if (!(+g2[t3 + (m3 << 4) + 12 >> 2] <= u3)) break a; + f2 = f2 + 1 | 0; + } while ((f2 | 0) != (w2 | 0)); + N3 = w2 + v3 | 0; + f2 = w2; + u3 = u3 + 1; + v3 = v3 << 1; + w2 = N3; + } + H3 = f2 + -1 | 0; + I3 = j2 + T3 | 0; + K3 = T3 + U3 | 0; + J3 = j2 + K3 | 0; + K3 = j2 + (K3 + -4) | 0; + L3 = Y3 + 4 | 0; + M2 = Y3 + 4 | 0; + N3 = 0; + while (1) { + if (N3 >>> 0 >= Q3 >>> 0) { + f2 = 82; + break; + } + m3 = c[y3 >> 2] | 0; + if (N3 >>> 0 >= (m3 >>> 0 < 8 ? m3 : 8) >>> 0) { + f2 = 82; + break; + } + C3 = N3 - m3 & 7; + D3 = h2 - (c[s2 + (C3 * 28 | 0) >> 2] | 0) | 0; + do + if (D3 >>> 0 >= 6) { + if (D3 >>> 0 < 130) { + G3 = D3 + -2 | 0; + m3 = ((aa(G3 | 0) | 0) ^ 31) + -1 | 0; + m3 = (m3 << 1) + (G3 >>> m3) + 2 & 65535; + break; + } + if (D3 >>> 0 < 2114) { + m3 = ((aa(D3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (D3 >>> 0 < 6210) m3 = 21; + else m3 = D3 >>> 0 < 22594 ? 22 : 23; + } else m3 = D3 & 65535; + while (0); + G3 = m3 & 65535; + F3 = c[O3 >> 2] | 0; + E3 = +g2[s2 + (C3 * 28 | 0) + 20 >> 2] + +((c[17268 + (G3 << 2) >> 2] | 0) >>> 0) + (+g2[F3 + (h2 << 2) >> 2] - +g2[F3 >> 2]); + F3 = G3 << 3 & 56; + G3 = (G3 >>> 3) * 3 | 0; + e2 = (m3 & 65535) < 8; + m3 = H3; + B3 = 0; + while (1) { + if (!(B3 >>> 0 < 16 & m3 >>> 0 < U3 >>> 0)) break; + n2 = (c[s2 + (C3 * 28 | 0) + 4 + (c[11372 + (B3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (B3 << 2) >> 2] | 0) | 0; + v3 = S3 - n2 | 0; + b: do + if (((!(v3 >>> 0 >= S3 >>> 0 | n2 >>> 0 > R3 >>> 0) ? (V3 = v3 & l2, W3 = T3 + m3 | 0, W3 >>> 0 <= l2 >>> 0) : 0) ? (X3 = V3 + m3 | 0, X3 >>> 0 <= l2 >>> 0) : 0) ? (a[j2 + W3 >> 0] | 0) == (a[j2 + X3 >> 0] | 0) : 0) { + v3 = 0; + w2 = I3; + while (1) { + if (w2 >>> 0 > K3 >>> 0) break; + A3 = j2 + (V3 + v3) | 0; + if ((d[w2 >> 0] | d[w2 + 1 >> 0] << 8 | d[w2 + 2 >> 0] << 16 | d[w2 + 3 >> 0] << 24 | 0) != (d[A3 >> 0] | d[A3 + 1 >> 0] << 8 | d[A3 + 2 >> 0] << 16 | d[A3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + w2 = w2 + 4 | 0; + } + while (1) { + if (w2 >>> 0 >= J3 >>> 0) break; + if ((a[j2 + (V3 + v3) >> 0] | 0) != (a[w2 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + w2 = w2 + 1 | 0; + } + x3 = E3 + +g2[r2 + 2816 + (B3 << 2) >> 2]; + A3 = (B3 | 0) == 0; + z3 = n2 | (B3 << 25) + 33554432; + while (1) { + o2 = m3 + 1 | 0; + if (o2 >>> 0 > v3 >>> 0) break b; + do + if (o2 >>> 0 >= 10) { + if (o2 >>> 0 < 134) { + n2 = m3 + -5 | 0; + m3 = ((aa(n2 | 0) | 0) ^ 31) + -1 | 0; + m3 = (m3 << 1) + (n2 >>> m3) + 4 & 65535; + break; + } + if (o2 >>> 0 < 2118) m3 = ((aa(m3 + -69 | 0) | 0) ^ 31) + 12 & 65535; + else m3 = 23; + } else m3 = m3 + 65535 & 65535; + while (0); + n2 = m3 & 65535; + w2 = n2 & 7 | F3; + if (((A3 ^ 1 | e2 ^ 1) ^ 1) & (m3 & 65535) < 16) m3 = ((m3 & 65535) < 8 ? w2 : w2 | 64) & 65535; + else m3 = b2[88156 + ((n2 >>> 3) + G3 << 1) >> 1] | w2 & 65535; + u3 = ((m3 & 65535) < 128 ? E3 : x3) + +((c[17460 + (n2 << 2) >> 2] | 0) >>> 0) + +g2[r2 + ((m3 & 65535) << 2) >> 2]; + m3 = o2 + h2 | 0; + if (!(u3 < +g2[t3 + (m3 << 4) + 12 >> 2])) { + m3 = o2; + continue; + } + c[t3 + (m3 << 4) >> 2] = o2 | 150994944; + c[t3 + (m3 << 4) + 4 >> 2] = z3; + c[t3 + (m3 << 4) + 8 >> 2] = D3; + g2[t3 + (m3 << 4) + 12 >> 2] = u3; + m3 = o2; + } + } + while (0); + B3 = B3 + 1 | 0; + } + c: do + if (N3 >>> 0 <= 1) { + o2 = f2; + C3 = 0; + while (1) { + if ((C3 | 0) == (p2 | 0)) break c; + z3 = q2 + (C3 << 3) | 0; + e2 = c[z3 >> 2] | 0; + z3 = c[z3 + 4 >> 2] | 0; + n2 = Y3; + c[n2 >> 2] = e2; + c[n2 + 4 >> 2] = z3; + n2 = e2 >>> 0 > R3 >>> 0; + m3 = n2 & 1; + v3 = e2 + 15 | 0; + B3 = bc(e2 | 0, z3 | 0, 37) | 0; + if (v3 >>> 0 < 16) w2 = 0; + else { + _2 = e2 + 3 | 0; + w2 = ((aa(_2 | 0) | 0) ^ 31) + -1 | 0; + A3 = _2 >>> w2 & 1; + v3 = ((w2 << 1) + 65534 | A3) + 16 | 0; + w2 = w2 << 24 | _2 - ((A3 | 2) << w2); + } + x3 = E3 + +(w2 >>> 24 >>> 0) + +g2[r2 + 2816 + ((v3 & 65535) << 2) >> 2]; + if (o2 >>> 0 < B3 >>> 0) { + _2 = n2 | B3 >>> 0 > P3 >>> 0; + m3 = _2 ? m3 : 0; + o2 = _2 ? B3 : o2; + } + A3 = m3 << 24 >> 24 == 0; + w2 = bc(e2 | 0, z3 | 0, 37) | 0; + w2 = w2 + 1 | 0; + n2 = o2 >>> 0 > w2 >>> 0; + z3 = o2; + while (1) { + if (z3 >>> 0 > B3 >>> 0) break; + if (!A3) { + m3 = c[L3 >> 2] & 31; + if (!m3) m3 = (c[M2 >> 2] | 0) >>> 5; + } else m3 = z3; + do + if (m3 >>> 0 >= 10) { + if (m3 >>> 0 < 134) { + _2 = m3 + -6 | 0; + v3 = ((aa(_2 | 0) | 0) ^ 31) + -1 | 0; + v3 = (v3 << 1) + (_2 >>> v3) + 4 | 0; + break; + } + if (m3 >>> 0 < 2118) v3 = ((aa(m3 + -70 | 0) | 0) ^ 31) + 12 | 0; + else v3 = 23; + } else v3 = m3 + 65534 | 0; + while (0); + _2 = v3 & 65535; + u3 = x3 + +((c[17460 + (_2 << 2) >> 2] | 0) >>> 0) + +g2[r2 + (((b2[88156 + ((_2 >>> 3) + G3 << 1) >> 1] | (v3 & 7 | F3) & 65535) & 65535) << 2) >> 2]; + v3 = z3 + h2 | 0; + if (u3 < +g2[t3 + (v3 << 4) + 12 >> 2]) { + c[t3 + (v3 << 4) >> 2] = z3 | z3 + 9 - m3 << 24; + c[t3 + (v3 << 4) + 4 >> 2] = e2; + c[t3 + (v3 << 4) + 8 >> 2] = D3; + g2[t3 + (v3 << 4) + 12 >> 2] = u3; + } + z3 = z3 + 1 | 0; + } + o2 = n2 ? o2 : w2; + C3 = C3 + 1 | 0; + } + } + while (0); + N3 = N3 + 1 | 0; + } + if ((f2 | 0) == 82) { + i = Z3; + return; + } + } + function Ha2(b3, e2, f2, h2, i2, j2, k2, l2, m3, n2, o2, p2, q2) { + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + h2 = h2 | 0; + i2 = i2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + var r2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0; + M2 = (1 << c[k2 + 8 >> 2]) + -16 | 0; + Ua2(b3, l2, k2, f2, e2, h2); + a: do + if (e2 >>> 0 > 2 & f2 >>> 0 > 127) { + L3 = f2 + -127 | 0; + K3 = L3 + e2 | 0; + K3 = K3 >>> 0 > f2 >>> 0 ? f2 : K3; + J3 = l2 + 524292 | 0; + I3 = l2 + 524296 | 0; + b: while (1) { + if (L3 >>> 0 >= K3 >>> 0) break a; + t3 = c[l2 >> 2] | 0; + E3 = f2 - L3 | 0; + E3 = t3 - (E3 >>> 0 < 15 ? 15 : E3) | 0; + F3 = L3 & j2; + G3 = i2 + F3 | 0; + C3 = l2 + 4 + ((_(d[G3 >> 0] | d[G3 + 1 >> 0] << 8 | d[G3 + 2 >> 0] << 16 | d[G3 + 3 >> 0] << 24, 506832829) | 0) >>> 15 << 2) | 0; + B3 = c[C3 >> 2] | 0; + t3 = (L3 & t3) << 1; + c[C3 >> 2] = L3; + C3 = 0; + u3 = 0; + D3 = 0; + r2 = t3; + t3 = t3 | 1; + H3 = 64; + while (1) { + A3 = B3 & j2; + if ((L3 | 0) == (B3 | 0) | (L3 - B3 | 0) >>> 0 > E3 >>> 0 | (H3 | 0) == 0) { + h2 = 6; + break; + } + z3 = u3 >>> 0 < D3 >>> 0 ? u3 : D3; + if (z3 >>> 0 >= 129) { + h2 = 8; + break b; + } + x3 = F3 + z3 | 0; + y3 = i2 + (A3 + 128) | 0; + v3 = i2 + (A3 + 124) | 0; + w2 = 0; + h2 = i2 + (A3 + z3) | 0; + while (1) { + if (h2 >>> 0 > v3 >>> 0) break; + N3 = i2 + (x3 + w2) | 0; + if ((d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0) != (d[N3 >> 0] | d[N3 + 1 >> 0] << 8 | d[N3 + 2 >> 0] << 16 | d[N3 + 3 >> 0] << 24 | 0)) break; + w2 = w2 + 4 | 0; + h2 = h2 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= y3 >>> 0) break; + if ((a[i2 + (x3 + w2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + w2 = w2 + 1 | 0; + h2 = h2 + 1 | 0; + } + z3 = z3 + w2 | 0; + c: do + if (z3) { + h2 = z3; + x3 = G3; + y3 = i2 + A3 | 0; + while (1) { + v3 = a[x3 >> 0] | 0; + w2 = a[y3 >> 0] | 0; + if (v3 << 24 >> 24 != w2 << 24 >> 24) break; + h2 = h2 + -1 | 0; + if (!h2) break c; + else { + x3 = x3 + 1 | 0; + y3 = y3 + 1 | 0; + } + } + if (v3 << 24 >> 24 != w2 << 24 >> 24) { + h2 = 21; + break b; + } + } + while (0); + if (C3) { + h2 = 23; + break b; + } + if (z3 >>> 0 >= 128) { + h2 = 25; + break; + } + h2 = c[J3 >> 2] | 0; + if ((d[i2 + (F3 + z3) >> 0] | 0) > (d[i2 + (A3 + z3) >> 0] | 0)) { + c[h2 + (r2 << 2) >> 2] = B3; + v3 = (B3 & c[l2 >> 2]) << 1 | 1; + u3 = z3; + h2 = D3; + r2 = v3; + v3 = (c[J3 >> 2] | 0) + (v3 << 2) | 0; + } else { + c[h2 + (t3 << 2) >> 2] = B3; + v3 = (B3 & c[l2 >> 2]) << 1; + h2 = z3; + t3 = v3; + v3 = (c[J3 >> 2] | 0) + (v3 << 2) | 0; + } + C3 = 0; + D3 = h2; + B3 = c[v3 >> 2] | 0; + H3 = H3 + -1 | 0; + } + if ((h2 | 0) == 6) { + c[(c[J3 >> 2] | 0) + (r2 << 2) >> 2] = c[I3 >> 2]; + c[(c[J3 >> 2] | 0) + (t3 << 2) >> 2] = c[I3 >> 2]; + } else if ((h2 | 0) == 25) { + N3 = c[J3 >> 2] | 0; + c[N3 + (r2 << 2) >> 2] = c[N3 + ((B3 & c[l2 >> 2]) << 1 << 2) >> 2]; + N3 = c[J3 >> 2] | 0; + c[N3 + (t3 << 2) >> 2] = c[N3 + (((B3 & c[l2 >> 2]) << 1 | 1) << 2) >> 2]; + } + L3 = L3 + 1 | 0; + } + if ((h2 | 0) == 8) pa2(405873, 405905, 373, 405932); + else if ((h2 | 0) == 21) pa2(405955, 405905, 378, 405932); + else if ((h2 | 0) == 23) na(); + } + while (0); + h2 = b3 + 8 | 0; + r2 = sa2[c[b3 >> 2] & 1](c[h2 >> 2] | 0, (e2 << 4) + 16 | 0) | 0; + if (!r2) oa2(1); + t3 = e2 + 1 | 0; + u3 = 0; + while (1) { + if ((u3 | 0) == (t3 | 0)) break; + c[r2 + (u3 << 4) >> 2] = 1; + c[r2 + (u3 << 4) + 4 >> 2] = 0; + c[r2 + (u3 << 4) + 8 >> 2] = 0; + g2[r2 + (u3 << 4) + 12 >> 2] = s; + u3 = u3 + 1 | 0; + } + N3 = Ea2(b3, e2, f2, i2, j2, k2, M2, m3, l2, r2) | 0; + c[p2 >> 2] = (c[p2 >> 2] | 0) + N3; + Da2(e2, f2, M2, r2, m3, n2, o2, q2); + ra2[c[b3 + 4 >> 2] & 1](c[h2 >> 2] | 0, r2); + return; + } + function Ia2(e2, f2, h2, j2, l2, m3, n2, o2, p2, q2, r2, t3, u3) { + e2 = e2 | 0; + f2 = f2 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + t3 = t3 | 0; + u3 = u3 | 0; + var v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, aa2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, qa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0; + va3 = i; + i = i + 12256 | 0; + fa3 = va3 + 12028 | 0; + ea3 = va3 + 12024 | 0; + qa3 = va3 + 11e3 | 0; + la3 = va3 + 8184 | 0; + ma3 = va3 + 6104 | 0; + ka3 = va3 + 5080 | 0; + aa2 = va3 + 4928 | 0; + ua3 = va3 + 4912 | 0; + ta3 = va3; + ga3 = (1 << c[n2 + 8 >> 2]) + -16 | 0; + da3 = f2 << 2; + ia3 = e2 + 8 | 0; + ja3 = sa2[c[e2 >> 2] & 1](c[ia3 >> 2] | 0, da3) | 0; + if (!ja3) oa2(1); + $2 = f2 >>> 0 > 127 ? h2 + f2 + -127 | 0 : h2; + ca3 = sa2[c[e2 >> 2] & 1](c[ia3 >> 2] | 0, f2 << 5) | 0; + Q3 = ca3; + if (!ca3) oa2(1); + Ua2(e2, o2, n2, h2, f2, j2); + a: do + if (f2 >>> 0 > 2 & h2 >>> 0 > 127) { + P3 = h2 + -127 | 0; + O3 = P3 + f2 | 0; + O3 = O3 >>> 0 > h2 >>> 0 ? h2 : O3; + M2 = o2 + 524292 | 0; + N3 = o2 + 524296 | 0; + b: while (1) { + if (P3 >>> 0 >= O3 >>> 0) break a; + w2 = c[o2 >> 2] | 0; + I3 = h2 - P3 | 0; + I3 = w2 - (I3 >>> 0 < 15 ? 15 : I3) | 0; + J3 = P3 & m3; + K3 = l2 + J3 | 0; + G3 = o2 + 4 + ((_(d[K3 >> 0] | d[K3 + 1 >> 0] << 8 | d[K3 + 2 >> 0] << 16 | d[K3 + 3 >> 0] << 24, 506832829) | 0) >>> 15 << 2) | 0; + F3 = c[G3 >> 2] | 0; + w2 = (P3 & w2) << 1; + c[G3 >> 2] = P3; + G3 = 0; + x3 = 0; + H3 = 0; + v3 = w2; + w2 = w2 | 1; + L3 = 64; + while (1) { + E3 = F3 & m3; + if ((P3 | 0) == (F3 | 0) | (P3 - F3 | 0) >>> 0 > I3 >>> 0 | (L3 | 0) == 0) { + x3 = 11; + break; + } + D3 = x3 >>> 0 < H3 >>> 0 ? x3 : H3; + if (D3 >>> 0 >= 129) { + x3 = 13; + break b; + } + B3 = J3 + D3 | 0; + C3 = l2 + (E3 + 128) | 0; + z3 = l2 + (E3 + 124) | 0; + A3 = 0; + j2 = l2 + (E3 + D3) | 0; + while (1) { + if (j2 >>> 0 > z3 >>> 0) break; + ca3 = l2 + (B3 + A3) | 0; + if ((d[j2 >> 0] | d[j2 + 1 >> 0] << 8 | d[j2 + 2 >> 0] << 16 | d[j2 + 3 >> 0] << 24 | 0) != (d[ca3 >> 0] | d[ca3 + 1 >> 0] << 8 | d[ca3 + 2 >> 0] << 16 | d[ca3 + 3 >> 0] << 24 | 0)) break; + A3 = A3 + 4 | 0; + j2 = j2 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= C3 >>> 0) break; + if ((a[l2 + (B3 + A3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + A3 = A3 + 1 | 0; + j2 = j2 + 1 | 0; + } + D3 = D3 + A3 | 0; + c: do + if (D3) { + j2 = D3; + B3 = K3; + C3 = l2 + E3 | 0; + while (1) { + z3 = a[B3 >> 0] | 0; + A3 = a[C3 >> 0] | 0; + if (z3 << 24 >> 24 != A3 << 24 >> 24) break; + j2 = j2 + -1 | 0; + if (!j2) break c; + else { + B3 = B3 + 1 | 0; + C3 = C3 + 1 | 0; + } + } + if (z3 << 24 >> 24 != A3 << 24 >> 24) { + x3 = 26; + break b; + } + } + while (0); + if (G3) { + x3 = 28; + break b; + } + if (D3 >>> 0 >= 128) { + x3 = 30; + break; + } + j2 = c[M2 >> 2] | 0; + if ((d[l2 + (J3 + D3) >> 0] | 0) > (d[l2 + (E3 + D3) >> 0] | 0)) { + c[j2 + (v3 << 2) >> 2] = F3; + z3 = (F3 & c[o2 >> 2]) << 1 | 1; + x3 = D3; + j2 = H3; + v3 = z3; + z3 = (c[M2 >> 2] | 0) + (z3 << 2) | 0; + } else { + c[j2 + (w2 << 2) >> 2] = F3; + z3 = (F3 & c[o2 >> 2]) << 1; + j2 = D3; + w2 = z3; + z3 = (c[M2 >> 2] | 0) + (z3 << 2) | 0; + } + G3 = 0; + H3 = j2; + F3 = c[z3 >> 2] | 0; + L3 = L3 + -1 | 0; + } + if ((x3 | 0) == 11) { + c[(c[M2 >> 2] | 0) + (v3 << 2) >> 2] = c[N3 >> 2]; + c[(c[M2 >> 2] | 0) + (w2 << 2) >> 2] = c[N3 >> 2]; + } else if ((x3 | 0) == 30) { + ca3 = c[M2 >> 2] | 0; + c[ca3 + (v3 << 2) >> 2] = c[ca3 + ((F3 & c[o2 >> 2]) << 1 << 2) >> 2]; + ca3 = c[M2 >> 2] | 0; + c[ca3 + (w2 << 2) >> 2] = c[ca3 + (((F3 & c[o2 >> 2]) << 1 | 1) << 2) >> 2]; + } + P3 = P3 + 1 | 0; + } + if ((x3 | 0) == 13) pa2(405873, 405905, 373, 405932); + else if ((x3 | 0) == 26) pa2(405955, 405905, 378, 405932); + else if ((x3 | 0) == 28) na(); + } + while (0); + ba2 = e2 + 4 | 0; + ca3 = n2 + 4 | 0; + Y3 = o2 + 524292 | 0; + Z3 = o2 + 524296 | 0; + W3 = 0; + A3 = da3; + v3 = 0; + d: while (1) { + if ((v3 + 3 | 0) >>> 0 >= f2 >>> 0) { + x3 = 142; + break; + } + V3 = v3 + h2 | 0; + U3 = V3 >>> 0 < ga3 >>> 0 ? V3 : ga3; + R3 = f2 - v3 | 0; + j2 = W3 + 128 | 0; + if (A3 >>> 0 < j2 >>> 0) { + x3 = (A3 | 0) == 0; + z3 = x3 ? j2 : A3; + while (1) { + if (z3 >>> 0 >= j2 >>> 0) break; + z3 = z3 << 1; + } + w2 = sa2[c[e2 >> 2] & 1](c[ia3 >> 2] | 0, z3 << 3) | 0; + if (!w2) { + x3 = 42; + break; + } + j2 = Q3; + if (!x3) dc(w2 | 0, j2 | 0, A3 << 3 | 0) | 0; + ra2[c[ba2 >> 2] & 1](c[ia3 >> 2] | 0, j2); + X3 = z3; + } else { + w2 = Q3; + X3 = A3; + } + S3 = w2; + T3 = S3 + (W3 << 3) | 0; + P3 = V3 & m3; + E3 = (c[ca3 >> 2] | 0) != 11 ? 16 : 64; + E3 = V3 >>> 0 < E3 >>> 0 ? 0 : V3 - E3 | 0; + Q3 = l2 + P3 | 0; + F3 = l2 + (P3 + 1) | 0; + H3 = P3 + R3 | 0; + G3 = l2 + H3 | 0; + H3 = l2 + (H3 + -4) | 0; + j2 = T3; + z3 = 1; + x3 = V3; + while (1) { + x3 = x3 + -1 | 0; + if (!(x3 >>> 0 > E3 >>> 0 & z3 >>> 0 < 3)) break; + C3 = V3 - x3 | 0; + if (C3 >>> 0 > U3 >>> 0) break; + D3 = x3 & m3; + if ((a[Q3 >> 0] | 0) != (a[l2 + D3 >> 0] | 0)) { + N3 = z3; + O3 = j2; + z3 = N3; + j2 = O3; + continue; + } + if ((a[F3 >> 0] | 0) == (a[l2 + (D3 + 1) >> 0] | 0)) { + A3 = 0; + B3 = Q3; + } else { + N3 = z3; + O3 = j2; + z3 = N3; + j2 = O3; + continue; + } + while (1) { + if (B3 >>> 0 > H3 >>> 0) break; + O3 = l2 + (D3 + A3) | 0; + if ((d[B3 >> 0] | d[B3 + 1 >> 0] << 8 | d[B3 + 2 >> 0] << 16 | d[B3 + 3 >> 0] << 24 | 0) != (d[O3 >> 0] | d[O3 + 1 >> 0] << 8 | d[O3 + 2 >> 0] << 16 | d[O3 + 3 >> 0] << 24 | 0)) break; + A3 = A3 + 4 | 0; + B3 = B3 + 4 | 0; + } + while (1) { + if (B3 >>> 0 >= G3 >>> 0) break; + if ((a[l2 + (D3 + A3) >> 0] | 0) != (a[B3 >> 0] | 0)) break; + A3 = A3 + 1 | 0; + B3 = B3 + 1 | 0; + } + if (A3 >>> 0 <= z3 >>> 0) { + N3 = z3; + O3 = j2; + z3 = N3; + j2 = O3; + continue; + } + z3 = j2; + c[z3 >> 2] = C3; + c[z3 + 4 >> 2] = A3 << 5; + j2 = z3 + 8 | 0; + z3 = A3; + } + do + if (z3 >>> 0 < R3 >>> 0) { + N3 = R3 >>> 0 < 128 ? R3 : 128; + O3 = R3 >>> 0 > 127; + x3 = o2 + 4 + ((_(d[Q3 >> 0] | d[Q3 + 1 >> 0] << 8 | d[Q3 + 2 >> 0] << 16 | d[Q3 + 3 >> 0] << 24, 506832829) | 0) >>> 15 << 2) | 0; + C3 = c[x3 >> 2] | 0; + A3 = (V3 & c[o2 >> 2]) << 1; + B3 = A3 | 1; + if (O3) { + c[x3 >> 2] = V3; + L3 = 0; + M2 = 0; + K3 = 64; + } else { + L3 = 0; + M2 = 0; + K3 = 64; + } + while (1) { + I3 = V3 - C3 | 0; + J3 = C3 & m3; + if ((V3 | 0) == (C3 | 0) | I3 >>> 0 > U3 >>> 0 | (K3 | 0) == 0) { + x3 = 63; + break; + } + H3 = L3 >>> 0 < M2 >>> 0 ? L3 : M2; + if (H3 >>> 0 >= 129) { + x3 = 66; + break d; + } + F3 = P3 + H3 | 0; + D3 = J3 + R3 | 0; + G3 = l2 + D3 | 0; + D3 = l2 + (D3 + -4) | 0; + E3 = 0; + x3 = l2 + (J3 + H3) | 0; + while (1) { + if (x3 >>> 0 > D3 >>> 0) break; + wa3 = l2 + (F3 + E3) | 0; + if ((d[x3 >> 0] | d[x3 + 1 >> 0] << 8 | d[x3 + 2 >> 0] << 16 | d[x3 + 3 >> 0] << 24 | 0) != (d[wa3 >> 0] | d[wa3 + 1 >> 0] << 8 | d[wa3 + 2 >> 0] << 16 | d[wa3 + 3 >> 0] << 24 | 0)) break; + E3 = E3 + 4 | 0; + x3 = x3 + 4 | 0; + } + while (1) { + if (x3 >>> 0 >= G3 >>> 0) break; + if ((a[l2 + (F3 + E3) >> 0] | 0) != (a[x3 >> 0] | 0)) break; + E3 = E3 + 1 | 0; + x3 = x3 + 1 | 0; + } + H3 = H3 + E3 | 0; + e: do + if (H3) { + x3 = H3; + F3 = Q3; + G3 = l2 + J3 | 0; + while (1) { + D3 = a[F3 >> 0] | 0; + E3 = a[G3 >> 0] | 0; + if (D3 << 24 >> 24 != E3 << 24 >> 24) break; + x3 = x3 + -1 | 0; + if (!x3) break e; + else { + F3 = F3 + 1 | 0; + G3 = G3 + 1 | 0; + } + } + if (D3 << 24 >> 24 != E3 << 24 >> 24) { + x3 = 79; + break d; + } + } + while (0); + x3 = j2; + if ((j2 | 0) != 0 & H3 >>> 0 > z3 >>> 0) { + c[x3 >> 2] = I3; + c[x3 + 4 >> 2] = H3 << 5; + j2 = x3 + 8 | 0; + z3 = H3; + } + if (H3 >>> 0 >= N3 >>> 0) { + x3 = 83; + break; + } + if ((d[l2 + (P3 + H3) >> 0] | 0) > (d[l2 + (J3 + H3) >> 0] | 0)) { + if (O3) c[(c[Y3 >> 2] | 0) + (A3 << 2) >> 2] = C3; + D3 = (C3 & c[o2 >> 2]) << 1 | 1; + C3 = H3; + x3 = M2; + A3 = D3; + D3 = (c[Y3 >> 2] | 0) + (D3 << 2) | 0; + } else { + if (O3) c[(c[Y3 >> 2] | 0) + (B3 << 2) >> 2] = C3; + D3 = (C3 & c[o2 >> 2]) << 1; + C3 = L3; + x3 = H3; + B3 = D3; + D3 = (c[Y3 >> 2] | 0) + (D3 << 2) | 0; + } + L3 = C3; + M2 = x3; + C3 = c[D3 >> 2] | 0; + K3 = K3 + -1 | 0; + } + if ((x3 | 0) == 63) { + if (!O3) break; + c[(c[Y3 >> 2] | 0) + (A3 << 2) >> 2] = c[Z3 >> 2]; + c[(c[Y3 >> 2] | 0) + (B3 << 2) >> 2] = c[Z3 >> 2]; + break; + } else if ((x3 | 0) == 83) { + if (!O3) break; + wa3 = c[Y3 >> 2] | 0; + c[wa3 + (A3 << 2) >> 2] = c[wa3 + ((C3 & c[o2 >> 2]) << 1 << 2) >> 2]; + wa3 = c[Y3 >> 2] | 0; + c[wa3 + (B3 << 2) >> 2] = c[wa3 + (((C3 & c[o2 >> 2]) << 1 | 1) << 2) >> 2]; + break; + } + } + while (0); + x3 = 0; + while (1) { + if ((x3 | 0) == 38) break; + c[aa2 + (x3 << 2) >> 2] = 268435455; + x3 = x3 + 1 | 0; + } + z3 = z3 + 1 | 0; + z3 = z3 >>> 0 < 4 ? 4 : z3; + f: do + if (Vb(Q3, z3, R3, aa2) | 0) { + A3 = R3 >>> 0 > 37 ? 37 : R3; + while (1) { + if (z3 >>> 0 > A3 >>> 0) break f; + x3 = c[aa2 + (z3 << 2) >> 2] | 0; + if (x3 >>> 0 < 268435455) { + wa3 = x3 & 31; + c[j2 >> 2] = U3 + (x3 >>> 5) + 1; + c[j2 + 4 >> 2] = z3 << 5 | ((z3 | 0) == (wa3 | 0) ? 0 : wa3); + j2 = j2 + 8 | 0; + } + z3 = z3 + 1 | 0; + } + } + while (0); + A3 = j2 - T3 >> 3; + j2 = W3 + A3 | 0; + z3 = W3; + while (1) { + x3 = z3; + z3 = z3 + 1 | 0; + if (z3 >>> 0 >= j2 >>> 0) break; + if ((c[S3 + (x3 << 3) + 4 >> 2] | 0) >>> 5 >>> 0 >= (c[S3 + (z3 << 3) + 4 >> 2] | 0) >>> 5 >>> 0) { + x3 = 105; + break d; + } + x3 = c[S3 + (x3 << 3) >> 2] | 0; + if (x3 >>> 0 > U3 >>> 0) continue; + if (x3 >>> 0 > (c[S3 + (z3 << 3) >> 2] | 0) >>> 0) { + x3 = 108; + break d; + } + } + B3 = ja3 + (v3 << 2) | 0; + c[B3 >> 2] = A3; + if (A3) { + x3 = j2 + -1 | 0; + wa3 = c[S3 + (x3 << 3) + 4 >> 2] | 0; + z3 = wa3 >>> 5; + if (wa3 >>> 0 > 10431) { + R3 = z3 + -1 | 0; + j2 = W3 + 1 | 0; + wa3 = S3 + (x3 << 3) | 0; + P3 = c[wa3 + 4 >> 2] | 0; + Q3 = T3; + c[Q3 >> 2] = c[wa3 >> 2]; + c[Q3 + 4 >> 2] = P3; + c[B3 >> 2] = 1; + Q3 = V3 + z3 | 0; + Q3 = Q3 >>> 0 < $2 >>> 0 ? Q3 : $2; + P3 = (V3 + 64 | 0) >>> 0 > Q3 >>> 0 ? V3 + 1 | 0 : Q3 + -63 | 0; + while (1) { + if (P3 >>> 0 >= Q3 >>> 0) break; + A3 = c[o2 >> 2] | 0; + L3 = A3 + -15 | 0; + M2 = P3 & m3; + N3 = l2 + M2 | 0; + J3 = o2 + 4 + ((_(d[N3 >> 0] | d[N3 + 1 >> 0] << 8 | d[N3 + 2 >> 0] << 16 | d[N3 + 3 >> 0] << 24, 506832829) | 0) >>> 15 << 2) | 0; + I3 = c[J3 >> 2] | 0; + A3 = (P3 & A3) << 1; + c[J3 >> 2] = P3; + J3 = 0; + B3 = 0; + K3 = 0; + z3 = A3; + A3 = A3 | 1; + O3 = 64; + while (1) { + H3 = I3 & m3; + if ((P3 | 0) == (I3 | 0) | (P3 - I3 | 0) >>> 0 > L3 >>> 0 | (O3 | 0) == 0) { + x3 = 115; + break; + } + G3 = B3 >>> 0 < K3 >>> 0 ? B3 : K3; + if (G3 >>> 0 >= 129) { + x3 = 117; + break d; + } + E3 = M2 + G3 | 0; + F3 = l2 + (H3 + 128) | 0; + C3 = l2 + (H3 + 124) | 0; + D3 = 0; + x3 = l2 + (H3 + G3) | 0; + while (1) { + if (x3 >>> 0 > C3 >>> 0) break; + wa3 = l2 + (E3 + D3) | 0; + if ((d[x3 >> 0] | d[x3 + 1 >> 0] << 8 | d[x3 + 2 >> 0] << 16 | d[x3 + 3 >> 0] << 24 | 0) != (d[wa3 >> 0] | d[wa3 + 1 >> 0] << 8 | d[wa3 + 2 >> 0] << 16 | d[wa3 + 3 >> 0] << 24 | 0)) break; + D3 = D3 + 4 | 0; + x3 = x3 + 4 | 0; + } + while (1) { + if (x3 >>> 0 >= F3 >>> 0) break; + if ((a[l2 + (E3 + D3) >> 0] | 0) != (a[x3 >> 0] | 0)) break; + D3 = D3 + 1 | 0; + x3 = x3 + 1 | 0; + } + G3 = G3 + D3 | 0; + g: do + if (G3) { + x3 = G3; + E3 = N3; + F3 = l2 + H3 | 0; + while (1) { + C3 = a[E3 >> 0] | 0; + D3 = a[F3 >> 0] | 0; + if (C3 << 24 >> 24 != D3 << 24 >> 24) break; + x3 = x3 + -1 | 0; + if (!x3) break g; + else { + E3 = E3 + 1 | 0; + F3 = F3 + 1 | 0; + } + } + if (C3 << 24 >> 24 != D3 << 24 >> 24) { + x3 = 130; + break d; + } + } + while (0); + if (J3) { + x3 = 132; + break d; + } + if (G3 >>> 0 >= 128) { + x3 = 134; + break; + } + x3 = c[Y3 >> 2] | 0; + if ((d[l2 + (M2 + G3) >> 0] | 0) > (d[l2 + (H3 + G3) >> 0] | 0)) { + c[x3 + (z3 << 2) >> 2] = I3; + C3 = (I3 & c[o2 >> 2]) << 1 | 1; + B3 = G3; + x3 = K3; + z3 = C3; + C3 = (c[Y3 >> 2] | 0) + (C3 << 2) | 0; + } else { + c[x3 + (A3 << 2) >> 2] = I3; + C3 = (I3 & c[o2 >> 2]) << 1; + x3 = G3; + A3 = C3; + C3 = (c[Y3 >> 2] | 0) + (C3 << 2) | 0; + } + J3 = 0; + K3 = x3; + I3 = c[C3 >> 2] | 0; + O3 = O3 + -1 | 0; + } + if ((x3 | 0) == 115) { + c[(c[Y3 >> 2] | 0) + (z3 << 2) >> 2] = c[Z3 >> 2]; + c[(c[Y3 >> 2] | 0) + (A3 << 2) >> 2] = c[Z3 >> 2]; + } else if ((x3 | 0) == 134) { + wa3 = c[Y3 >> 2] | 0; + c[wa3 + (z3 << 2) >> 2] = c[wa3 + ((I3 & c[o2 >> 2]) << 1 << 2) >> 2]; + wa3 = c[Y3 >> 2] | 0; + c[wa3 + (A3 << 2) >> 2] = c[wa3 + (((I3 & c[o2 >> 2]) << 1 | 1) << 2) >> 2]; + } + P3 = P3 + 1 | 0; + } + ac(ja3 + (v3 + 1 << 2) | 0, 0, R3 << 2 | 0) | 0; + v3 = v3 + R3 | 0; + } + } else j2 = W3; + W3 = j2; + Q3 = w2; + A3 = X3; + v3 = v3 + 1 | 0; + } + if ((x3 | 0) == 42) oa2(1); + else if ((x3 | 0) == 66) pa2(405873, 405905, 373, 405932); + else if ((x3 | 0) == 79) pa2(405955, 405905, 378, 405932); + else if ((x3 | 0) == 105) pa2(403595, 403667, 793, 403707); + else if ((x3 | 0) == 108) pa2(403740, 403667, 795, 403707); + else if ((x3 | 0) == 117) pa2(405873, 405905, 373, 405932); + else if ((x3 | 0) == 130) pa2(405955, 405905, 378, 405932); + else if ((x3 | 0) == 132) na(); + else if ((x3 | 0) == 142) { + K3 = c[u3 >> 2] | 0; + L3 = c[q2 >> 2] | 0; + c[ua3 >> 2] = c[p2 >> 2]; + c[ua3 + 4 >> 2] = c[p2 + 4 >> 2]; + c[ua3 + 8 >> 2] = c[p2 + 8 >> 2]; + c[ua3 + 12 >> 2] = c[p2 + 12 >> 2]; + M2 = c[t3 >> 2] | 0; + N3 = sa2[c[e2 >> 2] & 1](c[ia3 >> 2] | 0, (f2 << 4) + 16 | 0) | 0; + if (!N3) oa2(1); + O3 = ta3 + 4904 | 0; + c[O3 >> 2] = f2; + j2 = sa2[c[e2 >> 2] & 1](c[ia3 >> 2] | 0, da3 + 8 | 0) | 0; + if (!j2) oa2(1); + J3 = ta3 + 4896 | 0; + c[J3 >> 2] = j2; + B3 = N3 + 12 | 0; + C3 = fa3 + 224 | 0; + D3 = Q3; + E3 = h2 - L3 | 0; + F3 = ta3 + 2816 | 0; + G3 = ta3 + 4900 | 0; + H3 = f2 + 1 | 0; + I3 = 0; + while (1) { + if ((I3 | 0) == 2) break; + else j2 = 0; + while (1) { + if ((j2 | 0) == (H3 | 0)) break; + c[N3 + (j2 << 4) >> 2] = 1; + c[N3 + (j2 << 4) + 4 >> 2] = 0; + c[N3 + (j2 << 4) + 8 >> 2] = 0; + g2[N3 + (j2 << 4) + 12 >> 2] = s; + j2 = j2 + 1 | 0; + } + if (!I3) Fa2(ta3, h2, l2, m3); + else { + v3 = c[t3 >> 2] | 0; + ac(qa3 | 0, 0, 1024) | 0; + ac(la3 | 0, 0, 2816) | 0; + ac(ma3 | 0, 0, 2080) | 0; + v3 = v3 - M2 | 0; + z3 = E3; + A3 = 0; + while (1) { + if ((A3 | 0) == (v3 | 0)) break; + w2 = c[r2 + (A3 << 4) >> 2] | 0; + x3 = c[r2 + (A3 << 4) + 4 >> 2] & 16777215; + j2 = b2[r2 + (A3 << 4) + 14 >> 1] | 0; + wa3 = b2[r2 + (A3 << 4) + 12 >> 1] | 0; + e2 = la3 + ((wa3 & 65535) << 2) | 0; + c[e2 >> 2] = (c[e2 >> 2] | 0) + 1; + if ((wa3 & 65535) > 127) { + j2 = ma3 + ((j2 & 65535) << 2) | 0; + c[j2 >> 2] = (c[j2 >> 2] | 0) + 1; + j2 = 0; + } else j2 = 0; + while (1) { + if ((j2 | 0) == (w2 | 0)) break; + wa3 = qa3 + (d[l2 + (z3 + j2 & m3) >> 0] << 2) | 0; + c[wa3 >> 2] = (c[wa3 >> 2] | 0) + 1; + j2 = j2 + 1 | 0; + } + z3 = z3 + (w2 + x3) | 0; + A3 = A3 + 1 | 0; + } + Va2(qa3, 256, ka3); + Va2(la3, 704, ta3); + Va2(ma3, 520, F3); + j2 = 2139095040; + v3 = 0; + while (1) { + if ((v3 | 0) == 704) break; + wa3 = c[ta3 + (v3 << 2) >> 2] | 0; + c[fa3 >> 2] = j2; + c[ea3 >> 2] = wa3; + y3 = (c[k >> 2] = j2, +g2[k >> 2]); + j2 = c[(y3 < (c[k >> 2] = wa3, +g2[k >> 2]) ? fa3 : ea3) >> 2] | 0; + v3 = v3 + 1 | 0; + } + c[G3 >> 2] = j2; + v3 = c[O3 >> 2] | 0; + j2 = c[J3 >> 2] | 0; + g2[j2 >> 2] = 0; + y3 = 0; + w2 = 0; + while (1) { + if ((w2 | 0) == (v3 | 0)) break; + xa3 = y3 + +g2[ka3 + (d[l2 + (w2 + h2 & m3) >> 0] << 2) >> 2]; + wa3 = w2 + 1 | 0; + g2[j2 + (wa3 << 2) >> 2] = xa3; + y3 = xa3; + w2 = wa3; + } + } + c[t3 >> 2] = M2; + c[u3 >> 2] = K3; + c[q2 >> 2] = L3; + c[p2 >> 2] = c[ua3 >> 2]; + c[p2 + 4 >> 2] = c[ua3 + 4 >> 2]; + c[p2 + 8 >> 2] = c[ua3 + 8 >> 2]; + c[p2 + 12 >> 2] = c[ua3 + 12 >> 2]; + w2 = (c[ca3 >> 2] | 0) < 11 ? 150 : 325; + c[N3 >> 2] = 0; + g2[B3 >> 2] = 0; + c[C3 >> 2] = 0; + j2 = 0; + v3 = 0; + while (1) { + if ((v3 + 3 | 0) >>> 0 >= f2 >>> 0) { + j2 = f2; + break; + } + wa3 = ja3 + (v3 << 2) | 0; + Ga2(f2, h2, v3, l2, m3, n2, ga3, p2, c[wa3 >> 2] | 0, D3 + (j2 << 3) | 0, ta3, fa3, N3); + wa3 = c[wa3 >> 2] | 0; + j2 = j2 + wa3 | 0; + if ((wa3 | 0) == 1 ? (ha3 = (c[D3 + (j2 + -1 << 3) + 4 >> 2] | 0) >>> 5, ha3 >>> 0 > w2 >>> 0) : 0) { + c[C3 >> 2] = 0; + v3 = v3 + (ha3 + -1) | 0; + } + v3 = v3 + 1 | 0; + } + while (1) { + if (c[N3 + (j2 << 4) + 8 >> 2] | 0) break; + if ((c[N3 + (j2 << 4) >> 2] | 0) != 1) break; + j2 = j2 + -1 | 0; + } + c[N3 + (j2 << 4) + 12 >> 2] = -1; + v3 = 0; + while (1) { + if (!j2) break; + e2 = (c[N3 + (j2 << 4) >> 2] & 16777215) + (c[N3 + (j2 << 4) + 8 >> 2] | 0) | 0; + wa3 = j2 - e2 | 0; + c[N3 + (wa3 << 4) + 12 >> 2] = e2; + j2 = wa3; + v3 = v3 + 1 | 0; + } + c[t3 >> 2] = (c[t3 >> 2] | 0) + v3; + Da2(f2, h2, ga3, N3, p2, q2, r2, u3); + I3 = I3 + 1 | 0; + } + ra2[c[ba2 >> 2] & 1](c[ia3 >> 2] | 0, c[J3 >> 2] | 0); + c[J3 >> 2] = 0; + ra2[c[ba2 >> 2] & 1](c[ia3 >> 2] | 0, N3); + ra2[c[ba2 >> 2] & 1](c[ia3 >> 2] | 0, Q3); + ra2[c[ba2 >> 2] & 1](c[ia3 >> 2] | 0, ja3); + i = va3; + return; + } + } + function Ja2(e2, f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2) { + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + var s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0; + ga3 = i; + i = i + 32 | 0; + ea3 = ga3 + 16 | 0; + fa3 = ga3; + ca3 = (1 << c[l2 + 8 >> 2]) + -16 | 0; + t3 = c[o2 >> 2] | 0; + da3 = g3 + f2 | 0; + ba2 = f2 >>> 0 > 7 ? da3 + -7 | 0 : g3; + $2 = l2 + 4 | 0; + Z3 = (c[$2 >> 2] | 0) < 9 ? 64 : 512; + s2 = Z3 + g3 | 0; + if ((((g3 | 0) == 0 ^ 1 | h2 ^ 1) ^ 1) & f2 >>> 0 < 2049) { + e2 = 0; + while (1) { + if ((e2 | 0) == (f2 | 0)) break; + Y3 = j2 + e2 | 0; + X3 = Y3; + Y3 = Y3 + 4 | 0; + Y3 = lc(d[X3 >> 0] | d[X3 + 1 >> 0] << 8 | d[X3 + 2 >> 0] << 16 | d[X3 + 3 >> 0] << 24 | 0, d[Y3 >> 0] | d[Y3 + 1 >> 0] << 8 | d[Y3 + 2 >> 0] << 16 | d[Y3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + Y3 = bc(Y3 | 0, C2 | 0, 48) | 0; + c[m3 + (Y3 << 2) >> 2] = 0; + e2 = e2 + 1 | 0; + } + if (f2) { + a[m3 + 262148 >> 0] = 0; + ta3 = 8; + } + } else if (!(a[m3 + 262148 >> 0] & 1)) ta3 = 8; + else { + ac(m3 | 0, 0, 262149) | 0; + ta3 = 8; + } + if ((ta3 | 0) == 8 ? f2 >>> 0 > 6 & g3 >>> 0 > 2 : 0) { + X3 = g3 + -3 | 0; + Y3 = j2 + (X3 & k2) | 0; + W3 = Y3; + Y3 = Y3 + 4 | 0; + Y3 = lc(d[W3 >> 0] | d[W3 + 1 >> 0] << 8 | d[W3 + 2 >> 0] << 16 | d[W3 + 3 >> 0] << 24 | 0, d[Y3 >> 0] | d[Y3 + 1 >> 0] << 8 | d[Y3 + 2 >> 0] << 16 | d[Y3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + Y3 = bc(Y3 | 0, C2 | 0, 48) | 0; + c[m3 + (Y3 << 2) >> 2] = X3; + Y3 = g3 + -2 | 0; + X3 = j2 + (Y3 & k2) | 0; + W3 = X3; + X3 = X3 + 4 | 0; + X3 = lc(d[W3 >> 0] | d[W3 + 1 >> 0] << 8 | d[W3 + 2 >> 0] << 16 | d[W3 + 3 >> 0] << 24 | 0, d[X3 >> 0] | d[X3 + 1 >> 0] << 8 | d[X3 + 2 >> 0] << 16 | d[X3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + X3 = bc(X3 | 0, C2 | 0, 48) | 0; + c[m3 + (X3 << 2) >> 2] = Y3; + X3 = g3 + -1 | 0; + Y3 = j2 + (X3 & k2) | 0; + W3 = Y3; + Y3 = Y3 + 4 | 0; + Y3 = lc(d[W3 >> 0] | d[W3 + 1 >> 0] << 8 | d[W3 + 2 >> 0] << 16 | d[W3 + 3 >> 0] << 24 | 0, d[Y3 >> 0] | d[Y3 + 1 >> 0] << 8 | d[Y3 + 2 >> 0] << 16 | d[Y3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + Y3 = bc(Y3 | 0, C2 | 0, 48) | 0; + c[m3 + (Y3 << 2) >> 2] = X3; + } + G3 = ea3 + 4 | 0; + H3 = ea3 + 8 | 0; + I3 = ea3 + 12 | 0; + J3 = ea3 + 4 | 0; + K3 = m3 + 262156 | 0; + L3 = m3 + 262152 | 0; + M2 = ea3 + 12 | 0; + N3 = ea3 + 8 | 0; + O3 = Z3 << 2; + P3 = da3 + -7 | 0; + Q3 = fa3 + 4 | 0; + R3 = fa3 + 8 | 0; + S3 = fa3 + 12 | 0; + T3 = fa3 + 4 | 0; + U3 = fa3 + 8 | 0; + V3 = fa3 + 12 | 0; + W3 = n2 + 8 | 0; + X3 = n2 + 12 | 0; + Y3 = n2 + 4 | 0; + l2 = g3; + F3 = p2; + e2 = t3; + a: while (1) { + B3 = F3; + E3 = s2 + O3 | 0; + b: while (1) { + D3 = da3 - l2 | 0; + if ((l2 + 8 | 0) >>> 0 >= da3 >>> 0) break a; + z3 = l2 >>> 0 < ca3 >>> 0 ? l2 : ca3; + c[ea3 >> 2] = 0; + c[G3 >> 2] = 0; + c[H3 >> 2] = 0; + c[I3 >> 2] = 4240; + A3 = l2 & k2; + x3 = j2 + A3 | 0; + u3 = x3; + w2 = u3; + w2 = d[w2 >> 0] | d[w2 + 1 >> 0] << 8 | d[w2 + 2 >> 0] << 16 | d[w2 + 3 >> 0] << 24; + u3 = u3 + 4 | 0; + u3 = lc(w2 | 0, d[u3 >> 0] | d[u3 + 1 >> 0] << 8 | d[u3 + 2 >> 0] << 16 | d[u3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + u3 = bc(u3 | 0, C2 | 0, 48) | 0; + v3 = c[n2 >> 2] | 0; + h2 = l2 - v3 | 0; + c[J3 >> 2] = 0; + if (h2 >>> 0 < l2 >>> 0 ? (ha3 = h2 & k2, (a[j2 + ha3 >> 0] | 0) == (w2 & 255) << 24 >> 24) : 0) { + f2 = A3 + D3 | 0; + t3 = j2 + f2 | 0; + f2 = j2 + (f2 + -4) | 0; + g3 = 0; + h2 = x3; + while (1) { + if (h2 >>> 0 > f2 >>> 0) break; + y3 = j2 + (ha3 + g3) | 0; + if ((d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0) != (d[y3 >> 0] | d[y3 + 1 >> 0] << 8 | d[y3 + 2 >> 0] << 16 | d[y3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + h2 = h2 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= t3 >>> 0) break; + if ((a[j2 + (ha3 + g3) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (g3 >>> 0 > 3) { + ta3 = 22; + break; + } + } + y3 = m3 + (u3 << 2) | 0; + t3 = c[y3 >> 2] | 0; + c[y3 >> 2] = l2; + u3 = l2 - t3 | 0; + v3 = t3 & k2; + if (!(((l2 | 0) == (t3 | 0) ? 1 : (a[j2 + v3 >> 0] | 0) != (w2 & 255) << 24 >> 24) | u3 >>> 0 > z3 >>> 0)) { + f2 = A3 + D3 | 0; + t3 = j2 + f2 | 0; + f2 = j2 + (f2 + -4) | 0; + g3 = 0; + h2 = x3; + while (1) { + if (h2 >>> 0 > f2 >>> 0) break; + w2 = j2 + (v3 + g3) | 0; + if ((d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0) != (d[w2 >> 0] | d[w2 + 1 >> 0] << 8 | d[w2 + 2 >> 0] << 16 | d[w2 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + h2 = h2 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= t3 >>> 0) break; + if ((a[j2 + (v3 + g3) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (g3 >>> 0 > 3) { + ta3 = 32; + break; + } + if ((c[K3 >> 2] | 0) >>> 0 < (c[L3 >> 2] | 0) >>> 7 >>> 0) h2 = 0; + else { + w2 = 0; + h2 = 0; + v3 = (_(d[x3 >> 0] | d[x3 + 1 >> 0] << 8 | d[x3 + 2 >> 0] << 16 | d[x3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((w2 | 0) == 1) break; + x3 = b2[21084 + (v3 << 1) >> 1] | 0; + f2 = x3 & 65535; + c[L3 >> 2] = (c[L3 >> 2] | 0) + 1; + if (x3 << 16 >> 16 != 0 ? (ia3 = f2 & 31, ja3 = f2 >>> 5, ka3 = (c[11272 + (ia3 << 2) >> 2] | 0) + (_(ia3, ja3) | 0) | 0, ia3 >>> 0 <= D3 >>> 0) : 0) { + g3 = ka3 + ia3 | 0; + u3 = 280811 + g3 | 0; + g3 = 280811 + (g3 + -4) | 0; + t3 = 0; + f2 = 280811 + ka3 | 0; + while (1) { + if (f2 >>> 0 > g3 >>> 0) break; + x3 = j2 + (A3 + t3) | 0; + if ((d[f2 >> 0] | d[f2 + 1 >> 0] << 8 | d[f2 + 2 >> 0] << 16 | d[f2 + 3 >> 0] << 24 | 0) != (d[x3 >> 0] | d[x3 + 1 >> 0] << 8 | d[x3 + 2 >> 0] << 16 | d[x3 + 3 >> 0] << 24 | 0)) break; + t3 = t3 + 4 | 0; + f2 = f2 + 4 | 0; + } + while (1) { + if (f2 >>> 0 >= u3 >>> 0) break; + if ((a[j2 + (A3 + t3) >> 0] | 0) != (a[f2 >> 0] | 0)) break; + t3 = t3 + 1 | 0; + f2 = f2 + 1 | 0; + } + if (!((t3 + 10 | 0) >>> 0 <= ia3 >>> 0 | (t3 | 0) == 0) ? (la3 = z3 + ja3 + 1 + (d[407930 + (ia3 - t3) >> 0] << d[280786 + ia3 >> 0]) | 0, ma3 = (t3 * 540 | 0) + 3840 + (_((aa(la3 | 0) | 0) ^ 31, -120) | 0) | 0, ma3 >>> 0 >= (c[M2 >> 2] | 0) >>> 0) : 0) { + c[ea3 >> 2] = t3; + c[J3 >> 2] = ia3 ^ t3; + c[N3 >> 2] = la3; + c[M2 >> 2] = ma3; + c[K3 >> 2] = (c[K3 >> 2] | 0) + 1; + h2 = 1; + } + } + w2 = w2 + 1 | 0; + v3 = v3 + 1 | 0; + } + h2 = (h2 & 1) != 0; + } + c[y3 >> 2] = l2; + if (h2 & 1) { + E3 = 0; + break; + } + } + e2 = e2 + 1 | 0; + f2 = l2 + 1 | 0; + if (f2 >>> 0 <= s2 >>> 0) { + l2 = f2; + continue; + } + if (f2 >>> 0 > E3 >>> 0) { + h2 = l2 + 17 | 0; + h2 = h2 >>> 0 < P3 >>> 0 ? h2 : P3; + l2 = f2; + while (1) { + if (l2 >>> 0 >= h2 >>> 0) continue b; + D3 = j2 + (l2 & k2) | 0; + A3 = D3; + D3 = D3 + 4 | 0; + D3 = lc(d[A3 >> 0] | d[A3 + 1 >> 0] << 8 | d[A3 + 2 >> 0] << 16 | d[A3 + 3 >> 0] << 24 | 0, d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + D3 = bc(D3 | 0, C2 | 0, 48) | 0; + c[m3 + (D3 << 2) >> 2] = l2; + l2 = l2 + 4 | 0; + e2 = e2 + 4 | 0; + } + } else { + h2 = l2 + 9 | 0; + h2 = h2 >>> 0 < P3 >>> 0 ? h2 : P3; + l2 = f2; + while (1) { + if (l2 >>> 0 >= h2 >>> 0) continue b; + D3 = j2 + (l2 & k2) | 0; + A3 = D3; + D3 = D3 + 4 | 0; + D3 = lc(d[A3 >> 0] | d[A3 + 1 >> 0] << 8 | d[A3 + 2 >> 0] << 16 | d[A3 + 3 >> 0] << 24 | 0, d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + D3 = bc(D3 | 0, C2 | 0, 48) | 0; + c[m3 + (D3 << 2) >> 2] = l2; + l2 = l2 + 2 | 0; + e2 = e2 + 2 | 0; + } + } + } + if ((ta3 | 0) == 22) { + ta3 = 0; + c[ea3 >> 2] = g3; + c[N3 >> 2] = v3; + c[M2 >> 2] = (g3 * 540 | 0) + 3900; + c[m3 + (u3 << 2) >> 2] = l2; + E3 = 0; + } else if ((ta3 | 0) == 32) { + ta3 = 0; + c[ea3 >> 2] = g3; + c[N3 >> 2] = u3; + c[M2 >> 2] = (g3 * 540 | 0) + 3840 + (_((aa(u3 | 0) | 0) ^ 31, -120) | 0); + E3 = 0; + } + c: while (1) { + D3 = D3 + -1 | 0; + if ((c[$2 >> 2] | 0) < 5) { + v3 = (c[ea3 >> 2] | 0) + -1 | 0; + v3 = v3 >>> 0 < D3 >>> 0 ? v3 : D3; + } else v3 = 0; + c[fa3 >> 2] = v3; + c[Q3 >> 2] = 0; + c[R3 >> 2] = 0; + c[S3 >> 2] = 4240; + x3 = l2 + 1 | 0; + A3 = x3 >>> 0 < ca3 >>> 0 ? x3 : ca3; + B3 = x3 & k2; + y3 = j2 + B3 | 0; + t3 = y3; + w2 = t3; + t3 = t3 + 4 | 0; + t3 = lc(d[w2 >> 0] | d[w2 + 1 >> 0] << 8 | d[w2 + 2 >> 0] << 16 | d[w2 + 3 >> 0] << 24 | 0, d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + t3 = bc(t3 | 0, C2 | 0, 48) | 0; + w2 = a[j2 + (B3 + v3) >> 0] | 0; + u3 = c[n2 >> 2] | 0; + h2 = x3 - u3 | 0; + c[T3 >> 2] = 0; + if (h2 >>> 0 < x3 >>> 0 ? (na2 = h2 & k2, w2 << 24 >> 24 == (a[j2 + (na2 + v3) >> 0] | 0)) : 0) { + f2 = B3 + D3 | 0; + g3 = j2 + f2 | 0; + f2 = j2 + (f2 + -4) | 0; + s2 = 0; + h2 = y3; + while (1) { + if (h2 >>> 0 > f2 >>> 0) break; + z3 = j2 + (na2 + s2) | 0; + if ((d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0) != (d[z3 >> 0] | d[z3 + 1 >> 0] << 8 | d[z3 + 2 >> 0] << 16 | d[z3 + 3 >> 0] << 24 | 0)) break; + s2 = s2 + 4 | 0; + h2 = h2 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= g3 >>> 0) break; + if ((a[j2 + (na2 + s2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + s2 = s2 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (s2 >>> 0 > 3) { + c[fa3 >> 2] = s2; + c[U3 >> 2] = u3; + c[V3 >> 2] = (s2 * 540 | 0) + 3900; + c[m3 + (t3 << 2) >> 2] = x3; + } else ta3 = 64; + } else ta3 = 64; + do + if ((ta3 | 0) == 64) { + ta3 = 0; + z3 = m3 + (t3 << 2) | 0; + g3 = c[z3 >> 2] | 0; + c[z3 >> 2] = x3; + t3 = x3 - g3 | 0; + u3 = g3 & k2; + if (((x3 | 0) == (g3 | 0) ? 1 : w2 << 24 >> 24 != (a[j2 + (u3 + v3) >> 0] | 0)) | t3 >>> 0 > A3 >>> 0) { + x3 = l2; + w2 = e2; + break c; + } + f2 = B3 + D3 | 0; + g3 = j2 + f2 | 0; + f2 = j2 + (f2 + -4) | 0; + s2 = 0; + h2 = y3; + while (1) { + if (h2 >>> 0 > f2 >>> 0) break; + w2 = j2 + (u3 + s2) | 0; + if ((d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0) != (d[w2 >> 0] | d[w2 + 1 >> 0] << 8 | d[w2 + 2 >> 0] << 16 | d[w2 + 3 >> 0] << 24 | 0)) break; + s2 = s2 + 4 | 0; + h2 = h2 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= g3 >>> 0) break; + if ((a[j2 + (u3 + s2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + s2 = s2 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (s2 >>> 0 > 3) { + c[fa3 >> 2] = s2; + c[U3 >> 2] = t3; + c[V3 >> 2] = (s2 * 540 | 0) + 3840 + (_((aa(t3 | 0) | 0) ^ 31, -120) | 0); + break; + } + if ((c[K3 >> 2] | 0) >>> 0 < (c[L3 >> 2] | 0) >>> 7 >>> 0) h2 = 0; + else { + v3 = 0; + h2 = 0; + u3 = (_(d[y3 >> 0] | d[y3 + 1 >> 0] << 8 | d[y3 + 2 >> 0] << 16 | d[y3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 1) break; + y3 = b2[21084 + (u3 << 1) >> 1] | 0; + f2 = y3 & 65535; + c[L3 >> 2] = (c[L3 >> 2] | 0) + 1; + if (y3 << 16 >> 16 != 0 ? (oa3 = f2 & 31, pa3 = f2 >>> 5, qa3 = (c[11272 + (oa3 << 2) >> 2] | 0) + (_(oa3, pa3) | 0) | 0, oa3 >>> 0 <= D3 >>> 0) : 0) { + s2 = qa3 + oa3 | 0; + t3 = 280811 + s2 | 0; + s2 = 280811 + (s2 + -4) | 0; + g3 = 0; + f2 = 280811 + qa3 | 0; + while (1) { + if (f2 >>> 0 > s2 >>> 0) break; + y3 = j2 + (B3 + g3) | 0; + if ((d[f2 >> 0] | d[f2 + 1 >> 0] << 8 | d[f2 + 2 >> 0] << 16 | d[f2 + 3 >> 0] << 24 | 0) != (d[y3 >> 0] | d[y3 + 1 >> 0] << 8 | d[y3 + 2 >> 0] << 16 | d[y3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + f2 = f2 + 4 | 0; + } + while (1) { + if (f2 >>> 0 >= t3 >>> 0) break; + if ((a[j2 + (B3 + g3) >> 0] | 0) != (a[f2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + f2 = f2 + 1 | 0; + } + if (!((g3 + 10 | 0) >>> 0 <= oa3 >>> 0 | (g3 | 0) == 0) ? (ra3 = A3 + pa3 + 1 + (d[407930 + (oa3 - g3) >> 0] << d[280786 + oa3 >> 0]) | 0, sa3 = (g3 * 540 | 0) + 3840 + (_((aa(ra3 | 0) | 0) ^ 31, -120) | 0) | 0, sa3 >>> 0 >= (c[V3 >> 2] | 0) >>> 0) : 0) { + c[fa3 >> 2] = g3; + c[T3 >> 2] = oa3 ^ g3; + c[U3 >> 2] = ra3; + c[V3 >> 2] = sa3; + c[K3 >> 2] = (c[K3 >> 2] | 0) + 1; + h2 = 1; + } + } + v3 = v3 + 1 | 0; + u3 = u3 + 1 | 0; + } + h2 = (h2 & 1) != 0; + } + c[z3 >> 2] = x3; + if (!(h2 & 1)) { + x3 = l2; + w2 = e2; + break c; + } + } + while (0); + if ((c[S3 >> 2] | 0) >>> 0 < ((c[I3 >> 2] | 0) + 700 | 0) >>> 0) { + x3 = l2; + w2 = e2; + break; + } + e2 = e2 + 1 | 0; + c[ea3 >> 2] = c[fa3 >> 2]; + c[ea3 + 4 >> 2] = c[fa3 + 4 >> 2]; + c[ea3 + 8 >> 2] = c[fa3 + 8 >> 2]; + c[ea3 + 12 >> 2] = c[fa3 + 12 >> 2]; + E3 = E3 + 1 | 0; + if (!((E3 | 0) < 4 & (l2 + 9 | 0) >>> 0 < da3 >>> 0)) { + w2 = e2; + break; + } else l2 = x3; + } + l2 = c[ea3 >> 2] | 0; + s2 = x3 + (l2 << 1) + Z3 | 0; + e2 = c[H3 >> 2] | 0; + d: do + if (e2 >>> 0 <= (x3 >>> 0 < ca3 >>> 0 ? x3 : ca3) >>> 0) { + g3 = e2 + 3 | 0; + E3 = c[n2 >> 2] | 0; + h2 = g3 - E3 | 0; + f2 = c[Y3 >> 2] | 0; + g3 = g3 - f2 | 0; + if ((e2 | 0) == (E3 | 0)) e2 = 0; + else { + e: do + if ((e2 | 0) != (f2 | 0)) { + do + if (h2 >>> 0 < 7) e2 = 158663784 >>> (h2 << 2) & 15; + else { + if (g3 >>> 0 < 7) { + e2 = 266017486 >>> (g3 << 2) & 15; + break; + } + if ((e2 | 0) == (c[W3 >> 2] | 0)) { + e2 = 2; + break e; + } + if ((e2 | 0) == (c[X3 >> 2] | 0)) { + e2 = 3; + break e; + } + e2 = e2 + 15 | 0; + } + while (0); + if (!e2) break d; + } else e2 = 1; + while (0); + c[X3 >> 2] = c[W3 >> 2]; + c[W3 >> 2] = c[Y3 >> 2]; + c[Y3 >> 2] = c[n2 >> 2]; + c[n2 >> 2] = c[H3 >> 2]; + l2 = c[ea3 >> 2] | 0; + } + } else e2 = e2 + 15 | 0; + while (0); + v3 = F3 + 16 | 0; + E3 = c[G3 >> 2] | 0; + h2 = l2 ^ E3; + c[F3 >> 2] = w2; + c[F3 + 4 >> 2] = l2 | E3 << 24; + l2 = F3 + 14 | 0; + if (e2 >>> 0 < 16) { + e2 = e2 & 65535; + b2[l2 >> 1] = e2; + l2 = 0; + } else { + B3 = e2 + -12 | 0; + E3 = ((aa(B3 | 0) | 0) ^ 31) + -1 | 0; + D3 = B3 >>> E3 & 1; + e2 = ((E3 << 1) + 65534 | D3) + 16 & 65535; + b2[l2 >> 1] = e2; + l2 = E3 << 24 | B3 - ((D3 | 2) << E3); + } + c[F3 + 8 >> 2] = l2; + t3 = e2 << 16 >> 16 == 0; + u3 = F3 + 12 | 0; + do + if (w2 >>> 0 >= 6) { + if (w2 >>> 0 < 130) { + F3 = w2 + -2 | 0; + g3 = ((aa(F3 | 0) | 0) ^ 31) + -1 | 0; + g3 = (g3 << 1) + (F3 >>> g3) + 2 & 65535; + break; + } + if (w2 >>> 0 < 2114) { + g3 = ((aa(w2 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (w2 >>> 0 < 6210) g3 = 21; + else g3 = w2 >>> 0 < 22594 ? 22 : 23; + } else g3 = w2 & 65535; + while (0); + do + if (h2 >>> 0 >= 10) { + if (h2 >>> 0 < 134) { + F3 = h2 + -6 | 0; + e2 = ((aa(F3 | 0) | 0) ^ 31) + -1 | 0; + e2 = (e2 << 1) + (F3 >>> e2) + 4 & 65535; + break; + } + if (h2 >>> 0 < 2118) e2 = ((aa(h2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else e2 = 23; + } else e2 = h2 + 65534 & 65535; + while (0); + l2 = e2 & 65535; + h2 = g3 & 65535; + f2 = l2 & 7 | h2 << 3 & 56; + if (t3 & (g3 & 65535) < 8 & (e2 & 65535) < 16) e2 = ((e2 & 65535) < 8 ? f2 : f2 | 64) & 65535; + else e2 = b2[88156 + ((l2 >>> 3) + ((h2 >>> 3) * 3 | 0) << 1) >> 1] | f2 & 65535; + b2[u3 >> 1] = e2; + c[r2 >> 2] = (c[r2 >> 2] | 0) + w2; + e2 = x3 + (c[ea3 >> 2] | 0) | 0; + e2 = e2 >>> 0 < ba2 >>> 0 ? e2 : ba2; + l2 = x3 + 2 | 0; + while (1) { + if (l2 >>> 0 >= e2 >>> 0) break; + F3 = j2 + (l2 & k2) | 0; + E3 = F3; + F3 = F3 + 4 | 0; + F3 = lc(d[E3 >> 0] | d[E3 + 1 >> 0] << 8 | d[E3 + 2 >> 0] << 16 | d[E3 + 3 >> 0] << 24 | 0, d[F3 >> 0] | d[F3 + 1 >> 0] << 8 | d[F3 + 2 >> 0] << 16 | d[F3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + F3 = bc(F3 | 0, C2 | 0, 48) | 0; + c[m3 + (F3 << 2) >> 2] = l2; + l2 = l2 + 1 | 0; + } + l2 = x3 + (c[ea3 >> 2] | 0) | 0; + F3 = v3; + e2 = 0; + } + c[o2 >> 2] = e2 + D3; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (B3 - p2 >> 4); + i = ga3; + return; + } + function Ka2(e2, f2, g3, h2, i2, j2, k2, l2, m3, n2, o2, p2, q2) { + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + i2 = i2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + var r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0; + X3 = (1 << c[k2 + 8 >> 2]) + -16 | 0; + s2 = c[n2 >> 2] | 0; + Y3 = g3 + f2 | 0; + W3 = f2 >>> 0 > 7 ? Y3 + -7 | 0 : g3; + V3 = k2 + 4 | 0; + U3 = (c[V3 >> 2] | 0) < 9 ? 64 : 512; + k2 = U3 + g3 | 0; + if ((((g3 | 0) == 0 ^ 1 | h2 ^ 1) ^ 1) & f2 >>> 0 < 2049) { + e2 = 0; + while (1) { + if ((e2 | 0) == (f2 | 0)) break; + T3 = i2 + e2 | 0; + S3 = T3; + T3 = T3 + 4 | 0; + T3 = lc(d[S3 >> 0] | d[S3 + 1 >> 0] << 8 | d[S3 + 2 >> 0] << 16 | d[S3 + 3 >> 0] << 24 | 0, d[T3 >> 0] | d[T3 + 1 >> 0] << 8 | d[T3 + 2 >> 0] << 16 | d[T3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + T3 = bc(T3 | 0, C2 | 0, 48) | 0; + T3 = l2 + (T3 << 2) | 0; + c[T3 >> 2] = 0; + c[T3 + 4 >> 2] = 0; + e2 = e2 + 1 | 0; + } + if (f2) { + a[l2 + 262152 >> 0] = 0; + r2 = 8; + } + } else if (!(a[l2 + 262152 >> 0] & 1)) r2 = 8; + else { + ac(l2 | 0, 0, 262153) | 0; + r2 = 8; + } + if ((r2 | 0) == 8 ? f2 >>> 0 > 6 & g3 >>> 0 > 2 : 0) { + T3 = g3 + -3 | 0; + S3 = i2 + (T3 & j2) | 0; + R3 = S3; + S3 = S3 + 4 | 0; + S3 = lc(d[R3 >> 0] | d[R3 + 1 >> 0] << 8 | d[R3 + 2 >> 0] << 16 | d[R3 + 3 >> 0] << 24 | 0, d[S3 >> 0] | d[S3 + 1 >> 0] << 8 | d[S3 + 2 >> 0] << 16 | d[S3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + S3 = bc(S3 | 0, C2 | 0, 48) | 0; + c[l2 + (S3 + (T3 >>> 3 & 1) << 2) >> 2] = T3; + T3 = g3 + -2 | 0; + S3 = i2 + (T3 & j2) | 0; + R3 = S3; + S3 = S3 + 4 | 0; + S3 = lc(d[R3 >> 0] | d[R3 + 1 >> 0] << 8 | d[R3 + 2 >> 0] << 16 | d[R3 + 3 >> 0] << 24 | 0, d[S3 >> 0] | d[S3 + 1 >> 0] << 8 | d[S3 + 2 >> 0] << 16 | d[S3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + S3 = bc(S3 | 0, C2 | 0, 48) | 0; + c[l2 + (S3 + (T3 >>> 3 & 1) << 2) >> 2] = T3; + T3 = g3 + -1 | 0; + S3 = i2 + (T3 & j2) | 0; + R3 = S3; + S3 = S3 + 4 | 0; + S3 = lc(d[R3 >> 0] | d[R3 + 1 >> 0] << 8 | d[R3 + 2 >> 0] << 16 | d[R3 + 3 >> 0] << 24 | 0, d[S3 >> 0] | d[S3 + 1 >> 0] << 8 | d[S3 + 2 >> 0] << 16 | d[S3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + S3 = bc(S3 | 0, C2 | 0, 48) | 0; + c[l2 + (S3 + (T3 >>> 3 & 1) << 2) >> 2] = T3; + } + P3 = U3 << 2; + Q3 = Y3 + -7 | 0; + R3 = m3 + 8 | 0; + S3 = m3 + 12 | 0; + T3 = m3 + 4 | 0; + h2 = g3; + O3 = o2; + v3 = k2; + e2 = s2; + a: while (1) { + J3 = O3; + K3 = v3 + P3 | 0; + b: while (1) { + M2 = Y3 - h2 | 0; + if ((h2 + 8 | 0) >>> 0 >= Y3 >>> 0) break a; + F3 = h2 >>> 0 < X3 >>> 0 ? h2 : X3; + G3 = h2 & j2; + H3 = i2 + G3 | 0; + I3 = H3; + k2 = I3; + k2 = d[k2 >> 0] | d[k2 + 1 >> 0] << 8 | d[k2 + 2 >> 0] << 16 | d[k2 + 3 >> 0] << 24; + I3 = I3 + 4 | 0; + I3 = lc(k2 | 0, d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + I3 = bc(I3 | 0, C2 | 0, 48) | 0; + t3 = k2 & 255; + f2 = c[m3 >> 2] | 0; + r2 = h2 - f2 | 0; + if (r2 >>> 0 < h2 >>> 0 ? (Z3 = r2 & j2, (a[i2 + Z3 >> 0] | 0) == (k2 & 255) << 24 >> 24) : 0) { + r2 = G3 + M2 | 0; + s2 = i2 + r2 | 0; + r2 = i2 + (r2 + -4) | 0; + g3 = 0; + k2 = H3; + while (1) { + if (k2 >>> 0 > r2 >>> 0) break; + N3 = i2 + (Z3 + g3) | 0; + if ((d[k2 >> 0] | d[k2 + 1 >> 0] << 8 | d[k2 + 2 >> 0] << 16 | d[k2 + 3 >> 0] << 24 | 0) != (d[N3 >> 0] | d[N3 + 1 >> 0] << 8 | d[N3 + 2 >> 0] << 16 | d[N3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + k2 = k2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= s2 >>> 0) break; + if ((a[i2 + (Z3 + g3) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + k2 = k2 + 1 | 0; + } + if (g3 >>> 0 > 3) { + t3 = d[i2 + (G3 + g3) >> 0] | 0; + k2 = 1; + s2 = g3; + g3 = (g3 * 540 | 0) + 3900 | 0; + } else { + k2 = 0; + s2 = 0; + f2 = 0; + g3 = 4240; + } + } else { + k2 = 0; + s2 = 0; + f2 = 0; + g3 = 4240; + } + D3 = G3 + M2 | 0; + B3 = i2 + D3 | 0; + D3 = i2 + (D3 + -4) | 0; + x3 = s2; + u3 = g3; + E3 = l2 + (I3 + 1 << 2) | 0; + y3 = 0; + r2 = l2 + (I3 << 2) | 0; + z3 = s2; + A3 = g3; + while (1) { + r2 = c[r2 >> 2] | 0; + if ((y3 | 0) == 2) break; + w2 = h2 - r2 | 0; + s2 = r2 & j2; + if (!(((h2 | 0) == (r2 | 0) ? 1 : (t3 | 0) != (d[i2 + (s2 + x3) >> 0] | 0)) | w2 >>> 0 > F3 >>> 0)) { + r2 = 0; + g3 = H3; + while (1) { + if (g3 >>> 0 > D3 >>> 0) break; + N3 = i2 + (s2 + r2) | 0; + if ((d[g3 >> 0] | d[g3 + 1 >> 0] << 8 | d[g3 + 2 >> 0] << 16 | d[g3 + 3 >> 0] << 24 | 0) != (d[N3 >> 0] | d[N3 + 1 >> 0] << 8 | d[N3 + 2 >> 0] << 16 | d[N3 + 3 >> 0] << 24 | 0)) break; + r2 = r2 + 4 | 0; + g3 = g3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= B3 >>> 0) break; + if ((a[i2 + (s2 + r2) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + r2 = r2 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (r2 >>> 0 > 3 ? ($2 = (r2 * 540 | 0) + 3840 + (_((aa(w2 | 0) | 0) ^ 31, -120) | 0) | 0, u3 >>> 0 < $2 >>> 0) : 0) { + s2 = r2; + u3 = $2; + t3 = d[i2 + (G3 + r2) >> 0] | 0; + k2 = 1; + g3 = r2; + f2 = w2; + r2 = $2; + } else { + s2 = x3; + g3 = z3; + r2 = A3; + } + } else { + s2 = x3; + g3 = z3; + r2 = A3; + } + N3 = E3; + x3 = s2; + E3 = E3 + 4 | 0; + y3 = y3 + 1 | 0; + z3 = g3; + A3 = r2; + r2 = N3; + } + c[l2 + (I3 + (h2 >>> 3 & 1) << 2) >> 2] = h2; + if (k2 & 1) { + N3 = 0; + break; + } + e2 = e2 + 1 | 0; + f2 = h2 + 1 | 0; + if (f2 >>> 0 <= v3 >>> 0) { + h2 = f2; + continue; + } + if (f2 >>> 0 > K3 >>> 0) { + k2 = h2 + 17 | 0; + k2 = k2 >>> 0 < Q3 >>> 0 ? k2 : Q3; + h2 = f2; + while (1) { + if (h2 >>> 0 >= k2 >>> 0) continue b; + N3 = i2 + (h2 & j2) | 0; + M2 = N3; + N3 = N3 + 4 | 0; + N3 = lc(d[M2 >> 0] | d[M2 + 1 >> 0] << 8 | d[M2 + 2 >> 0] << 16 | d[M2 + 3 >> 0] << 24 | 0, d[N3 >> 0] | d[N3 + 1 >> 0] << 8 | d[N3 + 2 >> 0] << 16 | d[N3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + N3 = bc(N3 | 0, C2 | 0, 48) | 0; + c[l2 + (N3 + (h2 >>> 3 & 1) << 2) >> 2] = h2; + h2 = h2 + 4 | 0; + e2 = e2 + 4 | 0; + } + } else { + k2 = h2 + 9 | 0; + k2 = k2 >>> 0 < Q3 >>> 0 ? k2 : Q3; + h2 = f2; + while (1) { + if (h2 >>> 0 >= k2 >>> 0) continue b; + N3 = i2 + (h2 & j2) | 0; + M2 = N3; + N3 = N3 + 4 | 0; + N3 = lc(d[M2 >> 0] | d[M2 + 1 >> 0] << 8 | d[M2 + 2 >> 0] << 16 | d[M2 + 3 >> 0] << 24 | 0, d[N3 >> 0] | d[N3 + 1 >> 0] << 8 | d[N3 + 2 >> 0] << 16 | d[N3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + N3 = bc(N3 | 0, C2 | 0, 48) | 0; + c[l2 + (N3 + (h2 >>> 3 & 1) << 2) >> 2] = h2; + h2 = h2 + 2 | 0; + e2 = e2 + 2 | 0; + } + } + } + while (1) { + M2 = M2 + -1 | 0; + if ((c[V3 >> 2] | 0) < 5) { + u3 = z3 + -1 | 0; + u3 = u3 >>> 0 < M2 >>> 0 ? u3 : M2; + } else u3 = 0; + x3 = h2 + 1 | 0; + I3 = x3 >>> 0 < X3 >>> 0 ? x3 : X3; + J3 = x3 & j2; + K3 = i2 + J3 | 0; + L3 = K3; + k2 = L3; + L3 = L3 + 4 | 0; + L3 = lc(d[k2 >> 0] | d[k2 + 1 >> 0] << 8 | d[k2 + 2 >> 0] << 16 | d[k2 + 3 >> 0] << 24 | 0, d[L3 >> 0] | d[L3 + 1 >> 0] << 8 | d[L3 + 2 >> 0] << 16 | d[L3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + L3 = bc(L3 | 0, C2 | 0, 48) | 0; + k2 = a[i2 + (J3 + u3) >> 0] | 0; + t3 = k2 & 255; + v3 = c[m3 >> 2] | 0; + r2 = x3 - v3 | 0; + if (r2 >>> 0 < x3 >>> 0 ? (ba2 = r2 & j2, k2 << 24 >> 24 == (a[i2 + (ba2 + u3) >> 0] | 0)) : 0) { + r2 = J3 + M2 | 0; + s2 = i2 + r2 | 0; + r2 = i2 + (r2 + -4) | 0; + g3 = 0; + k2 = K3; + while (1) { + if (k2 >>> 0 > r2 >>> 0) break; + H3 = i2 + (ba2 + g3) | 0; + if ((d[k2 >> 0] | d[k2 + 1 >> 0] << 8 | d[k2 + 2 >> 0] << 16 | d[k2 + 3 >> 0] << 24 | 0) != (d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + k2 = k2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= s2 >>> 0) break; + if ((a[i2 + (ba2 + g3) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + k2 = k2 + 1 | 0; + } + if (g3 >>> 0 > 3) { + t3 = d[i2 + (J3 + g3) >> 0] | 0; + k2 = 1; + u3 = g3; + r2 = (g3 * 540 | 0) + 3900 | 0; + } else { + k2 = 0; + r2 = 4240; + v3 = 0; + } + } else { + k2 = 0; + r2 = 4240; + v3 = 0; + } + G3 = J3 + M2 | 0; + F3 = i2 + G3 | 0; + G3 = i2 + (G3 + -4) | 0; + B3 = u3; + D3 = r2; + H3 = l2 + (L3 + 1 << 2) | 0; + E3 = 0; + s2 = k2; + k2 = l2 + (L3 << 2) | 0; + y3 = r2; + while (1) { + k2 = c[k2 >> 2] | 0; + if ((E3 | 0) == 2) break; + w2 = x3 - k2 | 0; + g3 = k2 & j2; + if (!(((x3 | 0) == (k2 | 0) ? 1 : (t3 | 0) != (d[i2 + (g3 + B3) >> 0] | 0)) | w2 >>> 0 > I3 >>> 0)) { + k2 = 0; + r2 = K3; + while (1) { + if (r2 >>> 0 > G3 >>> 0) break; + da3 = i2 + (g3 + k2) | 0; + if ((d[r2 >> 0] | d[r2 + 1 >> 0] << 8 | d[r2 + 2 >> 0] << 16 | d[r2 + 3 >> 0] << 24 | 0) != (d[da3 >> 0] | d[da3 + 1 >> 0] << 8 | d[da3 + 2 >> 0] << 16 | d[da3 + 3 >> 0] << 24 | 0)) break; + k2 = k2 + 4 | 0; + r2 = r2 + 4 | 0; + } + while (1) { + if (r2 >>> 0 >= F3 >>> 0) break; + if ((a[i2 + (g3 + k2) >> 0] | 0) != (a[r2 >> 0] | 0)) break; + k2 = k2 + 1 | 0; + r2 = r2 + 1 | 0; + } + if (k2 >>> 0 > 3 ? (ca3 = (k2 * 540 | 0) + 3840 + (_((aa(w2 | 0) | 0) ^ 31, -120) | 0) | 0, D3 >>> 0 < ca3 >>> 0) : 0) { + r2 = k2; + g3 = ca3; + t3 = d[i2 + (J3 + k2) >> 0] | 0; + s2 = 1; + u3 = k2; + k2 = ca3; + v3 = w2; + } else { + r2 = B3; + g3 = D3; + k2 = y3; + } + } else { + r2 = B3; + g3 = D3; + k2 = y3; + } + da3 = H3; + B3 = r2; + D3 = g3; + H3 = H3 + 4 | 0; + E3 = E3 + 1 | 0; + y3 = k2; + k2 = da3; + } + c[l2 + (L3 + (x3 >>> 3 & 1) << 2) >> 2] = x3; + if ((s2 & 1) == 0 | y3 >>> 0 < (A3 + 700 | 0) >>> 0) { + x3 = h2; + w2 = e2; + u3 = z3; + break; + } + e2 = e2 + 1 | 0; + N3 = N3 + 1 | 0; + if (!((N3 | 0) < 4 & (h2 + 9 | 0) >>> 0 < Y3 >>> 0)) { + w2 = e2; + f2 = v3; + break; + } else { + h2 = x3; + z3 = u3; + f2 = v3; + A3 = y3; + } + } + v3 = x3 + (u3 << 1) + U3 | 0; + c: do + if (f2 >>> 0 <= (x3 >>> 0 < X3 >>> 0 ? x3 : X3) >>> 0) { + h2 = f2 + 3 | 0; + da3 = c[m3 >> 2] | 0; + e2 = h2 - da3 | 0; + k2 = c[T3 >> 2] | 0; + h2 = h2 - k2 | 0; + if ((f2 | 0) == (da3 | 0)) e2 = 0; + else { + d: do + if ((f2 | 0) != (k2 | 0)) { + do + if (e2 >>> 0 < 7) e2 = 158663784 >>> (e2 << 2) & 15; + else { + if (h2 >>> 0 < 7) { + e2 = 266017486 >>> (h2 << 2) & 15; + break; + } + if ((f2 | 0) == (c[R3 >> 2] | 0)) { + e2 = 2; + break d; + } + if ((f2 | 0) == (c[S3 >> 2] | 0)) { + e2 = 3; + break d; + } + e2 = f2 + 15 | 0; + } + while (0); + if (!e2) break c; + } else e2 = 1; + while (0); + c[S3 >> 2] = c[R3 >> 2]; + c[R3 >> 2] = c[T3 >> 2]; + c[T3 >> 2] = c[m3 >> 2]; + c[m3 >> 2] = f2; + } + } else e2 = f2 + 15 | 0; + while (0); + t3 = O3 + 16 | 0; + c[O3 >> 2] = w2; + c[O3 + 4 >> 2] = u3; + k2 = O3 + 14 | 0; + if (e2 >>> 0 < 16) { + e2 = e2 & 65535; + b2[k2 >> 1] = e2; + k2 = 0; + } else { + M2 = e2 + -12 | 0; + da3 = ((aa(M2 | 0) | 0) ^ 31) + -1 | 0; + N3 = M2 >>> da3 & 1; + e2 = ((da3 << 1) + 65534 | N3) + 16 & 65535; + b2[k2 >> 1] = e2; + k2 = da3 << 24 | M2 - ((N3 | 2) << da3); + } + c[O3 + 8 >> 2] = k2; + g3 = e2 << 16 >> 16 == 0; + s2 = O3 + 12 | 0; + do + if (w2 >>> 0 >= 6) { + if (w2 >>> 0 < 130) { + da3 = w2 + -2 | 0; + k2 = ((aa(da3 | 0) | 0) ^ 31) + -1 | 0; + k2 = (k2 << 1) + (da3 >>> k2) + 2 & 65535; + break; + } + if (w2 >>> 0 < 2114) { + k2 = ((aa(w2 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (w2 >>> 0 < 6210) k2 = 21; + else k2 = w2 >>> 0 < 22594 ? 22 : 23; + } else k2 = w2 & 65535; + while (0); + do + if (u3 >>> 0 >= 10) { + if (u3 >>> 0 < 134) { + da3 = u3 + -6 | 0; + e2 = ((aa(da3 | 0) | 0) ^ 31) + -1 | 0; + e2 = (e2 << 1) + (da3 >>> e2) + 4 & 65535; + break; + } + if (u3 >>> 0 < 2118) e2 = ((aa(u3 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else e2 = 23; + } else e2 = u3 + 65534 & 65535; + while (0); + h2 = e2 & 65535; + f2 = k2 & 65535; + r2 = h2 & 7 | f2 << 3 & 56; + if (g3 & (k2 & 65535) < 8 & (e2 & 65535) < 16) e2 = ((e2 & 65535) < 8 ? r2 : r2 | 64) & 65535; + else e2 = b2[88156 + ((h2 >>> 3) + ((f2 >>> 3) * 3 | 0) << 1) >> 1] | r2 & 65535; + b2[s2 >> 1] = e2; + c[q2 >> 2] = (c[q2 >> 2] | 0) + w2; + h2 = x3 + u3 | 0; + k2 = h2 >>> 0 < W3 >>> 0 ? h2 : W3; + e2 = x3 + 2 | 0; + while (1) { + if (e2 >>> 0 >= k2 >>> 0) { + O3 = t3; + e2 = 0; + continue a; + } + da3 = i2 + (e2 & j2) | 0; + O3 = da3; + da3 = da3 + 4 | 0; + da3 = lc(d[O3 >> 0] | d[O3 + 1 >> 0] << 8 | d[O3 + 2 >> 0] << 16 | d[O3 + 3 >> 0] << 24 | 0, d[da3 >> 0] | d[da3 + 1 >> 0] << 8 | d[da3 + 2 >> 0] << 16 | d[da3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + da3 = bc(da3 | 0, C2 | 0, 48) | 0; + c[l2 + (da3 + (e2 >>> 3 & 1) << 2) >> 2] = e2; + e2 = e2 + 1 | 0; + } + } + c[n2 >> 2] = e2 + M2; + c[p2 >> 2] = (c[p2 >> 2] | 0) + (J3 - o2 >> 4); + return; + } + function La2(e2, f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2) { + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + var s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0; + la3 = i; + i = i + 32 | 0; + ja3 = la3 + 16 | 0; + ka3 = la3; + ha3 = (1 << c[l2 + 8 >> 2]) + -16 | 0; + u3 = c[o2 >> 2] | 0; + ia3 = g3 + f2 | 0; + ga3 = f2 >>> 0 > 7 ? ia3 + -7 | 0 : g3; + fa3 = l2 + 4 | 0; + ea3 = (c[fa3 >> 2] | 0) < 9 ? 64 : 512; + t3 = ea3 + g3 | 0; + if ((((g3 | 0) == 0 ^ 1 | h2 ^ 1) ^ 1) & f2 >>> 0 < 4097) { + e2 = 0; + while (1) { + if ((e2 | 0) == (f2 | 0)) break; + da3 = j2 + e2 | 0; + ca3 = da3; + da3 = da3 + 4 | 0; + da3 = lc(d[ca3 >> 0] | d[ca3 + 1 >> 0] << 8 | d[ca3 + 2 >> 0] << 16 | d[ca3 + 3 >> 0] << 24 | 0, d[da3 >> 0] | d[da3 + 1 >> 0] << 8 | d[da3 + 2 >> 0] << 16 | d[da3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + da3 = bc(da3 | 0, C2 | 0, 47) | 0; + da3 = m3 + (da3 << 2) | 0; + c[da3 >> 2] = 0; + c[da3 + 4 >> 2] = 0; + c[da3 + 8 >> 2] = 0; + c[da3 + 12 >> 2] = 0; + e2 = e2 + 1 | 0; + } + if (f2) { + a[m3 + 524304 >> 0] = 0; + s2 = 8; + } + } else if (!(a[m3 + 524304 >> 0] & 1)) s2 = 8; + else { + ac(m3 | 0, 0, 524305) | 0; + s2 = 8; + } + if ((s2 | 0) == 8 ? f2 >>> 0 > 6 & g3 >>> 0 > 2 : 0) { + da3 = g3 + -3 | 0; + ca3 = j2 + (da3 & k2) | 0; + ba2 = ca3; + ca3 = ca3 + 4 | 0; + ca3 = lc(d[ba2 >> 0] | d[ba2 + 1 >> 0] << 8 | d[ba2 + 2 >> 0] << 16 | d[ba2 + 3 >> 0] << 24 | 0, d[ca3 >> 0] | d[ca3 + 1 >> 0] << 8 | d[ca3 + 2 >> 0] << 16 | d[ca3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + ca3 = bc(ca3 | 0, C2 | 0, 47) | 0; + c[m3 + (ca3 + (da3 >>> 3 & 3) << 2) >> 2] = da3; + da3 = g3 + -2 | 0; + ca3 = j2 + (da3 & k2) | 0; + ba2 = ca3; + ca3 = ca3 + 4 | 0; + ca3 = lc(d[ba2 >> 0] | d[ba2 + 1 >> 0] << 8 | d[ba2 + 2 >> 0] << 16 | d[ba2 + 3 >> 0] << 24 | 0, d[ca3 >> 0] | d[ca3 + 1 >> 0] << 8 | d[ca3 + 2 >> 0] << 16 | d[ca3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + ca3 = bc(ca3 | 0, C2 | 0, 47) | 0; + c[m3 + (ca3 + (da3 >>> 3 & 3) << 2) >> 2] = da3; + da3 = g3 + -1 | 0; + ca3 = j2 + (da3 & k2) | 0; + ba2 = ca3; + ca3 = ca3 + 4 | 0; + ca3 = lc(d[ba2 >> 0] | d[ba2 + 1 >> 0] << 8 | d[ba2 + 2 >> 0] << 16 | d[ba2 + 3 >> 0] << 24 | 0, d[ca3 >> 0] | d[ca3 + 1 >> 0] << 8 | d[ca3 + 2 >> 0] << 16 | d[ca3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + ca3 = bc(ca3 | 0, C2 | 0, 47) | 0; + c[m3 + (ca3 + (da3 >>> 3 & 3) << 2) >> 2] = da3; + } + R3 = ja3 + 4 | 0; + S3 = ja3 + 8 | 0; + T3 = ja3 + 12 | 0; + U3 = ja3 + 12 | 0; + V3 = ja3 + 4 | 0; + W3 = ja3 + 8 | 0; + X3 = m3 + 524312 | 0; + Y3 = m3 + 524308 | 0; + Z3 = ea3 << 2; + $2 = ia3 + -7 | 0; + ba2 = ka3 + 12 | 0; + ca3 = ka3 + 4 | 0; + da3 = ka3 + 8 | 0; + L3 = ka3 + 12 | 0; + M2 = ka3 + 4 | 0; + N3 = ka3 + 8 | 0; + O3 = n2 + 8 | 0; + P3 = n2 + 12 | 0; + Q3 = n2 + 4 | 0; + l2 = g3; + K3 = p2; + e2 = u3; + a: while (1) { + I3 = K3; + J3 = t3 + Z3 | 0; + b: while (1) { + H3 = ia3 - l2 | 0; + if ((l2 + 8 | 0) >>> 0 >= ia3 >>> 0) break a; + E3 = l2 >>> 0 < ha3 >>> 0 ? l2 : ha3; + c[ja3 >> 2] = 0; + c[R3 >> 2] = 0; + c[S3 >> 2] = 0; + c[T3 >> 2] = 4240; + F3 = l2 & k2; + D3 = j2 + F3 | 0; + G3 = D3; + h2 = G3; + h2 = d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24; + G3 = G3 + 4 | 0; + G3 = lc(h2 | 0, d[G3 >> 0] | d[G3 + 1 >> 0] << 8 | d[G3 + 2 >> 0] << 16 | d[G3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + G3 = bc(G3 | 0, C2 | 0, 47) | 0; + w2 = h2 & 255; + v3 = c[U3 >> 2] | 0; + u3 = c[n2 >> 2] | 0; + f2 = l2 - u3 | 0; + c[V3 >> 2] = 0; + if (f2 >>> 0 < l2 >>> 0 ? (ma3 = f2 & k2, (a[j2 + ma3 >> 0] | 0) == (h2 & 255) << 24 >> 24) : 0) { + f2 = F3 + H3 | 0; + g3 = j2 + f2 | 0; + f2 = j2 + (f2 + -4) | 0; + s2 = 0; + h2 = D3; + while (1) { + if (h2 >>> 0 > f2 >>> 0) break; + B3 = j2 + (ma3 + s2) | 0; + if ((d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0) != (d[B3 >> 0] | d[B3 + 1 >> 0] << 8 | d[B3 + 2 >> 0] << 16 | d[B3 + 3 >> 0] << 24 | 0)) break; + s2 = s2 + 4 | 0; + h2 = h2 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= g3 >>> 0) break; + if ((a[j2 + (ma3 + s2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + s2 = s2 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (s2 >>> 0 > 3) { + g3 = (s2 * 540 | 0) + 3900 | 0; + c[ja3 >> 2] = s2; + c[W3 >> 2] = u3; + c[U3 >> 2] = g3; + f2 = s2; + s2 = d[j2 + (F3 + s2) >> 0] | 0; + h2 = 1; + } else { + f2 = 0; + g3 = v3; + s2 = w2; + h2 = 0; + } + } else { + f2 = 0; + g3 = v3; + s2 = w2; + h2 = 0; + } + B3 = F3 + H3 | 0; + A3 = j2 + B3 | 0; + B3 = j2 + (B3 + -4) | 0; + z3 = m3 + (G3 + 1 << 2) | 0; + y3 = 0; + u3 = m3 + (G3 << 2) | 0; + while (1) { + u3 = c[u3 >> 2] | 0; + if ((y3 | 0) == 4) break; + w2 = l2 - u3 | 0; + x3 = u3 & k2; + if (!(((l2 | 0) == (u3 | 0) ? 1 : (s2 | 0) != (d[j2 + (x3 + f2) >> 0] | 0)) | w2 >>> 0 > E3 >>> 0)) { + u3 = 0; + v3 = D3; + while (1) { + if (v3 >>> 0 > B3 >>> 0) break; + Aa3 = j2 + (x3 + u3) | 0; + if ((d[v3 >> 0] | d[v3 + 1 >> 0] << 8 | d[v3 + 2 >> 0] << 16 | d[v3 + 3 >> 0] << 24 | 0) != (d[Aa3 >> 0] | d[Aa3 + 1 >> 0] << 8 | d[Aa3 + 2 >> 0] << 16 | d[Aa3 + 3 >> 0] << 24 | 0)) break; + u3 = u3 + 4 | 0; + v3 = v3 + 4 | 0; + } + while (1) { + if (v3 >>> 0 >= A3 >>> 0) break; + if ((a[j2 + (x3 + u3) >> 0] | 0) != (a[v3 >> 0] | 0)) break; + u3 = u3 + 1 | 0; + v3 = v3 + 1 | 0; + } + if (u3 >>> 0 > 3 ? (na2 = (u3 * 540 | 0) + 3840 + (_((aa(w2 | 0) | 0) ^ 31, -120) | 0) | 0, g3 >>> 0 < na2 >>> 0) : 0) { + c[ja3 >> 2] = u3; + c[W3 >> 2] = w2; + c[U3 >> 2] = na2; + f2 = u3; + g3 = na2; + s2 = d[j2 + (F3 + u3) >> 0] | 0; + h2 = 1; + } + } + u3 = z3; + z3 = z3 + 4 | 0; + y3 = y3 + 1 | 0; + } + if (!(h2 & 1)) { + if ((c[X3 >> 2] | 0) >>> 0 < (c[Y3 >> 2] | 0) >>> 7 >>> 0) h2 = 0; + else { + w2 = 0; + h2 = 0; + v3 = (_(d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((w2 | 0) == 1) break; + Aa3 = b2[21084 + (v3 << 1) >> 1] | 0; + f2 = Aa3 & 65535; + c[Y3 >> 2] = (c[Y3 >> 2] | 0) + 1; + if (Aa3 << 16 >> 16 != 0 ? (oa3 = f2 & 31, pa3 = f2 >>> 5, qa3 = (c[11272 + (oa3 << 2) >> 2] | 0) + (_(oa3, pa3) | 0) | 0, oa3 >>> 0 <= H3 >>> 0) : 0) { + s2 = qa3 + oa3 | 0; + u3 = 280811 + s2 | 0; + s2 = 280811 + (s2 + -4) | 0; + g3 = 0; + f2 = 280811 + qa3 | 0; + while (1) { + if (f2 >>> 0 > s2 >>> 0) break; + Aa3 = j2 + (F3 + g3) | 0; + if ((d[f2 >> 0] | d[f2 + 1 >> 0] << 8 | d[f2 + 2 >> 0] << 16 | d[f2 + 3 >> 0] << 24 | 0) != (d[Aa3 >> 0] | d[Aa3 + 1 >> 0] << 8 | d[Aa3 + 2 >> 0] << 16 | d[Aa3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + f2 = f2 + 4 | 0; + } + while (1) { + if (f2 >>> 0 >= u3 >>> 0) break; + if ((a[j2 + (F3 + g3) >> 0] | 0) != (a[f2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + f2 = f2 + 1 | 0; + } + if (!((g3 + 10 | 0) >>> 0 <= oa3 >>> 0 | (g3 | 0) == 0) ? (ra3 = E3 + pa3 + 1 + (d[407930 + (oa3 - g3) >> 0] << d[280786 + oa3 >> 0]) | 0, sa3 = (g3 * 540 | 0) + 3840 + (_((aa(ra3 | 0) | 0) ^ 31, -120) | 0) | 0, sa3 >>> 0 >= (c[U3 >> 2] | 0) >>> 0) : 0) { + c[ja3 >> 2] = g3; + c[V3 >> 2] = oa3 ^ g3; + c[W3 >> 2] = ra3; + c[U3 >> 2] = sa3; + c[X3 >> 2] = (c[X3 >> 2] | 0) + 1; + h2 = 1; + } + } + w2 = w2 + 1 | 0; + v3 = v3 + 1 | 0; + } + h2 = (h2 & 1) != 0; + } + h2 = h2 & 1; + } + c[m3 + (G3 + (l2 >>> 3 & 3) << 2) >> 2] = l2; + if (h2 & 1) { + I3 = 0; + break; + } + e2 = e2 + 1 | 0; + f2 = l2 + 1 | 0; + if (f2 >>> 0 <= t3 >>> 0) { + l2 = f2; + continue; + } + if (f2 >>> 0 > J3 >>> 0) { + h2 = l2 + 17 | 0; + h2 = h2 >>> 0 < $2 >>> 0 ? h2 : $2; + l2 = f2; + while (1) { + if (l2 >>> 0 >= h2 >>> 0) continue b; + Aa3 = j2 + (l2 & k2) | 0; + H3 = Aa3; + Aa3 = Aa3 + 4 | 0; + Aa3 = lc(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24 | 0, d[Aa3 >> 0] | d[Aa3 + 1 >> 0] << 8 | d[Aa3 + 2 >> 0] << 16 | d[Aa3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + Aa3 = bc(Aa3 | 0, C2 | 0, 47) | 0; + c[m3 + (Aa3 + (l2 >>> 3 & 3) << 2) >> 2] = l2; + l2 = l2 + 4 | 0; + e2 = e2 + 4 | 0; + } + } else { + h2 = l2 + 9 | 0; + h2 = h2 >>> 0 < $2 >>> 0 ? h2 : $2; + l2 = f2; + while (1) { + if (l2 >>> 0 >= h2 >>> 0) continue b; + Aa3 = j2 + (l2 & k2) | 0; + H3 = Aa3; + Aa3 = Aa3 + 4 | 0; + Aa3 = lc(d[H3 >> 0] | d[H3 + 1 >> 0] << 8 | d[H3 + 2 >> 0] << 16 | d[H3 + 3 >> 0] << 24 | 0, d[Aa3 >> 0] | d[Aa3 + 1 >> 0] << 8 | d[Aa3 + 2 >> 0] << 16 | d[Aa3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + Aa3 = bc(Aa3 | 0, C2 | 0, 47) | 0; + c[m3 + (Aa3 + (l2 >>> 3 & 3) << 2) >> 2] = l2; + l2 = l2 + 2 | 0; + e2 = e2 + 2 | 0; + } + } + } + while (1) { + H3 = H3 + -1 | 0; + if ((c[fa3 >> 2] | 0) < 5) { + u3 = (c[ja3 >> 2] | 0) + -1 | 0; + u3 = u3 >>> 0 < H3 >>> 0 ? u3 : H3; + } else u3 = 0; + c[ka3 >> 2] = u3; + c[ca3 >> 2] = 0; + c[da3 >> 2] = 0; + c[ba2 >> 2] = 4240; + x3 = l2 + 1 | 0; + E3 = x3 >>> 0 < ha3 >>> 0 ? x3 : ha3; + F3 = x3 & k2; + D3 = j2 + F3 | 0; + G3 = D3; + h2 = G3; + G3 = G3 + 4 | 0; + G3 = lc(d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0, d[G3 >> 0] | d[G3 + 1 >> 0] << 8 | d[G3 + 2 >> 0] << 16 | d[G3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + G3 = bc(G3 | 0, C2 | 0, 47) | 0; + h2 = a[j2 + (F3 + u3) >> 0] | 0; + w2 = h2 & 255; + t3 = c[L3 >> 2] | 0; + v3 = c[n2 >> 2] | 0; + f2 = x3 - v3 | 0; + c[M2 >> 2] = 0; + if (f2 >>> 0 < x3 >>> 0 ? (ta3 = f2 & k2, h2 << 24 >> 24 == (a[j2 + (ta3 + u3) >> 0] | 0)) : 0) { + f2 = F3 + H3 | 0; + g3 = j2 + f2 | 0; + f2 = j2 + (f2 + -4) | 0; + s2 = 0; + h2 = D3; + while (1) { + if (h2 >>> 0 > f2 >>> 0) break; + Aa3 = j2 + (ta3 + s2) | 0; + if ((d[h2 >> 0] | d[h2 + 1 >> 0] << 8 | d[h2 + 2 >> 0] << 16 | d[h2 + 3 >> 0] << 24 | 0) != (d[Aa3 >> 0] | d[Aa3 + 1 >> 0] << 8 | d[Aa3 + 2 >> 0] << 16 | d[Aa3 + 3 >> 0] << 24 | 0)) break; + s2 = s2 + 4 | 0; + h2 = h2 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= g3 >>> 0) break; + if ((a[j2 + (ta3 + s2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + s2 = s2 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (s2 >>> 0 > 3) { + t3 = (s2 * 540 | 0) + 3900 | 0; + c[ka3 >> 2] = s2; + c[N3 >> 2] = v3; + c[L3 >> 2] = t3; + f2 = s2; + s2 = d[j2 + (F3 + s2) >> 0] | 0; + h2 = 1; + } else { + f2 = u3; + s2 = w2; + h2 = 0; + } + } else { + f2 = u3; + s2 = w2; + h2 = 0; + } + B3 = F3 + H3 | 0; + A3 = j2 + B3 | 0; + B3 = j2 + (B3 + -4) | 0; + z3 = m3 + (G3 + 1 << 2) | 0; + y3 = 0; + g3 = m3 + (G3 << 2) | 0; + while (1) { + g3 = c[g3 >> 2] | 0; + if ((y3 | 0) == 4) break; + v3 = x3 - g3 | 0; + w2 = g3 & k2; + if (!(((x3 | 0) == (g3 | 0) ? 1 : (s2 | 0) != (d[j2 + (w2 + f2) >> 0] | 0)) | v3 >>> 0 > E3 >>> 0)) { + g3 = 0; + u3 = D3; + while (1) { + if (u3 >>> 0 > B3 >>> 0) break; + Aa3 = j2 + (w2 + g3) | 0; + if ((d[u3 >> 0] | d[u3 + 1 >> 0] << 8 | d[u3 + 2 >> 0] << 16 | d[u3 + 3 >> 0] << 24 | 0) != (d[Aa3 >> 0] | d[Aa3 + 1 >> 0] << 8 | d[Aa3 + 2 >> 0] << 16 | d[Aa3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + u3 = u3 + 4 | 0; + } + while (1) { + if (u3 >>> 0 >= A3 >>> 0) break; + if ((a[j2 + (w2 + g3) >> 0] | 0) != (a[u3 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + u3 = u3 + 1 | 0; + } + if (g3 >>> 0 > 3 ? (ua3 = (g3 * 540 | 0) + 3840 + (_((aa(v3 | 0) | 0) ^ 31, -120) | 0) | 0, t3 >>> 0 < ua3 >>> 0) : 0) { + c[ka3 >> 2] = g3; + c[N3 >> 2] = v3; + c[L3 >> 2] = ua3; + f2 = g3; + t3 = ua3; + s2 = d[j2 + (F3 + g3) >> 0] | 0; + h2 = 1; + } + } + g3 = z3; + z3 = z3 + 4 | 0; + y3 = y3 + 1 | 0; + } + if (!(h2 & 1)) { + if ((c[X3 >> 2] | 0) >>> 0 < (c[Y3 >> 2] | 0) >>> 7 >>> 0) h2 = 0; + else { + v3 = 0; + h2 = 0; + u3 = (_(d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 1) break; + Aa3 = b2[21084 + (u3 << 1) >> 1] | 0; + f2 = Aa3 & 65535; + c[Y3 >> 2] = (c[Y3 >> 2] | 0) + 1; + if (Aa3 << 16 >> 16 != 0 ? (va3 = f2 & 31, wa3 = f2 >>> 5, xa3 = (c[11272 + (va3 << 2) >> 2] | 0) + (_(va3, wa3) | 0) | 0, va3 >>> 0 <= H3 >>> 0) : 0) { + s2 = xa3 + va3 | 0; + g3 = 280811 + s2 | 0; + s2 = 280811 + (s2 + -4) | 0; + t3 = 0; + f2 = 280811 + xa3 | 0; + while (1) { + if (f2 >>> 0 > s2 >>> 0) break; + Aa3 = j2 + (F3 + t3) | 0; + if ((d[f2 >> 0] | d[f2 + 1 >> 0] << 8 | d[f2 + 2 >> 0] << 16 | d[f2 + 3 >> 0] << 24 | 0) != (d[Aa3 >> 0] | d[Aa3 + 1 >> 0] << 8 | d[Aa3 + 2 >> 0] << 16 | d[Aa3 + 3 >> 0] << 24 | 0)) break; + t3 = t3 + 4 | 0; + f2 = f2 + 4 | 0; + } + while (1) { + if (f2 >>> 0 >= g3 >>> 0) break; + if ((a[j2 + (F3 + t3) >> 0] | 0) != (a[f2 >> 0] | 0)) break; + t3 = t3 + 1 | 0; + f2 = f2 + 1 | 0; + } + if (!((t3 + 10 | 0) >>> 0 <= va3 >>> 0 | (t3 | 0) == 0) ? (ya3 = E3 + wa3 + 1 + (d[407930 + (va3 - t3) >> 0] << d[280786 + va3 >> 0]) | 0, za3 = (t3 * 540 | 0) + 3840 + (_((aa(ya3 | 0) | 0) ^ 31, -120) | 0) | 0, za3 >>> 0 >= (c[L3 >> 2] | 0) >>> 0) : 0) { + c[ka3 >> 2] = t3; + c[M2 >> 2] = va3 ^ t3; + c[N3 >> 2] = ya3; + c[L3 >> 2] = za3; + c[X3 >> 2] = (c[X3 >> 2] | 0) + 1; + h2 = 1; + } + } + v3 = v3 + 1 | 0; + u3 = u3 + 1 | 0; + } + h2 = (h2 & 1) != 0; + } + h2 = h2 & 1; + } + c[m3 + (G3 + (x3 >>> 3 & 3) << 2) >> 2] = x3; + if (!(h2 & 1)) { + x3 = l2; + w2 = e2; + break; + } + if ((c[ba2 >> 2] | 0) >>> 0 < ((c[T3 >> 2] | 0) + 700 | 0) >>> 0) { + x3 = l2; + w2 = e2; + break; + } + e2 = e2 + 1 | 0; + c[ja3 >> 2] = c[ka3 >> 2]; + c[ja3 + 4 >> 2] = c[ka3 + 4 >> 2]; + c[ja3 + 8 >> 2] = c[ka3 + 8 >> 2]; + c[ja3 + 12 >> 2] = c[ka3 + 12 >> 2]; + I3 = I3 + 1 | 0; + if (!((I3 | 0) < 4 & (l2 + 9 | 0) >>> 0 < ia3 >>> 0)) { + w2 = e2; + break; + } else l2 = x3; + } + l2 = c[ja3 >> 2] | 0; + t3 = x3 + (l2 << 1) + ea3 | 0; + e2 = c[S3 >> 2] | 0; + c: do + if (e2 >>> 0 <= (x3 >>> 0 < ha3 >>> 0 ? x3 : ha3) >>> 0) { + s2 = e2 + 3 | 0; + Aa3 = c[n2 >> 2] | 0; + h2 = s2 - Aa3 | 0; + f2 = c[Q3 >> 2] | 0; + s2 = s2 - f2 | 0; + if ((e2 | 0) == (Aa3 | 0)) e2 = 0; + else { + d: do + if ((e2 | 0) != (f2 | 0)) { + do + if (h2 >>> 0 < 7) e2 = 158663784 >>> (h2 << 2) & 15; + else { + if (s2 >>> 0 < 7) { + e2 = 266017486 >>> (s2 << 2) & 15; + break; + } + if ((e2 | 0) == (c[O3 >> 2] | 0)) { + e2 = 2; + break d; + } + if ((e2 | 0) == (c[P3 >> 2] | 0)) { + e2 = 3; + break d; + } + e2 = e2 + 15 | 0; + } + while (0); + if (!e2) break c; + } else e2 = 1; + while (0); + c[P3 >> 2] = c[O3 >> 2]; + c[O3 >> 2] = c[Q3 >> 2]; + c[Q3 >> 2] = c[n2 >> 2]; + c[n2 >> 2] = c[S3 >> 2]; + l2 = c[ja3 >> 2] | 0; + } + } else e2 = e2 + 15 | 0; + while (0); + v3 = K3 + 16 | 0; + Aa3 = c[R3 >> 2] | 0; + h2 = l2 ^ Aa3; + c[K3 >> 2] = w2; + c[K3 + 4 >> 2] = l2 | Aa3 << 24; + l2 = K3 + 14 | 0; + if (e2 >>> 0 < 16) { + e2 = e2 & 65535; + b2[l2 >> 1] = e2; + l2 = 0; + } else { + I3 = e2 + -12 | 0; + Aa3 = ((aa(I3 | 0) | 0) ^ 31) + -1 | 0; + J3 = I3 >>> Aa3 & 1; + e2 = ((Aa3 << 1) + 65534 | J3) + 16 & 65535; + b2[l2 >> 1] = e2; + l2 = Aa3 << 24 | I3 - ((J3 | 2) << Aa3); + } + c[K3 + 8 >> 2] = l2; + g3 = e2 << 16 >> 16 == 0; + u3 = K3 + 12 | 0; + do + if (w2 >>> 0 >= 6) { + if (w2 >>> 0 < 130) { + Aa3 = w2 + -2 | 0; + s2 = ((aa(Aa3 | 0) | 0) ^ 31) + -1 | 0; + s2 = (s2 << 1) + (Aa3 >>> s2) + 2 & 65535; + break; + } + if (w2 >>> 0 < 2114) { + s2 = ((aa(w2 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (w2 >>> 0 < 6210) s2 = 21; + else s2 = w2 >>> 0 < 22594 ? 22 : 23; + } else s2 = w2 & 65535; + while (0); + do + if (h2 >>> 0 >= 10) { + if (h2 >>> 0 < 134) { + Aa3 = h2 + -6 | 0; + e2 = ((aa(Aa3 | 0) | 0) ^ 31) + -1 | 0; + e2 = (e2 << 1) + (Aa3 >>> e2) + 4 & 65535; + break; + } + if (h2 >>> 0 < 2118) e2 = ((aa(h2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else e2 = 23; + } else e2 = h2 + 65534 & 65535; + while (0); + l2 = e2 & 65535; + h2 = s2 & 65535; + f2 = l2 & 7 | h2 << 3 & 56; + if (g3 & (s2 & 65535) < 8 & (e2 & 65535) < 16) e2 = ((e2 & 65535) < 8 ? f2 : f2 | 64) & 65535; + else e2 = b2[88156 + ((l2 >>> 3) + ((h2 >>> 3) * 3 | 0) << 1) >> 1] | f2 & 65535; + b2[u3 >> 1] = e2; + c[r2 >> 2] = (c[r2 >> 2] | 0) + w2; + e2 = x3 + (c[ja3 >> 2] | 0) | 0; + e2 = e2 >>> 0 < ga3 >>> 0 ? e2 : ga3; + l2 = x3 + 2 | 0; + while (1) { + if (l2 >>> 0 >= e2 >>> 0) break; + Aa3 = j2 + (l2 & k2) | 0; + K3 = Aa3; + Aa3 = Aa3 + 4 | 0; + Aa3 = lc(d[K3 >> 0] | d[K3 + 1 >> 0] << 8 | d[K3 + 2 >> 0] << 16 | d[K3 + 3 >> 0] << 24 | 0, d[Aa3 >> 0] | d[Aa3 + 1 >> 0] << 8 | d[Aa3 + 2 >> 0] << 16 | d[Aa3 + 3 >> 0] << 24 | 0, -1124073472, 1979815) | 0; + Aa3 = bc(Aa3 | 0, C2 | 0, 47) | 0; + c[m3 + (Aa3 + (l2 >>> 3 & 3) << 2) >> 2] = l2; + l2 = l2 + 1 | 0; + } + l2 = x3 + (c[ja3 >> 2] | 0) | 0; + K3 = v3; + e2 = 0; + } + c[o2 >> 2] = e2 + H3; + c[q2 >> 2] = (c[q2 >> 2] | 0) + (I3 - p2 >> 4); + i = la3; + return; + } + function Ma2(f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2, s2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0, Ha3 = 0, Ia3 = 0; + qa3 = i; + i = i + 32 | 0; + oa3 = qa3 + 16 | 0; + pa3 = qa3; + ma3 = (1 << c[m3 + 8 >> 2]) + -16 | 0; + v3 = c[p2 >> 2] | 0; + na2 = h2 + g3 | 0; + la3 = g3 >>> 0 > 3 ? na2 + -3 | 0 : h2; + ka3 = m3 + 4 | 0; + ja3 = (c[ka3 >> 2] | 0) < 9 ? 64 : 512; + u3 = ja3 + h2 | 0; + if ((((h2 | 0) == 0 ^ 1 | j2 ^ 1) ^ 1) & g3 >>> 0 < 257) { + f2 = 0; + while (1) { + if ((f2 | 0) == (g3 | 0)) break; + ia3 = k2 + f2 | 0; + b2[n2 + ((_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1) >> 1] = 0; + f2 = f2 + 1 | 0; + } + if (g3) { + a[n2 + 1081344 >> 0] = 0; + t3 = 8; + } + } else { + f2 = n2 + 1081344 | 0; + if (!(a[f2 >> 0] & 1)) t3 = 8; + else { + ac(n2 | 0, 0, 32768) | 0; + a[f2 >> 0] = 0; + t3 = 8; + } + } + if ((t3 | 0) == 8 ? g3 >>> 0 > 2 & h2 >>> 0 > 2 : 0) { + ga3 = h2 + -3 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 32768 + ((e[ia3 >> 1] & 15 | ha3 << 4) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + ia3 = h2 + -2 | 0; + ha3 = k2 + (ia3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + ga3 = n2 + (ha3 << 1) | 0; + c[n2 + 32768 + ((e[ga3 >> 1] & 15 | ha3 << 4) << 2) >> 2] = ia3; + b2[ga3 >> 1] = (b2[ga3 >> 1] | 0) + 1 << 16 >> 16; + ga3 = h2 + -1 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 32768 + ((e[ia3 >> 1] & 15 | ha3 << 4) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + } + P3 = oa3 + 4 | 0; + Q3 = oa3 + 8 | 0; + R3 = oa3 + 12 | 0; + S3 = oa3 + 4 | 0; + T3 = oa3 + 8 | 0; + U3 = oa3 + 12 | 0; + V3 = n2 + 1081352 | 0; + W3 = n2 + 1081348 | 0; + X3 = ja3 << 2; + Y3 = na2 + -4 | 0; + Z3 = na2 + -3 | 0; + $2 = pa3 + 12 | 0; + ba2 = pa3 + 4 | 0; + ca3 = pa3 + 8 | 0; + da3 = pa3 + 4 | 0; + ea3 = pa3 + 8 | 0; + fa3 = pa3 + 12 | 0; + ga3 = o2 + 8 | 0; + ha3 = o2 + 12 | 0; + ia3 = o2 + 4 | 0; + m3 = h2; + O3 = q2; + f2 = v3; + a: while (1) { + M2 = O3; + N3 = u3 + X3 | 0; + b: while (1) { + L3 = na2 - m3 | 0; + if ((m3 + 4 | 0) >>> 0 >= na2 >>> 0) break a; + J3 = m3 >>> 0 < ma3 >>> 0 ? m3 : ma3; + c[oa3 >> 2] = 0; + c[P3 >> 2] = 0; + c[Q3 >> 2] = 0; + c[R3 >> 2] = 4240; + K3 = m3 & l2; + g3 = c[oa3 >> 2] | 0; + c[oa3 >> 2] = 0; + c[S3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + y3 = 4240; + j2 = 0; + x3 = 0; + while (1) { + if ((x3 | 0) == 4) break; + w2 = (c[o2 + (c[11372 + (x3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (x3 << 2) >> 2] | 0) | 0; + t3 = m3 - w2 | 0; + do + if (((!(t3 >>> 0 >= m3 >>> 0 | w2 >>> 0 > J3 >>> 0) ? (ra3 = t3 & l2, sa3 = K3 + g3 | 0, sa3 >>> 0 <= l2 >>> 0) : 0) ? (ta3 = ra3 + g3 | 0, ta3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + sa3 >> 0] | 0) == (a[k2 + ta3 >> 0] | 0) : 0) { + v3 = 0; + t3 = F3; + while (1) { + h2 = t3; + if (h2 >>> 0 > H3 >>> 0) break; + D3 = t3; + E3 = k2 + (ra3 + v3) | 0; + if ((d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0) != (d[E3 >> 0] | d[E3 + 1 >> 0] << 8 | d[E3 + 2 >> 0] << 16 | d[E3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + t3 = h2 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (ra3 + v3) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (v3 >>> 0 <= 2 ? !((v3 | 0) == 2 & x3 >>> 0 < 2) : 0) { + t3 = y3; + break; + } + t3 = (v3 * 540 | 0) + (c[11500 + (x3 << 2) >> 2] | 0) | 0; + if (y3 >>> 0 < t3 >>> 0) { + c[oa3 >> 2] = v3; + c[T3 >> 2] = w2; + c[U3 >> 2] = t3; + g3 = v3; + j2 = 1; + } else t3 = y3; + } else t3 = y3; + while (0); + y3 = t3; + x3 = x3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + C3 = D3 << 4; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + t3 = E3 & 65535; + E3 = (E3 & 65535) > 16 ? t3 + -16 | 0 : 0; + c: while (1) { + B3 = K3 + g3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (t3 >>> 0 <= E3 >>> 0) break c; + t3 = t3 + -1 | 0; + h2 = c[n2 + 32768 + ((C3 | t3 & 15) << 2) >> 2] | 0; + z3 = m3 - h2 | 0; + if (z3 >>> 0 > J3 >>> 0) break c; + x3 = h2 & l2; + if (A3) continue; + h2 = x3 + g3 | 0; + if (h2 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + h2 >> 0] | 0)) { + w2 = 0; + h2 = F3; + } else continue; + while (1) { + v3 = h2; + if (v3 >>> 0 > H3 >>> 0) break; + Ia3 = h2; + Ha3 = k2 + (x3 + w2) | 0; + if ((d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0) != (d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0)) break; + w2 = w2 + 4 | 0; + h2 = v3 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (x3 + w2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + w2 = w2 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (w2 >>> 0 <= 3) continue; + h2 = (w2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (y3 >>> 0 < h2 >>> 0) break; + } + c[oa3 >> 2] = w2; + c[T3 >> 2] = z3; + c[U3 >> 2] = h2; + g3 = w2; + y3 = h2; + j2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 32768 + ((C3 | Ia3 & 15) << 2) >> 2] = m3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(j2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) j2 = 0; + else { + x3 = 0; + j2 = 0; + w2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((x3 | 0) == 2) break; + Ia3 = b2[21084 + (w2 << 1) >> 1] | 0; + t3 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (ua3 = t3 & 31, va3 = t3 >>> 5, wa3 = (c[11272 + (ua3 << 2) >> 2] | 0) + (_(ua3, va3) | 0) | 0, ua3 >>> 0 <= L3 >>> 0) : 0) { + g3 = wa3 + ua3 | 0; + v3 = 280811 + g3 | 0; + g3 = 280811 + (g3 + -4) | 0; + h2 = 0; + t3 = 280811 + wa3 | 0; + while (1) { + if (t3 >>> 0 > g3 >>> 0) break; + Ia3 = k2 + (K3 + h2) | 0; + if ((d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + t3 = t3 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= v3 >>> 0) break; + if ((a[k2 + (K3 + h2) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (!((h2 + 10 | 0) >>> 0 <= ua3 >>> 0 | (h2 | 0) == 0) ? (xa3 = J3 + va3 + 1 + (d[407930 + (ua3 - h2) >> 0] << d[280786 + ua3 >> 0]) | 0, ya3 = (h2 * 540 | 0) + 3840 + (_((aa(xa3 | 0) | 0) ^ 31, -120) | 0) | 0, ya3 >>> 0 >= (c[U3 >> 2] | 0) >>> 0) : 0) { + c[oa3 >> 2] = h2; + c[S3 >> 2] = ua3 ^ h2; + c[T3 >> 2] = xa3; + c[U3 >> 2] = ya3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + j2 = 1; + } + } + x3 = x3 + 1 | 0; + w2 = w2 + 1 | 0; + } + j2 = (j2 & 1) != 0; + } + j2 = j2 & 1; + } + if (j2 & 1) { + M2 = 0; + x3 = f2; + break; + } + f2 = f2 + 1 | 0; + t3 = m3 + 1 | 0; + if (t3 >>> 0 <= u3 >>> 0) { + m3 = t3; + continue; + } + if (t3 >>> 0 > N3 >>> 0) { + j2 = m3 + 17 | 0; + j2 = j2 >>> 0 < Y3 >>> 0 ? j2 : Y3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 32768 + ((e[Ia3 >> 1] & 15 | Ha3 << 4) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 4 | 0; + f2 = f2 + 4 | 0; + } + } else { + j2 = m3 + 9 | 0; + j2 = j2 >>> 0 < Z3 >>> 0 ? j2 : Z3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 32768 + ((e[Ia3 >> 1] & 15 | Ha3 << 4) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 2 | 0; + f2 = f2 + 2 | 0; + } + } + } + while (1) { + L3 = L3 + -1 | 0; + if ((c[ka3 >> 2] | 0) < 5) { + f2 = (c[oa3 >> 2] | 0) + -1 | 0; + f2 = f2 >>> 0 < L3 >>> 0 ? f2 : L3; + } else f2 = 0; + c[pa3 >> 2] = f2; + c[ba2 >> 2] = 0; + c[ca3 >> 2] = 0; + c[$2 >> 2] = 4240; + y3 = m3 + 1 | 0; + J3 = y3 >>> 0 < ma3 >>> 0 ? y3 : ma3; + K3 = y3 & l2; + t3 = c[pa3 >> 2] | 0; + c[pa3 >> 2] = 0; + c[da3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + w2 = 4240; + f2 = 0; + v3 = 0; + while (1) { + if ((v3 | 0) == 4) break; + h2 = (c[o2 + (c[11372 + (v3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (v3 << 2) >> 2] | 0) | 0; + j2 = y3 - h2 | 0; + do + if (((!(j2 >>> 0 >= y3 >>> 0 | h2 >>> 0 > J3 >>> 0) ? (za3 = j2 & l2, Aa3 = K3 + t3 | 0, Aa3 >>> 0 <= l2 >>> 0) : 0) ? (Ba3 = za3 + t3 | 0, Ba3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + Aa3 >> 0] | 0) == (a[k2 + Ba3 >> 0] | 0) : 0) { + u3 = 0; + j2 = F3; + while (1) { + g3 = j2; + if (g3 >>> 0 > H3 >>> 0) break; + Ha3 = j2; + Ia3 = k2 + (za3 + u3) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + u3 = u3 + 4 | 0; + j2 = g3 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (za3 + u3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + u3 = u3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (u3 >>> 0 <= 2 ? !((u3 | 0) == 2 & v3 >>> 0 < 2) : 0) { + j2 = w2; + break; + } + j2 = (u3 * 540 | 0) + (c[11500 + (v3 << 2) >> 2] | 0) | 0; + if (w2 >>> 0 < j2 >>> 0) { + c[pa3 >> 2] = u3; + c[ea3 >> 2] = h2; + c[fa3 >> 2] = j2; + t3 = u3; + f2 = 1; + } else j2 = w2; + } else j2 = w2; + while (0); + w2 = j2; + v3 = v3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + C3 = D3 << 4; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + j2 = E3 & 65535; + E3 = (E3 & 65535) > 16 ? j2 + -16 | 0 : 0; + d: while (1) { + B3 = K3 + t3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (j2 >>> 0 <= E3 >>> 0) break d; + j2 = j2 + -1 | 0; + g3 = c[n2 + 32768 + ((C3 | j2 & 15) << 2) >> 2] | 0; + z3 = y3 - g3 | 0; + if (z3 >>> 0 > J3 >>> 0) break d; + v3 = g3 & l2; + if (A3) continue; + g3 = v3 + t3 | 0; + if (g3 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + g3 >> 0] | 0)) { + h2 = 0; + g3 = F3; + } else continue; + while (1) { + u3 = g3; + if (u3 >>> 0 > H3 >>> 0) break; + Ha3 = g3; + Ia3 = k2 + (v3 + h2) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + g3 = u3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (v3 + h2) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (h2 >>> 0 <= 3) continue; + g3 = (h2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (w2 >>> 0 < g3 >>> 0) break; + } + c[pa3 >> 2] = h2; + c[ea3 >> 2] = z3; + c[fa3 >> 2] = g3; + t3 = h2; + w2 = g3; + f2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 32768 + ((C3 | Ia3 & 15) << 2) >> 2] = y3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(f2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) f2 = 0; + else { + v3 = 0; + f2 = 0; + h2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 2) break; + Ia3 = b2[21084 + (h2 << 1) >> 1] | 0; + j2 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (Ca3 = j2 & 31, Da3 = j2 >>> 5, Ea3 = (c[11272 + (Ca3 << 2) >> 2] | 0) + (_(Ca3, Da3) | 0) | 0, Ca3 >>> 0 <= L3 >>> 0) : 0) { + t3 = Ea3 + Ca3 | 0; + u3 = 280811 + t3 | 0; + t3 = 280811 + (t3 + -4) | 0; + g3 = 0; + j2 = 280811 + Ea3 | 0; + while (1) { + if (j2 >>> 0 > t3 >>> 0) break; + Ia3 = k2 + (K3 + g3) | 0; + if ((d[j2 >> 0] | d[j2 + 1 >> 0] << 8 | d[j2 + 2 >> 0] << 16 | d[j2 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + j2 = j2 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= u3 >>> 0) break; + if ((a[k2 + (K3 + g3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (!((g3 + 10 | 0) >>> 0 <= Ca3 >>> 0 | (g3 | 0) == 0) ? (Fa3 = J3 + Da3 + 1 + (d[407930 + (Ca3 - g3) >> 0] << d[280786 + Ca3 >> 0]) | 0, Ga3 = (g3 * 540 | 0) + 3840 + (_((aa(Fa3 | 0) | 0) ^ 31, -120) | 0) | 0, Ga3 >>> 0 >= (c[fa3 >> 2] | 0) >>> 0) : 0) { + c[pa3 >> 2] = g3; + c[da3 >> 2] = Ca3 ^ g3; + c[ea3 >> 2] = Fa3; + c[fa3 >> 2] = Ga3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + f2 = 1; + } + } + v3 = v3 + 1 | 0; + h2 = h2 + 1 | 0; + } + f2 = (f2 & 1) != 0; + } + f2 = f2 & 1; + } + if (!(f2 & 1)) { + y3 = m3; + break; + } + if ((c[$2 >> 2] | 0) >>> 0 < ((c[R3 >> 2] | 0) + 700 | 0) >>> 0) { + y3 = m3; + break; + } + f2 = x3 + 1 | 0; + c[oa3 >> 2] = c[pa3 >> 2]; + c[oa3 + 4 >> 2] = c[pa3 + 4 >> 2]; + c[oa3 + 8 >> 2] = c[pa3 + 8 >> 2]; + c[oa3 + 12 >> 2] = c[pa3 + 12 >> 2]; + M2 = M2 + 1 | 0; + if (!((M2 | 0) < 4 & (m3 + 5 | 0) >>> 0 < na2 >>> 0)) { + x3 = f2; + break; + } else { + m3 = y3; + x3 = f2; + } + } + m3 = c[oa3 >> 2] | 0; + u3 = y3 + (m3 << 1) + ja3 | 0; + f2 = c[Q3 >> 2] | 0; + e: do + if (f2 >>> 0 <= (y3 >>> 0 < ma3 >>> 0 ? y3 : ma3) >>> 0) { + g3 = f2 + 3 | 0; + Ia3 = c[o2 >> 2] | 0; + j2 = g3 - Ia3 | 0; + t3 = c[ia3 >> 2] | 0; + g3 = g3 - t3 | 0; + if ((f2 | 0) == (Ia3 | 0)) f2 = 0; + else { + f: do + if ((f2 | 0) != (t3 | 0)) { + do + if (j2 >>> 0 < 7) f2 = 158663784 >>> (j2 << 2) & 15; + else { + if (g3 >>> 0 < 7) { + f2 = 266017486 >>> (g3 << 2) & 15; + break; + } + if ((f2 | 0) == (c[ga3 >> 2] | 0)) { + f2 = 2; + break f; + } + if ((f2 | 0) == (c[ha3 >> 2] | 0)) { + f2 = 3; + break f; + } + f2 = f2 + 15 | 0; + } + while (0); + if (!f2) break e; + } else f2 = 1; + while (0); + c[ha3 >> 2] = c[ga3 >> 2]; + c[ga3 >> 2] = c[ia3 >> 2]; + c[ia3 >> 2] = c[o2 >> 2]; + c[o2 >> 2] = c[Q3 >> 2]; + m3 = c[oa3 >> 2] | 0; + } + } else f2 = f2 + 15 | 0; + while (0); + w2 = O3 + 16 | 0; + Ia3 = c[P3 >> 2] | 0; + j2 = m3 ^ Ia3; + c[O3 >> 2] = x3; + c[O3 + 4 >> 2] = m3 | Ia3 << 24; + m3 = O3 + 14 | 0; + if (f2 >>> 0 < 16) { + f2 = f2 & 65535; + b2[m3 >> 1] = f2; + m3 = 0; + } else { + N3 = f2 + -12 | 0; + Ia3 = ((aa(N3 | 0) | 0) ^ 31) + -1 | 0; + Ha3 = N3 >>> Ia3 & 1; + f2 = ((Ia3 << 1) + 65534 | Ha3) + 16 & 65535; + b2[m3 >> 1] = f2; + m3 = Ia3 << 24 | N3 - ((Ha3 | 2) << Ia3); + } + c[O3 + 8 >> 2] = m3; + h2 = f2 << 16 >> 16 == 0; + v3 = O3 + 12 | 0; + do + if (x3 >>> 0 >= 6) { + if (x3 >>> 0 < 130) { + Ia3 = x3 + -2 | 0; + g3 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + g3 = (g3 << 1) + (Ia3 >>> g3) + 2 & 65535; + break; + } + if (x3 >>> 0 < 2114) { + g3 = ((aa(x3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (x3 >>> 0 < 6210) g3 = 21; + else g3 = x3 >>> 0 < 22594 ? 22 : 23; + } else g3 = x3 & 65535; + while (0); + do + if (j2 >>> 0 >= 10) { + if (j2 >>> 0 < 134) { + Ia3 = j2 + -6 | 0; + f2 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + f2 = (f2 << 1) + (Ia3 >>> f2) + 4 & 65535; + break; + } + if (j2 >>> 0 < 2118) f2 = ((aa(j2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else f2 = 23; + } else f2 = j2 + 65534 & 65535; + while (0); + m3 = f2 & 65535; + j2 = g3 & 65535; + t3 = m3 & 7 | j2 << 3 & 56; + if (h2 & (g3 & 65535) < 8 & (f2 & 65535) < 16) f2 = ((f2 & 65535) < 8 ? t3 : t3 | 64) & 65535; + else f2 = b2[88156 + ((m3 >>> 3) + ((j2 >>> 3) * 3 | 0) << 1) >> 1] | t3 & 65535; + b2[v3 >> 1] = f2; + c[s2 >> 2] = (c[s2 >> 2] | 0) + x3; + f2 = y3 + (c[oa3 >> 2] | 0) | 0; + f2 = f2 >>> 0 < la3 >>> 0 ? f2 : la3; + m3 = y3 + 2 | 0; + while (1) { + if (m3 >>> 0 >= f2 >>> 0) break; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 32768 + ((e[Ia3 >> 1] & 15 | Ha3 << 4) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 1 | 0; + } + m3 = y3 + (c[oa3 >> 2] | 0) | 0; + O3 = w2; + f2 = 0; + } + c[p2 >> 2] = f2 + L3; + c[r2 >> 2] = (c[r2 >> 2] | 0) + (M2 - q2 >> 4); + i = qa3; + return; + } + function Na2(f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2, s2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0, Ha3 = 0, Ia3 = 0; + qa3 = i; + i = i + 32 | 0; + oa3 = qa3 + 16 | 0; + pa3 = qa3; + ma3 = (1 << c[m3 + 8 >> 2]) + -16 | 0; + v3 = c[p2 >> 2] | 0; + na2 = h2 + g3 | 0; + la3 = g3 >>> 0 > 3 ? na2 + -3 | 0 : h2; + ka3 = m3 + 4 | 0; + ja3 = (c[ka3 >> 2] | 0) < 9 ? 64 : 512; + u3 = ja3 + h2 | 0; + if ((((h2 | 0) == 0 ^ 1 | j2 ^ 1) ^ 1) & g3 >>> 0 < 257) { + f2 = 0; + while (1) { + if ((f2 | 0) == (g3 | 0)) break; + ia3 = k2 + f2 | 0; + b2[n2 + ((_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1) >> 1] = 0; + f2 = f2 + 1 | 0; + } + if (g3) { + a[n2 + 2129920 >> 0] = 0; + t3 = 8; + } + } else { + f2 = n2 + 2129920 | 0; + if (!(a[f2 >> 0] & 1)) t3 = 8; + else { + ac(n2 | 0, 0, 32768) | 0; + a[f2 >> 0] = 0; + t3 = 8; + } + } + if ((t3 | 0) == 8 ? g3 >>> 0 > 2 & h2 >>> 0 > 2 : 0) { + ga3 = h2 + -3 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 32768 + ((e[ia3 >> 1] & 31 | ha3 << 5) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + ia3 = h2 + -2 | 0; + ha3 = k2 + (ia3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + ga3 = n2 + (ha3 << 1) | 0; + c[n2 + 32768 + ((e[ga3 >> 1] & 31 | ha3 << 5) << 2) >> 2] = ia3; + b2[ga3 >> 1] = (b2[ga3 >> 1] | 0) + 1 << 16 >> 16; + ga3 = h2 + -1 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 32768 + ((e[ia3 >> 1] & 31 | ha3 << 5) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + } + P3 = oa3 + 4 | 0; + Q3 = oa3 + 8 | 0; + R3 = oa3 + 12 | 0; + S3 = oa3 + 4 | 0; + T3 = oa3 + 8 | 0; + U3 = oa3 + 12 | 0; + V3 = n2 + 2129928 | 0; + W3 = n2 + 2129924 | 0; + X3 = ja3 << 2; + Y3 = na2 + -4 | 0; + Z3 = na2 + -3 | 0; + $2 = pa3 + 12 | 0; + ba2 = pa3 + 4 | 0; + ca3 = pa3 + 8 | 0; + da3 = pa3 + 4 | 0; + ea3 = pa3 + 8 | 0; + fa3 = pa3 + 12 | 0; + ga3 = o2 + 8 | 0; + ha3 = o2 + 12 | 0; + ia3 = o2 + 4 | 0; + m3 = h2; + O3 = q2; + f2 = v3; + a: while (1) { + M2 = O3; + N3 = u3 + X3 | 0; + b: while (1) { + L3 = na2 - m3 | 0; + if ((m3 + 4 | 0) >>> 0 >= na2 >>> 0) break a; + J3 = m3 >>> 0 < ma3 >>> 0 ? m3 : ma3; + c[oa3 >> 2] = 0; + c[P3 >> 2] = 0; + c[Q3 >> 2] = 0; + c[R3 >> 2] = 4240; + K3 = m3 & l2; + g3 = c[oa3 >> 2] | 0; + c[oa3 >> 2] = 0; + c[S3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + y3 = 4240; + j2 = 0; + x3 = 0; + while (1) { + if ((x3 | 0) == 4) break; + w2 = (c[o2 + (c[11372 + (x3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (x3 << 2) >> 2] | 0) | 0; + t3 = m3 - w2 | 0; + do + if (((!(t3 >>> 0 >= m3 >>> 0 | w2 >>> 0 > J3 >>> 0) ? (ra3 = t3 & l2, sa3 = K3 + g3 | 0, sa3 >>> 0 <= l2 >>> 0) : 0) ? (ta3 = ra3 + g3 | 0, ta3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + sa3 >> 0] | 0) == (a[k2 + ta3 >> 0] | 0) : 0) { + v3 = 0; + t3 = F3; + while (1) { + h2 = t3; + if (h2 >>> 0 > H3 >>> 0) break; + D3 = t3; + E3 = k2 + (ra3 + v3) | 0; + if ((d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0) != (d[E3 >> 0] | d[E3 + 1 >> 0] << 8 | d[E3 + 2 >> 0] << 16 | d[E3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + t3 = h2 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (ra3 + v3) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (v3 >>> 0 <= 2 ? !((v3 | 0) == 2 & x3 >>> 0 < 2) : 0) { + t3 = y3; + break; + } + t3 = (v3 * 540 | 0) + (c[11500 + (x3 << 2) >> 2] | 0) | 0; + if (y3 >>> 0 < t3 >>> 0) { + c[oa3 >> 2] = v3; + c[T3 >> 2] = w2; + c[U3 >> 2] = t3; + g3 = v3; + j2 = 1; + } else t3 = y3; + } else t3 = y3; + while (0); + y3 = t3; + x3 = x3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + C3 = D3 << 5; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + t3 = E3 & 65535; + E3 = (E3 & 65535) > 32 ? t3 + -32 | 0 : 0; + c: while (1) { + B3 = K3 + g3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (t3 >>> 0 <= E3 >>> 0) break c; + t3 = t3 + -1 | 0; + h2 = c[n2 + 32768 + ((C3 | t3 & 31) << 2) >> 2] | 0; + z3 = m3 - h2 | 0; + if (z3 >>> 0 > J3 >>> 0) break c; + x3 = h2 & l2; + if (A3) continue; + h2 = x3 + g3 | 0; + if (h2 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + h2 >> 0] | 0)) { + w2 = 0; + h2 = F3; + } else continue; + while (1) { + v3 = h2; + if (v3 >>> 0 > H3 >>> 0) break; + Ia3 = h2; + Ha3 = k2 + (x3 + w2) | 0; + if ((d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0) != (d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0)) break; + w2 = w2 + 4 | 0; + h2 = v3 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (x3 + w2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + w2 = w2 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (w2 >>> 0 <= 3) continue; + h2 = (w2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (y3 >>> 0 < h2 >>> 0) break; + } + c[oa3 >> 2] = w2; + c[T3 >> 2] = z3; + c[U3 >> 2] = h2; + g3 = w2; + y3 = h2; + j2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 32768 + ((C3 | Ia3 & 31) << 2) >> 2] = m3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(j2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) j2 = 0; + else { + x3 = 0; + j2 = 0; + w2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((x3 | 0) == 2) break; + Ia3 = b2[21084 + (w2 << 1) >> 1] | 0; + t3 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (ua3 = t3 & 31, va3 = t3 >>> 5, wa3 = (c[11272 + (ua3 << 2) >> 2] | 0) + (_(ua3, va3) | 0) | 0, ua3 >>> 0 <= L3 >>> 0) : 0) { + g3 = wa3 + ua3 | 0; + v3 = 280811 + g3 | 0; + g3 = 280811 + (g3 + -4) | 0; + h2 = 0; + t3 = 280811 + wa3 | 0; + while (1) { + if (t3 >>> 0 > g3 >>> 0) break; + Ia3 = k2 + (K3 + h2) | 0; + if ((d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + t3 = t3 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= v3 >>> 0) break; + if ((a[k2 + (K3 + h2) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (!((h2 + 10 | 0) >>> 0 <= ua3 >>> 0 | (h2 | 0) == 0) ? (xa3 = J3 + va3 + 1 + (d[407930 + (ua3 - h2) >> 0] << d[280786 + ua3 >> 0]) | 0, ya3 = (h2 * 540 | 0) + 3840 + (_((aa(xa3 | 0) | 0) ^ 31, -120) | 0) | 0, ya3 >>> 0 >= (c[U3 >> 2] | 0) >>> 0) : 0) { + c[oa3 >> 2] = h2; + c[S3 >> 2] = ua3 ^ h2; + c[T3 >> 2] = xa3; + c[U3 >> 2] = ya3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + j2 = 1; + } + } + x3 = x3 + 1 | 0; + w2 = w2 + 1 | 0; + } + j2 = (j2 & 1) != 0; + } + j2 = j2 & 1; + } + if (j2 & 1) { + M2 = 0; + x3 = f2; + break; + } + f2 = f2 + 1 | 0; + t3 = m3 + 1 | 0; + if (t3 >>> 0 <= u3 >>> 0) { + m3 = t3; + continue; + } + if (t3 >>> 0 > N3 >>> 0) { + j2 = m3 + 17 | 0; + j2 = j2 >>> 0 < Y3 >>> 0 ? j2 : Y3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 32768 + ((e[Ia3 >> 1] & 31 | Ha3 << 5) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 4 | 0; + f2 = f2 + 4 | 0; + } + } else { + j2 = m3 + 9 | 0; + j2 = j2 >>> 0 < Z3 >>> 0 ? j2 : Z3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 32768 + ((e[Ia3 >> 1] & 31 | Ha3 << 5) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 2 | 0; + f2 = f2 + 2 | 0; + } + } + } + while (1) { + L3 = L3 + -1 | 0; + if ((c[ka3 >> 2] | 0) < 5) { + f2 = (c[oa3 >> 2] | 0) + -1 | 0; + f2 = f2 >>> 0 < L3 >>> 0 ? f2 : L3; + } else f2 = 0; + c[pa3 >> 2] = f2; + c[ba2 >> 2] = 0; + c[ca3 >> 2] = 0; + c[$2 >> 2] = 4240; + y3 = m3 + 1 | 0; + J3 = y3 >>> 0 < ma3 >>> 0 ? y3 : ma3; + K3 = y3 & l2; + t3 = c[pa3 >> 2] | 0; + c[pa3 >> 2] = 0; + c[da3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + w2 = 4240; + f2 = 0; + v3 = 0; + while (1) { + if ((v3 | 0) == 4) break; + h2 = (c[o2 + (c[11372 + (v3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (v3 << 2) >> 2] | 0) | 0; + j2 = y3 - h2 | 0; + do + if (((!(j2 >>> 0 >= y3 >>> 0 | h2 >>> 0 > J3 >>> 0) ? (za3 = j2 & l2, Aa3 = K3 + t3 | 0, Aa3 >>> 0 <= l2 >>> 0) : 0) ? (Ba3 = za3 + t3 | 0, Ba3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + Aa3 >> 0] | 0) == (a[k2 + Ba3 >> 0] | 0) : 0) { + u3 = 0; + j2 = F3; + while (1) { + g3 = j2; + if (g3 >>> 0 > H3 >>> 0) break; + Ha3 = j2; + Ia3 = k2 + (za3 + u3) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + u3 = u3 + 4 | 0; + j2 = g3 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (za3 + u3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + u3 = u3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (u3 >>> 0 <= 2 ? !((u3 | 0) == 2 & v3 >>> 0 < 2) : 0) { + j2 = w2; + break; + } + j2 = (u3 * 540 | 0) + (c[11500 + (v3 << 2) >> 2] | 0) | 0; + if (w2 >>> 0 < j2 >>> 0) { + c[pa3 >> 2] = u3; + c[ea3 >> 2] = h2; + c[fa3 >> 2] = j2; + t3 = u3; + f2 = 1; + } else j2 = w2; + } else j2 = w2; + while (0); + w2 = j2; + v3 = v3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + C3 = D3 << 5; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + j2 = E3 & 65535; + E3 = (E3 & 65535) > 32 ? j2 + -32 | 0 : 0; + d: while (1) { + B3 = K3 + t3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (j2 >>> 0 <= E3 >>> 0) break d; + j2 = j2 + -1 | 0; + g3 = c[n2 + 32768 + ((C3 | j2 & 31) << 2) >> 2] | 0; + z3 = y3 - g3 | 0; + if (z3 >>> 0 > J3 >>> 0) break d; + v3 = g3 & l2; + if (A3) continue; + g3 = v3 + t3 | 0; + if (g3 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + g3 >> 0] | 0)) { + h2 = 0; + g3 = F3; + } else continue; + while (1) { + u3 = g3; + if (u3 >>> 0 > H3 >>> 0) break; + Ha3 = g3; + Ia3 = k2 + (v3 + h2) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + g3 = u3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (v3 + h2) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (h2 >>> 0 <= 3) continue; + g3 = (h2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (w2 >>> 0 < g3 >>> 0) break; + } + c[pa3 >> 2] = h2; + c[ea3 >> 2] = z3; + c[fa3 >> 2] = g3; + t3 = h2; + w2 = g3; + f2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 32768 + ((C3 | Ia3 & 31) << 2) >> 2] = y3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(f2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) f2 = 0; + else { + v3 = 0; + f2 = 0; + h2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 2) break; + Ia3 = b2[21084 + (h2 << 1) >> 1] | 0; + j2 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (Ca3 = j2 & 31, Da3 = j2 >>> 5, Ea3 = (c[11272 + (Ca3 << 2) >> 2] | 0) + (_(Ca3, Da3) | 0) | 0, Ca3 >>> 0 <= L3 >>> 0) : 0) { + t3 = Ea3 + Ca3 | 0; + u3 = 280811 + t3 | 0; + t3 = 280811 + (t3 + -4) | 0; + g3 = 0; + j2 = 280811 + Ea3 | 0; + while (1) { + if (j2 >>> 0 > t3 >>> 0) break; + Ia3 = k2 + (K3 + g3) | 0; + if ((d[j2 >> 0] | d[j2 + 1 >> 0] << 8 | d[j2 + 2 >> 0] << 16 | d[j2 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + j2 = j2 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= u3 >>> 0) break; + if ((a[k2 + (K3 + g3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (!((g3 + 10 | 0) >>> 0 <= Ca3 >>> 0 | (g3 | 0) == 0) ? (Fa3 = J3 + Da3 + 1 + (d[407930 + (Ca3 - g3) >> 0] << d[280786 + Ca3 >> 0]) | 0, Ga3 = (g3 * 540 | 0) + 3840 + (_((aa(Fa3 | 0) | 0) ^ 31, -120) | 0) | 0, Ga3 >>> 0 >= (c[fa3 >> 2] | 0) >>> 0) : 0) { + c[pa3 >> 2] = g3; + c[da3 >> 2] = Ca3 ^ g3; + c[ea3 >> 2] = Fa3; + c[fa3 >> 2] = Ga3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + f2 = 1; + } + } + v3 = v3 + 1 | 0; + h2 = h2 + 1 | 0; + } + f2 = (f2 & 1) != 0; + } + f2 = f2 & 1; + } + if (!(f2 & 1)) { + y3 = m3; + break; + } + if ((c[$2 >> 2] | 0) >>> 0 < ((c[R3 >> 2] | 0) + 700 | 0) >>> 0) { + y3 = m3; + break; + } + f2 = x3 + 1 | 0; + c[oa3 >> 2] = c[pa3 >> 2]; + c[oa3 + 4 >> 2] = c[pa3 + 4 >> 2]; + c[oa3 + 8 >> 2] = c[pa3 + 8 >> 2]; + c[oa3 + 12 >> 2] = c[pa3 + 12 >> 2]; + M2 = M2 + 1 | 0; + if (!((M2 | 0) < 4 & (m3 + 5 | 0) >>> 0 < na2 >>> 0)) { + x3 = f2; + break; + } else { + m3 = y3; + x3 = f2; + } + } + m3 = c[oa3 >> 2] | 0; + u3 = y3 + (m3 << 1) + ja3 | 0; + f2 = c[Q3 >> 2] | 0; + e: do + if (f2 >>> 0 <= (y3 >>> 0 < ma3 >>> 0 ? y3 : ma3) >>> 0) { + g3 = f2 + 3 | 0; + Ia3 = c[o2 >> 2] | 0; + j2 = g3 - Ia3 | 0; + t3 = c[ia3 >> 2] | 0; + g3 = g3 - t3 | 0; + if ((f2 | 0) == (Ia3 | 0)) f2 = 0; + else { + f: do + if ((f2 | 0) != (t3 | 0)) { + do + if (j2 >>> 0 < 7) f2 = 158663784 >>> (j2 << 2) & 15; + else { + if (g3 >>> 0 < 7) { + f2 = 266017486 >>> (g3 << 2) & 15; + break; + } + if ((f2 | 0) == (c[ga3 >> 2] | 0)) { + f2 = 2; + break f; + } + if ((f2 | 0) == (c[ha3 >> 2] | 0)) { + f2 = 3; + break f; + } + f2 = f2 + 15 | 0; + } + while (0); + if (!f2) break e; + } else f2 = 1; + while (0); + c[ha3 >> 2] = c[ga3 >> 2]; + c[ga3 >> 2] = c[ia3 >> 2]; + c[ia3 >> 2] = c[o2 >> 2]; + c[o2 >> 2] = c[Q3 >> 2]; + m3 = c[oa3 >> 2] | 0; + } + } else f2 = f2 + 15 | 0; + while (0); + w2 = O3 + 16 | 0; + Ia3 = c[P3 >> 2] | 0; + j2 = m3 ^ Ia3; + c[O3 >> 2] = x3; + c[O3 + 4 >> 2] = m3 | Ia3 << 24; + m3 = O3 + 14 | 0; + if (f2 >>> 0 < 16) { + f2 = f2 & 65535; + b2[m3 >> 1] = f2; + m3 = 0; + } else { + N3 = f2 + -12 | 0; + Ia3 = ((aa(N3 | 0) | 0) ^ 31) + -1 | 0; + Ha3 = N3 >>> Ia3 & 1; + f2 = ((Ia3 << 1) + 65534 | Ha3) + 16 & 65535; + b2[m3 >> 1] = f2; + m3 = Ia3 << 24 | N3 - ((Ha3 | 2) << Ia3); + } + c[O3 + 8 >> 2] = m3; + h2 = f2 << 16 >> 16 == 0; + v3 = O3 + 12 | 0; + do + if (x3 >>> 0 >= 6) { + if (x3 >>> 0 < 130) { + Ia3 = x3 + -2 | 0; + g3 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + g3 = (g3 << 1) + (Ia3 >>> g3) + 2 & 65535; + break; + } + if (x3 >>> 0 < 2114) { + g3 = ((aa(x3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (x3 >>> 0 < 6210) g3 = 21; + else g3 = x3 >>> 0 < 22594 ? 22 : 23; + } else g3 = x3 & 65535; + while (0); + do + if (j2 >>> 0 >= 10) { + if (j2 >>> 0 < 134) { + Ia3 = j2 + -6 | 0; + f2 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + f2 = (f2 << 1) + (Ia3 >>> f2) + 4 & 65535; + break; + } + if (j2 >>> 0 < 2118) f2 = ((aa(j2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else f2 = 23; + } else f2 = j2 + 65534 & 65535; + while (0); + m3 = f2 & 65535; + j2 = g3 & 65535; + t3 = m3 & 7 | j2 << 3 & 56; + if (h2 & (g3 & 65535) < 8 & (f2 & 65535) < 16) f2 = ((f2 & 65535) < 8 ? t3 : t3 | 64) & 65535; + else f2 = b2[88156 + ((m3 >>> 3) + ((j2 >>> 3) * 3 | 0) << 1) >> 1] | t3 & 65535; + b2[v3 >> 1] = f2; + c[s2 >> 2] = (c[s2 >> 2] | 0) + x3; + f2 = y3 + (c[oa3 >> 2] | 0) | 0; + f2 = f2 >>> 0 < la3 >>> 0 ? f2 : la3; + m3 = y3 + 2 | 0; + while (1) { + if (m3 >>> 0 >= f2 >>> 0) break; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 18; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 32768 + ((e[Ia3 >> 1] & 31 | Ha3 << 5) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 1 | 0; + } + m3 = y3 + (c[oa3 >> 2] | 0) | 0; + O3 = w2; + f2 = 0; + } + c[p2 >> 2] = f2 + L3; + c[r2 >> 2] = (c[r2 >> 2] | 0) + (M2 - q2 >> 4); + i = qa3; + return; + } + function Oa2(f2, g3, h2, j2, k2, l2, m3, n2, o2, p2, q2, r2, s2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + s2 = s2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, oa3 = 0, pa3 = 0, qa3 = 0, ra3 = 0, sa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0, Ha3 = 0, Ia3 = 0; + qa3 = i; + i = i + 32 | 0; + oa3 = qa3 + 16 | 0; + pa3 = qa3; + ma3 = (1 << c[m3 + 8 >> 2]) + -16 | 0; + v3 = c[p2 >> 2] | 0; + na2 = h2 + g3 | 0; + la3 = g3 >>> 0 > 3 ? na2 + -3 | 0 : h2; + ka3 = m3 + 4 | 0; + ja3 = (c[ka3 >> 2] | 0) < 9 ? 64 : 512; + u3 = ja3 + h2 | 0; + if ((((h2 | 0) == 0 ^ 1 | j2 ^ 1) ^ 1) & g3 >>> 0 < 513) { + f2 = 0; + while (1) { + if ((f2 | 0) == (g3 | 0)) break; + ia3 = k2 + f2 | 0; + b2[n2 + ((_(d[ia3 >> 0] | d[ia3 + 1 >> 0] << 8 | d[ia3 + 2 >> 0] << 16 | d[ia3 + 3 >> 0] << 24, 506832829) | 0) >>> 17 << 1) >> 1] = 0; + f2 = f2 + 1 | 0; + } + if (g3) { + a[n2 + 8454144 >> 0] = 0; + t3 = 8; + } + } else { + f2 = n2 + 8454144 | 0; + if (!(a[f2 >> 0] & 1)) t3 = 8; + else { + ac(n2 | 0, 0, 65536) | 0; + a[f2 >> 0] = 0; + t3 = 8; + } + } + if ((t3 | 0) == 8 ? g3 >>> 0 > 2 & h2 >>> 0 > 2 : 0) { + ga3 = h2 + -3 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 65536 + ((e[ia3 >> 1] & 63 | ha3 << 6) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + ia3 = h2 + -2 | 0; + ha3 = k2 + (ia3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ga3 = n2 + (ha3 << 1) | 0; + c[n2 + 65536 + ((e[ga3 >> 1] & 63 | ha3 << 6) << 2) >> 2] = ia3; + b2[ga3 >> 1] = (b2[ga3 >> 1] | 0) + 1 << 16 >> 16; + ga3 = h2 + -1 | 0; + ha3 = k2 + (ga3 & l2) | 0; + ha3 = (_(d[ha3 >> 0] | d[ha3 + 1 >> 0] << 8 | d[ha3 + 2 >> 0] << 16 | d[ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + ia3 = n2 + (ha3 << 1) | 0; + c[n2 + 65536 + ((e[ia3 >> 1] & 63 | ha3 << 6) << 2) >> 2] = ga3; + b2[ia3 >> 1] = (b2[ia3 >> 1] | 0) + 1 << 16 >> 16; + } + P3 = oa3 + 4 | 0; + Q3 = oa3 + 8 | 0; + R3 = oa3 + 12 | 0; + S3 = oa3 + 4 | 0; + T3 = oa3 + 8 | 0; + U3 = oa3 + 12 | 0; + V3 = n2 + 8454152 | 0; + W3 = n2 + 8454148 | 0; + X3 = ja3 << 2; + Y3 = na2 + -4 | 0; + Z3 = na2 + -3 | 0; + $2 = pa3 + 12 | 0; + ba2 = pa3 + 4 | 0; + ca3 = pa3 + 8 | 0; + da3 = pa3 + 4 | 0; + ea3 = pa3 + 8 | 0; + fa3 = pa3 + 12 | 0; + ga3 = o2 + 8 | 0; + ha3 = o2 + 12 | 0; + ia3 = o2 + 4 | 0; + m3 = h2; + O3 = q2; + f2 = v3; + a: while (1) { + M2 = O3; + N3 = u3 + X3 | 0; + b: while (1) { + L3 = na2 - m3 | 0; + if ((m3 + 4 | 0) >>> 0 >= na2 >>> 0) break a; + J3 = m3 >>> 0 < ma3 >>> 0 ? m3 : ma3; + c[oa3 >> 2] = 0; + c[P3 >> 2] = 0; + c[Q3 >> 2] = 0; + c[R3 >> 2] = 4240; + K3 = m3 & l2; + g3 = c[oa3 >> 2] | 0; + c[oa3 >> 2] = 0; + c[S3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + y3 = 4240; + j2 = 0; + x3 = 0; + while (1) { + if ((x3 | 0) == 10) break; + w2 = (c[o2 + (c[11372 + (x3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (x3 << 2) >> 2] | 0) | 0; + t3 = m3 - w2 | 0; + do + if (((!(t3 >>> 0 >= m3 >>> 0 | w2 >>> 0 > J3 >>> 0) ? (ra3 = t3 & l2, sa3 = K3 + g3 | 0, sa3 >>> 0 <= l2 >>> 0) : 0) ? (ta3 = ra3 + g3 | 0, ta3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + sa3 >> 0] | 0) == (a[k2 + ta3 >> 0] | 0) : 0) { + v3 = 0; + t3 = F3; + while (1) { + h2 = t3; + if (h2 >>> 0 > H3 >>> 0) break; + D3 = t3; + E3 = k2 + (ra3 + v3) | 0; + if ((d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24 | 0) != (d[E3 >> 0] | d[E3 + 1 >> 0] << 8 | d[E3 + 2 >> 0] << 16 | d[E3 + 3 >> 0] << 24 | 0)) break; + v3 = v3 + 4 | 0; + t3 = h2 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (ra3 + v3) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + v3 = v3 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (v3 >>> 0 <= 2 ? !((v3 | 0) == 2 & x3 >>> 0 < 2) : 0) { + t3 = y3; + break; + } + t3 = (v3 * 540 | 0) + (c[11500 + (x3 << 2) >> 2] | 0) | 0; + if (y3 >>> 0 < t3 >>> 0) { + c[oa3 >> 2] = v3; + c[T3 >> 2] = w2; + c[U3 >> 2] = t3; + g3 = v3; + j2 = 1; + } else t3 = y3; + } else t3 = y3; + while (0); + y3 = t3; + x3 = x3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + C3 = D3 << 6; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + t3 = E3 & 65535; + E3 = (E3 & 65535) > 64 ? t3 + -64 | 0 : 0; + c: while (1) { + B3 = K3 + g3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (t3 >>> 0 <= E3 >>> 0) break c; + t3 = t3 + -1 | 0; + h2 = c[n2 + 65536 + ((C3 | t3 & 63) << 2) >> 2] | 0; + z3 = m3 - h2 | 0; + if (z3 >>> 0 > J3 >>> 0) break c; + x3 = h2 & l2; + if (A3) continue; + h2 = x3 + g3 | 0; + if (h2 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + h2 >> 0] | 0)) { + w2 = 0; + h2 = F3; + } else continue; + while (1) { + v3 = h2; + if (v3 >>> 0 > H3 >>> 0) break; + Ia3 = h2; + Ha3 = k2 + (x3 + w2) | 0; + if ((d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0) != (d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0)) break; + w2 = w2 + 4 | 0; + h2 = v3 + 4 | 0; + } + while (1) { + if (h2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (x3 + w2) >> 0] | 0) != (a[h2 >> 0] | 0)) break; + w2 = w2 + 1 | 0; + h2 = h2 + 1 | 0; + } + if (w2 >>> 0 <= 3) continue; + h2 = (w2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (y3 >>> 0 < h2 >>> 0) break; + } + c[oa3 >> 2] = w2; + c[T3 >> 2] = z3; + c[U3 >> 2] = h2; + g3 = w2; + y3 = h2; + j2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 65536 + ((C3 | Ia3 & 63) << 2) >> 2] = m3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(j2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) j2 = 0; + else { + x3 = 0; + j2 = 0; + w2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((x3 | 0) == 2) break; + Ia3 = b2[21084 + (w2 << 1) >> 1] | 0; + t3 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (ua3 = t3 & 31, va3 = t3 >>> 5, wa3 = (c[11272 + (ua3 << 2) >> 2] | 0) + (_(ua3, va3) | 0) | 0, ua3 >>> 0 <= L3 >>> 0) : 0) { + g3 = wa3 + ua3 | 0; + v3 = 280811 + g3 | 0; + g3 = 280811 + (g3 + -4) | 0; + h2 = 0; + t3 = 280811 + wa3 | 0; + while (1) { + if (t3 >>> 0 > g3 >>> 0) break; + Ia3 = k2 + (K3 + h2) | 0; + if ((d[t3 >> 0] | d[t3 + 1 >> 0] << 8 | d[t3 + 2 >> 0] << 16 | d[t3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + t3 = t3 + 4 | 0; + } + while (1) { + if (t3 >>> 0 >= v3 >>> 0) break; + if ((a[k2 + (K3 + h2) >> 0] | 0) != (a[t3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + t3 = t3 + 1 | 0; + } + if (!((h2 + 10 | 0) >>> 0 <= ua3 >>> 0 | (h2 | 0) == 0) ? (xa3 = J3 + va3 + 1 + (d[407930 + (ua3 - h2) >> 0] << d[280786 + ua3 >> 0]) | 0, ya3 = (h2 * 540 | 0) + 3840 + (_((aa(xa3 | 0) | 0) ^ 31, -120) | 0) | 0, ya3 >>> 0 >= (c[U3 >> 2] | 0) >>> 0) : 0) { + c[oa3 >> 2] = h2; + c[S3 >> 2] = ua3 ^ h2; + c[T3 >> 2] = xa3; + c[U3 >> 2] = ya3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + j2 = 1; + } + } + x3 = x3 + 1 | 0; + w2 = w2 + 1 | 0; + } + j2 = (j2 & 1) != 0; + } + j2 = j2 & 1; + } + if (j2 & 1) { + M2 = 0; + x3 = f2; + break; + } + f2 = f2 + 1 | 0; + t3 = m3 + 1 | 0; + if (t3 >>> 0 <= u3 >>> 0) { + m3 = t3; + continue; + } + if (t3 >>> 0 > N3 >>> 0) { + j2 = m3 + 17 | 0; + j2 = j2 >>> 0 < Y3 >>> 0 ? j2 : Y3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 65536 + ((e[Ia3 >> 1] & 63 | Ha3 << 6) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 4 | 0; + f2 = f2 + 4 | 0; + } + } else { + j2 = m3 + 9 | 0; + j2 = j2 >>> 0 < Z3 >>> 0 ? j2 : Z3; + m3 = t3; + while (1) { + if (m3 >>> 0 >= j2 >>> 0) continue b; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 65536 + ((e[Ia3 >> 1] & 63 | Ha3 << 6) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 2 | 0; + f2 = f2 + 2 | 0; + } + } + } + while (1) { + L3 = L3 + -1 | 0; + if ((c[ka3 >> 2] | 0) < 5) { + f2 = (c[oa3 >> 2] | 0) + -1 | 0; + f2 = f2 >>> 0 < L3 >>> 0 ? f2 : L3; + } else f2 = 0; + c[pa3 >> 2] = f2; + c[ba2 >> 2] = 0; + c[ca3 >> 2] = 0; + c[$2 >> 2] = 4240; + y3 = m3 + 1 | 0; + J3 = y3 >>> 0 < ma3 >>> 0 ? y3 : ma3; + K3 = y3 & l2; + t3 = c[pa3 >> 2] | 0; + c[pa3 >> 2] = 0; + c[da3 >> 2] = 0; + I3 = k2 + K3 | 0; + H3 = K3 + L3 | 0; + G3 = k2 + H3 | 0; + F3 = I3; + H3 = k2 + (H3 + -4) | 0; + w2 = 4240; + f2 = 0; + v3 = 0; + while (1) { + if ((v3 | 0) == 10) break; + h2 = (c[o2 + (c[11372 + (v3 << 2) >> 2] << 2) >> 2] | 0) + (c[11436 + (v3 << 2) >> 2] | 0) | 0; + j2 = y3 - h2 | 0; + do + if (((!(j2 >>> 0 >= y3 >>> 0 | h2 >>> 0 > J3 >>> 0) ? (za3 = j2 & l2, Aa3 = K3 + t3 | 0, Aa3 >>> 0 <= l2 >>> 0) : 0) ? (Ba3 = za3 + t3 | 0, Ba3 >>> 0 <= l2 >>> 0) : 0) ? (a[k2 + Aa3 >> 0] | 0) == (a[k2 + Ba3 >> 0] | 0) : 0) { + u3 = 0; + j2 = F3; + while (1) { + g3 = j2; + if (g3 >>> 0 > H3 >>> 0) break; + Ha3 = j2; + Ia3 = k2 + (za3 + u3) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + u3 = u3 + 4 | 0; + j2 = g3 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (za3 + u3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + u3 = u3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (u3 >>> 0 <= 2 ? !((u3 | 0) == 2 & v3 >>> 0 < 2) : 0) { + j2 = w2; + break; + } + j2 = (u3 * 540 | 0) + (c[11500 + (v3 << 2) >> 2] | 0) | 0; + if (w2 >>> 0 < j2 >>> 0) { + c[pa3 >> 2] = u3; + c[ea3 >> 2] = h2; + c[fa3 >> 2] = j2; + t3 = u3; + f2 = 1; + } else j2 = w2; + } else j2 = w2; + while (0); + w2 = j2; + v3 = v3 + 1 | 0; + } + D3 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + C3 = D3 << 6; + D3 = n2 + (D3 << 1) | 0; + E3 = b2[D3 >> 1] | 0; + j2 = E3 & 65535; + E3 = (E3 & 65535) > 64 ? j2 + -64 | 0 : 0; + d: while (1) { + B3 = K3 + t3 | 0; + A3 = B3 >>> 0 > l2 >>> 0; + B3 = k2 + B3 | 0; + while (1) { + if (j2 >>> 0 <= E3 >>> 0) break d; + j2 = j2 + -1 | 0; + g3 = c[n2 + 65536 + ((C3 | j2 & 63) << 2) >> 2] | 0; + z3 = y3 - g3 | 0; + if (z3 >>> 0 > J3 >>> 0) break d; + v3 = g3 & l2; + if (A3) continue; + g3 = v3 + t3 | 0; + if (g3 >>> 0 > l2 >>> 0) continue; + if ((a[B3 >> 0] | 0) == (a[k2 + g3 >> 0] | 0)) { + h2 = 0; + g3 = F3; + } else continue; + while (1) { + u3 = g3; + if (u3 >>> 0 > H3 >>> 0) break; + Ha3 = g3; + Ia3 = k2 + (v3 + h2) | 0; + if ((d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + h2 = h2 + 4 | 0; + g3 = u3 + 4 | 0; + } + while (1) { + if (g3 >>> 0 >= G3 >>> 0) break; + if ((a[k2 + (v3 + h2) >> 0] | 0) != (a[g3 >> 0] | 0)) break; + h2 = h2 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (h2 >>> 0 <= 3) continue; + g3 = (h2 * 540 | 0) + 3840 + (_((aa(z3 | 0) | 0) ^ 31, -120) | 0) | 0; + if (w2 >>> 0 < g3 >>> 0) break; + } + c[pa3 >> 2] = h2; + c[ea3 >> 2] = z3; + c[fa3 >> 2] = g3; + t3 = h2; + w2 = g3; + f2 = 1; + } + Ia3 = b2[D3 >> 1] | 0; + c[n2 + 65536 + ((C3 | Ia3 & 63) << 2) >> 2] = y3; + b2[D3 >> 1] = Ia3 + 1 << 16 >> 16; + if (!(f2 & 1)) { + if ((c[V3 >> 2] | 0) >>> 0 < (c[W3 >> 2] | 0) >>> 7 >>> 0) f2 = 0; + else { + v3 = 0; + f2 = 0; + h2 = (_(d[I3 >> 0] | d[I3 + 1 >> 0] << 8 | d[I3 + 2 >> 0] << 16 | d[I3 + 3 >> 0] << 24, 506832829) | 0) >>> 18 << 1; + while (1) { + if ((v3 | 0) == 2) break; + Ia3 = b2[21084 + (h2 << 1) >> 1] | 0; + j2 = Ia3 & 65535; + c[W3 >> 2] = (c[W3 >> 2] | 0) + 1; + if (Ia3 << 16 >> 16 != 0 ? (Ca3 = j2 & 31, Da3 = j2 >>> 5, Ea3 = (c[11272 + (Ca3 << 2) >> 2] | 0) + (_(Ca3, Da3) | 0) | 0, Ca3 >>> 0 <= L3 >>> 0) : 0) { + t3 = Ea3 + Ca3 | 0; + u3 = 280811 + t3 | 0; + t3 = 280811 + (t3 + -4) | 0; + g3 = 0; + j2 = 280811 + Ea3 | 0; + while (1) { + if (j2 >>> 0 > t3 >>> 0) break; + Ia3 = k2 + (K3 + g3) | 0; + if ((d[j2 >> 0] | d[j2 + 1 >> 0] << 8 | d[j2 + 2 >> 0] << 16 | d[j2 + 3 >> 0] << 24 | 0) != (d[Ia3 >> 0] | d[Ia3 + 1 >> 0] << 8 | d[Ia3 + 2 >> 0] << 16 | d[Ia3 + 3 >> 0] << 24 | 0)) break; + g3 = g3 + 4 | 0; + j2 = j2 + 4 | 0; + } + while (1) { + if (j2 >>> 0 >= u3 >>> 0) break; + if ((a[k2 + (K3 + g3) >> 0] | 0) != (a[j2 >> 0] | 0)) break; + g3 = g3 + 1 | 0; + j2 = j2 + 1 | 0; + } + if (!((g3 + 10 | 0) >>> 0 <= Ca3 >>> 0 | (g3 | 0) == 0) ? (Fa3 = J3 + Da3 + 1 + (d[407930 + (Ca3 - g3) >> 0] << d[280786 + Ca3 >> 0]) | 0, Ga3 = (g3 * 540 | 0) + 3840 + (_((aa(Fa3 | 0) | 0) ^ 31, -120) | 0) | 0, Ga3 >>> 0 >= (c[fa3 >> 2] | 0) >>> 0) : 0) { + c[pa3 >> 2] = g3; + c[da3 >> 2] = Ca3 ^ g3; + c[ea3 >> 2] = Fa3; + c[fa3 >> 2] = Ga3; + c[V3 >> 2] = (c[V3 >> 2] | 0) + 1; + f2 = 1; + } + } + v3 = v3 + 1 | 0; + h2 = h2 + 1 | 0; + } + f2 = (f2 & 1) != 0; + } + f2 = f2 & 1; + } + if (!(f2 & 1)) { + y3 = m3; + break; + } + if ((c[$2 >> 2] | 0) >>> 0 < ((c[R3 >> 2] | 0) + 700 | 0) >>> 0) { + y3 = m3; + break; + } + f2 = x3 + 1 | 0; + c[oa3 >> 2] = c[pa3 >> 2]; + c[oa3 + 4 >> 2] = c[pa3 + 4 >> 2]; + c[oa3 + 8 >> 2] = c[pa3 + 8 >> 2]; + c[oa3 + 12 >> 2] = c[pa3 + 12 >> 2]; + M2 = M2 + 1 | 0; + if (!((M2 | 0) < 4 & (m3 + 5 | 0) >>> 0 < na2 >>> 0)) { + x3 = f2; + break; + } else { + m3 = y3; + x3 = f2; + } + } + m3 = c[oa3 >> 2] | 0; + u3 = y3 + (m3 << 1) + ja3 | 0; + f2 = c[Q3 >> 2] | 0; + e: do + if (f2 >>> 0 <= (y3 >>> 0 < ma3 >>> 0 ? y3 : ma3) >>> 0) { + g3 = f2 + 3 | 0; + Ia3 = c[o2 >> 2] | 0; + j2 = g3 - Ia3 | 0; + t3 = c[ia3 >> 2] | 0; + g3 = g3 - t3 | 0; + if ((f2 | 0) == (Ia3 | 0)) f2 = 0; + else { + f: do + if ((f2 | 0) != (t3 | 0)) { + do + if (j2 >>> 0 < 7) f2 = 158663784 >>> (j2 << 2) & 15; + else { + if (g3 >>> 0 < 7) { + f2 = 266017486 >>> (g3 << 2) & 15; + break; + } + if ((f2 | 0) == (c[ga3 >> 2] | 0)) { + f2 = 2; + break f; + } + if ((f2 | 0) == (c[ha3 >> 2] | 0)) { + f2 = 3; + break f; + } + f2 = f2 + 15 | 0; + } + while (0); + if (!f2) break e; + } else f2 = 1; + while (0); + c[ha3 >> 2] = c[ga3 >> 2]; + c[ga3 >> 2] = c[ia3 >> 2]; + c[ia3 >> 2] = c[o2 >> 2]; + c[o2 >> 2] = c[Q3 >> 2]; + m3 = c[oa3 >> 2] | 0; + } + } else f2 = f2 + 15 | 0; + while (0); + w2 = O3 + 16 | 0; + Ia3 = c[P3 >> 2] | 0; + j2 = m3 ^ Ia3; + c[O3 >> 2] = x3; + c[O3 + 4 >> 2] = m3 | Ia3 << 24; + m3 = O3 + 14 | 0; + if (f2 >>> 0 < 16) { + f2 = f2 & 65535; + b2[m3 >> 1] = f2; + m3 = 0; + } else { + N3 = f2 + -12 | 0; + Ia3 = ((aa(N3 | 0) | 0) ^ 31) + -1 | 0; + Ha3 = N3 >>> Ia3 & 1; + f2 = ((Ia3 << 1) + 65534 | Ha3) + 16 & 65535; + b2[m3 >> 1] = f2; + m3 = Ia3 << 24 | N3 - ((Ha3 | 2) << Ia3); + } + c[O3 + 8 >> 2] = m3; + h2 = f2 << 16 >> 16 == 0; + v3 = O3 + 12 | 0; + do + if (x3 >>> 0 >= 6) { + if (x3 >>> 0 < 130) { + Ia3 = x3 + -2 | 0; + g3 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + g3 = (g3 << 1) + (Ia3 >>> g3) + 2 & 65535; + break; + } + if (x3 >>> 0 < 2114) { + g3 = ((aa(x3 + -66 | 0) | 0) ^ 31) + 10 & 65535; + break; + } + if (x3 >>> 0 < 6210) g3 = 21; + else g3 = x3 >>> 0 < 22594 ? 22 : 23; + } else g3 = x3 & 65535; + while (0); + do + if (j2 >>> 0 >= 10) { + if (j2 >>> 0 < 134) { + Ia3 = j2 + -6 | 0; + f2 = ((aa(Ia3 | 0) | 0) ^ 31) + -1 | 0; + f2 = (f2 << 1) + (Ia3 >>> f2) + 4 & 65535; + break; + } + if (j2 >>> 0 < 2118) f2 = ((aa(j2 + -70 | 0) | 0) ^ 31) + 12 & 65535; + else f2 = 23; + } else f2 = j2 + 65534 & 65535; + while (0); + m3 = f2 & 65535; + j2 = g3 & 65535; + t3 = m3 & 7 | j2 << 3 & 56; + if (h2 & (g3 & 65535) < 8 & (f2 & 65535) < 16) f2 = ((f2 & 65535) < 8 ? t3 : t3 | 64) & 65535; + else f2 = b2[88156 + ((m3 >>> 3) + ((j2 >>> 3) * 3 | 0) << 1) >> 1] | t3 & 65535; + b2[v3 >> 1] = f2; + c[s2 >> 2] = (c[s2 >> 2] | 0) + x3; + f2 = y3 + (c[oa3 >> 2] | 0) | 0; + f2 = f2 >>> 0 < la3 >>> 0 ? f2 : la3; + m3 = y3 + 2 | 0; + while (1) { + if (m3 >>> 0 >= f2 >>> 0) break; + Ha3 = k2 + (m3 & l2) | 0; + Ha3 = (_(d[Ha3 >> 0] | d[Ha3 + 1 >> 0] << 8 | d[Ha3 + 2 >> 0] << 16 | d[Ha3 + 3 >> 0] << 24, 506832829) | 0) >>> 17; + Ia3 = n2 + (Ha3 << 1) | 0; + c[n2 + 65536 + ((e[Ia3 >> 1] & 63 | Ha3 << 6) << 2) >> 2] = m3; + b2[Ia3 >> 1] = (b2[Ia3 >> 1] | 0) + 1 << 16 >> 16; + m3 = m3 + 1 | 0; + } + m3 = y3 + (c[oa3 >> 2] | 0) | 0; + O3 = w2; + f2 = 0; + } + c[p2 >> 2] = f2 + L3; + c[r2 >> 2] = (c[r2 >> 2] | 0) + (M2 - q2 >> 4); + i = qa3; + return; + } + function Db(f2, j2, k2, l2, m3, n2, o2, p2, q2, r2, t3, u3, v3, w2, x3, y3, z3) { + f2 = f2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + t3 = t3 | 0; + u3 = u3 | 0; + v3 = v3 | 0; + w2 = w2 | 0; + x3 = x3 | 0; + y3 = y3 | 0; + z3 = z3 | 0; + var A3 = 0, B3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0, $2 = 0, ba2 = 0, ca3 = 0, da3 = 0, ea3 = 0, fa3 = 0, ga3 = 0, ha3 = 0, ia3 = 0, ja3 = 0, ka3 = 0, la3 = 0, ma3 = 0, na2 = 0, qa3 = 0, ta3 = 0, ua3 = 0, va3 = 0, wa3 = 0, xa3 = 0, ya3 = 0, za3 = 0, Aa3 = 0, Ba3 = 0, Ca3 = 0, Da3 = 0, Ea3 = 0, Fa3 = 0, Ga3 = 0, Ha3 = 0, Ia3 = 0; + Ga3 = i; + i = i + 12768 | 0; + Ca3 = Ga3 + 7760 | 0; + ya3 = Ga3 + 4928 | 0; + za3 = Ga3 + 2096 | 0; + O3 = Ga3 + 12504 | 0; + N3 = Ga3 + 10968 | 0; + B3 = Ga3; + E3 = Ga3 + 12248 | 0; + D3 = Ga3 + 10456 | 0; + J3 = Ga3 + 11544 | 0; + I3 = Ga3 + 9048 | 0; + L3 = Ga3 + 11480 | 0; + K3 = Ga3 + 8920 | 0; + Ba3 = Ga3 + 8808 | 0; + Q3 = Ga3 + 8804 | 0; + P3 = Ga3 + 8800 | 0; + if (m3 >>> 0 > 0 | (m3 | 0) == 0 & l2 >>> 0 > 3221225471) { + Fa3 = bc(l2 | 0, m3 | 0, 30) | 0; + Fa3 = l2 & 1073741823 | ((Fa3 & 1 ^ 1) << 30) + 1073741824; + } else Fa3 = l2; + if (!n2) { + k2 = c[y3 >> 2] | 0; + z3 = z3 + (k2 >>> 3) | 0; + u3 = d[z3 >> 0] | 0; + k2 = cc(3, 0, k2 & 7 | 0) | 0; + w2 = C2; + k2 = u3 | k2; + u3 = z3; + a[u3 >> 0] = k2; + a[u3 + 1 >> 0] = k2 >> 8; + a[u3 + 2 >> 0] = k2 >> 16; + a[u3 + 3 >> 0] = k2 >> 24; + z3 = z3 + 4 | 0; + a[z3 >> 0] = w2; + a[z3 + 1 >> 0] = w2 >> 8; + a[z3 + 2 >> 0] = w2 >> 16; + a[z3 + 3 >> 0] = w2 >> 24; + c[y3 >> 2] = (c[y3 >> 2] | 0) + 9 & -8; + i = Ga3; + return; + } + if (!(Fb(j2, k2, l2, m3, n2, t3, u3) | 0)) { + c[x3 >> 2] = c[w2 >> 2]; + c[x3 + 4 >> 2] = c[w2 + 4 >> 2]; + c[x3 + 8 >> 2] = c[w2 + 8 >> 2]; + c[x3 + 12 >> 2] = c[w2 + 12 >> 2]; + bb2(o2, j2, Fa3, k2, n2, y3, z3); + i = Ga3; + return; + } + Da3 = a[z3 >> 0] | 0; + Ea3 = c[y3 >> 2] | 0; + Aa3 = p2 + 4 | 0; + l2 = c[Aa3 >> 2] | 0; + if ((l2 | 0) > 9) if ((c[p2 >> 2] | 0) == 2) { + A3 = 0; + while (1) { + if ((A3 | 0) == (u3 | 0)) break; + do + if ((c[v3 + (A3 << 4) + 4 >> 2] & 16777215 | 0) != 0 ? (e[v3 + (A3 << 4) + 12 >> 1] | 0) > 127 : 0) { + t3 = v3 + (A3 << 4) + 14 | 0; + l2 = b2[t3 >> 1] | 0; + if ((l2 & 65535) >= 16) { + m3 = v3 + (A3 << 4) + 8 | 0; + xa3 = c[m3 >> 2] | 0; + wa3 = xa3 >>> 24; + l2 = ((l2 & 65535) + -12 - (wa3 << 1) << wa3) + (xa3 & 16777215) + 12 | 0; + if (l2 >>> 0 >= 28) { + va3 = l2 + -20 | 0; + ua3 = (aa(va3 | 0) | 0) ^ 31; + xa3 = ua3 + -1 | 0; + wa3 = va3 >>> xa3 & 1; + ua3 = ua3 + -2 | 0; + b2[t3 >> 1] = (((ua3 << 1) + 32766 | wa3) << 1) + 28 | va3 & 1; + c[m3 >> 2] = ua3 << 24 | (va3 - ((wa3 | 2) << xa3) | 0) >>> 1; + break; + } + } else { + m3 = v3 + (A3 << 4) + 8 | 0; + l2 = l2 & 65535; + } + b2[t3 >> 1] = l2; + c[m3 >> 2] = 0; + } + while (0); + A3 = A3 + 1 | 0; + } + l2 = c[Aa3 >> 2] | 0; + m3 = 1; + t3 = 12; + H3 = 19; + } else { + xa3 = 0; + wa3 = 0; + H3 = 38; + } + else { + m3 = 0; + t3 = 0; + H3 = 19; + } + do + if ((H3 | 0) == 19) { + if ((l2 | 0) >= 3) { + if ((l2 | 0) >= 4) { + xa3 = m3; + wa3 = t3; + H3 = 38; + break; + } + db(o2, n2, y3, z3); + ac(Ca3 | 0, 0, 1028) | 0; + h[Ca3 + 1032 >> 3] = s; + ac(ya3 | 0, 0, 2820) | 0; + h[ya3 + 2824 >> 3] = s; + ac(za3 | 0, 0, 2084) | 0; + h[za3 + 2088 >> 3] = s; + jb(j2, Fa3, k2, v3, u3, Ca3, ya3, za3); + l2 = z3 + ((c[y3 >> 2] | 0) >>> 3) | 0; + r2 = d[l2 >> 0] | 0; + m3 = l2; + a[m3 >> 0] = r2; + a[m3 + 1 >> 0] = r2 >> 8; + a[m3 + 2 >> 0] = r2 >> 16; + a[m3 + 3 >> 0] = r2 >> 24; + l2 = l2 + 4 | 0; + a[l2 >> 0] = 0; + a[l2 + 1 >> 0] = 0; + a[l2 + 2 >> 0] = 0; + a[l2 + 3 >> 0] = 0; + c[y3 >> 2] = (c[y3 >> 2] | 0) + 13; + l2 = f2 + 8 | 0; + m3 = sa2[c[f2 >> 2] & 1](c[l2 >> 2] | 0, 11272) | 0; + if (!m3) oa2(1); + kb(Ca3, 256, m3, O3, N3, y3, z3); + kb(ya3, 704, m3, J3, I3, y3, z3); + kb(za3, 64, m3, L3, K3, y3, z3); + ra2[c[f2 + 4 >> 2] & 1](c[l2 >> 2] | 0, m3); + lb(j2, Fa3, k2, v3, u3, O3, N3, J3, I3, L3, K3, y3, z3); + if (o2) { + u3 = (c[y3 >> 2] | 0) + 7 | 0; + c[y3 >> 2] = u3 & -8; + a[z3 + (u3 >>> 3) >> 0] = 0; + } + break; + } + db(o2, n2, y3, z3); + r2 = z3 + ((c[y3 >> 2] | 0) >>> 3) | 0; + Ba3 = d[r2 >> 0] | 0; + q2 = r2; + a[q2 >> 0] = Ba3; + a[q2 + 1 >> 0] = Ba3 >> 8; + a[q2 + 2 >> 0] = Ba3 >> 16; + a[q2 + 3 >> 0] = Ba3 >> 24; + r2 = r2 + 4 | 0; + a[r2 >> 0] = 0; + a[r2 + 1 >> 0] = 0; + a[r2 + 2 >> 0] = 0; + a[r2 + 3 >> 0] = 0; + c[y3 >> 2] = (c[y3 >> 2] | 0) + 13; + if (u3 >>> 0 < 129) { + ac(Ca3 | 0, 0, 1024) | 0; + t3 = 0; + A3 = Fa3; + D3 = 0; + while (1) { + if ((D3 | 0) == (u3 | 0)) break; + l2 = c[v3 + (D3 << 4) >> 2] | 0; + m3 = c[v3 + (D3 << 4) + 4 >> 2] | 0; + B3 = A3; + E3 = l2; + while (1) { + if (!E3) break; + r2 = Ca3 + ((d[j2 + (B3 & k2) >> 0] | 0) << 2) | 0; + c[r2 >> 2] = (c[r2 >> 2] | 0) + 1; + B3 = B3 + 1 | 0; + E3 = E3 + -1 | 0; + } + t3 = t3 + l2 | 0; + A3 = A3 + l2 + (m3 & 16777215) | 0; + D3 = D3 + 1 | 0; + } + $a2(f2, Ca3, t3, 8, O3, N3, y3, z3); + Ca3 = c[y3 >> 2] | 0; + q2 = z3 + (Ca3 >>> 3) | 0; + f2 = d[q2 >> 0] | 0; + Ca3 = cc(372273155, 9593412, Ca3 & 7 | 0) | 0; + r2 = C2; + Ca3 = f2 | Ca3; + f2 = q2; + a[f2 >> 0] = Ca3; + a[f2 + 1 >> 0] = Ca3 >> 8; + a[f2 + 2 >> 0] = Ca3 >> 16; + a[f2 + 3 >> 0] = Ca3 >> 24; + q2 = q2 + 4 | 0; + a[q2 >> 0] = r2; + a[q2 + 1 >> 0] = r2 >> 8; + a[q2 + 2 >> 0] = r2 >> 16; + a[q2 + 3 >> 0] = r2 >> 24; + q2 = (c[y3 >> 2] | 0) + 56 | 0; + c[y3 >> 2] = q2; + q2 = z3 + (q2 >>> 3) | 0; + r2 = d[q2 >> 0] | 0; + f2 = q2; + a[f2 >> 0] = r2; + a[f2 + 1 >> 0] = r2 >> 8; + a[f2 + 2 >> 0] = r2 >> 16; + a[f2 + 3 >> 0] = r2 >> 24; + q2 = q2 + 4 | 0; + a[q2 >> 0] = 0; + a[q2 + 1 >> 0] = 0; + a[q2 + 2 >> 0] = 0; + a[q2 + 3 >> 0] = 0; + q2 = (c[y3 >> 2] | 0) + 3 | 0; + c[y3 >> 2] = q2; + f2 = z3 + (q2 >>> 3) | 0; + r2 = d[f2 >> 0] | 0; + q2 = cc(57269251, 0, q2 & 7 | 0) | 0; + Ca3 = C2; + q2 = r2 | q2; + r2 = f2; + a[r2 >> 0] = q2; + a[r2 + 1 >> 0] = q2 >> 8; + a[r2 + 2 >> 0] = q2 >> 16; + a[r2 + 3 >> 0] = q2 >> 24; + f2 = f2 + 4 | 0; + a[f2 >> 0] = Ca3; + a[f2 + 1 >> 0] = Ca3 >> 8; + a[f2 + 2 >> 0] = Ca3 >> 16; + a[f2 + 3 >> 0] = Ca3 >> 24; + c[y3 >> 2] = (c[y3 >> 2] | 0) + 28; + lb(j2, Fa3, k2, v3, u3, O3, N3, 404412, 86620, 405116, 88028, y3, z3); + } else { + ac(ya3 | 0, 0, 1028) | 0; + h[ya3 + 1032 >> 3] = s; + ac(za3 | 0, 0, 2820) | 0; + h[za3 + 2824 >> 3] = s; + ac(B3 | 0, 0, 2084) | 0; + h[B3 + 2088 >> 3] = s; + jb(j2, Fa3, k2, v3, u3, ya3, za3, B3); + $a2(f2, ya3, c[ya3 + 1024 >> 2] | 0, 8, E3, D3, y3, z3); + $a2(f2, za3, c[za3 + 2816 >> 2] | 0, 10, J3, I3, y3, z3); + $a2(f2, B3, c[B3 + 2080 >> 2] | 0, 6, L3, K3, y3, z3); + lb(j2, Fa3, k2, v3, u3, E3, D3, J3, I3, L3, K3, y3, z3); + } + if (o2) { + u3 = (c[y3 >> 2] | 0) + 7 | 0; + c[y3 >> 2] = u3 & -8; + a[z3 + (u3 >>> 3) >> 0] = 0; + } + } + while (0); + if ((H3 | 0) == 38) { + ha3 = Ba3 + 8 | 0; + ia3 = Ba3 + 12 | 0; + K3 = Ba3 + 24 | 0; + ga3 = Ba3 + 28 | 0; + c[Ba3 >> 2] = 0; + c[Ba3 + 4 >> 2] = 0; + c[Ba3 + 8 >> 2] = 0; + c[Ba3 + 12 >> 2] = 0; + c[Ba3 + 16 >> 2] = 0; + c[Ba3 + 20 >> 2] = 0; + c[Ba3 + 24 >> 2] = 0; + ja3 = Ba3 + 32 | 0; + ka3 = Ba3 + 36 | 0; + L3 = Ba3 + 48 | 0; + c[ga3 >> 2] = 0; + c[ga3 + 4 >> 2] = 0; + c[ga3 + 8 >> 2] = 0; + c[ga3 + 12 >> 2] = 0; + c[ga3 + 16 >> 2] = 0; + c[L3 >> 2] = 0; + ga3 = Ba3 + 52 | 0; + la3 = Ba3 + 56 | 0; + ma3 = Ba3 + 60 | 0; + na2 = Ba3 + 72 | 0; + c[ga3 >> 2] = 0; + c[ga3 + 4 >> 2] = 0; + c[ga3 + 8 >> 2] = 0; + c[ga3 + 12 >> 2] = 0; + c[ga3 + 16 >> 2] = 0; + ga3 = Ba3 + 76 | 0; + qa3 = Ba3 + 80 | 0; + ta3 = Ba3 + 88 | 0; + J3 = Ba3 + 92 | 0; + ua3 = Ba3 + 96 | 0; + N3 = Ba3 + 100 | 0; + va3 = Ba3 + 104 | 0; + O3 = Ba3 + 108 | 0; + m3 = (l2 | 0) < 10; + t3 = na2; + A3 = t3 + 40 | 0; + do { + c[t3 >> 2] = 0; + t3 = t3 + 4 | 0; + } while ((t3 | 0) < (A3 | 0)); + do + if (m3) { + c[Q3 >> 2] = 1; + c[P3 >> 2] = 0; + if (!((l2 | 0) < 5 | n2 >>> 0 < 64)) { + D3 = Fa3 + n2 | 0; + t3 = za3; + A3 = t3 + 36 | 0; + do { + c[t3 >> 2] = 0; + t3 = t3 + 4 | 0; + } while ((t3 | 0) < (A3 | 0)); + B3 = Fa3; + while (1) { + A3 = B3 + 64 | 0; + if (A3 >>> 0 > D3 >>> 0) break; + t3 = d[j2 + (B3 & k2) >> 0] | 0; + m3 = B3; + while (1) { + m3 = m3 + 1 | 0; + if (m3 >>> 0 >= A3 >>> 0) break; + fa3 = d[j2 + (m3 & k2) >> 0] | 0; + ea3 = za3 + (((c[18900 + (t3 >>> 6 << 2) >> 2] | 0) * 3 | 0) + (c[18900 + (fa3 >>> 6 << 2) >> 2] | 0) << 2) | 0; + c[ea3 >> 2] = (c[ea3 >> 2] | 0) + 1; + t3 = fa3; + } + B3 = B3 + 4096 | 0; + } + c[Ca3 >> 2] = 0; + c[Ca3 + 4 >> 2] = 0; + c[Ca3 + 8 >> 2] = 0; + c[ya3 >> 2] = 0; + c[ya3 + 4 >> 2] = 0; + c[ya3 + 8 >> 2] = 0; + c[ya3 + 12 >> 2] = 0; + c[ya3 + 16 >> 2] = 0; + c[ya3 + 20 >> 2] = 0; + m3 = 0; + I3 = 0; + while (1) { + if ((m3 | 0) == 9) break; + fa3 = c[za3 + (m3 << 2) >> 2] | 0; + ea3 = Ca3 + (((m3 >>> 0) % 3 | 0) << 2) | 0; + c[ea3 >> 2] = (c[ea3 >> 2] | 0) + fa3; + ea3 = ya3 + ((m3 >>> 0 > 5 ? m3 + -6 | 0 : m3) << 2) | 0; + c[ea3 >> 2] = (c[ea3 >> 2] | 0) + fa3; + m3 = m3 + 1 | 0; + I3 = I3 + fa3 | 0; + } + D3 = Ca3 + 12 | 0; + B3 = Ca3; + M2 = 0; + m3 = 0; + while (1) { + A3 = B3 + 4 | 0; + t3 = c[B3 >> 2] | 0; + E3 = m3 + t3 | 0; + G3 = +(t3 >>> 0); + if (t3 >>> 0 < 256) F3 = +g2[19516 + (t3 << 2) >> 2]; + else F3 = +Xb(G3); + M2 = M2 - G3 * F3; + if (A3 >>> 0 >= D3 >>> 0) break; + m3 = c[A3 >> 2] | 0; + F3 = +(m3 >>> 0); + if (m3 >>> 0 < 256) G3 = +g2[19516 + (m3 << 2) >> 2]; + else G3 = +Xb(F3); + B3 = B3 + 8 | 0; + M2 = M2 - F3 * G3; + m3 = E3 + m3 | 0; + } + if (!E3) ba2 = M2; + else { + G3 = +(E3 >>> 0); + if (E3 >>> 0 < 256) F3 = +g2[19516 + (E3 << 2) >> 2]; + else F3 = +Xb(G3); + ba2 = M2 + G3 * F3; + } + H3 = ya3 + 12 | 0; + B3 = ya3; + M2 = 0; + m3 = 0; + while (1) { + A3 = B3 + 4 | 0; + t3 = c[B3 >> 2] | 0; + D3 = m3 + t3 | 0; + G3 = +(t3 >>> 0); + if (t3 >>> 0 < 256) F3 = +g2[19516 + (t3 << 2) >> 2]; + else F3 = +Xb(G3); + M2 = M2 - G3 * F3; + if (A3 >>> 0 >= H3 >>> 0) break; + m3 = c[A3 >> 2] | 0; + F3 = +(m3 >>> 0); + if (m3 >>> 0 < 256) G3 = +g2[19516 + (m3 << 2) >> 2]; + else G3 = +Xb(F3); + B3 = B3 + 8 | 0; + M2 = M2 - F3 * G3; + m3 = D3 + m3 | 0; + } + if (!D3) Z3 = M2; + else { + G3 = +(D3 >>> 0); + if (D3 >>> 0 < 256) F3 = +g2[19516 + (D3 << 2) >> 2]; + else F3 = +Xb(G3); + Z3 = M2 + G3 * F3; + } + E3 = ya3 + 24 | 0; + B3 = H3; + M2 = 0; + m3 = 0; + while (1) { + A3 = B3 + 4 | 0; + t3 = c[B3 >> 2] | 0; + D3 = m3 + t3 | 0; + G3 = +(t3 >>> 0); + if (t3 >>> 0 < 256) F3 = +g2[19516 + (t3 << 2) >> 2]; + else F3 = +Xb(G3); + M2 = M2 - G3 * F3; + if (A3 >>> 0 >= E3 >>> 0) break; + m3 = c[A3 >> 2] | 0; + F3 = +(m3 >>> 0); + if (m3 >>> 0 < 256) G3 = +g2[19516 + (m3 << 2) >> 2]; + else G3 = +Xb(F3); + B3 = B3 + 8 | 0; + M2 = M2 - F3 * G3; + m3 = D3 + m3 | 0; + } + if (!D3) R3 = M2; + else { + G3 = +(D3 >>> 0); + if (D3 >>> 0 < 256) F3 = +g2[19516 + (D3 << 2) >> 2]; + else F3 = +Xb(G3); + R3 = M2 + G3 * F3; + } + S3 = 0; + E3 = 0; + while (1) { + if ((E3 | 0) == 3) break; + t3 = E3 * 3 | 0; + A3 = za3 + (t3 + 3 << 2) | 0; + t3 = za3 + (t3 << 2) | 0; + M2 = 0; + m3 = 0; + while (1) { + B3 = t3 + 4 | 0; + t3 = c[t3 >> 2] | 0; + D3 = m3 + t3 | 0; + G3 = +(t3 >>> 0); + if (t3 >>> 0 < 256) F3 = +g2[19516 + (t3 << 2) >> 2]; + else F3 = +Xb(G3); + F3 = M2 - G3 * F3; + if (B3 >>> 0 >= A3 >>> 0) break; + m3 = c[B3 >> 2] | 0; + G3 = +(m3 >>> 0); + if (m3 >>> 0 < 256) M2 = +g2[19516 + (m3 << 2) >> 2]; + else M2 = +Xb(G3); + t3 = B3 + 4 | 0; + M2 = F3 - G3 * M2; + m3 = D3 + m3 | 0; + } + if (D3) { + M2 = +(D3 >>> 0); + if (D3 >>> 0 < 256) G3 = +g2[19516 + (D3 << 2) >> 2]; + else G3 = +Xb(M2); + F3 = F3 + M2 * G3; + } + S3 = S3 + F3; + E3 = E3 + 1 | 0; + } + if (!I3) pa2(406445, 406053, 339, 406456); + F3 = 1 / +(I3 >>> 0); + ba2 = ba2 * F3; + G3 = (Z3 + R3) * F3; + F3 = (l2 | 0) < 7 ? ba2 * 10 : S3 * F3; + do + if (!(ba2 - G3 < 0.2 & ba2 - F3 < 0.2)) if (G3 - F3 < 0.02) { + c[Q3 >> 2] = 2; + c[P3 >> 2] = 18916; + break; + } else { + c[Q3 >> 2] = 3; + c[P3 >> 2] = 19172; + break; + } + else c[Q3 >> 2] = 1; + while (0); + fa3 = c[P3 >> 2] | 0; + W3 = fa3; + if (fa3) { + fa3 = c[Q3 >> 2] | 0; + l2 = 0; + m3 = 0; + while (1) { + if ((m3 | 0) == (u3 | 0)) break; + l2 = l2 + (c[v3 + (m3 << 4) >> 2] | 0) | 0; + m3 = m3 + 1 | 0; + } + E3 = (l2 >>> 9) + 1 | 0; + c[Ca3 >> 2] = 256; + c[Ca3 + 4 >> 2] = fa3; + H3 = 256 / (fa3 >>> 0) | 0; + c[Ca3 + 8 >> 2] = H3; + c[Ca3 + 12 >> 2] = 512; + h[Ca3 + 16 >> 3] = 400; + c[Ca3 + 24 >> 2] = 0; + c[Ca3 + 28 >> 2] = Ba3; + c[Ca3 + 36 >> 2] = J3; + ca3 = Ca3 + 40 | 0; + c[ca3 >> 2] = 512; + da3 = Ca3 + 44 | 0; + c[da3 >> 2] = 0; + ea3 = Ca3 + 48 | 0; + c[ea3 >> 2] = 0; + c[Ca3 + 64 >> 2] = 0; + H3 = H3 + 1 | 0; + H3 = E3 >>> 0 < H3 >>> 0 ? E3 : H3; + D3 = Ba3 + 16 | 0; + l2 = c[D3 >> 2] | 0; + if (l2 >>> 0 < E3 >>> 0) { + B3 = (l2 | 0) == 0 ? E3 : l2; + while (1) { + if (B3 >>> 0 >= E3 >>> 0) break; + B3 = B3 << 1; + } + m3 = f2 + 8 | 0; + t3 = sa2[c[f2 >> 2] & 1](c[m3 >> 2] | 0, B3) | 0; + if (!t3) oa2(1); + A3 = c[D3 >> 2] | 0; + l2 = Ba3 + 8 | 0; + if (A3) dc(t3 | 0, c[l2 >> 2] | 0, A3 | 0) | 0; + ra2[c[f2 + 4 >> 2] & 1](c[m3 >> 2] | 0, c[l2 >> 2] | 0); + c[l2 >> 2] = t3; + c[D3 >> 2] = B3; + } + B3 = Ba3 + 20 | 0; + l2 = c[B3 >> 2] | 0; + if (l2 >>> 0 < E3 >>> 0) { + A3 = (l2 | 0) == 0 ? E3 : l2; + while (1) { + if (A3 >>> 0 >= E3 >>> 0) break; + A3 = A3 << 1; + } + D3 = f2 + 8 | 0; + m3 = sa2[c[f2 >> 2] & 1](c[D3 >> 2] | 0, A3 << 2) | 0; + if (!m3) oa2(1); + t3 = c[B3 >> 2] | 0; + l2 = Ba3 + 12 | 0; + if (t3) dc(m3 | 0, c[l2 >> 2] | 0, t3 << 2 | 0) | 0; + ra2[c[f2 + 4 >> 2] & 1](c[D3 >> 2] | 0, c[l2 >> 2] | 0); + c[l2 >> 2] = m3; + c[B3 >> 2] = A3; + $2 = f2; + } else { + $2 = f2; + D3 = f2 + 8 | 0; + } + c[Ba3 + 4 >> 2] = E3; + l2 = sa2[c[$2 >> 2] & 1](c[D3 >> 2] | 0, fa3 << 4) | 0; + if (!l2) oa2(1); + Y3 = Ca3 + 60 | 0; + c[Y3 >> 2] = l2; + if (c[ta3 >> 2] | 0) pa2(407776, 406802, 255, 407793); + m3 = _(H3, fa3) | 0; + c[J3 >> 2] = m3; + m3 = sa2[c[$2 >> 2] & 1](c[D3 >> 2] | 0, m3 * 1040 | 0) | 0; + l2 = m3; + if (!m3) oa2(1); + c[ta3 >> 2] = l2; + X3 = Ca3 + 32 | 0; + c[X3 >> 2] = l2; + l2 = 0; + while (1) { + if ((l2 | 0) == (fa3 | 0)) break; + ac(m3 + (l2 * 1040 | 0) | 0, 0, 1024) | 0; + c[m3 + (l2 * 1040 | 0) + 1024 >> 2] = 0; + h[m3 + (l2 * 1040 | 0) + 1032 >> 3] = s; + l2 = l2 + 1 | 0; + } + c[Ca3 + 56 >> 2] = 0; + c[Ca3 + 52 >> 2] = 0; + Pb(f2, ya3, u3, K3, ua3, N3); + Qb(f2, za3, u3, L3, va3, O3); + Q3 = ya3 + 40 | 0; + T3 = ya3 + 24 | 0; + U3 = ya3 + 36 | 0; + V3 = ya3 + 32 | 0; + L3 = za3 + 40 | 0; + N3 = za3 + 24 | 0; + O3 = za3 + 36 | 0; + p2 = za3 + 32 | 0; + t3 = Fa3; + m3 = q2; + l2 = r2; + P3 = 0; + while (1) { + if ((P3 | 0) == (u3 | 0)) break; + H3 = c[v3 + (P3 << 4) >> 2] | 0; + I3 = c[v3 + (P3 << 4) + 4 >> 2] | 0; + A3 = c[v3 + (P3 << 4) + 12 >> 2] | 0; + J3 = A3 & 65535; + K3 = A3 >>> 16; + E3 = c[Q3 >> 2] | 0; + B3 = c[T3 >> 2] | 0; + A3 = B3 + (E3 * 2832 | 0) + ((A3 & 65535) << 2) | 0; + c[A3 >> 2] = (c[A3 >> 2] | 0) + 1; + E3 = B3 + (E3 * 2832 | 0) + 2816 | 0; + c[E3 >> 2] = (c[E3 >> 2] | 0) + 1; + E3 = (c[U3 >> 2] | 0) + 1 | 0; + c[U3 >> 2] = E3; + if ((E3 | 0) == (c[V3 >> 2] | 0)) { + Sb(ya3, 0); + E3 = t3; + B3 = H3; + } else { + E3 = t3; + B3 = H3; + } + while (1) { + if (!B3) break; + A3 = a[j2 + (E3 & k2) >> 0] | 0; + l2 = (c[ea3 >> 2] | 0) + (c[W3 + (((a[406969 + (m3 & 255) >> 0] | a[406969 + (l2 & 255 | 256) >> 0]) & 255) << 2) >> 2] | 0) | 0; + Ha3 = c[X3 >> 2] | 0; + Ia3 = Ha3 + (l2 * 1040 | 0) + ((A3 & 255) << 2) | 0; + c[Ia3 >> 2] = (c[Ia3 >> 2] | 0) + 1; + l2 = Ha3 + (l2 * 1040 | 0) + 1024 | 0; + c[l2 >> 2] = (c[l2 >> 2] | 0) + 1; + l2 = (c[da3 >> 2] | 0) + 1 | 0; + c[da3 >> 2] = l2; + if ((l2 | 0) == (c[ca3 >> 2] | 0)) Ub(f2, Ca3, 0); + l2 = m3; + E3 = E3 + 1 | 0; + m3 = A3; + B3 = B3 + -1 | 0; + } + Ia3 = I3 & 16777215; + t3 = t3 + H3 + Ia3 | 0; + do + if (Ia3) { + l2 = a[j2 + (t3 + -2 & k2) >> 0] | 0; + m3 = a[j2 + (t3 + -1 & k2) >> 0] | 0; + if ((J3 & 65535) <= 127) break; + Ia3 = c[L3 >> 2] | 0; + Ha3 = c[N3 >> 2] | 0; + K3 = Ha3 + (Ia3 * 2096 | 0) + (K3 << 2) | 0; + c[K3 >> 2] = (c[K3 >> 2] | 0) + 1; + Ia3 = Ha3 + (Ia3 * 2096 | 0) + 2080 | 0; + c[Ia3 >> 2] = (c[Ia3 >> 2] | 0) + 1; + Ia3 = (c[O3 >> 2] | 0) + 1 | 0; + c[O3 >> 2] = Ia3; + if ((Ia3 | 0) != (c[p2 >> 2] | 0)) break; + Tb(za3, 0); + } + while (0); + P3 = P3 + 1 | 0; + } + Ub(f2, Ca3, 1); + ra2[c[f2 + 4 >> 2] & 1](c[D3 >> 2] | 0, c[Y3 >> 2] | 0); + c[Y3 >> 2] = 0; + Sb(ya3, 1); + Tb(za3, 1); + if (c[na2 >> 2] | 0) pa2(406853, 406802, 473, 407737); + l2 = c[Ba3 >> 2] | 0; + c[ga3 >> 2] = l2 << 6; + l2 = sa2[c[$2 >> 2] & 1](c[D3 >> 2] | 0, l2 << 8) | 0; + if (!l2) oa2(1); + c[na2 >> 2] = l2; + t3 = 0; + while (1) { + if (t3 >>> 0 >= (c[Ba3 >> 2] | 0) >>> 0) break; + l2 = _(t3, fa3) | 0; + m3 = t3 << 6; + A3 = 0; + while (1) { + if ((A3 | 0) == 64) break; + c[(c[na2 >> 2] | 0) + (m3 + A3 << 2) >> 2] = l2 + (c[W3 + (A3 << 2) >> 2] | 0); + A3 = A3 + 1 | 0; + } + t3 = t3 + 1 | 0; + } + l2 = 2; + break; + } + } + l2 = 0; + m3 = 0; + while (1) { + if ((m3 | 0) == (u3 | 0)) break; + l2 = l2 + (c[v3 + (m3 << 4) >> 2] | 0) | 0; + m3 = m3 + 1 | 0; + } + H3 = (l2 >>> 9) + 1 | 0; + E3 = H3 >>> 0 < 257 ? H3 : 257; + c[Ca3 >> 2] = 256; + c[Ca3 + 4 >> 2] = 512; + h[Ca3 + 8 >> 3] = 400; + c[Ca3 + 16 >> 2] = 0; + I3 = Ca3 + 20 | 0; + c[I3 >> 2] = Ba3; + c[Ca3 + 28 >> 2] = J3; + T3 = Ca3 + 32 | 0; + c[T3 >> 2] = 512; + U3 = Ca3 + 36 | 0; + c[U3 >> 2] = 0; + V3 = Ca3 + 40 | 0; + c[V3 >> 2] = 0; + c[Ca3 + 72 >> 2] = 0; + D3 = Ba3 + 16 | 0; + l2 = c[D3 >> 2] | 0; + if (l2 >>> 0 < H3 >>> 0) { + B3 = (l2 | 0) == 0 ? H3 : l2; + while (1) { + if (B3 >>> 0 >= H3 >>> 0) break; + B3 = B3 << 1; + } + m3 = f2 + 8 | 0; + t3 = sa2[c[f2 >> 2] & 1](c[m3 >> 2] | 0, B3) | 0; + if (!t3) oa2(1); + A3 = c[D3 >> 2] | 0; + l2 = Ba3 + 8 | 0; + if (A3) dc(t3 | 0, c[l2 >> 2] | 0, A3 | 0) | 0; + ra2[c[f2 + 4 >> 2] & 1](c[m3 >> 2] | 0, c[l2 >> 2] | 0); + c[l2 >> 2] = t3; + c[D3 >> 2] = B3; + } + D3 = Ba3 + 20 | 0; + l2 = c[D3 >> 2] | 0; + if (l2 >>> 0 < H3 >>> 0) { + B3 = (l2 | 0) == 0 ? H3 : l2; + while (1) { + if (B3 >>> 0 >= H3 >>> 0) break; + B3 = B3 << 1; + } + m3 = f2 + 8 | 0; + t3 = sa2[c[f2 >> 2] & 1](c[m3 >> 2] | 0, B3 << 2) | 0; + if (!t3) oa2(1); + A3 = c[D3 >> 2] | 0; + l2 = Ba3 + 12 | 0; + if (A3) dc(t3 | 0, c[l2 >> 2] | 0, A3 << 2 | 0) | 0; + ra2[c[f2 + 4 >> 2] & 1](c[m3 >> 2] | 0, c[l2 >> 2] | 0); + c[l2 >> 2] = t3; + c[D3 >> 2] = B3; + } + c[(c[I3 >> 2] | 0) + 4 >> 2] = H3; + if (c[ta3 >> 2] | 0) pa2(407776, 407818, 70, 407905); + c[J3 >> 2] = E3; + l2 = sa2[c[f2 >> 2] & 1](c[f2 + 8 >> 2] | 0, E3 * 1040 | 0) | 0; + m3 = l2; + if (!l2) oa2(1); + c[ta3 >> 2] = m3; + Q3 = Ca3 + 24 | 0; + c[Q3 >> 2] = m3; + ac(l2 | 0, 0, 1024) | 0; + c[l2 + 1024 >> 2] = 0; + h[l2 + 1032 >> 3] = s; + c[Ca3 + 48 >> 2] = 0; + c[Ca3 + 44 >> 2] = 0; + Pb(f2, ya3, u3, K3, ua3, N3); + Qb(f2, za3, u3, L3, va3, O3); + D3 = ya3 + 40 | 0; + E3 = ya3 + 24 | 0; + H3 = ya3 + 36 | 0; + I3 = ya3 + 32 | 0; + J3 = za3 + 40 | 0; + K3 = za3 + 24 | 0; + L3 = za3 + 36 | 0; + N3 = za3 + 32 | 0; + l2 = Fa3; + P3 = 0; + while (1) { + if ((P3 | 0) == (u3 | 0)) break; + t3 = c[v3 + (P3 << 4) >> 2] | 0; + A3 = c[v3 + (P3 << 4) + 4 >> 2] | 0; + ga3 = c[v3 + (P3 << 4) + 12 >> 2] | 0; + O3 = ga3 & 65535; + p2 = ga3 >>> 16; + Ia3 = c[D3 >> 2] | 0; + Ha3 = c[E3 >> 2] | 0; + ga3 = Ha3 + (Ia3 * 2832 | 0) + ((ga3 & 65535) << 2) | 0; + c[ga3 >> 2] = (c[ga3 >> 2] | 0) + 1; + Ia3 = Ha3 + (Ia3 * 2832 | 0) + 2816 | 0; + c[Ia3 >> 2] = (c[Ia3 >> 2] | 0) + 1; + Ia3 = (c[H3 >> 2] | 0) + 1 | 0; + c[H3 >> 2] = Ia3; + if ((Ia3 | 0) == (c[I3 >> 2] | 0)) { + Sb(ya3, 0); + m3 = l2; + B3 = t3; + } else { + m3 = l2; + B3 = t3; + } + while (1) { + if (!B3) break; + Ia3 = c[V3 >> 2] | 0; + Ha3 = c[Q3 >> 2] | 0; + ga3 = Ha3 + (Ia3 * 1040 | 0) + ((d[j2 + (m3 & k2) >> 0] | 0) << 2) | 0; + c[ga3 >> 2] = (c[ga3 >> 2] | 0) + 1; + Ia3 = Ha3 + (Ia3 * 1040 | 0) + 1024 | 0; + c[Ia3 >> 2] = (c[Ia3 >> 2] | 0) + 1; + Ia3 = (c[U3 >> 2] | 0) + 1 | 0; + c[U3 >> 2] = Ia3; + if ((Ia3 | 0) == (c[T3 >> 2] | 0)) Rb(Ca3, 0); + m3 = m3 + 1 | 0; + B3 = B3 + -1 | 0; + } + Ia3 = A3 & 16777215; + l2 = l2 + t3 + Ia3 | 0; + if ((Ia3 | 0) != 0 & (O3 & 65535) > 127 ? (Ia3 = c[J3 >> 2] | 0, Ha3 = c[K3 >> 2] | 0, ga3 = Ha3 + (Ia3 * 2096 | 0) + (p2 << 2) | 0, c[ga3 >> 2] = (c[ga3 >> 2] | 0) + 1, Ia3 = Ha3 + (Ia3 * 2096 | 0) + 2080 | 0, c[Ia3 >> 2] = (c[Ia3 >> 2] | 0) + 1, Ia3 = (c[L3 >> 2] | 0) + 1 | 0, c[L3 >> 2] = Ia3, (Ia3 | 0) == (c[N3 >> 2] | 0)) : 0) Tb(za3, 0); + P3 = P3 + 1 | 0; + } + Rb(Ca3, 1); + Sb(ya3, 1); + Tb(za3, 1); + l2 = 2; + } else { + l2 = Wb(j2, Fa3, k2, n2) | 0; + l2 = l2 ? 2 : 3; + Nb(f2, j2, Fa3, k2, p2, q2, r2, v3, u3, l2, Ba3); + } + while (0); + if ((c[Aa3 >> 2] | 0) > 3) Ob(wa3, xa3, Ba3); + ab2(f2, j2, Fa3, n2, k2, q2, r2, o2, wa3, xa3, l2, v3, u3, Ba3, y3, z3); + Ha3 = f2 + 4 | 0; + Ia3 = f2 + 8 | 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[Ba3 + 8 >> 2] | 0); + c[ha3 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[ia3 >> 2] | 0); + c[ia3 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[Ba3 + 32 >> 2] | 0); + c[ja3 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[ka3 >> 2] | 0); + c[ka3 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[Ba3 + 56 >> 2] | 0); + c[la3 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[ma3 >> 2] | 0); + c[ma3 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[na2 >> 2] | 0); + c[na2 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[qa3 >> 2] | 0); + c[qa3 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[ta3 >> 2] | 0); + c[ta3 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[ua3 >> 2] | 0); + c[ua3 >> 2] = 0; + ra2[c[Ha3 >> 2] & 1](c[Ia3 >> 2] | 0, c[va3 >> 2] | 0); + c[va3 >> 2] = 0; + } + if ((n2 + 4 | 0) >>> 0 >= (c[y3 >> 2] | 0) >>> 3 >>> 0) { + i = Ga3; + return; + } + ; + c[x3 >> 2] = c[w2 >> 2]; + c[x3 + 4 >> 2] = c[w2 + 4 >> 2]; + c[x3 + 8 >> 2] = c[w2 + 8 >> 2]; + c[x3 + 12 >> 2] = c[w2 + 12 >> 2]; + a[z3 >> 0] = Da3; + c[y3 >> 2] = Ea3 & 255; + bb2(o2, j2, Fa3, k2, n2, y3, z3); + i = Ga3; + return; + } + function Eb(b3) { + b3 = b3 | 0; + var e2 = 0, f2 = 0, g3 = 0, h2 = 0, i2 = 0; + f2 = b3 + 192 | 0; + g3 = d[f2 >> 0] | 0; + i2 = b3 + 193 | 0; + h2 = d[i2 >> 0] | 0; + a[f2 >> 0] = 0; + a[i2 >> 0] = 0; + i2 = 6 << h2; + f2 = b3 + 5216 | 0; + e2 = c[f2 >> 2] | 0; + if (!e2) { + e2 = b3 + 5228 | 0; + c[f2 >> 2] = e2; + } else e2 = e2 + (c[b3 + 5220 >> 2] | 0) | 0; + a[e2 >> 0] = g3 | i2; + if ((h2 + 6 | 0) >>> 0 > 8) a[e2 + 1 >> 0] = i2 >>> 8; + b3 = b3 + 5220 | 0; + c[b3 >> 2] = (c[b3 >> 2] | 0) + ((h2 + 13 | 0) >>> 3); + return; + } + function Fb(a2, b3, e2, f2, h2, j2, k2) { + a2 = a2 | 0; + b3 = b3 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + h2 = h2 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + var l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0; + s2 = i; + i = i + 1024 | 0; + q2 = s2; + if (((h2 >>> 8) + 2 | 0) >>> 0 > k2 >>> 0 ? (l2 = +(h2 >>> 0), +(j2 >>> 0) > l2 * 0.99) : 0) { + ac(q2 | 0, 0, 1024) | 0; + l2 = l2 * 7.92; + j2 = ((h2 + 12 | 0) >>> 0) / 13 | 0; + f2 = e2; + k2 = 0; + while (1) { + if (k2 >>> 0 >= j2 >>> 0) break; + e2 = q2 + ((d[a2 + (f2 & b3) >> 0] | 0) << 2) | 0; + c[e2 >> 2] = (c[e2 >> 2] | 0) + 1; + f2 = f2 + 13 | 0; + k2 = k2 + 1 | 0; + } + r2 = l2 / 13; + h2 = q2 + 1024 | 0; + f2 = q2; + l2 = 0; + e2 = 0; + while (1) { + if (f2 >>> 0 >= h2 >>> 0) break; + k2 = c[f2 >> 2] | 0; + m3 = +(k2 >>> 0); + if (k2 >>> 0 < 256) p2 = +g2[19516 + (k2 << 2) >> 2]; + else p2 = +Xb(m3); + j2 = c[f2 + 4 >> 2] | 0; + n2 = +(j2 >>> 0); + if (j2 >>> 0 < 256) o2 = +g2[19516 + (j2 << 2) >> 2]; + else o2 = +Xb(n2); + f2 = f2 + 8 | 0; + l2 = l2 - m3 * p2 - n2 * o2; + e2 = e2 + k2 + j2 | 0; + } + n2 = +(e2 >>> 0); + if (!e2) o2 = n2; + else { + if (e2 >>> 0 < 256) m3 = +g2[19516 + (e2 << 2) >> 2]; + else m3 = +Xb(n2); + o2 = n2; + l2 = l2 + n2 * m3; + } + if ((l2 < o2 ? o2 : l2) > r2) { + q2 = 0; + i = s2; + return q2 | 0; + } + } + q2 = 1; + i = s2; + return q2 | 0; + } + function Gb(d2, e2, f2, g3) { + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + var h2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0; + m3 = i; + i = i + 64 | 0; + l2 = m3; + if ((g3 | 0) >= 16) pa2(406658, 406674, 26, 406709); + c[l2 >> 2] = -1; + h2 = 0; + a: while (1) { + j2 = b2[e2 + (d2 << 3) + 4 >> 1] | 0; + if (j2 << 16 >> 16 > -1) { + k2 = h2 + 1 | 0; + if ((h2 | 0) >= (g3 | 0)) { + h2 = 0; + d2 = 12; + break; + } + c[l2 + (k2 << 2) >> 2] = b2[e2 + (d2 << 3) + 6 >> 1]; + h2 = k2; + d2 = j2 << 16 >> 16; + continue; + } + a[f2 + (b2[e2 + (d2 << 3) + 6 >> 1] | 0) >> 0] = h2; + while (1) { + if ((h2 | 0) <= -1) { + h2 = 1; + d2 = 12; + break a; + } + if ((c[l2 + (h2 << 2) >> 2] | 0) != -1) break; + h2 = h2 + -1 | 0; + } + k2 = l2 + (h2 << 2) | 0; + d2 = c[k2 >> 2] | 0; + c[k2 >> 2] = -1; + } + if ((d2 | 0) == 12) { + i = m3; + return h2 | 0; + } + return 0; + } + function Hb(d2, e2, f2, g3, h2) { + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + var j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0; + x3 = i; + i = i + 16 | 0; + u3 = x3 + 8 | 0; + v3 = x3; + t3 = 1; + while (1) { + j2 = e2; + s2 = 0; + a: while (1) { + do { + if (!j2) break a; + j2 = j2 + -1 | 0; + k2 = c[d2 + (j2 << 2) >> 2] | 0; + } while ((k2 | 0) == 0); + c[g3 + (s2 << 3) >> 2] = k2 >>> 0 > t3 >>> 0 ? k2 : t3; + b2[g3 + (s2 << 3) + 4 >> 1] = -1; + b2[g3 + (s2 << 3) + 6 >> 1] = j2; + s2 = s2 + 1 | 0; + } + if ((s2 | 0) == 1) break; + b: do + if (s2 >>> 0 < 13) { + o2 = 1; + while (1) { + if (o2 >>> 0 >= s2 >>> 0) break b; + n2 = g3 + (o2 << 3) | 0; + m3 = c[n2 >> 2] | 0; + n2 = c[n2 + 4 >> 2] | 0; + l2 = u3; + c[l2 >> 2] = m3; + c[l2 + 4 >> 2] = n2; + l2 = o2; + while (1) { + j2 = l2; + l2 = l2 + -1 | 0; + k2 = g3 + (l2 << 3) | 0; + if (!(Kb(u3, k2) | 0)) break; + p2 = k2; + q2 = c[p2 + 4 >> 2] | 0; + r2 = g3 + (j2 << 3) | 0; + c[r2 >> 2] = c[p2 >> 2]; + c[r2 + 4 >> 2] = q2; + if (!l2) { + j2 = 0; + break; + } + } + r2 = g3 + (j2 << 3) | 0; + c[r2 >> 2] = m3; + c[r2 + 4 >> 2] = n2; + o2 = o2 + 1 | 0; + } + } else { + p2 = s2 >>> 0 < 57 ? 2 : 0; + while (1) { + if ((p2 | 0) == 6) break b; + j2 = c[19428 + (p2 << 2) >> 2] | 0; + q2 = j2; + while (1) { + if (q2 >>> 0 >= s2 >>> 0) break; + l2 = g3 + (q2 << 3) | 0; + k2 = c[l2 >> 2] | 0; + l2 = c[l2 + 4 >> 2] | 0; + o2 = v3; + c[o2 >> 2] = k2; + c[o2 + 4 >> 2] = l2; + o2 = q2; + while (1) { + if (o2 >>> 0 < j2 >>> 0) break; + m3 = o2 - j2 | 0; + n2 = g3 + (m3 << 3) | 0; + if (!(Kb(v3, n2) | 0)) break; + y3 = n2; + n2 = c[y3 + 4 >> 2] | 0; + r2 = g3 + (o2 << 3) | 0; + c[r2 >> 2] = c[y3 >> 2]; + c[r2 + 4 >> 2] = n2; + o2 = m3; + } + y3 = g3 + (o2 << 3) | 0; + c[y3 >> 2] = k2; + c[y3 + 4 >> 2] = l2; + q2 = q2 + 1 | 0; + } + p2 = p2 + 1 | 0; + } + } + while (0); + n2 = g3 + (s2 << 3) | 0; + c[n2 >> 2] = -1; + c[n2 + 4 >> 2] = -1; + n2 = s2 + 1 | 0; + r2 = g3 + (n2 << 3) | 0; + c[r2 >> 2] = -1; + c[r2 + 4 >> 2] = -1; + r2 = s2 << 1; + m3 = 0; + j2 = s2; + while (1) { + j2 = j2 + -1 | 0; + if (!j2) break; + l2 = c[g3 + (m3 << 3) >> 2] | 0; + k2 = c[g3 + (n2 << 3) >> 2] | 0; + if (l2 >>> 0 > k2 >>> 0) { + q2 = n2 + 1 | 0; + k2 = c[g3 + (q2 << 3) >> 2] | 0; + p2 = m3; + o2 = n2; + } else { + p2 = m3 + 1 | 0; + l2 = c[g3 + (p2 << 3) >> 2] | 0; + q2 = n2; + o2 = m3; + } + if (l2 >>> 0 > k2 >>> 0) { + m3 = p2; + n2 = q2 + 1 | 0; + l2 = q2; + } else { + k2 = l2; + m3 = p2 + 1 | 0; + n2 = q2; + l2 = p2; + } + y3 = r2 - j2 | 0; + c[g3 + (y3 << 3) >> 2] = (c[g3 + (o2 << 3) >> 2] | 0) + k2; + b2[g3 + (y3 << 3) + 4 >> 1] = o2; + b2[g3 + (y3 << 3) + 6 >> 1] = l2; + y3 = g3 + (y3 + 1 << 3) | 0; + c[y3 >> 2] = -1; + c[y3 + 4 >> 2] = -1; + } + if (Gb(r2 + -1 | 0, g3, h2, f2) | 0) { + w2 = 36; + break; + } + t3 = t3 << 1; + } + if ((w2 | 0) == 36) { + i = x3; + return; + } + a[h2 + (b2[g3 + 6 >> 1] | 0) >> 0] = 1; + i = x3; + return; + } + function Ib(b3, d2, e2) { + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + var f2 = 0, g3 = 0, h2 = 0, i2 = 0, j2 = 0, k2 = 0, l2 = 0; + f2 = 0; + g3 = 0; + while (1) { + if ((g3 | 0) == (b3 | 0)) break; + f2 = (c[d2 + (g3 << 2) >> 2] | 0) == 0 ? f2 : f2 + 1 | 0; + g3 = g3 + 1 | 0; + } + if (f2 >>> 0 < 16) return; + else k2 = b3; + while (1) { + if (!k2) { + l2 = 55; + break; + } + b3 = k2 + -1 | 0; + if (!(c[d2 + (b3 << 2) >> 2] | 0)) k2 = b3; + else break; + } + if ((l2 | 0) == 55) return; + g3 = 0; + b3 = 1073741824; + h2 = 0; + while (1) { + if ((h2 | 0) == (k2 | 0)) break; + f2 = c[d2 + (h2 << 2) >> 2] | 0; + if (f2) { + g3 = g3 + 1 | 0; + b3 = b3 >>> 0 > f2 >>> 0 ? f2 : b3; + } + h2 = h2 + 1 | 0; + } + if (g3 >>> 0 < 5) return; + a: do + if (b3 >>> 0 < 4 & (k2 - g3 | 0) >>> 0 < 6) { + b3 = k2 + -1 | 0; + f2 = 1; + while (1) { + if (f2 >>> 0 >= b3 >>> 0) break a; + if (((c[d2 + (f2 + -1 << 2) >> 2] | 0) != 0 ? (i2 = d2 + (f2 << 2) | 0, (c[i2 >> 2] | 0) == 0) : 0) ? (c[d2 + (f2 + 1 << 2) >> 2] | 0) != 0 : 0) c[i2 >> 2] = 1; + f2 = f2 + 1 | 0; + } + } + while (0); + if (g3 >>> 0 < 28) return; + ac(e2 | 0, 0, k2 | 0) | 0; + b3 = 0; + i2 = 0; + f2 = c[d2 >> 2] | 0; + while (1) { + if (i2 >>> 0 > k2 >>> 0) break; + g3 = (i2 | 0) == (k2 | 0); + if (!g3 ? (c[d2 + (i2 << 2) >> 2] | 0) == (f2 | 0) : 0) b3 = b3 + 1 | 0; + else { + if (!f2) { + if (b3 >>> 0 > 4) { + h2 = 0; + l2 = 29; + } + } else if (b3 >>> 0 > 6) { + h2 = 0; + l2 = 29; + } + b: do + if ((l2 | 0) == 29) while (1) { + l2 = 0; + if ((h2 | 0) == (b3 | 0)) break b; + a[e2 + (i2 - h2 + -1) >> 0] = 1; + h2 = h2 + 1 | 0; + l2 = 29; + } + while (0); + if (g3) b3 = 1; + else { + b3 = 1; + f2 = c[d2 + (i2 << 2) >> 2] | 0; + } + } + i2 = i2 + 1 | 0; + } + i2 = k2 + -2 | 0; + f2 = (((c[d2 >> 2] | 0) + (c[d2 + 4 >> 2] | 0) + (c[d2 + 8 >> 2] | 0) << 8 >>> 0) / 3 | 0) + 420 | 0; + j2 = 0; + g3 = 0; + b3 = 0; + while (1) { + if (j2 >>> 0 > k2 >>> 0) break; + h2 = (j2 | 0) == (k2 | 0); + do + if (!h2 ? (a[e2 + j2 >> 0] | 0) == 0 : 0) { + if ((j2 | 0) != 0 ? (a[e2 + (j2 + -1) >> 0] | 0) != 0 : 0) { + l2 = 42; + break; + } + if (((c[d2 + (j2 << 2) >> 2] << 8) - f2 + 1240 | 0) >>> 0 > 2479) l2 = 42; + } else l2 = 42; + while (0); + do + if ((l2 | 0) == 42) { + l2 = 0; + if (!(g3 >>> 0 <= 3 ? !(g3 >>> 0 > 2 & (b3 | 0) == 0) : 0)) l2 = 44; + c: do + if ((l2 | 0) == 44) { + l2 = 0; + f2 = ((b3 + (g3 >>> 1) | 0) >>> 0) / (g3 >>> 0) | 0; + b3 = (b3 | 0) == 0 ? 0 : (f2 | 0) == 0 ? 1 : f2; + f2 = 0; + while (1) { + if ((f2 | 0) == (g3 | 0)) break c; + c[d2 + (j2 - f2 + -1 << 2) >> 2] = b3; + f2 = f2 + 1 | 0; + } + } + while (0); + if (j2 >>> 0 < i2 >>> 0) { + f2 = (((c[d2 + (j2 << 2) >> 2] | 0) + (c[d2 + (j2 + 1 << 2) >> 2] | 0) + (c[d2 + (j2 + 2 << 2) >> 2] | 0) << 8 >>> 0) / 3 | 0) + 420 | 0; + g3 = 0; + b3 = 0; + break; + } + if (j2 >>> 0 < k2 >>> 0) { + f2 = c[d2 + (j2 << 2) >> 2] << 8; + g3 = 0; + b3 = 0; + } else { + f2 = 0; + g3 = 0; + b3 = 0; + } + } + while (0); + g3 = g3 + 1 | 0; + if (!h2) { + b3 = b3 + (c[d2 + (j2 << 2) >> 2] | 0) | 0; + if (g3 >>> 0 > 3) { + f2 = (((b3 << 8) + (g3 >>> 1) | 0) >>> 0) / (g3 >>> 0) | 0; + f2 = (g3 | 0) == 4 ? f2 + 120 | 0 : f2; + } + } + j2 = j2 + 1 | 0; + } + return; + } + function Jb(f2, g3, h2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + var j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0; + p2 = i; + i = i + 64 | 0; + l2 = p2 + 32 | 0; + o2 = p2; + j2 = l2; + k2 = j2 + 32 | 0; + do { + b2[j2 >> 1] = 0; + j2 = j2 + 2 | 0; + } while ((j2 | 0) < (k2 | 0)); + j2 = 0; + while (1) { + if ((j2 | 0) == (g3 | 0)) break; + n2 = l2 + ((d[f2 + j2 >> 0] | 0) << 1) | 0; + b2[n2 >> 1] = (b2[n2 >> 1] | 0) + 1 << 16 >> 16; + j2 = j2 + 1 | 0; + } + b2[l2 >> 1] = 0; + b2[o2 >> 1] = 0; + j2 = 0; + k2 = 1; + while (1) { + if ((k2 | 0) == 16) { + n2 = 0; + break; + } + n2 = j2 + (e[l2 + (k2 + -1 << 1) >> 1] | 0) << 1; + b2[o2 + (k2 << 1) >> 1] = n2; + j2 = n2; + k2 = k2 + 1 | 0; + } + while (1) { + if ((n2 | 0) == (g3 | 0)) break; + j2 = a[f2 + n2 >> 0] | 0; + if (j2 << 24 >> 24) { + k2 = j2 & 255; + j2 = o2 + (k2 << 1) | 0; + l2 = b2[j2 >> 1] | 0; + b2[j2 >> 1] = l2 + 1 << 16 >> 16; + j2 = l2; + l2 = c[19452 + ((l2 & 15) << 2) >> 2] | 0; + m3 = 4; + while (1) { + if (m3 >>> 0 >= k2 >>> 0) break; + q2 = (j2 & 65535) >>> 4; + j2 = q2; + l2 = l2 << 4 | c[19452 + ((q2 & 15) << 2) >> 2]; + m3 = m3 + 4 | 0; + } + b2[h2 + (n2 << 1) >> 1] = l2 >>> (0 - k2 & 3); + } + n2 = n2 + 1 | 0; + } + i = p2; + return; + } + function Kb(a2, d2) { + a2 = a2 | 0; + d2 = d2 | 0; + var e2 = 0, f2 = 0; + e2 = c[a2 >> 2] | 0; + f2 = c[d2 >> 2] | 0; + if ((e2 | 0) == (f2 | 0)) { + d2 = (b2[a2 + 6 >> 1] | 0) > (b2[d2 + 6 >> 1] | 0); + return d2 | 0; + } else { + d2 = e2 >>> 0 < f2 >>> 0; + return d2 | 0; + } + return 0; + } + function Lb(a2, b3) { + a2 = a2 | 0; + b3 = b3 | 0; + return Yb(b3) | 0; + } + function Mb(a2, b3) { + a2 = a2 | 0; + b3 = b3 | 0; + Zb(b3); + return; + } + function Nb(f2, g3, j2, k2, l2, m3, n2, o2, p2, q2, r2) { + f2 = f2 | 0; + g3 = g3 | 0; + j2 = j2 | 0; + k2 = k2 | 0; + l2 = l2 | 0; + m3 = m3 | 0; + n2 = n2 | 0; + o2 = o2 | 0; + p2 = p2 | 0; + q2 = q2 | 0; + r2 = r2 | 0; + var t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0, O3 = 0, P3 = 0, Q3 = 0, R3 = 0, S3 = 0, T3 = 0, U3 = 0, V3 = 0, W3 = 0, X3 = 0, Y3 = 0, Z3 = 0; + Z3 = i; + i = i + 2096 | 0; + W3 = Z3; + Za2(f2, o2, p2, g3, j2, k2, l2, r2, r2 + 24 | 0, r2 + 48 | 0); + Y3 = f2 + 8 | 0; + R3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, c[r2 >> 2] << 2) | 0; + if (!R3) oa2(1); + l2 = 0; + while (1) { + t3 = c[r2 >> 2] | 0; + if (l2 >>> 0 >= t3 >>> 0) break; + c[R3 + (l2 << 2) >> 2] = q2; + l2 = l2 + 1 | 0; + } + U3 = r2 + 48 | 0; + u3 = c[U3 >> 2] | 0; + T3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, t3 * 66560 | 0) | 0; + if (!T3) oa2(1); + l2 = t3 << 6; + q2 = 0; + while (1) { + if ((q2 | 0) == (l2 | 0)) break; + ac(T3 + (q2 * 1040 | 0) | 0, 0, 1024) | 0; + c[T3 + (q2 * 1040 | 0) + 1024 >> 2] = 0; + h[T3 + (q2 * 1040 | 0) + 1032 >> 3] = s; + q2 = q2 + 1 | 0; + } + v3 = r2 + 96 | 0; + if (c[v3 >> 2] | 0) pa2(406774, 406802, 70, 406832); + t3 = c[r2 + 24 >> 2] | 0; + l2 = r2 + 100 | 0; + c[l2 >> 2] = t3; + t3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, t3 * 2832 | 0) | 0; + if (!t3) oa2(1); + c[v3 >> 2] = t3; + l2 = c[l2 >> 2] | 0; + q2 = 0; + while (1) { + if ((q2 | 0) == (l2 | 0)) break; + ac(t3 + (q2 * 2832 | 0) | 0, 0, 2816) | 0; + c[t3 + (q2 * 2832 | 0) + 2816 >> 2] = 0; + h[t3 + (q2 * 2832 | 0) + 2824 >> 3] = s; + q2 = q2 + 1 | 0; + } + X3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, u3 * 8384 | 0) | 0; + if (!X3) oa2(1); + l2 = u3 << 2; + q2 = 0; + while (1) { + if ((q2 | 0) == (l2 | 0)) break; + ac(X3 + (q2 * 2096 | 0) | 0, 0, 2080) | 0; + c[X3 + (q2 * 2096 | 0) + 2080 >> 2] = 0; + h[X3 + (q2 * 2096 | 0) + 2088 >> 3] = s; + q2 = q2 + 1 | 0; + } + l2 = c[r2 + 12 >> 2] | 0; + if (!l2) u3 = 0; + else u3 = c[l2 >> 2] | 0; + l2 = c[r2 + 36 >> 2] | 0; + if (!l2) q2 = 0; + else q2 = c[l2 >> 2] | 0; + l2 = c[r2 + 60 >> 2] | 0; + if (!l2) l2 = 0; + else l2 = c[l2 >> 2] | 0; + P3 = r2 + 32 | 0; + Q3 = r2 + 36 | 0; + K3 = c[v3 >> 2] | 0; + L3 = r2 + 8 | 0; + M2 = r2 + 12 | 0; + N3 = r2 + 56 | 0; + O3 = r2 + 60 | 0; + v3 = n2; + z3 = 0; + t3 = 0; + A3 = 0; + y3 = 0; + C3 = 0; + B3 = 0; + J3 = 0; + while (1) { + if ((J3 | 0) == (p2 | 0)) break; + if (!q2) { + y3 = y3 + 1 | 0; + I3 = d[(c[P3 >> 2] | 0) + y3 >> 0] | 0; + q2 = c[(c[Q3 >> 2] | 0) + (y3 << 2) >> 2] | 0; + } else I3 = A3; + G3 = o2 + (J3 << 4) + 12 | 0; + F3 = K3 + (I3 * 2832 | 0) + ((e[G3 >> 1] | 0) << 2) | 0; + c[F3 >> 2] = (c[F3 >> 2] | 0) + 1; + F3 = K3 + (I3 * 2832 | 0) + 2816 | 0; + c[F3 >> 2] = (c[F3 >> 2] | 0) + 1; + F3 = c[o2 + (J3 << 4) >> 2] | 0; + E3 = v3; + H3 = C3; + n2 = u3; + C3 = j2; + D3 = F3; + while (1) { + if (!D3) break; + if (!n2) { + B3 = B3 + 1 | 0; + A3 = d[(c[L3 >> 2] | 0) + B3 >> 0] | 0; + u3 = c[(c[M2 >> 2] | 0) + (B3 << 2) >> 2] | 0; + } else { + A3 = H3; + u3 = n2; + } + n2 = u3 + -1 | 0; + v3 = A3 << 6; + switch (c[R3 + (A3 << 2) >> 2] | 0) { + case 0: { + u3 = m3 & 63; + break; + } + case 1: { + u3 = (m3 & 255) >>> 2; + break; + } + case 2: { + u3 = a[406969 + (m3 & 255) >> 0] | a[406969 + (E3 & 255 | 256) >> 0]; + break; + } + case 3: { + u3 = ((d[407481 + (m3 & 255) >> 0] | 0) << 3) + (d[407481 + (E3 & 255) >> 0] | 0) & 255; + break; + } + default: + u3 = 0; + } + E3 = v3 + (u3 & 255) | 0; + H3 = g3 + (C3 & k2) | 0; + v3 = T3 + (E3 * 1040 | 0) + ((d[H3 >> 0] | 0) << 2) | 0; + c[v3 >> 2] = (c[v3 >> 2] | 0) + 1; + E3 = T3 + (E3 * 1040 | 0) + 1024 | 0; + c[E3 >> 2] = (c[E3 >> 2] | 0) + 1; + E3 = m3; + m3 = a[H3 >> 0] | 0; + H3 = A3; + C3 = C3 + 1 | 0; + D3 = D3 + -1 | 0; + } + q2 = q2 + -1 | 0; + D3 = c[o2 + (J3 << 4) + 4 >> 2] & 16777215; + j2 = j2 + F3 + D3 | 0; + if (D3) { + C3 = a[g3 + (j2 + -2 & k2) >> 0] | 0; + m3 = a[g3 + (j2 + -1 & k2) >> 0] | 0; + v3 = b2[G3 >> 1] | 0; + if ((v3 & 65535) > 127) { + if (!l2) { + A3 = t3 + 1 | 0; + z3 = d[(c[N3 >> 2] | 0) + A3 >> 0] | 0; + l2 = c[(c[O3 >> 2] | 0) + (A3 << 2) >> 2] | 0; + } else A3 = t3; + l2 = l2 + -1 | 0; + u3 = z3 << 2; + G3 = v3 & 65535; + t3 = G3 & 7; + switch (G3 >>> 6 | 0) { + case 7: + case 4: + case 2: + case 0: { + t3 = t3 >>> 0 < 3 ? t3 : 3; + break; + } + default: + t3 = 3; + } + v3 = u3 + t3 | 0; + u3 = X3 + (v3 * 2096 | 0) + ((e[o2 + (J3 << 4) + 14 >> 1] | 0) << 2) | 0; + c[u3 >> 2] = (c[u3 >> 2] | 0) + 1; + v3 = X3 + (v3 * 2096 | 0) + 2080 | 0; + c[v3 >> 2] = (c[v3 >> 2] | 0) + 1; + v3 = C3; + u3 = z3; + t3 = A3; + } else { + v3 = C3; + u3 = z3; + } + } else { + v3 = E3; + u3 = z3; + } + z3 = u3; + A3 = I3; + C3 = H3; + u3 = n2; + J3 = J3 + 1 | 0; + } + H3 = f2 + 4 | 0; + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, R3); + t3 = r2 + 72 | 0; + if (c[t3 >> 2] | 0) pa2(406853, 406802, 86, 406832); + l2 = c[r2 >> 2] | 0; + q2 = r2 + 76 | 0; + c[q2 >> 2] = l2 << 6; + l2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, l2 << 8) | 0; + if (!l2) oa2(1); + c[t3 >> 2] = l2; + l2 = r2 + 88 | 0; + if (c[l2 >> 2] | 0) pa2(406882, 406802, 92, 406832); + j2 = c[q2 >> 2] | 0; + G3 = r2 + 92 | 0; + c[G3 >> 2] = j2; + j2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, j2 * 1040 | 0) | 0; + if (!j2) oa2(1); + c[l2 >> 2] = j2; + F3 = c[q2 >> 2] | 0; + l2 = c[t3 >> 2] | 0; + C3 = F3 << 2; + n2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, C3) | 0; + if (!n2) oa2(1); + D3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, C3) | 0; + if (!D3) oa2(1); + v3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, 49176) | 0; + if (!v3) oa2(1); + q2 = 0; + while (1) { + if ((q2 | 0) == (F3 | 0)) break; + c[n2 + (q2 << 2) >> 2] = 1; + q2 = q2 + 1 | 0; + } + E3 = l2; + l2 = 0; + while (1) { + if ((l2 | 0) == (F3 | 0)) break; + g3 = T3 + (l2 * 1040 | 0) | 0; + dc(j2 + (l2 * 1040 | 0) | 0, g3 | 0, 1040) | 0; + h[j2 + (l2 * 1040 | 0) + 1032 >> 3] = +Wa2(g3); + c[E3 + (l2 << 2) >> 2] = l2; + l2 = l2 + 1 | 0; + } + u3 = 0; + q2 = 0; + while (1) { + if (F3 >>> 0 <= q2 >>> 0) break; + l2 = F3 - q2 | 0; + l2 = l2 >>> 0 < 64 ? l2 : 64; + t3 = 0; + while (1) { + if ((t3 | 0) == (l2 | 0)) break; + c[D3 + (u3 + t3 << 2) >> 2] = q2 + t3; + t3 = t3 + 1 | 0; + } + u3 = u3 + (pb(j2, n2, E3 + (q2 << 2) | 0, D3 + (u3 << 2) | 0, v3, l2, l2, 256, 2048) | 0) | 0; + q2 = q2 + 64 | 0; + } + l2 = u3 << 6; + t3 = _(u3 >>> 1, u3) | 0; + t3 = l2 >>> 0 < t3 >>> 0 ? l2 : t3; + l2 = t3 + 1 | 0; + do + if (l2 >>> 0 > 2048) { + q2 = 2048; + while (1) { + if (q2 >>> 0 >= l2 >>> 0) break; + q2 = q2 << 1; + } + l2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, q2 * 24 | 0) | 0; + if (!l2) oa2(1); + else { + dc(l2 | 0, v3 | 0, 49152) | 0; + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, v3); + S3 = l2; + break; + } + } else S3 = v3; + while (0); + B3 = pb(j2, n2, E3, D3, S3, u3, F3, 256, t3) | 0; + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, S3); + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, n2); + m3 = W3 + 1024 | 0; + y3 = W3 + 1024 | 0; + A3 = 0; + while (1) { + if ((A3 | 0) == (F3 | 0)) { + l2 = 0; + break; + } + t3 = c[((A3 | 0) == 0 ? E3 : E3 + (A3 + -1 << 2) | 0) >> 2] | 0; + l2 = T3 + (A3 * 1040 | 0) | 0; + z3 = T3 + (A3 * 1040 | 0) + 1024 | 0; + if (!(c[z3 >> 2] | 0)) w2 = 0; + else { + dc(W3 | 0, l2 | 0, 1040) | 0; + c[y3 >> 2] = (c[y3 >> 2] | 0) + (c[j2 + (t3 * 1040 | 0) + 1024 >> 2] | 0); + q2 = 0; + while (1) { + if ((q2 | 0) == 256) break; + S3 = W3 + (q2 << 2) | 0; + c[S3 >> 2] = (c[S3 >> 2] | 0) + (c[j2 + (t3 * 1040 | 0) + (q2 << 2) >> 2] | 0); + q2 = q2 + 1 | 0; + } + w2 = +Wa2(W3); + w2 = w2 - +h[j2 + (t3 * 1040 | 0) + 1032 >> 3]; + } + q2 = t3; + n2 = 0; + while (1) { + if ((n2 | 0) == (B3 | 0)) break; + v3 = D3 + (n2 << 2) | 0; + t3 = c[v3 >> 2] | 0; + if (!(c[z3 >> 2] | 0)) x3 = 0; + else { + dc(W3 | 0, l2 | 0, 1040) | 0; + c[m3 >> 2] = (c[m3 >> 2] | 0) + (c[j2 + (t3 * 1040 | 0) + 1024 >> 2] | 0); + u3 = 0; + while (1) { + if ((u3 | 0) == 256) break; + S3 = W3 + (u3 << 2) | 0; + c[S3 >> 2] = (c[S3 >> 2] | 0) + (c[j2 + (t3 * 1040 | 0) + (u3 << 2) >> 2] | 0); + u3 = u3 + 1 | 0; + } + x3 = +Wa2(W3); + x3 = x3 - +h[j2 + (t3 * 1040 | 0) + 1032 >> 3]; + } + if (x3 < w2) { + w2 = x3; + q2 = c[v3 >> 2] | 0; + } + n2 = n2 + 1 | 0; + } + c[E3 + (A3 << 2) >> 2] = q2; + A3 = A3 + 1 | 0; + } + while (1) { + if ((l2 | 0) == (B3 | 0)) { + q2 = 0; + break; + } + S3 = c[D3 + (l2 << 2) >> 2] | 0; + ac(j2 + (S3 * 1040 | 0) | 0, 0, 1024) | 0; + c[j2 + (S3 * 1040 | 0) + 1024 >> 2] = 0; + h[j2 + (S3 * 1040 | 0) + 1032 >> 3] = s; + l2 = l2 + 1 | 0; + } + while (1) { + if ((q2 | 0) == (F3 | 0)) break; + l2 = c[E3 + (q2 << 2) >> 2] | 0; + t3 = j2 + (l2 * 1040 | 0) + 1024 | 0; + c[t3 >> 2] = (c[t3 >> 2] | 0) + (c[T3 + (q2 * 1040 | 0) + 1024 >> 2] | 0); + t3 = 0; + while (1) { + if ((t3 | 0) == 256) break; + S3 = j2 + (l2 * 1040 | 0) + (t3 << 2) | 0; + c[S3 >> 2] = (c[S3 >> 2] | 0) + (c[T3 + (q2 * 1040 | 0) + (t3 << 2) >> 2] | 0); + t3 = t3 + 1 | 0; + } + q2 = q2 + 1 | 0; + } + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, D3); + m3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, C3) | 0; + if (!m3) oa2(1); + l2 = 0; + while (1) { + if ((l2 | 0) == (F3 | 0)) { + l2 = 0; + t3 = 0; + break; + } + c[m3 + (l2 << 2) >> 2] = -1; + l2 = l2 + 1 | 0; + } + while (1) { + if ((t3 | 0) == (F3 | 0)) break; + q2 = m3 + (c[E3 + (t3 << 2) >> 2] << 2) | 0; + if ((c[q2 >> 2] | 0) == -1) { + c[q2 >> 2] = l2; + l2 = l2 + 1 | 0; + } + t3 = t3 + 1 | 0; + } + n2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, l2 * 1040 | 0) | 0; + if (!n2) oa2(1); + u3 = 0; + v3 = 0; + while (1) { + if ((v3 | 0) == (F3 | 0)) break; + t3 = E3 + (v3 << 2) | 0; + l2 = c[t3 >> 2] | 0; + q2 = c[m3 + (l2 << 2) >> 2] | 0; + if ((q2 | 0) == (u3 | 0)) { + dc(n2 + (u3 * 1040 | 0) | 0, j2 + (l2 * 1040 | 0) | 0, 1040) | 0; + q2 = c[m3 + (c[t3 >> 2] << 2) >> 2] | 0; + l2 = u3 + 1 | 0; + } else l2 = u3; + c[t3 >> 2] = q2; + u3 = l2; + v3 = v3 + 1 | 0; + } + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, m3); + l2 = 0; + while (1) { + if ((l2 | 0) == (u3 | 0)) break; + dc(j2 + (l2 * 1040 | 0) | 0, n2 + (l2 * 1040 | 0) | 0, 1040) | 0; + l2 = l2 + 1 | 0; + } + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, n2); + c[G3 >> 2] = u3; + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, T3); + t3 = r2 + 80 | 0; + if (c[t3 >> 2] | 0) pa2(406910, 406802, 106, 406832); + l2 = c[U3 >> 2] | 0; + q2 = r2 + 84 | 0; + c[q2 >> 2] = l2 << 2; + l2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, l2 << 4) | 0; + if (!l2) oa2(1); + c[t3 >> 2] = l2; + l2 = r2 + 104 | 0; + if (c[l2 >> 2] | 0) pa2(406940, 406802, 112, 406832); + j2 = c[q2 >> 2] | 0; + G3 = r2 + 108 | 0; + c[G3 >> 2] = j2; + j2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, j2 * 2096 | 0) | 0; + if (!j2) oa2(1); + c[l2 >> 2] = j2; + F3 = c[q2 >> 2] | 0; + l2 = c[t3 >> 2] | 0; + C3 = F3 << 2; + n2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, C3) | 0; + if (!n2) oa2(1); + D3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, C3) | 0; + if (!D3) oa2(1); + v3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, 49176) | 0; + if (!v3) oa2(1); + q2 = 0; + while (1) { + if ((q2 | 0) == (F3 | 0)) break; + c[n2 + (q2 << 2) >> 2] = 1; + q2 = q2 + 1 | 0; + } + E3 = l2; + l2 = 0; + while (1) { + if ((l2 | 0) == (F3 | 0)) break; + r2 = X3 + (l2 * 2096 | 0) | 0; + dc(j2 + (l2 * 2096 | 0) | 0, r2 | 0, 2096) | 0; + h[j2 + (l2 * 2096 | 0) + 2088 >> 3] = +Ya(r2); + c[E3 + (l2 << 2) >> 2] = l2; + l2 = l2 + 1 | 0; + } + u3 = 0; + q2 = 0; + while (1) { + if (F3 >>> 0 <= q2 >>> 0) break; + l2 = F3 - q2 | 0; + l2 = l2 >>> 0 < 64 ? l2 : 64; + t3 = 0; + while (1) { + if ((t3 | 0) == (l2 | 0)) break; + c[D3 + (u3 + t3 << 2) >> 2] = q2 + t3; + t3 = t3 + 1 | 0; + } + u3 = u3 + (tb(j2, n2, E3 + (q2 << 2) | 0, D3 + (u3 << 2) | 0, v3, l2, l2, 256, 2048) | 0) | 0; + q2 = q2 + 64 | 0; + } + l2 = u3 << 6; + t3 = _(u3 >>> 1, u3) | 0; + t3 = l2 >>> 0 < t3 >>> 0 ? l2 : t3; + l2 = t3 + 1 | 0; + do + if (l2 >>> 0 > 2048) { + q2 = 2048; + while (1) { + if (q2 >>> 0 >= l2 >>> 0) break; + q2 = q2 << 1; + } + l2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, q2 * 24 | 0) | 0; + if (!l2) oa2(1); + else { + dc(l2 | 0, v3 | 0, 49152) | 0; + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, v3); + V3 = l2; + break; + } + } else V3 = v3; + while (0); + B3 = tb(j2, n2, E3, D3, V3, u3, F3, 256, t3) | 0; + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, V3); + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, n2); + m3 = W3 + 2080 | 0; + y3 = W3 + 2080 | 0; + A3 = 0; + while (1) { + if ((A3 | 0) == (F3 | 0)) { + l2 = 0; + break; + } + t3 = c[((A3 | 0) == 0 ? E3 : E3 + (A3 + -1 << 2) | 0) >> 2] | 0; + l2 = X3 + (A3 * 2096 | 0) | 0; + z3 = X3 + (A3 * 2096 | 0) + 2080 | 0; + if (!(c[z3 >> 2] | 0)) w2 = 0; + else { + dc(W3 | 0, l2 | 0, 2096) | 0; + c[y3 >> 2] = (c[y3 >> 2] | 0) + (c[j2 + (t3 * 2096 | 0) + 2080 >> 2] | 0); + q2 = 0; + while (1) { + if ((q2 | 0) == 520) break; + V3 = W3 + (q2 << 2) | 0; + c[V3 >> 2] = (c[V3 >> 2] | 0) + (c[j2 + (t3 * 2096 | 0) + (q2 << 2) >> 2] | 0); + q2 = q2 + 1 | 0; + } + w2 = +Ya(W3); + w2 = w2 - +h[j2 + (t3 * 2096 | 0) + 2088 >> 3]; + } + q2 = t3; + n2 = 0; + while (1) { + if ((n2 | 0) == (B3 | 0)) break; + v3 = D3 + (n2 << 2) | 0; + t3 = c[v3 >> 2] | 0; + if (!(c[z3 >> 2] | 0)) x3 = 0; + else { + dc(W3 | 0, l2 | 0, 2096) | 0; + c[m3 >> 2] = (c[m3 >> 2] | 0) + (c[j2 + (t3 * 2096 | 0) + 2080 >> 2] | 0); + u3 = 0; + while (1) { + if ((u3 | 0) == 520) break; + V3 = W3 + (u3 << 2) | 0; + c[V3 >> 2] = (c[V3 >> 2] | 0) + (c[j2 + (t3 * 2096 | 0) + (u3 << 2) >> 2] | 0); + u3 = u3 + 1 | 0; + } + x3 = +Ya(W3); + x3 = x3 - +h[j2 + (t3 * 2096 | 0) + 2088 >> 3]; + } + if (x3 < w2) { + w2 = x3; + q2 = c[v3 >> 2] | 0; + } + n2 = n2 + 1 | 0; + } + c[E3 + (A3 << 2) >> 2] = q2; + A3 = A3 + 1 | 0; + } + while (1) { + if ((l2 | 0) == (B3 | 0)) { + q2 = 0; + break; + } + W3 = c[D3 + (l2 << 2) >> 2] | 0; + ac(j2 + (W3 * 2096 | 0) | 0, 0, 2080) | 0; + c[j2 + (W3 * 2096 | 0) + 2080 >> 2] = 0; + h[j2 + (W3 * 2096 | 0) + 2088 >> 3] = s; + l2 = l2 + 1 | 0; + } + while (1) { + if ((q2 | 0) == (F3 | 0)) break; + l2 = c[E3 + (q2 << 2) >> 2] | 0; + t3 = j2 + (l2 * 2096 | 0) + 2080 | 0; + c[t3 >> 2] = (c[t3 >> 2] | 0) + (c[X3 + (q2 * 2096 | 0) + 2080 >> 2] | 0); + t3 = 0; + while (1) { + if ((t3 | 0) == 520) break; + W3 = j2 + (l2 * 2096 | 0) + (t3 << 2) | 0; + c[W3 >> 2] = (c[W3 >> 2] | 0) + (c[X3 + (q2 * 2096 | 0) + (t3 << 2) >> 2] | 0); + t3 = t3 + 1 | 0; + } + q2 = q2 + 1 | 0; + } + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, D3); + m3 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, C3) | 0; + if (!m3) oa2(1); + l2 = 0; + while (1) { + if ((l2 | 0) == (F3 | 0)) { + l2 = 0; + t3 = 0; + break; + } + c[m3 + (l2 << 2) >> 2] = -1; + l2 = l2 + 1 | 0; + } + while (1) { + if ((t3 | 0) == (F3 | 0)) break; + q2 = m3 + (c[E3 + (t3 << 2) >> 2] << 2) | 0; + if ((c[q2 >> 2] | 0) == -1) { + c[q2 >> 2] = l2; + l2 = l2 + 1 | 0; + } + t3 = t3 + 1 | 0; + } + n2 = sa2[c[f2 >> 2] & 1](c[Y3 >> 2] | 0, l2 * 2096 | 0) | 0; + if (!n2) oa2(1); + u3 = 0; + v3 = 0; + while (1) { + if ((v3 | 0) == (F3 | 0)) break; + t3 = E3 + (v3 << 2) | 0; + l2 = c[t3 >> 2] | 0; + q2 = c[m3 + (l2 << 2) >> 2] | 0; + if ((q2 | 0) == (u3 | 0)) { + dc(n2 + (u3 * 2096 | 0) | 0, j2 + (l2 * 2096 | 0) | 0, 2096) | 0; + q2 = c[m3 + (c[t3 >> 2] << 2) >> 2] | 0; + l2 = u3 + 1 | 0; + } else l2 = u3; + c[t3 >> 2] = q2; + u3 = l2; + v3 = v3 + 1 | 0; + } + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, m3); + l2 = 0; + while (1) { + if ((l2 | 0) == (u3 | 0)) break; + dc(j2 + (l2 * 2096 | 0) | 0, n2 + (l2 * 2096 | 0) | 0, 2096) | 0; + l2 = l2 + 1 | 0; + } + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, n2); + c[G3 >> 2] = u3; + ra2[c[H3 >> 2] & 1](c[Y3 >> 2] | 0, X3); + i = Z3; + return; + } + function Ob(a2, b3, d2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + var e2 = 0, f2 = 0, g3 = 0, h2 = 0, j2 = 0; + j2 = i; + i = i + 704 | 0; + h2 = j2; + e2 = d2 + 92 | 0; + f2 = d2 + 88 | 0; + g3 = 0; + while (1) { + if (g3 >>> 0 >= (c[e2 >> 2] | 0) >>> 0) break; + Ib(256, (c[f2 >> 2] | 0) + (g3 * 1040 | 0) | 0, h2); + g3 = g3 + 1 | 0; + } + e2 = d2 + 100 | 0; + f2 = d2 + 96 | 0; + g3 = 0; + while (1) { + if (g3 >>> 0 >= (c[e2 >> 2] | 0) >>> 0) break; + Ib(704, (c[f2 >> 2] | 0) + (g3 * 2832 | 0) | 0, h2); + g3 = g3 + 1 | 0; + } + g3 = a2 + 16 + (48 << b3) | 0; + b3 = d2 + 108 | 0; + e2 = d2 + 104 | 0; + f2 = 0; + while (1) { + if (f2 >>> 0 >= (c[b3 >> 2] | 0) >>> 0) break; + Ib(g3, (c[e2 >> 2] | 0) + (f2 * 2096 | 0) | 0, h2); + f2 = f2 + 1 | 0; + } + i = j2; + return; + } + function Pb(a2, b3, d2, e2, f2, g3) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + var i2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0; + o2 = (d2 >>> 10) + 1 | 0; + n2 = o2 >>> 0 < 257 ? o2 : 257; + c[b3 >> 2] = 704; + c[b3 + 4 >> 2] = 1024; + h[b3 + 8 >> 3] = 500; + c[b3 + 16 >> 2] = 0; + p2 = b3 + 20 | 0; + c[p2 >> 2] = e2; + c[b3 + 28 >> 2] = g3; + c[b3 + 32 >> 2] = 1024; + c[b3 + 36 >> 2] = 0; + c[b3 + 40 >> 2] = 0; + c[b3 + 72 >> 2] = 0; + m3 = e2 + 16 | 0; + d2 = c[m3 >> 2] | 0; + if (d2 >>> 0 < o2 >>> 0) { + l2 = (d2 | 0) == 0 ? o2 : d2; + while (1) { + if (l2 >>> 0 >= o2 >>> 0) break; + l2 = l2 << 1; + } + i2 = a2 + 8 | 0; + j2 = sa2[c[a2 >> 2] & 1](c[i2 >> 2] | 0, l2) | 0; + if (!j2) oa2(1); + k2 = c[m3 >> 2] | 0; + d2 = e2 + 8 | 0; + if (k2) dc(j2 | 0, c[d2 >> 2] | 0, k2 | 0) | 0; + ra2[c[a2 + 4 >> 2] & 1](c[i2 >> 2] | 0, c[d2 >> 2] | 0); + c[d2 >> 2] = j2; + c[m3 >> 2] = l2; + } + m3 = e2 + 20 | 0; + d2 = c[m3 >> 2] | 0; + if (d2 >>> 0 < o2 >>> 0) { + l2 = (d2 | 0) == 0 ? o2 : d2; + while (1) { + if (l2 >>> 0 >= o2 >>> 0) break; + l2 = l2 << 1; + } + i2 = a2 + 8 | 0; + j2 = sa2[c[a2 >> 2] & 1](c[i2 >> 2] | 0, l2 << 2) | 0; + if (!j2) oa2(1); + k2 = c[m3 >> 2] | 0; + d2 = e2 + 12 | 0; + if (k2) dc(j2 | 0, c[d2 >> 2] | 0, k2 << 2 | 0) | 0; + ra2[c[a2 + 4 >> 2] & 1](c[i2 >> 2] | 0, c[d2 >> 2] | 0); + c[d2 >> 2] = j2; + c[m3 >> 2] = l2; + } + c[(c[p2 >> 2] | 0) + 4 >> 2] = o2; + if (c[f2 >> 2] | 0) pa2(407776, 407818, 70, 407880); + c[g3 >> 2] = n2; + d2 = sa2[c[a2 >> 2] & 1](c[a2 + 8 >> 2] | 0, n2 * 2832 | 0) | 0; + i2 = d2; + if (!d2) oa2(1); + else { + c[f2 >> 2] = i2; + c[b3 + 24 >> 2] = i2; + ac(d2 | 0, 0, 2816) | 0; + c[d2 + 2816 >> 2] = 0; + h[d2 + 2824 >> 3] = s; + c[b3 + 48 >> 2] = 0; + c[b3 + 44 >> 2] = 0; + return; + } + } + function Qb(a2, b3, d2, e2, f2, g3) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + g3 = g3 | 0; + var i2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0; + o2 = (d2 >>> 9) + 1 | 0; + n2 = o2 >>> 0 < 257 ? o2 : 257; + c[b3 >> 2] = 64; + c[b3 + 4 >> 2] = 512; + h[b3 + 8 >> 3] = 100; + c[b3 + 16 >> 2] = 0; + p2 = b3 + 20 | 0; + c[p2 >> 2] = e2; + c[b3 + 28 >> 2] = g3; + c[b3 + 32 >> 2] = 512; + c[b3 + 36 >> 2] = 0; + c[b3 + 40 >> 2] = 0; + c[b3 + 72 >> 2] = 0; + m3 = e2 + 16 | 0; + d2 = c[m3 >> 2] | 0; + if (d2 >>> 0 < o2 >>> 0) { + l2 = (d2 | 0) == 0 ? o2 : d2; + while (1) { + if (l2 >>> 0 >= o2 >>> 0) break; + l2 = l2 << 1; + } + i2 = a2 + 8 | 0; + j2 = sa2[c[a2 >> 2] & 1](c[i2 >> 2] | 0, l2) | 0; + if (!j2) oa2(1); + k2 = c[m3 >> 2] | 0; + d2 = e2 + 8 | 0; + if (k2) dc(j2 | 0, c[d2 >> 2] | 0, k2 | 0) | 0; + ra2[c[a2 + 4 >> 2] & 1](c[i2 >> 2] | 0, c[d2 >> 2] | 0); + c[d2 >> 2] = j2; + c[m3 >> 2] = l2; + } + m3 = e2 + 20 | 0; + d2 = c[m3 >> 2] | 0; + if (d2 >>> 0 < o2 >>> 0) { + l2 = (d2 | 0) == 0 ? o2 : d2; + while (1) { + if (l2 >>> 0 >= o2 >>> 0) break; + l2 = l2 << 1; + } + i2 = a2 + 8 | 0; + j2 = sa2[c[a2 >> 2] & 1](c[i2 >> 2] | 0, l2 << 2) | 0; + if (!j2) oa2(1); + k2 = c[m3 >> 2] | 0; + d2 = e2 + 12 | 0; + if (k2) dc(j2 | 0, c[d2 >> 2] | 0, k2 << 2 | 0) | 0; + ra2[c[a2 + 4 >> 2] & 1](c[i2 >> 2] | 0, c[d2 >> 2] | 0); + c[d2 >> 2] = j2; + c[m3 >> 2] = l2; + } + c[(c[p2 >> 2] | 0) + 4 >> 2] = o2; + if (c[f2 >> 2] | 0) pa2(407776, 407818, 70, 407854); + c[g3 >> 2] = n2; + d2 = sa2[c[a2 >> 2] & 1](c[a2 + 8 >> 2] | 0, n2 * 2096 | 0) | 0; + i2 = d2; + if (!d2) oa2(1); + else { + c[f2 >> 2] = i2; + c[b3 + 24 >> 2] = i2; + ac(d2 | 0, 0, 2080) | 0; + c[d2 + 2080 >> 2] = 0; + h[d2 + 2088 >> 3] = s; + c[b3 + 48 >> 2] = 0; + c[b3 + 44 >> 2] = 0; + return; + } + } + function Rb(b3, d2) { + b3 = b3 | 0; + d2 = d2 | 0; + var e2 = 0, f2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0; + J3 = i; + i = i + 2112 | 0; + y3 = J3 + 32 | 0; + x3 = J3 + 16 | 0; + z3 = J3; + G3 = c[b3 + 20 >> 2] | 0; + F3 = b3 + 56 | 0; + e2 = c[b3 + 24 >> 2] | 0; + I3 = b3 + 36 | 0; + H3 = c[I3 >> 2] | 0; + D3 = b3 + 4 | 0; + B3 = c[D3 >> 2] | 0; + B3 = H3 >>> 0 > B3 >>> 0 ? H3 : B3; + c[I3 >> 2] = B3; + H3 = b3 + 16 | 0; + w2 = c[H3 >> 2] | 0; + do + if (w2) { + if (B3) { + E3 = b3 + 40 | 0; + u3 = c[E3 >> 2] | 0; + C3 = e2; + q2 = c[b3 >> 2] | 0; + e2 = C3 + (u3 * 1040 | 0) | 0; + o2 = C3 + (u3 * 1040 | 0) + (q2 << 2) | 0; + t3 = (q2 & 1 | 0) == 0; + if (t3) { + f2 = 0; + n2 = 0; + } else { + k2 = 0; + n2 = 0; + A3 = 27; + } + while (1) { + if ((A3 | 0) == 27) { + A3 = 0; + m3 = c[e2 >> 2] | 0; + f2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) j2 = +g2[19516 + (m3 << 2) >> 2]; + else j2 = +Xb(f2); + e2 = e2 + 4 | 0; + f2 = k2 - f2 * j2; + n2 = n2 + m3 | 0; + } + if (e2 >>> 0 >= o2 >>> 0) break; + m3 = c[e2 >> 2] | 0; + j2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) k2 = +g2[19516 + (m3 << 2) >> 2]; + else k2 = +Xb(j2); + e2 = e2 + 4 | 0; + k2 = f2 - j2 * k2; + n2 = n2 + m3 | 0; + A3 = 27; + } + l2 = +(n2 >>> 0); + if (!n2) k2 = l2; + else { + if (n2 >>> 0 < 256) j2 = +g2[19516 + (n2 << 2) >> 2]; + else j2 = +Xb(l2); + k2 = l2; + f2 = f2 + l2 * j2; + } + r2 = f2 < k2 ? k2 : f2; + p2 = 0; + while (1) { + if ((p2 | 0) == 2) break; + e2 = c[b3 + 44 + (p2 << 2) >> 2] | 0; + dc(y3 + (p2 * 1040 | 0) | 0, C3 + (u3 * 1040 | 0) | 0, 1040) | 0; + m3 = y3 + (p2 * 1040 | 0) + 1024 | 0; + c[m3 >> 2] = (c[m3 >> 2] | 0) + (c[C3 + (e2 * 1040 | 0) + 1024 >> 2] | 0); + m3 = 0; + while (1) { + if ((m3 | 0) == 256) break; + o2 = y3 + (p2 * 1040 | 0) + (m3 << 2) | 0; + c[o2 >> 2] = (c[o2 >> 2] | 0) + (c[C3 + (e2 * 1040 | 0) + (m3 << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + e2 = y3 + (p2 * 1040 | 0) | 0; + o2 = y3 + (p2 * 1040 | 0) + (q2 << 2) | 0; + if (t3) { + f2 = 0; + n2 = 0; + } else { + k2 = 0; + n2 = 0; + A3 = 47; + } + while (1) { + if ((A3 | 0) == 47) { + A3 = 0; + m3 = c[e2 >> 2] | 0; + f2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) j2 = +g2[19516 + (m3 << 2) >> 2]; + else j2 = +Xb(f2); + e2 = e2 + 4 | 0; + f2 = k2 - f2 * j2; + n2 = n2 + m3 | 0; + } + if (e2 >>> 0 >= o2 >>> 0) break; + m3 = c[e2 >> 2] | 0; + j2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) k2 = +g2[19516 + (m3 << 2) >> 2]; + else k2 = +Xb(j2); + e2 = e2 + 4 | 0; + k2 = f2 - j2 * k2; + n2 = n2 + m3 | 0; + A3 = 47; + } + l2 = +(n2 >>> 0); + if (!n2) k2 = l2; + else { + if (n2 >>> 0 < 256) j2 = +g2[19516 + (n2 << 2) >> 2]; + else j2 = +Xb(l2); + k2 = l2; + f2 = f2 + l2 * j2; + } + l2 = f2 < k2 ? k2 : f2; + h[x3 + (p2 << 3) >> 3] = l2; + h[z3 + (p2 << 3) >> 3] = l2 - r2 - +h[b3 + 56 + (p2 << 3) >> 3]; + p2 = p2 + 1 | 0; + } + e2 = G3; + f2 = +h[z3 >> 3]; + if (((c[e2 >> 2] | 0) >>> 0 < 256 ? (v3 = +h[b3 + 8 >> 3], f2 > v3) : 0) ? +h[z3 + 8 >> 3] > v3 : 0) { + c[(c[e2 + 12 >> 2] | 0) + (w2 << 2) >> 2] = B3; + a[(c[e2 + 8 >> 2] | 0) + (c[H3 >> 2] | 0) >> 0] = c[e2 >> 2]; + B3 = b3 + 44 | 0; + c[b3 + 48 >> 2] = c[B3 >> 2]; + c[B3 >> 2] = c[e2 >> 2] & 255; + h[b3 + 64 >> 3] = +h[F3 >> 3]; + h[F3 >> 3] = r2; + c[H3 >> 2] = (c[H3 >> 2] | 0) + 1; + c[e2 >> 2] = (c[e2 >> 2] | 0) + 1; + e2 = (c[E3 >> 2] | 0) + 1 | 0; + c[E3 >> 2] = e2; + if (e2 >>> 0 < (c[c[b3 + 28 >> 2] >> 2] | 0) >>> 0) { + ac(C3 + (e2 * 1040 | 0) | 0, 0, 1024) | 0; + c[C3 + (e2 * 1040 | 0) + 1024 >> 2] = 0; + h[C3 + (e2 * 1040 | 0) + 1032 >> 3] = s; + } + c[I3 >> 2] = 0; + c[b3 + 72 >> 2] = 0; + c[b3 + 32 >> 2] = c[D3 >> 2]; + break; + } + if (+h[z3 + 8 >> 3] < f2 + -20) { + c[(c[e2 + 12 >> 2] | 0) + (w2 << 2) >> 2] = B3; + w2 = c[H3 >> 2] | 0; + z3 = c[e2 + 8 >> 2] | 0; + a[z3 + w2 >> 0] = a[z3 + (w2 + -2) >> 0] | 0; + w2 = b3 + 44 | 0; + z3 = c[w2 >> 2] | 0; + A3 = b3 + 48 | 0; + B3 = c[A3 >> 2] | 0; + c[w2 >> 2] = B3; + c[A3 >> 2] = z3; + dc(C3 + (B3 * 1040 | 0) | 0, y3 + 1040 | 0, 1040) | 0; + h[b3 + 64 >> 3] = +h[F3 >> 3]; + h[F3 >> 3] = +h[x3 + 8 >> 3]; + c[H3 >> 2] = (c[H3 >> 2] | 0) + 1; + c[I3 >> 2] = 0; + I3 = c[E3 >> 2] | 0; + ac(C3 + (I3 * 1040 | 0) | 0, 0, 1024) | 0; + c[C3 + (I3 * 1040 | 0) + 1024 >> 2] = 0; + h[C3 + (I3 * 1040 | 0) + 1032 >> 3] = s; + c[b3 + 72 >> 2] = 0; + c[b3 + 32 >> 2] = c[D3 >> 2]; + break; + } + A3 = (c[e2 + 12 >> 2] | 0) + (w2 + -1 << 2) | 0; + c[A3 >> 2] = (c[A3 >> 2] | 0) + B3; + dc(C3 + ((c[b3 + 44 >> 2] | 0) * 1040 | 0) | 0, y3 | 0, 1040) | 0; + f2 = +h[x3 >> 3]; + h[F3 >> 3] = f2; + if ((c[e2 >> 2] | 0) == 1) h[b3 + 64 >> 3] = f2; + c[I3 >> 2] = 0; + F3 = c[E3 >> 2] | 0; + ac(C3 + (F3 * 1040 | 0) | 0, 0, 1024) | 0; + c[C3 + (F3 * 1040 | 0) + 1024 >> 2] = 0; + h[C3 + (F3 * 1040 | 0) + 1032 >> 3] = s; + F3 = b3 + 72 | 0; + I3 = (c[F3 >> 2] | 0) + 1 | 0; + c[F3 >> 2] = I3; + if (I3 >>> 0 > 1) { + I3 = b3 + 32 | 0; + c[I3 >> 2] = (c[I3 >> 2] | 0) + (c[D3 >> 2] | 0); + } + } + } else { + p2 = G3; + c[c[p2 + 12 >> 2] >> 2] = B3; + a[c[p2 + 8 >> 2] >> 0] = 0; + q2 = e2; + E3 = c[b3 >> 2] | 0; + o2 = q2 + (E3 << 2) | 0; + if (!(E3 & 1)) { + f2 = 0; + n2 = 0; + } else { + k2 = 0; + n2 = 0; + A3 = 8; + } + while (1) { + if ((A3 | 0) == 8) { + m3 = c[e2 >> 2] | 0; + f2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) j2 = +g2[19516 + (m3 << 2) >> 2]; + else j2 = +Xb(f2); + e2 = e2 + 4 | 0; + f2 = k2 - f2 * j2; + n2 = n2 + m3 | 0; + } + if (e2 >>> 0 >= o2 >>> 0) break; + m3 = c[e2 >> 2] | 0; + j2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) k2 = +g2[19516 + (m3 << 2) >> 2]; + else k2 = +Xb(j2); + e2 = e2 + 4 | 0; + k2 = f2 - j2 * k2; + n2 = n2 + m3 | 0; + A3 = 8; + } + l2 = +(n2 >>> 0); + if (!n2) k2 = l2; + else { + if (n2 >>> 0 < 256) j2 = +g2[19516 + (n2 << 2) >> 2]; + else j2 = +Xb(l2); + k2 = l2; + f2 = f2 + l2 * j2; + } + v3 = f2 < k2 ? k2 : f2; + h[F3 >> 3] = v3; + h[b3 + 64 >> 3] = v3; + c[H3 >> 2] = (c[H3 >> 2] | 0) + 1; + c[p2 >> 2] = (c[p2 >> 2] | 0) + 1; + F3 = b3 + 40 | 0; + e2 = (c[F3 >> 2] | 0) + 1 | 0; + c[F3 >> 2] = e2; + if (e2 >>> 0 < (c[c[b3 + 28 >> 2] >> 2] | 0) >>> 0) { + ac(q2 + (e2 * 1040 | 0) | 0, 0, 1024) | 0; + c[q2 + (e2 * 1040 | 0) + 1024 >> 2] = 0; + h[q2 + (e2 * 1040 | 0) + 1032 >> 3] = s; + } + c[I3 >> 2] = 0; + } + while (0); + if (!d2) { + i = J3; + return; + } + d2 = G3; + c[c[b3 + 28 >> 2] >> 2] = c[d2 >> 2]; + c[d2 + 4 >> 2] = c[H3 >> 2]; + i = J3; + return; + } + function Sb(b3, d2) { + b3 = b3 | 0; + d2 = d2 | 0; + var e2 = 0, f2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0; + J3 = i; + i = i + 5696 | 0; + y3 = J3 + 32 | 0; + x3 = J3 + 16 | 0; + z3 = J3; + G3 = c[b3 + 20 >> 2] | 0; + F3 = b3 + 56 | 0; + e2 = c[b3 + 24 >> 2] | 0; + I3 = b3 + 36 | 0; + H3 = c[I3 >> 2] | 0; + D3 = b3 + 4 | 0; + B3 = c[D3 >> 2] | 0; + B3 = H3 >>> 0 > B3 >>> 0 ? H3 : B3; + c[I3 >> 2] = B3; + H3 = b3 + 16 | 0; + w2 = c[H3 >> 2] | 0; + do + if (w2) { + if (B3) { + E3 = b3 + 40 | 0; + u3 = c[E3 >> 2] | 0; + C3 = e2; + q2 = c[b3 >> 2] | 0; + e2 = C3 + (u3 * 2832 | 0) | 0; + o2 = C3 + (u3 * 2832 | 0) + (q2 << 2) | 0; + t3 = (q2 & 1 | 0) == 0; + if (t3) { + f2 = 0; + n2 = 0; + } else { + k2 = 0; + n2 = 0; + A3 = 27; + } + while (1) { + if ((A3 | 0) == 27) { + A3 = 0; + m3 = c[e2 >> 2] | 0; + f2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) j2 = +g2[19516 + (m3 << 2) >> 2]; + else j2 = +Xb(f2); + e2 = e2 + 4 | 0; + f2 = k2 - f2 * j2; + n2 = n2 + m3 | 0; + } + if (e2 >>> 0 >= o2 >>> 0) break; + m3 = c[e2 >> 2] | 0; + j2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) k2 = +g2[19516 + (m3 << 2) >> 2]; + else k2 = +Xb(j2); + e2 = e2 + 4 | 0; + k2 = f2 - j2 * k2; + n2 = n2 + m3 | 0; + A3 = 27; + } + l2 = +(n2 >>> 0); + if (!n2) k2 = l2; + else { + if (n2 >>> 0 < 256) j2 = +g2[19516 + (n2 << 2) >> 2]; + else j2 = +Xb(l2); + k2 = l2; + f2 = f2 + l2 * j2; + } + r2 = f2 < k2 ? k2 : f2; + p2 = 0; + while (1) { + if ((p2 | 0) == 2) break; + e2 = c[b3 + 44 + (p2 << 2) >> 2] | 0; + dc(y3 + (p2 * 2832 | 0) | 0, C3 + (u3 * 2832 | 0) | 0, 2832) | 0; + m3 = y3 + (p2 * 2832 | 0) + 2816 | 0; + c[m3 >> 2] = (c[m3 >> 2] | 0) + (c[C3 + (e2 * 2832 | 0) + 2816 >> 2] | 0); + m3 = 0; + while (1) { + if ((m3 | 0) == 704) break; + o2 = y3 + (p2 * 2832 | 0) + (m3 << 2) | 0; + c[o2 >> 2] = (c[o2 >> 2] | 0) + (c[C3 + (e2 * 2832 | 0) + (m3 << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + e2 = y3 + (p2 * 2832 | 0) | 0; + o2 = y3 + (p2 * 2832 | 0) + (q2 << 2) | 0; + if (t3) { + f2 = 0; + n2 = 0; + } else { + k2 = 0; + n2 = 0; + A3 = 47; + } + while (1) { + if ((A3 | 0) == 47) { + A3 = 0; + m3 = c[e2 >> 2] | 0; + f2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) j2 = +g2[19516 + (m3 << 2) >> 2]; + else j2 = +Xb(f2); + e2 = e2 + 4 | 0; + f2 = k2 - f2 * j2; + n2 = n2 + m3 | 0; + } + if (e2 >>> 0 >= o2 >>> 0) break; + m3 = c[e2 >> 2] | 0; + j2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) k2 = +g2[19516 + (m3 << 2) >> 2]; + else k2 = +Xb(j2); + e2 = e2 + 4 | 0; + k2 = f2 - j2 * k2; + n2 = n2 + m3 | 0; + A3 = 47; + } + l2 = +(n2 >>> 0); + if (!n2) k2 = l2; + else { + if (n2 >>> 0 < 256) j2 = +g2[19516 + (n2 << 2) >> 2]; + else j2 = +Xb(l2); + k2 = l2; + f2 = f2 + l2 * j2; + } + l2 = f2 < k2 ? k2 : f2; + h[x3 + (p2 << 3) >> 3] = l2; + h[z3 + (p2 << 3) >> 3] = l2 - r2 - +h[b3 + 56 + (p2 << 3) >> 3]; + p2 = p2 + 1 | 0; + } + e2 = G3; + f2 = +h[z3 >> 3]; + if (((c[e2 >> 2] | 0) >>> 0 < 256 ? (v3 = +h[b3 + 8 >> 3], f2 > v3) : 0) ? +h[z3 + 8 >> 3] > v3 : 0) { + c[(c[e2 + 12 >> 2] | 0) + (w2 << 2) >> 2] = B3; + a[(c[e2 + 8 >> 2] | 0) + (c[H3 >> 2] | 0) >> 0] = c[e2 >> 2]; + B3 = b3 + 44 | 0; + c[b3 + 48 >> 2] = c[B3 >> 2]; + c[B3 >> 2] = c[e2 >> 2] & 255; + h[b3 + 64 >> 3] = +h[F3 >> 3]; + h[F3 >> 3] = r2; + c[H3 >> 2] = (c[H3 >> 2] | 0) + 1; + c[e2 >> 2] = (c[e2 >> 2] | 0) + 1; + e2 = (c[E3 >> 2] | 0) + 1 | 0; + c[E3 >> 2] = e2; + if (e2 >>> 0 < (c[c[b3 + 28 >> 2] >> 2] | 0) >>> 0) { + ac(C3 + (e2 * 2832 | 0) | 0, 0, 2816) | 0; + c[C3 + (e2 * 2832 | 0) + 2816 >> 2] = 0; + h[C3 + (e2 * 2832 | 0) + 2824 >> 3] = s; + } + c[I3 >> 2] = 0; + c[b3 + 72 >> 2] = 0; + c[b3 + 32 >> 2] = c[D3 >> 2]; + break; + } + if (+h[z3 + 8 >> 3] < f2 + -20) { + c[(c[e2 + 12 >> 2] | 0) + (w2 << 2) >> 2] = B3; + w2 = c[H3 >> 2] | 0; + z3 = c[e2 + 8 >> 2] | 0; + a[z3 + w2 >> 0] = a[z3 + (w2 + -2) >> 0] | 0; + w2 = b3 + 44 | 0; + z3 = c[w2 >> 2] | 0; + A3 = b3 + 48 | 0; + B3 = c[A3 >> 2] | 0; + c[w2 >> 2] = B3; + c[A3 >> 2] = z3; + dc(C3 + (B3 * 2832 | 0) | 0, y3 + 2832 | 0, 2832) | 0; + h[b3 + 64 >> 3] = +h[F3 >> 3]; + h[F3 >> 3] = +h[x3 + 8 >> 3]; + c[H3 >> 2] = (c[H3 >> 2] | 0) + 1; + c[I3 >> 2] = 0; + I3 = c[E3 >> 2] | 0; + ac(C3 + (I3 * 2832 | 0) | 0, 0, 2816) | 0; + c[C3 + (I3 * 2832 | 0) + 2816 >> 2] = 0; + h[C3 + (I3 * 2832 | 0) + 2824 >> 3] = s; + c[b3 + 72 >> 2] = 0; + c[b3 + 32 >> 2] = c[D3 >> 2]; + break; + } + A3 = (c[e2 + 12 >> 2] | 0) + (w2 + -1 << 2) | 0; + c[A3 >> 2] = (c[A3 >> 2] | 0) + B3; + dc(C3 + ((c[b3 + 44 >> 2] | 0) * 2832 | 0) | 0, y3 | 0, 2832) | 0; + f2 = +h[x3 >> 3]; + h[F3 >> 3] = f2; + if ((c[e2 >> 2] | 0) == 1) h[b3 + 64 >> 3] = f2; + c[I3 >> 2] = 0; + F3 = c[E3 >> 2] | 0; + ac(C3 + (F3 * 2832 | 0) | 0, 0, 2816) | 0; + c[C3 + (F3 * 2832 | 0) + 2816 >> 2] = 0; + h[C3 + (F3 * 2832 | 0) + 2824 >> 3] = s; + F3 = b3 + 72 | 0; + I3 = (c[F3 >> 2] | 0) + 1 | 0; + c[F3 >> 2] = I3; + if (I3 >>> 0 > 1) { + I3 = b3 + 32 | 0; + c[I3 >> 2] = (c[I3 >> 2] | 0) + (c[D3 >> 2] | 0); + } + } + } else { + p2 = G3; + c[c[p2 + 12 >> 2] >> 2] = B3; + a[c[p2 + 8 >> 2] >> 0] = 0; + q2 = e2; + E3 = c[b3 >> 2] | 0; + o2 = q2 + (E3 << 2) | 0; + if (!(E3 & 1)) { + f2 = 0; + n2 = 0; + } else { + k2 = 0; + n2 = 0; + A3 = 8; + } + while (1) { + if ((A3 | 0) == 8) { + m3 = c[e2 >> 2] | 0; + f2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) j2 = +g2[19516 + (m3 << 2) >> 2]; + else j2 = +Xb(f2); + e2 = e2 + 4 | 0; + f2 = k2 - f2 * j2; + n2 = n2 + m3 | 0; + } + if (e2 >>> 0 >= o2 >>> 0) break; + m3 = c[e2 >> 2] | 0; + j2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) k2 = +g2[19516 + (m3 << 2) >> 2]; + else k2 = +Xb(j2); + e2 = e2 + 4 | 0; + k2 = f2 - j2 * k2; + n2 = n2 + m3 | 0; + A3 = 8; + } + l2 = +(n2 >>> 0); + if (!n2) k2 = l2; + else { + if (n2 >>> 0 < 256) j2 = +g2[19516 + (n2 << 2) >> 2]; + else j2 = +Xb(l2); + k2 = l2; + f2 = f2 + l2 * j2; + } + v3 = f2 < k2 ? k2 : f2; + h[F3 >> 3] = v3; + h[b3 + 64 >> 3] = v3; + c[H3 >> 2] = (c[H3 >> 2] | 0) + 1; + c[p2 >> 2] = (c[p2 >> 2] | 0) + 1; + F3 = b3 + 40 | 0; + e2 = (c[F3 >> 2] | 0) + 1 | 0; + c[F3 >> 2] = e2; + if (e2 >>> 0 < (c[c[b3 + 28 >> 2] >> 2] | 0) >>> 0) { + ac(q2 + (e2 * 2832 | 0) | 0, 0, 2816) | 0; + c[q2 + (e2 * 2832 | 0) + 2816 >> 2] = 0; + h[q2 + (e2 * 2832 | 0) + 2824 >> 3] = s; + } + c[I3 >> 2] = 0; + } + while (0); + if (!d2) { + i = J3; + return; + } + d2 = G3; + c[c[b3 + 28 >> 2] >> 2] = c[d2 >> 2]; + c[d2 + 4 >> 2] = c[H3 >> 2]; + i = J3; + return; + } + function Tb(b3, d2) { + b3 = b3 | 0; + d2 = d2 | 0; + var e2 = 0, f2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0; + J3 = i; + i = i + 4224 | 0; + y3 = J3 + 32 | 0; + x3 = J3 + 16 | 0; + z3 = J3; + G3 = c[b3 + 20 >> 2] | 0; + F3 = b3 + 56 | 0; + e2 = c[b3 + 24 >> 2] | 0; + I3 = b3 + 36 | 0; + H3 = c[I3 >> 2] | 0; + D3 = b3 + 4 | 0; + B3 = c[D3 >> 2] | 0; + B3 = H3 >>> 0 > B3 >>> 0 ? H3 : B3; + c[I3 >> 2] = B3; + H3 = b3 + 16 | 0; + w2 = c[H3 >> 2] | 0; + do + if (w2) { + if (B3) { + E3 = b3 + 40 | 0; + u3 = c[E3 >> 2] | 0; + C3 = e2; + q2 = c[b3 >> 2] | 0; + e2 = C3 + (u3 * 2096 | 0) | 0; + o2 = C3 + (u3 * 2096 | 0) + (q2 << 2) | 0; + t3 = (q2 & 1 | 0) == 0; + if (t3) { + f2 = 0; + n2 = 0; + } else { + k2 = 0; + n2 = 0; + A3 = 27; + } + while (1) { + if ((A3 | 0) == 27) { + A3 = 0; + m3 = c[e2 >> 2] | 0; + f2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) j2 = +g2[19516 + (m3 << 2) >> 2]; + else j2 = +Xb(f2); + e2 = e2 + 4 | 0; + f2 = k2 - f2 * j2; + n2 = n2 + m3 | 0; + } + if (e2 >>> 0 >= o2 >>> 0) break; + m3 = c[e2 >> 2] | 0; + j2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) k2 = +g2[19516 + (m3 << 2) >> 2]; + else k2 = +Xb(j2); + e2 = e2 + 4 | 0; + k2 = f2 - j2 * k2; + n2 = n2 + m3 | 0; + A3 = 27; + } + l2 = +(n2 >>> 0); + if (!n2) k2 = l2; + else { + if (n2 >>> 0 < 256) j2 = +g2[19516 + (n2 << 2) >> 2]; + else j2 = +Xb(l2); + k2 = l2; + f2 = f2 + l2 * j2; + } + r2 = f2 < k2 ? k2 : f2; + p2 = 0; + while (1) { + if ((p2 | 0) == 2) break; + e2 = c[b3 + 44 + (p2 << 2) >> 2] | 0; + dc(y3 + (p2 * 2096 | 0) | 0, C3 + (u3 * 2096 | 0) | 0, 2096) | 0; + m3 = y3 + (p2 * 2096 | 0) + 2080 | 0; + c[m3 >> 2] = (c[m3 >> 2] | 0) + (c[C3 + (e2 * 2096 | 0) + 2080 >> 2] | 0); + m3 = 0; + while (1) { + if ((m3 | 0) == 520) break; + o2 = y3 + (p2 * 2096 | 0) + (m3 << 2) | 0; + c[o2 >> 2] = (c[o2 >> 2] | 0) + (c[C3 + (e2 * 2096 | 0) + (m3 << 2) >> 2] | 0); + m3 = m3 + 1 | 0; + } + e2 = y3 + (p2 * 2096 | 0) | 0; + o2 = y3 + (p2 * 2096 | 0) + (q2 << 2) | 0; + if (t3) { + f2 = 0; + n2 = 0; + } else { + k2 = 0; + n2 = 0; + A3 = 47; + } + while (1) { + if ((A3 | 0) == 47) { + A3 = 0; + m3 = c[e2 >> 2] | 0; + f2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) j2 = +g2[19516 + (m3 << 2) >> 2]; + else j2 = +Xb(f2); + e2 = e2 + 4 | 0; + f2 = k2 - f2 * j2; + n2 = n2 + m3 | 0; + } + if (e2 >>> 0 >= o2 >>> 0) break; + m3 = c[e2 >> 2] | 0; + j2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) k2 = +g2[19516 + (m3 << 2) >> 2]; + else k2 = +Xb(j2); + e2 = e2 + 4 | 0; + k2 = f2 - j2 * k2; + n2 = n2 + m3 | 0; + A3 = 47; + } + l2 = +(n2 >>> 0); + if (!n2) k2 = l2; + else { + if (n2 >>> 0 < 256) j2 = +g2[19516 + (n2 << 2) >> 2]; + else j2 = +Xb(l2); + k2 = l2; + f2 = f2 + l2 * j2; + } + l2 = f2 < k2 ? k2 : f2; + h[x3 + (p2 << 3) >> 3] = l2; + h[z3 + (p2 << 3) >> 3] = l2 - r2 - +h[b3 + 56 + (p2 << 3) >> 3]; + p2 = p2 + 1 | 0; + } + e2 = G3; + f2 = +h[z3 >> 3]; + if (((c[e2 >> 2] | 0) >>> 0 < 256 ? (v3 = +h[b3 + 8 >> 3], f2 > v3) : 0) ? +h[z3 + 8 >> 3] > v3 : 0) { + c[(c[e2 + 12 >> 2] | 0) + (w2 << 2) >> 2] = B3; + a[(c[e2 + 8 >> 2] | 0) + (c[H3 >> 2] | 0) >> 0] = c[e2 >> 2]; + B3 = b3 + 44 | 0; + c[b3 + 48 >> 2] = c[B3 >> 2]; + c[B3 >> 2] = c[e2 >> 2] & 255; + h[b3 + 64 >> 3] = +h[F3 >> 3]; + h[F3 >> 3] = r2; + c[H3 >> 2] = (c[H3 >> 2] | 0) + 1; + c[e2 >> 2] = (c[e2 >> 2] | 0) + 1; + e2 = (c[E3 >> 2] | 0) + 1 | 0; + c[E3 >> 2] = e2; + if (e2 >>> 0 < (c[c[b3 + 28 >> 2] >> 2] | 0) >>> 0) { + ac(C3 + (e2 * 2096 | 0) | 0, 0, 2080) | 0; + c[C3 + (e2 * 2096 | 0) + 2080 >> 2] = 0; + h[C3 + (e2 * 2096 | 0) + 2088 >> 3] = s; + } + c[I3 >> 2] = 0; + c[b3 + 72 >> 2] = 0; + c[b3 + 32 >> 2] = c[D3 >> 2]; + break; + } + if (+h[z3 + 8 >> 3] < f2 + -20) { + c[(c[e2 + 12 >> 2] | 0) + (w2 << 2) >> 2] = B3; + w2 = c[H3 >> 2] | 0; + z3 = c[e2 + 8 >> 2] | 0; + a[z3 + w2 >> 0] = a[z3 + (w2 + -2) >> 0] | 0; + w2 = b3 + 44 | 0; + z3 = c[w2 >> 2] | 0; + A3 = b3 + 48 | 0; + B3 = c[A3 >> 2] | 0; + c[w2 >> 2] = B3; + c[A3 >> 2] = z3; + dc(C3 + (B3 * 2096 | 0) | 0, y3 + 2096 | 0, 2096) | 0; + h[b3 + 64 >> 3] = +h[F3 >> 3]; + h[F3 >> 3] = +h[x3 + 8 >> 3]; + c[H3 >> 2] = (c[H3 >> 2] | 0) + 1; + c[I3 >> 2] = 0; + I3 = c[E3 >> 2] | 0; + ac(C3 + (I3 * 2096 | 0) | 0, 0, 2080) | 0; + c[C3 + (I3 * 2096 | 0) + 2080 >> 2] = 0; + h[C3 + (I3 * 2096 | 0) + 2088 >> 3] = s; + c[b3 + 72 >> 2] = 0; + c[b3 + 32 >> 2] = c[D3 >> 2]; + break; + } + A3 = (c[e2 + 12 >> 2] | 0) + (w2 + -1 << 2) | 0; + c[A3 >> 2] = (c[A3 >> 2] | 0) + B3; + dc(C3 + ((c[b3 + 44 >> 2] | 0) * 2096 | 0) | 0, y3 | 0, 2096) | 0; + f2 = +h[x3 >> 3]; + h[F3 >> 3] = f2; + if ((c[e2 >> 2] | 0) == 1) h[b3 + 64 >> 3] = f2; + c[I3 >> 2] = 0; + F3 = c[E3 >> 2] | 0; + ac(C3 + (F3 * 2096 | 0) | 0, 0, 2080) | 0; + c[C3 + (F3 * 2096 | 0) + 2080 >> 2] = 0; + h[C3 + (F3 * 2096 | 0) + 2088 >> 3] = s; + F3 = b3 + 72 | 0; + I3 = (c[F3 >> 2] | 0) + 1 | 0; + c[F3 >> 2] = I3; + if (I3 >>> 0 > 1) { + I3 = b3 + 32 | 0; + c[I3 >> 2] = (c[I3 >> 2] | 0) + (c[D3 >> 2] | 0); + } + } + } else { + p2 = G3; + c[c[p2 + 12 >> 2] >> 2] = B3; + a[c[p2 + 8 >> 2] >> 0] = 0; + q2 = e2; + E3 = c[b3 >> 2] | 0; + o2 = q2 + (E3 << 2) | 0; + if (!(E3 & 1)) { + f2 = 0; + n2 = 0; + } else { + k2 = 0; + n2 = 0; + A3 = 8; + } + while (1) { + if ((A3 | 0) == 8) { + m3 = c[e2 >> 2] | 0; + f2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) j2 = +g2[19516 + (m3 << 2) >> 2]; + else j2 = +Xb(f2); + e2 = e2 + 4 | 0; + f2 = k2 - f2 * j2; + n2 = n2 + m3 | 0; + } + if (e2 >>> 0 >= o2 >>> 0) break; + m3 = c[e2 >> 2] | 0; + j2 = +(m3 >>> 0); + if (m3 >>> 0 < 256) k2 = +g2[19516 + (m3 << 2) >> 2]; + else k2 = +Xb(j2); + e2 = e2 + 4 | 0; + k2 = f2 - j2 * k2; + n2 = n2 + m3 | 0; + A3 = 8; + } + l2 = +(n2 >>> 0); + if (!n2) k2 = l2; + else { + if (n2 >>> 0 < 256) j2 = +g2[19516 + (n2 << 2) >> 2]; + else j2 = +Xb(l2); + k2 = l2; + f2 = f2 + l2 * j2; + } + v3 = f2 < k2 ? k2 : f2; + h[F3 >> 3] = v3; + h[b3 + 64 >> 3] = v3; + c[H3 >> 2] = (c[H3 >> 2] | 0) + 1; + c[p2 >> 2] = (c[p2 >> 2] | 0) + 1; + F3 = b3 + 40 | 0; + e2 = (c[F3 >> 2] | 0) + 1 | 0; + c[F3 >> 2] = e2; + if (e2 >>> 0 < (c[c[b3 + 28 >> 2] >> 2] | 0) >>> 0) { + ac(q2 + (e2 * 2096 | 0) | 0, 0, 2080) | 0; + c[q2 + (e2 * 2096 | 0) + 2080 >> 2] = 0; + h[q2 + (e2 * 2096 | 0) + 2088 >> 3] = s; + } + c[I3 >> 2] = 0; + } + while (0); + if (!d2) { + i = J3; + return; + } + d2 = G3; + c[c[b3 + 28 >> 2] >> 2] = c[d2 >> 2]; + c[d2 + 4 >> 2] = c[H3 >> 2]; + i = J3; + return; + } + function Ub(b3, d2, e2) { + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + var f2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0, M2 = 0, N3 = 0; + N3 = i; + i = i + 16 | 0; + z3 = N3; + K3 = c[d2 + 28 >> 2] | 0; + I3 = d2 + 4 | 0; + L3 = c[I3 >> 2] | 0; + l2 = c[d2 + 60 >> 2] | 0; + H3 = d2 + 32 | 0; + k2 = c[H3 >> 2] | 0; + M2 = d2 + 44 | 0; + j2 = c[M2 >> 2] | 0; + F3 = d2 + 12 | 0; + f2 = c[F3 >> 2] | 0; + if (j2 >>> 0 < f2 >>> 0) c[M2 >> 2] = f2; + else f2 = j2; + J3 = d2 + 24 | 0; + if (c[J3 >> 2] | 0) { + if (f2) { + C3 = b3 + 8 | 0; + D3 = sa2[c[b3 >> 2] & 1](c[C3 >> 2] | 0, L3 << 3) | 0; + if (!D3) oa2(1); + E3 = sa2[c[b3 >> 2] & 1](c[C3 >> 2] | 0, L3 * 2080 | 0) | 0; + if (!E3) oa2(1); + B3 = sa2[c[b3 >> 2] & 1](c[C3 >> 2] | 0, L3 << 4) | 0; + if (!B3) oa2(1); + c[z3 >> 2] = 0; + c[z3 + 4 >> 2] = 0; + c[z3 + 8 >> 2] = 0; + c[z3 + 12 >> 2] = 0; + A3 = d2 + 48 | 0; + x3 = 0; + while (1) { + if ((x3 | 0) == (L3 | 0)) break; + t3 = (c[A3 >> 2] | 0) + x3 | 0; + w2 = c[d2 >> 2] | 0; + f2 = k2 + (t3 * 1040 | 0) | 0; + r2 = k2 + (t3 * 1040 | 0) + (w2 << 2) | 0; + if (!(w2 & 1)) { + m3 = 0; + q2 = 0; + } else { + o2 = 0; + q2 = 0; + G3 = 42; + } + while (1) { + if ((G3 | 0) == 42) { + G3 = 0; + j2 = c[f2 >> 2] | 0; + m3 = +(j2 >>> 0); + if (j2 >>> 0 < 256) n2 = +g2[19516 + (j2 << 2) >> 2]; + else n2 = +Xb(m3); + f2 = f2 + 4 | 0; + m3 = o2 - m3 * n2; + q2 = q2 + j2 | 0; + } + if (f2 >>> 0 >= r2 >>> 0) break; + j2 = c[f2 >> 2] | 0; + n2 = +(j2 >>> 0); + if (j2 >>> 0 < 256) o2 = +g2[19516 + (j2 << 2) >> 2]; + else o2 = +Xb(n2); + f2 = f2 + 4 | 0; + o2 = m3 - n2 * o2; + q2 = q2 + j2 | 0; + G3 = 42; + } + o2 = +(q2 >>> 0); + if (!q2) p2 = o2; + else { + if (q2 >>> 0 < 256) n2 = +g2[19516 + (q2 << 2) >> 2]; + else n2 = +Xb(o2); + p2 = o2; + m3 = m3 + o2 * n2; + } + w2 = D3 + (x3 << 3) | 0; + h[w2 >> 3] = m3 < p2 ? p2 : m3; + t3 = k2 + (t3 * 1040 | 0) | 0; + v3 = 0; + while (1) { + if ((v3 | 0) == 2) break; + u3 = (_(v3, L3) | 0) + x3 | 0; + f2 = (c[d2 + 52 + (v3 << 2) >> 2] | 0) + x3 | 0; + dc(E3 + (u3 * 1040 | 0) | 0, t3 | 0, 1040) | 0; + j2 = E3 + (u3 * 1040 | 0) + 1024 | 0; + c[j2 >> 2] = (c[j2 >> 2] | 0) + (c[k2 + (f2 * 1040 | 0) + 1024 >> 2] | 0); + j2 = 0; + while (1) { + if ((j2 | 0) == 256) break; + r2 = E3 + (u3 * 1040 | 0) + (j2 << 2) | 0; + c[r2 >> 2] = (c[r2 >> 2] | 0) + (c[k2 + (f2 * 1040 | 0) + (j2 << 2) >> 2] | 0); + j2 = j2 + 1 | 0; + } + q2 = c[d2 >> 2] | 0; + f2 = E3 + (u3 * 1040 | 0) | 0; + r2 = E3 + (u3 * 1040 | 0) + (q2 << 2) | 0; + if (!(q2 & 1)) { + m3 = 0; + q2 = 0; + } else { + o2 = 0; + q2 = 0; + G3 = 62; + } + while (1) { + if ((G3 | 0) == 62) { + G3 = 0; + j2 = c[f2 >> 2] | 0; + m3 = +(j2 >>> 0); + if (j2 >>> 0 < 256) n2 = +g2[19516 + (j2 << 2) >> 2]; + else n2 = +Xb(m3); + f2 = f2 + 4 | 0; + m3 = o2 - m3 * n2; + q2 = q2 + j2 | 0; + } + if (f2 >>> 0 >= r2 >>> 0) break; + j2 = c[f2 >> 2] | 0; + n2 = +(j2 >>> 0); + if (j2 >>> 0 < 256) o2 = +g2[19516 + (j2 << 2) >> 2]; + else o2 = +Xb(n2); + f2 = f2 + 4 | 0; + o2 = m3 - n2 * o2; + q2 = q2 + j2 | 0; + G3 = 62; + } + p2 = +(q2 >>> 0); + if (!q2) o2 = p2; + else { + if (q2 >>> 0 < 256) n2 = +g2[19516 + (q2 << 2) >> 2]; + else n2 = +Xb(p2); + o2 = p2; + m3 = m3 + p2 * n2; + } + p2 = m3 < o2 ? o2 : m3; + h[B3 + (u3 << 3) >> 3] = p2; + r2 = z3 + (v3 << 3) | 0; + h[r2 >> 3] = +h[r2 >> 3] + (p2 - +h[w2 >> 3] - +h[l2 + (u3 << 3) >> 3]); + v3 = v3 + 1 | 0; + } + x3 = x3 + 1 | 0; + } + q2 = K3; + m3 = +h[z3 >> 3]; + if (((c[q2 >> 2] | 0) >>> 0 < (c[d2 + 8 >> 2] | 0) >>> 0 ? (y3 = +h[d2 + 16 >> 3], m3 > y3) : 0) ? +h[z3 + 8 >> 3] > y3 : 0) { + c[(c[q2 + 12 >> 2] | 0) + (c[J3 >> 2] << 2) >> 2] = c[M2 >> 2]; + a[(c[q2 + 8 >> 2] | 0) + (c[J3 >> 2] | 0) >> 0] = c[q2 >> 2]; + f2 = d2 + 52 | 0; + c[d2 + 56 >> 2] = c[f2 >> 2]; + c[f2 >> 2] = _(c[q2 >> 2] | 0, L3) | 0; + f2 = 0; + while (1) { + if ((f2 | 0) == (L3 | 0)) break; + z3 = l2 + (f2 << 3) | 0; + h[l2 + (L3 + f2 << 3) >> 3] = +h[z3 >> 3]; + h[z3 >> 3] = +h[D3 + (f2 << 3) >> 3]; + f2 = f2 + 1 | 0; + } + c[J3 >> 2] = (c[J3 >> 2] | 0) + 1; + c[q2 >> 2] = (c[q2 >> 2] | 0) + 1; + l2 = (c[A3 >> 2] | 0) + L3 | 0; + c[A3 >> 2] = l2; + a: do + if (l2 >>> 0 < (c[c[d2 + 36 >> 2] >> 2] | 0) >>> 0) { + k2 = c[H3 >> 2] | 0; + f2 = c[I3 >> 2] | 0; + j2 = 0; + while (1) { + if ((j2 | 0) == (f2 | 0)) break a; + I3 = l2 + j2 | 0; + ac(k2 + (I3 * 1040 | 0) | 0, 0, 1024) | 0; + c[k2 + (I3 * 1040 | 0) + 1024 >> 2] = 0; + h[k2 + (I3 * 1040 | 0) + 1032 >> 3] = s; + j2 = j2 + 1 | 0; + } + } + while (0); + c[M2 >> 2] = 0; + c[d2 + 64 >> 2] = 0; + c[d2 + 40 >> 2] = c[F3 >> 2]; + } else G3 = 84; + do + if ((G3 | 0) == 84) { + f2 = c[M2 >> 2] | 0; + j2 = c[J3 >> 2] | 0; + if (+h[z3 + 8 >> 3] < m3 + -20) { + c[(c[q2 + 12 >> 2] | 0) + (j2 << 2) >> 2] = f2; + f2 = c[J3 >> 2] | 0; + I3 = c[q2 + 8 >> 2] | 0; + a[I3 + f2 >> 0] = a[I3 + (f2 + -2) >> 0] | 0; + f2 = d2 + 52 | 0; + I3 = c[f2 >> 2] | 0; + j2 = d2 + 56 | 0; + c[f2 >> 2] = c[j2 >> 2]; + c[j2 >> 2] = I3; + j2 = 0; + while (1) { + if ((j2 | 0) == (L3 | 0)) break; + H3 = L3 + j2 | 0; + dc(k2 + (((c[f2 >> 2] | 0) + j2 | 0) * 1040 | 0) | 0, E3 + (H3 * 1040 | 0) | 0, 1040) | 0; + I3 = l2 + (j2 << 3) | 0; + h[l2 + (H3 << 3) >> 3] = +h[I3 >> 3]; + h[I3 >> 3] = +h[B3 + (H3 << 3) >> 3]; + I3 = (c[A3 >> 2] | 0) + j2 | 0; + ac(k2 + (I3 * 1040 | 0) | 0, 0, 1024) | 0; + c[k2 + (I3 * 1040 | 0) + 1024 >> 2] = 0; + h[k2 + (I3 * 1040 | 0) + 1032 >> 3] = s; + j2 = j2 + 1 | 0; + } + c[J3 >> 2] = (c[J3 >> 2] | 0) + 1; + c[M2 >> 2] = 0; + c[d2 + 64 >> 2] = 0; + c[d2 + 40 >> 2] = c[F3 >> 2]; + break; + } + j2 = (c[q2 + 12 >> 2] | 0) + (j2 + -1 << 2) | 0; + c[j2 >> 2] = (c[j2 >> 2] | 0) + f2; + f2 = d2 + 52 | 0; + j2 = 0; + while (1) { + if ((j2 | 0) == (L3 | 0)) break; + dc(k2 + (((c[f2 >> 2] | 0) + j2 | 0) * 1040 | 0) | 0, E3 + (j2 * 1040 | 0) | 0, 1040) | 0; + m3 = +h[B3 + (j2 << 3) >> 3]; + h[l2 + (j2 << 3) >> 3] = m3; + if ((c[q2 >> 2] | 0) == 1) h[l2 + (L3 + j2 << 3) >> 3] = m3; + I3 = (c[A3 >> 2] | 0) + j2 | 0; + ac(k2 + (I3 * 1040 | 0) | 0, 0, 1024) | 0; + c[k2 + (I3 * 1040 | 0) + 1024 >> 2] = 0; + h[k2 + (I3 * 1040 | 0) + 1032 >> 3] = s; + j2 = j2 + 1 | 0; + } + c[M2 >> 2] = 0; + I3 = d2 + 64 | 0; + M2 = (c[I3 >> 2] | 0) + 1 | 0; + c[I3 >> 2] = M2; + if (M2 >>> 0 > 1) { + M2 = d2 + 40 | 0; + c[M2 >> 2] = (c[M2 >> 2] | 0) + (c[F3 >> 2] | 0); + } + } + while (0); + M2 = b3 + 4 | 0; + ra2[c[M2 >> 2] & 1](c[C3 >> 2] | 0, B3); + ra2[c[M2 >> 2] & 1](c[C3 >> 2] | 0, E3); + ra2[c[M2 >> 2] & 1](c[C3 >> 2] | 0, D3); + } + } else { + u3 = K3; + c[c[u3 + 12 >> 2] >> 2] = f2; + a[c[u3 + 8 >> 2] >> 0] = 0; + t3 = k2; + r2 = 0; + while (1) { + if ((r2 | 0) == (L3 | 0)) break; + b3 = c[d2 >> 2] | 0; + f2 = t3 + (r2 * 1040 | 0) | 0; + q2 = t3 + (r2 * 1040 | 0) + (b3 << 2) | 0; + if (!(b3 & 1)) { + m3 = 0; + k2 = 0; + } else { + o2 = 0; + k2 = 0; + G3 = 12; + } + while (1) { + if ((G3 | 0) == 12) { + G3 = 0; + j2 = c[f2 >> 2] | 0; + m3 = +(j2 >>> 0); + if (j2 >>> 0 < 256) n2 = +g2[19516 + (j2 << 2) >> 2]; + else n2 = +Xb(m3); + f2 = f2 + 4 | 0; + m3 = o2 - m3 * n2; + k2 = k2 + j2 | 0; + } + if (f2 >>> 0 >= q2 >>> 0) break; + j2 = c[f2 >> 2] | 0; + n2 = +(j2 >>> 0); + if (j2 >>> 0 < 256) o2 = +g2[19516 + (j2 << 2) >> 2]; + else o2 = +Xb(n2); + f2 = f2 + 4 | 0; + o2 = m3 - n2 * o2; + k2 = k2 + j2 | 0; + G3 = 12; + } + p2 = +(k2 >>> 0); + if (!k2) o2 = p2; + else { + if (k2 >>> 0 < 256) n2 = +g2[19516 + (k2 << 2) >> 2]; + else n2 = +Xb(p2); + o2 = p2; + m3 = m3 + p2 * n2; + } + y3 = m3 < o2 ? o2 : m3; + h[l2 + (r2 << 3) >> 3] = y3; + h[l2 + (L3 + r2 << 3) >> 3] = y3; + r2 = r2 + 1 | 0; + } + c[J3 >> 2] = (c[J3 >> 2] | 0) + 1; + c[u3 >> 2] = (c[u3 >> 2] | 0) + 1; + G3 = d2 + 48 | 0; + l2 = (c[G3 >> 2] | 0) + L3 | 0; + c[G3 >> 2] = l2; + b: do + if (l2 >>> 0 < (c[c[d2 + 36 >> 2] >> 2] | 0) >>> 0) { + k2 = c[H3 >> 2] | 0; + f2 = c[I3 >> 2] | 0; + j2 = 0; + while (1) { + if ((j2 | 0) == (f2 | 0)) break b; + I3 = l2 + j2 | 0; + ac(k2 + (I3 * 1040 | 0) | 0, 0, 1024) | 0; + c[k2 + (I3 * 1040 | 0) + 1024 >> 2] = 0; + h[k2 + (I3 * 1040 | 0) + 1032 >> 3] = s; + j2 = j2 + 1 | 0; + } + } + while (0); + c[M2 >> 2] = 0; + } + if (!e2) { + i = N3; + return; + } + e2 = K3; + M2 = _(c[e2 >> 2] | 0, L3) | 0; + c[c[d2 + 36 >> 2] >> 2] = M2; + c[e2 + 4 >> 2] = c[J3 >> 2]; + i = N3; + return; + } + function Vb(f2, g3, h2, i2) { + f2 = f2 | 0; + g3 = g3 | 0; + h2 = h2 | 0; + i2 = i2 | 0; + var j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0; + v3 = f2; + k2 = b2[88430 + ((_(d[f2 >> 0] | d[f2 + 1 >> 0] << 8 | d[f2 + 2 >> 0] << 16 | d[f2 + 3 >> 0] << 24, 506832829) | 0) >>> 17 << 1) >> 1] | 0; + D3 = f2 + 1 | 0; + B3 = D3; + l2 = k2 << 16 >> 16 == 0 & 1; + j2 = 0; + k2 = k2 & 65535; + a: while (1) { + if (l2 << 24 >> 24) break; + w2 = k2 + 1 | 0; + m3 = 153966 + (k2 << 2) | 0; + m3 = e[m3 >> 1] | e[m3 + 2 >> 1] << 16; + k2 = m3 >>> 8 & 255; + s2 = m3 >>> 16; + t3 = m3 & 127; + u3 = d[280786 + t3 >> 0] | 0; + r2 = 1 << u3; + l2 = (m3 & 255) >>> 7; + if (k2 << 24 >> 24) { + r2 = k2 << 24 >> 24 != 10; + if (t3 >>> 0 > h2 >>> 0) { + A3 = j2; + k2 = w2; + j2 = A3; + continue; + } + q2 = (c[11272 + (t3 << 2) >> 2] | 0) + (_(t3, m3 >>> 16) | 0) | 0; + k2 = 280811 + q2 | 0; + b: do + switch ((m3 >>> 8 & 255) << 24 >> 24) { + case 0: { + p2 = f2 + t3 | 0; + m3 = f2 + (t3 + -4) | 0; + o2 = 0; + k2 = v3; + while (1) { + n2 = k2; + if (n2 >>> 0 > m3 >>> 0) break; + z3 = k2; + A3 = 280811 + (q2 + o2) | 0; + if ((d[z3 >> 0] | d[z3 + 1 >> 0] << 8 | d[z3 + 2 >> 0] << 16 | d[z3 + 3 >> 0] << 24 | 0) != (d[A3 >> 0] | d[A3 + 1 >> 0] << 8 | d[A3 + 2 >> 0] << 16 | d[A3 + 3 >> 0] << 24 | 0)) break; + o2 = o2 + 4 | 0; + k2 = n2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= p2 >>> 0) break; + if ((a[280811 + (q2 + o2) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + o2 = o2 + 1 | 0; + k2 = k2 + 1 | 0; + } + if ((o2 | 0) != (t3 | 0)) { + A3 = j2; + k2 = w2; + j2 = A3; + continue a; + } + break; + } + case 10: { + k2 = a[k2 >> 0] | 0; + if (!((k2 & 255) > 96 & (k2 & 255) < 123)) { + A3 = j2; + k2 = w2; + j2 = A3; + continue a; + } + if ((k2 & 255 ^ 32 | 0) != (d[f2 >> 0] | 0)) { + A3 = j2; + k2 = w2; + j2 = A3; + continue a; + } + p2 = q2 + 1 | 0; + q2 = f2 + t3 | 0; + m3 = f2 + (t3 + -4) | 0; + o2 = 0; + k2 = B3; + while (1) { + n2 = k2; + if (n2 >>> 0 > m3 >>> 0) break; + z3 = k2; + A3 = 280811 + (p2 + o2) | 0; + if ((d[z3 >> 0] | d[z3 + 1 >> 0] << 8 | d[z3 + 2 >> 0] << 16 | d[z3 + 3 >> 0] << 24 | 0) != (d[A3 >> 0] | d[A3 + 1 >> 0] << 8 | d[A3 + 2 >> 0] << 16 | d[A3 + 3 >> 0] << 24 | 0)) break; + o2 = o2 + 4 | 0; + k2 = n2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= q2 >>> 0) break; + if ((a[280811 + (p2 + o2) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + o2 = o2 + 1 | 0; + k2 = k2 + 1 | 0; + } + if ((o2 | 0) != (t3 + -1 | 0)) { + A3 = j2; + k2 = w2; + j2 = A3; + continue a; + } + break; + } + default: { + m3 = 0; + while (1) { + if (m3 >>> 0 >= t3 >>> 0) break b; + k2 = a[280811 + (q2 + m3) >> 0] | 0; + if ((k2 & 255) > 96 & (k2 & 255) < 123) { + if ((k2 & 255 ^ 32 | 0) != (d[f2 + m3 >> 0] | 0)) { + A3 = j2; + k2 = w2; + j2 = A3; + continue a; + } + } else if (k2 << 24 >> 24 != (a[f2 + m3 >> 0] | 0)) { + A3 = j2; + k2 = w2; + j2 = A3; + continue a; + } + m3 = m3 + 1 | 0; + } + } + } + while (0); + A3 = (s2 + ((r2 ? 44 : 9) << u3) << 5) + t3 | 0; + j2 = i2 + (t3 << 2) | 0; + z3 = c[j2 >> 2] | 0; + c[j2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + j2 = t3 + 1 | 0; + if (j2 >>> 0 >= h2 >>> 0) { + j2 = 1; + k2 = w2; + continue; + } + switch (a[f2 + t3 >> 0] | 0) { + case 32: { + k2 = (s2 + (((r2 & 1) << 6 | 4) << u3) << 5) + t3 | 0; + j2 = i2 + (j2 << 2) | 0; + A3 = c[j2 >> 2] | 0; + c[j2 >> 2] = A3 >>> 0 < k2 >>> 0 ? A3 : k2; + j2 = 1; + k2 = w2; + continue a; + } + case 34: { + z3 = (s2 + ((r2 ? 87 : 66) << u3) << 5) + t3 | 0; + A3 = i2 + (j2 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + if ((a[f2 + (t3 + 1) >> 0] | 0) != 62) { + j2 = 1; + k2 = w2; + continue a; + } + k2 = (s2 + ((r2 ? 97 : 69) << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 2 << 2) | 0; + A3 = c[j2 >> 2] | 0; + c[j2 >> 2] = A3 >>> 0 < k2 >>> 0 ? A3 : k2; + j2 = 1; + k2 = w2; + continue a; + } + case 46: { + z3 = (s2 + ((r2 ? 101 : 79) << u3) << 5) + t3 | 0; + A3 = i2 + (j2 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + if ((a[f2 + (t3 + 1) >> 0] | 0) != 32) { + j2 = 1; + k2 = w2; + continue a; + } + k2 = (s2 + ((r2 ? 114 : 88) << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 2 << 2) | 0; + A3 = c[j2 >> 2] | 0; + c[j2 >> 2] = A3 >>> 0 < k2 >>> 0 ? A3 : k2; + j2 = 1; + k2 = w2; + continue a; + } + case 44: { + z3 = (s2 + ((r2 ? 112 : 99) << u3) << 5) + t3 | 0; + A3 = i2 + (j2 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + if ((a[f2 + (t3 + 1) >> 0] | 0) != 32) { + j2 = 1; + k2 = w2; + continue a; + } + k2 = (s2 + ((r2 ? 107 : 58) << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 2 << 2) | 0; + A3 = c[j2 >> 2] | 0; + c[j2 >> 2] = A3 >>> 0 < k2 >>> 0 ? A3 : k2; + j2 = 1; + k2 = w2; + continue a; + } + case 39: { + k2 = (s2 + ((r2 ? 94 : 74) << u3) << 5) + t3 | 0; + j2 = i2 + (j2 << 2) | 0; + A3 = c[j2 >> 2] | 0; + c[j2 >> 2] = A3 >>> 0 < k2 >>> 0 ? A3 : k2; + j2 = 1; + k2 = w2; + continue a; + } + case 40: { + k2 = (s2 + ((r2 ? 113 : 78) << u3) << 5) + t3 | 0; + j2 = i2 + (j2 << 2) | 0; + A3 = c[j2 >> 2] | 0; + c[j2 >> 2] = A3 >>> 0 < k2 >>> 0 ? A3 : k2; + j2 = 1; + k2 = w2; + continue a; + } + case 61: + switch (a[f2 + (t3 + 1) >> 0] | 0) { + case 34: { + k2 = (s2 + ((r2 & 1 | 104) << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 2 << 2) | 0; + A3 = c[j2 >> 2] | 0; + c[j2 >> 2] = A3 >>> 0 < k2 >>> 0 ? A3 : k2; + j2 = 1; + k2 = w2; + continue a; + } + case 39: { + k2 = (s2 + (((r2 & 1) << 3) + 108 << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 2 << 2) | 0; + A3 = c[j2 >> 2] | 0; + c[j2 >> 2] = A3 >>> 0 < k2 >>> 0 ? A3 : k2; + j2 = 1; + k2 = w2; + continue a; + } + default: { + j2 = 1; + k2 = w2; + continue a; + } + } + default: { + j2 = 1; + k2 = w2; + continue a; + } + } + } + p2 = (c[11272 + (t3 << 2) >> 2] | 0) + (_(t3, s2) | 0) | 0; + m3 = t3 >>> 0 < h2 >>> 0 ? t3 : h2; + q2 = f2 + m3 | 0; + m3 = f2 + (m3 + -4) | 0; + o2 = 0; + k2 = v3; + while (1) { + n2 = k2; + if (n2 >>> 0 > m3 >>> 0) break; + z3 = k2; + A3 = 280811 + (p2 + o2) | 0; + if ((d[z3 >> 0] | d[z3 + 1 >> 0] << 8 | d[z3 + 2 >> 0] << 16 | d[z3 + 3 >> 0] << 24 | 0) != (d[A3 >> 0] | d[A3 + 1 >> 0] << 8 | d[A3 + 2 >> 0] << 16 | d[A3 + 3 >> 0] << 24 | 0)) break; + o2 = o2 + 4 | 0; + k2 = n2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= q2 >>> 0) break; + if ((a[280811 + (p2 + o2) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + o2 = o2 + 1 | 0; + k2 = k2 + 1 | 0; + } + if ((o2 | 0) == (t3 | 0)) { + A3 = (s2 << 5) + t3 | 0; + j2 = i2 + (t3 << 2) | 0; + z3 = c[j2 >> 2] | 0; + c[j2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + j2 = 1; + } + k2 = t3 + -1 | 0; + if (o2 >>> 0 >= k2 >>> 0) { + z3 = (s2 + (12 << u3) << 5) + t3 | 0; + A3 = i2 + (k2 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + A3 = t3 + 2 | 0; + if ((((A3 >>> 0 < h2 >>> 0 ? (a[f2 + k2 >> 0] | 0) == 105 : 0) ? (a[f2 + t3 >> 0] | 0) == 110 : 0) ? (a[f2 + (t3 + 1) >> 0] | 0) == 103 : 0) ? (a[f2 + A3 >> 0] | 0) == 32 : 0) { + A3 = (s2 + (49 << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 3 << 2) | 0; + z3 = c[j2 >> 2] | 0; + c[j2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + j2 = 1; + } else j2 = 1; + } + if (t3 >>> 0 > 9) { + k2 = t3 + -9 | 0; + k2 = k2 >>> 0 < g3 >>> 0 ? g3 : k2; + } else k2 = g3; + m3 = t3 + -2 | 0; + m3 = o2 >>> 0 < m3 >>> 0 ? o2 : m3; + while (1) { + if (k2 >>> 0 > m3 >>> 0) break; + A3 = (s2 + (d[407930 + (t3 - k2) >> 0] << u3) << 5) + t3 | 0; + j2 = i2 + (k2 << 2) | 0; + z3 = c[j2 >> 2] | 0; + c[j2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + j2 = 1; + k2 = k2 + 1 | 0; + } + if (o2 >>> 0 < t3 >>> 0) { + k2 = w2; + continue; + } + k2 = t3 + 6 | 0; + if (k2 >>> 0 >= h2 >>> 0) { + k2 = w2; + continue; + } + do + switch (a[f2 + t3 >> 0] | 0) { + case 32: { + z3 = (s2 + r2 << 5) + t3 | 0; + A3 = i2 + (t3 + 1 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + switch (a[f2 + (t3 + 1) >> 0] | 0) { + case 97: + switch (a[f2 + (t3 + 2) >> 0] | 0) { + case 32: { + A3 = (s2 + (28 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 3 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 115: { + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (46 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 116: { + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (60 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 110: { + if ((a[f2 + (t3 + 3) >> 0] | 0) != 100) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 4) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (10 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 5 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + case 98: { + if ((a[f2 + (t3 + 2) >> 0] | 0) != 121) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (38 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 105: + switch (a[f2 + (t3 + 2) >> 0] | 0) { + case 110: { + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (r2 << 4) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 115: { + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (47 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + case 102: { + switch (a[f2 + (t3 + 2) >> 0] | 0) { + case 111: { + if ((a[f2 + (t3 + 3) >> 0] | 0) != 114) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 4) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (25 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 5 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 114: + break; + default: { + k2 = w2; + continue a; + } + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 111) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 4) >> 0] | 0) != 109) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 5) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (37 << u3) << 5) + t3 | 0; + k2 = i2 + (k2 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 111: + switch (a[f2 + (t3 + 2) >> 0] | 0) { + case 102: { + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (r2 << 3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 110: { + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (45 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + case 110: { + if ((a[f2 + (t3 + 2) >> 0] | 0) != 111) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 116) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 4) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (80 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 5 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 116: { + switch (a[f2 + (t3 + 2) >> 0] | 0) { + case 104: + break; + case 111: { + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (17 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + switch (a[f2 + (t3 + 3) >> 0] | 0) { + case 101: { + if ((a[f2 + (t3 + 4) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (5 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 5 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 97: + break; + default: { + k2 = w2; + continue a; + } + } + if ((a[f2 + (t3 + 4) >> 0] | 0) != 116) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 5) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (29 << u3) << 5) + t3 | 0; + k2 = i2 + (k2 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 119: { + if ((a[f2 + (t3 + 2) >> 0] | 0) != 105) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 116) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 4) >> 0] | 0) != 104) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 5) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (35 << u3) << 5) + t3 | 0; + k2 = i2 + (k2 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + } + case 34: { + z3 = (s2 + (19 << u3) << 5) + t3 | 0; + A3 = i2 + (t3 + 1 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + if ((a[f2 + (t3 + 1) >> 0] | 0) != 62) { + k2 = w2; + continue a; + } + A3 = (s2 + (21 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 2 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 46: { + z3 = (s2 + (20 << u3) << 5) + t3 | 0; + A3 = i2 + (t3 + 1 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + if ((a[f2 + (t3 + 1) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + z3 = (s2 + (31 << u3) << 5) + t3 | 0; + A3 = i2 + (t3 + 2 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + if ((a[f2 + (t3 + 2) >> 0] | 0) != 84) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 104) { + k2 = w2; + continue a; + } + switch (a[f2 + (t3 + 4) >> 0] | 0) { + case 101: { + if ((a[f2 + (t3 + 5) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (43 << u3) << 5) + t3 | 0; + k2 = i2 + (k2 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 105: + break; + default: { + k2 = w2; + continue a; + } + } + if ((a[f2 + (t3 + 5) >> 0] | 0) != 115) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 6) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (75 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 7 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 44: { + z3 = (s2 + (76 << u3) << 5) + t3 | 0; + A3 = i2 + (t3 + 1 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + if ((a[f2 + (t3 + 1) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (14 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 2 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 10: { + z3 = (s2 + (22 << u3) << 5) + t3 | 0; + A3 = i2 + (t3 + 1 << 2) | 0; + y3 = c[A3 >> 2] | 0; + c[A3 >> 2] = y3 >>> 0 < z3 >>> 0 ? y3 : z3; + if ((a[f2 + (t3 + 1) >> 0] | 0) != 9) { + k2 = w2; + continue a; + } + A3 = (s2 + (50 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 2 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 93: { + A3 = (s2 + (24 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 1 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 39: { + A3 = (s2 + (36 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 1 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 58: { + A3 = (s2 + (51 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 1 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 40: { + A3 = (s2 + (57 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 1 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 61: + switch (a[f2 + (t3 + 1) >> 0] | 0) { + case 34: { + A3 = (s2 + (70 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 2 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 39: { + A3 = (s2 + (86 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 2 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + case 97: { + if ((a[f2 + (t3 + 1) >> 0] | 0) != 108) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 2) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (84 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 3 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 101: + switch (a[f2 + (t3 + 1) >> 0] | 0) { + case 100: { + if ((a[f2 + (t3 + 2) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (53 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 3 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 114: { + if ((a[f2 + (t3 + 2) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (82 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 3 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 115: { + if ((a[f2 + (t3 + 2) >> 0] | 0) != 116) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (95 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + case 102: { + if ((a[f2 + (t3 + 1) >> 0] | 0) != 117) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 2) >> 0] | 0) != 108) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (90 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 105: + switch (a[f2 + (t3 + 1) >> 0] | 0) { + case 118: { + if ((a[f2 + (t3 + 2) >> 0] | 0) != 101) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (92 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 122: { + if ((a[f2 + (t3 + 2) >> 0] | 0) != 101) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (100 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + case 108: { + switch (a[f2 + (t3 + 1) >> 0] | 0) { + case 101: + break; + case 121: { + if ((a[f2 + (t3 + 2) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (61 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 3 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + if ((a[f2 + (t3 + 2) >> 0] | 0) != 115) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 115) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 4) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (93 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 5 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + case 111: { + if ((a[f2 + (t3 + 1) >> 0] | 0) != 117) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 2) >> 0] | 0) != 115) { + k2 = w2; + continue a; + } + if ((a[f2 + (t3 + 3) >> 0] | 0) != 32) { + k2 = w2; + continue a; + } + A3 = (s2 + (106 << u3) << 5) + t3 | 0; + k2 = i2 + (t3 + 4 << 2) | 0; + z3 = c[k2 >> 2] | 0; + c[k2 >> 2] = z3 >>> 0 < A3 >>> 0 ? z3 : A3; + k2 = w2; + continue a; + } + default: { + k2 = w2; + continue a; + } + } + while (0); + } + if (h2 >>> 0 <= 4) { + h2 = j2; + h2 = h2 & 1; + h2 = h2 << 24 >> 24 != 0; + return h2 | 0; + } + A3 = a[f2 >> 0] | 0; + w2 = A3 << 24 >> 24 == 32; + c: do + switch (A3 << 24 >> 24) { + case 32: + case 46: { + k2 = b2[88430 + ((_(d[D3 >> 0] | d[D3 + 1 >> 0] << 8 | d[D3 + 2 >> 0] << 16 | d[D3 + 3 >> 0] << 24, 506832829) | 0) >>> 17 << 1) >> 1] | 0; + g3 = h2 + -1 | 0; + x3 = w2 ? 6 : 32; + y3 = w2 ? 2 : 77; + z3 = w2 ? 89 : 67; + A3 = f2 + 2 | 0; + l2 = k2 << 16 >> 16 == 0 & 1; + k2 = k2 & 65535; + d: while (1) { + if (l2 << 24 >> 24) break c; + v3 = k2 + 1 | 0; + m3 = 153966 + (k2 << 2) | 0; + m3 = e[m3 >> 1] | e[m3 + 2 >> 1] << 16; + k2 = m3 >>> 8 & 255; + s2 = m3 >>> 16; + t3 = m3 & 127; + u3 = d[280786 + t3 >> 0] | 0; + l2 = (m3 & 255) >>> 7; + if (!(k2 << 24 >> 24)) { + if (t3 >>> 0 > g3 >>> 0) { + u3 = j2; + k2 = v3; + j2 = u3; + continue; + } + p2 = (c[11272 + (t3 << 2) >> 2] | 0) + (_(t3, m3 >>> 16) | 0) | 0; + q2 = f2 + (t3 + 1) | 0; + m3 = f2 + (t3 + -3) | 0; + o2 = 0; + k2 = B3; + while (1) { + n2 = k2; + if (n2 >>> 0 > m3 >>> 0) break; + E3 = k2; + r2 = 280811 + (p2 + o2) | 0; + if ((d[E3 >> 0] | d[E3 + 1 >> 0] << 8 | d[E3 + 2 >> 0] << 16 | d[E3 + 3 >> 0] << 24 | 0) != (d[r2 >> 0] | d[r2 + 1 >> 0] << 8 | d[r2 + 2 >> 0] << 16 | d[r2 + 3 >> 0] << 24 | 0)) break; + o2 = o2 + 4 | 0; + k2 = n2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= q2 >>> 0) break; + if ((a[280811 + (p2 + o2) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + o2 = o2 + 1 | 0; + k2 = k2 + 1 | 0; + } + if ((o2 | 0) != (t3 | 0)) { + E3 = j2; + k2 = v3; + j2 = E3; + continue; + } + j2 = t3 + 1 | 0; + E3 = (s2 + (x3 << u3) << 5) + t3 | 0; + k2 = i2 + (j2 << 2) | 0; + r2 = c[k2 >> 2] | 0; + c[k2 >> 2] = r2 >>> 0 < E3 >>> 0 ? r2 : E3; + k2 = t3 + 2 | 0; + if (k2 >>> 0 >= h2 >>> 0) { + j2 = 1; + k2 = v3; + continue; + } + j2 = a[f2 + j2 >> 0] | 0; + switch (j2 << 24 >> 24) { + case 32: { + E3 = (s2 + (y3 << u3) << 5) + t3 | 0; + j2 = i2 + (k2 << 2) | 0; + k2 = c[j2 >> 2] | 0; + c[j2 >> 2] = k2 >>> 0 < E3 >>> 0 ? k2 : E3; + j2 = 1; + k2 = v3; + continue d; + } + case 40: { + E3 = (s2 + (z3 << u3) << 5) + t3 | 0; + j2 = i2 + (k2 << 2) | 0; + k2 = c[j2 >> 2] | 0; + c[j2 >> 2] = k2 >>> 0 < E3 >>> 0 ? k2 : E3; + j2 = 1; + k2 = v3; + continue d; + } + default: { + if (!w2) { + j2 = 1; + k2 = v3; + continue d; + } + switch (j2 << 24 >> 24) { + case 44: { + r2 = (s2 + (103 << u3) << 5) + t3 | 0; + E3 = i2 + (k2 << 2) | 0; + q2 = c[E3 >> 2] | 0; + c[E3 >> 2] = q2 >>> 0 < r2 >>> 0 ? q2 : r2; + if ((a[f2 + (t3 + 2) >> 0] | 0) != 32) { + j2 = 1; + k2 = v3; + continue d; + } + k2 = (s2 + (33 << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 3 << 2) | 0; + E3 = c[j2 >> 2] | 0; + c[j2 >> 2] = E3 >>> 0 < k2 >>> 0 ? E3 : k2; + j2 = 1; + k2 = v3; + continue d; + } + case 46: { + r2 = (s2 + (71 << u3) << 5) + t3 | 0; + E3 = i2 + (k2 << 2) | 0; + q2 = c[E3 >> 2] | 0; + c[E3 >> 2] = q2 >>> 0 < r2 >>> 0 ? q2 : r2; + if ((a[f2 + (t3 + 2) >> 0] | 0) != 32) { + j2 = 1; + k2 = v3; + continue d; + } + k2 = (s2 + (52 << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 3 << 2) | 0; + E3 = c[j2 >> 2] | 0; + c[j2 >> 2] = E3 >>> 0 < k2 >>> 0 ? E3 : k2; + j2 = 1; + k2 = v3; + continue d; + } + case 61: + switch (a[f2 + (t3 + 2) >> 0] | 0) { + case 34: { + k2 = (s2 + (81 << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 3 << 2) | 0; + E3 = c[j2 >> 2] | 0; + c[j2 >> 2] = E3 >>> 0 < k2 >>> 0 ? E3 : k2; + j2 = 1; + k2 = v3; + continue d; + } + case 39: { + k2 = (s2 + (98 << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 3 << 2) | 0; + E3 = c[j2 >> 2] | 0; + c[j2 >> 2] = E3 >>> 0 < k2 >>> 0 ? E3 : k2; + j2 = 1; + k2 = v3; + continue d; + } + default: { + j2 = 1; + k2 = v3; + continue d; + } + } + default: { + j2 = 1; + k2 = v3; + continue d; + } + } + } + } + } + if (!w2) { + E3 = j2; + k2 = v3; + j2 = E3; + continue; + } + r2 = k2 << 24 >> 24 != 10; + if (t3 >>> 0 > g3 >>> 0) { + E3 = j2; + k2 = v3; + j2 = E3; + continue; + } + q2 = (c[11272 + (t3 << 2) >> 2] | 0) + (_(t3, m3 >>> 16) | 0) | 0; + k2 = 280811 + q2 | 0; + e: do + switch ((m3 >>> 8 & 255) << 24 >> 24) { + case 0: { + p2 = f2 + (t3 + 1) | 0; + m3 = f2 + (t3 + -3) | 0; + o2 = 0; + k2 = B3; + while (1) { + n2 = k2; + if (n2 >>> 0 > m3 >>> 0) break; + F3 = k2; + E3 = 280811 + (q2 + o2) | 0; + if ((d[F3 >> 0] | d[F3 + 1 >> 0] << 8 | d[F3 + 2 >> 0] << 16 | d[F3 + 3 >> 0] << 24 | 0) != (d[E3 >> 0] | d[E3 + 1 >> 0] << 8 | d[E3 + 2 >> 0] << 16 | d[E3 + 3 >> 0] << 24 | 0)) break; + o2 = o2 + 4 | 0; + k2 = n2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= p2 >>> 0) break; + if ((a[280811 + (q2 + o2) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + o2 = o2 + 1 | 0; + k2 = k2 + 1 | 0; + } + if ((o2 | 0) != (t3 | 0)) { + F3 = j2; + k2 = v3; + j2 = F3; + continue d; + } + break; + } + case 10: { + k2 = a[k2 >> 0] | 0; + if (!((k2 & 255) > 96 & (k2 & 255) < 123)) { + F3 = j2; + k2 = v3; + j2 = F3; + continue d; + } + if ((k2 & 255 ^ 32 | 0) != (d[D3 >> 0] | 0)) { + F3 = j2; + k2 = v3; + j2 = F3; + continue d; + } + o2 = q2 + 1 | 0; + p2 = f2 + (t3 + 1) | 0; + m3 = f2 + (t3 + -3) | 0; + n2 = 0; + k2 = A3; + while (1) { + if (k2 >>> 0 > m3 >>> 0) break; + F3 = 280811 + (o2 + n2) | 0; + if ((d[k2 >> 0] | d[k2 + 1 >> 0] << 8 | d[k2 + 2 >> 0] << 16 | d[k2 + 3 >> 0] << 24 | 0) != (d[F3 >> 0] | d[F3 + 1 >> 0] << 8 | d[F3 + 2 >> 0] << 16 | d[F3 + 3 >> 0] << 24 | 0)) break; + n2 = n2 + 4 | 0; + k2 = k2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= p2 >>> 0) break; + if ((a[280811 + (o2 + n2) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + n2 = n2 + 1 | 0; + k2 = k2 + 1 | 0; + } + if ((n2 | 0) != (t3 + -1 | 0)) { + F3 = j2; + k2 = v3; + j2 = F3; + continue d; + } + break; + } + default: { + m3 = 0; + while (1) { + if (m3 >>> 0 >= t3 >>> 0) break e; + k2 = a[280811 + (q2 + m3) >> 0] | 0; + if ((k2 & 255) > 96 & (k2 & 255) < 123) { + if ((k2 & 255 ^ 32 | 0) != (d[f2 + (m3 + 1) >> 0] | 0)) { + F3 = j2; + k2 = v3; + j2 = F3; + continue d; + } + } else if (k2 << 24 >> 24 != (a[f2 + (m3 + 1) >> 0] | 0)) { + F3 = j2; + k2 = v3; + j2 = F3; + continue d; + } + m3 = m3 + 1 | 0; + } + } + } + while (0); + j2 = t3 + 1 | 0; + F3 = (s2 + ((r2 ? 85 : 30) << u3) << 5) + t3 | 0; + k2 = i2 + (j2 << 2) | 0; + E3 = c[k2 >> 2] | 0; + c[k2 >> 2] = E3 >>> 0 < F3 >>> 0 ? E3 : F3; + k2 = t3 + 2 | 0; + if (k2 >>> 0 >= h2 >>> 0) { + j2 = 1; + k2 = v3; + continue; + } + switch (a[f2 + j2 >> 0] | 0) { + case 32: { + F3 = (s2 + ((r2 ? 83 : 15) << u3) << 5) + t3 | 0; + j2 = i2 + (k2 << 2) | 0; + k2 = c[j2 >> 2] | 0; + c[j2 >> 2] = k2 >>> 0 < F3 >>> 0 ? k2 : F3; + j2 = 1; + k2 = v3; + continue d; + } + case 44: { + if (!r2) { + E3 = (s2 + (109 << u3) << 5) + t3 | 0; + F3 = i2 + (k2 << 2) | 0; + q2 = c[F3 >> 2] | 0; + c[F3 >> 2] = q2 >>> 0 < E3 >>> 0 ? q2 : E3; + } + if ((a[f2 + (t3 + 2) >> 0] | 0) != 32) { + j2 = 1; + k2 = v3; + continue d; + } + k2 = (s2 + ((r2 ? 111 : 65) << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 3 << 2) | 0; + F3 = c[j2 >> 2] | 0; + c[j2 >> 2] = F3 >>> 0 < k2 >>> 0 ? F3 : k2; + j2 = 1; + k2 = v3; + continue d; + } + case 46: { + E3 = (s2 + ((r2 ? 115 : 96) << u3) << 5) + t3 | 0; + F3 = i2 + (k2 << 2) | 0; + q2 = c[F3 >> 2] | 0; + c[F3 >> 2] = q2 >>> 0 < E3 >>> 0 ? q2 : E3; + if ((a[f2 + (t3 + 2) >> 0] | 0) != 32) { + j2 = 1; + k2 = v3; + continue d; + } + k2 = (s2 + ((r2 ? 117 : 91) << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 3 << 2) | 0; + F3 = c[j2 >> 2] | 0; + c[j2 >> 2] = F3 >>> 0 < k2 >>> 0 ? F3 : k2; + j2 = 1; + k2 = v3; + continue d; + } + case 61: + switch (a[f2 + (t3 + 2) >> 0] | 0) { + case 34: { + k2 = (s2 + (((r2 & 1) << 3 ^ 8) + 110 << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 3 << 2) | 0; + F3 = c[j2 >> 2] | 0; + c[j2 >> 2] = F3 >>> 0 < k2 >>> 0 ? F3 : k2; + j2 = 1; + k2 = v3; + continue d; + } + case 39: { + k2 = (s2 + (120 - (r2 & 1) << u3) << 5) + t3 | 0; + j2 = i2 + (t3 + 3 << 2) | 0; + F3 = c[j2 >> 2] | 0; + c[j2 >> 2] = F3 >>> 0 < k2 >>> 0 ? F3 : k2; + j2 = 1; + k2 = v3; + continue d; + } + default: { + j2 = 1; + k2 = v3; + continue d; + } + } + default: { + j2 = 1; + k2 = v3; + continue d; + } + } + } + } + default: { + } + } + while (0); + if (h2 >>> 0 <= 5) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + k2 = a[D3 >> 0] | 0; + l2 = a[f2 >> 0] | 0; + f: do + if (k2 << 24 >> 24 == 32) { + switch (l2 << 24 >> 24) { + case 44: + case 115: + case 101: { + C3 = 241; + break f; + } + case -62: + break; + default: + break f; + } + if (k2 << 24 >> 24 == -96) C3 = 241; + } else if (l2 << 24 >> 24 == -62 & k2 << 24 >> 24 == -96) C3 = 241; + while (0); + g: do + if ((C3 | 0) == 241) { + u3 = f2 + 2 | 0; + k2 = b2[88430 + ((_(d[u3 >> 0] | d[u3 + 1 >> 0] << 8 | d[u3 + 2 >> 0] << 16 | d[u3 + 3 >> 0] << 24, 506832829) | 0) >>> 17 << 1) >> 1] | 0; + v3 = h2 + -2 | 0; + l2 = k2 << 16 >> 16 == 0 & 1; + k2 = k2 & 65535; + while (1) { + if (l2 << 24 >> 24) break g; + t3 = k2 + 1 | 0; + k2 = 153966 + (k2 << 2) | 0; + k2 = e[k2 >> 1] | e[k2 + 2 >> 1] << 16; + q2 = k2 >>> 16; + r2 = k2 & 127; + s2 = d[280786 + r2 >> 0] | 0; + l2 = (k2 & 255) >>> 7; + if ((k2 & 65280 | 0) != 0 | r2 >>> 0 > v3 >>> 0) { + F3 = j2; + k2 = t3; + j2 = F3; + continue; + } + o2 = (c[11272 + (r2 << 2) >> 2] | 0) + (_(r2, k2 >>> 16) | 0) | 0; + p2 = f2 + (r2 + 2) | 0; + m3 = f2 + (r2 + -2) | 0; + n2 = 0; + k2 = u3; + while (1) { + if (k2 >>> 0 > m3 >>> 0) break; + F3 = 280811 + (o2 + n2) | 0; + if ((d[k2 >> 0] | d[k2 + 1 >> 0] << 8 | d[k2 + 2 >> 0] << 16 | d[k2 + 3 >> 0] << 24 | 0) != (d[F3 >> 0] | d[F3 + 1 >> 0] << 8 | d[F3 + 2 >> 0] << 16 | d[F3 + 3 >> 0] << 24 | 0)) break; + n2 = n2 + 4 | 0; + k2 = k2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= p2 >>> 0) break; + if ((a[280811 + (o2 + n2) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + n2 = n2 + 1 | 0; + k2 = k2 + 1 | 0; + } + if ((n2 | 0) != (r2 | 0)) { + F3 = j2; + k2 = t3; + j2 = F3; + continue; + } + k2 = a[f2 >> 0] | 0; + if (k2 << 24 >> 24 == -62) { + k2 = (q2 + (102 << s2) << 5) + r2 | 0; + j2 = i2 + (r2 + 2 << 2) | 0; + F3 = c[j2 >> 2] | 0; + c[j2 >> 2] = F3 >>> 0 < k2 >>> 0 ? F3 : k2; + j2 = 1; + k2 = t3; + continue; + } + m3 = r2 + 2 | 0; + if (m3 >>> 0 >= h2 >>> 0) { + F3 = j2; + k2 = t3; + j2 = F3; + continue; + } + if ((a[f2 + m3 >> 0] | 0) != 32) { + F3 = j2; + k2 = t3; + j2 = F3; + continue; + } + k2 = (q2 + ((k2 << 24 >> 24 == 101 ? 18 : k2 << 24 >> 24 == 115 ? 7 : 13) << s2) << 5) + r2 | 0; + j2 = i2 + (r2 + 3 << 2) | 0; + F3 = c[j2 >> 2] | 0; + c[j2 >> 2] = F3 >>> 0 < k2 >>> 0 ? F3 : k2; + j2 = 1; + k2 = t3; + } + } + while (0); + if (h2 >>> 0 <= 8) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + switch (a[f2 >> 0] | 0) { + case 32: { + if ((a[D3 >> 0] | 0) != 116) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + if ((a[f2 + 2 >> 0] | 0) != 104) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + if ((a[f2 + 3 >> 0] | 0) != 101) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + if ((a[f2 + 4 >> 0] | 0) != 32) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + break; + } + case 46: { + if ((a[D3 >> 0] | 0) != 99) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + if ((a[f2 + 2 >> 0] | 0) != 111) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + if ((a[f2 + 3 >> 0] | 0) != 109) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + if ((a[f2 + 4 >> 0] | 0) != 47) { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + break; + } + default: { + F3 = j2; + F3 = F3 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + } + u3 = f2 + 5 | 0; + k2 = b2[88430 + ((_(d[u3 >> 0] | d[u3 + 1 >> 0] << 8 | d[u3 + 2 >> 0] << 16 | d[u3 + 3 >> 0] << 24, 506832829) | 0) >>> 17 << 1) >> 1] | 0; + v3 = h2 + -5 | 0; + l2 = k2 << 16 >> 16 == 0 & 1; + k2 = k2 & 65535; + while (1) { + if (l2 << 24 >> 24) break; + t3 = k2 + 1 | 0; + k2 = 153966 + (k2 << 2) | 0; + k2 = e[k2 >> 1] | e[k2 + 2 >> 1] << 16; + q2 = k2 >>> 16; + r2 = k2 & 127; + s2 = d[280786 + r2 >> 0] | 0; + l2 = (k2 & 255) >>> 7; + if ((k2 & 65280 | 0) != 0 | r2 >>> 0 > v3 >>> 0) { + F3 = j2; + k2 = t3; + j2 = F3; + continue; + } + o2 = (c[11272 + (r2 << 2) >> 2] | 0) + (_(r2, k2 >>> 16) | 0) | 0; + p2 = f2 + (r2 + 5) | 0; + m3 = f2 + (r2 + 1) | 0; + n2 = 0; + k2 = u3; + while (1) { + if (k2 >>> 0 > m3 >>> 0) break; + F3 = 280811 + (o2 + n2) | 0; + if ((d[k2 >> 0] | d[k2 + 1 >> 0] << 8 | d[k2 + 2 >> 0] << 16 | d[k2 + 3 >> 0] << 24 | 0) != (d[F3 >> 0] | d[F3 + 1 >> 0] << 8 | d[F3 + 2 >> 0] << 16 | d[F3 + 3 >> 0] << 24 | 0)) break; + n2 = n2 + 4 | 0; + k2 = k2 + 4 | 0; + } + while (1) { + if (k2 >>> 0 >= p2 >>> 0) break; + if ((a[280811 + (o2 + n2) >> 0] | 0) != (a[k2 >> 0] | 0)) break; + n2 = n2 + 1 | 0; + k2 = k2 + 1 | 0; + } + if ((n2 | 0) != (r2 | 0)) { + F3 = j2; + k2 = t3; + j2 = F3; + continue; + } + j2 = r2 + 5 | 0; + E3 = (q2 + (((a[f2 >> 0] | 0) == 32 ? 41 : 72) << s2) << 5) + r2 | 0; + F3 = i2 + (j2 << 2) | 0; + D3 = c[F3 >> 2] | 0; + c[F3 >> 2] = D3 >>> 0 < E3 >>> 0 ? D3 : E3; + if (j2 >>> 0 >= h2 >>> 0) { + j2 = 1; + k2 = t3; + continue; + } + if (!((a[f2 >> 0] | 0) == 32 & (r2 + 8 | 0) >>> 0 < h2 >>> 0)) { + j2 = 1; + k2 = t3; + continue; + } + if ((a[f2 + j2 >> 0] | 0) != 32) { + j2 = 1; + k2 = t3; + continue; + } + if ((a[f2 + (r2 + 6) >> 0] | 0) != 111) { + j2 = 1; + k2 = t3; + continue; + } + if ((a[f2 + (r2 + 7) >> 0] | 0) != 102) { + j2 = 1; + k2 = t3; + continue; + } + if ((a[f2 + (r2 + 8) >> 0] | 0) != 32) { + j2 = 1; + k2 = t3; + continue; + } + E3 = (q2 + (62 << s2) << 5) + r2 | 0; + F3 = i2 + (r2 + 9 << 2) | 0; + D3 = c[F3 >> 2] | 0; + c[F3 >> 2] = D3 >>> 0 < E3 >>> 0 ? D3 : E3; + if ((r2 + 12 | 0) >>> 0 >= h2 >>> 0) { + j2 = 1; + k2 = t3; + continue; + } + if ((a[f2 + (r2 + 9) >> 0] | 0) != 116) { + j2 = 1; + k2 = t3; + continue; + } + if ((a[f2 + (r2 + 10) >> 0] | 0) != 104) { + j2 = 1; + k2 = t3; + continue; + } + if ((a[f2 + (r2 + 11) >> 0] | 0) != 101) { + j2 = 1; + k2 = t3; + continue; + } + if ((a[f2 + (r2 + 12) >> 0] | 0) != 32) { + j2 = 1; + k2 = t3; + continue; + } + k2 = (q2 + (73 << s2) << 5) + r2 | 0; + j2 = i2 + (r2 + 13 << 2) | 0; + F3 = c[j2 >> 2] | 0; + c[j2 >> 2] = F3 >>> 0 < k2 >>> 0 ? F3 : k2; + j2 = 1; + k2 = t3; + } + F3 = j2 & 1; + F3 = F3 << 24 >> 24 != 0; + return F3 | 0; + } + function Wb(b3, c2, d2, e2) { + b3 = b3 | 0; + c2 = c2 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + var f2 = 0, g3 = 0, h2 = 0, i2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0; + f2 = 0; + r2 = 0; + a: while (1) { + b: do { + if (f2 >>> 0 >= e2 >>> 0) break a; + g3 = f2 + c2 & d2; + h2 = e2 - f2 | 0; + i2 = a[b3 + g3 >> 0] | 0; + if (!(i2 << 24 >> 24 <= -1 | i2 << 24 >> 24 == 0)) { + g3 = 1; + s2 = 20; + break; + } + do + if (h2 >>> 0 > 1) { + if (((i2 & -32) << 24 >> 24 == -64 ? (j2 = a[b3 + (g3 + 1) >> 0] | 0, (j2 & -64) << 24 >> 24 == -128) : 0) ? (k2 = (i2 & 255) << 6 & 1984 | j2 & 63, k2 >>> 0 > 127) : 0) { + h2 = 2; + g3 = k2; + break; + } + if (h2 >>> 0 > 2) { + if ((((i2 & -16) << 24 >> 24 == -32 ? (l2 = a[b3 + (g3 + 1) >> 0] | 0, (l2 & -64) << 24 >> 24 == -128) : 0) ? (m3 = a[b3 + (g3 + 2) >> 0] | 0, (m3 & -64) << 24 >> 24 == -128) : 0) ? (n2 = (i2 & 255) << 12 & 61440 | (l2 & 255) << 6 & 4032 | m3 & 63, n2 >>> 0 > 2047) : 0) { + h2 = 3; + g3 = n2; + break; + } + if ((((h2 >>> 0 > 3 & (i2 & -8) << 24 >> 24 == -16 ? (o2 = a[b3 + (g3 + 1) >> 0] | 0, (o2 & -64) << 24 >> 24 == -128) : 0) ? (p2 = a[b3 + (g3 + 2) >> 0] | 0, (p2 & -64) << 24 >> 24 == -128) : 0) ? (q2 = a[b3 + (g3 + 3) >> 0] | 0, (q2 & -64) << 24 >> 24 == -128) : 0) ? (s2 = (i2 & 255) << 18 & 1835008 | (o2 & 255) << 12 & 258048 | (p2 & 255) << 6 & 4032 | q2 & 63, s2 >>> 0 > 65535 & s2 >>> 0 < 1114112) : 0) { + g3 = 4; + s2 = 20; + break b; + } else s2 = 19; + } else s2 = 19; + } else s2 = 19; + while (0); + if ((s2 | 0) == 19) { + s2 = 0; + h2 = 1; + g3 = i2 & 255 | 1114112; + } + f2 = f2 + h2 | 0; + } while ((g3 | 0) >= 1114112); + if ((s2 | 0) == 20) { + s2 = 0; + h2 = g3; + f2 = f2 + g3 | 0; + } + r2 = r2 + h2 | 0; + } + return +(r2 >>> 0) > +(e2 >>> 0) * 0.75 | 0; + } + function Xb(a2) { + a2 = +a2; + var b3 = 0, d2 = 0, e2 = 0, f2 = 0, g3 = 0, i2 = 0, j2 = 0, l2 = 0, m3 = 0; + h[k >> 3] = a2; + d2 = c[k >> 2] | 0; + b3 = c[k + 4 >> 2] | 0; + e2 = (b3 | 0) < 0; + do + if (e2 | b3 >>> 0 < 1048576) { + if ((d2 | 0) == 0 & (b3 & 2147483647 | 0) == 0) { + a2 = -1 / (a2 * a2); + break; + } + if (e2) { + a2 = (a2 - a2) / 0; + break; + } else { + h[k >> 3] = a2 * 18014398509481984; + b3 = c[k + 4 >> 2] | 0; + e2 = c[k >> 2] | 0; + d2 = -1077; + f2 = 9; + break; + } + } else if (b3 >>> 0 <= 2146435071) if ((d2 | 0) == 0 & true & (b3 | 0) == 1072693248) a2 = 0; + else { + e2 = d2; + d2 = -1023; + f2 = 9; + } + while (0); + if ((f2 | 0) == 9) { + f2 = b3 + 614242 | 0; + c[k >> 2] = e2; + c[k + 4 >> 2] = (f2 & 1048575) + 1072079006; + l2 = +h[k >> 3] + -1; + a2 = l2 * (l2 * 0.5); + m3 = l2 / (l2 + 2); + i2 = m3 * m3; + j2 = i2 * i2; + h[k >> 3] = l2 - a2; + e2 = c[k + 4 >> 2] | 0; + c[k >> 2] = 0; + c[k + 4 >> 2] = e2; + g3 = +h[k >> 3]; + a2 = m3 * (a2 + (j2 * (j2 * (j2 * 0.15313837699209373 + 0.22222198432149784) + 0.3999999999940942) + i2 * (j2 * (j2 * (j2 * 0.14798198605116586 + 0.1818357216161805) + 0.2857142874366239) + 0.6666666666666735))) + (l2 - g3 - a2); + l2 = g3 * 1.4426950407214463; + j2 = +(d2 + (f2 >>> 20) | 0); + i2 = j2 + l2; + a2 = i2 + (l2 + (j2 - i2) + (a2 * 1.4426950407214463 + (g3 + a2) * 16751713164886512e-26)); + } + return +a2; + } + function Yb(a2) { + a2 = a2 | 0; + var b3 = 0, d2 = 0, e2 = 0, f2 = 0, g3 = 0, h2 = 0, i2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0, v3 = 0, w2 = 0, x3 = 0, y3 = 0, z3 = 0, A3 = 0, B3 = 0, C3 = 0, D3 = 0, E3 = 0, F3 = 0, G3 = 0, H3 = 0, I3 = 0, J3 = 0, K3 = 0, L3 = 0; + do + if (a2 >>> 0 < 245) { + o2 = a2 >>> 0 < 11 ? 16 : a2 + 11 & -8; + a2 = o2 >>> 3; + i2 = c[5147] | 0; + b3 = i2 >>> a2; + if (b3 & 3) { + b3 = (b3 & 1 ^ 1) + a2 | 0; + e2 = b3 << 1; + d2 = 20628 + (e2 << 2) | 0; + e2 = 20628 + (e2 + 2 << 2) | 0; + f2 = c[e2 >> 2] | 0; + g3 = f2 + 8 | 0; + h2 = c[g3 >> 2] | 0; + do + if ((d2 | 0) != (h2 | 0)) { + if (h2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + a2 = h2 + 12 | 0; + if ((c[a2 >> 2] | 0) == (f2 | 0)) { + c[a2 >> 2] = d2; + c[e2 >> 2] = h2; + break; + } else ha2(); + } else c[5147] = i2 & ~(1 << b3); + while (0); + L3 = b3 << 3; + c[f2 + 4 >> 2] = L3 | 3; + L3 = f2 + (L3 | 4) | 0; + c[L3 >> 2] = c[L3 >> 2] | 1; + L3 = g3; + return L3 | 0; + } + h2 = c[5149] | 0; + if (o2 >>> 0 > h2 >>> 0) { + if (b3) { + e2 = 2 << a2; + e2 = b3 << a2 & (e2 | 0 - e2); + e2 = (e2 & 0 - e2) + -1 | 0; + j2 = e2 >>> 12 & 16; + e2 = e2 >>> j2; + f2 = e2 >>> 5 & 8; + e2 = e2 >>> f2; + g3 = e2 >>> 2 & 4; + e2 = e2 >>> g3; + d2 = e2 >>> 1 & 2; + e2 = e2 >>> d2; + b3 = e2 >>> 1 & 1; + b3 = (f2 | j2 | g3 | d2 | b3) + (e2 >>> b3) | 0; + e2 = b3 << 1; + d2 = 20628 + (e2 << 2) | 0; + e2 = 20628 + (e2 + 2 << 2) | 0; + g3 = c[e2 >> 2] | 0; + j2 = g3 + 8 | 0; + f2 = c[j2 >> 2] | 0; + do + if ((d2 | 0) != (f2 | 0)) { + if (f2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + a2 = f2 + 12 | 0; + if ((c[a2 >> 2] | 0) == (g3 | 0)) { + c[a2 >> 2] = d2; + c[e2 >> 2] = f2; + k2 = c[5149] | 0; + break; + } else ha2(); + } else { + c[5147] = i2 & ~(1 << b3); + k2 = h2; + } + while (0); + L3 = b3 << 3; + h2 = L3 - o2 | 0; + c[g3 + 4 >> 2] = o2 | 3; + i2 = g3 + o2 | 0; + c[g3 + (o2 | 4) >> 2] = h2 | 1; + c[g3 + L3 >> 2] = h2; + if (k2) { + f2 = c[5152] | 0; + d2 = k2 >>> 3; + a2 = d2 << 1; + e2 = 20628 + (a2 << 2) | 0; + b3 = c[5147] | 0; + d2 = 1 << d2; + if (b3 & d2) { + b3 = 20628 + (a2 + 2 << 2) | 0; + a2 = c[b3 >> 2] | 0; + if (a2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + l2 = b3; + m3 = a2; + } + } else { + c[5147] = b3 | d2; + l2 = 20628 + (a2 + 2 << 2) | 0; + m3 = e2; + } + c[l2 >> 2] = f2; + c[m3 + 12 >> 2] = f2; + c[f2 + 8 >> 2] = m3; + c[f2 + 12 >> 2] = e2; + } + c[5149] = h2; + c[5152] = i2; + L3 = j2; + return L3 | 0; + } + a2 = c[5148] | 0; + if (a2) { + i2 = (a2 & 0 - a2) + -1 | 0; + K3 = i2 >>> 12 & 16; + i2 = i2 >>> K3; + J3 = i2 >>> 5 & 8; + i2 = i2 >>> J3; + L3 = i2 >>> 2 & 4; + i2 = i2 >>> L3; + b3 = i2 >>> 1 & 2; + i2 = i2 >>> b3; + j2 = i2 >>> 1 & 1; + j2 = c[20892 + ((J3 | K3 | L3 | b3 | j2) + (i2 >>> j2) << 2) >> 2] | 0; + i2 = (c[j2 + 4 >> 2] & -8) - o2 | 0; + b3 = j2; + while (1) { + a2 = c[b3 + 16 >> 2] | 0; + if (!a2) { + a2 = c[b3 + 20 >> 2] | 0; + if (!a2) break; + } + b3 = (c[a2 + 4 >> 2] & -8) - o2 | 0; + L3 = b3 >>> 0 < i2 >>> 0; + i2 = L3 ? b3 : i2; + b3 = a2; + j2 = L3 ? a2 : j2; + } + f2 = c[5151] | 0; + if (j2 >>> 0 < f2 >>> 0) ha2(); + h2 = j2 + o2 | 0; + if (j2 >>> 0 >= h2 >>> 0) ha2(); + g3 = c[j2 + 24 >> 2] | 0; + d2 = c[j2 + 12 >> 2] | 0; + do + if ((d2 | 0) == (j2 | 0)) { + b3 = j2 + 20 | 0; + a2 = c[b3 >> 2] | 0; + if (!a2) { + b3 = j2 + 16 | 0; + a2 = c[b3 >> 2] | 0; + if (!a2) { + n2 = 0; + break; + } + } + while (1) { + d2 = a2 + 20 | 0; + e2 = c[d2 >> 2] | 0; + if (e2) { + a2 = e2; + b3 = d2; + continue; + } + d2 = a2 + 16 | 0; + e2 = c[d2 >> 2] | 0; + if (!e2) break; + else { + a2 = e2; + b3 = d2; + } + } + if (b3 >>> 0 < f2 >>> 0) ha2(); + else { + c[b3 >> 2] = 0; + n2 = a2; + break; + } + } else { + e2 = c[j2 + 8 >> 2] | 0; + if (e2 >>> 0 < f2 >>> 0) ha2(); + a2 = e2 + 12 | 0; + if ((c[a2 >> 2] | 0) != (j2 | 0)) ha2(); + b3 = d2 + 8 | 0; + if ((c[b3 >> 2] | 0) == (j2 | 0)) { + c[a2 >> 2] = d2; + c[b3 >> 2] = e2; + n2 = d2; + break; + } else ha2(); + } + while (0); + do + if (g3) { + a2 = c[j2 + 28 >> 2] | 0; + b3 = 20892 + (a2 << 2) | 0; + if ((j2 | 0) == (c[b3 >> 2] | 0)) { + c[b3 >> 2] = n2; + if (!n2) { + c[5148] = c[5148] & ~(1 << a2); + break; + } + } else { + if (g3 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + a2 = g3 + 16 | 0; + if ((c[a2 >> 2] | 0) == (j2 | 0)) c[a2 >> 2] = n2; + else c[g3 + 20 >> 2] = n2; + if (!n2) break; + } + b3 = c[5151] | 0; + if (n2 >>> 0 < b3 >>> 0) ha2(); + c[n2 + 24 >> 2] = g3; + a2 = c[j2 + 16 >> 2] | 0; + do + if (a2) if (a2 >>> 0 < b3 >>> 0) ha2(); + else { + c[n2 + 16 >> 2] = a2; + c[a2 + 24 >> 2] = n2; + break; + } + while (0); + a2 = c[j2 + 20 >> 2] | 0; + if (a2) if (a2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[n2 + 20 >> 2] = a2; + c[a2 + 24 >> 2] = n2; + break; + } + } + while (0); + if (i2 >>> 0 < 16) { + L3 = i2 + o2 | 0; + c[j2 + 4 >> 2] = L3 | 3; + L3 = j2 + (L3 + 4) | 0; + c[L3 >> 2] = c[L3 >> 2] | 1; + } else { + c[j2 + 4 >> 2] = o2 | 3; + c[j2 + (o2 | 4) >> 2] = i2 | 1; + c[j2 + (i2 + o2) >> 2] = i2; + a2 = c[5149] | 0; + if (a2) { + f2 = c[5152] | 0; + d2 = a2 >>> 3; + a2 = d2 << 1; + e2 = 20628 + (a2 << 2) | 0; + b3 = c[5147] | 0; + d2 = 1 << d2; + if (b3 & d2) { + a2 = 20628 + (a2 + 2 << 2) | 0; + b3 = c[a2 >> 2] | 0; + if (b3 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + p2 = a2; + q2 = b3; + } + } else { + c[5147] = b3 | d2; + p2 = 20628 + (a2 + 2 << 2) | 0; + q2 = e2; + } + c[p2 >> 2] = f2; + c[q2 + 12 >> 2] = f2; + c[f2 + 8 >> 2] = q2; + c[f2 + 12 >> 2] = e2; + } + c[5149] = i2; + c[5152] = h2; + } + L3 = j2 + 8 | 0; + return L3 | 0; + } + } + } else if (a2 >>> 0 <= 4294967231) { + a2 = a2 + 11 | 0; + o2 = a2 & -8; + j2 = c[5148] | 0; + if (j2) { + b3 = 0 - o2 | 0; + a2 = a2 >>> 8; + if (a2) if (o2 >>> 0 > 16777215) i2 = 31; + else { + q2 = (a2 + 1048320 | 0) >>> 16 & 8; + x3 = a2 << q2; + p2 = (x3 + 520192 | 0) >>> 16 & 4; + x3 = x3 << p2; + i2 = (x3 + 245760 | 0) >>> 16 & 2; + i2 = 14 - (p2 | q2 | i2) + (x3 << i2 >>> 15) | 0; + i2 = o2 >>> (i2 + 7 | 0) & 1 | i2 << 1; + } + else i2 = 0; + a2 = c[20892 + (i2 << 2) >> 2] | 0; + a: do + if (!a2) { + d2 = 0; + a2 = 0; + x3 = 86; + } else { + f2 = b3; + d2 = 0; + g3 = o2 << ((i2 | 0) == 31 ? 0 : 25 - (i2 >>> 1) | 0); + h2 = a2; + a2 = 0; + while (1) { + e2 = c[h2 + 4 >> 2] & -8; + b3 = e2 - o2 | 0; + if (b3 >>> 0 < f2 >>> 0) if ((e2 | 0) == (o2 | 0)) { + e2 = h2; + a2 = h2; + x3 = 90; + break a; + } else a2 = h2; + else b3 = f2; + x3 = c[h2 + 20 >> 2] | 0; + h2 = c[h2 + 16 + (g3 >>> 31 << 2) >> 2] | 0; + d2 = (x3 | 0) == 0 | (x3 | 0) == (h2 | 0) ? d2 : x3; + if (!h2) { + x3 = 86; + break; + } else { + f2 = b3; + g3 = g3 << 1; + } + } + } + while (0); + if ((x3 | 0) == 86) { + if ((d2 | 0) == 0 & (a2 | 0) == 0) { + a2 = 2 << i2; + a2 = j2 & (a2 | 0 - a2); + if (!a2) break; + a2 = (a2 & 0 - a2) + -1 | 0; + n2 = a2 >>> 12 & 16; + a2 = a2 >>> n2; + m3 = a2 >>> 5 & 8; + a2 = a2 >>> m3; + p2 = a2 >>> 2 & 4; + a2 = a2 >>> p2; + q2 = a2 >>> 1 & 2; + a2 = a2 >>> q2; + d2 = a2 >>> 1 & 1; + d2 = c[20892 + ((m3 | n2 | p2 | q2 | d2) + (a2 >>> d2) << 2) >> 2] | 0; + a2 = 0; + } + if (!d2) { + i2 = b3; + j2 = a2; + } else { + e2 = d2; + x3 = 90; + } + } + if ((x3 | 0) == 90) while (1) { + x3 = 0; + q2 = (c[e2 + 4 >> 2] & -8) - o2 | 0; + d2 = q2 >>> 0 < b3 >>> 0; + b3 = d2 ? q2 : b3; + a2 = d2 ? e2 : a2; + d2 = c[e2 + 16 >> 2] | 0; + if (d2) { + e2 = d2; + x3 = 90; + continue; + } + e2 = c[e2 + 20 >> 2] | 0; + if (!e2) { + i2 = b3; + j2 = a2; + break; + } else x3 = 90; + } + if ((j2 | 0) != 0 ? i2 >>> 0 < ((c[5149] | 0) - o2 | 0) >>> 0 : 0) { + f2 = c[5151] | 0; + if (j2 >>> 0 < f2 >>> 0) ha2(); + h2 = j2 + o2 | 0; + if (j2 >>> 0 >= h2 >>> 0) ha2(); + g3 = c[j2 + 24 >> 2] | 0; + d2 = c[j2 + 12 >> 2] | 0; + do + if ((d2 | 0) == (j2 | 0)) { + b3 = j2 + 20 | 0; + a2 = c[b3 >> 2] | 0; + if (!a2) { + b3 = j2 + 16 | 0; + a2 = c[b3 >> 2] | 0; + if (!a2) { + s2 = 0; + break; + } + } + while (1) { + d2 = a2 + 20 | 0; + e2 = c[d2 >> 2] | 0; + if (e2) { + a2 = e2; + b3 = d2; + continue; + } + d2 = a2 + 16 | 0; + e2 = c[d2 >> 2] | 0; + if (!e2) break; + else { + a2 = e2; + b3 = d2; + } + } + if (b3 >>> 0 < f2 >>> 0) ha2(); + else { + c[b3 >> 2] = 0; + s2 = a2; + break; + } + } else { + e2 = c[j2 + 8 >> 2] | 0; + if (e2 >>> 0 < f2 >>> 0) ha2(); + a2 = e2 + 12 | 0; + if ((c[a2 >> 2] | 0) != (j2 | 0)) ha2(); + b3 = d2 + 8 | 0; + if ((c[b3 >> 2] | 0) == (j2 | 0)) { + c[a2 >> 2] = d2; + c[b3 >> 2] = e2; + s2 = d2; + break; + } else ha2(); + } + while (0); + do + if (g3) { + a2 = c[j2 + 28 >> 2] | 0; + b3 = 20892 + (a2 << 2) | 0; + if ((j2 | 0) == (c[b3 >> 2] | 0)) { + c[b3 >> 2] = s2; + if (!s2) { + c[5148] = c[5148] & ~(1 << a2); + break; + } + } else { + if (g3 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + a2 = g3 + 16 | 0; + if ((c[a2 >> 2] | 0) == (j2 | 0)) c[a2 >> 2] = s2; + else c[g3 + 20 >> 2] = s2; + if (!s2) break; + } + b3 = c[5151] | 0; + if (s2 >>> 0 < b3 >>> 0) ha2(); + c[s2 + 24 >> 2] = g3; + a2 = c[j2 + 16 >> 2] | 0; + do + if (a2) if (a2 >>> 0 < b3 >>> 0) ha2(); + else { + c[s2 + 16 >> 2] = a2; + c[a2 + 24 >> 2] = s2; + break; + } + while (0); + a2 = c[j2 + 20 >> 2] | 0; + if (a2) if (a2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[s2 + 20 >> 2] = a2; + c[a2 + 24 >> 2] = s2; + break; + } + } + while (0); + b: do + if (i2 >>> 0 >= 16) { + c[j2 + 4 >> 2] = o2 | 3; + c[j2 + (o2 | 4) >> 2] = i2 | 1; + c[j2 + (i2 + o2) >> 2] = i2; + a2 = i2 >>> 3; + if (i2 >>> 0 < 256) { + b3 = a2 << 1; + e2 = 20628 + (b3 << 2) | 0; + d2 = c[5147] | 0; + a2 = 1 << a2; + if (d2 & a2) { + a2 = 20628 + (b3 + 2 << 2) | 0; + b3 = c[a2 >> 2] | 0; + if (b3 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + t3 = a2; + u3 = b3; + } + } else { + c[5147] = d2 | a2; + t3 = 20628 + (b3 + 2 << 2) | 0; + u3 = e2; + } + c[t3 >> 2] = h2; + c[u3 + 12 >> 2] = h2; + c[j2 + (o2 + 8) >> 2] = u3; + c[j2 + (o2 + 12) >> 2] = e2; + break; + } + a2 = i2 >>> 8; + if (a2) if (i2 >>> 0 > 16777215) e2 = 31; + else { + K3 = (a2 + 1048320 | 0) >>> 16 & 8; + L3 = a2 << K3; + J3 = (L3 + 520192 | 0) >>> 16 & 4; + L3 = L3 << J3; + e2 = (L3 + 245760 | 0) >>> 16 & 2; + e2 = 14 - (J3 | K3 | e2) + (L3 << e2 >>> 15) | 0; + e2 = i2 >>> (e2 + 7 | 0) & 1 | e2 << 1; + } + else e2 = 0; + a2 = 20892 + (e2 << 2) | 0; + c[j2 + (o2 + 28) >> 2] = e2; + c[j2 + (o2 + 20) >> 2] = 0; + c[j2 + (o2 + 16) >> 2] = 0; + b3 = c[5148] | 0; + d2 = 1 << e2; + if (!(b3 & d2)) { + c[5148] = b3 | d2; + c[a2 >> 2] = h2; + c[j2 + (o2 + 24) >> 2] = a2; + c[j2 + (o2 + 12) >> 2] = h2; + c[j2 + (o2 + 8) >> 2] = h2; + break; + } + a2 = c[a2 >> 2] | 0; + c: do + if ((c[a2 + 4 >> 2] & -8 | 0) != (i2 | 0)) { + e2 = i2 << ((e2 | 0) == 31 ? 0 : 25 - (e2 >>> 1) | 0); + while (1) { + d2 = a2 + 16 + (e2 >>> 31 << 2) | 0; + b3 = c[d2 >> 2] | 0; + if (!b3) break; + if ((c[b3 + 4 >> 2] & -8 | 0) == (i2 | 0)) { + w2 = b3; + break c; + } else { + e2 = e2 << 1; + a2 = b3; + } + } + if (d2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[d2 >> 2] = h2; + c[j2 + (o2 + 24) >> 2] = a2; + c[j2 + (o2 + 12) >> 2] = h2; + c[j2 + (o2 + 8) >> 2] = h2; + break b; + } + } else w2 = a2; + while (0); + a2 = w2 + 8 | 0; + b3 = c[a2 >> 2] | 0; + L3 = c[5151] | 0; + if (b3 >>> 0 >= L3 >>> 0 & w2 >>> 0 >= L3 >>> 0) { + c[b3 + 12 >> 2] = h2; + c[a2 >> 2] = h2; + c[j2 + (o2 + 8) >> 2] = b3; + c[j2 + (o2 + 12) >> 2] = w2; + c[j2 + (o2 + 24) >> 2] = 0; + break; + } else ha2(); + } else { + L3 = i2 + o2 | 0; + c[j2 + 4 >> 2] = L3 | 3; + L3 = j2 + (L3 + 4) | 0; + c[L3 >> 2] = c[L3 >> 2] | 1; + } + while (0); + L3 = j2 + 8 | 0; + return L3 | 0; + } + } + } else o2 = -1; + while (0); + d2 = c[5149] | 0; + if (d2 >>> 0 >= o2 >>> 0) { + a2 = d2 - o2 | 0; + b3 = c[5152] | 0; + if (a2 >>> 0 > 15) { + c[5152] = b3 + o2; + c[5149] = a2; + c[b3 + (o2 + 4) >> 2] = a2 | 1; + c[b3 + d2 >> 2] = a2; + c[b3 + 4 >> 2] = o2 | 3; + } else { + c[5149] = 0; + c[5152] = 0; + c[b3 + 4 >> 2] = d2 | 3; + L3 = b3 + (d2 + 4) | 0; + c[L3 >> 2] = c[L3 >> 2] | 1; + } + L3 = b3 + 8 | 0; + return L3 | 0; + } + a2 = c[5150] | 0; + if (a2 >>> 0 > o2 >>> 0) { + K3 = a2 - o2 | 0; + c[5150] = K3; + L3 = c[5153] | 0; + c[5153] = L3 + o2; + c[L3 + (o2 + 4) >> 2] = K3 | 1; + c[L3 + 4 >> 2] = o2 | 3; + L3 = L3 + 8 | 0; + return L3 | 0; + } + do + if (!(c[5265] | 0)) { + a2 = ja2(30) | 0; + if (!(a2 + -1 & a2)) { + c[5267] = a2; + c[5266] = a2; + c[5268] = -1; + c[5269] = -1; + c[5270] = 0; + c[5258] = 0; + c[5265] = (la2(0) | 0) & -16 ^ 1431655768; + break; + } else ha2(); + } + while (0); + g3 = o2 + 48 | 0; + f2 = c[5267] | 0; + h2 = o2 + 47 | 0; + e2 = f2 + h2 | 0; + f2 = 0 - f2 | 0; + i2 = e2 & f2; + if (i2 >>> 0 <= o2 >>> 0) { + L3 = 0; + return L3 | 0; + } + a2 = c[5257] | 0; + if ((a2 | 0) != 0 ? (u3 = c[5255] | 0, w2 = u3 + i2 | 0, w2 >>> 0 <= u3 >>> 0 | w2 >>> 0 > a2 >>> 0) : 0) { + L3 = 0; + return L3 | 0; + } + d: do + if (!(c[5258] & 4)) { + d2 = c[5153] | 0; + e: do + if (d2) { + a2 = 21036; + while (1) { + b3 = c[a2 >> 2] | 0; + if (b3 >>> 0 <= d2 >>> 0 ? (r2 = a2 + 4 | 0, (b3 + (c[r2 >> 2] | 0) | 0) >>> 0 > d2 >>> 0) : 0) break; + a2 = c[a2 + 8 >> 2] | 0; + if (!a2) { + x3 = 174; + break e; + } + } + b3 = e2 - (c[5150] | 0) & f2; + if (b3 >>> 0 < 2147483647) { + d2 = ka2(b3 | 0) | 0; + w2 = (d2 | 0) == ((c[a2 >> 2] | 0) + (c[r2 >> 2] | 0) | 0); + a2 = w2 ? b3 : 0; + if (w2) { + if ((d2 | 0) != (-1 | 0)) { + r2 = d2; + q2 = a2; + x3 = 194; + break d; + } + } else x3 = 184; + } else a2 = 0; + } else x3 = 174; + while (0); + do + if ((x3 | 0) == 174) { + e2 = ka2(0) | 0; + if ((e2 | 0) != (-1 | 0)) { + a2 = e2; + b3 = c[5266] | 0; + d2 = b3 + -1 | 0; + if (!(d2 & a2)) b3 = i2; + else b3 = i2 - a2 + (d2 + a2 & 0 - b3) | 0; + a2 = c[5255] | 0; + d2 = a2 + b3 | 0; + if (b3 >>> 0 > o2 >>> 0 & b3 >>> 0 < 2147483647) { + w2 = c[5257] | 0; + if ((w2 | 0) != 0 ? d2 >>> 0 <= a2 >>> 0 | d2 >>> 0 > w2 >>> 0 : 0) { + a2 = 0; + break; + } + d2 = ka2(b3 | 0) | 0; + x3 = (d2 | 0) == (e2 | 0); + a2 = x3 ? b3 : 0; + if (x3) { + r2 = e2; + q2 = a2; + x3 = 194; + break d; + } else x3 = 184; + } else a2 = 0; + } else a2 = 0; + } + while (0); + f: do + if ((x3 | 0) == 184) { + e2 = 0 - b3 | 0; + do + if (g3 >>> 0 > b3 >>> 0 & (b3 >>> 0 < 2147483647 & (d2 | 0) != (-1 | 0)) ? (v3 = c[5267] | 0, v3 = h2 - b3 + v3 & 0 - v3, v3 >>> 0 < 2147483647) : 0) if ((ka2(v3 | 0) | 0) == (-1 | 0)) { + ka2(e2 | 0) | 0; + break f; + } else { + b3 = v3 + b3 | 0; + break; + } + while (0); + if ((d2 | 0) != (-1 | 0)) { + r2 = d2; + q2 = b3; + x3 = 194; + break d; + } + } + while (0); + c[5258] = c[5258] | 4; + x3 = 191; + } else { + a2 = 0; + x3 = 191; + } + while (0); + if ((((x3 | 0) == 191 ? i2 >>> 0 < 2147483647 : 0) ? (y3 = ka2(i2 | 0) | 0, z3 = ka2(0) | 0, y3 >>> 0 < z3 >>> 0 & ((y3 | 0) != (-1 | 0) & (z3 | 0) != (-1 | 0))) : 0) ? (A3 = z3 - y3 | 0, B3 = A3 >>> 0 > (o2 + 40 | 0) >>> 0, B3) : 0) { + r2 = y3; + q2 = B3 ? A3 : a2; + x3 = 194; + } + if ((x3 | 0) == 194) { + a2 = (c[5255] | 0) + q2 | 0; + c[5255] = a2; + if (a2 >>> 0 > (c[5256] | 0) >>> 0) c[5256] = a2; + h2 = c[5153] | 0; + g: do + if (h2) { + f2 = 21036; + while (1) { + a2 = c[f2 >> 2] | 0; + b3 = f2 + 4 | 0; + d2 = c[b3 >> 2] | 0; + if ((r2 | 0) == (a2 + d2 | 0)) { + x3 = 204; + break; + } + e2 = c[f2 + 8 >> 2] | 0; + if (!e2) break; + else f2 = e2; + } + if (((x3 | 0) == 204 ? (c[f2 + 12 >> 2] & 8 | 0) == 0 : 0) ? h2 >>> 0 < r2 >>> 0 & h2 >>> 0 >= a2 >>> 0 : 0) { + c[b3 >> 2] = d2 + q2; + L3 = (c[5150] | 0) + q2 | 0; + K3 = h2 + 8 | 0; + K3 = (K3 & 7 | 0) == 0 ? 0 : 0 - K3 & 7; + J3 = L3 - K3 | 0; + c[5153] = h2 + K3; + c[5150] = J3; + c[h2 + (K3 + 4) >> 2] = J3 | 1; + c[h2 + (L3 + 4) >> 2] = 40; + c[5154] = c[5269]; + break; + } + a2 = c[5151] | 0; + if (r2 >>> 0 < a2 >>> 0) { + c[5151] = r2; + j2 = r2; + } else j2 = a2; + b3 = r2 + q2 | 0; + a2 = 21036; + while (1) { + if ((c[a2 >> 2] | 0) == (b3 | 0)) { + x3 = 212; + break; + } + a2 = c[a2 + 8 >> 2] | 0; + if (!a2) { + b3 = 21036; + break; + } + } + if ((x3 | 0) == 212) if (!(c[a2 + 12 >> 2] & 8)) { + c[a2 >> 2] = r2; + n2 = a2 + 4 | 0; + c[n2 >> 2] = (c[n2 >> 2] | 0) + q2; + n2 = r2 + 8 | 0; + n2 = (n2 & 7 | 0) == 0 ? 0 : 0 - n2 & 7; + k2 = r2 + (q2 + 8) | 0; + k2 = (k2 & 7 | 0) == 0 ? 0 : 0 - k2 & 7; + a2 = r2 + (k2 + q2) | 0; + m3 = n2 + o2 | 0; + p2 = r2 + m3 | 0; + l2 = a2 - (r2 + n2) - o2 | 0; + c[r2 + (n2 + 4) >> 2] = o2 | 3; + h: do + if ((a2 | 0) != (h2 | 0)) { + if ((a2 | 0) == (c[5152] | 0)) { + L3 = (c[5149] | 0) + l2 | 0; + c[5149] = L3; + c[5152] = p2; + c[r2 + (m3 + 4) >> 2] = L3 | 1; + c[r2 + (L3 + m3) >> 2] = L3; + break; + } + h2 = q2 + 4 | 0; + b3 = c[r2 + (h2 + k2) >> 2] | 0; + if ((b3 & 3 | 0) == 1) { + i2 = b3 & -8; + f2 = b3 >>> 3; + i: do + if (b3 >>> 0 >= 256) { + g3 = c[r2 + ((k2 | 24) + q2) >> 2] | 0; + e2 = c[r2 + (q2 + 12 + k2) >> 2] | 0; + do + if ((e2 | 0) == (a2 | 0)) { + d2 = k2 | 16; + e2 = r2 + (h2 + d2) | 0; + b3 = c[e2 >> 2] | 0; + if (!b3) { + d2 = r2 + (d2 + q2) | 0; + b3 = c[d2 >> 2] | 0; + if (!b3) { + I3 = 0; + break; + } + } else d2 = e2; + while (1) { + e2 = b3 + 20 | 0; + f2 = c[e2 >> 2] | 0; + if (f2) { + b3 = f2; + d2 = e2; + continue; + } + e2 = b3 + 16 | 0; + f2 = c[e2 >> 2] | 0; + if (!f2) break; + else { + b3 = f2; + d2 = e2; + } + } + if (d2 >>> 0 < j2 >>> 0) ha2(); + else { + c[d2 >> 2] = 0; + I3 = b3; + break; + } + } else { + f2 = c[r2 + ((k2 | 8) + q2) >> 2] | 0; + if (f2 >>> 0 < j2 >>> 0) ha2(); + b3 = f2 + 12 | 0; + if ((c[b3 >> 2] | 0) != (a2 | 0)) ha2(); + d2 = e2 + 8 | 0; + if ((c[d2 >> 2] | 0) == (a2 | 0)) { + c[b3 >> 2] = e2; + c[d2 >> 2] = f2; + I3 = e2; + break; + } else ha2(); + } + while (0); + if (!g3) break; + b3 = c[r2 + (q2 + 28 + k2) >> 2] | 0; + d2 = 20892 + (b3 << 2) | 0; + do + if ((a2 | 0) != (c[d2 >> 2] | 0)) { + if (g3 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + b3 = g3 + 16 | 0; + if ((c[b3 >> 2] | 0) == (a2 | 0)) c[b3 >> 2] = I3; + else c[g3 + 20 >> 2] = I3; + if (!I3) break i; + } else { + c[d2 >> 2] = I3; + if (I3) break; + c[5148] = c[5148] & ~(1 << b3); + break i; + } + while (0); + d2 = c[5151] | 0; + if (I3 >>> 0 < d2 >>> 0) ha2(); + c[I3 + 24 >> 2] = g3; + a2 = k2 | 16; + b3 = c[r2 + (a2 + q2) >> 2] | 0; + do + if (b3) if (b3 >>> 0 < d2 >>> 0) ha2(); + else { + c[I3 + 16 >> 2] = b3; + c[b3 + 24 >> 2] = I3; + break; + } + while (0); + a2 = c[r2 + (h2 + a2) >> 2] | 0; + if (!a2) break; + if (a2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[I3 + 20 >> 2] = a2; + c[a2 + 24 >> 2] = I3; + break; + } + } else { + d2 = c[r2 + ((k2 | 8) + q2) >> 2] | 0; + e2 = c[r2 + (q2 + 12 + k2) >> 2] | 0; + b3 = 20628 + (f2 << 1 << 2) | 0; + do + if ((d2 | 0) != (b3 | 0)) { + if (d2 >>> 0 < j2 >>> 0) ha2(); + if ((c[d2 + 12 >> 2] | 0) == (a2 | 0)) break; + ha2(); + } + while (0); + if ((e2 | 0) == (d2 | 0)) { + c[5147] = c[5147] & ~(1 << f2); + break; + } + do + if ((e2 | 0) == (b3 | 0)) E3 = e2 + 8 | 0; + else { + if (e2 >>> 0 < j2 >>> 0) ha2(); + b3 = e2 + 8 | 0; + if ((c[b3 >> 2] | 0) == (a2 | 0)) { + E3 = b3; + break; + } + ha2(); + } + while (0); + c[d2 + 12 >> 2] = e2; + c[E3 >> 2] = d2; + } + while (0); + a2 = r2 + ((i2 | k2) + q2) | 0; + f2 = i2 + l2 | 0; + } else f2 = l2; + a2 = a2 + 4 | 0; + c[a2 >> 2] = c[a2 >> 2] & -2; + c[r2 + (m3 + 4) >> 2] = f2 | 1; + c[r2 + (f2 + m3) >> 2] = f2; + a2 = f2 >>> 3; + if (f2 >>> 0 < 256) { + b3 = a2 << 1; + e2 = 20628 + (b3 << 2) | 0; + d2 = c[5147] | 0; + a2 = 1 << a2; + do + if (!(d2 & a2)) { + c[5147] = d2 | a2; + J3 = 20628 + (b3 + 2 << 2) | 0; + K3 = e2; + } else { + a2 = 20628 + (b3 + 2 << 2) | 0; + b3 = c[a2 >> 2] | 0; + if (b3 >>> 0 >= (c[5151] | 0) >>> 0) { + J3 = a2; + K3 = b3; + break; + } + ha2(); + } + while (0); + c[J3 >> 2] = p2; + c[K3 + 12 >> 2] = p2; + c[r2 + (m3 + 8) >> 2] = K3; + c[r2 + (m3 + 12) >> 2] = e2; + break; + } + a2 = f2 >>> 8; + do + if (!a2) e2 = 0; + else { + if (f2 >>> 0 > 16777215) { + e2 = 31; + break; + } + J3 = (a2 + 1048320 | 0) >>> 16 & 8; + K3 = a2 << J3; + I3 = (K3 + 520192 | 0) >>> 16 & 4; + K3 = K3 << I3; + e2 = (K3 + 245760 | 0) >>> 16 & 2; + e2 = 14 - (I3 | J3 | e2) + (K3 << e2 >>> 15) | 0; + e2 = f2 >>> (e2 + 7 | 0) & 1 | e2 << 1; + } + while (0); + a2 = 20892 + (e2 << 2) | 0; + c[r2 + (m3 + 28) >> 2] = e2; + c[r2 + (m3 + 20) >> 2] = 0; + c[r2 + (m3 + 16) >> 2] = 0; + b3 = c[5148] | 0; + d2 = 1 << e2; + if (!(b3 & d2)) { + c[5148] = b3 | d2; + c[a2 >> 2] = p2; + c[r2 + (m3 + 24) >> 2] = a2; + c[r2 + (m3 + 12) >> 2] = p2; + c[r2 + (m3 + 8) >> 2] = p2; + break; + } + a2 = c[a2 >> 2] | 0; + j: do + if ((c[a2 + 4 >> 2] & -8 | 0) != (f2 | 0)) { + e2 = f2 << ((e2 | 0) == 31 ? 0 : 25 - (e2 >>> 1) | 0); + while (1) { + d2 = a2 + 16 + (e2 >>> 31 << 2) | 0; + b3 = c[d2 >> 2] | 0; + if (!b3) break; + if ((c[b3 + 4 >> 2] & -8 | 0) == (f2 | 0)) { + L3 = b3; + break j; + } else { + e2 = e2 << 1; + a2 = b3; + } + } + if (d2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[d2 >> 2] = p2; + c[r2 + (m3 + 24) >> 2] = a2; + c[r2 + (m3 + 12) >> 2] = p2; + c[r2 + (m3 + 8) >> 2] = p2; + break h; + } + } else L3 = a2; + while (0); + a2 = L3 + 8 | 0; + b3 = c[a2 >> 2] | 0; + K3 = c[5151] | 0; + if (b3 >>> 0 >= K3 >>> 0 & L3 >>> 0 >= K3 >>> 0) { + c[b3 + 12 >> 2] = p2; + c[a2 >> 2] = p2; + c[r2 + (m3 + 8) >> 2] = b3; + c[r2 + (m3 + 12) >> 2] = L3; + c[r2 + (m3 + 24) >> 2] = 0; + break; + } else ha2(); + } else { + L3 = (c[5150] | 0) + l2 | 0; + c[5150] = L3; + c[5153] = p2; + c[r2 + (m3 + 4) >> 2] = L3 | 1; + } + while (0); + L3 = r2 + (n2 | 8) | 0; + return L3 | 0; + } else b3 = 21036; + while (1) { + a2 = c[b3 >> 2] | 0; + if (a2 >>> 0 <= h2 >>> 0 ? (C3 = c[b3 + 4 >> 2] | 0, D3 = a2 + C3 | 0, D3 >>> 0 > h2 >>> 0) : 0) break; + b3 = c[b3 + 8 >> 2] | 0; + } + b3 = a2 + (C3 + -39) | 0; + b3 = a2 + (C3 + -47 + ((b3 & 7 | 0) == 0 ? 0 : 0 - b3 & 7)) | 0; + f2 = h2 + 16 | 0; + b3 = b3 >>> 0 < f2 >>> 0 ? h2 : b3; + a2 = b3 + 8 | 0; + d2 = r2 + 8 | 0; + d2 = (d2 & 7 | 0) == 0 ? 0 : 0 - d2 & 7; + L3 = q2 + -40 - d2 | 0; + c[5153] = r2 + d2; + c[5150] = L3; + c[r2 + (d2 + 4) >> 2] = L3 | 1; + c[r2 + (q2 + -36) >> 2] = 40; + c[5154] = c[5269]; + d2 = b3 + 4 | 0; + c[d2 >> 2] = 27; + c[a2 >> 2] = c[5259]; + c[a2 + 4 >> 2] = c[5260]; + c[a2 + 8 >> 2] = c[5261]; + c[a2 + 12 >> 2] = c[5262]; + c[5259] = r2; + c[5260] = q2; + c[5262] = 0; + c[5261] = a2; + a2 = b3 + 28 | 0; + c[a2 >> 2] = 7; + if ((b3 + 32 | 0) >>> 0 < D3 >>> 0) do { + L3 = a2; + a2 = a2 + 4 | 0; + c[a2 >> 2] = 7; + } while ((L3 + 8 | 0) >>> 0 < D3 >>> 0); + if ((b3 | 0) != (h2 | 0)) { + g3 = b3 - h2 | 0; + c[d2 >> 2] = c[d2 >> 2] & -2; + c[h2 + 4 >> 2] = g3 | 1; + c[b3 >> 2] = g3; + a2 = g3 >>> 3; + if (g3 >>> 0 < 256) { + b3 = a2 << 1; + e2 = 20628 + (b3 << 2) | 0; + d2 = c[5147] | 0; + a2 = 1 << a2; + if (d2 & a2) { + a2 = 20628 + (b3 + 2 << 2) | 0; + b3 = c[a2 >> 2] | 0; + if (b3 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + F3 = a2; + G3 = b3; + } + } else { + c[5147] = d2 | a2; + F3 = 20628 + (b3 + 2 << 2) | 0; + G3 = e2; + } + c[F3 >> 2] = h2; + c[G3 + 12 >> 2] = h2; + c[h2 + 8 >> 2] = G3; + c[h2 + 12 >> 2] = e2; + break; + } + a2 = g3 >>> 8; + if (a2) if (g3 >>> 0 > 16777215) e2 = 31; + else { + K3 = (a2 + 1048320 | 0) >>> 16 & 8; + L3 = a2 << K3; + J3 = (L3 + 520192 | 0) >>> 16 & 4; + L3 = L3 << J3; + e2 = (L3 + 245760 | 0) >>> 16 & 2; + e2 = 14 - (J3 | K3 | e2) + (L3 << e2 >>> 15) | 0; + e2 = g3 >>> (e2 + 7 | 0) & 1 | e2 << 1; + } + else e2 = 0; + d2 = 20892 + (e2 << 2) | 0; + c[h2 + 28 >> 2] = e2; + c[h2 + 20 >> 2] = 0; + c[f2 >> 2] = 0; + a2 = c[5148] | 0; + b3 = 1 << e2; + if (!(a2 & b3)) { + c[5148] = a2 | b3; + c[d2 >> 2] = h2; + c[h2 + 24 >> 2] = d2; + c[h2 + 12 >> 2] = h2; + c[h2 + 8 >> 2] = h2; + break; + } + a2 = c[d2 >> 2] | 0; + k: do + if ((c[a2 + 4 >> 2] & -8 | 0) != (g3 | 0)) { + e2 = g3 << ((e2 | 0) == 31 ? 0 : 25 - (e2 >>> 1) | 0); + while (1) { + d2 = a2 + 16 + (e2 >>> 31 << 2) | 0; + b3 = c[d2 >> 2] | 0; + if (!b3) break; + if ((c[b3 + 4 >> 2] & -8 | 0) == (g3 | 0)) { + H3 = b3; + break k; + } else { + e2 = e2 << 1; + a2 = b3; + } + } + if (d2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[d2 >> 2] = h2; + c[h2 + 24 >> 2] = a2; + c[h2 + 12 >> 2] = h2; + c[h2 + 8 >> 2] = h2; + break g; + } + } else H3 = a2; + while (0); + a2 = H3 + 8 | 0; + b3 = c[a2 >> 2] | 0; + L3 = c[5151] | 0; + if (b3 >>> 0 >= L3 >>> 0 & H3 >>> 0 >= L3 >>> 0) { + c[b3 + 12 >> 2] = h2; + c[a2 >> 2] = h2; + c[h2 + 8 >> 2] = b3; + c[h2 + 12 >> 2] = H3; + c[h2 + 24 >> 2] = 0; + break; + } else ha2(); + } + } else { + L3 = c[5151] | 0; + if ((L3 | 0) == 0 | r2 >>> 0 < L3 >>> 0) c[5151] = r2; + c[5259] = r2; + c[5260] = q2; + c[5262] = 0; + c[5156] = c[5265]; + c[5155] = -1; + a2 = 0; + do { + L3 = a2 << 1; + K3 = 20628 + (L3 << 2) | 0; + c[20628 + (L3 + 3 << 2) >> 2] = K3; + c[20628 + (L3 + 2 << 2) >> 2] = K3; + a2 = a2 + 1 | 0; + } while ((a2 | 0) != 32); + L3 = r2 + 8 | 0; + L3 = (L3 & 7 | 0) == 0 ? 0 : 0 - L3 & 7; + K3 = q2 + -40 - L3 | 0; + c[5153] = r2 + L3; + c[5150] = K3; + c[r2 + (L3 + 4) >> 2] = K3 | 1; + c[r2 + (q2 + -36) >> 2] = 40; + c[5154] = c[5269]; + } + while (0); + a2 = c[5150] | 0; + if (a2 >>> 0 > o2 >>> 0) { + K3 = a2 - o2 | 0; + c[5150] = K3; + L3 = c[5153] | 0; + c[5153] = L3 + o2; + c[L3 + (o2 + 4) >> 2] = K3 | 1; + c[L3 + 4 >> 2] = o2 | 3; + L3 = L3 + 8 | 0; + return L3 | 0; + } + } + if (!(c[5135] | 0)) a2 = 20584; + else a2 = c[(ga2() | 0) + 60 >> 2] | 0; + c[a2 >> 2] = 12; + L3 = 0; + return L3 | 0; + } + function Zb(a2) { + a2 = a2 | 0; + var b3 = 0, d2 = 0, e2 = 0, f2 = 0, g3 = 0, h2 = 0, i2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0, q2 = 0, r2 = 0, s2 = 0, t3 = 0, u3 = 0; + if (!a2) return; + b3 = a2 + -8 | 0; + i2 = c[5151] | 0; + if (b3 >>> 0 < i2 >>> 0) ha2(); + d2 = c[a2 + -4 >> 2] | 0; + e2 = d2 & 3; + if ((e2 | 0) == 1) ha2(); + o2 = d2 & -8; + q2 = a2 + (o2 + -8) | 0; + do + if (!(d2 & 1)) { + b3 = c[b3 >> 2] | 0; + if (!e2) return; + j2 = -8 - b3 | 0; + l2 = a2 + j2 | 0; + m3 = b3 + o2 | 0; + if (l2 >>> 0 < i2 >>> 0) ha2(); + if ((l2 | 0) == (c[5152] | 0)) { + b3 = a2 + (o2 + -4) | 0; + d2 = c[b3 >> 2] | 0; + if ((d2 & 3 | 0) != 3) { + u3 = l2; + g3 = m3; + break; + } + c[5149] = m3; + c[b3 >> 2] = d2 & -2; + c[a2 + (j2 + 4) >> 2] = m3 | 1; + c[q2 >> 2] = m3; + return; + } + f2 = b3 >>> 3; + if (b3 >>> 0 < 256) { + e2 = c[a2 + (j2 + 8) >> 2] | 0; + d2 = c[a2 + (j2 + 12) >> 2] | 0; + b3 = 20628 + (f2 << 1 << 2) | 0; + if ((e2 | 0) != (b3 | 0)) { + if (e2 >>> 0 < i2 >>> 0) ha2(); + if ((c[e2 + 12 >> 2] | 0) != (l2 | 0)) ha2(); + } + if ((d2 | 0) == (e2 | 0)) { + c[5147] = c[5147] & ~(1 << f2); + u3 = l2; + g3 = m3; + break; + } + if ((d2 | 0) != (b3 | 0)) { + if (d2 >>> 0 < i2 >>> 0) ha2(); + b3 = d2 + 8 | 0; + if ((c[b3 >> 2] | 0) == (l2 | 0)) h2 = b3; + else ha2(); + } else h2 = d2 + 8 | 0; + c[e2 + 12 >> 2] = d2; + c[h2 >> 2] = e2; + u3 = l2; + g3 = m3; + break; + } + h2 = c[a2 + (j2 + 24) >> 2] | 0; + e2 = c[a2 + (j2 + 12) >> 2] | 0; + do + if ((e2 | 0) == (l2 | 0)) { + d2 = a2 + (j2 + 20) | 0; + b3 = c[d2 >> 2] | 0; + if (!b3) { + d2 = a2 + (j2 + 16) | 0; + b3 = c[d2 >> 2] | 0; + if (!b3) { + k2 = 0; + break; + } + } + while (1) { + e2 = b3 + 20 | 0; + f2 = c[e2 >> 2] | 0; + if (f2) { + b3 = f2; + d2 = e2; + continue; + } + e2 = b3 + 16 | 0; + f2 = c[e2 >> 2] | 0; + if (!f2) break; + else { + b3 = f2; + d2 = e2; + } + } + if (d2 >>> 0 < i2 >>> 0) ha2(); + else { + c[d2 >> 2] = 0; + k2 = b3; + break; + } + } else { + f2 = c[a2 + (j2 + 8) >> 2] | 0; + if (f2 >>> 0 < i2 >>> 0) ha2(); + b3 = f2 + 12 | 0; + if ((c[b3 >> 2] | 0) != (l2 | 0)) ha2(); + d2 = e2 + 8 | 0; + if ((c[d2 >> 2] | 0) == (l2 | 0)) { + c[b3 >> 2] = e2; + c[d2 >> 2] = f2; + k2 = e2; + break; + } else ha2(); + } + while (0); + if (h2) { + b3 = c[a2 + (j2 + 28) >> 2] | 0; + d2 = 20892 + (b3 << 2) | 0; + if ((l2 | 0) == (c[d2 >> 2] | 0)) { + c[d2 >> 2] = k2; + if (!k2) { + c[5148] = c[5148] & ~(1 << b3); + u3 = l2; + g3 = m3; + break; + } + } else { + if (h2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + b3 = h2 + 16 | 0; + if ((c[b3 >> 2] | 0) == (l2 | 0)) c[b3 >> 2] = k2; + else c[h2 + 20 >> 2] = k2; + if (!k2) { + u3 = l2; + g3 = m3; + break; + } + } + d2 = c[5151] | 0; + if (k2 >>> 0 < d2 >>> 0) ha2(); + c[k2 + 24 >> 2] = h2; + b3 = c[a2 + (j2 + 16) >> 2] | 0; + do + if (b3) if (b3 >>> 0 < d2 >>> 0) ha2(); + else { + c[k2 + 16 >> 2] = b3; + c[b3 + 24 >> 2] = k2; + break; + } + while (0); + b3 = c[a2 + (j2 + 20) >> 2] | 0; + if (b3) if (b3 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[k2 + 20 >> 2] = b3; + c[b3 + 24 >> 2] = k2; + u3 = l2; + g3 = m3; + break; + } + else { + u3 = l2; + g3 = m3; + } + } else { + u3 = l2; + g3 = m3; + } + } else { + u3 = b3; + g3 = o2; + } + while (0); + if (u3 >>> 0 >= q2 >>> 0) ha2(); + b3 = a2 + (o2 + -4) | 0; + d2 = c[b3 >> 2] | 0; + if (!(d2 & 1)) ha2(); + if (!(d2 & 2)) { + if ((q2 | 0) == (c[5153] | 0)) { + t3 = (c[5150] | 0) + g3 | 0; + c[5150] = t3; + c[5153] = u3; + c[u3 + 4 >> 2] = t3 | 1; + if ((u3 | 0) != (c[5152] | 0)) return; + c[5152] = 0; + c[5149] = 0; + return; + } + if ((q2 | 0) == (c[5152] | 0)) { + t3 = (c[5149] | 0) + g3 | 0; + c[5149] = t3; + c[5152] = u3; + c[u3 + 4 >> 2] = t3 | 1; + c[u3 + t3 >> 2] = t3; + return; + } + g3 = (d2 & -8) + g3 | 0; + f2 = d2 >>> 3; + do + if (d2 >>> 0 >= 256) { + h2 = c[a2 + (o2 + 16) >> 2] | 0; + b3 = c[a2 + (o2 | 4) >> 2] | 0; + do + if ((b3 | 0) == (q2 | 0)) { + d2 = a2 + (o2 + 12) | 0; + b3 = c[d2 >> 2] | 0; + if (!b3) { + d2 = a2 + (o2 + 8) | 0; + b3 = c[d2 >> 2] | 0; + if (!b3) { + p2 = 0; + break; + } + } + while (1) { + e2 = b3 + 20 | 0; + f2 = c[e2 >> 2] | 0; + if (f2) { + b3 = f2; + d2 = e2; + continue; + } + e2 = b3 + 16 | 0; + f2 = c[e2 >> 2] | 0; + if (!f2) break; + else { + b3 = f2; + d2 = e2; + } + } + if (d2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[d2 >> 2] = 0; + p2 = b3; + break; + } + } else { + d2 = c[a2 + o2 >> 2] | 0; + if (d2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + e2 = d2 + 12 | 0; + if ((c[e2 >> 2] | 0) != (q2 | 0)) ha2(); + f2 = b3 + 8 | 0; + if ((c[f2 >> 2] | 0) == (q2 | 0)) { + c[e2 >> 2] = b3; + c[f2 >> 2] = d2; + p2 = b3; + break; + } else ha2(); + } + while (0); + if (h2) { + b3 = c[a2 + (o2 + 20) >> 2] | 0; + d2 = 20892 + (b3 << 2) | 0; + if ((q2 | 0) == (c[d2 >> 2] | 0)) { + c[d2 >> 2] = p2; + if (!p2) { + c[5148] = c[5148] & ~(1 << b3); + break; + } + } else { + if (h2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + b3 = h2 + 16 | 0; + if ((c[b3 >> 2] | 0) == (q2 | 0)) c[b3 >> 2] = p2; + else c[h2 + 20 >> 2] = p2; + if (!p2) break; + } + d2 = c[5151] | 0; + if (p2 >>> 0 < d2 >>> 0) ha2(); + c[p2 + 24 >> 2] = h2; + b3 = c[a2 + (o2 + 8) >> 2] | 0; + do + if (b3) if (b3 >>> 0 < d2 >>> 0) ha2(); + else { + c[p2 + 16 >> 2] = b3; + c[b3 + 24 >> 2] = p2; + break; + } + while (0); + b3 = c[a2 + (o2 + 12) >> 2] | 0; + if (b3) if (b3 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[p2 + 20 >> 2] = b3; + c[b3 + 24 >> 2] = p2; + break; + } + } + } else { + e2 = c[a2 + o2 >> 2] | 0; + d2 = c[a2 + (o2 | 4) >> 2] | 0; + b3 = 20628 + (f2 << 1 << 2) | 0; + if ((e2 | 0) != (b3 | 0)) { + if (e2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + if ((c[e2 + 12 >> 2] | 0) != (q2 | 0)) ha2(); + } + if ((d2 | 0) == (e2 | 0)) { + c[5147] = c[5147] & ~(1 << f2); + break; + } + if ((d2 | 0) != (b3 | 0)) { + if (d2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + b3 = d2 + 8 | 0; + if ((c[b3 >> 2] | 0) == (q2 | 0)) n2 = b3; + else ha2(); + } else n2 = d2 + 8 | 0; + c[e2 + 12 >> 2] = d2; + c[n2 >> 2] = e2; + } + while (0); + c[u3 + 4 >> 2] = g3 | 1; + c[u3 + g3 >> 2] = g3; + if ((u3 | 0) == (c[5152] | 0)) { + c[5149] = g3; + return; + } + } else { + c[b3 >> 2] = d2 & -2; + c[u3 + 4 >> 2] = g3 | 1; + c[u3 + g3 >> 2] = g3; + } + b3 = g3 >>> 3; + if (g3 >>> 0 < 256) { + d2 = b3 << 1; + f2 = 20628 + (d2 << 2) | 0; + e2 = c[5147] | 0; + b3 = 1 << b3; + if (e2 & b3) { + b3 = 20628 + (d2 + 2 << 2) | 0; + d2 = c[b3 >> 2] | 0; + if (d2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + r2 = b3; + s2 = d2; + } + } else { + c[5147] = e2 | b3; + r2 = 20628 + (d2 + 2 << 2) | 0; + s2 = f2; + } + c[r2 >> 2] = u3; + c[s2 + 12 >> 2] = u3; + c[u3 + 8 >> 2] = s2; + c[u3 + 12 >> 2] = f2; + return; + } + b3 = g3 >>> 8; + if (b3) if (g3 >>> 0 > 16777215) f2 = 31; + else { + r2 = (b3 + 1048320 | 0) >>> 16 & 8; + s2 = b3 << r2; + q2 = (s2 + 520192 | 0) >>> 16 & 4; + s2 = s2 << q2; + f2 = (s2 + 245760 | 0) >>> 16 & 2; + f2 = 14 - (q2 | r2 | f2) + (s2 << f2 >>> 15) | 0; + f2 = g3 >>> (f2 + 7 | 0) & 1 | f2 << 1; + } + else f2 = 0; + b3 = 20892 + (f2 << 2) | 0; + c[u3 + 28 >> 2] = f2; + c[u3 + 20 >> 2] = 0; + c[u3 + 16 >> 2] = 0; + d2 = c[5148] | 0; + e2 = 1 << f2; + a: do + if (d2 & e2) { + b3 = c[b3 >> 2] | 0; + b: do + if ((c[b3 + 4 >> 2] & -8 | 0) != (g3 | 0)) { + f2 = g3 << ((f2 | 0) == 31 ? 0 : 25 - (f2 >>> 1) | 0); + while (1) { + e2 = b3 + 16 + (f2 >>> 31 << 2) | 0; + d2 = c[e2 >> 2] | 0; + if (!d2) break; + if ((c[d2 + 4 >> 2] & -8 | 0) == (g3 | 0)) { + t3 = d2; + break b; + } else { + f2 = f2 << 1; + b3 = d2; + } + } + if (e2 >>> 0 < (c[5151] | 0) >>> 0) ha2(); + else { + c[e2 >> 2] = u3; + c[u3 + 24 >> 2] = b3; + c[u3 + 12 >> 2] = u3; + c[u3 + 8 >> 2] = u3; + break a; + } + } else t3 = b3; + while (0); + b3 = t3 + 8 | 0; + d2 = c[b3 >> 2] | 0; + s2 = c[5151] | 0; + if (d2 >>> 0 >= s2 >>> 0 & t3 >>> 0 >= s2 >>> 0) { + c[d2 + 12 >> 2] = u3; + c[b3 >> 2] = u3; + c[u3 + 8 >> 2] = d2; + c[u3 + 12 >> 2] = t3; + c[u3 + 24 >> 2] = 0; + break; + } else ha2(); + } else { + c[5148] = d2 | e2; + c[b3 >> 2] = u3; + c[u3 + 24 >> 2] = b3; + c[u3 + 12 >> 2] = u3; + c[u3 + 8 >> 2] = u3; + } + while (0); + u3 = (c[5155] | 0) + -1 | 0; + c[5155] = u3; + if (!u3) b3 = 21044; + else return; + while (1) { + b3 = c[b3 >> 2] | 0; + if (!b3) break; + else b3 = b3 + 8 | 0; + } + c[5155] = -1; + return; + } + function _b() { + } + function $b(a2, b3, c2, d2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + d2 = d2 | 0; + d2 = b3 - d2 - (c2 >>> 0 > a2 >>> 0 | 0) >>> 0; + return (C2 = d2, a2 - c2 >>> 0 | 0) | 0; + } + function ac(b3, d2, e2) { + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + a.fill(d2 & 255, b3, b3 + e2); + return b3 | 0; + } + function bc(a2, b3, c2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + if ((c2 | 0) < 32) { + C2 = b3 >>> c2; + return a2 >>> c2 | (b3 & (1 << c2) - 1) << 32 - c2; + } + C2 = 0; + return b3 >>> c2 - 32 | 0; + } + function cc(a2, b3, c2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + if ((c2 | 0) < 32) { + C2 = b3 << c2 | (a2 & (1 << c2) - 1 << 32 - c2) >>> 32 - c2; + return a2 << c2; + } + C2 = a2 << c2 - 32; + return 0; + } + function dc(b3, d2, e2) { + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + a.copyWithin(b3, d2, d2 + e2); + return b3 | 0; + } + function ec(a2, b3, c2, d2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + d2 = d2 | 0; + c2 = a2 + c2 >>> 0; + return (C2 = b3 + d2 + (c2 >>> 0 < a2 >>> 0 | 0) >>> 0, c2 | 0) | 0; + } + function fc(b3, c2, d2) { + b3 = b3 | 0; + c2 = c2 | 0; + d2 = d2 | 0; + a.copyWithin(b3, c2, c2 + d2); + return b3 | 0; + } + function gc(a2, b3, c2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + if ((c2 | 0) < 32) { + C2 = b3 >> c2; + return a2 >>> c2 | (b3 & (1 << c2) - 1) << 32 - c2; + } + C2 = (b3 | 0) < 0 ? -1 : 0; + return b3 >> c2 - 32 | 0; + } + function hc(b3) { + b3 = b3 | 0; + var c2 = 0; + c2 = a[m2 + (b3 & 255) >> 0] | 0; + if ((c2 | 0) < 8) return c2 | 0; + c2 = a[m2 + (b3 >> 8 & 255) >> 0] | 0; + if ((c2 | 0) < 8) return c2 + 8 | 0; + c2 = a[m2 + (b3 >> 16 & 255) >> 0] | 0; + if ((c2 | 0) < 8) return c2 + 16 | 0; + return (a[m2 + (b3 >>> 24) >> 0] | 0) + 24 | 0; + } + function ic(a2, b3) { + a2 = a2 | 0; + b3 = b3 | 0; + var c2 = 0, d2 = 0, e2 = 0, f2 = 0; + f2 = a2 & 65535; + e2 = b3 & 65535; + c2 = _(e2, f2) | 0; + d2 = a2 >>> 16; + a2 = (c2 >>> 16) + (_(e2, d2) | 0) | 0; + e2 = b3 >>> 16; + b3 = _(e2, f2) | 0; + return (C2 = (a2 >>> 16) + (_(e2, d2) | 0) + (((a2 & 65535) + b3 | 0) >>> 16) | 0, a2 + b3 << 16 | c2 & 65535 | 0) | 0; + } + function jc(a2, b3, c2, d2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + d2 = d2 | 0; + var e2 = 0, f2 = 0, g3 = 0, h2 = 0, i2 = 0, j2 = 0; + j2 = b3 >> 31 | ((b3 | 0) < 0 ? -1 : 0) << 1; + i2 = ((b3 | 0) < 0 ? -1 : 0) >> 31 | ((b3 | 0) < 0 ? -1 : 0) << 1; + f2 = d2 >> 31 | ((d2 | 0) < 0 ? -1 : 0) << 1; + e2 = ((d2 | 0) < 0 ? -1 : 0) >> 31 | ((d2 | 0) < 0 ? -1 : 0) << 1; + h2 = $b(j2 ^ a2, i2 ^ b3, j2, i2) | 0; + g3 = C2; + a2 = f2 ^ j2; + b3 = e2 ^ i2; + return $b((oc(h2, g3, $b(f2 ^ c2, e2 ^ d2, f2, e2) | 0, C2, 0) | 0) ^ a2, C2 ^ b3, a2, b3) | 0; + } + function kc(a2, b3, d2, e2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + var f2 = 0, g3 = 0, h2 = 0, j2 = 0, k2 = 0, l2 = 0; + f2 = i; + i = i + 16 | 0; + j2 = f2 | 0; + h2 = b3 >> 31 | ((b3 | 0) < 0 ? -1 : 0) << 1; + g3 = ((b3 | 0) < 0 ? -1 : 0) >> 31 | ((b3 | 0) < 0 ? -1 : 0) << 1; + l2 = e2 >> 31 | ((e2 | 0) < 0 ? -1 : 0) << 1; + k2 = ((e2 | 0) < 0 ? -1 : 0) >> 31 | ((e2 | 0) < 0 ? -1 : 0) << 1; + a2 = $b(h2 ^ a2, g3 ^ b3, h2, g3) | 0; + b3 = C2; + oc(a2, b3, $b(l2 ^ d2, k2 ^ e2, l2, k2) | 0, C2, j2) | 0; + e2 = $b(c[j2 >> 2] ^ h2, c[j2 + 4 >> 2] ^ g3, h2, g3) | 0; + d2 = C2; + i = f2; + return (C2 = d2, e2) | 0; + } + function lc(a2, b3, c2, d2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + d2 = d2 | 0; + var e2 = 0, f2 = 0; + e2 = a2; + f2 = c2; + c2 = ic(e2, f2) | 0; + a2 = C2; + return (C2 = (_(b3, f2) | 0) + (_(d2, e2) | 0) + a2 | a2 & 0, c2 | 0 | 0) | 0; + } + function mc(a2, b3, c2, d2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + d2 = d2 | 0; + return oc(a2, b3, c2, d2, 0) | 0; + } + function nc(a2, b3, d2, e2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + var f2 = 0, g3 = 0; + g3 = i; + i = i + 16 | 0; + f2 = g3 | 0; + oc(a2, b3, d2, e2, f2) | 0; + i = g3; + return (C2 = c[f2 + 4 >> 2] | 0, c[f2 >> 2] | 0) | 0; + } + function oc(a2, b3, d2, e2, f2) { + a2 = a2 | 0; + b3 = b3 | 0; + d2 = d2 | 0; + e2 = e2 | 0; + f2 = f2 | 0; + var g3 = 0, h2 = 0, i2 = 0, j2 = 0, k2 = 0, l2 = 0, m3 = 0, n2 = 0, o2 = 0, p2 = 0; + l2 = a2; + j2 = b3; + k2 = j2; + h2 = d2; + n2 = e2; + i2 = n2; + if (!k2) { + g3 = (f2 | 0) != 0; + if (!i2) { + if (g3) { + c[f2 >> 2] = (l2 >>> 0) % (h2 >>> 0); + c[f2 + 4 >> 2] = 0; + } + n2 = 0; + f2 = (l2 >>> 0) / (h2 >>> 0) >>> 0; + return (C2 = n2, f2) | 0; + } else { + if (!g3) { + n2 = 0; + f2 = 0; + return (C2 = n2, f2) | 0; + } + c[f2 >> 2] = a2 | 0; + c[f2 + 4 >> 2] = b3 & 0; + n2 = 0; + f2 = 0; + return (C2 = n2, f2) | 0; + } + } + g3 = (i2 | 0) == 0; + do + if (h2) { + if (!g3) { + g3 = (aa(i2 | 0) | 0) - (aa(k2 | 0) | 0) | 0; + if (g3 >>> 0 <= 31) { + m3 = g3 + 1 | 0; + i2 = 31 - g3 | 0; + b3 = g3 - 31 >> 31; + h2 = m3; + a2 = l2 >>> (m3 >>> 0) & b3 | k2 << i2; + b3 = k2 >>> (m3 >>> 0) & b3; + g3 = 0; + i2 = l2 << i2; + break; + } + if (!f2) { + n2 = 0; + f2 = 0; + return (C2 = n2, f2) | 0; + } + c[f2 >> 2] = a2 | 0; + c[f2 + 4 >> 2] = j2 | b3 & 0; + n2 = 0; + f2 = 0; + return (C2 = n2, f2) | 0; + } + g3 = h2 - 1 | 0; + if (g3 & h2) { + i2 = (aa(h2 | 0) | 0) + 33 - (aa(k2 | 0) | 0) | 0; + p2 = 64 - i2 | 0; + m3 = 32 - i2 | 0; + j2 = m3 >> 31; + o2 = i2 - 32 | 0; + b3 = o2 >> 31; + h2 = i2; + a2 = m3 - 1 >> 31 & k2 >>> (o2 >>> 0) | (k2 << m3 | l2 >>> (i2 >>> 0)) & b3; + b3 = b3 & k2 >>> (i2 >>> 0); + g3 = l2 << p2 & j2; + i2 = (k2 << p2 | l2 >>> (o2 >>> 0)) & j2 | l2 << m3 & i2 - 33 >> 31; + break; + } + if (f2) { + c[f2 >> 2] = g3 & l2; + c[f2 + 4 >> 2] = 0; + } + if ((h2 | 0) == 1) { + o2 = j2 | b3 & 0; + p2 = a2 | 0 | 0; + return (C2 = o2, p2) | 0; + } else { + p2 = hc(h2 | 0) | 0; + o2 = k2 >>> (p2 >>> 0) | 0; + p2 = k2 << 32 - p2 | l2 >>> (p2 >>> 0) | 0; + return (C2 = o2, p2) | 0; + } + } else { + if (g3) { + if (f2) { + c[f2 >> 2] = (k2 >>> 0) % (h2 >>> 0); + c[f2 + 4 >> 2] = 0; + } + o2 = 0; + p2 = (k2 >>> 0) / (h2 >>> 0) >>> 0; + return (C2 = o2, p2) | 0; + } + if (!l2) { + if (f2) { + c[f2 >> 2] = 0; + c[f2 + 4 >> 2] = (k2 >>> 0) % (i2 >>> 0); + } + o2 = 0; + p2 = (k2 >>> 0) / (i2 >>> 0) >>> 0; + return (C2 = o2, p2) | 0; + } + g3 = i2 - 1 | 0; + if (!(g3 & i2)) { + if (f2) { + c[f2 >> 2] = a2 | 0; + c[f2 + 4 >> 2] = g3 & k2 | b3 & 0; + } + o2 = 0; + p2 = k2 >>> ((hc(i2 | 0) | 0) >>> 0); + return (C2 = o2, p2) | 0; + } + g3 = (aa(i2 | 0) | 0) - (aa(k2 | 0) | 0) | 0; + if (g3 >>> 0 <= 30) { + b3 = g3 + 1 | 0; + i2 = 31 - g3 | 0; + h2 = b3; + a2 = k2 << i2 | l2 >>> (b3 >>> 0); + b3 = k2 >>> (b3 >>> 0); + g3 = 0; + i2 = l2 << i2; + break; + } + if (!f2) { + o2 = 0; + p2 = 0; + return (C2 = o2, p2) | 0; + } + c[f2 >> 2] = a2 | 0; + c[f2 + 4 >> 2] = j2 | b3 & 0; + o2 = 0; + p2 = 0; + return (C2 = o2, p2) | 0; + } + while (0); + if (!h2) { + k2 = i2; + j2 = 0; + i2 = 0; + } else { + m3 = d2 | 0 | 0; + l2 = n2 | e2 & 0; + k2 = ec(m3 | 0, l2 | 0, -1, -1) | 0; + d2 = C2; + j2 = i2; + i2 = 0; + do { + e2 = j2; + j2 = g3 >>> 31 | j2 << 1; + g3 = i2 | g3 << 1; + e2 = a2 << 1 | e2 >>> 31 | 0; + n2 = a2 >>> 31 | b3 << 1 | 0; + $b(k2, d2, e2, n2) | 0; + p2 = C2; + o2 = p2 >> 31 | ((p2 | 0) < 0 ? -1 : 0) << 1; + i2 = o2 & 1; + a2 = $b(e2, n2, o2 & m3, (((p2 | 0) < 0 ? -1 : 0) >> 31 | ((p2 | 0) < 0 ? -1 : 0) << 1) & l2) | 0; + b3 = C2; + h2 = h2 - 1 | 0; + } while ((h2 | 0) != 0); + k2 = j2; + j2 = 0; + } + h2 = 0; + if (f2) { + c[f2 >> 2] = a2; + c[f2 + 4 >> 2] = b3; + } + o2 = (g3 | 0) >>> 31 | (k2 | h2) << 1 | (h2 << 1 | g3 >>> 31) & 0 | j2; + p2 = (g3 << 1 | 0 >>> 31) & -2 | i2; + return (C2 = o2, p2) | 0; + } + function pc(a2, b3, c2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + ra2[a2 & 1](b3 | 0, c2 | 0); + } + function qc(a2, b3, c2) { + a2 = a2 | 0; + b3 = b3 | 0; + c2 = c2 | 0; + return sa2[a2 & 1](b3 | 0, c2 | 0) | 0; + } + function rc(a2, b3) { + a2 = a2 | 0; + b3 = b3 | 0; + ba(0); + } + function sc(a2, b3) { + a2 = a2 | 0; + b3 = b3 | 0; + ba(1); + return 0; + } + var ra2 = [rc, Mb]; + var sa2 = [sc, Lb]; + return { _i64Subtract: $b, _free: Zb, _i64Add: ec, _memmove: fc, _memset: ac, _malloc: Yb, _encode: Ca2, _memcpy: dc, _bitshift64Lshr: bc, _bitshift64Shl: cc, runPostSets: _b, stackAlloc: ta2, stackSave: ua2, stackRestore: va2, establishStackSpace: wa2, setThrew: xa2, setTempRet0: Aa2, getTempRet0: Ba2, dynCall_vii: pc, dynCall_iii: qc }; + })(b.I, b.J, buffer); + var Ja = b._i64Subtract = Y._i64Subtract; + var pa = b._free = Y._free; + b.runPostSets = Y.runPostSets; + var Pa = b._i64Add = Y._i64Add; + var Qa = b._memmove = Y._memmove; + var La = b._memset = Y._memset; + var ia = b._malloc = Y._malloc; + b._encode = Y._encode; + var Oa = b._memcpy = Y._memcpy; + var Ma = b._bitshift64Lshr = Y._bitshift64Lshr; + var Na = b._bitshift64Shl = Y._bitshift64Shl; + b.dynCall_vii = Y.dynCall_vii; + b.dynCall_iii = Y.dynCall_iii; + A.n = Y.stackAlloc; + A.G = Y.stackSave; + A.F = Y.stackRestore; + A.W = Y.establishStackSpace; + A.P = Y.setTempRet0; + A.N = Y.getTempRet0; + if (W) if ("function" === typeof b.locateFile ? W = b.locateFile(W) : b.memoryInitializerPrefixURL && (W = b.memoryInitializerPrefixURL + W), v || x) { + Ta = b.readBinary(W); + P.set(Ta, A.C); + } else { + Va = function() { + Browser.T(W, Ua, function() { + throw "could not load memory initializer " + W; + }); + }; + U++; + b.monitorRunDependencies && b.monitorRunDependencies(U); + Ua = function(a) { + a.byteLength && (a = new Uint8Array(a)); + P.set(a, A.C); + U--; + b.monitorRunDependencies && b.monitorRunDependencies(U); + 0 == U && (null !== Ha && (clearInterval(Ha), Ha = null), V && (a = V, V = null, a())); + }, Z = b.memoryInitializerRequest; + if (Z) { + Wa = function() { + 200 !== Z.status && 0 !== Z.status ? (console.warn("a problem seems to have happened with Module.memoryInitializerRequest, status: " + Z.status + ", retrying " + W), Va()) : Ua(Z.response); + }; + Z.response ? setTimeout(Wa, 0) : Z.addEventListener("load", Wa); + } else Va(); + } + var Ta; + var Va; + var Ua; + var Z; + var Wa; + function y(a) { + this.name = "ExitStatus"; + this.message = "Program terminated with exit(" + a + ")"; + this.status = a; + } + y.prototype = Error(); + y.prototype.constructor = y; + var Xa = null; + var V = function Ya() { + b.calledRun || Za(); + b.calledRun || (V = Ya); + }; + b.callMain = b.U = function(a) { + function c() { + for (var a2 = 0; 3 > a2; a2++) e.push(0); + } + assert(0 == U, "cannot call main when async dependencies remain! (listen on __ATMAIN__)"); + assert(0 == Aa.length, "cannot call main when preRun functions remain to be called"); + a = a || []; + T || (T = true, S(Ba)); + var d = a.length + 1, e = [O(Ga(b.thisProgram), "i8", 0)]; + c(); + for (var h = 0; h < d - 1; h += 1) e.push(O(Ga(a[h]), "i8", 0)), c(); + e.push(0); + e = O(e, "i32", 0); + try { + var l = b._main(d, e, 0); + $a(l, true); + } catch (k) { + if (!(k instanceof y)) if ("SimulateInfiniteLoop" == k) b.noExitRuntime = true; + else throw k && "object" === typeof k && k.stack && b.A("exception thrown: " + [k, k.stack]), k; + } finally { + } + }; + function Za(a) { + function c() { + if (!b.calledRun && (b.calledRun = true, !F)) { + T || (T = true, S(Ba)); + S(Ca); + if (b.onRuntimeInitialized) b.onRuntimeInitialized(); + b._main && ab && b.callMain(a); + if (b.postRun) for ("function" == typeof b.postRun && (b.postRun = [b.postRun]); b.postRun.length; ) { + var c2 = b.postRun.shift(); + Ea.unshift(c2); + } + S(Ea); + } + } + a = a || b.arguments; + null === Xa && (Xa = Date.now()); + if (!(0 < U)) { + if (b.preRun) for ("function" == typeof b.preRun && (b.preRun = [b.preRun]); b.preRun.length; ) Fa(); + S(Aa); + 0 < U || b.calledRun || (b.setStatus ? (b.setStatus("Running..."), setTimeout(function() { + setTimeout(function() { + b.setStatus(""); + }, 1); + c(); + }, 1)) : c()); + } + } + b.run = b.run = Za; + function $a(a, c) { + if (!c || !b.noExitRuntime) { + if (!b.noExitRuntime && (F = true, z = void 0, S(Da), b.onExit)) b.onExit(a); + v ? (process.stdout.once("drain", function() { + process.exit(a); + }), console.log(" "), setTimeout(function() { + process.exit(a); + }, 500)) : x && "function" === typeof quit && quit(a); + throw new y(a); + } + } + b.exit = b.exit = $a; + var bb = []; + function E(a) { + void 0 !== a ? (b.print(a), b.A(a), a = JSON.stringify(a)) : a = ""; + F = true; + var c = "abort(" + a + ") at " + qa() + "\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information."; + bb && bb.forEach(function(d) { + c = d(c, a); + }); + throw c; + } + b.abort = b.abort = E; + if (b.preInit) for ("function" == typeof b.preInit && (b.preInit = [b.preInit]); 0 < b.preInit.length; ) b.preInit.pop()(); + var ab = true; + b.noInitialRun && (ab = false); + Za(); + } +}); + +// brotli-encoder-entry.cjs +var encoder = require_encode(); +module.exports = function compress(bytes, options = {}) { + const input = encoder._malloc(Math.max(bytes.length, 1)); + const capacity = bytes.length + 1024; + const output = encoder._malloc(capacity); + try { + encoder.HEAPU8.set(bytes, input); + const length = encoder._encode(options.quality ?? 11, options.lgwin ?? 22, options.mode ?? 0, bytes.length, input, capacity, output); + if (length === -1) throw new Error("Brotli compression failed"); + return encoder.HEAPU8.slice(output, output + length); + } finally { + encoder._free(input); + encoder._free(output); + } +}; diff --git a/src/Node/Lib/buffer.cjs b/src/Node/Lib/buffer.cjs new file mode 100644 index 00000000..a462b3e5 --- /dev/null +++ b/src/Node/Lib/buffer.cjs @@ -0,0 +1,1804 @@ +// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt. +"use strict"; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + try { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + } catch (e) { + throw mod = 0, e; + } +}; + +// node_modules/base64-js/index.js +var require_base64_js = __commonJS({ + "node_modules/base64-js/index.js"(exports2) { + "use strict"; + exports2.byteLength = byteLength2; + exports2.toByteArray = toByteArray; + exports2.fromByteArray = fromByteArray; + var lookup = []; + var revLookup = []; + var Arr = typeof Uint8Array !== "undefined" ? Uint8Array : Array; + var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + for (i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i]; + revLookup[code.charCodeAt(i)] = i; + } + var i; + var len; + revLookup["-".charCodeAt(0)] = 62; + revLookup["_".charCodeAt(0)] = 63; + function getLens(b64) { + var len2 = b64.length; + if (len2 % 4 > 0) { + throw new Error("Invalid string. Length must be a multiple of 4"); + } + var validLen = b64.indexOf("="); + if (validLen === -1) validLen = len2; + var placeHoldersLen = validLen === len2 ? 0 : 4 - validLen % 4; + return [validLen, placeHoldersLen]; + } + function byteLength2(b64) { + var lens = getLens(b64); + var validLen = lens[0]; + var placeHoldersLen = lens[1]; + return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen; + } + function _byteLength(b64, validLen, placeHoldersLen) { + return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen; + } + function toByteArray(b64) { + var tmp; + var lens = getLens(b64); + var validLen = lens[0]; + var placeHoldersLen = lens[1]; + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)); + var curByte = 0; + var len2 = placeHoldersLen > 0 ? validLen - 4 : validLen; + var i2; + for (i2 = 0; i2 < len2; i2 += 4) { + tmp = revLookup[b64.charCodeAt(i2)] << 18 | revLookup[b64.charCodeAt(i2 + 1)] << 12 | revLookup[b64.charCodeAt(i2 + 2)] << 6 | revLookup[b64.charCodeAt(i2 + 3)]; + arr[curByte++] = tmp >> 16 & 255; + arr[curByte++] = tmp >> 8 & 255; + arr[curByte++] = tmp & 255; + } + if (placeHoldersLen === 2) { + tmp = revLookup[b64.charCodeAt(i2)] << 2 | revLookup[b64.charCodeAt(i2 + 1)] >> 4; + arr[curByte++] = tmp & 255; + } + if (placeHoldersLen === 1) { + tmp = revLookup[b64.charCodeAt(i2)] << 10 | revLookup[b64.charCodeAt(i2 + 1)] << 4 | revLookup[b64.charCodeAt(i2 + 2)] >> 2; + arr[curByte++] = tmp >> 8 & 255; + arr[curByte++] = tmp & 255; + } + return arr; + } + function tripletToBase64(num) { + return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63]; + } + function encodeChunk(uint8, start, end) { + var tmp; + var output = []; + for (var i2 = start; i2 < end; i2 += 3) { + tmp = (uint8[i2] << 16 & 16711680) + (uint8[i2 + 1] << 8 & 65280) + (uint8[i2 + 2] & 255); + output.push(tripletToBase64(tmp)); + } + return output.join(""); + } + function fromByteArray(uint8) { + var tmp; + var len2 = uint8.length; + var extraBytes = len2 % 3; + var parts = []; + var maxChunkLength = 16383; + for (var i2 = 0, len22 = len2 - extraBytes; i2 < len22; i2 += maxChunkLength) { + parts.push(encodeChunk(uint8, i2, i2 + maxChunkLength > len22 ? len22 : i2 + maxChunkLength)); + } + if (extraBytes === 1) { + tmp = uint8[len2 - 1]; + parts.push( + lookup[tmp >> 2] + lookup[tmp << 4 & 63] + "==" + ); + } else if (extraBytes === 2) { + tmp = (uint8[len2 - 2] << 8) + uint8[len2 - 1]; + parts.push( + lookup[tmp >> 10] + lookup[tmp >> 4 & 63] + lookup[tmp << 2 & 63] + "=" + ); + } + return parts.join(""); + } + } +}); + +// node_modules/ieee754/index.js +var require_ieee754 = __commonJS({ + "node_modules/ieee754/index.js"(exports2) { + /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ + exports2.read = function(buffer, offset, isLE, mLen, nBytes) { + var e, m; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var nBits = -7; + var i = isLE ? nBytes - 1 : 0; + var d = isLE ? -1 : 1; + var s = buffer[offset + i]; + i += d; + e = s & (1 << -nBits) - 1; + s >>= -nBits; + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) { + } + m = e & (1 << -nBits) - 1; + e >>= -nBits; + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) { + } + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : (s ? -1 : 1) * Infinity; + } else { + m = m + Math.pow(2, mLen); + e = e - eBias; + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen); + }; + exports2.write = function(buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0; + var i = isLE ? 0 : nBytes - 1; + var d = isLE ? 1 : -1; + var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0; + value = Math.abs(value); + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e + eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } + for (; mLen >= 8; buffer[offset + i] = m & 255, i += d, m /= 256, mLen -= 8) { + } + e = e << mLen | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 255, i += d, e /= 256, eLen -= 8) { + } + buffer[offset + i - d] |= s * 128; + }; + } +}); + +// node_modules/buffer/index.js +var require_buffer = __commonJS({ + "node_modules/buffer/index.js"(exports2) { + "use strict"; + /*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ + var base64 = require_base64_js(); + var ieee754 = require_ieee754(); + var customInspectSymbol = typeof Symbol === "function" && typeof Symbol["for"] === "function" ? Symbol["for"]("nodejs.util.inspect.custom") : null; + exports2.Buffer = Buffer3; + exports2.SlowBuffer = SlowBuffer; + exports2.INSPECT_MAX_BYTES = 50; + var K_MAX_LENGTH = 2147483647; + exports2.kMaxLength = K_MAX_LENGTH; + Buffer3.TYPED_ARRAY_SUPPORT = typedArraySupport(); + if (!Buffer3.TYPED_ARRAY_SUPPORT && typeof console !== "undefined" && typeof console.error === "function") { + console.error( + "This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support." + ); + } + function typedArraySupport() { + try { + const arr = new Uint8Array(1); + const proto = { foo: function() { + return 42; + } }; + Object.setPrototypeOf(proto, Uint8Array.prototype); + Object.setPrototypeOf(arr, proto); + return arr.foo() === 42; + } catch (e) { + return false; + } + } + Object.defineProperty(Buffer3.prototype, "parent", { + enumerable: true, + get: function() { + if (!Buffer3.isBuffer(this)) return void 0; + return this.buffer; + } + }); + Object.defineProperty(Buffer3.prototype, "offset", { + enumerable: true, + get: function() { + if (!Buffer3.isBuffer(this)) return void 0; + return this.byteOffset; + } + }); + function createBuffer(length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"'); + } + const buf = new Uint8Array(length); + Object.setPrototypeOf(buf, Buffer3.prototype); + return buf; + } + function Buffer3(arg, encodingOrOffset, length) { + if (typeof arg === "number") { + if (typeof encodingOrOffset === "string") { + throw new TypeError( + 'The "string" argument must be of type string. Received type number' + ); + } + return allocUnsafe(arg); + } + return from2(arg, encodingOrOffset, length); + } + Buffer3.poolSize = 8192; + function from2(value, encodingOrOffset, length) { + if (typeof value === "string") { + return fromString(value, encodingOrOffset); + } + if (ArrayBuffer.isView(value)) { + return fromArrayView(value); + } + if (value == null) { + throw new TypeError( + "The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type " + typeof value + ); + } + if (isInstance(value, ArrayBuffer) || value && isInstance(value.buffer, ArrayBuffer)) { + return fromArrayBuffer(value, encodingOrOffset, length); + } + if (typeof SharedArrayBuffer !== "undefined" && (isInstance(value, SharedArrayBuffer) || value && isInstance(value.buffer, SharedArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length); + } + if (typeof value === "number") { + throw new TypeError( + 'The "value" argument must not be of type number. Received type number' + ); + } + const valueOf = value.valueOf && value.valueOf(); + if (valueOf != null && valueOf !== value) { + return Buffer3.from(valueOf, encodingOrOffset, length); + } + const b = fromObject(value); + if (b) return b; + if (typeof Symbol !== "undefined" && Symbol.toPrimitive != null && typeof value[Symbol.toPrimitive] === "function") { + return Buffer3.from(value[Symbol.toPrimitive]("string"), encodingOrOffset, length); + } + throw new TypeError( + "The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type " + typeof value + ); + } + Buffer3.from = function(value, encodingOrOffset, length) { + return from2(value, encodingOrOffset, length); + }; + Object.setPrototypeOf(Buffer3.prototype, Uint8Array.prototype); + Object.setPrototypeOf(Buffer3, Uint8Array); + function assertSize(size) { + if (typeof size !== "number") { + throw new TypeError('"size" argument must be of type number'); + } else if (size < 0) { + throw new RangeError('The value "' + size + '" is invalid for option "size"'); + } + } + function alloc(size, fill, encoding) { + assertSize(size); + if (size <= 0) { + return createBuffer(size); + } + if (fill !== void 0) { + return typeof encoding === "string" ? createBuffer(size).fill(fill, encoding) : createBuffer(size).fill(fill); + } + return createBuffer(size); + } + Buffer3.alloc = function(size, fill, encoding) { + return alloc(size, fill, encoding); + }; + function allocUnsafe(size) { + assertSize(size); + return createBuffer(size < 0 ? 0 : checked(size) | 0); + } + Buffer3.allocUnsafe = function(size) { + return allocUnsafe(size); + }; + Buffer3.allocUnsafeSlow = function(size) { + return allocUnsafe(size); + }; + function fromString(string, encoding) { + if (typeof encoding !== "string" || encoding === "") { + encoding = "utf8"; + } + if (!Buffer3.isEncoding(encoding)) { + throw new TypeError("Unknown encoding: " + encoding); + } + const length = byteLength2(string, encoding) | 0; + let buf = createBuffer(length); + const actual = buf.write(string, encoding); + if (actual !== length) { + buf = buf.slice(0, actual); + } + return buf; + } + function fromArrayLike(array) { + const length = array.length < 0 ? 0 : checked(array.length) | 0; + const buf = createBuffer(length); + for (let i = 0; i < length; i += 1) { + buf[i] = array[i] & 255; + } + return buf; + } + function fromArrayView(arrayView) { + if (isInstance(arrayView, Uint8Array)) { + const copy = new Uint8Array(arrayView); + return fromArrayBuffer(copy.buffer, copy.byteOffset, copy.byteLength); + } + return fromArrayLike(arrayView); + } + function fromArrayBuffer(array, byteOffset, length) { + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('"offset" is outside of buffer bounds'); + } + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('"length" is outside of buffer bounds'); + } + let buf; + if (byteOffset === void 0 && length === void 0) { + buf = new Uint8Array(array); + } else if (length === void 0) { + buf = new Uint8Array(array, byteOffset); + } else { + buf = new Uint8Array(array, byteOffset, length); + } + Object.setPrototypeOf(buf, Buffer3.prototype); + return buf; + } + function fromObject(obj) { + if (Buffer3.isBuffer(obj)) { + const len = checked(obj.length) | 0; + const buf = createBuffer(len); + if (buf.length === 0) { + return buf; + } + obj.copy(buf, 0, 0, len); + return buf; + } + if (obj.length !== void 0) { + if (typeof obj.length !== "number" || numberIsNaN(obj.length)) { + return createBuffer(0); + } + return fromArrayLike(obj); + } + if (obj.type === "Buffer" && Array.isArray(obj.data)) { + return fromArrayLike(obj.data); + } + } + function checked(length) { + if (length >= K_MAX_LENGTH) { + throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x" + K_MAX_LENGTH.toString(16) + " bytes"); + } + return length | 0; + } + function SlowBuffer(length) { + if (+length != length) { + length = 0; + } + return Buffer3.alloc(+length); + } + Buffer3.isBuffer = function isBuffer(b) { + return b != null && b._isBuffer === true && b !== Buffer3.prototype; + }; + Buffer3.compare = function compare(a, b) { + if (isInstance(a, Uint8Array)) a = Buffer3.from(a, a.offset, a.byteLength); + if (isInstance(b, Uint8Array)) b = Buffer3.from(b, b.offset, b.byteLength); + if (!Buffer3.isBuffer(a) || !Buffer3.isBuffer(b)) { + throw new TypeError( + 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' + ); + } + if (a === b) return 0; + let x = a.length; + let y = b.length; + for (let i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break; + } + } + if (x < y) return -1; + if (y < x) return 1; + return 0; + }; + Buffer3.isEncoding = function isEncoding2(encoding) { + switch (String(encoding).toLowerCase()) { + case "hex": + case "utf8": + case "utf-8": + case "ascii": + case "latin1": + case "binary": + case "base64": + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + return true; + default: + return false; + } + }; + Buffer3.concat = function concat(list, length) { + if (!Array.isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers'); + } + if (list.length === 0) { + return Buffer3.alloc(0); + } + let i; + if (length === void 0) { + length = 0; + for (i = 0; i < list.length; ++i) { + length += list[i].length; + } + } + const buffer = Buffer3.allocUnsafe(length); + let pos = 0; + for (i = 0; i < list.length; ++i) { + let buf = list[i]; + if (isInstance(buf, Uint8Array)) { + if (pos + buf.length > buffer.length) { + if (!Buffer3.isBuffer(buf)) buf = Buffer3.from(buf); + buf.copy(buffer, pos); + } else { + Uint8Array.prototype.set.call( + buffer, + buf, + pos + ); + } + } else if (!Buffer3.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers'); + } else { + buf.copy(buffer, pos); + } + pos += buf.length; + } + return buffer; + }; + function byteLength2(string, encoding) { + if (Buffer3.isBuffer(string)) { + return string.length; + } + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { + return string.byteLength; + } + if (typeof string !== "string") { + throw new TypeError( + 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type ' + typeof string + ); + } + const len = string.length; + const mustMatch = arguments.length > 2 && arguments[2] === true; + if (!mustMatch && len === 0) return 0; + let loweredCase = false; + for (; ; ) { + switch (encoding) { + case "ascii": + case "latin1": + case "binary": + return len; + case "utf8": + case "utf-8": + return new TextEncoder().encode(string).length; + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + return len * 2; + case "hex": + return len >>> 1; + case "base64": + return base64ToBytes(string).length; + default: + if (loweredCase) { + return mustMatch ? -1 : new TextEncoder().encode(string).length; + } + encoding = ("" + encoding).toLowerCase(); + loweredCase = true; + } + } + } + Buffer3.byteLength = byteLength2; + function slowToString(encoding, start, end) { + let loweredCase = false; + if (start === void 0 || start < 0) { + start = 0; + } + if (start > this.length) { + return ""; + } + if (end === void 0 || end > this.length) { + end = this.length; + } + if (end <= 0) { + return ""; + } + end >>>= 0; + start >>>= 0; + if (end <= start) { + return ""; + } + if (!encoding) encoding = "utf8"; + while (true) { + switch (encoding) { + case "hex": + return hexSlice(this, start, end); + case "utf8": + case "utf-8": + return utf8Slice(this, start, end); + case "ascii": + return asciiSlice(this, start, end); + case "latin1": + case "binary": + return latin1Slice(this, start, end); + case "base64": + return base64Slice(this, start, end); + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + return utf16leSlice(this, start, end); + default: + if (loweredCase) throw new TypeError("Unknown encoding: " + encoding); + encoding = (encoding + "").toLowerCase(); + loweredCase = true; + } + } + } + Buffer3.prototype._isBuffer = true; + function swap(b, n, m) { + const i = b[n]; + b[n] = b[m]; + b[m] = i; + } + Buffer3.prototype.swap16 = function swap16() { + const len = this.length; + if (len % 2 !== 0) { + throw new RangeError("Buffer size must be a multiple of 16-bits"); + } + for (let i = 0; i < len; i += 2) { + swap(this, i, i + 1); + } + return this; + }; + Buffer3.prototype.swap32 = function swap32() { + const len = this.length; + if (len % 4 !== 0) { + throw new RangeError("Buffer size must be a multiple of 32-bits"); + } + for (let i = 0; i < len; i += 4) { + swap(this, i, i + 3); + swap(this, i + 1, i + 2); + } + return this; + }; + Buffer3.prototype.swap64 = function swap64() { + const len = this.length; + if (len % 8 !== 0) { + throw new RangeError("Buffer size must be a multiple of 64-bits"); + } + for (let i = 0; i < len; i += 8) { + swap(this, i, i + 7); + swap(this, i + 1, i + 6); + swap(this, i + 2, i + 5); + swap(this, i + 3, i + 4); + } + return this; + }; + Buffer3.prototype.toString = function toString2() { + const length = this.length; + if (length === 0) return ""; + if (arguments.length === 0) return utf8Slice(this, 0, length); + return slowToString.apply(this, arguments); + }; + Buffer3.prototype.toLocaleString = Buffer3.prototype.toString; + Buffer3.prototype.equals = function equals(b) { + if (!Buffer3.isBuffer(b)) throw new TypeError("Argument must be a Buffer"); + if (this === b) return true; + return Buffer3.compare(this, b) === 0; + }; + Buffer3.prototype.inspect = function inspect() { + let str = ""; + const max = exports2.INSPECT_MAX_BYTES; + str = this.toString("hex", 0, max).replace(/(.{2})/g, "$1 ").trim(); + if (this.length > max) str += " ... "; + return ""; + }; + if (customInspectSymbol) { + Buffer3.prototype[customInspectSymbol] = Buffer3.prototype.inspect; + } + Buffer3.prototype.compare = function compare(target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer3.from(target, target.offset, target.byteLength); + } + if (!Buffer3.isBuffer(target)) { + throw new TypeError( + 'The "target" argument must be one of type Buffer or Uint8Array. Received type ' + typeof target + ); + } + if (start === void 0) { + start = 0; + } + if (end === void 0) { + end = target ? target.length : 0; + } + if (thisStart === void 0) { + thisStart = 0; + } + if (thisEnd === void 0) { + thisEnd = this.length; + } + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError("out of range index"); + } + if (thisStart >= thisEnd && start >= end) { + return 0; + } + if (thisStart >= thisEnd) { + return -1; + } + if (start >= end) { + return 1; + } + start >>>= 0; + end >>>= 0; + thisStart >>>= 0; + thisEnd >>>= 0; + if (this === target) return 0; + let x = thisEnd - thisStart; + let y = end - start; + const len = Math.min(x, y); + const thisCopy = this.slice(thisStart, thisEnd); + const targetCopy = target.slice(start, end); + for (let i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i]; + y = targetCopy[i]; + break; + } + } + if (x < y) return -1; + if (y < x) return 1; + return 0; + }; + function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) { + if (buffer.length === 0) return -1; + if (typeof byteOffset === "string") { + encoding = byteOffset; + byteOffset = 0; + } else if (byteOffset > 2147483647) { + byteOffset = 2147483647; + } else if (byteOffset < -2147483648) { + byteOffset = -2147483648; + } + byteOffset = +byteOffset; + if (numberIsNaN(byteOffset)) { + byteOffset = dir ? 0 : buffer.length - 1; + } + if (byteOffset < 0) byteOffset = buffer.length + byteOffset; + if (byteOffset >= buffer.length) { + if (dir) return -1; + else byteOffset = buffer.length - 1; + } else if (byteOffset < 0) { + if (dir) byteOffset = 0; + else return -1; + } + if (typeof val === "string") { + val = Buffer3.from(val, encoding); + } + if (Buffer3.isBuffer(val)) { + if (val.length === 0) { + return -1; + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir); + } else if (typeof val === "number") { + val = val & 255; + if (typeof Uint8Array.prototype.indexOf === "function") { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset); + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset); + } + } + return arrayIndexOf(buffer, [val], byteOffset, encoding, dir); + } + throw new TypeError("val must be string, number or Buffer"); + } + function arrayIndexOf(arr, val, byteOffset, encoding, dir) { + let indexSize = 1; + let arrLength = arr.length; + let valLength = val.length; + if (encoding !== void 0) { + encoding = String(encoding).toLowerCase(); + if (encoding === "ucs2" || encoding === "ucs-2" || encoding === "utf16le" || encoding === "utf-16le") { + if (arr.length < 2 || val.length < 2) { + return -1; + } + indexSize = 2; + arrLength /= 2; + valLength /= 2; + byteOffset /= 2; + } + } + function read(buf, i2) { + if (indexSize === 1) { + return buf[i2]; + } else { + return buf.readUInt16BE(i2 * indexSize); + } + } + let i; + if (dir) { + let foundIndex = -1; + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i; + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize; + } else { + if (foundIndex !== -1) i -= i - foundIndex; + foundIndex = -1; + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength; + for (i = byteOffset; i >= 0; i--) { + let found = true; + for (let j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false; + break; + } + } + if (found) return i; + } + } + return -1; + } + Buffer3.prototype.includes = function includes(val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1; + }; + Buffer3.prototype.indexOf = function indexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true); + }; + Buffer3.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false); + }; + function hexWrite(buf, string, offset, length) { + offset = Number(offset) || 0; + const remaining = buf.length - offset; + if (!length) { + length = remaining; + } else { + length = Number(length); + if (length > remaining) { + length = remaining; + } + } + const strLen = string.length; + if (length > strLen / 2) { + length = strLen / 2; + } + let i; + for (i = 0; i < length; ++i) { + const parsed = parseInt(string.substr(i * 2, 2), 16); + if (numberIsNaN(parsed)) return i; + buf[offset + i] = parsed; + } + return i; + } + function utf8Write(buf, string, offset, length) { + return new TextEncoder().encodeInto(string, new Uint8Array(buf.buffer, buf.byteOffset + offset, length)).written; + } + function asciiWrite(buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length); + } + function base64Write(buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length); + } + function ucs2Write(buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length); + } + Buffer3.prototype.write = function write2(string, offset, length, encoding) { + if (offset === void 0) { + encoding = "utf8"; + length = this.length; + offset = 0; + } else if (length === void 0 && typeof offset === "string") { + encoding = offset; + length = this.length; + offset = 0; + } else if (isFinite(offset)) { + offset = offset >>> 0; + if (isFinite(length)) { + length = length >>> 0; + if (encoding === void 0) encoding = "utf8"; + } else { + encoding = length; + length = void 0; + } + } else { + throw new Error( + "Buffer.write(string, encoding, offset[, length]) is no longer supported" + ); + } + const remaining = this.length - offset; + if (length === void 0 || length > remaining) length = remaining; + if (string.length > 0 && (length < 0 || offset < 0) || offset > this.length) { + throw new RangeError("Attempt to write outside buffer bounds"); + } + if (!encoding) encoding = "utf8"; + let loweredCase = false; + for (; ; ) { + switch (encoding) { + case "hex": + return hexWrite(this, string, offset, length); + case "utf8": + case "utf-8": + return utf8Write(this, string, offset, length); + case "ascii": + case "latin1": + case "binary": + return asciiWrite(this, string, offset, length); + case "base64": + return base64Write(this, string, offset, length); + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + return ucs2Write(this, string, offset, length); + default: + if (loweredCase) throw new TypeError("Unknown encoding: " + encoding); + encoding = ("" + encoding).toLowerCase(); + loweredCase = true; + } + } + }; + Buffer3.prototype.toJSON = function toJSON() { + return { + type: "Buffer", + data: Array.prototype.slice.call(this._arr || this, 0) + }; + }; + function base64Slice(buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf); + } else { + return base64.fromByteArray(buf.slice(start, end)); + } + } + function utf8Slice(buf, start, end) { + end = Math.min(buf.length, end); + const res = []; + let i = start; + while (i < end) { + const firstByte = buf[i]; + let codePoint = null; + let bytesPerSequence = firstByte > 239 ? 4 : firstByte > 223 ? 3 : firstByte > 191 ? 2 : 1; + if (i + bytesPerSequence <= end) { + let secondByte, thirdByte, fourthByte, tempCodePoint; + switch (bytesPerSequence) { + case 1: + if (firstByte < 128) { + codePoint = firstByte; + } + break; + case 2: + secondByte = buf[i + 1]; + if ((secondByte & 192) === 128) { + tempCodePoint = (firstByte & 31) << 6 | secondByte & 63; + if (tempCodePoint > 127) { + codePoint = tempCodePoint; + } + } + break; + case 3: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + if ((secondByte & 192) === 128 && (thirdByte & 192) === 128) { + tempCodePoint = (firstByte & 15) << 12 | (secondByte & 63) << 6 | thirdByte & 63; + if (tempCodePoint > 2047 && (tempCodePoint < 55296 || tempCodePoint > 57343)) { + codePoint = tempCodePoint; + } + } + break; + case 4: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + fourthByte = buf[i + 3]; + if ((secondByte & 192) === 128 && (thirdByte & 192) === 128 && (fourthByte & 192) === 128) { + tempCodePoint = (firstByte & 15) << 18 | (secondByte & 63) << 12 | (thirdByte & 63) << 6 | fourthByte & 63; + if (tempCodePoint > 65535 && tempCodePoint < 1114112) { + codePoint = tempCodePoint; + } + } + } + } + if (codePoint === null) { + codePoint = 65533; + bytesPerSequence = 1; + } else if (codePoint > 65535) { + codePoint -= 65536; + res.push(codePoint >>> 10 & 1023 | 55296); + codePoint = 56320 | codePoint & 1023; + } + res.push(codePoint); + i += bytesPerSequence; + } + return decodeCodePointsArray(res); + } + var MAX_ARGUMENTS_LENGTH = 4096; + function decodeCodePointsArray(codePoints) { + const len = codePoints.length; + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints); + } + let res = ""; + let i = 0; + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ); + } + return res; + } + function asciiSlice(buf, start, end) { + let ret = ""; + end = Math.min(buf.length, end); + for (let i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 127); + } + return ret; + } + function latin1Slice(buf, start, end) { + let ret = ""; + end = Math.min(buf.length, end); + for (let i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]); + } + return ret; + } + function hexSlice(buf, start, end) { + const len = buf.length; + if (!start || start < 0) start = 0; + if (!end || end < 0 || end > len) end = len; + let out = ""; + for (let i = start; i < end; ++i) { + out += hexSliceLookupTable[buf[i]]; + } + return out; + } + function utf16leSlice(buf, start, end) { + const bytes = buf.slice(start, end); + let res = ""; + for (let i = 0; i < bytes.length - 1; i += 2) { + res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256); + } + return res; + } + Buffer3.prototype.slice = function slice(start, end) { + const len = this.length; + start = ~~start; + end = end === void 0 ? len : ~~end; + if (start < 0) { + start += len; + if (start < 0) start = 0; + } else if (start > len) { + start = len; + } + if (end < 0) { + end += len; + if (end < 0) end = 0; + } else if (end > len) { + end = len; + } + if (end < start) end = start; + const newBuf = this.subarray(start, end); + Object.setPrototypeOf(newBuf, Buffer3.prototype); + return newBuf; + }; + function checkOffset(offset, ext, length) { + if (offset % 1 !== 0 || offset < 0) throw new RangeError("offset is not uint"); + if (offset + ext > length) throw new RangeError("Trying to access beyond buffer length"); + } + Buffer3.prototype.readUintLE = Buffer3.prototype.readUIntLE = function readUIntLE(offset, byteLength3, noAssert) { + offset = offset >>> 0; + byteLength3 = byteLength3 >>> 0; + if (!noAssert) checkOffset(offset, byteLength3, this.length); + let val = this[offset]; + let mul = 1; + let i = 0; + while (++i < byteLength3 && (mul *= 256)) { + val += this[offset + i] * mul; + } + return val; + }; + Buffer3.prototype.readUintBE = Buffer3.prototype.readUIntBE = function readUIntBE(offset, byteLength3, noAssert) { + offset = offset >>> 0; + byteLength3 = byteLength3 >>> 0; + if (!noAssert) { + checkOffset(offset, byteLength3, this.length); + } + let val = this[offset + --byteLength3]; + let mul = 1; + while (byteLength3 > 0 && (mul *= 256)) { + val += this[offset + --byteLength3] * mul; + } + return val; + }; + Buffer3.prototype.readUint8 = Buffer3.prototype.readUInt8 = function readUInt8(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 1, this.length); + return this[offset]; + }; + Buffer3.prototype.readUint16LE = Buffer3.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 2, this.length); + return this[offset] | this[offset + 1] << 8; + }; + Buffer3.prototype.readUint16BE = Buffer3.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 2, this.length); + return this[offset] << 8 | this[offset + 1]; + }; + Buffer3.prototype.readUint32LE = Buffer3.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return (this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16) + this[offset + 3] * 16777216; + }; + Buffer3.prototype.readUint32BE = Buffer3.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return this[offset] * 16777216 + (this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]); + }; + Buffer3.prototype.readBigUInt64LE = defineBigIntMethod(function readBigUInt64LE(offset) { + offset = offset >>> 0; + validateNumber(offset, "offset"); + const first = this[offset]; + const last = this[offset + 7]; + if (first === void 0 || last === void 0) { + boundsError(offset, this.length - 8); + } + const lo = first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 24; + const hi = this[++offset] + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + last * 2 ** 24; + return BigInt(lo) + (BigInt(hi) << BigInt(32)); + }); + Buffer3.prototype.readBigUInt64BE = defineBigIntMethod(function readBigUInt64BE(offset) { + offset = offset >>> 0; + validateNumber(offset, "offset"); + const first = this[offset]; + const last = this[offset + 7]; + if (first === void 0 || last === void 0) { + boundsError(offset, this.length - 8); + } + const hi = first * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + this[++offset]; + const lo = this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + last; + return (BigInt(hi) << BigInt(32)) + BigInt(lo); + }); + Buffer3.prototype.readIntLE = function readIntLE(offset, byteLength3, noAssert) { + offset = offset >>> 0; + byteLength3 = byteLength3 >>> 0; + if (!noAssert) checkOffset(offset, byteLength3, this.length); + let val = this[offset]; + let mul = 1; + let i = 0; + while (++i < byteLength3 && (mul *= 256)) { + val += this[offset + i] * mul; + } + mul *= 128; + if (val >= mul) val -= Math.pow(2, 8 * byteLength3); + return val; + }; + Buffer3.prototype.readIntBE = function readIntBE(offset, byteLength3, noAssert) { + offset = offset >>> 0; + byteLength3 = byteLength3 >>> 0; + if (!noAssert) checkOffset(offset, byteLength3, this.length); + let i = byteLength3; + let mul = 1; + let val = this[offset + --i]; + while (i > 0 && (mul *= 256)) { + val += this[offset + --i] * mul; + } + mul *= 128; + if (val >= mul) val -= Math.pow(2, 8 * byteLength3); + return val; + }; + Buffer3.prototype.readInt8 = function readInt8(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 1, this.length); + if (!(this[offset] & 128)) return this[offset]; + return (255 - this[offset] + 1) * -1; + }; + Buffer3.prototype.readInt16LE = function readInt16LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 2, this.length); + const val = this[offset] | this[offset + 1] << 8; + return val & 32768 ? val | 4294901760 : val; + }; + Buffer3.prototype.readInt16BE = function readInt16BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 2, this.length); + const val = this[offset + 1] | this[offset] << 8; + return val & 32768 ? val | 4294901760 : val; + }; + Buffer3.prototype.readInt32LE = function readInt32LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16 | this[offset + 3] << 24; + }; + Buffer3.prototype.readInt32BE = function readInt32BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return this[offset] << 24 | this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]; + }; + Buffer3.prototype.readBigInt64LE = defineBigIntMethod(function readBigInt64LE(offset) { + offset = offset >>> 0; + validateNumber(offset, "offset"); + const first = this[offset]; + const last = this[offset + 7]; + if (first === void 0 || last === void 0) { + boundsError(offset, this.length - 8); + } + const val = this[offset + 4] + this[offset + 5] * 2 ** 8 + this[offset + 6] * 2 ** 16 + (last << 24); + return (BigInt(val) << BigInt(32)) + BigInt(first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 24); + }); + Buffer3.prototype.readBigInt64BE = defineBigIntMethod(function readBigInt64BE(offset) { + offset = offset >>> 0; + validateNumber(offset, "offset"); + const first = this[offset]; + const last = this[offset + 7]; + if (first === void 0 || last === void 0) { + boundsError(offset, this.length - 8); + } + const val = (first << 24) + // Overflow + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + this[++offset]; + return (BigInt(val) << BigInt(32)) + BigInt(this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + last); + }); + Buffer3.prototype.readFloatLE = function readFloatLE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return ieee754.read(this, offset, true, 23, 4); + }; + Buffer3.prototype.readFloatBE = function readFloatBE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return ieee754.read(this, offset, false, 23, 4); + }; + Buffer3.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 8, this.length); + return ieee754.read(this, offset, true, 52, 8); + }; + Buffer3.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 8, this.length); + return ieee754.read(this, offset, false, 52, 8); + }; + function checkInt(buf, value, offset, ext, max, min) { + if (!Buffer3.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance'); + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds'); + if (offset + ext > buf.length) throw new RangeError("Index out of range"); + } + Buffer3.prototype.writeUintLE = Buffer3.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength3, noAssert) { + value = +value; + offset = offset >>> 0; + byteLength3 = byteLength3 >>> 0; + if (!noAssert) { + const maxBytes = Math.pow(2, 8 * byteLength3) - 1; + checkInt(this, value, offset, byteLength3, maxBytes, 0); + } + let mul = 1; + let i = 0; + this[offset] = value & 255; + while (++i < byteLength3 && (mul *= 256)) { + this[offset + i] = value / mul & 255; + } + return offset + byteLength3; + }; + Buffer3.prototype.writeUintBE = Buffer3.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength3, noAssert) { + value = +value; + offset = offset >>> 0; + byteLength3 = byteLength3 >>> 0; + if (!noAssert) { + const maxBytes = Math.pow(2, 8 * byteLength3) - 1; + checkInt(this, value, offset, byteLength3, maxBytes, 0); + } + let i = byteLength3 - 1; + let mul = 1; + this[offset + i] = value & 255; + while (--i >= 0 && (mul *= 256)) { + this[offset + i] = value / mul & 255; + } + return offset + byteLength3; + }; + Buffer3.prototype.writeUint8 = Buffer3.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 1, 255, 0); + this[offset] = value & 255; + return offset + 1; + }; + Buffer3.prototype.writeUint16LE = Buffer3.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 2, 65535, 0); + this[offset] = value & 255; + this[offset + 1] = value >>> 8; + return offset + 2; + }; + Buffer3.prototype.writeUint16BE = Buffer3.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 2, 65535, 0); + this[offset] = value >>> 8; + this[offset + 1] = value & 255; + return offset + 2; + }; + Buffer3.prototype.writeUint32LE = Buffer3.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 4, 4294967295, 0); + this[offset + 3] = value >>> 24; + this[offset + 2] = value >>> 16; + this[offset + 1] = value >>> 8; + this[offset] = value & 255; + return offset + 4; + }; + Buffer3.prototype.writeUint32BE = Buffer3.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 4, 4294967295, 0); + this[offset] = value >>> 24; + this[offset + 1] = value >>> 16; + this[offset + 2] = value >>> 8; + this[offset + 3] = value & 255; + return offset + 4; + }; + function wrtBigUInt64LE(buf, value, offset, min, max) { + checkIntBI(value, min, max, buf, offset, 7); + let lo = Number(value & BigInt(4294967295)); + buf[offset++] = lo; + lo = lo >> 8; + buf[offset++] = lo; + lo = lo >> 8; + buf[offset++] = lo; + lo = lo >> 8; + buf[offset++] = lo; + let hi = Number(value >> BigInt(32) & BigInt(4294967295)); + buf[offset++] = hi; + hi = hi >> 8; + buf[offset++] = hi; + hi = hi >> 8; + buf[offset++] = hi; + hi = hi >> 8; + buf[offset++] = hi; + return offset; + } + function wrtBigUInt64BE(buf, value, offset, min, max) { + checkIntBI(value, min, max, buf, offset, 7); + let lo = Number(value & BigInt(4294967295)); + buf[offset + 7] = lo; + lo = lo >> 8; + buf[offset + 6] = lo; + lo = lo >> 8; + buf[offset + 5] = lo; + lo = lo >> 8; + buf[offset + 4] = lo; + let hi = Number(value >> BigInt(32) & BigInt(4294967295)); + buf[offset + 3] = hi; + hi = hi >> 8; + buf[offset + 2] = hi; + hi = hi >> 8; + buf[offset + 1] = hi; + hi = hi >> 8; + buf[offset] = hi; + return offset + 8; + } + Buffer3.prototype.writeBigUInt64LE = defineBigIntMethod(function writeBigUInt64LE(value, offset = 0) { + return wrtBigUInt64LE(this, value, offset, BigInt(0), BigInt("0xffffffffffffffff")); + }); + Buffer3.prototype.writeBigUInt64BE = defineBigIntMethod(function writeBigUInt64BE(value, offset = 0) { + return wrtBigUInt64BE(this, value, offset, BigInt(0), BigInt("0xffffffffffffffff")); + }); + Buffer3.prototype.writeIntLE = function writeIntLE(value, offset, byteLength3, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) { + const limit = Math.pow(2, 8 * byteLength3 - 1); + checkInt(this, value, offset, byteLength3, limit - 1, -limit); + } + let i = 0; + let mul = 1; + let sub = 0; + this[offset] = value & 255; + while (++i < byteLength3 && (mul *= 256)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1; + } + this[offset + i] = (value / mul >> 0) - sub & 255; + } + return offset + byteLength3; + }; + Buffer3.prototype.writeIntBE = function writeIntBE(value, offset, byteLength3, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) { + const limit = Math.pow(2, 8 * byteLength3 - 1); + checkInt(this, value, offset, byteLength3, limit - 1, -limit); + } + let i = byteLength3 - 1; + let mul = 1; + let sub = 0; + this[offset + i] = value & 255; + while (--i >= 0 && (mul *= 256)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1; + } + this[offset + i] = (value / mul >> 0) - sub & 255; + } + return offset + byteLength3; + }; + Buffer3.prototype.writeInt8 = function writeInt8(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 1, 127, -128); + if (value < 0) value = 255 + value + 1; + this[offset] = value & 255; + return offset + 1; + }; + Buffer3.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 2, 32767, -32768); + this[offset] = value & 255; + this[offset + 1] = value >>> 8; + return offset + 2; + }; + Buffer3.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 2, 32767, -32768); + this[offset] = value >>> 8; + this[offset + 1] = value & 255; + return offset + 2; + }; + Buffer3.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 4, 2147483647, -2147483648); + this[offset] = value & 255; + this[offset + 1] = value >>> 8; + this[offset + 2] = value >>> 16; + this[offset + 3] = value >>> 24; + return offset + 4; + }; + Buffer3.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 4, 2147483647, -2147483648); + if (value < 0) value = 4294967295 + value + 1; + this[offset] = value >>> 24; + this[offset + 1] = value >>> 16; + this[offset + 2] = value >>> 8; + this[offset + 3] = value & 255; + return offset + 4; + }; + Buffer3.prototype.writeBigInt64LE = defineBigIntMethod(function writeBigInt64LE(value, offset = 0) { + return wrtBigUInt64LE(this, value, offset, -BigInt("0x8000000000000000"), BigInt("0x7fffffffffffffff")); + }); + Buffer3.prototype.writeBigInt64BE = defineBigIntMethod(function writeBigInt64BE(value, offset = 0) { + return wrtBigUInt64BE(this, value, offset, -BigInt("0x8000000000000000"), BigInt("0x7fffffffffffffff")); + }); + function checkIEEE754(buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError("Index out of range"); + if (offset < 0) throw new RangeError("Index out of range"); + } + function writeFloat(buf, value, offset, littleEndian, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 34028234663852886e22, -34028234663852886e22); + } + ieee754.write(buf, value, offset, littleEndian, 23, 4); + return offset + 4; + } + Buffer3.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert); + }; + Buffer3.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert); + }; + function writeDouble(buf, value, offset, littleEndian, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 17976931348623157e292, -17976931348623157e292); + } + ieee754.write(buf, value, offset, littleEndian, 52, 8); + return offset + 8; + } + Buffer3.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert); + }; + Buffer3.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert); + }; + Buffer3.prototype.copy = function copy(target, targetStart, start, end) { + if (!Buffer3.isBuffer(target)) throw new TypeError("argument should be a Buffer"); + if (!start) start = 0; + if (!end && end !== 0) end = this.length; + if (targetStart >= target.length) targetStart = target.length; + if (!targetStart) targetStart = 0; + if (end > 0 && end < start) end = start; + if (end === start) return 0; + if (target.length === 0 || this.length === 0) return 0; + if (targetStart < 0) { + throw new RangeError("targetStart out of bounds"); + } + if (start < 0 || start >= this.length) throw new RangeError("Index out of range"); + if (end < 0) throw new RangeError("sourceEnd out of bounds"); + if (end > this.length) end = this.length; + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start; + } + const len = end - start; + if (this === target && typeof Uint8Array.prototype.copyWithin === "function") { + this.copyWithin(targetStart, start, end); + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, end), + targetStart + ); + } + return len; + }; + Buffer3.prototype.fill = function fill(val, start, end, encoding) { + if (typeof val === "string") { + if (typeof start === "string") { + encoding = start; + start = 0; + end = this.length; + } else if (typeof end === "string") { + encoding = end; + end = this.length; + } + if (encoding !== void 0 && typeof encoding !== "string") { + throw new TypeError("encoding must be a string"); + } + if (typeof encoding === "string" && !Buffer3.isEncoding(encoding)) { + throw new TypeError("Unknown encoding: " + encoding); + } + if (val.length === 1) { + const code = val.charCodeAt(0); + if (encoding === "utf8" && code < 128 || encoding === "latin1") { + val = code; + } + } + } else if (typeof val === "number") { + val = val & 255; + } else if (typeof val === "boolean") { + val = Number(val); + } + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError("Out of range index"); + } + if (end <= start) { + return this; + } + start = start >>> 0; + end = end === void 0 ? this.length : end >>> 0; + if (!val) val = 0; + let i; + if (typeof val === "number") { + Uint8Array.prototype.fill.call(this, val, start, end); + } else { + const bytes = Buffer3.isBuffer(val) ? val : Buffer3.from(val, encoding); + const len = bytes.length; + if (len === 0) { + throw new TypeError('The value "' + val + '" is invalid for argument "value"'); + } + const count = end - start; + const seed = Math.min(len, count); + Uint8Array.prototype.set.call(this, bytes.subarray(0, seed), start); + for (let filled = seed; filled < count; filled *= 2) { + Uint8Array.prototype.copyWithin.call(this, start + filled, start, start + Math.min(filled, count - filled)); + } + } + return this; + }; + var errors = {}; + function E(sym, getMessage, Base) { + errors[sym] = class NodeError extends Base { + constructor() { + super(); + Object.defineProperty(this, "message", { + value: getMessage.apply(this, arguments), + writable: true, + configurable: true + }); + this.name = `${this.name} [${sym}]`; + this.stack; + delete this.name; + } + get code() { + return sym; + } + set code(value) { + Object.defineProperty(this, "code", { + configurable: true, + enumerable: true, + value, + writable: true + }); + } + toString() { + return `${this.name} [${sym}]: ${this.message}`; + } + }; + } + E( + "ERR_BUFFER_OUT_OF_BOUNDS", + function(name) { + if (name) { + return `${name} is outside of buffer bounds`; + } + return "Attempt to access memory outside buffer bounds"; + }, + RangeError + ); + E( + "ERR_INVALID_ARG_TYPE", + function(name, actual) { + return `The "${name}" argument must be of type number. Received type ${typeof actual}`; + }, + TypeError + ); + E( + "ERR_OUT_OF_RANGE", + function(str, range, input) { + let msg = `The value of "${str}" is out of range.`; + let received = input; + if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) { + received = addNumericalSeparator(String(input)); + } else if (typeof input === "bigint") { + received = String(input); + if (input > BigInt(2) ** BigInt(32) || input < -(BigInt(2) ** BigInt(32))) { + received = addNumericalSeparator(received); + } + received += "n"; + } + msg += ` It must be ${range}. Received ${received}`; + return msg; + }, + RangeError + ); + function addNumericalSeparator(val) { + let res = ""; + let i = val.length; + const start = val[0] === "-" ? 1 : 0; + for (; i >= start + 4; i -= 3) { + res = `_${val.slice(i - 3, i)}${res}`; + } + return `${val.slice(0, i)}${res}`; + } + function checkBounds(buf, offset, byteLength3) { + validateNumber(offset, "offset"); + if (buf[offset] === void 0 || buf[offset + byteLength3] === void 0) { + boundsError(offset, buf.length - (byteLength3 + 1)); + } + } + function checkIntBI(value, min, max, buf, offset, byteLength3) { + if (value > max || value < min) { + const n = typeof min === "bigint" ? "n" : ""; + let range; + if (byteLength3 > 3) { + if (min === 0 || min === BigInt(0)) { + range = `>= 0${n} and < 2${n} ** ${(byteLength3 + 1) * 8}${n}`; + } else { + range = `>= -(2${n} ** ${(byteLength3 + 1) * 8 - 1}${n}) and < 2 ** ${(byteLength3 + 1) * 8 - 1}${n}`; + } + } else { + range = `>= ${min}${n} and <= ${max}${n}`; + } + throw new errors.ERR_OUT_OF_RANGE("value", range, value); + } + checkBounds(buf, offset, byteLength3); + } + function validateNumber(value, name) { + if (typeof value !== "number") { + throw new errors.ERR_INVALID_ARG_TYPE(name, "number", value); + } + } + function boundsError(value, length, type) { + if (Math.floor(value) !== value) { + validateNumber(value, type); + throw new errors.ERR_OUT_OF_RANGE(type || "offset", "an integer", value); + } + if (length < 0) { + throw new errors.ERR_BUFFER_OUT_OF_BOUNDS(); + } + throw new errors.ERR_OUT_OF_RANGE( + type || "offset", + `>= ${type ? 1 : 0} and <= ${length}`, + value + ); + } + var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g; + function base64clean(str) { + str = str.split("=")[0]; + str = str.trim().replace(INVALID_BASE64_RE, ""); + if (str.length < 2) return ""; + while (str.length % 4 !== 0) { + str = str + "="; + } + return str; + } + function asciiToBytes(str) { + const byteArray = []; + for (let i = 0; i < str.length; ++i) { + byteArray.push(str.charCodeAt(i) & 255); + } + return byteArray; + } + function utf16leToBytes(str, units) { + let c, hi, lo; + const byteArray = []; + for (let i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break; + c = str.charCodeAt(i); + hi = c >> 8; + lo = c % 256; + byteArray.push(lo); + byteArray.push(hi); + } + return byteArray; + } + function base64ToBytes(str) { + return base64.toByteArray(base64clean(str)); + } + function blitBuffer(src, dst, offset, length) { + let i; + for (i = 0; i < length; ++i) { + if (i + offset >= dst.length || i >= src.length) break; + dst[i + offset] = src[i]; + } + return i; + } + function isInstance(obj, type) { + return obj instanceof type || obj != null && obj.constructor != null && obj.constructor.name != null && obj.constructor.name === type.name; + } + function numberIsNaN(obj) { + return obj !== obj; + } + var hexSliceLookupTable = (function() { + const alphabet = "0123456789abcdef"; + const table = new Array(256); + for (let i = 0; i < 16; ++i) { + const i16 = i * 16; + for (let j = 0; j < 16; ++j) { + table[i16 + j] = alphabet[i] + alphabet[j]; + } + } + return table; + })(); + function defineBigIntMethod(fn) { + return typeof BigInt === "undefined" ? BufferBigIntNotDefined : fn; + } + function BufferBigIntNotDefined() { + throw new Error("BigInt not supported"); + } + } +}); + +// buffer-entry.cjs +var exported = require_buffer(); +var { Buffer: Buffer2 } = exported; +var from = Buffer2.from; +var byteLength = Buffer2.byteLength; +var isEncoding = Buffer2.isEncoding; +var toString = Buffer2.prototype.toString; +var write = Buffer2.prototype.write; +var normalize = (encoding) => typeof encoding === "string" && encoding.toLowerCase() === "base64url" ? "base64" : encoding; +Buffer2.from = function(value, encodingOrOffset, length) { + return from(value, normalize(encodingOrOffset), length); +}; +Buffer2.byteLength = function(value, encoding) { + return byteLength(value, normalize(encoding)); +}; +Buffer2.isEncoding = function(encoding) { + return isEncoding(normalize(encoding)); +}; +Buffer2.prototype.toString = function(encoding, start, end) { + if (!encoding || typeof encoding === "string" && /^(utf8|utf-8)$/i.test(encoding)) { + if (start === void 0 || start < 0) start = 0; + if (start > this.length) return ""; + if (end === void 0 || end > this.length) end = this.length; + if (end <= 0) return ""; + end >>>= 0; + start >>>= 0; + if (end <= start) return ""; + return new TextDecoder("utf-8", { ignoreBOM: true }).decode(new Uint8Array(this.buffer, this.byteOffset + start, end - start)); + } + const result = toString.call(this, normalize(encoding), start, end); + return typeof encoding === "string" && encoding.toLowerCase() === "base64url" ? result.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "") : result; +}; +Buffer2.prototype.write = function(string, offset, length, encoding) { + return write.call(this, string, normalize(offset), normalize(length), normalize(encoding)); +}; +Buffer2.copyBytesFrom = function(view, offset = 0, length) { + if (!ArrayBuffer.isView(view) || view instanceof DataView) throw new TypeError('The "view" argument must be a TypedArray.'); + length ??= Math.max(view.length - offset, 0); + for (const [name, value] of [["offset", offset], ["length", length]]) { + if (!Number.isInteger(value) || value < 0) throw new RangeError(`The "${name}" argument is out of range.`); + } + const start = Math.min(offset, view.length); + const count = Math.min(length, view.length - start); + return Buffer2.from(new Uint8Array(view.buffer, view.byteOffset + start * view.BYTES_PER_ELEMENT, count * view.BYTES_PER_ELEMENT)); +}; +Buffer2.prototype.readBigUint64LE = Buffer2.prototype.readBigUInt64LE; +Buffer2.prototype.readBigUint64BE = Buffer2.prototype.readBigUInt64BE; +Buffer2.prototype.writeBigUint64LE = Buffer2.prototype.writeBigUInt64LE; +Buffer2.prototype.writeBigUint64BE = Buffer2.prototype.writeBigUInt64BE; +exported.Blob = globalThis.Blob; +exported.File = globalThis.File; +exported.atob = globalThis.atob; +exported.btoa = globalThis.btoa; +exported.constants = Object.freeze({ MAX_LENGTH: exported.kMaxLength, MAX_STRING_LENGTH: 536870888 }); +exported.isAscii = function(input) { + if (!ArrayBuffer.isView(input) && !(input instanceof ArrayBuffer)) throw new TypeError('The "input" argument must be an ArrayBuffer or ArrayBufferView.'); + const bytes = input instanceof ArrayBuffer ? new Uint8Array(input) : new Uint8Array(input.buffer, input.byteOffset, input.byteLength); + return bytes.every((byte) => byte < 128); +}; +exported.isUtf8 = function(input) { + if (!ArrayBuffer.isView(input) && !(input instanceof ArrayBuffer)) throw new TypeError('The "input" argument must be an ArrayBuffer or ArrayBufferView.'); + try { + new TextDecoder("utf-8", { fatal: true }).decode(input); + return true; + } catch { + return false; + } +}; +module.exports = exported; diff --git a/src/Node/Lib/child_process.cjs b/src/Node/Lib/child_process.cjs new file mode 100644 index 00000000..215c36cb --- /dev/null +++ b/src/Node/Lib/child_process.cjs @@ -0,0 +1,301 @@ +'use strict'; + +const { EventEmitter } = require('events'); +const { Readable, Writable } = require('stream'); +const { Buffer } = require('buffer'); +const { fileURLToPath } = require('url'); +const host = __phasisNodeHost.child_process; +const signals = require('os').constants.signals; +const promisify = Symbol.for('nodejs.util.promisify.custom'); + +function failure(code, message, Constructor = TypeError) { + return Object.assign(new Constructor(message), { code }); +} +function unavailable(name) { + throw failure('ERR_FEATURE_UNAVAILABLE_ON_PLATFORM', `${name} is unavailable through PHP process streams`, Error); +} +function text(value, name) { + if (typeof value !== 'string') throw failure('ERR_INVALID_ARG_TYPE', `The "${name}" argument must be of type string`); + if (value.includes('\0')) throw failure('ERR_INVALID_ARG_VALUE', `The argument '${name}' must be a string without null bytes`); + return value; +} +function signalNumber(value = 'SIGTERM') { + if (typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 64) return value; + const number = signals[String(value).toUpperCase()]; + if (number === undefined) throw failure('ERR_UNKNOWN_SIGNAL', `Unknown signal: ${value}`); + return number; +} +function nativeError(value, file, args) { + const error = Object.assign(new Error(value.message), value); + if (file !== undefined) { error.path = file; error.spawnargs = args; } + return error; +} +function call(name, ...args) { + const result = host.call(name, ...args); + if (result.error) throw nativeError(result.error); + return result.value; +} +function normalize(file, args, options) { + text(file, 'file'); + if (!file.length) throw failure('ERR_INVALID_ARG_VALUE', "The argument 'file' cannot be empty"); + if (args === undefined || args === null) args = []; + else if (!Array.isArray(args)) { options = args; args = []; } + if (options === undefined || options === null) options = {}; + if (typeof options !== 'object') throw failure('ERR_INVALID_ARG_TYPE', 'The "options" argument must be of type object'); + args = args.map((value, i) => text(String(value), `args[${i}]`)); + let cwd = options.cwd === undefined || options.cwd === null ? process.cwd() : options.cwd; + if (cwd instanceof URL) cwd = fileURLToPath(cwd); + if (Buffer.isBuffer(cwd)) cwd = cwd.toString(); + text(cwd, 'options.cwd'); + const env = {}; + const source = options.env === undefined || options.env === null ? process.env : options.env; + for (const key in source) if (source[key] !== undefined) env[text(key, 'options.env')] = text(String(source[key]), `options.env.${key}`); + for (const name of ['timeout', 'maxBuffer']) { + if (options[name] !== undefined && (typeof options[name] !== 'number' || options[name] < 0 || Number.isNaN(options[name]))) { + throw failure('ERR_OUT_OF_RANGE', `The value of "options.${name}" is out of range`, RangeError); + } + } + if (options.detached) unavailable('Detached process sessions'); + if (options.signal !== undefined && !(options.signal instanceof AbortSignal)) throw failure('ERR_INVALID_ARG_TYPE', 'The "options.signal" property must be an instance of AbortSignal'); + if (options.uid !== undefined || options.gid !== undefined) unavailable('Child uid/gid'); + if (options.argv0 !== undefined && options.argv0 !== file) unavailable('Custom child argv0'); + let stdio = options.stdio === undefined ? 'pipe' : options.stdio; + if (typeof stdio === 'string') stdio = [stdio, stdio, stdio]; + if (!Array.isArray(stdio)) throw failure('ERR_INVALID_ARG_VALUE', 'The argument stdio is invalid'); + if (stdio.length > 3 && stdio.slice(3).some((value) => value !== null && value !== undefined && value !== 'ignore')) unavailable('Additional child stdio and IPC'); + stdio = [0, 1, 2].map((fd) => { + let value = stdio[fd]; + if (value === null || value === undefined) value = 'pipe'; + if (value === 'inherit') return fd; + if (value && typeof value === 'object') value = value.fd; + if (value === 'pipe' || value === 'overlapped' || value === 'ignore' || value === 0 || value === 1 || value === 2) return value; + if (typeof value === 'number') unavailable('Inherited file descriptors other than standard streams'); + throw failure('ERR_INVALID_ARG_VALUE', `The argument stdio is invalid. Received ${value}`); + }); + const originalFile = file; + const originalArgs = args; + if (options.shell) { + const command = [file, ...args].join(' '); + file = typeof options.shell === 'string' ? text(options.shell, 'options.shell') : '/bin/sh'; + args = ['-c', command]; + } + let input = options.input; + if (typeof input === 'string') input = Buffer.from(input, options.encoding && options.encoding !== 'buffer' ? options.encoding : 'utf8'); + else if (input !== undefined) { + if (!ArrayBuffer.isView(input)) throw failure('ERR_INVALID_ARG_TYPE', 'The "options.input" property must be a string or an ArrayBufferView'); + input = Buffer.from(input.buffer, input.byteOffset, input.byteLength); + } + const encoding = options.encoding; + if (encoding !== undefined && encoding !== null && encoding !== 'buffer' && !Buffer.isEncoding(encoding)) throw failure('ERR_UNKNOWN_ENCODING', `Unknown encoding: ${encoding}`); + return { + file, args, cwd, env, stdio, input, encoding, + timeout: options.timeout === undefined ? 0 : options.timeout, + maxBuffer: options.maxBuffer === undefined ? 1024 * 1024 : options.maxBuffer, + killSignal: signalNumber(options.killSignal), + signal: options.signal, + originalFile, originalArgs, + }; +} +function decode(bytes, encoding) { + if (bytes === null) return null; + const buffer = Buffer.from(bytes); + return encoding && encoding !== 'buffer' ? buffer.toString(encoding) : buffer; +} +function spawnSync(file, args, options) { + const config = normalize(file, args, options); + const native = host.call('spawnSync', config); + let result; + if (native.error) result = { pid: 0, output: null, stdout: null, stderr: null, status: null, signal: null, error: native.error }; + else { + result = native.value; + result.stdout = config.stdio[1] === 'pipe' || config.stdio[1] === 'overlapped' ? decode(result.stdout, config.encoding) : null; + result.stderr = config.stdio[2] === 'pipe' || config.stdio[2] === 'overlapped' ? decode(result.stderr, config.encoding) : null; + result.output = [null, result.stdout, result.stderr]; + } + if (result.error) result.error = nativeError(result.error, config.file, config.args); + return result; +} +function syncFailure(result, command) { + if (result.error) return Object.assign(result.error, result); + const error = new Error(`Command failed: ${command}${result.stderr && result.stderr.length ? `\n${result.stderr}` : ''}`); + return Object.assign(error, result); +} +function execFileSync(file, args, options) { + const result = spawnSync(file, args, options); + if (result.error || result.status !== 0) throw syncFailure(result, file); + return result.stdout; +} +function execSync(command, options) { + text(command, 'command'); + const result = spawnSync(command, [], { ...options, shell: options && options.shell || true }); + if (result.error || result.status !== 0) throw syncFailure(result, command); + return result.stdout; +} + +class ChildReadable extends Readable { + constructor(child, fd) { super({ autoDestroy: true }); this._child = child; this._fd = fd; } + _read() { if (!this._child._closed) call('pause', this._child._id, this._fd, false); } + _destroy(error, callback) { + if (!this._child._closed) call('closePipe', this._child._id, this._fd); + callback(error); + } + ref() { if (!this._child._closed) call('ref', this._child._id, true, this._fd); return this; } + unref() { if (!this._child._closed) call('ref', this._child._id, false, this._fd); return this; } +} +class ChildWritable extends Writable { + constructor(child) { super({ autoDestroy: true }); this._child = child; } + _write(chunk, encoding, callback) { + try { call('write', this._child._id, chunk, (error) => callback(error ? nativeError(error) : undefined)); } + catch (error) { callback(error); } + } + _final(callback) { + try { call('end', this._child._id); callback(); } catch (error) { callback(error); } + } + _destroy(error, callback) { + if (!this._child._closed) call('closePipe', this._child._id, 0); + callback(error); + } + ref() { if (!this._child._closed) call('ref', this._child._id, true, 0); return this; } + unref() { if (!this._child._closed) call('ref', this._child._id, false, 0); return this; } +} +class ChildProcess extends EventEmitter { + constructor() { + super(); + this.connected = false; + this.killed = false; + this.exitCode = null; + this.signalCode = null; + this.spawnargs = []; + this.spawnfile = undefined; + this.pid = undefined; + this.stdin = null; + this.stdout = null; + this.stderr = null; + this.stdio = [null, null, null]; + this._id = null; + this._closed = false; + } + spawn(options) { + if (!options || typeof options.file !== 'string') throw failure('ERR_INVALID_ARG_TYPE', 'The options.file property must be a string'); + const config = normalize(options.file, (options.args || []).slice(1), options); + this._start(config); + return this._spawnError ? this._spawnError.errno : 0; + } + _start(config) { + this.spawnfile = config.file; + this.spawnargs = [config.file, ...config.args]; + const result = host.call('spawn', config, (event, value) => this._onNative(event, value)); + if (result.error) { + this._spawnError = nativeError(result.error, config.file, config.args); + this._closed = true; + process.nextTick(() => { this.emit('error', this._spawnError); this.emit('close', this._spawnError.errno, null); }); + return; + } + this._id = result.value.id; + this.pid = result.value.pid; + for (const fd of result.value.pipes) this.stdio[fd] = fd === 0 ? new ChildWritable(this) : new ChildReadable(this, fd); + [this.stdin, this.stdout, this.stderr] = this.stdio; + if (config.timeout) { + this._timer = setTimeout(() => { this.kill(config.killSignal); }, config.timeout); + this._timer.unref(); + } + if (config.signal !== undefined) { + const signal = config.signal; + if (!(signal instanceof AbortSignal)) throw failure('ERR_INVALID_ARG_TYPE', 'The "options.signal" property must be an instance of AbortSignal'); + const abort = () => { + if (this.kill(config.killSignal)) { + const error = Object.assign(new Error('The operation was aborted'), { name: 'AbortError', code: 'ABORT_ERR', cause: signal.reason }); + this.emit('error', error); + } + }; + if (signal.aborted) process.nextTick(abort); + else { signal.addEventListener('abort', abort, { once: true }); this.once('close', () => signal.removeEventListener('abort', abort)); } + } + } + _onNative(event, value) { + if (event === 'spawn') this.emit('spawn'); + else if (event === 'data') { + const stream = this.stdio[value.fd]; + if (stream && !stream.destroyed && !stream.push(Buffer.from(value.data))) call('pause', this._id, value.fd, true); + } else if (event === 'end') { + const stream = this.stdio[value]; + if (stream && !stream.destroyed) stream.push(null); + } else if (event === 'exit') { + this.exitCode = value.code; + this.signalCode = value.signal; + if (this._timer) clearTimeout(this._timer); + if (this.stdin) this.stdin.destroy(); + this.emit('exit', value.code, value.signal); + process.nextTick(() => { + for (const stream of [this.stdout, this.stderr]) if (stream && !stream.readableFlowing) stream.resume(); + }); + } else if (event === 'close') { + this._closed = true; + process.nextTick(() => this.emit('close', value.code, value.signal)); + } + } + kill(signal) { + const number = signalNumber(signal); + if (this._id === null || this._closed) return false; + const killed = call('kill', this._id, number); + if (killed) this.killed = true; + return killed; + } + ref() { if (!this._closed && this._id !== null) call('ref', this._id, true); return this; } + unref() { if (!this._closed && this._id !== null) call('ref', this._id, false); return this; } + [Symbol.dispose]() { this.kill(); } +} +function spawn(file, args, options) { + const config = normalize(file, args, options); + const child = new ChildProcess(); + child._start(config); + return child; +} +function execFile(file, args, options, callback) { + if (typeof args === 'function') { callback = args; args = []; options = {}; } + else if (!Array.isArray(args)) { callback = options; options = args; args = []; } + else if (typeof options === 'function') { callback = options; options = {}; } + options = options || {}; + if (callback !== undefined && typeof callback !== 'function') throw failure('ERR_INVALID_ARG_TYPE', 'The "callback" argument must be of type function'); + const config = normalize(file, args, options); + const child = new ChildProcess(); + child._start(config); + const chunks = [[], []]; + const lengths = [0, 0]; + let error; + for (const [index, stream] of [child.stdout, child.stderr].entries()) if (stream) stream.on('data', (chunk) => { + const remaining = config.maxBuffer - lengths[index]; + lengths[index] += chunk.length; + if (chunk.length > remaining && !error) { + error = failure('ERR_CHILD_PROCESS_STDIO_MAXBUFFER', `${index === 0 ? 'stdout' : 'stderr'} maxBuffer length exceeded`, RangeError); + chunks[index].push(chunk.subarray(0, Math.max(0, remaining))); + child.kill(config.killSignal); + } else if (!error) chunks[index].push(chunk); + }); + child.on('error', (value) => { error = value; }); + child.once('close', (code, signal) => { + const encoding = options.encoding === undefined ? 'utf8' : options.encoding; + const stdout = decode(Buffer.concat(chunks[0]), encoding); + const stderr = decode(Buffer.concat(chunks[1]), encoding); + if (!error && (code !== 0 || signal !== null)) error = Object.assign(new Error(`Command failed: ${[file, ...args].join(' ')}${stderr.length ? `\n${stderr}` : ''}`), { code, signal, killed: child.killed }); + if (error) { error.cmd = [file, ...args].join(' '); error.stdout = stdout; error.stderr = stderr; } + if (callback) callback(error || null, stdout, stderr); + }); + return child; +} +function exec(command, options, callback) { + if (typeof options === 'function') { callback = options; options = {}; } + text(command, 'command'); + return execFile(command, [], { ...options, shell: options && options.shell || true }, callback); +} +for (const method of [exec, execFile]) Object.defineProperty(method, promisify, { value: (...args) => { + let child; + const promise = new Promise((resolve, reject) => { + child = method(...args, (error, stdout, stderr) => error ? reject(error) : resolve({ stdout, stderr })); + }); + promise.child = child; + return promise; +}, configurable: true }); +function fork() { unavailable('IPC-backed child_process.fork'); } + +module.exports = { ChildProcess, spawn, spawnSync, exec, execSync, execFile, execFileSync, fork }; diff --git a/src/Node/Lib/crypto.cjs b/src/Node/Lib/crypto.cjs new file mode 100644 index 00000000..e54df20f --- /dev/null +++ b/src/Node/Lib/crypto.cjs @@ -0,0 +1,206 @@ +'use strict'; + +const host = __phasisNodeHost.crypto; +const { Buffer } = require('buffer'); +const { Transform } = require('stream'); +const webcrypto = globalThis.crypto; + +function fail(code, message, Constructor = TypeError) { + const error = new Constructor(message); + error.code = code; + throw error; +} +function integer(value, name, minimum, maximum) { + if (typeof value !== 'number') fail('ERR_INVALID_ARG_TYPE', `The "${name}" argument must be of type number.`); + if (!Number.isInteger(value) || value < minimum || value > maximum) { + fail('ERR_OUT_OF_RANGE', `The value of "${name}" is out of range. It must be >= ${minimum} and <= ${maximum}. Received ${value}`, RangeError); + } + return value; +} +function bytes(value, encoding, name = 'data', strings = true) { + if (strings && typeof value === 'string') return Buffer.from(value, encoding); + if (ArrayBuffer.isView(value)) return Buffer.from(value.buffer, value.byteOffset, value.byteLength); + if (value instanceof ArrayBuffer || typeof SharedArrayBuffer !== 'undefined' && value instanceof SharedArrayBuffer) return Buffer.from(value); + fail('ERR_INVALID_ARG_TYPE', `The "${name}" argument must be a string, Buffer, TypedArray, DataView, or ArrayBuffer.`); +} +function callback(value) { + if (typeof value !== 'function') fail('ERR_INVALID_ARG_TYPE', 'The "callback" argument must be of type function.'); + return value; +} +function asyncResult(fn, done) { + process.nextTick(() => { + let value; + try { value = fn(); } catch (error) { done(error); return; } + done(null, value); + }); +} +function algorithm(value) { + if (typeof value !== 'string') fail('ERR_INVALID_ARG_TYPE', 'The "algorithm" argument must be of type string.'); + return value; +} +function options(value) { + if (value !== undefined && (value === null || typeof value !== 'object')) fail('ERR_INVALID_ARG_TYPE', 'The "options" argument must be of type object.'); + return value || {}; +} + +class Hash extends Transform { + constructor(name, configuration) { + super(configuration); + const opts = options(configuration); + if (opts.outputLength !== undefined) { + integer(opts.outputLength, 'options.outputLength', 0, 0xffffffff); + if (opts.outputLength !== host.hashLength(algorithm(name))) fail('ERR_OSSL_EVP_NOT_XOF_OR_INVALID_LENGTH', 'Variable-length digests are unavailable from this PHP cryptography provider.', Error); + } + this._hash = host.createHash(algorithm(name)); + this._digested = false; + } + update(data, encoding) { + if (this._digested) fail('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called', Error); + host.updateHash(this._hash, bytes(data, encoding)); + return this; + } + digest(encoding) { + if (this._digested) fail('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called', Error); + const result = Buffer.from(host.digestHash(this._hash)); + this._digested = true; + return encoding && encoding !== 'buffer' ? result.toString(encoding) : result; + } + copy(configuration) { + if (this._digested) fail('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called', Error); + const opts = options(configuration); + if (opts.outputLength !== undefined) { + integer(opts.outputLength, 'options.outputLength', 0, 0xffffffff); + fail('ERR_OSSL_EVP_NOT_XOF_OR_INVALID_LENGTH', 'Changing digest length is unavailable from this PHP cryptography provider.', Error); + } + const copy = Object.create(Hash.prototype); + Transform.call(copy, configuration); + copy._hash = host.copyHash(this._hash); + copy._digested = false; + return copy; + } + _transform(chunk, encoding, done) { + try { this.update(chunk, encoding); done(); } catch (error) { done(error); } + } + _flush(done) { + try { this.push(this.digest()); done(); } catch (error) { done(error); } + } +} + +class Hmac extends Transform { + constructor(name, key, configuration) { + super(configuration); + const opts = options(configuration); + this._hash = host.createHash(algorithm(name), bytes(key, opts.encoding, 'key')); + this._digested = false; + } + update(data, encoding) { return Hash.prototype.update.call(this, data, encoding); } + digest(encoding) { + if (this._digested) return encoding && encoding !== 'buffer' ? '' : Buffer.alloc(0); + return Hash.prototype.digest.call(this, encoding); + } + _transform(chunk, encoding, done) { return Hash.prototype._transform.call(this, chunk, encoding, done); } + _flush(done) { return Hash.prototype._flush.call(this, done); } +} + +function randomBytes(size, done) { + integer(size, 'size', 0, 0x7fffffff); + if (done === undefined) return Buffer.from(host.randomBytes(size)); + callback(done); + asyncResult(() => Buffer.from(host.randomBytes(size)), done); +} +function randomFillSync(buffer, offset = 0, size) { + const view = bytes(buffer, undefined, 'buf', false); + const width = buffer.BYTES_PER_ELEMENT || 1; + integer(offset, 'offset', 0, view.length / width); + if (size === undefined) size = view.length / width - offset; + integer(size, 'size', 0, view.length / width - offset); + view.set(host.randomBytes(size * width), offset * width); + return buffer; +} +function randomFill(buffer, offset, size, done) { + if (typeof offset === 'function') { done = offset; offset = 0; size = undefined; } + else if (typeof size === 'function') { done = size; size = undefined; } + callback(done); + const view = bytes(buffer, undefined, 'buf', false); + const width = buffer.BYTES_PER_ELEMENT || 1; + if (offset === undefined) offset = 0; + integer(offset, 'offset', 0, view.length / width); + if (size === undefined) size = view.length / width - offset; + integer(size, 'size', 0, view.length / width - offset); + asyncResult(() => randomFillSync(buffer, offset, size), done); +} +function randomInt(min, max, done) { + if (typeof max === 'function') { done = max; max = undefined; } + if (max === undefined) { max = min; min = 0; } + integer(min, 'min', Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); + integer(max, 'max', min + 1, Number.MAX_SAFE_INTEGER); + if (max - min > 0xffffffffffff) fail('ERR_OUT_OF_RANGE', 'The value of "max - min" must be <= 281474976710655.', RangeError); + if (done === undefined) return host.randomInt(min, max); + callback(done); + asyncResult(() => host.randomInt(min, max), done); +} +function timingSafeEqual(a, b) { + a = bytes(a, undefined, 'buf1', false); + b = bytes(b, undefined, 'buf2', false); + if (a.length !== b.length) fail('ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH', 'Input buffers must have the same byte length', RangeError); + return host.timingSafeEqual(a, b); +} +function pbkdf2Sync(password, salt, iterations, keylen, digest) { + password = bytes(password, undefined, 'password'); + salt = bytes(salt, undefined, 'salt'); + integer(iterations, 'iterations', 1, 0x7fffffff); + integer(keylen, 'keylen', 0, 0x7fffffff); + return Buffer.from(host.pbkdf2(password, salt, iterations, keylen, algorithm(digest))); +} +function pbkdf2(password, salt, iterations, keylen, digest, done) { + callback(done); + password = bytes(password, undefined, 'password'); + salt = bytes(salt, undefined, 'salt'); + integer(iterations, 'iterations', 1, 0x7fffffff); + integer(keylen, 'keylen', 0, 0x7fffffff); + algorithm(digest); + asyncResult(() => pbkdf2Sync(password, salt, iterations, keylen, digest), done); +} +function hkdfSync(digest, ikm, salt, info, keylen) { + algorithm(digest); + ikm = bytes(ikm, undefined, 'ikm'); + salt = bytes(salt, undefined, 'salt'); + info = bytes(info, undefined, 'info'); + integer(keylen, 'keylen', 0, 0x7fffffff); + if (info.length > 1024) fail('ERR_OUT_OF_RANGE', 'The value of "info" must not contain more than 1024 bytes.', RangeError); + if (keylen > 255 * host.hashLength(digest)) fail('ERR_CRYPTO_INVALID_KEYLEN', 'Invalid key length', RangeError); + const result = host.hkdf(digest, ikm, salt, info, keylen); + return result.buffer.slice(result.byteOffset, result.byteOffset + result.byteLength); +} +function hkdf(digest, ikm, salt, info, keylen, done) { + callback(done); + algorithm(digest); + ikm = bytes(ikm, undefined, 'ikm'); + salt = bytes(salt, undefined, 'salt'); + info = bytes(info, undefined, 'info'); + integer(keylen, 'keylen', 0, 0x7fffffff); + if (info.length > 1024) fail('ERR_OUT_OF_RANGE', 'The value of "info" must not contain more than 1024 bytes.', RangeError); + if (keylen > 255 * host.hashLength(digest)) fail('ERR_CRYPTO_INVALID_KEYLEN', 'Invalid key length', RangeError); + asyncResult(() => hkdfSync(digest, ikm, salt, info, keylen), done); +} + +module.exports = { + Hash, Hmac, + createHash: (name, configuration) => new Hash(name, configuration), + createHmac: (name, key, configuration) => new Hmac(name, key, configuration), + hash(name, data, configuration = 'hex') { + const opts = typeof configuration === 'string' ? { outputEncoding: configuration } : options(configuration); + return new Hash(name, opts.outputLength === undefined ? undefined : { outputLength: opts.outputLength }).update(data).digest(opts.outputEncoding || 'hex'); + }, + getHashes: () => host.hashes(), + randomBytes, randomFill, randomFillSync, randomInt, + pseudoRandomBytes: randomBytes, rng: randomBytes, prng: randomBytes, + randomUUID(configuration) { + const opts = options(configuration); + if (opts.disableEntropyCache !== undefined && typeof opts.disableEntropyCache !== 'boolean') fail('ERR_INVALID_ARG_TYPE', 'The "options.disableEntropyCache" property must be of type boolean.'); + return webcrypto.randomUUID(); + }, + timingSafeEqual, pbkdf2, pbkdf2Sync, hkdf, hkdfSync, + webcrypto, subtle: webcrypto.subtle, + getRandomValues: (array) => webcrypto.getRandomValues(array), +}; diff --git a/src/Node/Lib/events.cjs b/src/Node/Lib/events.cjs new file mode 100644 index 00000000..09cfc347 --- /dev/null +++ b/src/Node/Lib/events.cjs @@ -0,0 +1,613 @@ +// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt. +"use strict"; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + try { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + } catch (e) { + throw mod = 0, e; + } +}; + +// node_modules/events/events.js +var require_events = __commonJS({ + "node_modules/events/events.js"(exports2, module2) { + "use strict"; + var R = typeof Reflect === "object" ? Reflect : null; + var ReflectApply = R && typeof R.apply === "function" ? R.apply : function ReflectApply2(target, receiver, args) { + return Function.prototype.apply.call(target, receiver, args); + }; + var ReflectOwnKeys; + if (R && typeof R.ownKeys === "function") { + ReflectOwnKeys = R.ownKeys; + } else if (Object.getOwnPropertySymbols) { + ReflectOwnKeys = function ReflectOwnKeys2(target) { + return Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)); + }; + } else { + ReflectOwnKeys = function ReflectOwnKeys2(target) { + return Object.getOwnPropertyNames(target); + }; + } + function ProcessEmitWarning(warning) { + if (console && console.warn) console.warn(warning); + } + var NumberIsNaN = Number.isNaN || function NumberIsNaN2(value) { + return value !== value; + }; + function EventEmitter2() { + EventEmitter2.init.call(this); + } + module2.exports = EventEmitter2; + module2.exports.once = once2; + EventEmitter2.EventEmitter = EventEmitter2; + EventEmitter2.prototype._events = void 0; + EventEmitter2.prototype._eventsCount = 0; + EventEmitter2.prototype._maxListeners = void 0; + var defaultMaxListeners = 10; + function checkListener(listener) { + if (typeof listener !== "function") { + throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); + } + } + Object.defineProperty(EventEmitter2, "defaultMaxListeners", { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + if (typeof arg !== "number" || arg < 0 || NumberIsNaN(arg)) { + throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + "."); + } + defaultMaxListeners = arg; + } + }); + EventEmitter2.init = function() { + if (this._events === void 0 || this._events === Object.getPrototypeOf(this)._events) { + this._events = /* @__PURE__ */ Object.create(null); + this._eventsCount = 0; + } + this._maxListeners = this._maxListeners || void 0; + }; + EventEmitter2.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== "number" || n < 0 || NumberIsNaN(n)) { + throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + "."); + } + this._maxListeners = n; + return this; + }; + function _getMaxListeners(that) { + if (that._maxListeners === void 0) + return EventEmitter2.defaultMaxListeners; + return that._maxListeners; + } + EventEmitter2.prototype.getMaxListeners = function getMaxListeners() { + return _getMaxListeners(this); + }; + EventEmitter2.prototype.emit = function emit2(type) { + var args = []; + for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); + var doError = type === "error"; + var events = this._events; + if (events !== void 0) + doError = doError && events.error === void 0; + else if (!doError) + return false; + if (doError) { + var er; + if (args.length > 0) + er = args[0]; + if (er instanceof Error) { + throw er; + } + var err = new Error("Unhandled error." + (er ? " (" + er.message + ")" : "")); + err.context = er; + throw err; + } + var handler = events[type]; + if (handler === void 0) + return false; + if (typeof handler === "function") { + ReflectApply(handler, this, args); + } else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + ReflectApply(listeners[i], this, args); + } + return true; + }; + function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + checkListener(listener); + events = target._events; + if (events === void 0) { + events = target._events = /* @__PURE__ */ Object.create(null); + target._eventsCount = 0; + } else { + if (events.newListener !== void 0) { + target.emit( + "newListener", + type, + listener.listener ? listener.listener : listener + ); + events = target._events; + } + existing = events[type]; + } + if (existing === void 0) { + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === "function") { + existing = events[type] = prepend ? [listener, existing] : [existing, listener]; + } else if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + m = _getMaxListeners(target); + if (m > 0 && existing.length > m && !existing.warned) { + existing.warned = true; + var w = new Error("Possible EventEmitter memory leak detected. " + existing.length + " " + String(type) + " listeners added. Use emitter.setMaxListeners() to increase limit"); + w.name = "MaxListenersExceededWarning"; + w.emitter = target; + w.type = type; + w.count = existing.length; + ProcessEmitWarning(w); + } + } + return target; + } + EventEmitter2.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); + }; + EventEmitter2.prototype.on = EventEmitter2.prototype.addListener; + EventEmitter2.prototype.prependListener = function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; + function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + if (arguments.length === 0) + return this.listener.call(this.target); + return this.listener.apply(this.target, arguments); + } + } + function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: void 0, target, type, listener }; + var wrapped = onceWrapper.bind(state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; + } + EventEmitter2.prototype.once = function once3(type, listener) { + checkListener(listener); + this.on(type, _onceWrap(this, type, listener)); + return this; + }; + EventEmitter2.prototype.prependOnceListener = function prependOnceListener(type, listener) { + checkListener(listener); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + EventEmitter2.prototype.removeListener = function removeListener(type, listener) { + var list, events, position, i, originalListener; + checkListener(listener); + events = this._events; + if (events === void 0) + return this; + list = events[type]; + if (list === void 0) + return this; + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = /* @__PURE__ */ Object.create(null); + else { + delete events[type]; + if (events.removeListener) + this.emit("removeListener", type, list.listener || listener); + } + } else if (typeof list !== "function") { + position = -1; + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + if (position < 0) + return this; + if (position === 0) + list.shift(); + else { + spliceOne(list, position); + } + if (list.length === 1) + events[type] = list[0]; + if (events.removeListener !== void 0) + this.emit("removeListener", type, originalListener || listener); + } + return this; + }; + EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener; + EventEmitter2.prototype.removeAllListeners = function removeAllListeners(type) { + var listeners, events, i; + events = this._events; + if (events === void 0) + return this; + if (events.removeListener === void 0) { + if (arguments.length === 0) { + this._events = /* @__PURE__ */ Object.create(null); + this._eventsCount = 0; + } else if (events[type] !== void 0) { + if (--this._eventsCount === 0) + this._events = /* @__PURE__ */ Object.create(null); + else + delete events[type]; + } + return this; + } + if (arguments.length === 0) { + var keys = Object.keys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === "removeListener") continue; + this.removeAllListeners(key); + } + this.removeAllListeners("removeListener"); + this._events = /* @__PURE__ */ Object.create(null); + this._eventsCount = 0; + return this; + } + listeners = events[type]; + if (typeof listeners === "function") { + this.removeListener(type, listeners); + } else if (listeners !== void 0) { + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + return this; + }; + function _listeners(target, type, unwrap) { + var events = target._events; + if (events === void 0) + return []; + var evlistener = events[type]; + if (evlistener === void 0) + return []; + if (typeof evlistener === "function") + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); + } + EventEmitter2.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); + }; + EventEmitter2.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); + }; + EventEmitter2.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === "function") { + return emitter.listenerCount(type); + } else { + return listenerCount2.call(emitter, type); + } + }; + EventEmitter2.prototype.listenerCount = listenerCount2; + function listenerCount2(type) { + var events = this._events; + if (events !== void 0) { + var evlistener = events[type]; + if (typeof evlistener === "function") { + return 1; + } else if (evlistener !== void 0) { + return evlistener.length; + } + } + return 0; + } + EventEmitter2.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; + }; + function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; + } + function spliceOne(list, index) { + for (; index + 1 < list.length; index++) + list[index] = list[index + 1]; + list.pop(); + } + function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; + } + function once2(emitter, name) { + return new Promise(function(resolve, reject) { + function errorListener(err) { + emitter.removeListener(name, resolver); + reject(err); + } + function resolver() { + if (typeof emitter.removeListener === "function") { + emitter.removeListener("error", errorListener); + } + resolve([].slice.call(arguments)); + } + ; + eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); + if (name !== "error") { + addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); + } + }); + } + function addErrorHandlerIfEventEmitter(emitter, handler, flags) { + if (typeof emitter.on === "function") { + eventTargetAgnosticAddListener(emitter, "error", handler, flags); + } + } + function eventTargetAgnosticAddListener(emitter, name, listener, flags) { + if (typeof emitter.on === "function") { + if (flags.once) { + emitter.once(name, listener); + } else { + emitter.on(name, listener); + } + } else if (typeof emitter.addEventListener === "function") { + emitter.addEventListener(name, function wrapListener(arg) { + if (flags.once) { + emitter.removeEventListener(name, wrapListener); + } + listener(arg); + }); + } else { + throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); + } + } + } +}); + +// events-entry.cjs +var Base = require_events(); +var capture = /* @__PURE__ */ Symbol("captureRejections"); +var rejection = /* @__PURE__ */ Symbol.for("nodejs.rejection"); +var errorMonitor = /* @__PURE__ */ Symbol("events.errorMonitor"); +var targetLimits = /* @__PURE__ */ new WeakMap(); +var defaultCapture = false; +function EventEmitter(options) { + Base.call(this); + const value = options?.captureRejections; + if (value !== void 0 && typeof value !== "boolean") throw new TypeError('The "options.captureRejections" property must be boolean.'); + this[capture] = value ?? defaultCapture; +} +Object.setPrototypeOf(EventEmitter, Base); +EventEmitter.prototype = Base.prototype; +Object.defineProperty(EventEmitter.prototype, "constructor", { value: EventEmitter, writable: true, configurable: true }); +var emit = Base.prototype.emit; +EventEmitter.prototype.emit = function(name, ...args) { + if (name === "error") emit.call(this, errorMonitor, ...args); + if (!this[capture]) return emit.call(this, name, ...args); + const listeners = this.rawListeners(name); + if (!listeners.length) return emit.call(this, name, ...args); + for (const listener of listeners) { + const result = Reflect.apply(listener, this, args); + if (result !== null && (typeof result === "object" || typeof result === "function")) { + try { + if (typeof result.then === "function") result.then(void 0, (error) => queueMicrotask(() => { + if (typeof this[rejection] === "function") this[rejection](error, name, ...args); + else { + const previous = this[capture]; + this[capture] = false; + try { + this.emit("error", error); + } finally { + this[capture] = previous; + } + } + })); + } catch (error) { + this.emit("error", error); + } + } + } + return true; +}; +var listenerCount = Base.prototype.listenerCount; +EventEmitter.prototype.listenerCount = function(name, listener) { + return listener === void 0 ? listenerCount.call(this, name) : this.rawListeners(name).filter((item) => item === listener || item.listener === listener).length; +}; +Object.defineProperty(EventEmitter, "captureRejections", { + enumerable: true, + get() { + return defaultCapture; + }, + set(value) { + if (typeof value !== "boolean") throw new TypeError("captureRejections must be boolean."); + defaultCapture = value; + } +}); +function abortError(signal) { + const error = new Error("The operation was aborted", { cause: signal?.reason }); + error.name = "AbortError"; + error.code = "ABORT_ERR"; + return error; +} +function validateSignal(signal) { + if (signal !== void 0 && (!signal || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function")) throw new TypeError('The "signal" argument must be an AbortSignal.'); +} +function listen(target, name, listener, once2 = false) { + if (typeof target.on === "function") { + target[once2 ? "once" : "on"](name, listener); + return () => target.removeListener(name, listener); + } + if (typeof target.addEventListener === "function") { + target.addEventListener(name, listener, { once: once2 }); + return () => target.removeEventListener(name, listener); + } + throw new TypeError("The emitter must be an EventEmitter or EventTarget."); +} +function once(emitter, name, options = {}) { + const signal = options.signal; + validateSignal(signal); + return new Promise((resolve, reject) => { + if (signal?.aborted) { + reject(abortError(signal)); + return; + } + const removers = []; + const cleanup = () => { + for (const remove of removers) remove(); + }; + removers.push(listen(emitter, name, (...args) => { + cleanup(); + resolve(args); + }, true)); + if (name !== "error" && typeof emitter.on === "function") removers.push(listen(emitter, "error", (error) => { + cleanup(); + reject(error); + }, true)); + if (signal) removers.push(listen(signal, "abort", () => { + cleanup(); + reject(abortError(signal)); + }, true)); + }); +} +function on(emitter, name, options = {}) { + const signal = options.signal; + validateSignal(signal); + if (signal?.aborted) throw abortError(signal); + const high = options.highWaterMark ?? options.highWatermark ?? Number.MAX_SAFE_INTEGER; + const low = options.lowWaterMark ?? options.lowWatermark ?? 1; + if (!Number.isInteger(high) || high < 1 || !Number.isInteger(low) || low < 1) throw new RangeError("Invalid event iterator water mark."); + const values = []; + const waiters = []; + const removers = []; + let error; + let done = false; + let paused = false; + function cleanup() { + for (const remove of removers) remove(); + } + function finish(reason) { + done = true; + error = reason; + cleanup(); + while (waiters.length) { + const waiter = waiters.shift(); + if (error) { + waiter.reject(error); + error = void 0; + } else waiter.resolve({ value: void 0, done: true }); + } + } + removers.push(listen(emitter, name, (...args) => { + if (waiters.length) waiters.shift().resolve({ value: args, done: false }); + else { + values.push(args); + if (!paused && values.length > high) { + paused = true; + emitter.pause(); + } + } + })); + if (name !== "error" && typeof emitter.on === "function") removers.push(listen(emitter, "error", finish)); + if (signal) removers.push(listen(signal, "abort", () => finish(abortError(signal)), true)); + for (const event of options.close || []) removers.push(listen(emitter, event, () => finish(), true)); + return { + next() { + if (values.length) { + const value = values.shift(); + if (paused && values.length < low) { + paused = false; + emitter.resume(); + } + return Promise.resolve({ value, done: false }); + } + if (error) { + const reason = error; + error = void 0; + return Promise.reject(reason); + } + if (done) return Promise.resolve({ value: void 0, done: true }); + return new Promise((resolve, reject) => waiters.push({ resolve, reject })); + }, + return() { + finish(); + return Promise.resolve({ value: void 0, done: true }); + }, + throw(reason) { + if (!(reason instanceof Error)) throw new TypeError('The "error" argument must be an Error.'); + finish(reason); + return Promise.resolve({ value: void 0, done: true }); + }, + [Symbol.asyncIterator]() { + return this; + } + }; +} +function addAbortListener(signal, listener) { + validateSignal(signal); + if (!signal) throw new TypeError('The "signal" argument must be an AbortSignal.'); + if (typeof listener !== "function") throw new TypeError('The "listener" argument must be a function.'); + let dispose; + if (signal.aborted) queueMicrotask(() => listener()); + else dispose = listen(signal, "abort", listener, true); + return { [Symbol.dispose]() { + dispose?.(); + dispose = void 0; + } }; +} +EventEmitter.EventEmitter = EventEmitter; +EventEmitter.captureRejectionSymbol = rejection; +EventEmitter.errorMonitor = errorMonitor; +EventEmitter.once = once; +EventEmitter.on = on; +EventEmitter.addAbortListener = addAbortListener; +EventEmitter.getEventListeners = (emitter, name) => { + if (typeof emitter.listeners === "function") return emitter.listeners(name); + if (typeof globalThis.__phasisNodeHost?.eventListeners === "function") return globalThis.__phasisNodeHost.eventListeners(emitter, name); + throw new TypeError("EventTarget listener inspection requires the host listener adapter."); +}; +EventEmitter.getMaxListeners = (emitter) => typeof emitter.getMaxListeners === "function" ? emitter.getMaxListeners() : targetLimits.get(emitter) ?? EventEmitter.defaultMaxListeners; +EventEmitter.setMaxListeners = (count, ...targets) => { + if (typeof count !== "number" || count < 0 || Number.isNaN(count)) throw new RangeError('The "n" argument is out of range.'); + if (!targets.length) EventEmitter.defaultMaxListeners = count; + for (const target of targets) { + if (typeof target.setMaxListeners === "function") target.setMaxListeners(count); + else if (typeof target.addEventListener === "function") targetLimits.set(target, count); + else throw new TypeError("The target must be an EventEmitter or EventTarget."); + } +}; +var EventEmitterAsyncResource = class extends EventEmitter { + constructor(options = {}) { + if (typeof options === "string") options = { name: options }; + super(options); + const { AsyncResource } = require("async_hooks"); + this.asyncResource = new AsyncResource(options.name || new.target.name, options); + } + emit(name, ...args) { + return this.asyncResource.runInAsyncScope(super.emit, this, name, ...args); + } + emitDestroy() { + this.asyncResource.emitDestroy(); + } + get asyncId() { + return this.asyncResource.asyncId(); + } + get triggerAsyncId() { + return this.asyncResource.triggerAsyncId(); + } +}; +EventEmitter.EventEmitterAsyncResource = EventEmitterAsyncResource; +module.exports = EventEmitter; diff --git a/src/Node/Lib/fetch.cjs b/src/Node/Lib/fetch.cjs new file mode 100644 index 00000000..21c3184d --- /dev/null +++ b/src/Node/Lib/fetch.cjs @@ -0,0 +1,88 @@ +'use strict'; + +const http = require('http'); +const https = require('https'); +const { Buffer } = require('buffer'); +const { Readable } = require('stream'); +const zlib = require('zlib'); + +module.exports = async function fetchTransport(request, originalBytes, cookieGet, cookieSet, finalize, Response) { + const signal = request.signal; + const headers = new Headers(request.headers); + if (!headers.has('accept')) headers.set('accept', '*/*'); + if (!headers.has('accept-language')) headers.set('accept-language', '*'); + if (!headers.has('user-agent')) headers.set('user-agent', 'phasis'); + if (!headers.has('accept-encoding')) headers.set('accept-encoding', 'gzip, deflate, br'); + let url = new URL(request.url), method = request.method, body = request.body; + let replay = originalBytes === null ? null : Buffer.from(originalBytes); + for (let hops = 0; ; hops++) { + if (signal.aborted) throw signal.reason; + if (!['http:', 'https:'].includes(url.protocol)) throw new TypeError('fetch failed: unsupported URL scheme'); + if (url.username || url.password) throw new TypeError('Request cannot be constructed from a URL that includes credentials'); + const outgoing = {}; + for (const [name, value] of headers) outgoing[name] = value; + const cookie = cookieGet(url.href); + if (cookie) outgoing.cookie = outgoing.cookie ? outgoing.cookie + '; ' + cookie : cookie; + if (body && replay !== null && !headers.has('content-length')) outgoing['content-length'] = String(replay.length); + const response = await new Promise((resolve, reject) => { + let responseStarted = false; + const transport = url.protocol === 'https:' ? https : http; + const req = transport.request(url, { method, headers: outgoing }, incoming => { + responseStarted = true; + for (let i = 0; i < incoming.rawHeaders.length; i += 2) if (incoming.rawHeaders[i].toLowerCase() === 'set-cookie') cookieSet(url.href, incoming.rawHeaders[i + 1]); + resolve(incoming); + }); + const abort = () => { const error = signal.reason; req.destroy(error instanceof Error ? error : new Error('The operation was aborted')); if (req.res) req.res.destroy(error); reject(error); }; + signal.addEventListener('abort', abort, { once: true }); + req.once('close', () => signal.removeEventListener('abort', abort)); + req.on('error', error => { if (!responseStarted) reject(signal.aborted ? signal.reason : new TypeError('fetch failed', { cause: error })); }); + if (!body) { req.end(); return; } + const reader = body.getReader(); + const pump = async () => { + try { + for (;;) { + const { value, done } = await reader.read(); + if (done) break; + if (!(value instanceof Uint8Array)) throw new TypeError('ReadableStream body chunks must be Uint8Array'); + if (!req.write(Buffer.from(value))) await new Promise((resolve, reject) => { req.once('drain', resolve); req.once('error', reject); }); + } + req.end(); + } catch (error) { req.destroy(error); reject(error); } + finally { reader.releaseLock(); } + }; + pump(); + }); + const status = response.statusCode; + const location = response.headers.location; + if ([301, 302, 303, 307, 308].includes(status) && location && request.redirect !== 'manual') { + response.resume(); + if (request.redirect === 'error') throw new TypeError('fetch failed: unexpected redirect'); + if (hops >= 20) throw new TypeError('fetch failed: redirect count exceeded'); + const next = new URL(location, url); + if (next.origin !== url.origin) for (const name of ['authorization', 'proxy-authorization', 'cookie', 'host']) headers.delete(name); + if (((status === 301 || status === 302) && method === 'POST') || (status === 303 && method !== 'GET' && method !== 'HEAD')) { + method = 'GET'; body = null; replay = null; + for (const name of ['content-encoding', 'content-language', 'content-location', 'content-type', 'content-length']) headers.delete(name); + } else if (body) { + if (replay === null) throw new TypeError('fetch failed: cannot replay a streamed request body'); + body = new ReadableStream({ start(controller) { controller.enqueue(new Uint8Array(replay)); controller.close(); } }); + } + url = next; + continue; + } + let stream = response; + const encodings = String(response.headers['content-encoding'] || '').split(',').map(value => value.trim()).filter(Boolean).reverse(); + if (method !== 'HEAD' && ![204, 205, 304].includes(status)) { + for (const encoding of encodings) { + const decoder = encoding === 'gzip' || encoding === 'x-gzip' ? zlib.createGunzip() : encoding === 'deflate' ? zlib.createInflate() : encoding === 'br' ? zlib.createBrotliDecompress() : null; + if (decoder) { const source = stream; source.on('error', error => decoder.destroy(error)); stream = source.pipe(decoder); } + } + } + const headerPairs = []; + for (let i = 0; i < response.rawHeaders.length; i += 2) headerPairs.push([response.rawHeaders[i], response.rawHeaders[i + 1]]); + const nullBody = method === 'HEAD' || [204, 205, 304].includes(status); + if (nullBody) response.resume(); + const result = new Response(nullBody ? null : Readable.toWeb(stream), { status, statusText: response.statusMessage || '', headers: headerPairs }); + return finalize(result, url.href, hops > 0); + } +}; diff --git a/src/Node/Lib/fs.cjs b/src/Node/Lib/fs.cjs new file mode 100644 index 00000000..7bc866b1 --- /dev/null +++ b/src/Node/Lib/fs.cjs @@ -0,0 +1,535 @@ +'use strict'; + +const { Buffer } = require('buffer'); +const { Readable, Writable } = require('stream'); +const { EventEmitter } = require('events'); +const pathModule = require('path'); +const host = __phasisNodeHost.fs; +const fs = module.exports; +const customPromisify = Symbol.for('nodejs.util.promisify.custom'); + +function coded(ErrorClass, code, message) { + return Object.assign(new ErrorClass(message), { code }); +} +function argument(name, expected) { + throw coded(TypeError, 'ERR_INVALID_ARG_TYPE', `The "${name}" argument must be ${expected}`); +} +function integer(value, name, min = 0, max = Number.MAX_SAFE_INTEGER) { + if (typeof value !== 'number') argument(name, 'of type number'); + if (!Number.isInteger(value) || value < min || value > max) { + throw coded(RangeError, 'ERR_OUT_OF_RANGE', `The value of "${name}" is out of range. It must be >= ${min} and <= ${max}. Received ${value}`); + } + return value; +} +function pathValue(value) { + if (value instanceof URL) { + if (value.protocol !== 'file:') throw coded(TypeError, 'ERR_INVALID_URL_SCHEME', 'The URL must be of scheme file'); + if (value.hostname && value.hostname !== 'localhost') throw coded(TypeError, 'ERR_INVALID_FILE_URL_HOST', 'File URL host must be "localhost" or empty'); + if (/%2f|%5c/i.test(value.pathname)) throw coded(TypeError, 'ERR_INVALID_FILE_URL_PATH', 'File URL path must not include encoded path separators'); + value = decodeURIComponent(value.pathname); + } else if (Buffer.isBuffer(value)) value = value.toString(); + if (typeof value !== 'string') argument('path', 'a string, Buffer, or URL'); + if (value.includes('\0')) throw coded(TypeError, 'ERR_INVALID_ARG_VALUE', 'The argument \'path\' must be a string, Uint8Array, or URL without null bytes'); + return value; +} +function options(value, defaults = {}) { + if (value == null) return { ...defaults }; + if (typeof value === 'string') return { ...defaults, encoding: value }; + if (typeof value !== 'object') argument('options', 'a string or object'); + return { ...defaults, ...value }; +} +function encoding(value) { + if (value != null && value !== 'buffer' && !Buffer.isEncoding(value)) { + throw coded(TypeError, 'ERR_INVALID_ARG_VALUE', `The argument 'encoding' is invalid. Received '${value}'`); + } + return value; +} +function decode(value, selected) { + const result = Buffer.from(value.buffer, value.byteOffset, value.byteLength); + return selected == null || selected === 'buffer' ? result : result.toString(encoding(selected)); +} +function view(value) { + if (!ArrayBuffer.isView(value)) argument('buffer', 'a Buffer, TypedArray, or DataView'); + return new Uint8Array(value.buffer, value.byteOffset, value.byteLength); +} +function modeValue(value, fallback = 0o666) { + if (value === undefined) return fallback; + if (typeof value === 'string' && /^[0-7]+$/.test(value)) value = parseInt(value, 8); + return integer(value, 'mode', 0, 0xffffffff); +} +function call(operation, ...args) { + const result = host.call(operation, ...args); + if (result.error) { + const { message, ...properties } = result.error; + throw Object.assign(new Error(message), properties); + } + return result.value; +} +function callback(value) { + if (typeof value !== 'function') argument('cb', 'of type function'); + return value; +} +function later(fn, args, cb, map = value => [value]) { + callback(cb); + process.nextTick(() => { + let result; + try { result = map(fn(...args)); } + catch (error) { cb(error); return; } + cb(null, ...result); + }); +} +function abort(signal) { + if (signal?.aborted) throw Object.assign(new Error('The operation was aborted', { cause: signal.reason }), { name: 'AbortError', code: 'ABORT_ERR' }); +} + +const darwin = process.platform === 'darwin'; +const constants = fs.constants = Object.freeze({ + F_OK: 0, R_OK: 4, W_OK: 2, X_OK: 1, + O_RDONLY: 0, O_WRONLY: 1, O_RDWR: 2, + O_CREAT: darwin ? 512 : 64, O_EXCL: darwin ? 2048 : 128, + O_TRUNC: darwin ? 1024 : 512, O_APPEND: darwin ? 8 : 1024, + O_NONBLOCK: darwin ? 4 : 2048, O_NOCTTY: darwin ? 131072 : 256, + O_DIRECTORY: darwin ? 1048576 : 65536, O_NOFOLLOW: darwin ? 256 : 131072, + O_SYNC: darwin ? 128 : 1052672, O_DSYNC: darwin ? 4194304 : 4096, + S_IFMT: 0o170000, S_IFREG: 0o100000, S_IFDIR: 0o040000, + S_IFCHR: 0o020000, S_IFBLK: 0o060000, S_IFIFO: 0o010000, + S_IFLNK: 0o120000, S_IFSOCK: 0o140000, + S_IRWXU: 0o700, S_IRUSR: 0o400, S_IWUSR: 0o200, S_IXUSR: 0o100, + S_IRWXG: 0o070, S_IRGRP: 0o040, S_IWGRP: 0o020, S_IXGRP: 0o010, + S_IRWXO: 0o007, S_IROTH: 0o004, S_IWOTH: 0o002, S_IXOTH: 0o001, + COPYFILE_EXCL: 1, COPYFILE_FICLONE: 2, COPYFILE_FICLONE_FORCE: 4, + UV_FS_COPYFILE_EXCL: 1, UV_FS_COPYFILE_FICLONE: 2, UV_FS_COPYFILE_FICLONE_FORCE: 4, + UV_FS_SYMLINK_DIR: 1, UV_FS_SYMLINK_JUNCTION: 2, +}); +for (const name of ['F_OK', 'R_OK', 'W_OK', 'X_OK']) fs[name] = constants[name]; +function flagValue(flags = 'r') { + if (typeof flags === 'number') { + integer(flags, 'flags', 0, 0xffffffff); + const access = flags & 3; + const create = (flags & constants.O_CREAT) !== 0; + const exclusive = (flags & constants.O_EXCL) !== 0; + const append = (flags & constants.O_APPEND) !== 0; + const truncate = (flags & constants.O_TRUNC) !== 0; + // c/c+ preserve existing contents while allowing O_CREAT without O_TRUNC. + const base = append ? 'a' : truncate ? 'w' : create ? 'c' : 'r'; + return base + (exclusive && create ? 'x' : '') + (access === 2 || (access === 1 && base === 'r') ? '+' : ''); + } + if (typeof flags !== 'string') argument('flags', 'a string or number'); + if (!['r', 'r+', 'rs', 'rs+', 'sr', 'sr+', 'w', 'wx', 'xw', 'w+', 'wx+', 'xw+', 'a', 'ax', 'xa', 'a+', 'ax+', 'xa+', 'as', 'as+'].includes(flags)) { + throw coded(TypeError, 'ERR_INVALID_ARG_VALUE', `The argument 'flags' is invalid. Received '${flags}'`); + } + return flags.replace('s', '').replace(/^x([wa])/, '$1x'); +} +fs.openSync = (path, flags, mode) => call('open', pathValue(path), flagValue(flags), modeValue(mode)); +fs.closeSync = fd => call('close', integer(fd, 'fd', 0, 0x7fffffff)); +fs.open = function (path, flags, mode, cb) { + if (typeof flags === 'function') { cb = flags; flags = 'r'; mode = undefined; } + else if (typeof mode === 'function') { cb = mode; mode = undefined; } + later(fs.openSync, [path, flags, mode], cb); +}; +fs.close = (fd, cb = () => {}) => later(fs.closeSync, [fd], cb, () => []); + +function readArguments(buffer, offset, length, position) { + if (!ArrayBuffer.isView(buffer)) { + const config = options(buffer); + buffer = config.buffer ?? Buffer.alloc(16384); + offset = config.offset ?? 0; length = config.length ?? buffer.byteLength - offset; position = config.position ?? null; + } else if (offset !== null && typeof offset === 'object') { + const config = offset; + offset = config.offset ?? 0; length = config.length ?? buffer.byteLength - offset; position = config.position ?? null; + } else { + offset ??= 0; length ??= buffer.byteLength - offset; position ??= null; + } + const bytes = view(buffer); + integer(offset, 'offset', 0, bytes.byteLength); + integer(length, 'length', 0, bytes.byteLength - offset); + if (position != null && position !== -1) integer(position, 'position'); + return { buffer, bytes, offset, length, position }; +} +fs.readSync = function (fd, buffer, offset, length, position) { + integer(fd, 'fd', 0, 0x7fffffff); + const config = readArguments(buffer, offset, length, position); + return call('read', fd, config.bytes, config.offset, config.length, config.position); +}; +fs.read = function (fd, ...args) { + const cb = callback(args.pop()); + const config = readArguments(...args); + later(fs.readSync, [fd, config.buffer, config.offset, config.length, config.position], cb, bytesRead => [bytesRead, config.buffer]); +}; +fs.writeSync = function (fd, data, offset, length, position) { + integer(fd, 'fd', 0, 0x7fffffff); + if (typeof data === 'string') { + position = offset ?? null; + data = Buffer.from(data, encoding(length) ?? 'utf8'); + offset = 0; length = data.length; + } else if (offset !== null && typeof offset === 'object') { + const config = offset; + offset = config.offset ?? 0; length = config.length ?? data.byteLength - offset; position = config.position ?? null; + } else { + offset ??= 0; length ??= data.byteLength - offset; position ??= null; + } + const bytes = view(data); + integer(offset, 'offset', 0, bytes.byteLength); + integer(length, 'length', 0, bytes.byteLength - offset); + if (position != null && position !== -1) integer(position, 'position'); + return call('write', fd, bytes, offset, length, position); +}; +fs.write = function (fd, data, ...args) { + const cb = callback(args.pop()); + later(fs.writeSync, [fd, data, ...args], cb, bytesWritten => [bytesWritten, data]); +}; +for (const operation of ['read', 'write']) { + const resultName = operation === 'read' ? 'bytesRead' : 'bytesWritten'; + fs[operation][customPromisify] = (...args) => new Promise((resolve, reject) => fs[operation](...args, (error, count, buffer) => error ? reject(error) : resolve({ [resultName]: count, buffer }))); + fs[operation + 'vSync'] = (fd, buffers, position = null) => { + if (!Array.isArray(buffers)) argument('buffers', 'an array'); + let total = 0; + for (const buffer of buffers) { + const count = fs[operation + 'Sync'](fd, buffer, 0, buffer.byteLength, position == null ? null : position + total); + total += count; + if (operation === 'read' && count < buffer.byteLength) break; + } + return total; + }; + fs[operation + 'v'] = (fd, buffers, position, cb) => { + if (typeof position === 'function') { cb = position; position = null; } + later(fs[operation + 'vSync'], [fd, buffers, position], cb, count => [count, buffers]); + }; + fs[operation + 'v'][customPromisify] = (...args) => new Promise((resolve, reject) => fs[operation + 'v'](...args, (error, count, buffers) => error ? reject(error) : resolve({ [resultName]: count, buffers }))); +} + +fs.readFileSync = function (file, value) { + const config = options(value, { encoding: null, flag: 'r' }); + encoding(config.encoding); abort(config.signal); + const owns = typeof file !== 'number'; + const fd = owns ? fs.openSync(file, config.flag) : integer(file, 'fd', 0, 0x7fffffff); + try { return decode(call('readAll', fd), config.encoding); } + finally { if (owns) fs.closeSync(fd); } +}; +fs.writeFileSync = function (file, data, value) { + const config = options(value, { encoding: 'utf8', flag: 'w', mode: 0o666 }); + encoding(config.encoding); abort(config.signal); + const bytes = typeof data === 'string' ? Buffer.from(data, config.encoding) : view(data); + const owns = typeof file !== 'number'; + const fd = owns ? fs.openSync(file, config.flag, config.mode) : integer(file, 'fd', 0, 0x7fffffff); + try { + let offset = 0; + while (offset < bytes.byteLength) { + const count = fs.writeSync(fd, bytes, offset, bytes.byteLength - offset, null); + if (!count) throw coded(Error, 'EIO', 'EIO: i/o error, write'); + offset += count; + } + if (config.flush) fs.fsyncSync(fd); + } finally { if (owns) fs.closeSync(fd); } +}; +fs.appendFileSync = (file, data, value) => fs.writeFileSync(file, data, options(value, { flag: 'a' })); + +class Stats { + constructor(data, bigint = false) { + if (!data) return; + for (const [key, value] of Object.entries(data)) this[key] = bigint ? BigInt(Math.trunc(value)) : value; + for (const key of ['atime', 'mtime', 'ctime', 'birthtime']) { + this[key] = new Date(Number(this[key + 'Ms'])); + if (bigint) this[key + 'Ns'] = this[key + 'Ms'] * 1000000n; + } + } + _is(type) { return Number(this.mode) % 0x10000 & constants.S_IFMT ? (Number(this.mode) & constants.S_IFMT) === type : false; } + isFile() { return this._is(constants.S_IFREG); } + isDirectory() { return this._is(constants.S_IFDIR); } + isBlockDevice() { return this._is(constants.S_IFBLK); } + isCharacterDevice() { return this._is(constants.S_IFCHR); } + isSymbolicLink() { return this._is(constants.S_IFLNK); } + isFIFO() { return this._is(constants.S_IFIFO); } + isSocket() { return this._is(constants.S_IFSOCK); } +} +fs.Stats = Stats; +for (const operation of ['stat', 'lstat', 'fstat']) { + fs[operation + 'Sync'] = (path, value) => { + const config = options(value); + try { + return new Stats(call(operation, operation === 'fstat' ? integer(path, 'fd', 0, 0x7fffffff) : pathValue(path)), config.bigint); + } catch (error) { + if (config.throwIfNoEntry === false && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) return undefined; + throw error; + } + }; +} +class Dirent extends Stats { + constructor(name, mode, parentPath) { + super(); this.name = name; this.parentPath = parentPath; + Object.defineProperty(this, 'mode', { value: mode }); + } +} +fs.Dirent = Dirent; +fs.readdirSync = function (path, value) { + path = pathValue(path); + const config = options(value, { encoding: 'utf8' }); + encoding(config.encoding); + const result = []; + const walk = (current, prefix) => { + const entries = call('readdir', current); + for (const entry of entries) { + const name = decode(entry.name, config.encoding); + const rawName = decode(entry.name, 'utf8'); + result.push(config.withFileTypes ? new Dirent(name, entry.mode, current) : (prefix ? (config.encoding === 'buffer' ? Buffer.from(prefix + rawName) : prefix + name) : name)); + } + if (config.recursive) for (const entry of entries) { + if ((entry.mode & constants.S_IFMT) === constants.S_IFDIR) { + const name = decode(entry.name, 'utf8'); + walk(pathModule.join(current, name), prefix + name + pathModule.sep); + } + } + }; + walk(path, ''); + return result; +}; +fs.existsSync = path => { try { return call('exists', pathValue(path)); } catch { return false; } }; +fs.exists = (path, cb) => { callback(cb); process.nextTick(() => cb(fs.existsSync(path))); }; +fs.accessSync = (path, mode = 0) => call('access', pathValue(path), integer(mode, 'mode', 0, 7)); +fs.mkdirSync = (path, value) => { + const config = typeof value === 'number' || typeof value === 'string' ? { mode: value } : options(value); + return call('mkdir', pathValue(path), modeValue(config.mode, 0o777), !!config.recursive); +}; +fs.mkdtempSync = (prefix, value) => decode(call('mkdtemp', pathValue(prefix)), encoding(options(value, { encoding: 'utf8' }).encoding)); +for (const operation of ['realpath', 'readlink']) { + fs[operation + 'Sync'] = (path, value) => decode(call(operation, pathValue(path)), encoding(options(value, { encoding: 'utf8' }).encoding)); +} +for (const operation of ['rename', 'link']) fs[operation + 'Sync'] = (first, second) => call(operation, pathValue(first), pathValue(second)); +fs.symlinkSync = (target, path, type) => call('symlink', pathValue(target), pathValue(path), type); +fs.copyFileSync = (source, destination, mode = 0) => call('copyFile', pathValue(source), pathValue(destination), integer(mode, 'mode', 0, 7)); +fs.unlinkSync = path => call('unlink', pathValue(path)); +fs.rmdirSync = (path, value) => { + if (options(value).recursive) return fs.rmSync(path, { ...value, recursive: true }); + return call('rmdir', pathValue(path)); +}; +fs.rmSync = function (path, value) { + path = pathValue(path); + const config = options(value); + let stat; + try { stat = fs.lstatSync(path); } + catch (error) { if (config.force && error.code === 'ENOENT') return; throw error; } + if (!stat.isDirectory()) return fs.unlinkSync(path); + if (!config.recursive) throw Object.assign(coded(Error, 'ERR_FS_EISDIR', `Path is a directory: rm returned EISDIR (is a directory) ${path}`), { syscall: 'rm', path }); + for (const name of fs.readdirSync(path)) fs.rmSync(pathModule.join(path, name), config); + return call('rmdir', path); +}; +fs.chmodSync = (path, mode) => call('chmod', pathValue(path), modeValue(mode)); +for (const operation of ['chown', 'lchown']) fs[operation + 'Sync'] = (path, uid, gid) => call(operation, pathValue(path), integer(uid, 'uid', -1, 0xffffffff), integer(gid, 'gid', -1, 0xffffffff)); +function timeValue(value) { + if (value instanceof Date) value = value.getTime() / 1000; + else if (typeof value === 'string' && value.trim()) value = Number(value); + if (typeof value !== 'number' || !Number.isFinite(value)) argument('time', 'a number, numeric string, or Date'); + return value < 0 ? Date.now() / 1000 : value; +} +fs.utimesSync = (path, atime, mtime) => call('utimes', pathValue(path), timeValue(atime), timeValue(mtime)); +fs.ftruncateSync = (fd, length = 0) => call('ftruncate', integer(fd, 'fd', 0, 0x7fffffff), integer(Math.max(length, 0), 'len')); +fs.truncateSync = function (path, length = 0) { + if (typeof path === 'number') return fs.ftruncateSync(path, length); + const fd = fs.openSync(path, 'r+'); + try { fs.ftruncateSync(fd, length); } finally { fs.closeSync(fd); } +}; +for (const operation of ['fsync', 'fdatasync']) fs[operation + 'Sync'] = fd => call(operation, integer(fd, 'fd', 0, 0x7fffffff)); +fs.cpSync = function (source, destination, value) { + source = pathValue(source); destination = pathValue(destination); + const config = options(value, { force: true }); + if (config.filter && !config.filter(source, destination)) return; + const stat = (config.dereference ? fs.statSync : fs.lstatSync)(source); + if (stat.isDirectory()) { + if (!config.recursive) throw coded(Error, 'ERR_FS_EISDIR', `Path is a directory: ${source}`); + const relative = pathModule.relative(pathModule.resolve(source), pathModule.resolve(destination)); + if (relative === '' || (!relative.startsWith('..' + pathModule.sep) && relative !== '..' && !pathModule.isAbsolute(relative))) { + throw coded(Error, 'ERR_FS_CP_EINVAL', 'Cannot copy a directory into itself'); + } + fs.mkdirSync(destination, { recursive: true, mode: Number(stat.mode) & 0o777 }); + for (const name of fs.readdirSync(source)) fs.cpSync(pathModule.join(source, name), pathModule.join(destination, name), config); + } else { + const targetExists = fs.lstatSync(destination, { throwIfNoEntry: false }); + if (targetExists && !config.force) { + if (config.errorOnExist) throw coded(Error, 'ERR_FS_CP_EEXIST', `Target already exists: ${destination}`); + return; + } + fs.mkdirSync(pathModule.dirname(destination), { recursive: true }); + if (stat.isSymbolicLink()) { + if (targetExists) fs.unlinkSync(destination); + let target = fs.readlinkSync(source); + if (!config.verbatimSymlinks) target = pathModule.resolve(pathModule.dirname(source), target); + fs.symlinkSync(target, destination); + } else fs.copyFileSync(source, destination, config.mode ?? 0); + } + if (config.preserveTimestamps && !stat.isSymbolicLink()) fs.utimesSync(destination, stat.atime, stat.mtime); +}; + +const noResult = new Set(['writeFile', 'appendFile', 'access', 'copyFile', 'cp', 'rename', 'link', 'symlink', 'unlink', 'rm', 'rmdir', 'chmod', 'chown', 'lchown', 'utimes', 'truncate', 'ftruncate', 'fsync', 'fdatasync']); +for (const name of ['readFile', 'writeFile', 'appendFile', 'stat', 'lstat', 'fstat', 'readdir', 'access', 'mkdir', 'mkdtemp', 'realpath', 'readlink', 'copyFile', 'cp', 'rename', 'link', 'symlink', 'unlink', 'rm', 'rmdir', 'chmod', 'chown', 'lchown', 'utimes', 'truncate', 'ftruncate', 'fsync', 'fdatasync']) { + fs[name] = (...args) => later(fs[name + 'Sync'], args.slice(0, -1), callback(args.at(-1)), noResult.has(name) ? () => [] : value => [value]); +} +fs.realpath.native = fs.realpath; +fs.realpathSync.native = fs.realpathSync; + +class ReadStream extends Readable { + constructor(path, value) { + const config = options(value); + super({ ...config, highWaterMark: config.highWaterMark ?? 64 * 1024, autoDestroy: config.autoClose !== false }); + this.path = path; + this.flags = config.flags ?? 'r'; + this.mode = modeValue(config.mode); + this.start = config.start; + this.end = config.end ?? Infinity; + if (this.start !== undefined) integer(this.start, 'start'); + if (this.end !== Infinity) integer(this.end, 'end', this.start ?? 0); + this.pos = this.start; + this.bytesRead = 0; + this.autoClose = config.autoClose !== false; + this._fs = config.fs ?? fs; + this._handle = config.fd instanceof FileHandle ? config.fd : null; + this.fd = this._handle ? this._handle.fd : config.fd ?? null; + if (this.fd === null) pathValue(path); + else integer(this.fd, 'fd', 0, 0x7fffffff); + } + get pending() { return this.fd === null; } + _construct(done) { + if (this.fd !== null) { done(); return; } + this._fs.open(this.path, this.flags, this.mode, (error, fd) => { + if (error) { done(error); return; } + this.fd = fd; this.emit('open', fd); this.emit('ready'); done(); + }); + } + _read(size) { + if (this.destroyed) return; + const position = this.pos ?? this.bytesRead; + const length = Math.min(size, this.end - position + 1); + if (length <= 0) { this.push(null); return; } + const buffer = Buffer.allocUnsafe(length); + this._fs.read(this.fd, buffer, 0, length, this.pos ?? null, (error, count) => { + if (error) { this.destroy(error); return; } + if (this.pos !== undefined) this.pos += count; + this.bytesRead += count; + this.push(count ? buffer.subarray(0, count) : null); + }); + } + _destroy(error, done) { closeStream(this, error, done); } + close(cb) { if (cb) this.once('close', cb); this.autoClose = true; this.destroy(); } +} +class WriteStream extends Writable { + constructor(path, value) { + const config = options(value); + super({ ...config, autoDestroy: config.autoClose !== false }); + this.path = path; this.flags = config.flags ?? 'w'; this.mode = modeValue(config.mode); + this.start = config.start; + if (this.start !== undefined) integer(this.start, 'start'); + this.pos = this.start; this.bytesWritten = 0; + this.autoClose = config.autoClose !== false; this.flush = config.flush === true; + this._fs = config.fs ?? fs; + this._handle = config.fd instanceof FileHandle ? config.fd : null; + this.fd = this._handle ? this._handle.fd : config.fd ?? null; + if (this.fd === null) pathValue(path); + else integer(this.fd, 'fd', 0, 0x7fffffff); + } + get pending() { return this.fd === null; } + _construct(done) { ReadStream.prototype._construct.call(this, done); } + _write(chunk, selectedEncoding, done) { + const bytes = typeof chunk === 'string' ? Buffer.from(chunk, selectedEncoding) : chunk; + let offset = 0; + const write = () => this._fs.write(this.fd, bytes, offset, bytes.length - offset, this.pos ?? null, (error, count) => { + if (error) { done(error); return; } + if (!count && offset < bytes.length) { done(coded(Error, 'EIO', 'EIO: i/o error, write')); return; } + offset += count; this.bytesWritten += count; + if (this.pos !== undefined) this.pos += count; + if (offset < bytes.length) write(); else done(); + }); + write(); + } + _writev(chunks, done) { this._write(Buffer.concat(chunks.map(entry => entry.chunk)), 'buffer', done); } + _final(done) { if (this.flush) this._fs.fsync(this.fd, done); else done(); } + _destroy(error, done) { closeStream(this, error, done); } + close(cb) { if (cb) this.once('close', cb); this.autoClose = true; this.end(); } + destroySoon() { this.end(); } +} +function closeStream(stream, error, done) { + if (!stream.autoClose || stream.fd === null) { done(error); return; } + const fd = stream.fd; stream.fd = null; + if (stream._handle) stream._handle.close().then(() => done(error), closeError => done(error || closeError)); + else stream._fs.close(fd, closeError => done(error || closeError)); +} +fs.ReadStream = fs.FileReadStream = ReadStream; +fs.WriteStream = fs.FileWriteStream = WriteStream; +fs.createReadStream = (path, value) => new ReadStream(path, value); +fs.createWriteStream = (path, value) => new WriteStream(path, value); + +class Dir { + constructor(path, config) { this.path = path; this._entries = fs.readdirSync(path, { ...config, withFileTypes: true }); this._closed = false; } + readSync() { + if (this._closed) throw coded(Error, 'ERR_DIR_CLOSED', 'Directory handle was closed'); + return this._entries.shift() ?? null; + } + read(cb) { + if (cb !== undefined) { later(() => this.readSync(), [], cb); return; } + return Promise.resolve().then(() => this.readSync()); + } + closeSync() { + if (this._closed) throw coded(Error, 'ERR_DIR_CLOSED', 'Directory handle was closed'); + this._closed = true; this._entries = []; + } + close(cb) { + if (cb !== undefined) { later(() => this.closeSync(), [], cb, () => []); return; } + return Promise.resolve().then(() => this.closeSync()); + } + async *[Symbol.asyncIterator]() { + try { let entry; while ((entry = await this.read()) !== null) yield entry; } + finally { if (!this._closed) await this.close(); } + } + [Symbol.asyncDispose]() { return this.close(); } + [Symbol.dispose]() { this.closeSync(); } +} +fs.Dir = Dir; +fs.opendirSync = (path, value) => new Dir(pathValue(path), options(value)); +fs.opendir = (...args) => later(fs.opendirSync, args.slice(0, -1), callback(args.at(-1))); + +const promises = fs.promises = { constants }; +for (const name of ['readFile', 'writeFile', 'appendFile', 'stat', 'lstat', 'readdir', 'access', 'mkdir', 'mkdtemp', 'realpath', 'readlink', 'copyFile', 'cp', 'rename', 'link', 'symlink', 'unlink', 'rm', 'rmdir', 'chmod', 'chown', 'lchown', 'utimes', 'truncate', 'opendir']) { + promises[name] = (...args) => new Promise((resolve, reject) => fs[name](...args, (error, value) => error ? reject(error) : resolve(value))); +} +class FileHandle extends EventEmitter { + constructor(fd) { super(); this._fd = fd; this._closing = null; } + get fd() { return this._fd; } + close() { + if (this._closing) return this._closing; + if (this._fd === -1) return Promise.resolve(); + const fd = this._fd; this._fd = -1; + this._closing = new Promise((resolve, reject) => fs.close(fd, error => { + if (error) { reject(error); return; } + this.emit('close'); resolve(); + })); + return this._closing; + } + _check(syscall) { if (this._fd === -1) throw Object.assign(coded(Error, 'EBADF', 'file closed'), { errno: -9, syscall }); } + async read(...args) { this._check('read'); return fs.read[customPromisify](this._fd, ...args); } + async write(...args) { this._check('write'); return fs.write[customPromisify](this._fd, ...args); } + async readv(...args) { this._check('readv'); return fs.readv[customPromisify](this._fd, ...args); } + async writev(...args) { this._check('writev'); return fs.writev[customPromisify](this._fd, ...args); } + createReadStream(value) { this._check('read'); return new ReadStream(undefined, { ...options(value), fd: this }); } + createWriteStream(value) { this._check('write'); return new WriteStream(undefined, { ...options(value), fd: this }); } + readableWebStream(value = {}) { return Readable.toWeb(this.createReadStream({ autoClose: !!value.autoClose })); } + [Symbol.asyncDispose]() { return this.close(); } +} +for (const [method, operation] of Object.entries({ readFile: 'readFile', writeFile: 'writeFile', appendFile: 'appendFile', stat: 'fstat', truncate: 'ftruncate', sync: 'fsync', datasync: 'fdatasync' })) { + FileHandle.prototype[method] = async function (...args) { + this._check(method); + return new Promise((resolve, reject) => fs[operation](this._fd, ...args, (error, value) => error ? reject(error) : resolve(value))); + }; +} +promises.open = (path, flags, mode) => new Promise((resolve, reject) => fs.open(path, flags, mode, (error, fd) => error ? reject(error) : resolve(new FileHandle(fd)))); +promises.readFile = (file, value) => file instanceof FileHandle ? file.readFile(value) : new Promise((resolve, reject) => fs.readFile(file, value, (error, data) => error ? reject(error) : resolve(data))); +for (const name of ['writeFile', 'appendFile']) { + promises[name] = async (file, data, value) => { + if (file instanceof FileHandle) return file[name](data, value); + if (typeof data !== 'string' && !ArrayBuffer.isView(data) && data != null && (data[Symbol.asyncIterator] || data[Symbol.iterator])) { + const config = options(value, { flag: name === 'appendFile' ? 'a' : 'w', mode: 0o666 }); + const handle = await promises.open(file, config.flag, config.mode); + try { for await (const chunk of data) { abort(config.signal); await handle.writeFile(chunk, config); } } + finally { await handle.close(); } + return; + } + return new Promise((resolve, reject) => fs[name](file, data, value, error => error ? reject(error) : resolve())); + }; +} diff --git a/src/Node/Lib/http-common.cjs b/src/Node/Lib/http-common.cjs new file mode 100644 index 00000000..7b1ceb09 --- /dev/null +++ b/src/Node/Lib/http-common.cjs @@ -0,0 +1,45 @@ +'use strict'; + +const { HTTPParser: Parser, methods } = require('./http-parser.cjs'); +const { executionAsyncId } = require('async_hooks'); +const { Buffer } = require('buffer'); + +class HTTPParser { + constructor() { + this._parser = null; + this._paused = false; + this._pending = []; + this._asyncId = executionAsyncId(); + } + initialize(type, resource, maxHeaderSize = 0) { + if (type !== HTTPParser.REQUEST && type !== HTTPParser.RESPONSE) throw new TypeError('Invalid HTTP parser type'); + this._parser = new Parser(type === HTTPParser.REQUEST ? Parser.REQUEST : Parser.RESPONSE); + if (maxHeaderSize) this._parser.maxHeaderSize = maxHeaderSize; + this._paused = false; + this._pending = []; + this._parser[Parser.kOnHeaders] = (headers, url) => this._call(HTTPParser.kOnHeaders, headers, url); + this._parser[Parser.kOnHeadersComplete] = info => this._call(HTTPParser.kOnHeadersComplete, info.versionMajor, info.versionMinor, info.headers, info.method, info.url, info.statusCode, info.statusMessage, info.upgrade, info.shouldKeepAlive); + this._parser[Parser.kOnBody] = chunk => this._call(HTTPParser.kOnBody, chunk); + this._parser[Parser.kOnMessageComplete] = () => this._call(HTTPParser.kOnMessageComplete); + for (const state of ['REQUEST_LINE', 'RESPONSE_LINE', 'HEADER', 'BODY_CHUNKHEAD', 'BODY_CHUNK', 'BODY_CHUNKEMPTYLINE', 'BODY_CHUNKTRAILERS', 'BODY_RAW', 'BODY_SIZED']) { + const execute = this._parser[state]; + this._parser[state] = (...args) => this._paused || execute.apply(this._parser, args); + } + } + _call(index, ...args) { return typeof this[index] === 'function' ? this[index](...args) : undefined; } + execute(bytes) { + if (!this._parser) throw new Error('HTTP parser has not been initialized'); + if (this._paused) { this._pending.push(Buffer.from(bytes)); return 0; } + const result = this._parser.execute(bytes); + if (typeof result === 'number' && result < bytes.length && this._paused) this._pending.push(Buffer.from(bytes.subarray(result))); + return result; + } + finish() { return this._parser && this._parser.finish(); } + pause() { this._paused = true; } + resume() { this._paused = false; while (!this._paused && this._pending.length) this.execute(this._pending.shift()); } + free() { this._parser = null; this._pending = []; } + close() { this.free(); } + getAsyncId() { return this._asyncId; } +} +Object.assign(HTTPParser, { REQUEST: 1, RESPONSE: 2, kOnMessageBegin: 0, kOnHeaders: 1, kOnHeadersComplete: 2, kOnBody: 3, kOnMessageComplete: 4, kOnExecute: 5, kOnTimeout: 6 }); +module.exports = { HTTPParser, methods }; diff --git a/src/Node/Lib/http-constants.cjs b/src/Node/Lib/http-constants.cjs new file mode 100644 index 00000000..8973273f --- /dev/null +++ b/src/Node/Lib/http-constants.cjs @@ -0,0 +1,106 @@ +'use strict'; +// Node.js 26.12.0 HTTP method and status registries. +module.exports = { + "methods": [ + "ACL", + "BIND", + "CHECKOUT", + "CONNECT", + "COPY", + "DELETE", + "GET", + "HEAD", + "LINK", + "LOCK", + "M-SEARCH", + "MERGE", + "MKACTIVITY", + "MKCALENDAR", + "MKCOL", + "MOVE", + "NOTIFY", + "OPTIONS", + "PATCH", + "POST", + "PROPFIND", + "PROPPATCH", + "PURGE", + "PUT", + "QUERY", + "REBIND", + "REPORT", + "SEARCH", + "SOURCE", + "SUBSCRIBE", + "TRACE", + "UNBIND", + "UNLINK", + "UNLOCK", + "UNSUBSCRIBE" + ], + "status": { + "100": "Continue", + "101": "Switching Protocols", + "102": "Processing", + "103": "Early Hints", + "200": "OK", + "201": "Created", + "202": "Accepted", + "203": "Non-Authoritative Information", + "204": "No Content", + "205": "Reset Content", + "206": "Partial Content", + "207": "Multi-Status", + "208": "Already Reported", + "226": "IM Used", + "300": "Multiple Choices", + "301": "Moved Permanently", + "302": "Found", + "303": "See Other", + "304": "Not Modified", + "305": "Use Proxy", + "307": "Temporary Redirect", + "308": "Permanent Redirect", + "400": "Bad Request", + "401": "Unauthorized", + "402": "Payment Required", + "403": "Forbidden", + "404": "Not Found", + "405": "Method Not Allowed", + "406": "Not Acceptable", + "407": "Proxy Authentication Required", + "408": "Request Timeout", + "409": "Conflict", + "410": "Gone", + "411": "Length Required", + "412": "Precondition Failed", + "413": "Payload Too Large", + "414": "URI Too Long", + "415": "Unsupported Media Type", + "416": "Range Not Satisfiable", + "417": "Expectation Failed", + "418": "I'm a Teapot", + "421": "Misdirected Request", + "422": "Unprocessable Entity", + "423": "Locked", + "424": "Failed Dependency", + "425": "Too Early", + "426": "Upgrade Required", + "428": "Precondition Required", + "429": "Too Many Requests", + "431": "Request Header Fields Too Large", + "451": "Unavailable For Legal Reasons", + "500": "Internal Server Error", + "501": "Not Implemented", + "502": "Bad Gateway", + "503": "Service Unavailable", + "504": "Gateway Timeout", + "505": "HTTP Version Not Supported", + "506": "Variant Also Negotiates", + "507": "Insufficient Storage", + "508": "Loop Detected", + "509": "Bandwidth Limit Exceeded", + "510": "Not Extended", + "511": "Network Authentication Required" + } +}; diff --git a/src/Node/Lib/http-parser.LICENSE.md b/src/Node/Lib/http-parser.LICENSE.md new file mode 100644 index 00000000..91e8ce10 --- /dev/null +++ b/src/Node/Lib/http-parser.LICENSE.md @@ -0,0 +1,110 @@ +Copyright (c) 2015 Tim Caswell (https://github.com/creationix) and other +contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +Some files from the tests folder are from joyent/node and mscedex/io.js, a fork +of nodejs/io.js: + +- tests/iojs/test-http-parser-durability.js + + This file is from https://github.com/mscdex/io.js/blob/js-http-parser/test/pummel/test-http-parser-durability.js + with modifications by Jan Schär (jscissr). + + """ + Copyright io.js contributors. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + """ + +- tests/fixtures/* + tests/parallel/* + tests/testpy/* + tests/common.js + tests/test.py + tests/utils.py + + These files are from https://github.com/nodejs/node with changes by + Jan Schär (jscissr). + + Node.js is licensed for use as follows: + + """ + Copyright Node.js contributors. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + """ + + This license applies to parts of Node.js originating from the + https://github.com/joyent/node repository: + + """ + Copyright Joyent, Inc. and other Node contributors. All rights reserved. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + """ + \ No newline at end of file diff --git a/src/Node/Lib/http-parser.cjs b/src/Node/Lib/http-parser.cjs new file mode 100644 index 00000000..3e98ab9a --- /dev/null +++ b/src/Node/Lib/http-parser.cjs @@ -0,0 +1,470 @@ +/*jshint node:true */ + +exports.HTTPParser = HTTPParser; +function HTTPParser(type) { + if (type !== undefined && type !== HTTPParser.REQUEST && type !== HTTPParser.RESPONSE) { + throw new Error('type must be REQUEST or RESPONSE'); + } + if (type === undefined) { + // Node v12+ + } else { + this.initialize(type); + } + this.maxHeaderSize=HTTPParser.maxHeaderSize +} +HTTPParser.prototype.initialize = function (type, async_resource) { + if (type !== HTTPParser.REQUEST && type !== HTTPParser.RESPONSE) { + throw new Error('type must be REQUEST or RESPONSE'); + } + this.type = type; + this.state = type + '_LINE'; + this.info = { + headers: [], + upgrade: false + }; + this.trailers = []; + this.line = ''; + this.isChunked = false; + this.connection = ''; + this.headerSize = 0; // for preventing too big headers + this.body_bytes = null; + this.isUserCall = false; + this.hadError = false; +}; + +HTTPParser.encoding = 'ascii'; +HTTPParser.maxHeaderSize = 80 * 1024; // maxHeaderSize (in bytes) is configurable, but 80kb by default; +HTTPParser.REQUEST = 'REQUEST'; +HTTPParser.RESPONSE = 'RESPONSE'; + +// Note: *not* starting with kOnHeaders=0 line the Node parser, because any +// newly added constants (kOnTimeout in Node v12.19.0) will overwrite 0! +var kOnHeaders = HTTPParser.kOnHeaders = 1; +var kOnHeadersComplete = HTTPParser.kOnHeadersComplete = 2; +var kOnBody = HTTPParser.kOnBody = 3; +var kOnMessageComplete = HTTPParser.kOnMessageComplete = 4; + +// Some handler stubs, needed for compatibility +HTTPParser.prototype[kOnHeaders] = +HTTPParser.prototype[kOnHeadersComplete] = +HTTPParser.prototype[kOnBody] = +HTTPParser.prototype[kOnMessageComplete] = function () {}; + +var compatMode0_12 = true; +Object.defineProperty(HTTPParser, 'kOnExecute', { + get: function () { + // hack for backward compatibility + compatMode0_12 = false; + return 99; + } + }); + +var methods = exports.methods = HTTPParser.methods = [ + 'DELETE', + 'GET', + 'HEAD', + 'POST', + 'PUT', + 'CONNECT', + 'OPTIONS', + 'TRACE', + 'COPY', + 'LOCK', + 'MKCOL', + 'MOVE', + 'PROPFIND', + 'PROPPATCH', + 'SEARCH', + 'UNLOCK', + 'BIND', + 'REBIND', + 'UNBIND', + 'ACL', + 'REPORT', + 'MKACTIVITY', + 'CHECKOUT', + 'MERGE', + 'M-SEARCH', + 'NOTIFY', + 'SUBSCRIBE', + 'UNSUBSCRIBE', + 'PATCH', + 'PURGE', + 'MKCALENDAR', + 'LINK', + 'UNLINK', + 'SOURCE', +]; +var method_connect = methods.indexOf('CONNECT'); +HTTPParser.prototype.reinitialize = HTTPParser; +HTTPParser.prototype.close = +HTTPParser.prototype.pause = +HTTPParser.prototype.resume = +HTTPParser.prototype.remove = +HTTPParser.prototype.free = function () {}; +HTTPParser.prototype._compatMode0_11 = false; +HTTPParser.prototype.getAsyncId = function() { return 0; }; + +var headerState = { + REQUEST_LINE: true, + RESPONSE_LINE: true, + HEADER: true +}; +HTTPParser.prototype.execute = function (chunk, start, length) { + if (!(this instanceof HTTPParser)) { + throw new TypeError('not a HTTPParser'); + } + + // backward compat to node < 0.11.4 + // Note: the start and length params were removed in newer version + start = start || 0; + length = typeof length === 'number' ? length : chunk.length; + + this.chunk = chunk; + this.offset = start; + var end = this.end = start + length; + try { + while (this.offset < end) { + if (this[this.state]()) { + break; + } + } + } catch (err) { + if (this.isUserCall) { + throw err; + } + this.hadError = true; + return err; + } + this.chunk = null; + length = this.offset - start; + if (headerState[this.state]) { + this.headerSize += length; + if (this.headerSize > (this.maxHeaderSize||HTTPParser.maxHeaderSize)) { + return new Error('max header size exceeded'); + } + } + return length; +}; + +var stateFinishAllowed = { + REQUEST_LINE: true, + RESPONSE_LINE: true, + BODY_RAW: true +}; +HTTPParser.prototype.finish = function () { + if (this.hadError) { + return; + } + if (!stateFinishAllowed[this.state]) { + return new Error('invalid state for EOF'); + } + if (this.state === 'BODY_RAW') { + this.userCall()(this[kOnMessageComplete]()); + } +}; + +// These three methods are used for an internal speed optimization, and it also +// works if theses are noops. Basically consume() asks us to read the bytes +// ourselves, but if we don't do it we get them through execute(). +HTTPParser.prototype.consume = +HTTPParser.prototype.unconsume = +HTTPParser.prototype.getCurrentBuffer = function () {}; + +//For correct error handling - see HTTPParser#execute +//Usage: this.userCall()(userFunction('arg')); +HTTPParser.prototype.userCall = function () { + this.isUserCall = true; + var self = this; + return function (ret) { + self.isUserCall = false; + return ret; + }; +}; + +HTTPParser.prototype.nextRequest = function () { + this.userCall()(this[kOnMessageComplete]()); + this.reinitialize(this.type); +}; + +HTTPParser.prototype.consumeLine = function () { + var end = this.end, + chunk = this.chunk; + for (var i = this.offset; i < end; i++) { + if (chunk[i] === 0x0a) { // \n + var line = this.line + chunk.toString(HTTPParser.encoding, this.offset, i); + if (line.charAt(line.length - 1) === '\r') { + line = line.substr(0, line.length - 1); + } + this.line = ''; + this.offset = i + 1; + return line; + } + } + //line split over multiple chunks + this.line += chunk.toString(HTTPParser.encoding, this.offset, this.end); + this.offset = this.end; +}; + +var headerExp = /^([^: \t]+):[ \t]*((?:.*[^ \t])|)/; +var headerContinueExp = /^[ \t]+(.*[^ \t])/; +HTTPParser.prototype.parseHeader = function (line, headers) { + if (line.indexOf('\r') !== -1) { + throw parseErrorCode('HPE_LF_EXPECTED'); + } + + var match = headerExp.exec(line); + var k = match && match[1]; + if (k) { // skip empty string (malformed header) + headers.push(k); + headers.push(match[2]); + } else { + var matchContinue = headerContinueExp.exec(line); + if (matchContinue && headers.length) { + if (headers[headers.length - 1]) { + headers[headers.length - 1] += ' '; + } + headers[headers.length - 1] += matchContinue[1]; + } + } +}; + +var requestExp = /^([A-Z-]+) ([^ ]+) HTTP\/(\d)\.(\d)$/; +HTTPParser.prototype.REQUEST_LINE = function () { + var line = this.consumeLine(); + if (!line) { + return; + } + var match = requestExp.exec(line); + if (match === null) { + throw parseErrorCode('HPE_INVALID_CONSTANT'); + } + this.info.method = this._compatMode0_11 ? match[1] : methods.indexOf(match[1]); + if (this.info.method === -1) { + throw new Error('invalid request method'); + } + this.info.url = match[2]; + this.info.versionMajor = +match[3]; + this.info.versionMinor = +match[4]; + this.body_bytes = 0; + this.state = 'HEADER'; +}; + +var responseExp = /^HTTP\/(\d)\.(\d) (\d{3}) ?(.*)$/; +HTTPParser.prototype.RESPONSE_LINE = function () { + var line = this.consumeLine(); + if (!line) { + return; + } + var match = responseExp.exec(line); + if (match === null) { + throw parseErrorCode('HPE_INVALID_CONSTANT'); + } + this.info.versionMajor = +match[1]; + this.info.versionMinor = +match[2]; + var statusCode = this.info.statusCode = +match[3]; + this.info.statusMessage = match[4]; + // Implied zero length. + if ((statusCode / 100 | 0) === 1 || statusCode === 204 || statusCode === 304) { + this.body_bytes = 0; + } + this.state = 'HEADER'; +}; + +HTTPParser.prototype.shouldKeepAlive = function () { + if (this.info.versionMajor > 0 && this.info.versionMinor > 0) { + if (this.connection.indexOf('close') !== -1) { + return false; + } + } else if (this.connection.indexOf('keep-alive') === -1) { + return false; + } + if (this.body_bytes !== null || this.isChunked) { // || skipBody + return true; + } + return false; +}; + +HTTPParser.prototype.HEADER = function () { + var line = this.consumeLine(); + if (line === undefined) { + return; + } + var info = this.info; + if (line) { + this.parseHeader(line, info.headers); + } else { + var headers = info.headers; + var hasContentLength = false; + var currentContentLengthValue; + var hasUpgradeHeader = false; + for (var i = 0; i < headers.length; i += 2) { + switch (headers[i].toLowerCase()) { + case 'transfer-encoding': + this.isChunked = headers[i + 1].toLowerCase() === 'chunked'; + break; + case 'content-length': + currentContentLengthValue = +headers[i + 1]; + if (hasContentLength) { + // Fix duplicate Content-Length header with same values. + // Throw error only if values are different. + // Known issues: + // https://github.com/request/request/issues/2091#issuecomment-328715113 + // https://github.com/nodejs/node/issues/6517#issuecomment-216263771 + if (currentContentLengthValue !== this.body_bytes) { + throw parseErrorCode('HPE_UNEXPECTED_CONTENT_LENGTH'); + } + } else { + hasContentLength = true; + this.body_bytes = currentContentLengthValue; + } + break; + case 'connection': + this.connection += headers[i + 1].toLowerCase(); + break; + case 'upgrade': + hasUpgradeHeader = true; + break; + } + } + + // if both isChunked and hasContentLength, isChunked wins + // This is required so the body is parsed using the chunked method, and matches + // Chrome's behavior. We could, maybe, ignore them both (would get chunked + // encoding into the body), and/or disable shouldKeepAlive to be more + // resilient. + if (this.isChunked && hasContentLength) { + hasContentLength = false; + this.body_bytes = null; + } + + // Logic from https://github.com/nodejs/http-parser/blob/921d5585515a153fa00e411cf144280c59b41f90/http_parser.c#L1727-L1737 + // "For responses, "Upgrade: foo" and "Connection: upgrade" are + // mandatory only when it is a 101 Switching Protocols response, + // otherwise it is purely informational, to announce support. + if (hasUpgradeHeader && this.connection.indexOf('upgrade') != -1) { + info.upgrade = this.type === HTTPParser.REQUEST || info.statusCode === 101; + } else { + info.upgrade = info.method === method_connect; + } + + if (this.isChunked && info.upgrade) { + this.isChunked = false; + } + + info.shouldKeepAlive = this.shouldKeepAlive(); + //problem which also exists in original node: we should know skipBody before calling onHeadersComplete + var skipBody; + if (compatMode0_12) { + skipBody = this.userCall()(this[kOnHeadersComplete](info)); + } else { + skipBody = this.userCall()(this[kOnHeadersComplete](info.versionMajor, + info.versionMinor, info.headers, info.method, info.url, info.statusCode, + info.statusMessage, info.upgrade, info.shouldKeepAlive)); + } + if (skipBody === 2) { + this.nextRequest(); + return true; + } else if (this.isChunked && !skipBody) { + this.state = 'BODY_CHUNKHEAD'; + } else if (skipBody || this.body_bytes === 0) { + this.nextRequest(); + // For older versions of node (v6.x and older?), that return skipBody=1 or skipBody=true, + // need this "return true;" if it's an upgrade request. + return info.upgrade; + } else if (this.body_bytes === null) { + this.state = 'BODY_RAW'; + } else { + this.state = 'BODY_SIZED'; + } + } +}; + +HTTPParser.prototype.BODY_CHUNKHEAD = function () { + var line = this.consumeLine(); + if (line === undefined) { + return; + } + this.body_bytes = parseInt(line, 16); + if (!this.body_bytes) { + this.state = 'BODY_CHUNKTRAILERS'; + } else { + this.state = 'BODY_CHUNK'; + } +}; + +HTTPParser.prototype.BODY_CHUNK = function () { + var length = Math.min(this.end - this.offset, this.body_bytes); + // 0, length are for backwards compatibility. See: https://github.com/creationix/http-parser-js/pull/98 + this.userCall()(this[kOnBody](this.chunk.slice(this.offset, this.offset + length), 0, length)); + this.offset += length; + this.body_bytes -= length; + if (!this.body_bytes) { + this.state = 'BODY_CHUNKEMPTYLINE'; + } +}; + +HTTPParser.prototype.BODY_CHUNKEMPTYLINE = function () { + var line = this.consumeLine(); + if (line === undefined) { + return; + } + if (line !== '') { + throw new Error('Expected empty line'); + } + this.state = 'BODY_CHUNKHEAD'; +}; + +HTTPParser.prototype.BODY_CHUNKTRAILERS = function () { + var line = this.consumeLine(); + if (line === undefined) { + return; + } + if (line) { + this.parseHeader(line, this.trailers); + } else { + if (this.trailers.length) { + this.userCall()(this[kOnHeaders](this.trailers, '')); + } + this.nextRequest(); + } +}; + +HTTPParser.prototype.BODY_RAW = function () { + // 0, length are for backwards compatibility. See: https://github.com/creationix/http-parser-js/pull/98 + this.userCall()(this[kOnBody](this.chunk.slice(this.offset, this.end), 0, this.end - this.offset)); + this.offset = this.end; +}; + +HTTPParser.prototype.BODY_SIZED = function () { + var length = Math.min(this.end - this.offset, this.body_bytes); + // 0, length are for backwards compatibility. See: https://github.com/creationix/http-parser-js/pull/98 + this.userCall()(this[kOnBody](this.chunk.slice(this.offset, this.offset + length), 0, length)); + this.offset += length; + this.body_bytes -= length; + if (!this.body_bytes) { + this.nextRequest(); + } +}; + +// backward compat to node < 0.11.6 +['Headers', 'HeadersComplete', 'Body', 'MessageComplete'].forEach(function (name) { + var k = HTTPParser['kOn' + name]; + Object.defineProperty(HTTPParser.prototype, 'on' + name, { + get: function () { + return this[k]; + }, + set: function (to) { + // hack for backward compatibility + this._compatMode0_11 = true; + method_connect = 'CONNECT'; + return (this[k] = to); + } + }); +}); + +function parseErrorCode(code) { + var err = new Error('Parse Error'); + err.code = code; + return err; +} diff --git a/src/Node/Lib/http.cjs b/src/Node/Lib/http.cjs new file mode 100644 index 00000000..1a88bc3b --- /dev/null +++ b/src/Node/Lib/http.cjs @@ -0,0 +1,544 @@ +'use strict'; + +const net = require('net'); +const { Readable, Writable } = require('stream'); +const { EventEmitter } = require('events'); +const { Buffer } = require('buffer'); +const { urlToHttpOptions } = require('url'); +const { HTTPParser } = require('./http-parser.cjs'); +const { methods: METHODS, status: STATUS_CODES } = require('./http-constants.cjs'); +// QUERY was standardized after the parser's method table was released. +if (!HTTPParser.methods.includes('QUERY')) HTTPParser.methods.push('QUERY'); +const token = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/; +const invalidValue = /[^\t\x20-\x7e\x80-\xff]/; + +function coded(ErrorType, code, message) { return Object.assign(new ErrorType(message), { code }); } +function validateHeaderName(name, label = 'Header name') { + if (typeof name !== 'string' || !token.test(name)) throw coded(TypeError, 'ERR_INVALID_HTTP_TOKEN', `${label} must be a valid HTTP token ["${name}"]`); +} +function validateHeaderValue(name, value) { + if (value === undefined) throw coded(TypeError, 'ERR_HTTP_INVALID_HEADER_VALUE', `Invalid value "undefined" for header "${name}"`); + if (invalidValue.test(String(value))) throw coded(TypeError, 'ERR_INVALID_CHAR', `Invalid character in header content ["${name}"]`); +} +const singletonHeaders = new Set(['age', 'authorization', 'content-length', 'content-type', 'etag', 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since', 'last-modified', 'location', 'max-forwards', 'proxy-authorization', 'referer', 'retry-after', 'server', 'user-agent']); +function headersObject(raw, distinct = false, joinDuplicates = false) { + const headers = {}; + for (let i = 0; i < raw.length; i += 2) { + const key = raw[i].toLowerCase(), value = raw[i + 1]; + if (distinct || key === 'set-cookie') (headers[key] || (headers[key] = [])).push(value); + else if (headers[key] === undefined) headers[key] = value; + else if (!singletonHeaders.has(key) || joinDuplicates) headers[key] += (key === 'cookie' ? '; ' : ', ') + value; + } + return headers; +} +function validateIncoming(raw, request) { + let contentLength = false; + const encodings = []; + for (let i = 0; i < raw.length; i += 2) { + const name = raw[i], value = raw[i + 1]; + if (!token.test(name) || invalidValue.test(value)) throw coded(Error, 'HPE_INVALID_HEADER_TOKEN', 'Parse Error: Invalid header token'); + if (name.toLowerCase() === 'content-length') { + if (contentLength || !/^\d+$/.test(value)) throw coded(Error, 'HPE_UNEXPECTED_CONTENT_LENGTH', 'Parse Error: Invalid Content-Length'); + contentLength = true; + } + if (name.toLowerCase() === 'transfer-encoding') { + encodings.push(...value.toLowerCase().split(',').map(value => value.trim())); + } + } + if (contentLength && encodings.length) throw coded(Error, 'HPE_UNEXPECTED_CONTENT_LENGTH', 'Parse Error: Content-Length cannot accompany Transfer-Encoding'); + const chunked = encodings[encodings.length - 1] === 'chunked'; + if (encodings.some(value => !token.test(value)) || + encodings.slice(0, -1).includes('chunked') || request && encodings.length && !chunked) { + throw coded(Error, 'HPE_INVALID_TRANSFER_ENCODING', 'Parse Error: Invalid Transfer-Encoding'); + } + return chunked; +} + +class IncomingMessage extends Readable { + constructor(socket) { + super({ autoDestroy: true }); + this.socket = socket; + this.httpVersionMajor = 1; + this.httpVersionMinor = 1; + this.httpVersion = '1.1'; + this.complete = false; + this.aborted = false; + this.headers = {}; + this.rawHeaders = []; + this.trailers = {}; + this.rawTrailers = []; + this.url = ''; + this.method = null; + this.statusCode = null; + this.statusMessage = null; + } + get connection() { return this.socket; } + set connection(value) { this.socket = value; } + get headersDistinct() { return headersObject(this.rawHeaders, true); } + get trailersDistinct() { return headersObject(this.rawTrailers, true); } + _read() { if (this.socket && !this.socket.destroyed) this.socket.resume(); } + _destroy(error, callback) { + if (!this.complete && !this.aborted) { this.aborted = true; this.emit('aborted'); } + if (!this.complete && this.socket && !this.socket.destroyed) this.socket.destroy(error); + callback(error); + } + setTimeout(timeout, callback) { this.socket.setTimeout(timeout); if (callback) this.on('timeout', callback); return this; } + _dump() { this.removeAllListeners('data'); this.resume(); } +} + +class OutgoingMessage extends Writable { + constructor() { + super({ decodeStrings: true, autoDestroy: false, emitClose: true }); + this._headers = Object.create(null); + this._header = null; + this._headerSent = false; + this._trailer = ''; + this._pendingOutput = []; + this._active = true; + this.socket = null; + this.sendDate = false; + this.shouldKeepAlive = true; + this.useChunkedEncodingByDefault = true; + this.chunkedEncoding = false; + this._hasBody = true; + this._removedConnection = false; + this._removedContLen = false; + this._removedTE = false; + this._contentLength = null; + this._bodyBytes = 0; + this.strictContentLength = false; + } + get connection() { return this.socket; } + set connection(value) { this.socket = value; } + get headersSent() { return this._header !== null; } + get finished() { return this.writableEnded; } + get writableLength() { return super.writableLength + (this.socket ? this.socket.writableLength : 0); } + _assertHeaders(action) { if (this._header !== null) throw coded(Error, 'ERR_HTTP_HEADERS_SENT', `Cannot ${action} headers after they are sent to the client`); } + setHeader(name, value) { + this._assertHeaders('set'); validateHeaderName(name); + for (const item of Array.isArray(value) ? value : [value]) validateHeaderValue(name, item); + this._headers[name.toLowerCase()] = [name, value]; + return this; + } + appendHeader(name, value) { + if (!this.hasHeader(name)) return this.setHeader(name, value); + const old = this.getHeader(name); + return this.setHeader(name, [].concat(old, value)); + } + setHeaders(headers) { if (!headers || typeof headers.entries !== 'function') throw new TypeError('headers must be a Map or Headers'); for (const [key, value] of headers) this.setHeader(key, value); return this; } + getHeader(name) { if (typeof name !== 'string') throw new TypeError('name must be a string'); const pair = this._headers[name.toLowerCase()]; return pair && pair[1]; } + getHeaderNames() { return Object.keys(this._headers); } + getRawHeaderNames() { return Object.values(this._headers).map(pair => pair[0]); } + getHeaders() { const out = Object.create(null); for (const key of Object.keys(this._headers)) out[key] = this._headers[key][1]; return out; } + hasHeader(name) { if (typeof name !== 'string') throw new TypeError('name must be a string'); return Object.prototype.hasOwnProperty.call(this._headers, name.toLowerCase()); } + removeHeader(name) { + this._assertHeaders('remove'); + const key = String(name).toLowerCase(); delete this._headers[key]; + if (key === 'connection') this._removedConnection = true; + if (key === 'content-length') this._removedContLen = true; + if (key === 'transfer-encoding') this._removedTE = true; + if (key === 'date') this.sendDate = false; + } + _storeHeader(firstLine) { + if (this.sendDate && !this.hasHeader('date')) this.setHeader('Date', new Date().toUTCString()); + const status = this.statusCode; + if (this.req && (this.req.method === 'HEAD' || status < 200 || status === 204 || status === 304)) this._hasBody = false; + if (status === 204 || status === 304 || status < 200) { + delete this._headers['transfer-encoding']; + if (status !== 304) delete this._headers['content-length']; + } + if (this.hasHeader('content-length')) this._contentLength = Number(this.getHeader('content-length')); + if (!this.hasHeader('content-length') && !this.hasHeader('transfer-encoding') && this._hasBody) { + if (this.useChunkedEncodingByDefault && !this._removedTE) this.setHeader('Transfer-Encoding', 'chunked'); + else if (this._contentLength === null) this.shouldKeepAlive = false; + } + this.chunkedEncoding = /(?:^|,)\s*chunked\s*$/i.test(String(this.getHeader('transfer-encoding') || '')) && this._hasBody; + if (this._hasBody && this.hasHeader('transfer-encoding') && !this.chunkedEncoding) this.shouldKeepAlive = false; + if (this.hasHeader('connection')) { + if (/\bclose\b/i.test(String(this.getHeader('connection')))) this.shouldKeepAlive = false; + } else if (!this._removedConnection) this.setHeader('Connection', this.shouldKeepAlive ? 'keep-alive' : 'close'); + if (this.req && this.shouldKeepAlive && !this.hasHeader('keep-alive') && this._keepAliveTimeout) this.setHeader('Keep-Alive', `timeout=${Math.floor(this._keepAliveTimeout / 1000)}`); + let header = firstLine; + for (const [name, value] of Object.values(this._headers)) { + const values = Array.isArray(value) ? value : [value]; + if (name.toLowerCase() === 'cookie') header += name + ': ' + values.join('; ') + '\r\n'; + else for (const item of values) header += name + ': ' + item + '\r\n'; + } + this._header = header + '\r\n'; + } + _send(data, callback) { + if (!this._active || !this.socket) { this._pendingOutput.push([data, callback]); return; } + if (this.socket.destroyed) { if (callback) process.nextTick(callback, coded(Error, 'ERR_STREAM_DESTROYED', 'Cannot call write after a stream was destroyed')); return; } + this.socket.write(data, callback); + } + _activate(socket) { + this.socket = socket; + this._active = true; + const pending = this._pendingOutput.splice(0); + for (const [data, callback] of pending) this._send(data, callback); + } + _flushHeader() { if (this._header === null) this._implicitHeader(); if (!this._headerSent) { this._headerSent = true; this._send(Buffer.from(this._header, 'latin1')); } } + flushHeaders() { this._flushHeader(); } + _write(chunk, encoding, callback) { + this._flushHeader(); + if (!this._hasBody || chunk.length === 0) { process.nextTick(callback); return; } + if (!Buffer.isBuffer(chunk)) chunk = Buffer.from(chunk, encoding); + this._bodyBytes += chunk.length; + if (this.strictContentLength && this._contentLength !== null && this._bodyBytes > this._contentLength) { callback(coded(Error, 'ERR_HTTP_CONTENT_LENGTH_MISMATCH', 'Response body length does not match Content-Length')); return; } + if (this.chunkedEncoding) this._send(Buffer.concat([Buffer.from(chunk.length.toString(16) + '\r\n'), chunk, Buffer.from('\r\n')]), callback); + else this._send(chunk, callback); + } + write(chunk, encoding, callback) { if (this._header === null) this._implicitHeader(); return super.write(chunk, encoding, callback); } + end(chunk, encoding, callback) { + if (typeof chunk === 'function') { callback = chunk; chunk = undefined; encoding = undefined; } + else if (typeof encoding === 'function') { callback = encoding; encoding = undefined; } + if (this._header === null && !this.hasHeader('content-length') && !this.hasHeader('transfer-encoding') && !this._removedContLen) { + if (chunk !== undefined && chunk !== null) this.setHeader('Content-Length', Buffer.isBuffer(chunk) || chunk instanceof Uint8Array ? chunk.length : Buffer.byteLength(chunk, encoding)); + else if (this.req || !['GET', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE', 'CONNECT'].includes(this.method)) this.setHeader('Content-Length', 0); + else { this.useChunkedEncodingByDefault = false; this._contentLength = 0; } + } + if (this._header === null) this._implicitHeader(); + return super.end(chunk, encoding, callback); + } + _final(callback) { + this._flushHeader(); + if (this.strictContentLength && this._hasBody && this._contentLength !== null && this._bodyBytes !== this._contentLength) { callback(coded(Error, 'ERR_HTTP_CONTENT_LENGTH_MISMATCH', 'Response body length does not match Content-Length')); return; } + if (this.chunkedEncoding) this._send(Buffer.from('0\r\n' + this._trailer + '\r\n', 'latin1'), callback); + else this._send(Buffer.alloc(0), callback); + } + addTrailers(headers) { for (const [name, value] of Object.entries(headers)) { validateHeaderName(name); validateHeaderValue(name, value); this._trailer += name + ': ' + value + '\r\n'; } } + setTimeout(timeout, callback) { if (callback) this.on('timeout', callback); if (this.socket) this.socket.setTimeout(timeout); else this.once('socket', socket => socket.setTimeout(timeout)); return this; } + _destroy(error, callback) { if (this.socket && !this.socket.destroyed) this.socket.destroy(error); callback(error); } +} + +class ServerResponse extends OutgoingMessage { + constructor(req) { + super(); + this.req = req; + this.statusCode = 200; + this.statusMessage = undefined; + this.sendDate = true; + this.shouldKeepAlive = req.httpVersionMajor === 1 && req.httpVersionMinor === 1 ? !/\bclose\b/i.test(req.headers.connection || '') : /\bkeep-alive\b/i.test(req.headers.connection || ''); + this.useChunkedEncodingByDefault = req.httpVersionMinor >= 1; + this._hasBody = req.method !== 'HEAD'; + } + assignSocket(socket) { socket._httpMessage = this; this._activate(socket); } + detachSocket(socket) { if (socket._httpMessage === this) socket._httpMessage = null; this.socket = null; } + _implicitHeader() { this.writeHead(this.statusCode); } + writeHead(statusCode, statusMessage, headers) { + this._assertHeaders('write'); + const code = Number(statusCode); + if (!Number.isInteger(code) || code < 100 || code > 999) throw coded(RangeError, 'ERR_HTTP_INVALID_STATUS_CODE', `Invalid status code: ${statusCode}`); + this.statusCode = code; + if (typeof statusMessage === 'string') this.statusMessage = statusMessage; + else { headers = statusMessage; this.statusMessage = this.statusMessage || STATUS_CODES[code] || 'unknown'; } + if (invalidValue.test(this.statusMessage)) throw coded(TypeError, 'ERR_INVALID_CHAR', 'Invalid character in statusMessage'); + if (Array.isArray(headers)) { for (let i = 0; i < headers.length; i += 2) this.appendHeader(headers[i], headers[i + 1]); } + else if (headers) for (const [name, value] of Object.entries(headers)) this.setHeader(name, value); + this._storeHeader(`HTTP/1.1 ${code} ${this.statusMessage}\r\n`); + return this; + } + writeContinue(callback) { this._send(Buffer.from('HTTP/1.1 100 Continue\r\n\r\n'), callback); } + writeProcessing(callback) { this._send(Buffer.from('HTTP/1.1 102 Processing\r\n\r\n'), callback); } + writeEarlyHints(hints, callback) { this.writeInformation(103, hints, callback); } + writeInformation(code, headers, callback) { + let text = `HTTP/1.1 ${code} ${STATUS_CODES[code] || 'unknown'}\r\n`; + for (const [name, value] of Object.entries(headers || {})) { validateHeaderName(name); validateHeaderValue(name, value); text += name + ': ' + (Array.isArray(value) ? value.join(', ') : value) + '\r\n'; } + this._send(Buffer.from(text + '\r\n', 'latin1'), callback); + } +} + +function fillIncoming(message, info, joinDuplicateHeaders) { + message.httpVersionMajor = info.versionMajor; + message.httpVersionMinor = info.versionMinor; + message.httpVersion = info.versionMajor + '.' + info.versionMinor; + message.rawHeaders = info.headers.slice(); + message.headers = headersObject(message.rawHeaders, false, joinDuplicateHeaders); + message.url = info.url || ''; + message.method = info.method === undefined ? null : HTTPParser.methods[info.method]; + message.statusCode = info.statusCode === undefined ? null : info.statusCode; + message.statusMessage = info.statusMessage; +} + +class Server extends net.Server { + constructor(options = {}, listener) { + if (typeof options === 'function') { listener = options; options = {}; } + super({ ...options, allowHalfOpen: true }); + this._httpOptions = options; + this.httpAllowHalfOpen = false; + this.timeout = 0; + this.keepAliveTimeout = options.keepAliveTimeout === undefined ? 5000 : options.keepAliveTimeout; + this.keepAliveTimeoutBuffer = 1000; + this.requestTimeout = options.requestTimeout === undefined ? 300000 : options.requestTimeout; + this.headersTimeout = options.headersTimeout === undefined ? Math.min(60000, this.requestTimeout) : options.headersTimeout; + this.maxHeadersCount = null; + this.maxRequestsPerSocket = 0; + this.on('connection', socket => this._connection(socket)); + if (listener) this.on('request', listener); + } + _connection(socket) { + const parser = new HTTPParser(HTTPParser.REQUEST); + parser.maxHeaderSize = this._httpOptions.maxHeaderSize || 16384; + const responses = []; + let incoming = null, upgraded = null; + socket._httpResponses = responses; + socket._httpIdle = true; + if (this.timeout) socket.setTimeout(this.timeout); + socket.on('timeout', () => { + const handled = (incoming && incoming.emit('timeout')) | (socket._httpMessage && socket._httpMessage.emit('timeout')) | this.emit('timeout', socket); + if (!handled) socket.destroy(); + }); + parser[HTTPParser.kOnHeadersComplete] = info => { + parser.isChunked = validateIncoming(info.headers, true); + const req = incoming = new (this._httpOptions.IncomingMessage || IncomingMessage)(socket); + fillIncoming(req, info, this._httpOptions.joinDuplicateHeaders); + socket._httpIdle = false; + socket.setTimeout(this.timeout); + if (info.upgrade) { upgraded = req; return 2; } + const res = new (this._httpOptions.ServerResponse || ServerResponse)(req); + res._keepAliveTimeout = this.keepAliveTimeout; + res.socket = socket; + res._active = responses.length === 0; + responses.push(res); + if (res._active) socket._httpMessage = res; + res.once('finish', () => { + if (!req.readableEnded) req._dump(); + const index = responses.indexOf(res); if (index !== -1) responses.splice(index, 1); + res.emit('close'); + if (!res.shouldKeepAlive) socket.end(); + else if (responses.length) responses[0].assignSocket(socket); + else { + socket._httpMessage = null; + socket._httpIdle = true; + if (!this.listening) socket.end(); + else socket.setTimeout(this.keepAliveTimeout + this.keepAliveTimeoutBuffer); + } + }); + if (/^100-continue$/i.test(req.headers.expect || '')) { + if (this.listenerCount('checkContinue')) this.emit('checkContinue', req, res); + else { res.writeContinue(); this.emit('request', req, res); } + } else if (req.headers.expect) { + if (this.listenerCount('checkExpectation')) this.emit('checkExpectation', req, res); + else { res.statusCode = 417; res.end(); } + } else this.emit('request', req, res); + return false; + }; + parser[HTTPParser.kOnBody] = chunk => { if (incoming && !incoming.push(Buffer.from(chunk))) socket.pause(); }; + parser[HTTPParser.kOnHeaders] = headers => { if (incoming) { incoming.rawTrailers = headers.slice(); incoming.trailers = headersObject(headers); } }; + parser[HTTPParser.kOnMessageComplete] = () => { if (incoming) { incoming.complete = true; incoming.push(null); } }; + const onData = data => { + let parsed; + try { parsed = parser.execute(data); } catch (error) { onError(error); return; } + if (parsed instanceof Error) { onError(parsed); return; } + if (upgraded) { + socket.removeListener('data', onData); + socket.removeListener('end', onEnd); + const event = upgraded.method === 'CONNECT' ? 'connect' : 'upgrade'; + if (this.listenerCount(event)) this.emit(event, upgraded, socket, data.subarray(parsed)); + else socket.destroy(); + } + }; + const onError = error => { + if (!this.emit('clientError', error, socket)) { + if (socket.writable && !socket.destroyed) socket.end('HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n'); + else socket.destroy(); + } + }; + const onEnd = () => { + const error = parser.finish(); + if (error) { onError(error); return; } + if (!this.httpAllowHalfOpen || !responses.length) socket.end(); + else responses[responses.length - 1].shouldKeepAlive = false; + }; + socket.on('data', onData); + socket.on('end', onEnd); + socket.on('error', onError); + socket.on('close', () => { + if (incoming && !incoming.complete && !incoming.destroyed) incoming.destroy(coded(Error, 'ECONNRESET', 'aborted')); + for (const response of responses) if (!response.destroyed) response.destroy(); + }); + } + setTimeout(timeout = 0, callback) { this.timeout = timeout; if (callback) this.on('timeout', callback); return this; } + close(callback) { super.close(callback); this.closeIdleConnections(); return this; } + closeAllConnections() { for (const socket of this._sockets) socket.destroy(); } + closeIdleConnections() { for (const socket of this._sockets) if (socket._httpIdle) socket.end(); } +} + +class Agent extends EventEmitter { + constructor(options = {}) { + super(); + this.options = { ...options }; + this.defaultPort = 80; + this.protocol = 'http:'; + this.keepAlive = !!options.keepAlive; + this.keepAliveMsecs = options.keepAliveMsecs || 1000; + this.maxSockets = options.maxSockets || Infinity; + this.maxTotalSockets = options.maxTotalSockets || Infinity; + this.maxFreeSockets = options.maxFreeSockets === undefined ? 256 : options.maxFreeSockets; + this.scheduling = options.scheduling || 'lifo'; + this.sockets = Object.create(null); + this.freeSockets = Object.create(null); + this.requests = Object.create(null); + this.totalSocketCount = 0; + } + getName(options = {}) { return `${options.host || 'localhost'}:${options.port || this.defaultPort}:${options.localAddress || ''}:${options.family || ''}`; } + createConnection(options, callback) { return net.createConnection(options, callback); } + addRequest(request, options) { + const name = this.getName(options); + const free = this.freeSockets[name] || []; + let socket; + while (free.length && !socket) { const candidate = this.scheduling === 'fifo' ? free.shift() : free.pop(); if (!candidate.destroyed) socket = candidate; } + if (!free.length) delete this.freeSockets[name]; + if (socket) { socket.ref(); this.reuseSocket(socket, request); } + else if ((this.sockets[name] || []).length >= this.maxSockets || this.totalSocketCount >= this.maxTotalSockets) { (this.requests[name] || (this.requests[name] = [])).push([request, options]); return; } + else { + socket = this.createConnection({ ...this.options, ...options }); + this.totalSocketCount++; + socket.once('close', () => { + this.totalSocketCount--; + this.removeSocket(socket, options); + const pending = this.requests[name]; + if (pending && pending.length) { const next = pending.shift(); if (!pending.length) delete this.requests[name]; this.addRequest(...next); } + }); + } + (this.sockets[name] || (this.sockets[name] = [])).push(socket); + request.onSocket(socket); + } + removeSocket(socket, options) { + const name = this.getName(options); + for (const map of [this.sockets, this.freeSockets]) { + const list = map[name]; if (!list) continue; + const index = list.indexOf(socket); if (index !== -1) list.splice(index, 1); + if (!list.length) delete map[name]; + } + } + keepSocketAlive(socket) { socket.setKeepAlive(true, this.keepAliveMsecs); socket.unref(); return true; } + reuseSocket(socket, request) { request.reusedSocket = true; socket.ref(); } + _free(socket, request, options) { + this.removeSocket(socket, options); + const name = this.getName(options), pending = this.requests[name]; + if (pending && pending.length && !socket.destroyed) { + const [next] = pending.shift(); if (!pending.length) delete this.requests[name]; + (this.sockets[name] || (this.sockets[name] = [])).push(socket); + socket.ref(); next.onSocket(socket); return; + } + if (!this.keepAlive || !request.shouldKeepAlive || socket.destroyed || (this.freeSockets[name] || []).length >= this.maxFreeSockets || !this.keepSocketAlive(socket)) { socket.destroy(); return; } + (this.freeSockets[name] || (this.freeSockets[name] = [])).push(socket); + socket.emit('free'); + } + destroy() { for (const map of [this.sockets, this.freeSockets]) for (const sockets of Object.values(map)) for (const socket of sockets) socket.destroy(); } +} +const globalAgent = new Agent({ keepAlive: true, scheduling: 'lifo', timeout: 5000 }); + +function requestOptions(input, options) { + if (typeof input === 'string' || input instanceof URL) return { ...urlToHttpOptions(input instanceof URL ? input : new URL(input)), ...options }; + return { ...(input || {}), ...options }; +} +class ClientRequest extends OutgoingMessage { + constructor(input, options, callback) { + super(); + if (typeof options === 'function') { callback = options; options = undefined; } + options = requestOptions(input, options); + this.protocol = options.protocol || 'http:'; + this.agent = options.agent === undefined ? globalAgent : options.agent === false ? new Agent() : options.agent; + if (this.agent && this.protocol !== this.agent.protocol) throw coded(TypeError, 'ERR_INVALID_PROTOCOL', `Protocol "${this.protocol}" not supported. Expected "${this.agent.protocol}"`); + this.method = String(options.method || 'GET').toUpperCase(); + if (!token.test(this.method)) throw coded(TypeError, 'ERR_INVALID_HTTP_TOKEN', 'Method must be a valid HTTP token'); + this.path = options.path || '/'; + if (/[^\x21-\xff]/.test(this.path)) throw coded(TypeError, 'ERR_UNESCAPED_CHARACTERS', 'Request path contains unescaped characters'); + this.host = options.hostname || options.host || 'localhost'; + const port = Number(options.port || (this.agent && this.agent.defaultPort) || 80); + this._options = { ...options, host: this.host, port, path: options.socketPath }; + this.reusedSocket = false; + this.aborted = false; + this.res = null; + this.shouldKeepAlive = !!(this.agent && this.agent.keepAlive); + this.useChunkedEncodingByDefault = !['GET', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE', 'CONNECT'].includes(this.method); + if (Array.isArray(options.headers)) { for (let i = 0; i < options.headers.length; i += 2) this.appendHeader(options.headers[i], options.headers[i + 1]); } + else if (options.headers) for (const [key, value] of Object.entries(options.headers)) this.setHeader(key, value); + if (options.setHost !== false && !this.hasHeader('host')) this.setHeader('Host', (this.host.includes(':') ? '[' + this.host + ']' : this.host) + (port === (this.agent ? this.agent.defaultPort : 80) ? '' : ':' + port)); + if (options.auth && !this.hasHeader('authorization')) this.setHeader('Authorization', 'Basic ' + Buffer.from(options.auth).toString('base64')); + if (callback) this.once('response', callback); + if (options.signal) { + const abort = () => this.destroy(Object.assign(new Error('The operation was aborted'), { name: 'AbortError', code: 'ABORT_ERR', cause: options.signal.reason })); + if (options.signal.aborted) process.nextTick(abort); + else { options.signal.addEventListener('abort', abort, { once: true }); this.once('close', () => options.signal.removeEventListener('abort', abort)); } + } + if (options.timeout) this.setTimeout(options.timeout); + if (options.createConnection) this.onSocket(options.createConnection(this._options)); + else if (this.agent) this.agent.addRequest(this, this._options); + else this.onSocket(net.createConnection(this._options)); + } + _implicitHeader() { this._storeHeader(`${this.method} ${this.path} HTTP/1.1\r\n`); } + onSocket(socket) { + process.nextTick(() => { + if (this.destroyed) { socket.destroy(); return; } + const parser = new HTTPParser(HTTPParser.RESPONSE); + parser.maxHeaderSize = this._options.maxHeaderSize || 16384; + let response = null, upgraded = false, finished = false; + socket._httpMessage = this; + const cleanup = () => { + socket.removeListener('data', onData); socket.removeListener('end', onEnd); socket.removeListener('error', onError); socket.removeListener('close', onClose); socket.removeListener('timeout', onTimeout); + }; + const complete = () => { + if (finished) return; finished = true; cleanup(); + if (this.agent) this.agent._free(socket, this, this._options); else socket.destroy(); + this.emit('close'); + }; + parser[HTTPParser.kOnHeadersComplete] = info => { + parser.isChunked = validateIncoming(info.headers, false); + info.shouldKeepAlive = parser.shouldKeepAlive(); + response = new IncomingMessage(socket); fillIncoming(response, info, this._options.joinDuplicateHeaders); response.req = this; + if (info.statusCode < 200 && info.statusCode !== 101) { + if (info.statusCode === 100) this.emit('continue'); + this.emit('information', { statusCode: info.statusCode, statusMessage: info.statusMessage, httpVersion: response.httpVersion, httpVersionMajor: info.versionMajor, httpVersionMinor: info.versionMinor, headers: response.headers, rawHeaders: response.rawHeaders }); + response = null; return true; + } + this.res = response; + if (!info.shouldKeepAlive || /\bclose\b/i.test(response.headers.connection || '')) this.shouldKeepAlive = false; + if (info.upgrade || this.method === 'CONNECT') { upgraded = true; return 2; } + response.once('end', complete); + if (!this.emit('response', response)) response._dump(); + return this.method === 'HEAD'; + }; + parser[HTTPParser.kOnBody] = chunk => { if (response && !response.push(Buffer.from(chunk))) socket.pause(); }; + parser[HTTPParser.kOnHeaders] = headers => { if (response) { response.rawTrailers = headers.slice(); response.trailers = headersObject(headers); } }; + parser[HTTPParser.kOnMessageComplete] = () => { if (response) { response.complete = true; response.push(null); } }; + const onData = data => { + let parsed; try { parsed = parser.execute(data); } catch (error) { onError(error); return; } + if (parsed instanceof Error) { onError(parsed); return; } + if (upgraded) { cleanup(); const event = this.method === 'CONNECT' ? 'connect' : 'upgrade'; if (this.listenerCount(event)) this.emit(event, response, socket, data.subarray(parsed)); else socket.destroy(); } + }; + const onError = error => { cleanup(); this.destroy(error); }; + const onEnd = () => { + const error = parser.finish(); + if (!response || error) onError(coded(Error, 'ECONNRESET', 'socket hang up')); + }; + const onClose = () => { + if (finished) return; + cleanup(); + if (response && !response.complete) response.destroy(coded(Error, 'ECONNRESET', 'aborted')); + else if (!response) this.destroy(coded(Error, 'ECONNRESET', 'socket hang up')); + }; + const onTimeout = () => this.emit('timeout'); + socket.on('data', onData); socket.on('end', onEnd); socket.on('error', onError); socket.on('close', onClose); socket.on('timeout', onTimeout); + this._activate(socket); + this.emit('socket', socket); + }); + } + _destroy(error, callback) { + if (!error && !this.res && (this.socket || !this.aborted)) error = coded(Error, 'ECONNRESET', 'socket hang up'); + super._destroy(error, callback); + } + abort() { if (!this.aborted) { this.aborted = true; process.nextTick(() => this.emit('abort')); this.destroy(); } } + setNoDelay(value = true) { if (this.socket) this.socket.setNoDelay(value); else this.once('socket', socket => socket.setNoDelay(value)); return this; } + setSocketKeepAlive(value = false, delay = 0) { if (this.socket) this.socket.setKeepAlive(value, delay); else this.once('socket', socket => socket.setKeepAlive(value, delay)); return this; } +} + +function request(input, options, callback) { return new ClientRequest(input, options, callback); } +function get(input, options, callback) { const req = request(input, options, callback); req.end(); return req; } +module.exports = { + METHODS, STATUS_CODES, IncomingMessage, OutgoingMessage, ServerResponse, Server, Agent, ClientRequest, + globalAgent, request, get, createServer: (options, listener) => new Server(options, listener), + validateHeaderName, validateHeaderValue, maxHeaderSize: 16384, +}; diff --git a/src/Node/Lib/http2.cjs b/src/Node/Lib/http2.cjs new file mode 100644 index 00000000..de7e877e --- /dev/null +++ b/src/Node/Lib/http2.cjs @@ -0,0 +1,496 @@ +'use strict'; + +const net = require('net'); +const tls = require('tls'); +const { EventEmitter } = require('events'); +const { Duplex, Readable, Writable } = require('stream'); +const { Buffer } = require('buffer'); +const constants = require('./portable/http2-constants.json'); +const hpack = require('./portable/hpack.cjs'); +const sensitiveHeaders = Symbol('nodejs.http2.sensitiveHeaders'); +const preface = Buffer.from('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n'); +const settingNames = { headerTableSize: 1, enablePush: 2, maxConcurrentStreams: 3, initialWindowSize: 4, maxFrameSize: 5, maxHeaderListSize: 6, enableConnectProtocol: 8 }; +const settingKeys = Object.fromEntries(Object.entries(settingNames).map(([name, id]) => [id, name])); +const defaults = { headerTableSize: 4096, enablePush: true, maxConcurrentStreams: 0xffffffff, initialWindowSize: 65535, maxFrameSize: 16384, maxHeaderListSize: 65535, enableConnectProtocol: false }; +const connectionHeaders = new Set(['connection', 'upgrade', 'keep-alive', 'proxy-connection', 'transfer-encoding']); +function error(code, message) { return Object.assign(new Error(message), { code }); } +function integer(value, minimum, maximum, name) { + if (!Number.isInteger(value) || value < minimum || value > maximum) throw new RangeError(`Invalid ${name}: ${value}`); + return value; +} +function getPackedSettings(settings = {}) { + const entries = Object.entries(settings).filter(([key]) => settingNames[key]); + const buffer = Buffer.alloc(entries.length * 6); + entries.forEach(([key, value], index) => { + if (key === 'enablePush' || key === 'enableConnectProtocol') { + if (typeof value !== 'boolean') throw new TypeError(`${key} must be a boolean.`); + value = Number(value); + } + integer(value, key === 'maxFrameSize' ? 16384 : 0, key === 'initialWindowSize' ? 0x7fffffff : key === 'maxFrameSize' ? 0xffffff : 0xffffffff, key); + buffer.writeUInt16BE(settingNames[key], index * 6); + buffer.writeUInt32BE(value, index * 6 + 2); + }); + return buffer; +} +function getUnpackedSettings(buffer) { + buffer = Buffer.from(buffer); + if (buffer.length % 6) throw error('ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH', 'Settings buffer length must be a multiple of six.'); + const settings = {}; + for (let i = 0; i < buffer.length; i += 6) { + const name = settingKeys[buffer.readUInt16BE(i)]; + if (!name) continue; + const value = buffer.readUInt32BE(i + 2); + settings[name] = name === 'enablePush' || name === 'enableConnectProtocol' ? !!value : value; + } + getPackedSettings(settings); + return settings; +} +function headerList(headers) { + const list = [], sensitive = headers[sensitiveHeaders] || []; + for (const name of Object.keys(headers).sort((a, b) => Number(b.startsWith(':')) - Number(a.startsWith(':')))) { + if (name !== name.toLowerCase() || !/^:?[!#$%&'*+.^_`|~0-9a-z-]+$/.test(name)) throw error('ERR_HTTP2_INVALID_HEADER_VALUE', 'Invalid HTTP/2 header name: ' + name); + if (connectionHeaders.has(name) || name === 'te' && headers[name] !== 'trailers') throw error('ERR_HTTP2_INVALID_CONNECTION_HEADERS', 'HTTP/1 connection headers are forbidden in HTTP/2.'); + const values = Array.isArray(headers[name]) ? headers[name] : [headers[name]]; + for (const value of values) { + if (value === undefined) continue; + const text = String(value); + if (/[\0\r\n]/.test(text)) throw error('ERR_HTTP2_INVALID_HEADER_VALUE', 'Invalid HTTP/2 header value.'); + list.push({ name, value: text, neverIndex: sensitive.includes(name) }); + } + } + return list; +} + +class Http2Stream extends Duplex { + constructor(session, id, options = {}) { + super({ allowHalfOpen: true, autoDestroy: true, emitClose: true }); + this.session = session; + this.id = id; + this.pending = false; + this.rstCode = 0; + this.sentHeaders = undefined; + this.sentTrailers = undefined; + this.headersSent = false; + this.endAfterHeaders = false; + this.pushAllowed = session.type === constants.NGHTTP2_SESSION_SERVER && session.remoteSettings.enablePush; + this._sendWindow = session.remoteSettings.initialWindowSize; + this._receiveWindow = session.localSettings.initialWindowSize; + this._pendingWrite = null; + this._localEnded = false; + this._remoteEnded = false; + this._waitForTrailers = !!options.waitForTrailers; + this._timeout = null; + session._streams.set(id, this); + this.once('close', () => { session._streams.delete(id); session._maybeClose(); if (this._timeout) clearTimeout(this._timeout); }); + } + _read() {} + _write(chunk, encoding, done) { + if (this.session.type === constants.NGHTTP2_SESSION_SERVER && !this.headersSent) this.respond(); + this._pendingWrite = { data: Buffer.from(chunk), offset: 0, done }; + this._flushData(); + } + _flushData() { + const pending = this._pendingWrite; + if (!pending || this.destroyed) return; + while (pending.offset < pending.data.length && this._sendWindow > 0 && this.session._sendWindow > 0) { + const length = Math.min(pending.data.length - pending.offset, this._sendWindow, this.session._sendWindow, this.session.remoteSettings.maxFrameSize); + this.session._frame(0, 0, this.id, pending.data.subarray(pending.offset, pending.offset + length)); + pending.offset += length; + this._sendWindow -= length; + this.session._sendWindow -= length; + } + if (pending.offset === pending.data.length) { this._pendingWrite = null; pending.done(); } + } + _final(done) { + if (this._localEnded) { done(); return; } + if (this.session.type === constants.NGHTTP2_SESSION_SERVER && !this.headersSent) this.respond(); + if (this._waitForTrailers) { this._trailerCallback = done; this.emit('wantTrailers'); return; } + this.session._frame(0, 1, this.id, Buffer.alloc(0)); + this._localEnded = true; + done(); + } + _destroy(reason, done) { + if (!this._localEnded || !this._remoteEnded) { + if (!this.session.destroyed && !this._resetReceived) this.session._reset(this.id, this.rstCode || (reason ? constants.NGHTTP2_INTERNAL_ERROR : constants.NGHTTP2_CANCEL)); + } + if (this._pendingWrite) { const pending = this._pendingWrite; this._pendingWrite = null; pending.done(reason || error('ERR_STREAM_DESTROYED', 'HTTP/2 stream was destroyed.')); } + done(reason); + } + respond(headers = {}, options = {}) { + if (this.headersSent) throw error('ERR_HTTP2_HEADERS_SENT', 'Response has already been initiated.'); + headers = { ':status': 200, ...headers }; + integer(Number(headers[':status']), 200, 599, 'status'); + this.headersSent = true; + this.sentHeaders = headers; + this._waitForTrailers = !!options.waitForTrailers; + this.endAfterHeaders = !!options.endStream; + this.session._headers(this.id, headers, options.endStream ? 1 : 0); + if (options.endStream) { this._localEnded = true; this.end(); } + } + additionalHeaders(headers) { + if (this.headersSent) throw error('ERR_HTTP2_HEADERS_AFTER_RESPOND', 'Cannot send informational headers after the response.'); + integer(Number(headers[':status']), 100, 199, 'informational status'); + this.session._headers(this.id, headers, 0); + } + sendTrailers(headers) { + if (!this._trailerCallback) throw error('ERR_HTTP2_TRAILERS_NOT_READY', 'Trailers cannot be sent until wantTrailers.'); + this.sentTrailers = headers; + this.session._headers(this.id, headers, 1); + this._localEnded = true; + const done = this._trailerCallback; this._trailerCallback = null; done(); + } + close(code = constants.NGHTTP2_NO_ERROR, callback) { + if (callback) this.once('close', callback); + this.rstCode = code; + this.session._reset(this.id, code); + this._resetReceived = true; + this.destroy(); + } + setTimeout(milliseconds, callback) { + if (this._timeout) clearTimeout(this._timeout); + if (callback) this.once('timeout', callback); + this._timeout = milliseconds ? setTimeout(() => this.emit('timeout'), milliseconds) : null; + return this; + } + priority(options = {}) { + const buffer = Buffer.alloc(5); + buffer.writeUInt32BE(((options.parent || 0) | (options.exclusive ? 0x80000000 : 0)) >>> 0); + buffer[4] = integer(options.weight || 16, 1, 256, 'weight') - 1; + if (!options.silent) this.session._frame(2, 0, this.id, buffer); + } + pushStream(headers, options, callback) { + if (typeof options === 'function') { callback = options; options = {}; } + if (!this.pushAllowed) { process.nextTick(callback, error('ERR_HTTP2_PUSH_DISABLED', 'HTTP/2 push is disabled.')); return; } + const id = this.session._nextId; this.session._nextId += 2; + const pushed = new Http2Stream(this.session, id, options || {}); + pushed._remoteEnded = true; pushed.push(null); + this.session._headers(this.id, headers, 0, id); + process.nextTick(callback, null, pushed, headers, 0); + } + respondWithFile(path, headers, options = {}) { + const fs = require('fs'); + const stream = fs.createReadStream(path, options); + stream.once('error', reason => options.onError ? options.onError(reason) : this.destroy(reason)); + stream.once('open', () => { this.respond(headers, options); stream.pipe(this); }); + } +} + +class Http2Session extends EventEmitter { + constructor(socket, server, options = {}, authority) { + super(); + this.socket = socket; + this.type = server ? constants.NGHTTP2_SESSION_SERVER : constants.NGHTTP2_SESSION_CLIENT; + this.encrypted = !!socket.encrypted; + this.alpnProtocol = this.encrypted ? socket.alpnProtocol : 'h2c'; + this.connecting = socket.connecting || !!socket._secureConnecting; + this.closed = false; + this.destroyed = false; + this.remoteSettings = { ...defaults }; + this.localSettings = { ...defaults, ...options.settings }; + this.pendingSettingsAck = true; + this._authority = authority; + this._streams = new Map(); + this._nextId = server ? 2 : 1; + this._lastPeerId = 0; + this._sendWindow = 65535; + this._receiveWindow = 65535; + this._input = Buffer.alloc(0); + this._prefaceReceived = !server; + this._block = null; + this._encoder = hpack.compressor.create({ table: { maxSize: 4096 } }); + this._decoder = hpack.decompressor.create({ table: { maxSize: this.localSettings.headerTableSize } }); + this._encoder.on('error', reason => this.destroy(reason, constants.NGHTTP2_COMPRESSION_ERROR)); + this._decoder.on('error', reason => this.destroy(reason, constants.NGHTTP2_COMPRESSION_ERROR)); + this._pings = new Map(); + this._settingsCallbacks = [null]; + socket.on('data', data => this._receive(data)); + socket.on('error', reason => this.destroy(reason)); + socket.on('close', () => { + if (!this.destroyed) this.destroy(); + if (!this._closedEmitted) { this._closedEmitted = true; this.emit('close'); } + }); + const connected = () => { + this.connecting = false; + this.alpnProtocol = this.encrypted ? socket.alpnProtocol : 'h2c'; + this.emit('connect', this, socket); + }; + if (this.connecting) socket.once(this.encrypted ? 'secureConnect' : 'connect', connected); + else process.nextTick(connected); + if (!server) socket.write(preface); + this._frame(4, 0, 0, getPackedSettings(options.settings || {})); + } + _frame(type, flags, id, payload) { + if (this.destroyed || this.socket.destroyed || this.socket.writableEnded) return; + const header = Buffer.alloc(9); + header.writeUIntBE(payload.length, 0, 3); header[3] = type; header[4] = flags; header.writeUInt32BE(id & 0x7fffffff, 5); + this.socket.write(Buffer.concat([header, payload])); + } + _headers(id, headers, flags, promisedId) { + this._encoder.write(headerList(headers)); + const chunks = []; let chunk; + while ((chunk = this._encoder.read()) !== null) chunks.push(chunk); + let block = Buffer.concat(chunks); + if (promisedId !== undefined) { const prefix = Buffer.alloc(4); prefix.writeUInt32BE(promisedId); block = Buffer.concat([prefix, block]); } + const maximum = this.remoteSettings.maxFrameSize; + for (let offset = 0, first = true; first || offset < block.length; offset += maximum, first = false) { + const fragment = block.subarray(offset, offset + maximum); + this._frame(first ? promisedId === undefined ? 1 : 5 : 9, (first ? flags : 0) | (offset + maximum >= block.length ? 4 : 0), id, fragment); + } + } + _reset(id, code) { const payload = Buffer.alloc(4); payload.writeUInt32BE(code); this._frame(3, 0, id, payload); } + _receive(data) { + if (this.destroyed) return; + this._input = Buffer.concat([this._input, data]); + try { + if (!this._prefaceReceived) { + if (this._input.length < preface.length) return; + if (!this._input.subarray(0, preface.length).equals(preface)) throw error('ERR_HTTP2_ERROR', 'Invalid HTTP/2 connection preface.'); + this._input = this._input.subarray(preface.length); this._prefaceReceived = true; + } + while (this._input.length >= 9 && !this.destroyed) { + const length = this._input.readUIntBE(0, 3), type = this._input[3], flags = this._input[4], id = this._input.readUInt32BE(5) & 0x7fffffff; + if (length > this.localSettings.maxFrameSize) throw error('ERR_HTTP2_FRAME_SIZE_ERROR', 'HTTP/2 frame exceeds maxFrameSize.'); + if (this._input.length < length + 9) return; + const payload = this._input.subarray(9, length + 9); this._input = this._input.subarray(length + 9); + if (this._block && (type !== 9 || id !== this._block.id)) throw error('ERR_HTTP2_ERROR', 'Expected a CONTINUATION frame.'); + this._handle(type, flags, id, payload); + } + } catch (reason) { this.destroy(reason, constants.NGHTTP2_PROTOCOL_ERROR); } + } + _handle(type, flags, id, payload) { + let stream = this._streams.get(id); + if (type === 4) { + if (id !== 0 || payload.length % 6 || flags & 1 && payload.length) throw error('ERR_HTTP2_ERROR', 'Invalid SETTINGS frame.'); + if (flags & 1) { + const callback = this._settingsCallbacks.shift(); this.pendingSettingsAck = this._settingsCallbacks.length > 0; + if (callback) callback(null, this.localSettings, 0); + this.emit('localSettings', this.localSettings); return; + } + const settings = getUnpackedSettings(payload); + if (settings.initialWindowSize !== undefined) { + const delta = settings.initialWindowSize - this.remoteSettings.initialWindowSize; + for (const active of this._streams.values()) active._sendWindow += delta; + } + Object.assign(this.remoteSettings, settings); + if (settings.headerTableSize !== undefined) this._encoder.updateTableSize(settings.headerTableSize); + this._frame(4, 1, 0, Buffer.alloc(0)); this.emit('remoteSettings', this.remoteSettings); + for (const active of this._streams.values()) active._flushData(); + return; + } + if (type === 6) { + if (id !== 0 || payload.length !== 8) throw error('ERR_HTTP2_ERROR', 'Invalid PING frame.'); + if (!(flags & 1)) { this._frame(6, 1, 0, payload); this.emit('ping', payload); } + else { const pending = this._pings.get(payload.toString('hex')); if (pending) { this._pings.delete(payload.toString('hex')); pending.callback(null, performance.now() - pending.start, payload); } } + return; + } + if (type === 7) { + if (id !== 0 || payload.length < 8) throw error('ERR_HTTP2_ERROR', 'Invalid GOAWAY frame.'); + this.closed = true; + this.emit('goaway', payload.readUInt32BE(4), payload.readUInt32BE(0) & 0x7fffffff, payload.subarray(8)); + this._maybeClose(); return; + } + if (type === 8) { + if (payload.length !== 4) throw error('ERR_HTTP2_ERROR', 'Invalid WINDOW_UPDATE frame.'); + const increment = payload.readUInt32BE() & 0x7fffffff; + if (!increment) throw error('ERR_HTTP2_ERROR', 'WINDOW_UPDATE increment must be positive.'); + if (id === 0) { this._sendWindow += increment; if (this._sendWindow > 0x7fffffff) throw error('ERR_HTTP2_ERROR', 'Connection flow-control window overflow.'); } + else if (stream) { stream._sendWindow += increment; if (stream._sendWindow > 0x7fffffff) { stream.close(constants.NGHTTP2_FLOW_CONTROL_ERROR); return; } } + for (const active of this._streams.values()) active._flushData(); + return; + } + if (type === 1 || type === 5 || type === 9) { + if (id === 0) throw error('ERR_HTTP2_ERROR', 'Header frame requires a stream.'); + let fragment = payload, promisedId; + if (type !== 9 && flags & 8) { const padding = payload[0]; if (padding >= payload.length) throw error('ERR_HTTP2_ERROR', 'Invalid header padding.'); fragment = payload.subarray(1, payload.length - padding); } + if (type === 1 && flags & 32) { if (fragment.length < 5) throw error('ERR_HTTP2_ERROR', 'Invalid header priority.'); fragment = fragment.subarray(5); } + if (type === 5) { if (fragment.length < 4) throw error('ERR_HTTP2_ERROR', 'Invalid PUSH_PROMISE.'); promisedId = fragment.readUInt32BE() & 0x7fffffff; fragment = fragment.subarray(4); } + if (type === 9) { if (!this._block) throw error('ERR_HTTP2_ERROR', 'Unexpected CONTINUATION.'); this._block.chunks.push(fragment); } + else this._block = { id, flags, promisedId, chunks: [fragment] }; + if (flags & 4) { const block = this._block; this._block = null; this._receivedHeaders(block); } + return; + } + if (type === 0) { + if (!id) throw error('ERR_HTTP2_ERROR', 'DATA frame requires a stream.'); + if (!stream) { this._reset(id, constants.NGHTTP2_STREAM_CLOSED); return; } + const padding = flags & 8 ? payload[0] : 0; + if (flags & 8 && padding >= payload.length) throw error('ERR_HTTP2_ERROR', 'Invalid DATA padding.'); + const data = flags & 8 ? payload.subarray(1, payload.length - padding) : payload; + this._receiveWindow -= payload.length; stream._receiveWindow -= payload.length; + if (this._receiveWindow < 0 || stream._receiveWindow < 0) throw error('ERR_HTTP2_ERROR', 'Receive flow-control window exceeded.'); + if (data.length) stream.push(data); + if (payload.length) { + const update = Buffer.alloc(4); update.writeUInt32BE(payload.length); + this._frame(8, 0, 0, update); this._frame(8, 0, id, update); + this._receiveWindow += payload.length; stream._receiveWindow += payload.length; + } + if (flags & 1) { stream._remoteEnded = true; stream.push(null); } + return; + } + if (type === 3) { + if (!id || payload.length !== 4) throw error('ERR_HTTP2_ERROR', 'Invalid RST_STREAM frame.'); + if (stream) { stream.rstCode = payload.readUInt32BE(); stream._resetReceived = true; stream.destroy(stream.rstCode ? error('ERR_HTTP2_STREAM_ERROR', 'Stream closed with code ' + stream.rstCode) : undefined); } + return; + } + if (type === 2 && (!id || payload.length !== 5)) throw error('ERR_HTTP2_ERROR', 'Invalid PRIORITY frame.'); + } + _receivedHeaders(block) { + this._decoder.write(Buffer.concat(block.chunks)); this._decoder.execute(); + if (this.destroyed) return; + const headers = Object.create(null), raw = []; let entry, size = 0, ordinary = false; + while ((entry = this._decoder.read()) !== null) { + const name = entry.name, value = entry.value; + size += name.length + value.length + 32; + if (size > this.localSettings.maxHeaderListSize) throw error('ERR_HTTP2_ERROR', 'Header list is too large.'); + if (name.startsWith(':')) { if (ordinary || headers[name] !== undefined) throw error('ERR_HTTP2_ERROR', 'Invalid pseudo-header ordering.'); } + else ordinary = true; + headerList({ [name]: value }); raw.push(name, value); + if (name === 'set-cookie') (headers[name] || (headers[name] = [])).push(value); + else if (headers[name] === undefined) headers[name] = name === ':status' ? Number(value) : value; + else headers[name] += (name === 'cookie' ? '; ' : ', ') + value; + } + const id = block.promisedId === undefined ? block.id : block.promisedId; + let stream = this._streams.get(id); + if (!stream) { + const incomingParity = this.type === constants.NGHTTP2_SESSION_SERVER ? 1 : 0; + if (id <= this._lastPeerId || id % 2 !== incomingParity) throw error('ERR_HTTP2_ERROR', 'Invalid peer stream identifier.'); + this._lastPeerId = id; + stream = new Http2Stream(this, id); + stream._receivedInitialHeaders = block.promisedId === undefined; + if (block.promisedId !== undefined) { stream._localEnded = true; stream.end(); } + this.emit('stream', stream, headers, block.flags, raw); + } else if (this.type === constants.NGHTTP2_SESSION_CLIENT && !stream._receivedInitialHeaders) { + if (headers[':status'] >= 200) { stream._receivedInitialHeaders = true; stream.emit('response', headers, block.flags, raw); } + else stream.emit('headers', headers, block.flags, raw); + } else stream.emit('trailers', headers, block.flags, raw); + if (block.flags & 1 && block.promisedId === undefined) { stream._remoteEnded = true; stream.push(null); } + } + request(headers = {}, options = {}) { + if (this.closed || this.destroyed) throw error('ERR_HTTP2_GOAWAY_SESSION', 'New streams cannot be created after GOAWAY.'); + headers = { ':method': 'GET', ':path': '/', ':scheme': this.encrypted ? 'https' : 'http', ':authority': this._authority.host, ...headers }; + if (headers[':method'] === 'CONNECT') { delete headers[':path']; delete headers[':scheme']; } + const stream = new Http2Stream(this, this._nextId, options); this._nextId += 2; + stream.sentHeaders = headers; + stream.headersSent = true; + const end = options.endStream === undefined ? ['GET', 'HEAD', 'DELETE'].includes(headers[':method']) : !!options.endStream; + this._headers(stream.id, headers, end ? 1 : 0); + if (end) { stream._localEnded = true; stream.end(); } + return stream; + } + settings(settings, callback) { + const payload = getPackedSettings(settings); + Object.assign(this.localSettings, settings); this.pendingSettingsAck = true; + this._settingsCallbacks.push(callback || null); this._frame(4, 0, 0, payload); + } + ping(payload, callback) { + if (typeof payload === 'function') { callback = payload; payload = require('crypto').randomBytes(8); } + payload = payload === undefined ? require('crypto').randomBytes(8) : Buffer.from(payload); + if (payload.length !== 8) throw new RangeError('HTTP/2 PING payload must contain eight bytes.'); + if (typeof callback !== 'function') throw new TypeError('A ping callback is required.'); + this._pings.set(payload.toString('hex'), { callback, start: performance.now() }); this._frame(6, 0, 0, payload); return true; + } + goaway(code = 0, lastStreamId = this._lastPeerId, opaqueData = Buffer.alloc(0)) { + const payload = Buffer.alloc(8); payload.writeUInt32BE(lastStreamId); payload.writeUInt32BE(code, 4); + this._frame(7, 0, 0, Buffer.concat([payload, Buffer.from(opaqueData)])); + } + close(callback) { if (callback) this.once('close', callback); this.closed = true; this._maybeClose(); } + _maybeClose() { + if (this.closed && !this.destroyed && !this._transportClosing && this._streams.size === 0) { + this._transportClosing = true; this.goaway(); this.socket.end(); + } + } + destroy(reason, code = constants.NGHTTP2_NO_ERROR) { + if (this.destroyed) return; + this.goaway(code); this.destroyed = true; this.closed = true; + for (const stream of this._streams.values()) { stream._resetReceived = true; stream.destroy(reason); } + this.socket.destroy(); + if (reason) this.emit('error', reason); + } + setTimeout(milliseconds, callback) { this.socket.setTimeout(milliseconds); if (callback) this.on('timeout', callback); this.socket.on('timeout', () => this.emit('timeout')); return this; } + setLocalWindowSize(size) { integer(size, 0, 0x7fffffff, 'window size'); const increment = size - this._receiveWindow; if (increment > 0) { const value = Buffer.alloc(4); value.writeUInt32BE(increment); this._frame(8, 0, 0, value); this._receiveWindow = size; } } + ref() { this.socket.ref(); return this; } + unref() { this.socket.unref(); return this; } +} + +class Http2ServerRequest extends Readable { + constructor(stream, headers, rawHeaders) { + super(); this.stream = stream; this.socket = stream.session.socket; this.connection = this.socket; + this.headers = headers; this.rawHeaders = rawHeaders; this.trailers = {}; this.rawTrailers = []; + this.method = headers[':method']; this.url = headers[':path']; this.authority = headers[':authority']; this.scheme = headers[':scheme']; + this.httpVersion = '2.0'; this.httpVersionMajor = 2; this.httpVersionMinor = 0; this.complete = false; this.aborted = false; + stream.on('data', data => { if (!this.push(data)) stream.pause(); }); + stream.on('end', () => { this.complete = true; this.push(null); }); + stream.on('trailers', (trailers, flags, raw) => { this.trailers = trailers; this.rawTrailers = raw; }); + stream.on('error', reason => this.destroy(reason)); + } + _read() { this.stream.resume(); } + setTimeout(milliseconds, callback) { this.stream.setTimeout(milliseconds, callback); return this; } +} +class Http2ServerResponse extends Writable { + constructor(stream) { + super(); this.stream = stream; this.socket = stream.session.socket; this.connection = this.socket; + this.statusCode = 200; this.statusMessage = ''; this.sendDate = true; this.headersSent = false; + this._headers = Object.create(null); this._trailers = null; + } + setHeader(name, value) { if (this.headersSent) throw error('ERR_HTTP2_HEADERS_SENT', 'Headers are already sent.'); headerList({ [name.toLowerCase()]: value }); this._headers[name.toLowerCase()] = value; return this; } + appendHeader(name, value) { const previous = this.getHeader(name); return this.setHeader(name, previous === undefined ? value : [].concat(previous, value)); } + getHeader(name) { return this._headers[name.toLowerCase()]; } + getHeaders() { return { ...this._headers }; } + getHeaderNames() { return Object.keys(this._headers); } + hasHeader(name) { return this.getHeader(name) !== undefined; } + removeHeader(name) { if (this.headersSent) throw error('ERR_HTTP2_HEADERS_SENT', 'Headers are already sent.'); delete this._headers[name.toLowerCase()]; } + writeHead(code, message, headers) { this.statusCode = code; if (typeof message !== 'string') headers = message; if (headers) for (const [name, value] of Object.entries(headers)) this.setHeader(name, value); this.flushHeaders(); return this; } + flushHeaders() { + if (this.headersSent) return; + if (this.sendDate && !this.hasHeader('date')) this.setHeader('date', new Date().toUTCString()); + this.headersSent = true; this.stream.respond({ ':status': this.statusCode, ...this._headers }); + } + _write(data, encoding, done) { this.flushHeaders(); this.stream.write(data, encoding, done); } + _final(done) { this.flushHeaders(); this.stream.end(done); } + _destroy(reason, done) { if (reason) this.stream.destroy(reason); done(reason); } + addTrailers(headers) { this._trailers = headers; this.stream._waitForTrailers = true; this.stream.once('wantTrailers', () => this.stream.sendTrailers(headers)); } + setTimeout(milliseconds, callback) { this.stream.setTimeout(milliseconds, callback); return this; } + writeContinue() { this.stream.additionalHeaders({ ':status': 100 }); } + writeEarlyHints(headers) { this.stream.additionalHeaders({ ':status': 103, ...headers }); } +} +function attachServer(server, options, event) { + server._http2Sessions = new Set(); + server.on(event, socket => { + if (socket.encrypted && socket.alpnProtocol !== 'h2') { + if (!server.emit('unknownProtocol', socket)) socket.destroy(); + return; + } + const session = new Http2Session(socket, true, options); + server._http2Sessions.add(session); session.once('close', () => server._http2Sessions.delete(session)); + session.on('error', reason => { server.emit('sessionError', reason, session); }); + session.on('stream', (stream, headers, flags, raw) => { + server.emit('stream', stream, headers, flags, raw); + if (server.listenerCount('request')) server.emit('request', new Http2ServerRequest(stream, headers, raw), new Http2ServerResponse(stream)); + }); + server.emit('session', session); + }); + server.updateSettings = settings => { options.settings = { ...options.settings, ...settings }; for (const session of server._http2Sessions) session.settings(settings); }; + return server; +} +class Http2Server extends net.Server { + constructor(options = {}, handler) { if (typeof options === 'function') { handler = options; options = {}; } super(options); attachServer(this, options, 'connection'); if (handler) this.on('request', handler); } +} +class Http2SecureServer extends tls.Server { + constructor(options = {}, handler) { super({ ...options, ALPNProtocols: ['h2'] }); attachServer(this, options, 'secureConnection'); if (handler) this.on('request', handler); } +} +function connect(authority, options = {}, listener) { + if (typeof options === 'function') { listener = options; options = {}; } + const url = authority instanceof URL ? authority : new URL(authority); + if (!['http:', 'https:'].includes(url.protocol)) throw error('ERR_HTTP2_UNSUPPORTED_PROTOCOL', 'Unsupported HTTP/2 protocol.'); + const config = { ...options, host: url.hostname.replace(/^\[|\]$/g, ''), port: Number(url.port || (url.protocol === 'https:' ? 443 : 80)) }; + const socket = options.createConnection ? options.createConnection(url, config) : url.protocol === 'https:' + ? tls.connect({ ...config, servername: options.servername || config.host, ALPNProtocols: ['h2'] }) : net.connect(config); + const session = new Http2Session(socket, false, options, url); + if (listener) session.once('connect', listener); + return session; +} +module.exports = { + constants, sensitiveHeaders, connect, Http2ServerRequest, Http2ServerResponse, + createServer: (options, handler) => new Http2Server(options, handler), + createSecureServer: (options, handler) => new Http2SecureServer(options, handler), + getDefaultSettings: () => ({ ...defaults }), getPackedSettings, getUnpackedSettings, +}; diff --git a/src/Node/Lib/https.cjs b/src/Node/Lib/https.cjs new file mode 100644 index 00000000..1b14791e --- /dev/null +++ b/src/Node/Lib/https.cjs @@ -0,0 +1,40 @@ +'use strict'; + +const http = require('http'); +const tls = require('tls'); +const { urlToHttpOptions } = require('url'); + +class Agent extends http.Agent { + constructor(options = {}) { + super(options); + this.defaultPort = 443; + this.protocol = 'https:'; + } + createConnection(options, callback) { return tls.connect(options, callback); } + getName(options = {}) { + return super.getName(options) + ':' + ['servername', 'ca', 'cert', 'key', 'pfx', 'rejectUnauthorized', 'minVersion', 'maxVersion'] + .map(name => String(options[name] === undefined ? '' : options[name])).join(':'); + } +} +const globalAgent = new Agent({ keepAlive: true, scheduling: 'lifo', timeout: 5000 }); + +class Server extends http.Server { + constructor(options = {}, listener) { + if (typeof options === 'function') { listener = options; options = {}; } + super(options, listener); + this._tlsOptions = { ...options, isServer: true }; + } + _createSocket(handle) { return tls.Server.prototype._createSocket.call(this, handle); } + setSecureContext(options) { return tls.Server.prototype.setSecureContext.call(this, options); } +} +function request(input, options, callback) { + if (typeof options === 'function') { callback = options; options = undefined; } + const base = typeof input === 'string' || input instanceof URL ? urlToHttpOptions(input instanceof URL ? input : new URL(input)) : input || {}; + const config = { ...base, ...options }; + config.protocol = config.protocol || 'https:'; + if (config.protocol !== 'https:') throw Object.assign(new TypeError(`Protocol "${config.protocol}" not supported. Expected "https:"`), { code: 'ERR_INVALID_PROTOCOL' }); + config.agent = config.agent === undefined ? globalAgent : config.agent === false ? new Agent() : config.agent; + return new http.ClientRequest(config, callback); +} +function get(input, options, callback) { const result = request(input, options, callback); result.end(); return result; } +module.exports = { Agent, Server, globalAgent, request, get, createServer: (options, listener) => new Server(options, listener) }; diff --git a/src/Node/Lib/module.cjs b/src/Node/Lib/module.cjs new file mode 100644 index 00000000..8764d580 --- /dev/null +++ b/src/Node/Lib/module.cjs @@ -0,0 +1,12 @@ +'use strict'; + +const host = __phasisNodeHost; +const builtinModules = host.builtinNames(); +module.exports = { + builtinModules, + createRequire: (filename) => host.createRequire(filename), + isBuiltin: (name) => typeof name === 'string' && builtinModules.includes(name.startsWith('node:') ? name.slice(5) : name), + syncBuiltinESMExports() { + throw new Error('syncBuiltinESMExports has not been implemented'); + }, +}; diff --git a/src/Node/Lib/net.cjs b/src/Node/Lib/net.cjs new file mode 100644 index 00000000..0727d4b1 --- /dev/null +++ b/src/Node/Lib/net.cjs @@ -0,0 +1,216 @@ +'use strict'; + +const { Duplex } = require('stream'); +const { EventEmitter } = require('events'); +const { Buffer } = require('buffer'); +const host = __phasisNodeHost.net; + +function call(operation, ...args) { + const result = host.call(operation, ...args); + if (result.error) throw Object.assign(new Error(result.error.message), result.error); + return result.value; +} + +function normalize(args) { + let options; + if (args[0] !== null && typeof args[0] === 'object') options = { ...args[0] }; + else if (typeof args[0] === 'string' && !/^\d+$/.test(args[0])) options = { path: args[0] }; + else options = { port: args[0] === undefined ? 0 : Number(args[0]) }; + if (typeof args[1] === 'string' && options.path === undefined) options.host = args[1]; + if (typeof args[1] === 'number') options.backlog = args[1]; + if (typeof args[2] === 'number') options.backlog = args[2]; + const callback = typeof args[args.length - 1] === 'function' ? args[args.length - 1] : undefined; + if (options.path === undefined && (!Number.isInteger(options.port) || options.port < 0 || options.port > 65535)) { + throw Object.assign(new RangeError('Port should be >= 0 and < 65536'), { code: 'ERR_SOCKET_BAD_PORT' }); + } + return [options, callback]; +} + +class Socket extends Duplex { + constructor(options = {}) { + super({ ...options, allowHalfOpen: !!options.allowHalfOpen, autoDestroy: true, emitClose: true }); + this._handle = null; + this.connecting = false; + this.pending = true; + this.bytesRead = 0; + this.bytesWritten = 0; + this.timeout = 0; + this._timer = null; + this._referenced = true; + this._noDelay = true; + this._keepAlive = false; + this._onNative = (event, value) => this._native(event, value); + if (options.handle !== undefined) { + this._handle = options.handle; + this.pending = false; + call('callback', this._handle, this._onNative); + call('pause', this._handle, !!options.pauseOnCreate); + } + if (options.signal) { + const abort = () => this.destroy(Object.assign(new Error('The operation was aborted'), { name: 'AbortError', code: 'ABORT_ERR', cause: options.signal.reason })); + if (options.signal.aborted) process.nextTick(abort); + else { options.signal.addEventListener('abort', abort, { once: true }); this.once('close', () => options.signal.removeEventListener('abort', abort)); } + } + } + connect(...args) { + const [options, callback] = normalize(args); + if (callback) this.once('connect', callback); + if (this._handle !== null) throw Object.assign(new Error('Socket is already connected'), { code: 'ERR_SOCKET_IS_CONNECTED' }); + this.connecting = true; + this.pending = true; + try { + this._handle = call('connect', options, this._onNative); + call('ref', this._handle, this._referenced); + } catch (error) { process.nextTick(() => this.destroy(error)); } + return this; + } + _native(event, value) { + if (event === 'connect') { + this.connecting = false; + this.pending = false; + this._touch(); + this.emit('connect'); + this.emit('ready'); + } else if (event === 'data') { + this._touch(); + this.bytesRead += value.length; + if (!this.push(Buffer.from(value)) && this._handle !== null) call('pause', this._handle, true); + } else if (event === 'end') { + this.push(null); + } else if (event === 'error') { + this.destroy(Object.assign(new Error(value.message), value)); + } else if (event === 'close') { + this._handle = null; + this.connecting = false; + if (!this.destroyed) this.destroy(); + } + } + _read() { if (this._handle !== null) call('pause', this._handle, false); } + _write(chunk, encoding, callback) { + if (this.connecting) { this.once('connect', () => this._write(chunk, encoding, callback)); return; } + if (this._handle === null) { callback(Object.assign(new Error('Socket is closed'), { code: 'ERR_SOCKET_CLOSED' })); return; } + if (!Buffer.isBuffer(chunk)) chunk = Buffer.from(chunk, encoding); + this.bytesWritten += chunk.length; + this._touch(); + try { call('write', this._handle, chunk, callback); } catch (error) { callback(error); } + } + _final(callback) { + if (this.connecting) { this.once('connect', () => this._final(callback)); return; } + try { if (this._handle !== null) call('end', this._handle); callback(); } + catch (error) { callback(error); } + } + _destroy(error, callback) { + if (this._timer !== null) clearTimeout(this._timer); + const handle = this._handle; + this._handle = null; + this.connecting = false; + if (handle !== null) call('close', handle); + callback(error); + } + _touch() { + if (this._timer !== null) clearTimeout(this._timer); + if (this.timeout > 0 && !this.destroyed) { + this._timer = setTimeout(() => { this._timer = null; this.emit('timeout'); }, this.timeout); + if (this._timer.unref) this._timer.unref(); + } + } + setTimeout(timeout, callback) { + if (typeof timeout !== 'number' || timeout < 0 || !Number.isFinite(timeout)) throw new RangeError('timeout must be a non-negative number'); + this.timeout = timeout; + if (callback) this.once('timeout', callback); + this._touch(); + return this; + } + setNoDelay(enabled = true) { this._noDelay = !!enabled; if (this._handle !== null) call('noDelay', this._handle, this._noDelay); return this; } + setKeepAlive(enabled = false, initialDelay = 0) { this._keepAlive = !!enabled; if (this._handle !== null) call('keepAlive', this._handle, this._keepAlive, initialDelay); return this; } + ref() { this._referenced = true; if (this._handle !== null) call('ref', this._handle, true); return this; } + unref() { this._referenced = false; if (this._handle !== null) call('ref', this._handle, false); return this; } + address() { return this._handle === null ? {} : call('address', this._handle, false) || {}; } + _remote() { return this._handle === null ? {} : call('address', this._handle, true) || {}; } + get localAddress() { return this.address().address; } + get localPort() { return this.address().port; } + get localFamily() { return this.address().family; } + get remoteAddress() { return this._remote().address; } + get remotePort() { return this._remote().port; } + get remoteFamily() { return this._remote().family; } + get readyState() { return this.connecting ? 'opening' : this.destroyed ? 'closed' : this.readable && this.writable ? 'open' : this.readable ? 'readOnly' : this.writable ? 'writeOnly' : 'closed'; } + get bufferSize() { return this.writableLength; } + destroySoon() { if (this.writableFinished) this.destroy(); else this.end(() => this.destroy()); return this; } + resetAndDestroy() { return this.destroy(); } +} + +class Server extends EventEmitter { + constructor(options = {}, listener) { + super(); + if (typeof options === 'function') { listener = options; options = {}; } + this._options = options; + this._handle = null; + this._sockets = new Set(); + this._closing = false; + this._referenced = true; + this.listening = false; + if (listener) this.on('connection', listener); + } + listen(...args) { + if (this._handle !== null) throw Object.assign(new Error('Listen method has been called more than once without closing'), { code: 'ERR_SERVER_ALREADY_LISTEN' }); + const [options, callback] = normalize(args); + if (callback) this.once('listening', callback); + this._closing = false; + try { + this._handle = call('listen', options, (event, value) => { + if (event === 'connection') { + const socket = this._createSocket(value); + socket.server = this; + if (this.maxConnections !== undefined && this._sockets.size >= this.maxConnections) { + this.emit('drop', { localAddress: socket.localAddress, localPort: socket.localPort, localFamily: socket.localFamily, remoteAddress: socket.remoteAddress, remotePort: socket.remotePort, remoteFamily: socket.remoteFamily }); + socket.destroy(); + return; + } + this._sockets.add(socket); + socket.once('close', () => { this._sockets.delete(socket); this._maybeClose(); }); + this.emit('connection', socket); + } + }); + call('ref', this._handle, this._referenced); + this.listening = true; + process.nextTick(() => { if (this.listening) this.emit('listening'); }); + if (options.signal) { + const close = () => this.close(); + if (options.signal.aborted) process.nextTick(close); + else { options.signal.addEventListener('abort', close, { once: true }); this.once('close', () => options.signal.removeEventListener('abort', close)); } + } + } catch (error) { process.nextTick(() => this.emit('error', error)); } + return this; + } + address() { return this._handle === null ? null : call('address', this._handle, false); } + _createSocket(handle) { return new Socket({ ...this._options, handle, pauseOnCreate: this._options.pauseOnConnect }); } + close(callback) { + if (callback) this.once('close', callback); + if (!this.listening) { + const error = Object.assign(new Error('Server is not running.'), { code: 'ERR_SERVER_NOT_RUNNING' }); + process.nextTick(() => this.emit('close', error)); + return this; + } + this.listening = false; + this._closing = true; + const handle = this._handle; + this._handle = null; + if (handle !== null) call('close', handle); + this._maybeClose(); + return this; + } + _maybeClose() { if (this._closing && this._sockets.size === 0) { this._closing = false; process.nextTick(() => this.emit('close')); } } + getConnections(callback) { process.nextTick(callback, null, this._sockets.size); } + ref() { this._referenced = true; if (this._handle !== null) call('ref', this._handle, true); return this; } + unref() { this._referenced = false; if (this._handle !== null) call('ref', this._handle, false); return this; } + [Symbol.asyncDispose]() { return new Promise((resolve, reject) => this.close(error => error && error.code !== 'ERR_SERVER_NOT_RUNNING' ? reject(error) : resolve())); } +} + +const isIP = input => typeof input === 'string' ? call('isIP', input) : 0; +module.exports = { + Socket, Stream: Socket, Server, + createServer: (options, listener) => new Server(options, listener), + createConnection: (...args) => new Socket(typeof args[0] === 'object' ? args[0] : {}).connect(...args), + connect: (...args) => new Socket(typeof args[0] === 'object' ? args[0] : {}).connect(...args), + isIP, isIPv4: input => isIP(input) === 4, isIPv6: input => isIP(input) === 6, +}; diff --git a/src/Node/Lib/path.cjs b/src/Node/Lib/path.cjs new file mode 100644 index 00000000..dd51dee0 --- /dev/null +++ b/src/Node/Lib/path.cjs @@ -0,0 +1,1712 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +const { + ArrayPrototypeIncludes, + ArrayPrototypeJoin, + ArrayPrototypePush, + ArrayPrototypeSlice, + FunctionPrototypeBind, + StringPrototypeCharCodeAt, + StringPrototypeIncludes, + StringPrototypeIndexOf, + StringPrototypeLastIndexOf, + StringPrototypeRepeat, + StringPrototypeReplace, + StringPrototypeSlice, + StringPrototypeSplit, + StringPrototypeToLowerCase, + StringPrototypeToUpperCase, +} = require('./portable/primordials.cjs'); + +const { + CHAR_UPPERCASE_A, + CHAR_LOWERCASE_A, + CHAR_UPPERCASE_Z, + CHAR_LOWERCASE_Z, + CHAR_DOT, + CHAR_FORWARD_SLASH, + CHAR_BACKWARD_SLASH, + CHAR_COLON, + CHAR_QUESTION_MARK, +} = require('./portable/constants.cjs'); +const { + validateObject, + validateString, +} = require('./portable/validators.cjs'); + +const { + isWindows, + getLazy, +} = require('./portable/helpers.cjs'); + +const lazyMatchGlobPattern = getLazy(() => require('./portable/glob.cjs').matchGlobPattern); + +function isPathSeparator(code) { + return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; +} + +function isPosixPathSeparator(code) { + return code === CHAR_FORWARD_SLASH; +} + +const WINDOWS_RESERVED_NAMES = [ + 'CON', 'PRN', 'AUX', 'NUL', + 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', + 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9', + 'COM\xb9', 'COM\xb2', 'COM\xb3', + 'LPT\xb9', 'LPT\xb2', 'LPT\xb3', +]; + +function isWindowsReservedName(path, colonIndex) { + const devicePart = StringPrototypeToUpperCase(StringPrototypeSlice(path, 0, colonIndex)); + return ArrayPrototypeIncludes(WINDOWS_RESERVED_NAMES, devicePart); +} + +function isWindowsDeviceRoot(code) { + return (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || + (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z); +} + +// Resolves . and .. elements in a path with directory names +function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { + if (globalThis.__phasisNodeHost && __phasisNodeHost.path) + return __phasisNodeHost.path.normalizeString(path, allowAboveRoot, separator); + let res = ''; + let lastSegmentLength = 0; + let lastSlash = -1; + let dots = 0; + let code = 0; + for (let i = 0; i <= path.length; ++i) { + if (i < path.length) + code = StringPrototypeCharCodeAt(path, i); + else if (isPathSeparator(code)) + break; + else + code = CHAR_FORWARD_SLASH; + + if (isPathSeparator(code)) { + if (lastSlash === i - 1 || dots === 1) { + // NOOP + } else if (dots === 2) { + if (res.length < 2 || lastSegmentLength !== 2 || + StringPrototypeCharCodeAt(res, res.length - 1) !== CHAR_DOT || + StringPrototypeCharCodeAt(res, res.length - 2) !== CHAR_DOT) { + if (res.length > 2) { + const lastSlashIndex = res.length - lastSegmentLength - 1; + if (lastSlashIndex === -1) { + res = ''; + lastSegmentLength = 0; + } else { + res = StringPrototypeSlice(res, 0, lastSlashIndex); + lastSegmentLength = + res.length - 1 - StringPrototypeLastIndexOf(res, separator); + } + lastSlash = i; + dots = 0; + continue; + } else if (res.length !== 0) { + res = ''; + lastSegmentLength = 0; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + res += res.length > 0 ? `${separator}..` : '..'; + lastSegmentLength = 2; + } + } else { + if (res.length > 0) + res += `${separator}${StringPrototypeSlice(path, lastSlash + 1, i)}`; + else + res = StringPrototypeSlice(path, lastSlash + 1, i); + lastSegmentLength = i - lastSlash - 1; + } + lastSlash = i; + dots = 0; + } else if (code === CHAR_DOT && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} + +function formatExt(ext) { + return ext ? `${ext[0] === '.' ? '' : '.'}${ext}` : ''; +} + +/** + * @param {string} sep + * @param {{ + * dir?: string; + * root?: string; + * base?: string; + * name?: string; + * ext?: string; + * }} pathObject + * @returns {string} + */ +function _format(sep, pathObject) { + validateObject(pathObject, 'pathObject'); + const dir = pathObject.dir || pathObject.root; + const base = pathObject.base || + `${pathObject.name || ''}${formatExt(pathObject.ext)}`; + if (!dir) { + return base; + } + return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`; +} + +const forwardSlashRegExp = /\//g; + +const win32 = { + /** + * path.resolve([from ...], to) + * @param {...string} args + * @returns {string} + */ + resolve(...args) { + let resolvedDevice = ''; + let resolvedTail = ''; + let resolvedAbsolute = false; + + for (let i = args.length - 1; i >= -1; i--) { + let path; + if (i >= 0) { + path = args[i]; + validateString(path, `paths[${i}]`); + + // Skip empty entries + if (path.length === 0) { + continue; + } + } else if (resolvedDevice.length === 0) { + path = process.cwd(); + // Fast path for current directory + if (args.length === 0 || ((args.length === 1 && (args[0] === '' || args[0] === '.')) && + isPathSeparator(StringPrototypeCharCodeAt(path, 0)))) { + if (!isWindows) { + path = StringPrototypeReplace(path, forwardSlashRegExp, '\\'); + } + return path; + } + } else { + // Windows has the concept of drive-specific current working + // directories. If we've resolved a drive letter but not yet an + // absolute path, get cwd for that drive, or the process cwd if + // the drive cwd is not available. We're sure the device is not + // a UNC path at this points, because UNC paths are always absolute. + path = process.env[`=${resolvedDevice}`] || process.cwd(); + + // Verify that a cwd was found and that it actually points + // to our drive. If not, default to the drive's root. + if (path === undefined || + (StringPrototypeToLowerCase(StringPrototypeSlice(path, 0, 2)) !== + StringPrototypeToLowerCase(resolvedDevice) && + StringPrototypeCharCodeAt(path, 2) === CHAR_BACKWARD_SLASH)) { + path = `${resolvedDevice}\\`; + } + } + + const len = path.length; + let rootEnd = 0; + let device = ''; + let isAbsolute = false; + const code = StringPrototypeCharCodeAt(path, 0); + + // Try to match a root + if (len === 1) { + if (isPathSeparator(code)) { + // `path` contains just a path separator + rootEnd = 1; + isAbsolute = true; + } + } else if (isPathSeparator(code)) { + // Possible UNC root + + // If we started with a separator, we know we at least have an + // absolute path of some kind (UNC or otherwise) + isAbsolute = true; + + if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + while (j < len && + !isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j < len && j !== last) { + const firstPart = StringPrototypeSlice(path, last, j); + // Matched! + last = j; + // Match 1 or more path separators + while (j < len && + isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more non-path separators + while (j < len && + !isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j === len || j !== last) { + if (firstPart !== '.' && firstPart !== '?') { + // We matched a UNC root + device = + `\\\\${firstPart}\\${StringPrototypeSlice(path, last, j)}`; + rootEnd = j; + } else { + // We matched a device root (e.g. \\\\.\\PHYSICALDRIVE0) + device = `\\\\${firstPart}`; + rootEnd = 4; + } + } + } + } + } else { + rootEnd = 1; + } + } else if (isWindowsDeviceRoot(code) && + StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) { + // Possible device root + device = StringPrototypeSlice(path, 0, 2); + rootEnd = 2; + if (len > 2 && isPathSeparator(StringPrototypeCharCodeAt(path, 2))) { + // Treat separator following drive name as an absolute path + // indicator + isAbsolute = true; + rootEnd = 3; + } + } + + if (device.length > 0) { + if (resolvedDevice.length > 0) { + if (StringPrototypeToLowerCase(device) !== + StringPrototypeToLowerCase(resolvedDevice)) + // This path points to another device so it is not applicable + continue; + } else { + resolvedDevice = device; + } + } + + if (resolvedAbsolute) { + if (resolvedDevice.length > 0) + break; + } else { + resolvedTail = + `${StringPrototypeSlice(path, rootEnd)}\\${resolvedTail}`; + resolvedAbsolute = isAbsolute; + if (isAbsolute && resolvedDevice.length > 0) { + break; + } + } + } + + // At this point the path should be resolved to a full absolute path, + // but handle relative paths to be safe (might happen when process.cwd() + // fails) + + // Normalize the tail path + resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', + isPathSeparator); + + return resolvedAbsolute ? + `${resolvedDevice}\\${resolvedTail}` : + `${resolvedDevice}${resolvedTail}` || '.'; + }, + + /** + * @param {string} path + * @returns {string} + */ + normalize(path) { + validateString(path, 'path'); + const len = path.length; + if (len === 0) + return '.'; + let rootEnd = 0; + let device; + let isAbsolute = false; + const code = StringPrototypeCharCodeAt(path, 0); + + // Try to match a root + if (len === 1) { + // `path` contains just a single char, exit early to avoid + // unnecessary work + return isPosixPathSeparator(code) ? '\\' : path; + } + if (isPathSeparator(code)) { + // Possible UNC root + + // If we started with a separator, we know we at least have an absolute + // path of some kind (UNC or otherwise) + isAbsolute = true; + + if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + while (j < len && + !isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j < len && j !== last) { + const firstPart = StringPrototypeSlice(path, last, j); + // Matched! + last = j; + // Match 1 or more path separators + while (j < len && + isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more non-path separators + while (j < len && + !isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j === len || j !== last) { + if (firstPart === '.' || firstPart === '?') { + // We matched a device root (e.g. \\\\.\\PHYSICALDRIVE0) + device = `\\\\${firstPart}`; + rootEnd = 4; + const colonIndex = StringPrototypeIndexOf(path, ':'); + // Special case: handle \\?\COM1: or similar reserved device paths + const possibleDevice = StringPrototypeSlice(path, 4, colonIndex + 1); + if (isWindowsReservedName(possibleDevice, possibleDevice.length - 1)) { + device = `\\\\?\\${possibleDevice}`; + rootEnd = 4 + possibleDevice.length; + } + } else if (j === len) { + // We matched a UNC root only + // Return the normalized version of the UNC root since there + // is nothing left to process + return `\\\\${firstPart}\\${StringPrototypeSlice(path, last)}\\`; + } else { + // We matched a UNC root with leftovers + device = + `\\\\${firstPart}\\${StringPrototypeSlice(path, last, j)}`; + rootEnd = j; + } + } + } + } + } else { + rootEnd = 1; + } + } else { + const colonIndex = StringPrototypeIndexOf(path, ':'); + if (colonIndex > 0) { + if (isWindowsDeviceRoot(code) && colonIndex === 1) { + device = StringPrototypeSlice(path, 0, 2); + rootEnd = 2; + if (len > 2 && isPathSeparator(StringPrototypeCharCodeAt(path, 2))) { + isAbsolute = true; + rootEnd = 3; + } + } else if (isWindowsReservedName(path, colonIndex)) { + device = StringPrototypeSlice(path, 0, colonIndex + 1); + rootEnd = colonIndex + 1; + + } + } + } + + let tail = rootEnd < len ? + normalizeString(StringPrototypeSlice(path, rootEnd), + !isAbsolute, '\\', isPathSeparator) : + ''; + if (tail.length === 0 && !isAbsolute) + tail = '.'; + if (tail.length > 0 && + isPathSeparator(StringPrototypeCharCodeAt(path, len - 1))) + tail += '\\'; + if (!isAbsolute && device === undefined && StringPrototypeIncludes(path, ':')) { + // If the original path was not absolute and if we have not been able to + // resolve it relative to a particular device, we need to ensure that the + // `tail` has not become something that Windows might interpret as an + // absolute path. See CVE-2024-36139. + if (tail.length >= 2 && + isWindowsDeviceRoot(StringPrototypeCharCodeAt(tail, 0)) && + StringPrototypeCharCodeAt(tail, 1) === CHAR_COLON) { + return `.\\${tail}`; + } + let index = StringPrototypeIndexOf(path, ':'); + + do { + if (index === len - 1 || isPathSeparator(StringPrototypeCharCodeAt(path, index + 1))) { + return `.\\${tail}`; + } + } while ((index = StringPrototypeIndexOf(path, ':', index + 1)) !== -1); + } + const colonIndex = StringPrototypeIndexOf(path, ':'); + if (isWindowsReservedName(path, colonIndex)) { + return `.\\${device ?? ''}${tail}`; + } + if (device === undefined) { + return isAbsolute ? `\\${tail}` : tail; + } + return isAbsolute ? `${device}\\${tail}` : `${device}${tail}`; + }, + + /** + * @param {string} path + * @returns {boolean} + */ + isAbsolute(path) { + validateString(path, 'path'); + const len = path.length; + if (len === 0) + return false; + + const code = StringPrototypeCharCodeAt(path, 0); + return isPathSeparator(code) || + // Possible device root + (len > 2 && + isWindowsDeviceRoot(code) && + StringPrototypeCharCodeAt(path, 1) === CHAR_COLON && + isPathSeparator(StringPrototypeCharCodeAt(path, 2))); + }, + + /** + * @param {...string} args + * @returns {string} + */ + join(...args) { + if (args.length === 0) + return '.'; + + const path = []; + for (let i = 0; i < args.length; ++i) { + const arg = args[i]; + validateString(arg, 'path'); + if (arg.length > 0) { + ArrayPrototypePush(path, arg); + } + } + + if (path.length === 0) + return '.'; + + const firstPart = path[0]; + let joined = ArrayPrototypeJoin(path, '\\'); + + // Make sure that the joined path doesn't start with two slashes, because + // normalize() will mistake it for a UNC path then. + // + // This step is skipped when it is very clear that the user actually + // intended to point at a UNC path. This is assumed when the first + // non-empty string arguments starts with exactly two slashes followed by + // at least one more non-slash character. + // + // Note that for normalize() to treat a path as a UNC path it needs to + // have at least 2 components, so we don't filter for that here. + // This means that the user can use join to construct UNC paths from + // a server name and a share name; for example: + // path.join('//server', 'share') -> '\\\\server\\share\\') + let needsReplace = true; + let slashCount = 0; + if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 0))) { + ++slashCount; + const firstLen = firstPart.length; + if (firstLen > 1 && + isPathSeparator(StringPrototypeCharCodeAt(firstPart, 1))) { + ++slashCount; + if (firstLen > 2) { + if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 2))) + ++slashCount; + else { + // We matched a UNC path in the first part + needsReplace = false; + } + } + } + } + if (needsReplace) { + // Find any more consecutive slashes we need to replace + while (slashCount < joined.length && + isPathSeparator(StringPrototypeCharCodeAt(joined, slashCount))) { + slashCount++; + } + + // Replace the slashes if needed + if (slashCount >= 2) + joined = `\\${StringPrototypeSlice(joined, slashCount)}`; + } + + // Skip normalization when reserved device names are present + const parts = []; + let part = ''; + + for (let i = 0; i < joined.length; i++) { + if (joined[i] === '\\') { + if (part) parts.push(part); + part = ''; + // Skip consecutive backslashes + while (i + 1 < joined.length && joined[i + 1] === '\\') i++; + } else { + part += joined[i]; + } + } + // Add the final part if any + if (part) parts.push(part); + + // Check if any part has a Windows reserved name + if (parts.some((p) => { + const colonIndex = StringPrototypeIndexOf(p, ':'); + return colonIndex !== -1 && isWindowsReservedName(p, colonIndex); + })) { + // Replace forward slashes with backslashes + let result = ''; + for (let i = 0; i < joined.length; i++) { + result += joined[i] === '/' ? '\\' : joined[i]; + } + return result; + } + + return win32.normalize(joined); + }, + + /** + * It will solve the relative path from `from` to `to`, for instance + * from = 'C:\\orandea\\test\\aaa' + * to = 'C:\\orandea\\impl\\bbb' + * The output of the function should be: '..\\..\\impl\\bbb' + * @param {string} from + * @param {string} to + * @returns {string} + */ + relative(from, to) { + validateString(from, 'from'); + validateString(to, 'to'); + + if (from === to) + return ''; + + const fromOrig = win32.resolve(from); + const toOrig = win32.resolve(to); + + if (fromOrig === toOrig) + return ''; + + from = StringPrototypeToLowerCase(fromOrig); + to = StringPrototypeToLowerCase(toOrig); + + if (from === to) + return ''; + + if (fromOrig.length !== from.length || toOrig.length !== to.length) { + const fromSplit = StringPrototypeSplit(fromOrig, '\\'); + const toSplit = StringPrototypeSplit(toOrig, '\\'); + if (fromSplit[fromSplit.length - 1] === '') { + fromSplit.pop(); + } + if (toSplit[toSplit.length - 1] === '') { + toSplit.pop(); + } + + const fromLen = fromSplit.length; + const toLen = toSplit.length; + const length = fromLen < toLen ? fromLen : toLen; + + let i; + for (i = 0; i < length; i++) { + if (StringPrototypeToLowerCase(fromSplit[i]) !== StringPrototypeToLowerCase(toSplit[i])) { + break; + } + } + + if (i === 0) { + return toOrig; + } else if (i === length) { + if (toLen > length) { + return ArrayPrototypeJoin(ArrayPrototypeSlice(toSplit, i), '\\'); + } + if (fromLen > length) { + return StringPrototypeRepeat('..\\', fromLen - 1 - i) + '..'; + } + return ''; + } + + return StringPrototypeRepeat('..\\', fromLen - i) + ArrayPrototypeJoin(ArrayPrototypeSlice(toSplit, i), '\\'); + } + + // Trim any leading backslashes + let fromStart = 0; + while (fromStart < from.length && + StringPrototypeCharCodeAt(from, fromStart) === CHAR_BACKWARD_SLASH) { + fromStart++; + } + // Trim trailing backslashes (applicable to UNC paths only) + let fromEnd = from.length; + while ( + fromEnd - 1 > fromStart && + StringPrototypeCharCodeAt(from, fromEnd - 1) === CHAR_BACKWARD_SLASH + ) { + fromEnd--; + } + const fromLen = fromEnd - fromStart; + + // Trim any leading backslashes + let toStart = 0; + while (toStart < to.length && + StringPrototypeCharCodeAt(to, toStart) === CHAR_BACKWARD_SLASH) { + toStart++; + } + // Trim trailing backslashes (applicable to UNC paths only) + let toEnd = to.length; + while (toEnd - 1 > toStart && + StringPrototypeCharCodeAt(to, toEnd - 1) === CHAR_BACKWARD_SLASH) { + toEnd--; + } + const toLen = toEnd - toStart; + + // Compare paths to find the longest common path from root + const length = fromLen < toLen ? fromLen : toLen; + let lastCommonSep = -1; + let i = 0; + for (; i < length; i++) { + const fromCode = StringPrototypeCharCodeAt(from, fromStart + i); + if (fromCode !== StringPrototypeCharCodeAt(to, toStart + i)) + break; + else if (fromCode === CHAR_BACKWARD_SLASH) + lastCommonSep = i; + } + + // We found a mismatch before the first common path separator was seen, so + // return the original `to`. + if (i !== length) { + if (lastCommonSep === -1) + return toOrig; + } else { + if (toLen > length) { + if (StringPrototypeCharCodeAt(to, toStart + i) === + CHAR_BACKWARD_SLASH) { + // We get here if `from` is the exact base path for `to`. + // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz' + return StringPrototypeSlice(toOrig, toStart + i + 1); + } + if (i === 2) { + // We get here if `from` is the device root. + // For example: from='C:\\'; to='C:\\foo' + return StringPrototypeSlice(toOrig, toStart + i); + } + } + if (fromLen > length) { + if (StringPrototypeCharCodeAt(from, fromStart + i) === + CHAR_BACKWARD_SLASH) { + // We get here if `to` is the exact base path for `from`. + // For example: from='C:\\foo\\bar'; to='C:\\foo' + lastCommonSep = i; + } else if (i === 2) { + // We get here if `to` is the device root. + // For example: from='C:\\foo\\bar'; to='C:\\' + lastCommonSep = 3; + } + } + if (lastCommonSep === -1) + lastCommonSep = 0; + } + + let out = ''; + // Generate the relative path based on the path difference between `to` and + // `from` + for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { + if (i === fromEnd || + StringPrototypeCharCodeAt(from, i) === CHAR_BACKWARD_SLASH) { + out += out.length === 0 ? '..' : '\\..'; + } + } + + toStart += lastCommonSep; + + // Lastly, append the rest of the destination (`to`) path that comes after + // the common path parts + if (out.length > 0) + return `${out}${StringPrototypeSlice(toOrig, toStart, toEnd)}`; + + if (StringPrototypeCharCodeAt(toOrig, toStart) === CHAR_BACKWARD_SLASH) + ++toStart; + return StringPrototypeSlice(toOrig, toStart, toEnd); + }, + + /** + * @param {string} path + * @returns {string} + */ + toNamespacedPath(path) { + // Note: this will *probably* throw somewhere. + if (typeof path !== 'string' || path.length === 0) + return path; + + const resolvedPath = win32.resolve(path); + + if (resolvedPath.length <= 2) + return path; + + if (StringPrototypeCharCodeAt(resolvedPath, 0) === CHAR_BACKWARD_SLASH) { + // Possible UNC root + if (StringPrototypeCharCodeAt(resolvedPath, 1) === CHAR_BACKWARD_SLASH) { + const code = StringPrototypeCharCodeAt(resolvedPath, 2); + if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) { + // Matched non-long UNC root, convert the path to a long UNC path + return `\\\\?\\UNC\\${StringPrototypeSlice(resolvedPath, 2)}`; + } + } + } else if ( + isWindowsDeviceRoot(StringPrototypeCharCodeAt(resolvedPath, 0)) && + StringPrototypeCharCodeAt(resolvedPath, 1) === CHAR_COLON && + StringPrototypeCharCodeAt(resolvedPath, 2) === CHAR_BACKWARD_SLASH + ) { + // Matched device root, convert the path to a long UNC path + return `\\\\?\\${resolvedPath}`; + } + + return resolvedPath; + }, + + /** + * @param {string} path + * @returns {string} + */ + dirname(path) { + validateString(path, 'path'); + const len = path.length; + if (len === 0) + return '.'; + let rootEnd = -1; + let offset = 0; + const code = StringPrototypeCharCodeAt(path, 0); + + if (len === 1) { + // `path` contains just a path separator, exit early to avoid + // unnecessary work or a dot. + return isPathSeparator(code) ? path : '.'; + } + + // Try to match a root + if (isPathSeparator(code)) { + // Possible UNC root + + rootEnd = offset = 1; + + if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + while (j < len && + !isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more path separators + while (j < len && + isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more non-path separators + while (j < len && + !isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j === len) { + // We matched a UNC root only + return path; + } + if (j !== last) { + // We matched a UNC root with leftovers + + // Offset by 1 to include the separator after the UNC root to + // treat it as a "normal root" on top of a (UNC) root + rootEnd = offset = j + 1; + } + } + } + } + // Possible device root + } else if (isWindowsDeviceRoot(code) && + StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) { + rootEnd = + len > 2 && isPathSeparator(StringPrototypeCharCodeAt(path, 2)) ? 3 : 2; + offset = rootEnd; + } + + let end = -1; + let matchedSlash = true; + for (let i = len - 1; i >= offset; --i) { + if (isPathSeparator(StringPrototypeCharCodeAt(path, i))) { + if (!matchedSlash) { + end = i; + break; + } + } else { + // We saw the first non-path separator + matchedSlash = false; + } + } + + if (end === -1) { + if (rootEnd === -1) + return '.'; + + end = rootEnd; + } + return StringPrototypeSlice(path, 0, end); + }, + + /** + * @param {string} path + * @param {string} [suffix] + * @returns {string} + */ + basename(path, suffix) { + if (suffix !== undefined) + validateString(suffix, 'suffix'); + validateString(path, 'path'); + let start = 0; + let end = -1; + let matchedSlash = true; + + // Check for a drive letter prefix so as not to mistake the following + // path separator as an extra separator at the end of the path that can be + // disregarded + if (path.length >= 2 && + isWindowsDeviceRoot(StringPrototypeCharCodeAt(path, 0)) && + StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) { + start = 2; + } + + if (suffix !== undefined && suffix.length > 0 && suffix.length <= path.length) { + if (suffix === path) + return ''; + let extIdx = suffix.length - 1; + let firstNonSlashEnd = -1; + for (let i = path.length - 1; i >= start; --i) { + const code = StringPrototypeCharCodeAt(path, i); + if (isPathSeparator(code)) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else { + if (firstNonSlashEnd === -1) { + // We saw the first non-path separator, remember this index in case + // we need it if the extension ends up not matching + matchedSlash = false; + firstNonSlashEnd = i + 1; + } + if (extIdx >= 0) { + // Try to match the explicit extension + if (code === StringPrototypeCharCodeAt(suffix, extIdx)) { + if (--extIdx === -1) { + // We matched the extension, so mark this as the end of our path + // component + end = i; + } + } else { + // Extension does not match, so our result is the entire path + // component + extIdx = -1; + end = firstNonSlashEnd; + } + } + } + } + + if (start === end) + end = firstNonSlashEnd; + else if (end === -1) + end = path.length; + return StringPrototypeSlice(path, start, end); + } + for (let i = path.length - 1; i >= start; --i) { + if (isPathSeparator(StringPrototypeCharCodeAt(path, i))) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; + } + } + + if (end === -1) + return ''; + return StringPrototypeSlice(path, start, end); + }, + + /** + * @param {string} path + * @returns {string} + */ + extname(path) { + validateString(path, 'path'); + let start = 0; + let startDot = -1; + let startPart = 0; + let end = -1; + let matchedSlash = true; + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + let preDotState = 0; + + // Check for a drive letter prefix so as not to mistake the following + // path separator as an extra separator at the end of the path that can be + // disregarded + + if (path.length >= 2 && + StringPrototypeCharCodeAt(path, 1) === CHAR_COLON && + isWindowsDeviceRoot(StringPrototypeCharCodeAt(path, 0))) { + start = startPart = 2; + } + + for (let i = path.length - 1; i >= start; --i) { + const code = StringPrototypeCharCodeAt(path, i); + if (isPathSeparator(code)) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === CHAR_DOT) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || + end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + return ''; + } + return StringPrototypeSlice(path, startDot, end); + }, + + format: FunctionPrototypeBind(_format, null, '\\'), + + /** + * @param {string} path + * @returns {{ + * dir: string; + * root: string; + * base: string; + * name: string; + * ext: string; + * }} + */ + parse(path) { + validateString(path, 'path'); + + const ret = { root: '', dir: '', base: '', ext: '', name: '' }; + if (path.length === 0) + return ret; + + const len = path.length; + let rootEnd = 0; + let code = StringPrototypeCharCodeAt(path, 0); + + if (len === 1) { + if (isPathSeparator(code)) { + // `path` contains just a path separator, exit early to avoid + // unnecessary work + ret.root = ret.dir = path; + return ret; + } + ret.base = ret.name = path; + return ret; + } + // Try to match a root + if (isPathSeparator(code)) { + // Possible UNC root + + rootEnd = 1; + if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + while (j < len && + !isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more path separators + while (j < len && + isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more non-path separators + while (j < len && + !isPathSeparator(StringPrototypeCharCodeAt(path, j))) { + j++; + } + if (j === len) { + // We matched a UNC root only + rootEnd = j; + } else if (j !== last) { + // We matched a UNC root with leftovers + rootEnd = j + 1; + } + } + } + } + } else if (isWindowsDeviceRoot(code) && + StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) { + // Possible device root + if (len <= 2) { + // `path` contains just a drive root, exit early to avoid + // unnecessary work + ret.root = ret.dir = path; + return ret; + } + rootEnd = 2; + if (isPathSeparator(StringPrototypeCharCodeAt(path, 2))) { + if (len === 3) { + // `path` contains just a drive root, exit early to avoid + // unnecessary work + ret.root = ret.dir = path; + return ret; + } + rootEnd = 3; + } + } + if (rootEnd > 0) + ret.root = StringPrototypeSlice(path, 0, rootEnd); + + let startDot = -1; + let startPart = rootEnd; + let end = -1; + let matchedSlash = true; + let i = path.length - 1; + + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + let preDotState = 0; + + // Get non-dir info + for (; i >= rootEnd; --i) { + code = StringPrototypeCharCodeAt(path, i); + if (isPathSeparator(code)) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === CHAR_DOT) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (end !== -1) { + if (startDot === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + ret.base = ret.name = StringPrototypeSlice(path, startPart, end); + } else { + ret.name = StringPrototypeSlice(path, startPart, startDot); + ret.base = StringPrototypeSlice(path, startPart, end); + ret.ext = StringPrototypeSlice(path, startDot, end); + } + } + + // If the directory is the root, use the entire root as the `dir` including + // the trailing slash if any (`C:\abc` -> `C:\`). Otherwise, strip out the + // trailing slash (`C:\abc\def` -> `C:\abc`). + if (startPart > 0 && startPart !== rootEnd) + ret.dir = StringPrototypeSlice(path, 0, startPart - 1); + else + ret.dir = ret.root; + + return ret; + }, + + matchesGlob(path, pattern) { + return lazyMatchGlobPattern()(path, pattern, true); + }, + + sep: '\\', + delimiter: ';', + win32: null, + posix: null, +}; + +const posixCwd = (() => { + if (isWindows) { + // Converts Windows' backslash path separators to POSIX forward slashes + // and truncates any drive indicator + const regexp = /\\/g; + return () => { + const cwd = StringPrototypeReplace(process.cwd(), regexp, '/'); + return StringPrototypeSlice(cwd, StringPrototypeIndexOf(cwd, '/')); + }; + } + + // We're already on POSIX, no need for any transformations + return () => process.cwd(); +})(); + +const posix = { + /** + * path.resolve([from ...], to) + * @param {...string} args + * @returns {string} + */ + resolve(...args) { + if (args.length === 0 || (args.length === 1 && (args[0] === '' || args[0] === '.'))) { + const cwd = posixCwd(); + if (StringPrototypeCharCodeAt(cwd, 0) === CHAR_FORWARD_SLASH) { + return cwd; + } + } + let resolvedPath = ''; + let resolvedAbsolute = false; + + for (let i = args.length - 1; i >= 0 && !resolvedAbsolute; i--) { + const path = args[i]; + validateString(path, `paths[${i}]`); + + // Skip empty entries + if (path.length === 0) { + continue; + } + + resolvedPath = `${path}/${resolvedPath}`; + resolvedAbsolute = path[0] === '/'; + } + + if (!resolvedAbsolute) { + const cwd = posixCwd(); + resolvedPath = `${cwd}/${resolvedPath}`; + resolvedAbsolute = + StringPrototypeCharCodeAt(cwd, 0) === CHAR_FORWARD_SLASH; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', + isPosixPathSeparator); + + if (resolvedAbsolute) { + return `/${resolvedPath}`; + } + return resolvedPath.length > 0 ? resolvedPath : '.'; + }, + + /** + * @param {string} path + * @returns {string} + */ + normalize(path) { + validateString(path, 'path'); + + if (path.length === 0) + return '.'; + + const isAbsolute = path[0] === '/'; + const trailingSeparator = path[path.length - 1] === '/'; + + // Normalize the path + path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator); + + if (path.length === 0) { + if (isAbsolute) + return '/'; + return trailingSeparator ? './' : '.'; + } + if (trailingSeparator) + path += '/'; + + return isAbsolute ? `/${path}` : path; + }, + + /** + * @param {string} path + * @returns {boolean} + */ + isAbsolute(path) { + validateString(path, 'path'); + return path.length > 0 && + StringPrototypeCharCodeAt(path, 0) === CHAR_FORWARD_SLASH; + }, + + /** + * @param {...string} args + * @returns {string} + */ + join(...args) { + if (args.length === 0) + return '.'; + + const path = []; + for (let i = 0; i < args.length; ++i) { + const arg = args[i]; + validateString(arg, 'path'); + if (arg.length > 0) { + path.push(arg); + } + } + + if (path.length === 0) + return '.'; + + return posix.normalize(ArrayPrototypeJoin(path, '/')); + }, + + /** + * @param {string} from + * @param {string} to + * @returns {string} + */ + relative(from, to) { + validateString(from, 'from'); + validateString(to, 'to'); + + if (from === to) + return ''; + + // Trim leading forward slashes. + from = posix.resolve(from); + to = posix.resolve(to); + + if (from === to) + return ''; + + const fromStart = 1; + const fromEnd = from.length; + const fromLen = fromEnd - fromStart; + const toStart = 1; + const toLen = to.length - toStart; + + // Compare paths to find the longest common path from root + const length = (fromLen < toLen ? fromLen : toLen); + let lastCommonSep = -1; + let i = 0; + for (; i < length; i++) { + const fromCode = StringPrototypeCharCodeAt(from, fromStart + i); + if (fromCode !== StringPrototypeCharCodeAt(to, toStart + i)) + break; + else if (fromCode === CHAR_FORWARD_SLASH) + lastCommonSep = i; + } + if (i === length) { + if (toLen > length) { + if (StringPrototypeCharCodeAt(to, toStart + i) === CHAR_FORWARD_SLASH) { + // We get here if `from` is the exact base path for `to`. + // For example: from='/foo/bar'; to='/foo/bar/baz' + return StringPrototypeSlice(to, toStart + i + 1); + } + if (i === 0) { + // We get here if `from` is the root + // For example: from='/'; to='/foo' + return StringPrototypeSlice(to, toStart + i); + } + } else if (fromLen > length) { + if (StringPrototypeCharCodeAt(from, fromStart + i) === + CHAR_FORWARD_SLASH) { + // We get here if `to` is the exact base path for `from`. + // For example: from='/foo/bar/baz'; to='/foo/bar' + lastCommonSep = i; + } else if (i === 0) { + // We get here if `to` is the root. + // For example: from='/foo/bar'; to='/' + lastCommonSep = 0; + } + } + } + + let out = ''; + // Generate the relative path based on the path difference between `to` + // and `from`. + for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { + if (i === fromEnd || + StringPrototypeCharCodeAt(from, i) === CHAR_FORWARD_SLASH) { + out += out.length === 0 ? '..' : '/..'; + } + } + + // Lastly, append the rest of the destination (`to`) path that comes after + // the common path parts. + return `${out}${StringPrototypeSlice(to, toStart + lastCommonSep)}`; + }, + + /** + * @param {string} path + * @returns {string} + */ + toNamespacedPath(path) { + // Non-op on posix systems + return path; + }, + + /** + * @param {string} path + * @returns {string} + */ + dirname(path) { + validateString(path, 'path'); + if (path.length === 0) + return '.'; + const hasRoot = StringPrototypeCharCodeAt(path, 0) === CHAR_FORWARD_SLASH; + let end = -1; + let matchedSlash = true; + for (let i = path.length - 1; i >= 1; --i) { + if (StringPrototypeCharCodeAt(path, i) === CHAR_FORWARD_SLASH) { + if (!matchedSlash) { + end = i; + break; + } + } else { + // We saw the first non-path separator + matchedSlash = false; + } + } + + if (end === -1) + return hasRoot ? '/' : '.'; + if (hasRoot && end === 1) + return '//'; + return StringPrototypeSlice(path, 0, end); + }, + + /** + * @param {string} path + * @param {string} [suffix] + * @returns {string} + */ + basename(path, suffix) { + if (suffix !== undefined) + validateString(suffix, 'suffix'); + validateString(path, 'path'); + + let start = 0; + let end = -1; + let matchedSlash = true; + + if (suffix !== undefined && suffix.length > 0 && suffix.length <= path.length) { + if (suffix === path) + return ''; + let extIdx = suffix.length - 1; + let firstNonSlashEnd = -1; + for (let i = path.length - 1; i >= 0; --i) { + const code = StringPrototypeCharCodeAt(path, i); + if (code === CHAR_FORWARD_SLASH) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else { + if (firstNonSlashEnd === -1) { + // We saw the first non-path separator, remember this index in case + // we need it if the extension ends up not matching + matchedSlash = false; + firstNonSlashEnd = i + 1; + } + if (extIdx >= 0) { + // Try to match the explicit extension + if (code === StringPrototypeCharCodeAt(suffix, extIdx)) { + if (--extIdx === -1) { + // We matched the extension, so mark this as the end of our path + // component + end = i; + } + } else { + // Extension does not match, so our result is the entire path + // component + extIdx = -1; + end = firstNonSlashEnd; + } + } + } + } + + if (start === end) + end = firstNonSlashEnd; + else if (end === -1) + end = path.length; + return StringPrototypeSlice(path, start, end); + } + for (let i = path.length - 1; i >= 0; --i) { + if (StringPrototypeCharCodeAt(path, i) === CHAR_FORWARD_SLASH) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; + } + } + + if (end === -1) + return ''; + return StringPrototypeSlice(path, start, end); + }, + + /** + * @param {string} path + * @returns {string} + */ + extname(path) { + validateString(path, 'path'); + let startDot = -1; + let startPart = 0; + let end = -1; + let matchedSlash = true; + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + let preDotState = 0; + for (let i = path.length - 1; i >= 0; --i) { + const char = path[i]; + if (char === '/') { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (char === '.') { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || + end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + return ''; + } + return StringPrototypeSlice(path, startDot, end); + }, + + format: FunctionPrototypeBind(_format, null, '/'), + + /** + * @param {string} path + * @returns {{ + * dir: string; + * root: string; + * base: string; + * name: string; + * ext: string; + * }} + */ + parse(path) { + validateString(path, 'path'); + + const ret = { root: '', dir: '', base: '', ext: '', name: '' }; + if (path.length === 0) + return ret; + const isAbsolute = + StringPrototypeCharCodeAt(path, 0) === CHAR_FORWARD_SLASH; + let start; + if (isAbsolute) { + ret.root = '/'; + start = 1; + } else { + start = 0; + } + let startDot = -1; + let startPart = 0; + let end = -1; + let matchedSlash = true; + let i = path.length - 1; + + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + let preDotState = 0; + + // Get non-dir info + for (; i >= start; --i) { + const char = path[i]; + if (char === '/') { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (char === '.') { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (end !== -1) { + const start = startPart === 0 && isAbsolute ? 1 : startPart; + if (startDot === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + ret.base = ret.name = StringPrototypeSlice(path, start, end); + } else { + ret.name = StringPrototypeSlice(path, start, startDot); + ret.base = StringPrototypeSlice(path, start, end); + ret.ext = StringPrototypeSlice(path, startDot, end); + } + } + + if (startPart > 0) + ret.dir = StringPrototypeSlice(path, 0, startPart - 1); + else if (isAbsolute) + ret.dir = '/'; + + return ret; + }, + + matchesGlob(path, pattern) { + return lazyMatchGlobPattern()(path, pattern, false); + }, + + sep: '/', + delimiter: ':', + win32: null, + posix: null, +}; + +posix.win32 = win32.win32 = win32; +posix.posix = win32.posix = posix; + +// Legacy internal API, docs-only deprecated: DEP0080 +win32._makeLong = win32.toNamespacedPath; +posix._makeLong = posix.toNamespacedPath; + +module.exports = isWindows ? win32 : posix; diff --git a/src/Node/Lib/portable/LICENSES.json b/src/Node/Lib/portable/LICENSES.json new file mode 100644 index 00000000..a4fa9748 --- /dev/null +++ b/src/Node/Lib/portable/LICENSES.json @@ -0,0 +1,64 @@ +{ + "assert@2.1.0": "Copyright Joyent, Inc. and other Node contributors. All rights reserved.\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n", + "available-typed-arrays@1.0.7": "MIT License\n\nCopyright (c) 2020 Inspect JS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "balanced-match@4.0.4": "(MIT)\n\nOriginal code Copyright Julian Gruber \n\nPort to TypeScript Copyright Isaac Z. Schlueter \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "brace-expansion@5.0.12": "MIT License\n\nCopyright Julian Gruber \n\nTypeScript port Copyright Isaac Z. Schlueter \n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "call-bind@1.0.9": "MIT License\n\nCopyright (c) 2020 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "call-bind-apply-helpers@1.0.2": "MIT License\n\nCopyright (c) 2024 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "call-bound@1.0.4": "MIT License\n\nCopyright (c) 2024 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "core-util-is@1.0.3": "Copyright Node.js contributors. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n", + "define-data-property@1.1.4": "MIT License\n\nCopyright (c) 2023 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "define-properties@1.2.1": "The MIT License (MIT)\n\nCopyright (C) 2015 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.", + "dunder-proto@1.0.1": "MIT License\n\nCopyright (c) 2024 ECMAScript Shims\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "es-define-property@1.0.1": "MIT License\n\nCopyright (c) 2024 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "es-errors@1.3.0": "MIT License\n\nCopyright (c) 2024 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "es-object-atoms@1.1.2": "MIT License\n\nCopyright (c) 2024 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "esbuild@0.27.0": "MIT License\n\nCopyright (c) 2020 Evan Wallace\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "for-each@0.3.5": "The MIT License (MIT)\n\nCopyright (c) 2012 Raynos.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n", + "function-bind@1.1.2": "Copyright (c) 2013 Raynos.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n", + "generator-function@2.0.1": "Copyright (c) 2015 Tiancheng \u201cTimothy\u201d Gu\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "get-intrinsic@1.3.0": "MIT License\n\nCopyright (c) 2020 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "get-proto@1.0.1": "MIT License\n\nCopyright (c) 2025 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "gopd@1.2.0": "MIT License\n\nCopyright (c) 2022 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "has-property-descriptors@1.0.2": "MIT License\n\nCopyright (c) 2022 Inspect JS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "has-symbols@1.1.0": "MIT License\n\nCopyright (c) 2016 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "has-tostringtag@1.0.2": "MIT License\n\nCopyright (c) 2021 Inspect JS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "hasown@2.0.4": "MIT License\n\nCopyright (c) Jordan Harband and contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "hpack.js@2.1.6": "#### LICENSE\n\nThis software is licensed under the MIT License.\n\nCopyright Fedor Indutny, 2015.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the\nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n\n[0]: https://tools.ietf.org/html/rfc7541\n", + "inherits@2.0.4": "The ISC License\n\nCopyright (c) Isaac Z. Schlueter\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n\n", + "is-arguments@1.2.0": "The MIT License (MIT)\n\nCopyright (c) 2014 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "is-callable@1.2.7": "The MIT License (MIT)\n\nCopyright (c) 2015 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n", + "is-generator-function@1.1.2": "The MIT License (MIT)\n\nCopyright (c) 2014 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "is-nan@1.3.2": "The MIT License (MIT)\n\nCopyright (c) 2014 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "is-regex@1.2.1": "The MIT License (MIT)\n\nCopyright (c) 2014 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "is-typed-array@1.1.15": "The MIT License (MIT)\n\nCopyright (c) 2015 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n", + "isarray@1.0.0": "## License\n\n(MIT)\n\nCopyright (c) 2013 Julian Gruber <julian@juliangruber.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "math-intrinsics@1.1.0": "MIT License\n\nCopyright (c) 2024 ECMAScript Shims\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "minimalistic-assert@1.0.1": "Copyright 2015 Calvin Metcalf\n\nPermission to use, copy, modify, and/or distribute this software for any purpose\nwith or without fee is hereby granted, provided that the above copyright notice\nand this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE\nOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.", + "minimatch@10.2.2": "# Blue Oak Model License\n\nVersion 1.0.0\n\n## Purpose\n\nThis license gives everyone as much permission to work with\nthis software as possible, while protecting contributors\nfrom liability.\n\n## Acceptance\n\nIn order to receive this license, you must agree to its\nrules. The rules of this license are both obligations\nunder that agreement and conditions to your license.\nYou must not do anything with this software that triggers\na rule that you cannot or will not follow.\n\n## Copyright\n\nEach contributor licenses you to do everything with this\nsoftware that would otherwise infringe that contributor's\ncopyright in it.\n\n## Notices\n\nYou must ensure that everyone who gets a copy of\nany part of this software from you, with or without\nchanges, also gets the text of this license or a link to\n.\n\n## Excuse\n\nIf anyone notifies you in writing that you have not\ncomplied with [Notices](#notices), you can keep your\nlicense by taking all practical steps to comply within 30\ndays after the notice. If you do not do so, your license\nends immediately.\n\n## Patent\n\nEach contributor licenses you to do everything with this\nsoftware that would otherwise infringe any patent claims\nthey can license or become able to license.\n\n## Reliability\n\nNo contributor can revoke this license.\n\n## No Liability\n\n**_As far as the law allows, this software comes as is,\nwithout any warranty or condition, and no contributor\nwill be liable to anyone for any damages related to this\nsoftware or this license, under any kind of legal claim._**\n", + "object-inspect@1.13.4": "MIT License\n\nCopyright (c) 2013 James Halliday\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "object-is@1.1.6": "The MIT License (MIT)\n\nCopyright (c) 2014 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "object-keys@1.1.1": "The MIT License (MIT)\n\nCopyright (C) 2013 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.", + "object.assign@4.1.7": "The MIT License (MIT)\n\nCopyright (c) 2014 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.", + "obuf@1.1.2": "Copyright Fedor Indutny, 2015.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the\nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\nUSE OR OTHER DEALINGS IN THE SOFTWARE.", + "possible-typed-array-names@1.1.0": "MIT License\n\nCopyright (c) 2024 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "process-nextick-args@2.0.1": "# Copyright (c) 2015 Calvin Metcalf\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\n**THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.**\n", + "punycode@1.4.1": "## License\n\nPunycode.js is available under the [MIT](https://mths.be/mit) license.\n", + "qs@6.16.1": "BSD 3-Clause License\n\nCopyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/ljharb/qs/graphs/contributors)\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", + "readable-stream@2.3.8": "Node.js is licensed for use as follows:\n\n\"\"\"\nCopyright Node.js contributors. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n\"\"\"\n\nThis license applies to parts of Node.js originating from the\nhttps://github.com/joyent/node repository:\n\n\"\"\"\nCopyright Joyent, Inc. and other Node contributors. All rights reserved.\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n\"\"\"\n", + "safe-buffer@5.1.2": "The MIT License (MIT)\n\nCopyright (c) Feross Aboukhadijeh\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n", + "safe-regex-test@1.1.0": "MIT License\n\nCopyright (c) 2022 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "set-function-length@1.2.2": "MIT License\n\nCopyright (c) Jordan Harband and contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "side-channel@1.1.1": "MIT License\n\nCopyright (c) 2019 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "side-channel-list@1.0.1": "MIT License\n\nCopyright (c) 2024 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "side-channel-map@1.0.1": "MIT License\n\nCopyright (c) 2024 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "side-channel-weakmap@1.0.2": "MIT License\n\nCopyright (c) 2019 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "string_decoder@1.1.1": "Node.js is licensed for use as follows:\n\n\"\"\"\nCopyright Node.js contributors. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n\"\"\"\n\nThis license applies to parts of Node.js originating from the\nhttps://github.com/joyent/node repository:\n\n\"\"\"\nCopyright Joyent, Inc. and other Node contributors. All rights reserved.\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n\"\"\"\n\n", + "tr46@7.0.0": "The MIT License (MIT)\n\nCopyright (c) Sebastian Mayr\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "tr46/node_modules/punycode@2.3.1": "## License\n\nPunycode.js is available under the [MIT](https://mths.be/mit) license.\n", + "url@0.11.4": "The MIT License (MIT)\n\nCopyright 2014 Joyent, Inc. and other Node contributors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "util@0.12.5": "Copyright Joyent, Inc. and other Node contributors. All rights reserved.\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n", + "util-deprecate@1.0.2": "(The MIT License)\n\nCopyright (c) 2014 Nathan Rajlich \n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n", + "wbuf@1.7.3": "#### LICENSE\n\nThis software is licensed under the MIT License.\n\nCopyright Fedor Indutny, 2014.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the\nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "which-typed-array@1.1.24": "The MIT License (MIT)\n\nCopyright (c) 2015 Jordan Harband\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n" +} diff --git a/src/Node/Lib/portable/NODE_LICENSE.txt b/src/Node/Lib/portable/NODE_LICENSE.txt new file mode 100644 index 00000000..fc7b8c7d --- /dev/null +++ b/src/Node/Lib/portable/NODE_LICENSE.txt @@ -0,0 +1,2923 @@ +Node.js is licensed for use as follows: + +""" +Copyright Node.js contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +This license applies to parts of Node.js originating from the +https://github.com/joyent/node repository: + +""" +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +""" + +The Node.js license applies to all parts of Node.js that are not externally +maintained libraries. + +The externally maintained libraries used by Node.js are: + +- Acorn, located at deps/acorn, is licensed as follows: + """ + MIT License + + Copyright (C) 2012-2022 by various contributors (see AUTHORS) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + """ + +- c-ares, located at deps/cares, is licensed as follows: + """ + MIT License + + Copyright (c) 1998 Massachusetts Institute of Technology + Copyright (c) 2007 - 2023 Daniel Stenberg with many contributors, see AUTHORS + file. + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- merve, located at deps/merve, is licensed as follows: + """ + Copyright 2026 Yagiz Nizipli + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- ittapi, located at deps/v8/third_party/ittapi, is licensed as follows: + """ + Copyright (c) 2019 Intel Corporation. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- amaro, located at deps/amaro, is licensed as follows: + """ + MIT License + + Copyright (c) Marco Ippolito and Amaro contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- swc, located at deps/amaro/dist, is licensed as follows: + """ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024 SWC contributors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + """ + +- ICU, located at deps/icu-small, is licensed as follows: + """ + UNICODE LICENSE V3 + + COPYRIGHT AND PERMISSION NOTICE + + Copyright © 2016-2025 Unicode, Inc. + + NOTICE TO USER: Carefully read the following legal agreement. BY + DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR + SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE + TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT + DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of data files and any associated documentation (the "Data Files") or + software and any associated documentation (the "Software") to deal in the + Data Files or Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, and/or sell + copies of the Data Files or Software, and to permit persons to whom the + Data Files or Software are furnished to do so, provided that either (a) + this copyright and permission notice appear with all copies of the Data + Files or Software, or (b) this copyright and permission notice appear in + associated Documentation. + + THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + THIRD PARTY RIGHTS. + + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE + BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA + FILES OR SOFTWARE. + + Except as contained in this notice, the name of a copyright holder shall + not be used in advertising or otherwise to promote the sale, use or other + dealings in these Data Files or Software without prior written + authorization of the copyright holder. + + SPDX-License-Identifier: Unicode-3.0 + + ---------------------------------------------------------------------- + + Third-Party Software Licenses + + This section contains third-party software notices and/or additional + terms for licensed third-party software components included within ICU + libraries. + + ---------------------------------------------------------------------- + + ICU License - ICU 1.8.1 to ICU 57.1 + + COPYRIGHT AND PERMISSION NOTICE + + Copyright (c) 1995-2016 International Business Machines Corporation and others + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, and/or sell copies of the Software, and to permit persons + to whom the Software is furnished to do so, provided that the above + copyright notice(s) and this permission notice appear in all copies of + the Software and that both the above copyright notice(s) and this + permission notice appear in supporting documentation. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY + SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER + RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + Except as contained in this notice, the name of a copyright holder + shall not be used in advertising or otherwise to promote the sale, use + or other dealings in this Software without prior written authorization + of the copyright holder. + + All trademarks and registered trademarks mentioned herein are the + property of their respective owners. + + ---------------------------------------------------------------------- + + Chinese/Japanese Word Break Dictionary Data (cjdict.txt) + + # The Google Chrome software developed by Google is licensed under + # the BSD license. Other software included in this distribution is + # provided under other licenses, as set forth below. + # + # The BSD License + # http://opensource.org/licenses/bsd-license.php + # Copyright (C) 2006-2008, Google Inc. + # + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # Redistributions in binary form must reproduce the above + # copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided with + # the distribution. + # Neither the name of Google Inc. nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # + # + # The word list in cjdict.txt are generated by combining three word lists + # listed below with further processing for compound word breaking. The + # frequency is generated with an iterative training against Google web + # corpora. + # + # * Libtabe (Chinese) + # - https://sourceforge.net/project/?group_id=1519 + # - Its license terms and conditions are shown below. + # + # * IPADIC (Japanese) + # - http://chasen.aist-nara.ac.jp/chasen/distribution.html + # - Its license terms and conditions are shown below. + # + # ---------COPYING.libtabe ---- BEGIN-------------------- + # + # /* + # * Copyright (c) 1999 TaBE Project. + # * Copyright (c) 1999 Pai-Hsiang Hsiao. + # * All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the TaBE Project nor the names of its + # * contributors may be used to endorse or promote products derived + # * from this software without specific prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # /* + # * Copyright (c) 1999 Computer Systems and Communication Lab, + # * Institute of Information Science, Academia + # * Sinica. All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the Computer Systems and Communication Lab + # * nor the names of its contributors may be used to endorse or + # * promote products derived from this software without specific + # * prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, + # University of Illinois + # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 + # + # ---------------COPYING.libtabe-----END-------------------------------- + # + # + # ---------------COPYING.ipadic-----BEGIN------------------------------- + # + # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science + # and Technology. All Rights Reserved. + # + # Use, reproduction, and distribution of this software is permitted. + # Any copy of this software, whether in its original form or modified, + # must include both the above copyright notice and the following + # paragraphs. + # + # Nara Institute of Science and Technology (NAIST), + # the copyright holders, disclaims all warranties with regard to this + # software, including all implied warranties of merchantability and + # fitness, in no event shall NAIST be liable for + # any special, indirect or consequential damages or any damages + # whatsoever resulting from loss of use, data or profits, whether in an + # action of contract, negligence or other tortuous action, arising out + # of or in connection with the use or performance of this software. + # + # A large portion of the dictionary entries + # originate from ICOT Free Software. The following conditions for ICOT + # Free Software applies to the current dictionary as well. + # + # Each User may also freely distribute the Program, whether in its + # original form or modified, to any third party or parties, PROVIDED + # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear + # on, or be attached to, the Program, which is distributed substantially + # in the same form as set out herein and that such intended + # distribution, if actually made, will neither violate or otherwise + # contravene any of the laws and regulations of the countries having + # jurisdiction over the User or the intended distribution itself. + # + # NO WARRANTY + # + # The program was produced on an experimental basis in the course of the + # research and development conducted during the project and is provided + # to users as so produced on an experimental basis. Accordingly, the + # program is provided without any warranty whatsoever, whether express, + # implied, statutory or otherwise. The term "warranty" used herein + # includes, but is not limited to, any warranty of the quality, + # performance, merchantability and fitness for a particular purpose of + # the program and the nonexistence of any infringement or violation of + # any right of any third party. + # + # Each user of the program will agree and understand, and be deemed to + # have agreed and understood, that there is no warranty whatsoever for + # the program and, accordingly, the entire risk arising from or + # otherwise connected with the program is assumed by the user. + # + # Therefore, neither ICOT, the copyright holder, or any other + # organization that participated in or was otherwise related to the + # development of the program and their respective officials, directors, + # officers and other employees shall be held liable for any and all + # damages, including, without limitation, general, special, incidental + # and consequential damages, arising out of or otherwise in connection + # with the use or inability to use the program or any product, material + # or result produced or otherwise obtained by using the program, + # regardless of whether they have been advised of, or otherwise had + # knowledge of, the possibility of such damages at any time during the + # project or thereafter. Each user will be deemed to have agreed to the + # foregoing by his or her commencement of use of the program. The term + # "use" as used herein includes, but is not limited to, the use, + # modification, copying and distribution of the program and the + # production of secondary products from the program. + # + # In the case where the program, whether in its original form or + # modified, was distributed or delivered to or received by a user from + # any person, organization or entity other than ICOT, unless it makes or + # grants independently of ICOT any specific warranty to the user in + # writing, such person, organization or entity, will also be exempted + # from and not be held liable to the user for any such damages as noted + # above as far as the program is concerned. + # + # ---------------COPYING.ipadic-----END---------------------------------- + + ---------------------------------------------------------------------- + + Lao Word Break Dictionary Data (laodict.txt) + + # Copyright (C) 2016 and later: Unicode, Inc. and others. + # License & terms of use: http://www.unicode.org/copyright.html + # Copyright (c) 2015 International Business Machines Corporation + # and others. All Rights Reserved. + # + # Project: https://github.com/rober42539/lao-dictionary + # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt + # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt + # (copied below) + # + # This file is derived from the above dictionary version of Nov 22, 2020 + # ---------------------------------------------------------------------- + # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. Redistributions in binary + # form must reproduce the above copyright notice, this list of conditions and + # the following disclaimer in the documentation and/or other materials + # provided with the distribution. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # OF THE POSSIBILITY OF SUCH DAMAGE. + # -------------------------------------------------------------------------- + + ---------------------------------------------------------------------- + + Burmese Word Break Dictionary Data (burmesedict.txt) + + # Copyright (c) 2014 International Business Machines Corporation + # and others. All Rights Reserved. + # + # This list is part of a project hosted at: + # github.com/kanyawtech/myanmar-karen-word-lists + # + # -------------------------------------------------------------------------- + # Copyright (c) 2013, LeRoy Benjamin Sharon + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: Redistributions of source code must retain the above + # copyright notice, this list of conditions and the following + # disclaimer. Redistributions in binary form must reproduce the + # above copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided + # with the distribution. + # + # Neither the name Myanmar Karen Word Lists, nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + # SUCH DAMAGE. + # -------------------------------------------------------------------------- + + ---------------------------------------------------------------------- + + Time Zone Database + + ICU uses the public domain data and code derived from Time Zone + Database for its time zone support. The ownership of the TZ database + is explained in BCP 175: Procedure for Maintaining the Time Zone + Database section 7. + + # 7. Database Ownership + # + # The TZ database itself is not an IETF Contribution or an IETF + # document. Rather it is a pre-existing and regularly updated work + # that is in the public domain, and is intended to remain in the + # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do + # not apply to the TZ Database or contributions that individuals make + # to it. Should any claims be made and substantiated against the TZ + # Database, the organization that is providing the IANA + # Considerations defined in this RFC, under the memorandum of + # understanding with the IETF, currently ICANN, may act in accordance + # with all competent court orders. No ownership claims will be made + # by ICANN or the IETF Trust on the database or the code. Any person + # making a contribution to the database or code waives all rights to + # future claims in that contribution or in the TZ Database. + + ---------------------------------------------------------------------- + + Google double-conversion + + Copyright 2006-2011, the V8 project authors. All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ---------------------------------------------------------------------- + + JSON parsing library (nlohmann/json) + + File: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C) + + MIT License + + Copyright (c) 2013-2022 Niels Lohmann + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + ---------------------------------------------------------------------- + + File: aclocal.m4 (only for ICU4C) + Section: pkg.m4 - Macros to locate and utilise pkg-config. + + Copyright © 2004 Scott James Remnant . + Copyright © 2012-2015 Dan Nicholson + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + + As a special exception to the GNU General Public License, if you + distribute this file as part of a program that contains a + configuration script generated by Autoconf, you may include it under + the same distribution terms that you use for the rest of that + program. + + (The condition for the exception is fulfilled because + ICU4C includes a configuration script generated by Autoconf, + namely the `configure` script.) + + ---------------------------------------------------------------------- + + File: config.guess (only for ICU4C) + + This file is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + As a special exception to the GNU General Public License, if you + distribute this file as part of a program that contains a + configuration script generated by Autoconf, you may include it under + the same distribution terms that you use for the rest of that + program. This Exception is an additional permission under section 7 + of the GNU General Public License, version 3 ("GPLv3"). + + (The condition for the exception is fulfilled because + ICU4C includes a configuration script generated by Autoconf, + namely the `configure` script.) + + ---------------------------------------------------------------------- + + File: install-sh (only for ICU4C) + + Copyright 1991 by the Massachusetts Institute of Technology + + Permission to use, copy, modify, distribute, and sell this software and its + documentation for any purpose is hereby granted without fee, provided that + the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation, and that the name of M.I.T. not be used in advertising or + publicity pertaining to distribution of the software without specific, + written prior permission. M.I.T. makes no representations about the + suitability of this software for any purpose. It is provided "as is" + without express or implied warranty. + + ---------------------------------------------------------------------- + + File: sorttable.js (only for ICU4J) + + The MIT Licence, for code from kryogenix.org + + Code downloaded from the Browser Experiments section of kryogenix.org is + licenced under the so-called MIT licence. The licence is below. + + Copyright (c) 1997-date Stuart Langridge + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- libuv, located at deps/uv, is licensed as follows: + """ + Copyright (c) 2015-present libuv project contributors. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + This license applies to parts of libuv originating from the + https://github.com/joyent/libuv repository: + + ==== + + Copyright Joyent, Inc. and other Node contributors. All rights reserved. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + + ==== + + This license applies to all parts of libuv that are not externally + maintained libraries. + + The externally maintained libraries used by libuv are: + + - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. + + - inet_pton and inet_ntop implementations, contained in src/inet.c, are + copyright the Internet Systems Consortium, Inc., and licensed under the ISC + license. + """ + +- LIEF, located at deps/LIEF, is licensed as follows: + """ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 - 2026 R. Thomas + Copyright 2017 - 2026 Quarkslab + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + """ + +- llhttp, located at deps/llhttp, is licensed as follows: + """ + This software is licensed under the MIT License. + + Copyright Fedor Indutny, 2018. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- corepack, located at deps/corepack, is licensed as follows: + """ + **Copyright © Corepack contributors** + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- undici, located at deps/undici, is licensed as follows: + """ + MIT License + + Copyright (c) Matteo Collina and Undici contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- postject, located at test/fixtures/postject-copy, is licensed as follows: + """ + Postject is licensed for use as follows: + + """ + MIT License + + Copyright (c) 2022 Postman, Inc + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + + The Postject license applies to all parts of Postject that are not externally + maintained libraries. + + The externally maintained libraries used by Postject are: + + - LIEF, located at vendor/LIEF, is licensed as follows: + """ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 - 2022 R. Thomas + Copyright 2017 - 2022 Quarkslab + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + """ + """ + +- OpenSSL, located at deps/openssl, is licensed as follows: + """ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + """ + +- Punycode.js, located at lib/punycode.js, is licensed as follows: + """ + Copyright Mathias Bynens + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- V8, located at deps/v8, is licensed as follows: + """ + This license applies to all parts of V8 that are not externally + maintained libraries. The externally maintained libraries used by V8 + are: + + - PCRE test suite, located in + test/mjsunit/third_party/regexp-pcre/regexp-pcre.js. This is based on the + test suite from PCRE-7.3, which is copyrighted by the University + of Cambridge and Google, Inc. The copyright notice and license + are embedded in regexp-pcre.js. + + - Layout tests, located in test/mjsunit/third_party/object-keys. These are + based on layout tests from webkit.org which are copyrighted by + Apple Computer, Inc. and released under a 3-clause BSD license. + + - Strongtalk assembler, the basis of the files assembler-arm-inl.h, + assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h, + assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h, + assembler-x64.cc, assembler-x64.h, assembler.cc and assembler.h. + This code is copyrighted by Sun Microsystems Inc. and released + under a 3-clause BSD license. + + - Valgrind client API header, located at third_party/valgrind/valgrind.h + This is released under the BSD license. + + - The Wasm C/C++ API headers, located at third_party/wasm-api/wasm.{h,hh} + This is released under the Apache license. The API's upstream prototype + implementation also formed the basis of V8's implementation in + src/wasm/c-api.cc. + + These libraries have their own licenses; we recommend you read them, + as their terms may differ from the terms below. + + Further license information can be found in LICENSE files located in + sub-directories. + + Copyright 2014, the V8 project authors. All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- SipHash, located at deps/v8/src/third_party/siphash, is licensed as follows: + """ + SipHash reference C implementation + + Copyright (c) 2016 Jean-Philippe Aumasson + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to the public + domain worldwide. This software is distributed without any warranty. + """ + +- zlib, located at deps/zlib, is licensed as follows: + """ + zlib.h -- interface of the 'zlib' general purpose compression library + version 1.3.2.1, February xxth, 2026 + + Copyright (C) 1995-2026 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + """ + +- simdjson, located at deps/simdjson, is licensed as follows: + """ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2025 The simdjson authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + """ + +- simdutf, located at deps/v8/third_party/simdutf, is licensed as follows: + """ + Copyright 2021 The simdutf authors + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- ada, located at deps/ada, is licensed as follows: + """ + Copyright 2023 Yagiz Nizipli and Daniel Lemire + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- minimatch, located at deps/minimatch, is licensed as follows: + """ + # Blue Oak Model License + + Version 1.0.0 + + ## Purpose + + This license gives everyone as much permission to work with + this software as possible, while protecting contributors + from liability. + + ## Acceptance + + In order to receive this license, you must agree to its + rules. The rules of this license are both obligations + under that agreement and conditions to your license. + You must not do anything with this software that triggers + a rule that you cannot or will not follow. + + ## Copyright + + Each contributor licenses you to do everything with this + software that would otherwise infringe that contributor's + copyright in it. + + ## Notices + + You must ensure that everyone who gets a copy of + any part of this software from you, with or without + changes, also gets the text of this license or a link to + . + + ## Excuse + + If anyone notifies you in writing that you have not + complied with [Notices](#notices), you can keep your + license by taking all practical steps to comply within 30 + days after the notice. If you do not do so, your license + ends immediately. + + ## Patent + + Each contributor licenses you to do everything with this + software that would otherwise infringe any patent claims + they can license or become able to license. + + ## Reliability + + No contributor can revoke this license. + + ## No Liability + + **_As far as the law allows, this software comes as is, + without any warranty or condition, and no contributor + will be liable to anyone for any damages related to this + software or this license, under any kind of legal claim._** + """ + +- npm, located at deps/npm, is licensed as follows: + """ + The npm application + Copyright (c) npm, Inc. and Contributors + Licensed on the terms of The Artistic License 2.0 + + Node package dependencies of the npm application + Copyright (c) their respective copyright owners + Licensed on their respective license terms + + The npm public registry at https://registry.npmjs.org + and the npm website at https://www.npmjs.com + Operated by npm, Inc. + Use governed by terms published on https://www.npmjs.com + + "Node.js" + Trademark Joyent, Inc., https://joyent.com + Neither npm nor npm, Inc. are affiliated with Joyent, Inc. + + The Node.js application + Project of Node Foundation, https://nodejs.org + + The npm Logo + Copyright (c) Mathias Pettersson and Brian Hammond + + "Gubblebum Blocky" typeface + Copyright (c) Tjarda Koster, https://jelloween.deviantart.com + Used with permission + + -------- + + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + This license establishes the terms under which a given free software + Package may be copied, modified, distributed, and/or redistributed. + The intent is that the Copyright Holder maintains some artistic + control over the development of that Package while still keeping the + Package available as open source and free software. + + You are always permitted to make arrangements wholly outside of this + license directly with the Copyright Holder of a given Package. If the + terms of this license do not permit the full use that you propose to + make of the Package, you should contact the Copyright Holder and seek + a different licensing arrangement. + + Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + Permission for Use and Modification Without Distribution + + (1) You are permitted to use the Standard Version and create and use + Modified Versions for any purpose without restriction, provided that + you do not Distribute the Modified Version. + + Permissions for Redistribution of the Standard Version + + (2) You may Distribute verbatim copies of the Source form of the + Standard Version of this Package in any medium without restriction, + either gratis or for a Distributor Fee, provided that you duplicate + all of the original copyright notices and associated disclaimers. At + your discretion, such verbatim copies may or may not include a + Compiled form of the Package. + + (3) You may apply any bug fixes, portability changes, and other + modifications made available from the Copyright Holder. The resulting + Package will still be considered the Standard Version, and as such + will be subject to the Original License. + + Distribution of Modified Versions of the Package as Source + + (4) You may Distribute your Modified Version as Source (either gratis + or for a Distributor Fee, and with or without a Compiled form of the + Modified Version) provided that you clearly document how it differs + from the Standard Version, including, but not limited to, documenting + any non-standard features, executables, or modules, and provided that + you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + Distribution of Compiled Forms of the Standard Version + or Modified Versions without the Source + + (5) You may Distribute Compiled forms of the Standard Version without + the Source, provided that you include complete instructions on how to + get the Source of the Standard Version. Such instructions must be + valid at the time of your distribution. If these instructions, at any + time while you are carrying out such distribution, become invalid, you + must provide new instructions on demand or cease further distribution. + If you provide valid instructions or cease distribution within thirty + days after you become aware that the instructions are invalid, then + you do not forfeit any of your rights under this license. + + (6) You may Distribute a Modified Version in Compiled form without + the Source, provided that you comply with Section 4 with respect to + the Source of the Modified Version. + + Aggregating or Linking the Package + + (7) You may aggregate the Package (either the Standard Version or + Modified Version) with other packages and Distribute the resulting + aggregation provided that you do not charge a licensing fee for the + Package. Distributor Fees are permitted, and licensing fees for other + components in the aggregation are permitted. The terms of this license + apply to the use and Distribution of the Standard or Modified Versions + as included in the aggregation. + + (8) You are permitted to link Modified and Standard Versions with + other works, to embed the Package in a larger work of your own, or to + build stand-alone binary or bytecode versions of applications that + include the Package, and Distribute the result without restriction, + provided the result does not expose a direct interface to the Package. + + Items That are Not Considered Part of a Modified Version + + (9) Works (including, but not limited to, modules and scripts) that + merely extend or make use of the Package, do not, by themselves, cause + the Package to be a Modified Version. In addition, such works are not + considered parts of the Package itself, and are not subject to the + terms of this license. + + General Provisions + + (10) Any use, modification, and distribution of the Standard or + Modified Versions is governed by this Artistic License. By using, + modifying or distributing the Package, you accept this license. Do not + use, modify, or distribute the Package, if you do not accept this + license. + + (11) If your Modified Version has been derived from a Modified + Version made by someone other than you, you are nevertheless required + to ensure that your Modified Version complies with the requirements of + this license. + + (12) This license does not grant you the right to use any trademark, + service mark, tradename, or logo of the Copyright Holder. + + (13) This license includes the non-exclusive, worldwide, + free-of-charge patent license to make, have made, use, offer to sell, + sell, import and otherwise transfer the Package with respect to any + patent claims licensable by the Copyright Holder that are necessarily + infringed by the Package. If you institute patent litigation + (including a cross-claim or counterclaim) against any party alleging + that the Package constitutes direct or contributory patent + infringement, then this Artistic License to you shall terminate on the + date that such litigation is filed. + + (14) Disclaimer of Warranty: + THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS + IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL + LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL + DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + -------- + """ + +- GYP, located at tools/gyp, is licensed as follows: + """ + Copyright (c) 2020 Node.js contributors. All rights reserved. + Copyright (c) 2009 Google Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- inspector_protocol, located at deps/inspector_protocol, is licensed as follows: + """ + // Copyright 2016 The Chromium Authors. + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions are + // met: + // + // * Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // * Redistributions in binary form must reproduce the above + // copyright notice, this list of conditions and the following disclaimer + // in the documentation and/or other materials provided with the + // distribution. + // * Neither the name of Google Inc. nor the names of its + // contributors may be used to endorse or promote products derived from + // this software without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- jinja2, located at tools/inspector_protocol/jinja2, is licensed as follows: + """ + Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details. + + Some rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- markupsafe, located at tools/inspector_protocol/markupsafe, is licensed as follows: + """ + Copyright (c) 2010 by Armin Ronacher and contributors. See AUTHORS + for more details. + + Some rights reserved. + + Redistribution and use in source and binary forms of the software as well + as documentation, with or without modification, are permitted provided + that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + """ + +- cpplint.py, located at tools/cpplint.py, is licensed as follows: + """ + Copyright (c) 2009 Google Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- gypi_to_gn.py, located at tools/gypi_to_gn.py, is licensed as follows: + """ + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- gtest, located at deps/googletest, is licensed as follows: + """ + Copyright 2008, Google Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- nghttp2, located at deps/nghttp2, is licensed as follows: + """ + The MIT License + + Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa + Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- caja, located at lib/internal/freeze_intrinsics.js, is licensed as follows: + """ + Adapted from SES/Caja - Copyright (C) 2011 Google Inc. + Copyright (C) 2018 Agoric + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + """ + +- brotli, located at deps/brotli, is licensed as follows: + """ + Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + """ + +- zstd, located at deps/zstd, is licensed as follows: + """ + BSD License + + For Zstandard software + + Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook, nor Meta, nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + """ + +- HdrHistogram, located at deps/histogram, is licensed as follows: + """ + The code in this repository code was Written by Gil Tene, Michael Barker, + and Matt Warren, and released to the public domain, as explained at + http://creativecommons.org/publicdomain/zero/1.0/ + + For users of this code who wish to consume it under the "BSD" license + rather than under the public domain or CC0 contribution text mentioned + above, the code found under this directory is *also* provided under the + following license (commonly referred to as the BSD 2-Clause License). This + license does not detract from the above stated release of the code into + the public domain, and simply represents an additional license granted by + the Author. + + ----------------------------------------------------------------------------- + ** Beginning of "BSD 2-Clause License" text. ** + + Copyright (c) 2012, 2013, 2014 Gil Tene + Copyright (c) 2014 Michael Barker + Copyright (c) 2014 Matt Warren + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. + """ + +- node-heapdump, located at src/heap_utils.cc, is licensed as follows: + """ + ISC License + + Copyright (c) 2012, Ben Noordhuis + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + === src/compat.h src/compat-inl.h === + + ISC License + + Copyright (c) 2014, StrongLoop Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + """ + +- rimraf, located at lib/internal/fs/rimraf.js, is licensed as follows: + """ + The ISC License + + Copyright (c) Isaac Z. Schlueter and Contributors + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + """ + +- uvwasi, located at deps/uvwasi, is licensed as follows: + """ + MIT License + + Copyright (c) 2019 Colin Ihrig and Contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- ngtcp2, located at deps/ngtcp2/ngtcp2/, is licensed as follows: + """ + The MIT License + + Copyright (c) 2016 ngtcp2 contributors + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- nghttp3, located at deps/ngtcp2/nghttp3/, is licensed as follows: + """ + The MIT License + + Copyright (c) 2019 nghttp3 contributors + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- node-fs-extra, located at lib/internal/fs/cp, is licensed as follows: + """ + (The MIT License) + + Copyright (c) 2011-2017 JP Richardson + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files + (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + +- on-exit-leak-free, located at lib/internal/process/finalization, is licensed as follows: + """ + MIT License + + Copyright (c) 2021 Matteo Collina + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ + +- sonic-boom, located at lib/internal/streams/fast-utf8-stream.js, is licensed as follows: + """ + MIT License + + Copyright (c) 2017 Matteo Collina + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + """ diff --git a/src/Node/Lib/portable/constants.cjs b/src/Node/Lib/portable/constants.cjs new file mode 100644 index 00000000..c635272d --- /dev/null +++ b/src/Node/Lib/portable/constants.cjs @@ -0,0 +1,58 @@ +'use strict'; + +const isWindows = process.platform === 'win32'; + +module.exports = { + // Alphabet chars. + CHAR_UPPERCASE_A: 65, /* A */ + CHAR_LOWERCASE_A: 97, /* a */ + CHAR_UPPERCASE_Z: 90, /* Z */ + CHAR_LOWERCASE_Z: 122, /* z */ + CHAR_UPPERCASE_C: 67, /* C */ + CHAR_UPPERCASE_B: 66, /* B */ + CHAR_LOWERCASE_B: 98, /* b */ + CHAR_UPPERCASE_E: 69, /* E */ + CHAR_LOWERCASE_E: 101, /* e */ + CHAR_LOWERCASE_N: 110, /* n */ + + // Non-alphabetic chars. + CHAR_DOT: 46, /* . */ + CHAR_FORWARD_SLASH: 47, /* / */ + CHAR_BACKWARD_SLASH: 92, /* \ */ + CHAR_VERTICAL_LINE: 124, /* | */ + CHAR_COLON: 58, /* : */ + CHAR_QUESTION_MARK: 63, /* ? */ + CHAR_UNDERSCORE: 95, /* _ */ + CHAR_LINE_FEED: 10, /* \n */ + CHAR_CARRIAGE_RETURN: 13, /* \r */ + CHAR_TAB: 9, /* \t */ + CHAR_FORM_FEED: 12, /* \f */ + CHAR_EXCLAMATION_MARK: 33, /* ! */ + CHAR_HASH: 35, /* # */ + CHAR_SPACE: 32, /* */ + CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */ + CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */ + CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */ + CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */ + CHAR_LEFT_ANGLE_BRACKET: 60, /* < */ + CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */ + CHAR_LEFT_CURLY_BRACKET: 123, /* { */ + CHAR_RIGHT_CURLY_BRACKET: 125, /* } */ + CHAR_HYPHEN_MINUS: 45, /* - */ + CHAR_PLUS: 43, /* + */ + CHAR_DOUBLE_QUOTE: 34, /* " */ + CHAR_SINGLE_QUOTE: 39, /* ' */ + CHAR_PERCENT: 37, /* % */ + CHAR_SEMICOLON: 59, /* ; */ + CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */ + CHAR_GRAVE_ACCENT: 96, /* ` */ + CHAR_AT: 64, /* @ */ + CHAR_AMPERSAND: 38, /* & */ + CHAR_EQUAL: 61, /* = */ + + // Digits + CHAR_0: 48, /* 0 */ + CHAR_9: 57, /* 9 */ + + EOL: isWindows ? '\r\n' : '\n', +}; diff --git a/src/Node/Lib/portable/errors.cjs b/src/Node/Lib/portable/errors.cjs new file mode 100644 index 00000000..c049bad1 --- /dev/null +++ b/src/Node/Lib/portable/errors.cjs @@ -0,0 +1,28 @@ +'use strict'; + +function describe(value) { + if (value === null) return 'null'; + if (value === undefined) return 'undefined'; + if (typeof value === 'string') return "type string ('" + value + "')"; + if (typeof value === 'object') return 'an instance of ' + (value.constructor && value.constructor.name || 'Object'); + return 'type ' + typeof value + ' (' + String(value) + ')'; +} + +function coded(Base, code, message) { + return class extends Base { + constructor(...args) { + super(message(...args)); + this.code = code; + Object.defineProperty(this, 'name', { value: Base.name, configurable: true, writable: true }); + } + }; +} + +exports.codes = { + ERR_INVALID_ARG_TYPE: coded(TypeError, 'ERR_INVALID_ARG_TYPE', (name, expected, actual) => + 'The "' + name + '" argument must be of type ' + expected + '. Received ' + describe(actual)), + ERR_INVALID_ARG_VALUE: coded(TypeError, 'ERR_INVALID_ARG_VALUE', (name, value, reason = 'is invalid') => + 'The argument \'' + name + '\' ' + reason + '. Received ' + String(value)), + ERR_INVALID_URL: coded(TypeError, 'ERR_INVALID_URL', () => 'Invalid URL'), + ERR_INVALID_URI: coded(URIError, 'ERR_INVALID_URI', () => 'URI malformed'), +}; diff --git a/src/Node/Lib/portable/format.cjs b/src/Node/Lib/portable/format.cjs new file mode 100644 index 00000000..16f9a814 --- /dev/null +++ b/src/Node/Lib/portable/format.cjs @@ -0,0 +1,67 @@ +'use strict'; + +function number(value, options) { + if (Object.is(value, -0)) return '-0'; + let text = String(value); + if (options && options.numericSeparator && !/[eE]/.test(text)) { + const pieces = text.split('.'); + pieces[0] = pieces[0].replace(/\B(?=(\d{3})+(?!\d))/g, '_'); + if (pieces[1]) pieces[1] = pieces[1].replace(/(\d{3})(?=\d)/g, '$1_'); + text = pieces.join('.'); + } + return text + (typeof value === 'bigint' ? 'n' : ''); +} + +function json(value) { + try { return JSON.stringify(value); } catch (error) { + let circular; + try { const object = {}; object.object = object; JSON.stringify(object); } catch (failure) { circular = failure.message.split('\n')[0]; } + if (error.name === 'TypeError' && error.message.split('\n')[0] === circular) return '[Circular]'; + throw error; + } +} + +function builtInToString(value) { + const toString = value.toString; + const toPrimitive = value[Symbol.toPrimitive]; + if (typeof toString !== 'function' && typeof toPrimitive !== 'function') return true; + let owner = value; + while (owner !== null) { + if (typeof toString === 'function' && Object.hasOwn(owner, 'toString') || + typeof toPrimitive === 'function' && Object.hasOwn(owner, Symbol.toPrimitive)) { + const descriptor = Object.getOwnPropertyDescriptor(owner, 'constructor'); + return !!descriptor && typeof descriptor.value === 'function' && /\[native code\]/.test(Function.prototype.toString.call(descriptor.value)); + } + owner = Object.getPrototypeOf(owner); + } + return true; +} + +exports.format = function format(inspect, options, args) { + if (args.length === 0) return ''; + if (typeof args[0] !== 'string') return args.map(value => typeof value === 'string' ? value : inspect(value, options)).join(' '); + if (args.length === 1) return args[0]; + let index = 1; + let result = args[0].replace(/%[sdifoOjc%]/g, token => { + if (token === '%%') return '%'; + if (index === args.length) return token; + const value = args[index++]; + switch (token) { + case '%s': + if (typeof value === 'number' || typeof value === 'bigint') return number(value, options); + return value !== null && typeof value === 'object' && builtInToString(value) + ? inspect(value, { ...options, compact: 3, colors: false, depth: 0 }) : String(value); + case '%d': return typeof value === 'symbol' ? 'NaN' : number(typeof value === 'bigint' ? value : Number(value), options); + case '%i': return typeof value === 'symbol' ? 'NaN' : number(typeof value === 'bigint' ? value : parseInt(value), options); + case '%f': return typeof value === 'symbol' ? 'NaN' : number(parseFloat(value), options); + case '%j': return json(value); + case '%o': return inspect(value, { ...options, showHidden: true, showProxy: true, depth: 4 }); + case '%O': return inspect(value, options); + case '%c': return ''; + } + }); + for (; index < args.length; index++) { + result += ' ' + (typeof args[index] === 'string' ? args[index] : inspect(args[index], options)); + } + return result; +}; diff --git a/src/Node/Lib/portable/glob.cjs b/src/Node/Lib/portable/glob.cjs new file mode 100644 index 00000000..186ba1fb --- /dev/null +++ b/src/Node/Lib/portable/glob.cjs @@ -0,0 +1,26 @@ +'use strict'; + +const { Minimatch } = require('./minimatch.cjs'); +const { validateString } = require('./validators.cjs'); +const cache = new Map(); + +exports.matchGlobPattern = function matchGlobPattern(path, pattern, windows = process.platform === 'win32') { + validateString(path, 'path'); + validateString(pattern, 'pattern'); + const key = (windows ? 'win32:' : 'posix:') + pattern; + let matcher = cache.get(key); + if (!matcher) { + matcher = new Minimatch(pattern, { + nocase: process.platform === 'win32' || process.platform === 'darwin', + windowsPathsNoEscape: true, + nonegate: true, + nocomment: true, + optimizationLevel: 2, + platform: windows ? 'win32' : 'posix', + nocaseMagicOnly: true, + }); + cache.set(key, matcher); + if (cache.size >= 250) cache.delete(cache.keys().next().value); + } + return matcher.match(path); +}; diff --git a/src/Node/Lib/portable/helpers.cjs b/src/Node/Lib/portable/helpers.cjs new file mode 100644 index 00000000..a464442e --- /dev/null +++ b/src/Node/Lib/portable/helpers.cjs @@ -0,0 +1,15 @@ +'use strict'; + +exports.isWindows = process.platform === 'win32'; +exports.getLazy = function getLazy(factory) { + let value; + let loaded = false; + return function () { + if (!loaded) { value = factory(); loaded = true; } + return value; + }; +}; +exports.spliceOne = function spliceOne(list, index) { list.splice(index, 1); }; +exports.isInsideNodeModules = function isInsideNodeModules() { + return /[\\/]node_modules[\\/]/.test(new Error().stack || ''); +}; diff --git a/src/Node/Lib/portable/hpack.cjs b/src/Node/Lib/portable/hpack.cjs new file mode 100644 index 00000000..24e92b81 --- /dev/null +++ b/src/Node/Lib/portable/hpack.cjs @@ -0,0 +1,6152 @@ +var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; + +// scripts/node-portable/node_modules/hpack.js/lib/hpack/utils.js +var require_utils = __commonJS({ + "scripts/node-portable/node_modules/hpack.js/lib/hpack/utils.js"(exports2) { + exports2.assert = function assert(cond, text) { + if (!cond) + throw new Error(text); + }; + exports2.stringify = function stringify(arr) { + var res = ""; + for (var i = 0; i < arr.length; i++) + res += String.fromCharCode(arr[i]); + return res; + }; + exports2.toArray = function toArray(str) { + var res = []; + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + var hi = c >>> 8; + var lo = c & 255; + if (hi) + res.push(hi, lo); + else + res.push(lo); + } + return res; + }; + } +}); + +// scripts/node-portable/node_modules/hpack.js/lib/hpack/huffman.js +var require_huffman = __commonJS({ + "scripts/node-portable/node_modules/hpack.js/lib/hpack/huffman.js"(exports2) { + exports2.decode = [ + 2608, + 2609, + 2610, + 2657, + 2659, + 2661, + 2665, + 2671, + 2675, + 2676, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3104, + 3109, + 3117, + 3118, + 3119, + 3123, + 3124, + 3125, + 3126, + 3127, + 3128, + 3129, + 3133, + 3137, + 3167, + 3170, + 3172, + 3174, + 3175, + 3176, + 3180, + 3181, + 3182, + 3184, + 3186, + 3189, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3642, + 3650, + 3651, + 3652, + 3653, + 3654, + 3655, + 3656, + 3657, + 3658, + 3659, + 3660, + 3661, + 3662, + 3663, + 3664, + 3665, + 3666, + 3667, + 3668, + 3669, + 3670, + 3671, + 3673, + 3690, + 3691, + 3697, + 3702, + 3703, + 3704, + 3705, + 3706, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4134, + 4138, + 4140, + 4155, + 4184, + 4186, + [ + 1057, + 1058, + 1064, + 1065, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1087, + 0, + 1575, + 1579, + 1660, + 0, + 0, + 0, + 0, + 0, + 2083, + 2110, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2560, + 2596, + 2624, + 2651, + 2653, + 2686, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3166, + 3197, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3644, + 3680, + 3707, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + [ + 1628, + 1731, + 1744, + 0, + 0, + 0, + 2176, + 2178, + 2179, + 2210, + 2232, + 2242, + 2272, + 2274, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2713, + 2721, + 2727, + 2732, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 2736, + 2737, + 2739, + 2769, + 2776, + 2777, + 2787, + 2789, + 2790, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3201, + 3204, + 3205, + 3206, + 3208, + 3218, + 3226, + 3228, + 3232, + 3235, + 3236, + 3241, + 3242, + 3245, + 3250, + 3253, + 3257, + 3258, + 3259, + 3261, + 3262, + 3268, + 3270, + 3300, + 3304, + 3305, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3585, + 3719, + 3721, + 3722, + 3723, + 3724, + 3725, + 3727, + 3731, + 3733, + 3734, + 3735, + 3736, + 3739, + 3741, + 3742, + 3749, + 3750, + 3752, + 3758, + 3759, + 3764, + 3766, + 3767, + 3772, + 3775, + 3781, + 3815, + 3823, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4105, + 4238, + 4240, + 4241, + 4244, + 4255, + 4267, + 4302, + 4311, + 4321, + 4332, + 4333, + [ + 711, + 719, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 746, + 747, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1216, + 1217, + 1224, + 1225, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1226, + 1229, + 1234, + 1237, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1242, + 1243, + 1262, + 1264, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1266, + 1267, + 1279, + 0, + 0, + 0, + 1739, + 1740, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1747, + 1748, + 1750, + 1757, + 1758, + 1759, + 1777, + 1780, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1781, + 1782, + 1783, + 1784, + 1786, + 1787, + 1788, + 1789, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 1790, + 0, + 2050, + 2051, + 2052, + 2053, + 2054, + 2055, + 2056, + 2059, + 2060, + 2062, + 2063, + 2064, + 2065, + 2066, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + [ + 2067, + 2068, + 2069, + 2071, + 2072, + 2073, + 2074, + 2075, + 2076, + 2077, + 2078, + 2079, + 2175, + 2268, + 2297, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 3082, + 3085, + 3094, + 3328, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ] + ] + ]; + exports2.encode = [ + [13, 8184], + [23, 8388568], + [28, 268435426], + [28, 268435427], + [28, 268435428], + [ + 28, + 268435429 + ], + [28, 268435430], + [28, 268435431], + [28, 268435432], + [24, 16777194], + [ + 30, + 1073741820 + ], + [28, 268435433], + [28, 268435434], + [30, 1073741821], + [28, 268435435], + [28, 268435436], + [28, 268435437], + [28, 268435438], + [28, 268435439], + [28, 268435440], + [28, 268435441], + [28, 268435442], + [30, 1073741822], + [28, 268435443], + [ + 28, + 268435444 + ], + [28, 268435445], + [28, 268435446], + [28, 268435447], + [28, 268435448], + [ + 28, + 268435449 + ], + [28, 268435450], + [28, 268435451], + [6, 20], + [10, 1016], + [10, 1017], + [ + 12, + 4090 + ], + [13, 8185], + [6, 21], + [8, 248], + [11, 2042], + [10, 1018], + [10, 1019], + [8, 249], + [ + 11, + 2043 + ], + [8, 250], + [6, 22], + [6, 23], + [6, 24], + [5, 0], + [5, 1], + [5, 2], + [6, 25], + [6, 26], + [6, 27], + [6, 28], + [6, 29], + [6, 30], + [6, 31], + [7, 92], + [8, 251], + [15, 32764], + [6, 32], + [12, 4091], + [ + 10, + 1020 + ], + [13, 8186], + [6, 33], + [7, 93], + [7, 94], + [7, 95], + [7, 96], + [7, 97], + [7, 98], + [7, 99], + [ + 7, + 100 + ], + [7, 101], + [7, 102], + [7, 103], + [7, 104], + [7, 105], + [7, 106], + [7, 107], + [7, 108], + [ + 7, + 109 + ], + [7, 110], + [7, 111], + [7, 112], + [7, 113], + [7, 114], + [8, 252], + [7, 115], + [8, 253], + [ + 13, + 8187 + ], + [19, 524272], + [13, 8188], + [14, 16380], + [6, 34], + [15, 32765], + [5, 3], + [6, 35], + [ + 5, + 4 + ], + [6, 36], + [5, 5], + [6, 37], + [6, 38], + [6, 39], + [5, 6], + [7, 116], + [7, 117], + [6, 40], + [6, 41], + [6, 42], + [5, 7], + [6, 43], + [7, 118], + [6, 44], + [5, 8], + [5, 9], + [6, 45], + [7, 119], + [7, 120], + [ + 7, + 121 + ], + [7, 122], + [7, 123], + [15, 32766], + [11, 2044], + [14, 16381], + [13, 8189], + [ + 28, + 268435452 + ], + [20, 1048550], + [22, 4194258], + [20, 1048551], + [20, 1048552], + [ + 22, + 4194259 + ], + [22, 4194260], + [22, 4194261], + [23, 8388569], + [22, 4194262], + [23, 8388570], + [23, 8388571], + [23, 8388572], + [23, 8388573], + [23, 8388574], + [24, 16777195], + [ + 23, + 8388575 + ], + [24, 16777196], + [24, 16777197], + [22, 4194263], + [23, 8388576], + [ + 24, + 16777198 + ], + [23, 8388577], + [23, 8388578], + [23, 8388579], + [23, 8388580], + [21, 2097116], + [22, 4194264], + [23, 8388581], + [22, 4194265], + [23, 8388582], + [23, 8388583], + [ + 24, + 16777199 + ], + [22, 4194266], + [21, 2097117], + [20, 1048553], + [22, 4194267], + [22, 4194268], + [23, 8388584], + [23, 8388585], + [21, 2097118], + [23, 8388586], + [22, 4194269], + [ + 22, + 4194270 + ], + [24, 16777200], + [21, 2097119], + [22, 4194271], + [23, 8388587], + [23, 8388588], + [21, 2097120], + [21, 2097121], + [22, 4194272], + [21, 2097122], + [23, 8388589], + [ + 22, + 4194273 + ], + [23, 8388590], + [23, 8388591], + [20, 1048554], + [22, 4194274], + [22, 4194275], + [22, 4194276], + [23, 8388592], + [22, 4194277], + [22, 4194278], + [23, 8388593], + [ + 26, + 67108832 + ], + [26, 67108833], + [20, 1048555], + [19, 524273], + [22, 4194279], + [23, 8388594], + [22, 4194280], + [25, 33554412], + [26, 67108834], + [26, 67108835], + [26, 67108836], + [ + 27, + 134217694 + ], + [27, 134217695], + [26, 67108837], + [24, 16777201], + [25, 33554413], + [ + 19, + 524274 + ], + [21, 2097123], + [26, 67108838], + [27, 134217696], + [27, 134217697], + [ + 26, + 67108839 + ], + [27, 134217698], + [24, 16777202], + [21, 2097124], + [21, 2097125], + [ + 26, + 67108840 + ], + [26, 67108841], + [28, 268435453], + [27, 134217699], + [27, 134217700], + [ + 27, + 134217701 + ], + [20, 1048556], + [24, 16777203], + [20, 1048557], + [21, 2097126], + [ + 22, + 4194281 + ], + [21, 2097127], + [21, 2097128], + [23, 8388595], + [22, 4194282], + [22, 4194283], + [25, 33554414], + [25, 33554415], + [24, 16777204], + [24, 16777205], + [26, 67108842], + [ + 23, + 8388596 + ], + [26, 67108843], + [27, 134217702], + [26, 67108844], + [26, 67108845], + [ + 27, + 134217703 + ], + [27, 134217704], + [27, 134217705], + [27, 134217706], + [27, 134217707], + [ + 28, + 268435454 + ], + [27, 134217708], + [27, 134217709], + [27, 134217710], + [27, 134217711], + [ + 27, + 134217712 + ], + [26, 67108846], + [30, 1073741823] + ]; + } +}); + +// scripts/node-portable/node_modules/hpack.js/lib/hpack/static-table.js +var require_static_table = __commonJS({ + "scripts/node-portable/node_modules/hpack.js/lib/hpack/static-table.js"(exports2) { + exports2.table = [ + { + "name": ":authority", + "value": "", + "nameSize": 10, + "totalSize": 42 + }, + { + "name": ":method", + "value": "GET", + "nameSize": 7, + "totalSize": 42 + }, + { + "name": ":method", + "value": "POST", + "nameSize": 7, + "totalSize": 43 + }, + { + "name": ":path", + "value": "/", + "nameSize": 5, + "totalSize": 38 + }, + { + "name": ":path", + "value": "/index.html", + "nameSize": 5, + "totalSize": 48 + }, + { + "name": ":scheme", + "value": "http", + "nameSize": 7, + "totalSize": 43 + }, + { + "name": ":scheme", + "value": "https", + "nameSize": 7, + "totalSize": 44 + }, + { + "name": ":status", + "value": "200", + "nameSize": 7, + "totalSize": 42 + }, + { + "name": ":status", + "value": "204", + "nameSize": 7, + "totalSize": 42 + }, + { + "name": ":status", + "value": "206", + "nameSize": 7, + "totalSize": 42 + }, + { + "name": ":status", + "value": "304", + "nameSize": 7, + "totalSize": 42 + }, + { + "name": ":status", + "value": "400", + "nameSize": 7, + "totalSize": 42 + }, + { + "name": ":status", + "value": "404", + "nameSize": 7, + "totalSize": 42 + }, + { + "name": ":status", + "value": "500", + "nameSize": 7, + "totalSize": 42 + }, + { + "name": "accept-charset", + "value": "", + "nameSize": 14, + "totalSize": 46 + }, + { + "name": "accept-encoding", + "value": "gzip, deflate", + "nameSize": 15, + "totalSize": 60 + }, + { + "name": "accept-language", + "value": "", + "nameSize": 15, + "totalSize": 47 + }, + { + "name": "accept-ranges", + "value": "", + "nameSize": 13, + "totalSize": 45 + }, + { + "name": "accept", + "value": "", + "nameSize": 6, + "totalSize": 38 + }, + { + "name": "access-control-allow-origin", + "value": "", + "nameSize": 27, + "totalSize": 59 + }, + { + "name": "age", + "value": "", + "nameSize": 3, + "totalSize": 35 + }, + { + "name": "allow", + "value": "", + "nameSize": 5, + "totalSize": 37 + }, + { + "name": "authorization", + "value": "", + "nameSize": 13, + "totalSize": 45 + }, + { + "name": "cache-control", + "value": "", + "nameSize": 13, + "totalSize": 45 + }, + { + "name": "content-disposition", + "value": "", + "nameSize": 19, + "totalSize": 51 + }, + { + "name": "content-encoding", + "value": "", + "nameSize": 16, + "totalSize": 48 + }, + { + "name": "content-language", + "value": "", + "nameSize": 16, + "totalSize": 48 + }, + { + "name": "content-length", + "value": "", + "nameSize": 14, + "totalSize": 46 + }, + { + "name": "content-location", + "value": "", + "nameSize": 16, + "totalSize": 48 + }, + { + "name": "content-range", + "value": "", + "nameSize": 13, + "totalSize": 45 + }, + { + "name": "content-type", + "value": "", + "nameSize": 12, + "totalSize": 44 + }, + { + "name": "cookie", + "value": "", + "nameSize": 6, + "totalSize": 38 + }, + { + "name": "date", + "value": "", + "nameSize": 4, + "totalSize": 36 + }, + { + "name": "etag", + "value": "", + "nameSize": 4, + "totalSize": 36 + }, + { + "name": "expect", + "value": "", + "nameSize": 6, + "totalSize": 38 + }, + { + "name": "expires", + "value": "", + "nameSize": 7, + "totalSize": 39 + }, + { + "name": "from", + "value": "", + "nameSize": 4, + "totalSize": 36 + }, + { + "name": "host", + "value": "", + "nameSize": 4, + "totalSize": 36 + }, + { + "name": "if-match", + "value": "", + "nameSize": 8, + "totalSize": 40 + }, + { + "name": "if-modified-since", + "value": "", + "nameSize": 17, + "totalSize": 49 + }, + { + "name": "if-none-match", + "value": "", + "nameSize": 13, + "totalSize": 45 + }, + { + "name": "if-range", + "value": "", + "nameSize": 8, + "totalSize": 40 + }, + { + "name": "if-unmodified-since", + "value": "", + "nameSize": 19, + "totalSize": 51 + }, + { + "name": "last-modified", + "value": "", + "nameSize": 13, + "totalSize": 45 + }, + { + "name": "link", + "value": "", + "nameSize": 4, + "totalSize": 36 + }, + { + "name": "location", + "value": "", + "nameSize": 8, + "totalSize": 40 + }, + { + "name": "max-forwards", + "value": "", + "nameSize": 12, + "totalSize": 44 + }, + { + "name": "proxy-authenticate", + "value": "", + "nameSize": 18, + "totalSize": 50 + }, + { + "name": "proxy-authorization", + "value": "", + "nameSize": 19, + "totalSize": 51 + }, + { + "name": "range", + "value": "", + "nameSize": 5, + "totalSize": 37 + }, + { + "name": "referer", + "value": "", + "nameSize": 7, + "totalSize": 39 + }, + { + "name": "refresh", + "value": "", + "nameSize": 7, + "totalSize": 39 + }, + { + "name": "retry-after", + "value": "", + "nameSize": 11, + "totalSize": 43 + }, + { + "name": "server", + "value": "", + "nameSize": 6, + "totalSize": 38 + }, + { + "name": "set-cookie", + "value": "", + "nameSize": 10, + "totalSize": 42 + }, + { + "name": "strict-transport-security", + "value": "", + "nameSize": 25, + "totalSize": 57 + }, + { + "name": "transfer-encoding", + "value": "", + "nameSize": 17, + "totalSize": 49 + }, + { + "name": "user-agent", + "value": "", + "nameSize": 10, + "totalSize": 42 + }, + { + "name": "vary", + "value": "", + "nameSize": 4, + "totalSize": 36 + }, + { + "name": "via", + "value": "", + "nameSize": 3, + "totalSize": 35 + }, + { + "name": "www-authenticate", + "value": "", + "nameSize": 16, + "totalSize": 48 + } + ]; + exports2.map = { + ":authority": { + "index": 1, + "values": { + "": 1 + } + }, + ":method": { + "index": 2, + "values": { + "GET": 2, + "POST": 3 + } + }, + ":path": { + "index": 4, + "values": { + "/": 4, + "/index.html": 5 + } + }, + ":scheme": { + "index": 6, + "values": { + "http": 6, + "https": 7 + } + }, + ":status": { + "index": 8, + "values": { + "200": 8, + "204": 9, + "206": 10, + "304": 11, + "400": 12, + "404": 13, + "500": 14 + } + }, + "accept-charset": { + "index": 15, + "values": { + "": 15 + } + }, + "accept-encoding": { + "index": 16, + "values": { + "gzip, deflate": 16 + } + }, + "accept-language": { + "index": 17, + "values": { + "": 17 + } + }, + "accept-ranges": { + "index": 18, + "values": { + "": 18 + } + }, + "accept": { + "index": 19, + "values": { + "": 19 + } + }, + "access-control-allow-origin": { + "index": 20, + "values": { + "": 20 + } + }, + "age": { + "index": 21, + "values": { + "": 21 + } + }, + "allow": { + "index": 22, + "values": { + "": 22 + } + }, + "authorization": { + "index": 23, + "values": { + "": 23 + } + }, + "cache-control": { + "index": 24, + "values": { + "": 24 + } + }, + "content-disposition": { + "index": 25, + "values": { + "": 25 + } + }, + "content-encoding": { + "index": 26, + "values": { + "": 26 + } + }, + "content-language": { + "index": 27, + "values": { + "": 27 + } + }, + "content-length": { + "index": 28, + "values": { + "": 28 + } + }, + "content-location": { + "index": 29, + "values": { + "": 29 + } + }, + "content-range": { + "index": 30, + "values": { + "": 30 + } + }, + "content-type": { + "index": 31, + "values": { + "": 31 + } + }, + "cookie": { + "index": 32, + "values": { + "": 32 + } + }, + "date": { + "index": 33, + "values": { + "": 33 + } + }, + "etag": { + "index": 34, + "values": { + "": 34 + } + }, + "expect": { + "index": 35, + "values": { + "": 35 + } + }, + "expires": { + "index": 36, + "values": { + "": 36 + } + }, + "from": { + "index": 37, + "values": { + "": 37 + } + }, + "host": { + "index": 38, + "values": { + "": 38 + } + }, + "if-match": { + "index": 39, + "values": { + "": 39 + } + }, + "if-modified-since": { + "index": 40, + "values": { + "": 40 + } + }, + "if-none-match": { + "index": 41, + "values": { + "": 41 + } + }, + "if-range": { + "index": 42, + "values": { + "": 42 + } + }, + "if-unmodified-since": { + "index": 43, + "values": { + "": 43 + } + }, + "last-modified": { + "index": 44, + "values": { + "": 44 + } + }, + "link": { + "index": 45, + "values": { + "": 45 + } + }, + "location": { + "index": 46, + "values": { + "": 46 + } + }, + "max-forwards": { + "index": 47, + "values": { + "": 47 + } + }, + "proxy-authenticate": { + "index": 48, + "values": { + "": 48 + } + }, + "proxy-authorization": { + "index": 49, + "values": { + "": 49 + } + }, + "range": { + "index": 50, + "values": { + "": 50 + } + }, + "referer": { + "index": 51, + "values": { + "": 51 + } + }, + "refresh": { + "index": 52, + "values": { + "": 52 + } + }, + "retry-after": { + "index": 53, + "values": { + "": 53 + } + }, + "server": { + "index": 54, + "values": { + "": 54 + } + }, + "set-cookie": { + "index": 55, + "values": { + "": 55 + } + }, + "strict-transport-security": { + "index": 56, + "values": { + "": 56 + } + }, + "transfer-encoding": { + "index": 57, + "values": { + "": 57 + } + }, + "user-agent": { + "index": 58, + "values": { + "": 58 + } + }, + "vary": { + "index": 59, + "values": { + "": 59 + } + }, + "via": { + "index": 60, + "values": { + "": 60 + } + }, + "www-authenticate": { + "index": 61, + "values": { + "": 61 + } + } + }; + } +}); + +// scripts/node-portable/node_modules/hpack.js/lib/hpack/table.js +var require_table = __commonJS({ + "scripts/node-portable/node_modules/hpack.js/lib/hpack/table.js"(exports2, module2) { + var hpack = require_hpack(); + var utils = hpack.utils; + var assert = utils.assert; + function Table(options) { + this["static"] = hpack["static-table"]; + this.dynamic = []; + this.size = 0; + this.maxSize = 0; + this.length = this["static"].table.length; + this.protocolMaxSize = options.maxSize; + this.maxSize = this.protocolMaxSize; + this.lookupDepth = options.lookupDepth || 32; + } + module2.exports = Table; + Table.create = function create(options) { + return new Table(options); + }; + Table.prototype.lookup = function lookup(index) { + assert(index !== 0, "Zero indexed field"); + assert(index <= this.length, "Indexed field OOB"); + if (index <= this["static"].table.length) + return this["static"].table[index - 1]; + else + return this.dynamic[this.length - index]; + }; + Table.prototype.reverseLookup = function reverseLookup(name, value) { + var staticEntry = this["static"].map[name]; + if (staticEntry && staticEntry.values[value]) + return staticEntry.values[value]; + var limit = Math.max(0, this.dynamic.length - this.lookupDepth); + for (var i = this.dynamic.length - 1; i >= limit; i--) { + var entry = this.dynamic[i]; + if (entry.name === name && entry.value === value) + return this.length - i; + if (entry.name === name) { + if (staticEntry) + break; + return -(this.length - i); + } + } + if (staticEntry) + return -staticEntry.index; + return 0; + }; + Table.prototype.add = function add(name, value, nameSize, valueSize) { + var totalSize = nameSize + valueSize + 32; + this.dynamic.push({ + name, + value, + nameSize, + totalSize + }); + this.size += totalSize; + this.length++; + this.evict(); + }; + Table.prototype.evict = function evict() { + while (this.size > this.maxSize) { + var entry = this.dynamic.shift(); + this.size -= entry.totalSize; + this.length--; + } + assert(this.size >= 0, "Table size sanity check failed"); + }; + Table.prototype.updateSize = function updateSize(size) { + assert(size <= this.protocolMaxSize, "Table size bigger than maximum"); + this.maxSize = size; + this.evict(); + }; + } +}); + +// scripts/node-portable/node_modules/obuf/index.js +var require_obuf = __commonJS({ + "scripts/node-portable/node_modules/obuf/index.js"(exports2, module2) { + var Buffer2 = require("buffer").Buffer; + function OffsetBuffer() { + this.offset = 0; + this.size = 0; + this.buffers = []; + } + module2.exports = OffsetBuffer; + OffsetBuffer.prototype.isEmpty = function isEmpty() { + return this.size === 0; + }; + OffsetBuffer.prototype.clone = function clone(size) { + var r = new OffsetBuffer(); + r.offset = this.offset; + r.size = size; + r.buffers = this.buffers.slice(); + return r; + }; + OffsetBuffer.prototype.toChunks = function toChunks() { + if (this.size === 0) + return []; + if (this.offset !== 0) { + this.buffers[0] = this.buffers[0].slice(this.offset); + this.offset = 0; + } + var chunks = []; + var off = 0; + for (var i = 0; off <= this.size && i < this.buffers.length; i++) { + var buf = this.buffers[i]; + off += buf.length; + if (off > this.size) { + buf = buf.slice(0, buf.length - (off - this.size)); + this.buffers[i] = buf; + } + chunks.push(buf); + } + if (i < this.buffers.length) + this.buffers.length = i; + return chunks; + }; + OffsetBuffer.prototype.toString = function toString(enc) { + return this.toChunks().map(function(c) { + return c.toString(enc); + }).join(""); + }; + OffsetBuffer.prototype.use = function use(buf, off, n) { + this.buffers = [buf]; + this.offset = off; + this.size = n; + }; + OffsetBuffer.prototype.push = function push(data) { + if (data.length === 0) + return; + this.size += data.length; + this.buffers.push(data); + }; + OffsetBuffer.prototype.has = function has(n) { + return this.size >= n; + }; + OffsetBuffer.prototype.skip = function skip(n) { + if (this.size === 0) + return; + this.size -= n; + if (this.offset + n < this.buffers[0].length) { + this.offset += n; + return; + } + var left = n - (this.buffers[0].length - this.offset); + this.offset = 0; + for (var shift = 1; left > 0 && shift < this.buffers.length; shift++) { + var buf = this.buffers[shift]; + if (buf.length > left) { + this.offset = left; + break; + } + left -= buf.length; + } + this.buffers = this.buffers.slice(shift); + }; + OffsetBuffer.prototype.copy = function copy(target, targetOff, off, n) { + if (this.size === 0) + return; + if (off !== 0) + throw new Error("Unsupported offset in .copy()"); + var toff = targetOff; + var first = this.buffers[0]; + var toCopy = Math.min(n, first.length - this.offset); + first.copy(target, toff, this.offset, this.offset + toCopy); + toff += toCopy; + var left = n - toCopy; + for (var i = 1; left > 0 && i < this.buffers.length; i++) { + var buf = this.buffers[i]; + var toCopy = Math.min(left, buf.length); + buf.copy(target, toff, 0, toCopy); + toff += toCopy; + left -= toCopy; + } + }; + OffsetBuffer.prototype.take = function take(n) { + if (n === 0) + return new Buffer2(0); + this.size -= n; + var first = this.buffers[0].length - this.offset; + if (first === n) { + var r = this.buffers.shift(); + if (this.offset !== 0) { + r = r.slice(this.offset); + this.offset = 0; + } + return r; + } else if (first > n) { + var r = this.buffers[0].slice(this.offset, this.offset + n); + this.offset += n; + return r; + } + var out = new Buffer2(n); + var toOff = 0; + var startOff = this.offset; + for (var i = 0; toOff !== n && i < this.buffers.length; i++) { + var buf = this.buffers[i]; + var toCopy = Math.min(buf.length - startOff, n - toOff); + buf.copy(out, toOff, startOff, startOff + toCopy); + if (startOff + toCopy < buf.length) { + this.offset = startOff + toCopy; + break; + } else { + toOff += toCopy; + startOff = 0; + } + } + this.buffers = this.buffers.slice(i); + if (this.buffers.length === 0) + this.offset = 0; + return out; + }; + OffsetBuffer.prototype.peekUInt8 = function peekUInt8() { + return this.buffers[0][this.offset]; + }; + OffsetBuffer.prototype.readUInt8 = function readUInt8() { + this.size -= 1; + var first = this.buffers[0]; + var r = first[this.offset]; + if (++this.offset === first.length) { + this.offset = 0; + this.buffers.shift(); + } + return r; + }; + OffsetBuffer.prototype.readUInt16LE = function readUInt16LE() { + var first = this.buffers[0]; + this.size -= 2; + var r; + var shift; + if (first.length - this.offset >= 2) { + r = first.readUInt16LE(this.offset); + shift = 0; + this.offset += 2; + } else { + r = first[this.offset] | this.buffers[1][0] << 8; + shift = 1; + this.offset = 1; + } + if (this.offset === this.buffers[shift].length) { + this.offset = 0; + shift++; + } + if (shift !== 0) + this.buffers = this.buffers.slice(shift); + return r; + }; + OffsetBuffer.prototype.readUInt24LE = function readUInt24LE() { + var first = this.buffers[0]; + var r; + var shift; + var firstHas = first.length - this.offset; + if (firstHas >= 3) { + r = first.readUInt16LE(this.offset) | first[this.offset + 2] << 16; + shift = 0; + this.offset += 3; + } else if (firstHas >= 2) { + r = first.readUInt16LE(this.offset) | this.buffers[1][0] << 16; + shift = 1; + this.offset = 1; + } else { + r = first[this.offset]; + this.offset = 0; + this.buffers.shift(); + this.size -= 1; + r |= this.readUInt16LE() << 8; + return r; + } + this.size -= 3; + if (this.offset === this.buffers[shift].length) { + this.offset = 0; + shift++; + } + if (shift !== 0) + this.buffers = this.buffers.slice(shift); + return r; + }; + OffsetBuffer.prototype.readUInt32LE = function readUInt32LE() { + var first = this.buffers[0]; + var r; + var shift; + var firstHas = first.length - this.offset; + if (firstHas >= 4) { + r = first.readUInt32LE(this.offset); + shift = 0; + this.offset += 4; + } else if (firstHas >= 3) { + r = (first.readUInt16LE(this.offset) | first[this.offset + 2] << 16) + this.buffers[1][0] * 16777216; + shift = 1; + this.offset = 1; + } else if (firstHas >= 2) { + r = first.readUInt16LE(this.offset); + this.offset = 0; + this.buffers.shift(); + this.size -= 2; + r += this.readUInt16LE() * 65536; + return r; + } else { + r = first[this.offset]; + this.offset = 0; + this.buffers.shift(); + this.size -= 1; + r += this.readUInt24LE() * 256; + return r; + } + this.size -= 4; + if (this.offset === this.buffers[shift].length) { + this.offset = 0; + shift++; + } + if (shift !== 0) + this.buffers = this.buffers.slice(shift); + return r; + }; + OffsetBuffer.prototype.readUInt16BE = function readUInt16BE() { + var r = this.readUInt16LE(); + return (r & 255) << 8 | r >> 8; + }; + OffsetBuffer.prototype.readUInt24BE = function readUInt24BE() { + var r = this.readUInt24LE(); + return (r & 255) << 16 | (r >> 8 & 255) << 8 | r >> 16; + }; + OffsetBuffer.prototype.readUInt32BE = function readUInt32BE() { + var r = this.readUInt32LE(); + return ((r & 255) << 24 | (r >>> 8 & 255) << 16 | (r >>> 16 & 255) << 8 | r >>> 24) >>> 0; + }; + function signedInt8(num) { + if (num >= 128) + return -(255 ^ num) - 1; + else + return num; + } + OffsetBuffer.prototype.peekInt8 = function peekInt8() { + return signedInt8(this.peekUInt8()); + }; + OffsetBuffer.prototype.readInt8 = function readInt8() { + return signedInt8(this.readUInt8()); + }; + function signedInt16(num) { + if (num >= 32768) + return -(65535 ^ num) - 1; + else + return num; + } + OffsetBuffer.prototype.readInt16BE = function readInt16BE() { + return signedInt16(this.readUInt16BE()); + }; + OffsetBuffer.prototype.readInt16LE = function readInt16LE() { + return signedInt16(this.readUInt16LE()); + }; + function signedInt24(num) { + if (num >= 8388608) + return -(16777215 ^ num) - 1; + else + return num; + } + OffsetBuffer.prototype.readInt24BE = function readInt24BE() { + return signedInt24(this.readUInt24BE()); + }; + OffsetBuffer.prototype.readInt24LE = function readInt24LE() { + return signedInt24(this.readUInt24LE()); + }; + function signedInt32(num) { + if (num >= 2147483648) + return -(4294967295 ^ num) - 1; + else + return num; + } + OffsetBuffer.prototype.readInt32BE = function readInt32BE() { + return signedInt32(this.readUInt32BE()); + }; + OffsetBuffer.prototype.readInt32LE = function readInt32LE() { + return signedInt32(this.readUInt32LE()); + }; + } +}); + +// scripts/node-portable/node_modules/hpack.js/lib/hpack/decoder.js +var require_decoder = __commonJS({ + "scripts/node-portable/node_modules/hpack.js/lib/hpack/decoder.js"(exports2, module2) { + var hpack = require_hpack(); + var utils = hpack.utils; + var huffman = hpack.huffman.decode; + var assert = utils.assert; + var OffsetBuffer = require_obuf(); + function Decoder() { + this.buffer = new OffsetBuffer(); + this.bitOffset = 0; + this._huffmanNode = null; + } + module2.exports = Decoder; + Decoder.create = function create() { + return new Decoder(); + }; + Decoder.prototype.isEmpty = function isEmpty() { + return this.buffer.isEmpty(); + }; + Decoder.prototype.push = function push(chunk) { + this.buffer.push(chunk); + }; + Decoder.prototype.decodeBit = function decodeBit() { + assert(this.buffer.has(1), "Buffer too small for an int"); + var octet; + var offset = this.bitOffset; + if (++this.bitOffset === 8) { + octet = this.buffer.readUInt8(); + this.bitOffset = 0; + } else { + octet = this.buffer.peekUInt8(); + } + return octet >>> 7 - offset & 1; + }; + Decoder.prototype.skipBits = function skipBits(n) { + this.bitOffset += n; + this.buffer.skip(this.bitOffset >> 3); + this.bitOffset &= 7; + }; + Decoder.prototype.decodeInt = function decodeInt() { + assert(this.buffer.has(1), "Buffer too small for an int"); + var prefix = 8 - this.bitOffset; + this.bitOffset = 0; + var max = (1 << prefix) - 1; + var octet = this.buffer.readUInt8() & max; + if (octet !== max) + return octet; + var res = 0; + var isLast = false; + var len = 0; + do { + octet = this.buffer.readUInt8(); + isLast = (octet & 128) === 0; + res <<= 7; + res |= octet & 127; + len++; + } while (!isLast); + assert(isLast, "Incomplete data for multi-octet integer"); + assert(len <= 4, "Integer does not fit into 32 bits"); + res = res >>> 21 | (res >> 14 & 127) << 7 | (res >> 7 & 127) << 14 | (res & 127) << 21; + res >>= (4 - len) * 7; + res += max; + return res; + }; + Decoder.prototype.decodeHuffmanWord = function decodeHuffmanWord(input, inputBits, out) { + var root = huffman; + var node = this._huffmanNode; + var word = input; + var bits = inputBits; + for (; bits > 0; word &= (1 << bits) - 1) { + for (var i = Math.max(0, bits - 8); i < bits; i++) { + var subnode = node[word >>> i]; + if (typeof subnode !== "number") { + node = subnode; + bits = i; + break; + } + if (subnode === 0) + continue; + if (subnode >>> 9 !== bits - i) { + subnode = 0; + continue; + } + var octet = subnode & 511; + assert(octet !== 256, "EOS in encoding"); + out.push(octet); + node = root; + bits = i; + break; + } + if (subnode === 0) + break; + } + this._huffmanNode = node; + return bits; + }; + Decoder.prototype.decodeStr = function decodeStr() { + var isHuffman = this.decodeBit(); + var len = this.decodeInt(); + assert(this.buffer.has(len), "Not enough octets for string"); + if (!isHuffman) + return this.buffer.take(len); + this._huffmanNode = huffman; + var out = []; + var word = 0; + var bits = 0; + var lastKey = 0; + for (var i = 0; i < len; i++) { + word <<= 8; + word |= this.buffer.readUInt8(); + bits += 8; + bits = this.decodeHuffmanWord(word, bits, out); + lastKey = word >> bits; + word &= (1 << bits) - 1; + } + assert(this._huffmanNode === huffman, "8-bit EOS"); + assert(word + 1 === 1 << bits, "Final sequence is not EOS"); + this._huffmanNode = null; + return out; + }; + } +}); + +// scripts/node-portable/node_modules/inherits/inherits_browser.js +var require_inherits_browser = __commonJS({ + "scripts/node-portable/node_modules/inherits/inherits_browser.js"(exports2, module2) { + if (typeof Object.create === "function") { + module2.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor; + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + } + }; + } else { + module2.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor; + var TempCtor = function() { + }; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + } + }; + } + } +}); + +// scripts/node-portable/node_modules/inherits/inherits.js +var require_inherits = __commonJS({ + "scripts/node-portable/node_modules/inherits/inherits.js"(exports2, module2) { + try { + util = require("util"); + if (typeof util.inherits !== "function") throw ""; + module2.exports = util.inherits; + } catch (e) { + module2.exports = require_inherits_browser(); + } + var util; + } +}); + +// scripts/node-portable/node_modules/hpack.js/lib/hpack/decompressor.js +var require_decompressor = __commonJS({ + "scripts/node-portable/node_modules/hpack.js/lib/hpack/decompressor.js"(exports2, module2) { + var hpack = require_hpack(); + var utils = hpack.utils; + var decoder = hpack.decoder; + var table = hpack.table; + var assert = utils.assert; + var inherits = require_inherits(); + var Duplex = require("stream").Duplex; + function Decompressor(options) { + Duplex.call(this, { + readableObjectMode: true + }); + this._decoder = decoder.create(); + this._table = table.create(options.table); + } + inherits(Decompressor, Duplex); + module2.exports = Decompressor; + Decompressor.create = function create(options) { + return new Decompressor(options); + }; + Decompressor.prototype._read = function _read() { + }; + Decompressor.prototype._write = function _write(data, enc, cb) { + this._decoder.push(data); + cb(null); + }; + Decompressor.prototype.execute = function execute(cb) { + while (!this._decoder.isEmpty()) { + try { + this._execute(); + } catch (err) { + if (cb) + return done(err); + else + return this.emit("error", err); + } + } + if (cb) + done(null); + function done(err) { + process.nextTick(function() { + cb(err); + }); + } + }; + Decompressor.prototype.updateTableSize = function updateTableSize(size) { + this._table.updateSize(size); + }; + Decompressor.prototype._execute = function _execute() { + var isIndexed = this._decoder.decodeBit(); + if (isIndexed) + return this._processIndexed(); + var isIncremental = this._decoder.decodeBit(); + var neverIndex = 0; + if (!isIncremental) { + var isUpdate = this._decoder.decodeBit(); + if (isUpdate) + return this._processUpdate(); + neverIndex = this._decoder.decodeBit(); + } + this._processLiteral(isIncremental, neverIndex); + }; + Decompressor.prototype._processIndexed = function _processIndexed() { + var index = this._decoder.decodeInt(); + var lookup = this._table.lookup(index); + this.push({ name: lookup.name, value: lookup.value, neverIndex: false }); + }; + Decompressor.prototype._processLiteral = function _processLiteral(inc, never) { + var index = this._decoder.decodeInt(); + var name; + var nameSize; + if (index === 0) { + name = this._decoder.decodeStr(); + nameSize = name.length; + name = utils.stringify(name); + } else { + var lookup = this._table.lookup(index); + nameSize = lookup.nameSize; + name = lookup.name; + } + var value = this._decoder.decodeStr(); + var valueSize = value.length; + value = utils.stringify(value); + if (inc) + this._table.add(name, value, nameSize, valueSize); + this.push({ name, value, neverIndex: never !== 0 }); + }; + Decompressor.prototype._processUpdate = function _processUpdate() { + var size = this._decoder.decodeInt(); + this.updateTableSize(size); + }; + } +}); + +// scripts/node-portable/node_modules/minimalistic-assert/index.js +var require_minimalistic_assert = __commonJS({ + "scripts/node-portable/node_modules/minimalistic-assert/index.js"(exports2, module2) { + module2.exports = assert; + function assert(val, msg) { + if (!val) + throw new Error(msg || "Assertion failed"); + } + assert.equal = function assertEqual(l, r, msg) { + if (l != r) + throw new Error(msg || "Assertion failed: " + l + " != " + r); + }; + } +}); + +// scripts/node-portable/node_modules/wbuf/index.js +var require_wbuf = __commonJS({ + "scripts/node-portable/node_modules/wbuf/index.js"(exports2, module2) { + var assert = require_minimalistic_assert(); + var Buffer2 = require("buffer").Buffer; + function WBuf() { + this.buffers = []; + this.toReserve = 0; + this.size = 0; + this.maxSize = 0; + this.avail = 0; + this.last = null; + this.offset = 0; + this.sliceQueue = null; + this.forceReserve = false; + this.reserveRate = 64; + } + module2.exports = WBuf; + WBuf.prototype.reserve = function reserve(n) { + this.toReserve += n; + if (this.forceReserve) + this.toReserve = Math.max(this.toReserve, this.reserveRate); + }; + WBuf.prototype._ensure = function _ensure(n) { + if (this.avail >= n) + return; + if (this.toReserve === 0) + this.toReserve = this.reserveRate; + this.toReserve = Math.max(n - this.avail, this.toReserve); + if (this.avail === 0) + this._next(); + }; + WBuf.prototype._next = function _next() { + var buf; + if (this.sliceQueue === null) { + buf = new Buffer2(this.toReserve); + } else { + buf = this.sliceQueue.shift(); + if (this.sliceQueue.length === 0) + this.sliceQueue = null; + } + this.toReserve = 0; + this.buffers.push(buf); + this.avail = buf.length; + this.offset = 0; + this.last = buf; + }; + WBuf.prototype._rangeCheck = function _rangeCheck() { + if (this.maxSize !== 0 && this.size > this.maxSize) + throw new RangeError("WBuf overflow"); + }; + WBuf.prototype._move = function _move(n) { + this.size += n; + if (this.avail === 0) + this.last = null; + this._rangeCheck(); + }; + WBuf.prototype.slice = function slice(start, end) { + assert(0 <= start && start <= this.size); + assert(0 <= end && end <= this.size); + if (this.last === null) + this._next(); + var res = new WBuf(); + if (start >= this.size - this.offset) { + res.buffers.push(this.last); + res.last = this.last; + res.offset = start - this.size + this.offset; + res.maxSize = end - start; + res.avail = res.maxSize; + return res; + } + var startIndex = -1; + var startOffset = 0; + var endIndex = -1; + var offset = 0; + for (var i = 0; i < this.buffers.length; i++) { + var buf = this.buffers[i]; + var next = offset + buf.length; + if (start >= offset && start <= next) { + startIndex = i; + startOffset = start - offset; + if (endIndex !== -1) + break; + } + if (end >= offset && end <= next) { + endIndex = i; + if (startIndex !== -1) + break; + } + offset = next; + } + res.last = this.buffers[startIndex]; + res.offset = startOffset; + res.maxSize = end - start; + if (startIndex < endIndex) { + res.sliceQueue = this.buffers.slice(startIndex + 1, endIndex + 1); + res.last = res.last.slice(res.offset); + res.offset = 0; + } + res.avail = res.last.length - res.offset; + res.buffers.push(res.last); + return res; + }; + WBuf.prototype.skip = function skip(n) { + if (n === 0) + return this.slice(this.size, this.size); + this._ensure(n); + var left = n; + while (left > 0) { + var toSkip = Math.min(left, this.avail); + left -= toSkip; + this.size += toSkip; + if (toSkip === this.avail) { + if (left !== 0) { + this._next(); + } else { + this.avail -= toSkip; + this.offset += toSkip; + } + } else { + this.offset += toSkip; + this.avail -= toSkip; + } + } + this._rangeCheck(); + return this.slice(this.size - n, this.size); + }; + WBuf.prototype.write = function write(str) { + var len = 0; + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + if (c > 255) + len += 2; + else + len += 1; + } + this.reserve(len); + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + var hi = c >>> 8; + var lo = c & 255; + if (hi) + this.writeUInt8(hi); + this.writeUInt8(lo); + } + }; + WBuf.prototype.copyFrom = function copyFrom(buf, start, end) { + var off = start === void 0 ? 0 : start; + var len = end === void 0 ? buf.length : end; + if (off === len) + return; + this._ensure(len - off); + while (off < len) { + var toCopy = Math.min(len - off, this.avail); + buf.copy(this.last, this.offset, off, off + toCopy); + off += toCopy; + this.size += toCopy; + if (toCopy === this.avail) { + if (off !== len) { + this._next(); + } else { + this.avail = 0; + this.offset += toCopy; + } + } else { + this.offset += toCopy; + this.avail -= toCopy; + } + } + this._rangeCheck(); + }; + WBuf.prototype.writeUInt8 = function writeUInt8(v) { + this._ensure(1); + this.last[this.offset++] = v; + this.avail--; + this._move(1); + }; + WBuf.prototype.writeUInt16BE = function writeUInt16BE(v) { + this._ensure(2); + if (this.avail >= 2) { + this.last.writeUInt16BE(v, this.offset); + this.offset += 2; + this.avail -= 2; + } else { + this.last[this.offset] = v >>> 8; + this._next(); + this.last[this.offset++] = v & 255; + this.avail--; + } + this._move(2); + }; + WBuf.prototype.writeUInt24BE = function writeUInt24BE(v) { + this._ensure(3); + if (this.avail >= 3) { + this.last.writeUInt16BE(v >>> 8, this.offset); + this.last[this.offset + 2] = v & 255; + this.offset += 3; + this.avail -= 3; + this._move(3); + } else if (this.avail >= 2) { + this.last.writeUInt16BE(v >>> 8, this.offset); + this._next(); + this.last[this.offset++] = v & 255; + this.avail--; + this._move(3); + } else { + this.last[this.offset] = v >>> 16; + this._move(1); + this._next(); + this.writeUInt16BE(v & 65535); + } + }; + WBuf.prototype.writeUInt32BE = function writeUInt32BE(v) { + this._ensure(4); + if (this.avail >= 4) { + this.last.writeUInt32BE(v, this.offset); + this.offset += 4; + this.avail -= 4; + this._move(4); + } else if (this.avail >= 3) { + this.writeUInt24BE(v >>> 8); + this._next(); + this.last[this.offset++] = v & 255; + this.avail--; + this._move(1); + } else { + this.writeUInt16BE(v >>> 16); + this.writeUInt16BE(v & 65535); + } + }; + WBuf.prototype.writeUInt16LE = function writeUInt16LE(num) { + var r = (num & 255) << 8 | num >>> 8; + this.writeUInt16BE(r); + }; + WBuf.prototype.writeUInt24LE = function writeUInt24LE(num) { + var r = (num & 255) << 16 | (num >>> 8 & 255) << 8 | num >>> 16; + this.writeUInt24BE(r); + }; + WBuf.prototype.writeUInt32LE = function writeUInt32LE(num) { + this._ensure(4); + if (this.avail >= 4) { + this.last.writeUInt32LE(num, this.offset); + this.offset += 4; + this.avail -= 4; + this._move(4); + } else if (this.avail >= 3) { + this.writeUInt24LE(num & 16777215); + this._next(); + this.last[this.offset++] = num >>> 24; + this.avail--; + this._move(1); + } else { + this.writeUInt16LE(num & 65535); + this.writeUInt16LE(num >>> 16); + } + }; + WBuf.prototype.render = function render() { + var left = this.size; + var out = []; + for (var i = 0; i < this.buffers.length && left >= 0; i++) { + var buf = this.buffers[i]; + left -= buf.length; + if (left >= 0) { + out.push(buf); + } else { + out.push(buf.slice(0, buf.length + left)); + } + } + return out; + }; + WBuf.prototype.writeInt8 = function writeInt8(num) { + if (num < 0) + return this.writeUInt8(256 + num); + else + return this.writeUInt8(num); + }; + function toUnsigned16(num) { + if (num < 0) + return 65536 + num; + else + return num; + } + WBuf.prototype.writeInt16LE = function writeInt16LE(num) { + this.writeUInt16LE(toUnsigned16(num)); + }; + WBuf.prototype.writeInt16BE = function writeInt16BE(num) { + this.writeUInt16BE(toUnsigned16(num)); + }; + function toUnsigned24(num) { + if (num < 0) + return 16777216 + num; + else + return num; + } + WBuf.prototype.writeInt24LE = function writeInt24LE(num) { + this.writeUInt24LE(toUnsigned24(num)); + }; + WBuf.prototype.writeInt24BE = function writeInt24BE(num) { + this.writeUInt24BE(toUnsigned24(num)); + }; + function toUnsigned32(num) { + if (num < 0) + return 4294967295 + num + 1; + else + return num; + } + WBuf.prototype.writeInt32LE = function writeInt32LE(num) { + this.writeUInt32LE(toUnsigned32(num)); + }; + WBuf.prototype.writeInt32BE = function writeInt32BE(num) { + this.writeUInt32BE(toUnsigned32(num)); + }; + WBuf.prototype.writeComb = function writeComb(size, endian, value) { + if (size === 1) + return this.writeUInt8(value); + if (endian === "le") { + if (size === 2) + this.writeUInt16LE(value); + else if (size === 3) + this.writeUInt24LE(value); + else if (size === 4) + this.writeUInt32LE(value); + } else { + if (size === 2) + this.writeUInt16BE(value); + else if (size === 3) + this.writeUInt24BE(value); + else if (size === 4) + this.writeUInt32BE(value); + } + }; + } +}); + +// scripts/node-portable/node_modules/hpack.js/lib/hpack/encoder.js +var require_encoder = __commonJS({ + "scripts/node-portable/node_modules/hpack.js/lib/hpack/encoder.js"(exports2, module2) { + var hpack = require_hpack(); + var utils = hpack.utils; + var huffman = hpack.huffman.encode; + var assert = utils.assert; + var WBuf = require_wbuf(); + function Encoder() { + this.buffer = new WBuf(); + this.word = 0; + this.bitOffset = 0; + } + module2.exports = Encoder; + Encoder.create = function create() { + return new Encoder(); + }; + Encoder.prototype.render = function render() { + return this.buffer.render(); + }; + Encoder.prototype.encodeBit = function encodeBit(bit) { + var octet; + this.word <<= 1; + this.word |= bit; + this.bitOffset++; + if (this.bitOffset === 8) { + this.buffer.writeUInt8(this.word); + this.word = 0; + this.bitOffset = 0; + } + }; + Encoder.prototype.encodeBits = function encodeBits(bits, len) { + var left = bits; + var leftLen = len; + while (leftLen > 0) { + var avail = Math.min(leftLen, 8 - this.bitOffset); + var toWrite = left >>> leftLen - avail; + if (avail === 8) { + this.buffer.writeUInt8(toWrite); + } else { + this.word <<= avail; + this.word |= toWrite; + this.bitOffset += avail; + if (this.bitOffset === 8) { + this.buffer.writeUInt8(this.word); + this.word = 0; + this.bitOffset = 0; + } + } + leftLen -= avail; + left &= (1 << leftLen) - 1; + } + }; + Encoder.prototype.skipBits = function skipBits(num) { + this.bitOffset += num; + this.buffer.skip(this.bitOffset >> 3); + this.bitOffset &= 7; + }; + Encoder.prototype.encodeInt = function encodeInt(num) { + var prefix = 8 - this.bitOffset; + this.bitOffset = 0; + var max = (1 << prefix) - 1; + if (num < max) { + this.buffer.writeUInt8(this.word << prefix | num); + return octet; + } + var left = num - max; + this.buffer.writeUInt8(this.word << prefix | max); + do { + var octet = left & 127; + left >>= 7; + if (left !== 0) + octet |= 128; + this.buffer.writeUInt8(octet); + } while (left !== 0); + }; + Encoder.prototype.encodeStr = function encodeStr(value, isHuffman) { + this.encodeBit(isHuffman ? 1 : 0); + if (!isHuffman) { + this.buffer.reserve(value.length + 1); + this.encodeInt(value.length); + for (var i = 0; i < value.length; i++) + this.buffer.writeUInt8(value[i]); + return; + } + var codes = []; + var len = 0; + var pad = 0; + for (var i = 0; i < value.length; i++) { + var code = huffman[value[i]]; + codes.push(code); + len += code[0]; + } + if (len % 8 !== 0) + pad = 8 - len % 8; + len += pad; + this.buffer.reserve(len / 8 + 1); + this.encodeInt(len / 8); + for (var i = 0; i < codes.length; i++) { + var code = codes[i]; + this.encodeBits(code[1], code[0]); + } + this.encodeBits(255 >>> 8 - pad, pad); + }; + } +}); + +// scripts/node-portable/node_modules/hpack.js/lib/hpack/compressor.js +var require_compressor = __commonJS({ + "scripts/node-portable/node_modules/hpack.js/lib/hpack/compressor.js"(exports2, module2) { + var hpack = require_hpack(); + var utils = hpack.utils; + var encoder = hpack.encoder; + var table = hpack.table; + var assert = utils.assert; + var inherits = require_inherits(); + var Duplex = require("stream").Duplex; + function Compressor(options) { + Duplex.call(this, { + writableObjectMode: true + }); + this._encoder = null; + this._table = table.create(options.table); + } + inherits(Compressor, Duplex); + module2.exports = Compressor; + Compressor.create = function create(options) { + return new Compressor(options); + }; + Compressor.prototype._read = function _read() { + }; + Compressor.prototype._write = function _write(data, enc, cb) { + assert(Array.isArray(data), "Compressor.write() expects list of headers"); + this._encoder = encoder.create(); + for (var i = 0; i < data.length; i++) + this._encodeHeader(data[i]); + var data = this._encoder.render(); + this._encoder = null; + cb(null); + for (var i = 0; i < data.length; i++) + this.push(data[i]); + }; + Compressor.prototype.updateTableSize = function updateTableSize(size) { + if (size >= this._table.protocolMaxSize) { + size = this._table.protocolMaxSize; + var enc = encoder.create(); + enc.encodeBits(1, 3); + enc.encodeInt(size); + var data = enc.render(); + for (var i = 0; i < data.length; i++) + this.push(data[i]); + } + this._table.updateSize(size); + }; + Compressor.prototype.reset = function reset() { + var enc = encoder.create(); + var size = this._table.maxSize; + enc.encodeBits(1, 3); + enc.encodeInt(0); + this._table.updateSize(0); + enc.encodeBits(1, 3); + enc.encodeInt(size); + this._table.updateSize(size); + var data = enc.render(); + for (var i = 0; i < data.length; i++) + this.push(data[i]); + }; + Compressor.prototype._encodeHeader = function _encodeHeader(header) { + if (header.neverIndex) { + var index = 0; + var neverIndex = 1; + var isIndexed = 0; + var isIncremental = 0; + } else { + var index = this._table.reverseLookup(header.name, header.value); + var isIndexed = index > 0; + var isIncremental = header.incremental !== false; + var neverIndex = 0; + } + this._encoder.encodeBit(isIndexed); + if (isIndexed) { + this._encoder.encodeInt(index); + return; + } + var name = utils.toArray(header.name); + var value = utils.toArray(header.value); + this._encoder.encodeBit(isIncremental); + if (isIncremental) { + this._table.add(header.name, header.value, name.length, value.length); + } else { + this._encoder.encodeBit(0); + this._encoder.encodeBit(neverIndex); + } + this._encoder.encodeInt(-index); + if (index === 0) + this._encoder.encodeStr(name, header.huffman !== false); + this._encoder.encodeStr(value, header.huffman !== false); + }; + } +}); + +// scripts/node-portable/node_modules/hpack.js/lib/hpack.js +var require_hpack = __commonJS({ + "scripts/node-portable/node_modules/hpack.js/lib/hpack.js"(exports2) { + var hpack = exports2; + hpack.utils = require_utils(); + hpack.huffman = require_huffman(); + hpack["static-table"] = require_static_table(); + hpack.table = require_table(); + hpack.decoder = require_decoder(); + hpack.decompressor = require_decompressor(); + hpack.encoder = require_encoder(); + hpack.compressor = require_compressor(); + } +}); + +// scripts/node-portable/.entry-hpack.cjs +module.exports = require_hpack(); diff --git a/src/Node/Lib/portable/http2-constants.json b/src/Node/Lib/portable/http2-constants.json new file mode 100644 index 00000000..ee6069ec --- /dev/null +++ b/src/Node/Lib/portable/http2-constants.json @@ -0,0 +1,242 @@ +{ + "NGHTTP2_ERR_FRAME_SIZE_ERROR": -522, + "NGHTTP2_SESSION_SERVER": 0, + "NGHTTP2_SESSION_CLIENT": 1, + "NGHTTP2_STREAM_STATE_IDLE": 1, + "NGHTTP2_STREAM_STATE_OPEN": 2, + "NGHTTP2_STREAM_STATE_RESERVED_LOCAL": 3, + "NGHTTP2_STREAM_STATE_RESERVED_REMOTE": 4, + "NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL": 5, + "NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE": 6, + "NGHTTP2_STREAM_STATE_CLOSED": 7, + "NGHTTP2_FLAG_NONE": 0, + "NGHTTP2_FLAG_END_STREAM": 1, + "NGHTTP2_FLAG_END_HEADERS": 4, + "NGHTTP2_FLAG_ACK": 1, + "NGHTTP2_FLAG_PADDED": 8, + "NGHTTP2_FLAG_PRIORITY": 32, + "DEFAULT_SETTINGS_HEADER_TABLE_SIZE": 4096, + "DEFAULT_SETTINGS_ENABLE_PUSH": 1, + "DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS": 4294967295, + "DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE": 65535, + "DEFAULT_SETTINGS_MAX_FRAME_SIZE": 16384, + "DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE": 65535, + "DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL": 0, + "MAX_MAX_FRAME_SIZE": 16777215, + "MIN_MAX_FRAME_SIZE": 16384, + "MAX_INITIAL_WINDOW_SIZE": 2147483647, + "NGHTTP2_SETTINGS_HEADER_TABLE_SIZE": 1, + "NGHTTP2_SETTINGS_ENABLE_PUSH": 2, + "NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS": 3, + "NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE": 4, + "NGHTTP2_SETTINGS_MAX_FRAME_SIZE": 5, + "NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE": 6, + "NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL": 8, + "PADDING_STRATEGY_NONE": 0, + "PADDING_STRATEGY_ALIGNED": 1, + "PADDING_STRATEGY_MAX": 2, + "PADDING_STRATEGY_CALLBACK": 1, + "NGHTTP2_NO_ERROR": 0, + "NGHTTP2_PROTOCOL_ERROR": 1, + "NGHTTP2_INTERNAL_ERROR": 2, + "NGHTTP2_FLOW_CONTROL_ERROR": 3, + "NGHTTP2_SETTINGS_TIMEOUT": 4, + "NGHTTP2_STREAM_CLOSED": 5, + "NGHTTP2_FRAME_SIZE_ERROR": 6, + "NGHTTP2_REFUSED_STREAM": 7, + "NGHTTP2_CANCEL": 8, + "NGHTTP2_COMPRESSION_ERROR": 9, + "NGHTTP2_CONNECT_ERROR": 10, + "NGHTTP2_ENHANCE_YOUR_CALM": 11, + "NGHTTP2_INADEQUATE_SECURITY": 12, + "NGHTTP2_HTTP_1_1_REQUIRED": 13, + "NGHTTP2_DEFAULT_WEIGHT": 16, + "HTTP2_HEADER_STATUS": ":status", + "HTTP2_HEADER_METHOD": ":method", + "HTTP2_HEADER_AUTHORITY": ":authority", + "HTTP2_HEADER_SCHEME": ":scheme", + "HTTP2_HEADER_PATH": ":path", + "HTTP2_HEADER_PROTOCOL": ":protocol", + "HTTP2_HEADER_ACCEPT_ENCODING": "accept-encoding", + "HTTP2_HEADER_ACCEPT_LANGUAGE": "accept-language", + "HTTP2_HEADER_ACCEPT_RANGES": "accept-ranges", + "HTTP2_HEADER_ACCEPT": "accept", + "HTTP2_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS": "access-control-allow-credentials", + "HTTP2_HEADER_ACCESS_CONTROL_ALLOW_HEADERS": "access-control-allow-headers", + "HTTP2_HEADER_ACCESS_CONTROL_ALLOW_METHODS": "access-control-allow-methods", + "HTTP2_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN": "access-control-allow-origin", + "HTTP2_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS": "access-control-expose-headers", + "HTTP2_HEADER_ACCESS_CONTROL_REQUEST_HEADERS": "access-control-request-headers", + "HTTP2_HEADER_ACCESS_CONTROL_REQUEST_METHOD": "access-control-request-method", + "HTTP2_HEADER_AGE": "age", + "HTTP2_HEADER_AUTHORIZATION": "authorization", + "HTTP2_HEADER_CACHE_CONTROL": "cache-control", + "HTTP2_HEADER_CONNECTION": "connection", + "HTTP2_HEADER_CONTENT_DISPOSITION": "content-disposition", + "HTTP2_HEADER_CONTENT_ENCODING": "content-encoding", + "HTTP2_HEADER_CONTENT_LENGTH": "content-length", + "HTTP2_HEADER_CONTENT_TYPE": "content-type", + "HTTP2_HEADER_COOKIE": "cookie", + "HTTP2_HEADER_DATE": "date", + "HTTP2_HEADER_ETAG": "etag", + "HTTP2_HEADER_FORWARDED": "forwarded", + "HTTP2_HEADER_HOST": "host", + "HTTP2_HEADER_IF_MODIFIED_SINCE": "if-modified-since", + "HTTP2_HEADER_IF_NONE_MATCH": "if-none-match", + "HTTP2_HEADER_IF_RANGE": "if-range", + "HTTP2_HEADER_LAST_MODIFIED": "last-modified", + "HTTP2_HEADER_LINK": "link", + "HTTP2_HEADER_LOCATION": "location", + "HTTP2_HEADER_RANGE": "range", + "HTTP2_HEADER_REFERER": "referer", + "HTTP2_HEADER_SERVER": "server", + "HTTP2_HEADER_SET_COOKIE": "set-cookie", + "HTTP2_HEADER_STRICT_TRANSPORT_SECURITY": "strict-transport-security", + "HTTP2_HEADER_TRANSFER_ENCODING": "transfer-encoding", + "HTTP2_HEADER_TE": "te", + "HTTP2_HEADER_UPGRADE_INSECURE_REQUESTS": "upgrade-insecure-requests", + "HTTP2_HEADER_UPGRADE": "upgrade", + "HTTP2_HEADER_USER_AGENT": "user-agent", + "HTTP2_HEADER_VARY": "vary", + "HTTP2_HEADER_X_CONTENT_TYPE_OPTIONS": "x-content-type-options", + "HTTP2_HEADER_X_FRAME_OPTIONS": "x-frame-options", + "HTTP2_HEADER_KEEP_ALIVE": "keep-alive", + "HTTP2_HEADER_PROXY_CONNECTION": "proxy-connection", + "HTTP2_HEADER_X_XSS_PROTECTION": "x-xss-protection", + "HTTP2_HEADER_ALT_SVC": "alt-svc", + "HTTP2_HEADER_CONTENT_SECURITY_POLICY": "content-security-policy", + "HTTP2_HEADER_EARLY_DATA": "early-data", + "HTTP2_HEADER_EXPECT_CT": "expect-ct", + "HTTP2_HEADER_ORIGIN": "origin", + "HTTP2_HEADER_PURPOSE": "purpose", + "HTTP2_HEADER_TIMING_ALLOW_ORIGIN": "timing-allow-origin", + "HTTP2_HEADER_X_FORWARDED_FOR": "x-forwarded-for", + "HTTP2_HEADER_PRIORITY": "priority", + "HTTP2_HEADER_ACCEPT_CHARSET": "accept-charset", + "HTTP2_HEADER_ACCESS_CONTROL_MAX_AGE": "access-control-max-age", + "HTTP2_HEADER_ALLOW": "allow", + "HTTP2_HEADER_CONTENT_LANGUAGE": "content-language", + "HTTP2_HEADER_CONTENT_LOCATION": "content-location", + "HTTP2_HEADER_CONTENT_MD5": "content-md5", + "HTTP2_HEADER_CONTENT_RANGE": "content-range", + "HTTP2_HEADER_DNT": "dnt", + "HTTP2_HEADER_EXPECT": "expect", + "HTTP2_HEADER_EXPIRES": "expires", + "HTTP2_HEADER_FROM": "from", + "HTTP2_HEADER_IF_MATCH": "if-match", + "HTTP2_HEADER_IF_UNMODIFIED_SINCE": "if-unmodified-since", + "HTTP2_HEADER_MAX_FORWARDS": "max-forwards", + "HTTP2_HEADER_PREFER": "prefer", + "HTTP2_HEADER_PROXY_AUTHENTICATE": "proxy-authenticate", + "HTTP2_HEADER_PROXY_AUTHORIZATION": "proxy-authorization", + "HTTP2_HEADER_REFRESH": "refresh", + "HTTP2_HEADER_RETRY_AFTER": "retry-after", + "HTTP2_HEADER_TRAILER": "trailer", + "HTTP2_HEADER_TK": "tk", + "HTTP2_HEADER_VIA": "via", + "HTTP2_HEADER_WARNING": "warning", + "HTTP2_HEADER_WWW_AUTHENTICATE": "www-authenticate", + "HTTP2_HEADER_HTTP2_SETTINGS": "http2-settings", + "HTTP2_METHOD_ACL": "ACL", + "HTTP2_METHOD_BASELINE_CONTROL": "BASELINE-CONTROL", + "HTTP2_METHOD_BIND": "BIND", + "HTTP2_METHOD_CHECKIN": "CHECKIN", + "HTTP2_METHOD_CHECKOUT": "CHECKOUT", + "HTTP2_METHOD_CONNECT": "CONNECT", + "HTTP2_METHOD_COPY": "COPY", + "HTTP2_METHOD_DELETE": "DELETE", + "HTTP2_METHOD_GET": "GET", + "HTTP2_METHOD_HEAD": "HEAD", + "HTTP2_METHOD_LABEL": "LABEL", + "HTTP2_METHOD_LINK": "LINK", + "HTTP2_METHOD_LOCK": "LOCK", + "HTTP2_METHOD_MERGE": "MERGE", + "HTTP2_METHOD_MKACTIVITY": "MKACTIVITY", + "HTTP2_METHOD_MKCALENDAR": "MKCALENDAR", + "HTTP2_METHOD_MKCOL": "MKCOL", + "HTTP2_METHOD_MKREDIRECTREF": "MKREDIRECTREF", + "HTTP2_METHOD_MKWORKSPACE": "MKWORKSPACE", + "HTTP2_METHOD_MOVE": "MOVE", + "HTTP2_METHOD_OPTIONS": "OPTIONS", + "HTTP2_METHOD_ORDERPATCH": "ORDERPATCH", + "HTTP2_METHOD_PATCH": "PATCH", + "HTTP2_METHOD_POST": "POST", + "HTTP2_METHOD_PRI": "PRI", + "HTTP2_METHOD_PROPFIND": "PROPFIND", + "HTTP2_METHOD_PROPPATCH": "PROPPATCH", + "HTTP2_METHOD_PUT": "PUT", + "HTTP2_METHOD_REBIND": "REBIND", + "HTTP2_METHOD_REPORT": "REPORT", + "HTTP2_METHOD_SEARCH": "SEARCH", + "HTTP2_METHOD_TRACE": "TRACE", + "HTTP2_METHOD_UNBIND": "UNBIND", + "HTTP2_METHOD_UNCHECKOUT": "UNCHECKOUT", + "HTTP2_METHOD_UNLINK": "UNLINK", + "HTTP2_METHOD_UNLOCK": "UNLOCK", + "HTTP2_METHOD_UPDATE": "UPDATE", + "HTTP2_METHOD_UPDATEREDIRECTREF": "UPDATEREDIRECTREF", + "HTTP2_METHOD_VERSION_CONTROL": "VERSION-CONTROL", + "HTTP_STATUS_CONTINUE": 100, + "HTTP_STATUS_SWITCHING_PROTOCOLS": 101, + "HTTP_STATUS_PROCESSING": 102, + "HTTP_STATUS_EARLY_HINTS": 103, + "HTTP_STATUS_OK": 200, + "HTTP_STATUS_CREATED": 201, + "HTTP_STATUS_ACCEPTED": 202, + "HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION": 203, + "HTTP_STATUS_NO_CONTENT": 204, + "HTTP_STATUS_RESET_CONTENT": 205, + "HTTP_STATUS_PARTIAL_CONTENT": 206, + "HTTP_STATUS_MULTI_STATUS": 207, + "HTTP_STATUS_ALREADY_REPORTED": 208, + "HTTP_STATUS_IM_USED": 226, + "HTTP_STATUS_MULTIPLE_CHOICES": 300, + "HTTP_STATUS_MOVED_PERMANENTLY": 301, + "HTTP_STATUS_FOUND": 302, + "HTTP_STATUS_SEE_OTHER": 303, + "HTTP_STATUS_NOT_MODIFIED": 304, + "HTTP_STATUS_USE_PROXY": 305, + "HTTP_STATUS_TEMPORARY_REDIRECT": 307, + "HTTP_STATUS_PERMANENT_REDIRECT": 308, + "HTTP_STATUS_BAD_REQUEST": 400, + "HTTP_STATUS_UNAUTHORIZED": 401, + "HTTP_STATUS_PAYMENT_REQUIRED": 402, + "HTTP_STATUS_FORBIDDEN": 403, + "HTTP_STATUS_NOT_FOUND": 404, + "HTTP_STATUS_METHOD_NOT_ALLOWED": 405, + "HTTP_STATUS_NOT_ACCEPTABLE": 406, + "HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED": 407, + "HTTP_STATUS_REQUEST_TIMEOUT": 408, + "HTTP_STATUS_CONFLICT": 409, + "HTTP_STATUS_GONE": 410, + "HTTP_STATUS_LENGTH_REQUIRED": 411, + "HTTP_STATUS_PRECONDITION_FAILED": 412, + "HTTP_STATUS_PAYLOAD_TOO_LARGE": 413, + "HTTP_STATUS_URI_TOO_LONG": 414, + "HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE": 415, + "HTTP_STATUS_RANGE_NOT_SATISFIABLE": 416, + "HTTP_STATUS_EXPECTATION_FAILED": 417, + "HTTP_STATUS_TEAPOT": 418, + "HTTP_STATUS_MISDIRECTED_REQUEST": 421, + "HTTP_STATUS_UNPROCESSABLE_ENTITY": 422, + "HTTP_STATUS_LOCKED": 423, + "HTTP_STATUS_FAILED_DEPENDENCY": 424, + "HTTP_STATUS_TOO_EARLY": 425, + "HTTP_STATUS_UPGRADE_REQUIRED": 426, + "HTTP_STATUS_PRECONDITION_REQUIRED": 428, + "HTTP_STATUS_TOO_MANY_REQUESTS": 429, + "HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE": 431, + "HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS": 451, + "HTTP_STATUS_INTERNAL_SERVER_ERROR": 500, + "HTTP_STATUS_NOT_IMPLEMENTED": 501, + "HTTP_STATUS_BAD_GATEWAY": 502, + "HTTP_STATUS_SERVICE_UNAVAILABLE": 503, + "HTTP_STATUS_GATEWAY_TIMEOUT": 504, + "HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED": 505, + "HTTP_STATUS_VARIANT_ALSO_NEGOTIATES": 506, + "HTTP_STATUS_INSUFFICIENT_STORAGE": 507, + "HTTP_STATUS_LOOP_DETECTED": 508, + "HTTP_STATUS_BANDWIDTH_LIMIT_EXCEEDED": 509, + "HTTP_STATUS_NOT_EXTENDED": 510, + "HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED": 511 +} diff --git a/src/Node/Lib/portable/internal-querystring.cjs b/src/Node/Lib/portable/internal-querystring.cjs new file mode 100644 index 00000000..240794c3 --- /dev/null +++ b/src/Node/Lib/portable/internal-querystring.cjs @@ -0,0 +1,119 @@ +'use strict'; + +const { + Array, + Int8Array, + NumberPrototypeToString, + StringPrototypeCharCodeAt, + StringPrototypeSlice, + StringPrototypeToUpperCase, +} = require('./primordials.cjs'); + +const { ERR_INVALID_URI } = require('./errors.cjs').codes; + +const hexTable = new Array(256); +for (let i = 0; i < 256; ++i) + hexTable[i] = '%' + + StringPrototypeToUpperCase((i < 16 ? '0' : '') + + NumberPrototypeToString(i, 16)); + +const isHexTable = new Int8Array([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32 - 47 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64 - 79 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 - 95 + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96 - 111 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112 - 127 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 ... + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ... 256 +]); + +/** + * @param {string} str + * @param {Int8Array} noEscapeTable + * @param {string[]} hexTable + * @returns {string} + */ +function encodeStr(str, noEscapeTable, hexTable) { + const len = str.length; + if (len === 0) + return ''; + + let out = ''; + let lastPos = 0; + let i = 0; + + outer: + for (; i < len; i++) { + let c = StringPrototypeCharCodeAt(str, i); + + // ASCII + while (c < 0x80) { + if (noEscapeTable[c] !== 1) { + if (lastPos < i) + out += StringPrototypeSlice(str, lastPos, i); + lastPos = i + 1; + out += hexTable[c]; + } + + if (++i === len) + break outer; + + c = StringPrototypeCharCodeAt(str, i); + } + + if (lastPos < i) + out += StringPrototypeSlice(str, lastPos, i); + + // Multi-byte characters ... + if (c < 0x800) { + lastPos = i + 1; + out += hexTable[0xC0 | (c >> 6)] + + hexTable[0x80 | (c & 0x3F)]; + continue; + } + if (c < 0xD800 || c >= 0xE000) { + lastPos = i + 1; + out += hexTable[0xE0 | (c >> 12)] + + hexTable[0x80 | ((c >> 6) & 0x3F)] + + hexTable[0x80 | (c & 0x3F)]; + continue; + } + // Surrogate pair + ++i; + + // This branch should never happen because all URLSearchParams entries + // should already be converted to USVString. But, included for + // completion's sake anyway. + if (i >= len) + throw new ERR_INVALID_URI(); + + const c2 = StringPrototypeCharCodeAt(str, i) & 0x3FF; + + lastPos = i + 1; + c = 0x10000 + (((c & 0x3FF) << 10) | c2); + out += hexTable[0xF0 | (c >> 18)] + + hexTable[0x80 | ((c >> 12) & 0x3F)] + + hexTable[0x80 | ((c >> 6) & 0x3F)] + + hexTable[0x80 | (c & 0x3F)]; + } + if (lastPos === 0) + return str; + if (lastPos < len) + return out + StringPrototypeSlice(str, lastPos); + return out; +} + +module.exports = { + encodeStr, + hexTable, + isHexTable, +}; diff --git a/src/Node/Lib/portable/minimatch.cjs b/src/Node/Lib/portable/minimatch.cjs new file mode 100644 index 00000000..9b89649b --- /dev/null +++ b/src/Node/Lib/portable/minimatch.cjs @@ -0,0 +1,1733 @@ +var __getOwnPropNames = Object.getOwnPropertyNames; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; + +// scripts/node-portable/node_modules/balanced-match/dist/commonjs/index.js +var require_commonjs = __commonJS({ + "scripts/node-portable/node_modules/balanced-match/dist/commonjs/index.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.range = exports2.balanced = void 0; + var balanced = (a, b, str) => { + const ma = a instanceof RegExp ? maybeMatch(a, str) : a; + const mb = b instanceof RegExp ? maybeMatch(b, str) : b; + const r = ma !== null && mb != null && (0, exports2.range)(ma, mb, str); + return r && { + start: r[0], + end: r[1], + pre: str.slice(0, r[0]), + body: str.slice(r[0] + ma.length, r[1]), + post: str.slice(r[1] + mb.length) + }; + }; + exports2.balanced = balanced; + var maybeMatch = (reg, str) => { + const m = str.match(reg); + return m ? m[0] : null; + }; + var range = (a, b, str) => { + let begs, beg, left, right = void 0, result; + let ai = str.indexOf(a); + let bi = str.indexOf(b, ai + 1); + let i = ai; + if (ai >= 0 && bi > 0) { + if (a === b) { + return [ai, bi]; + } + begs = []; + left = str.length; + while (i >= 0 && !result) { + if (i === ai) { + begs.push(i); + ai = str.indexOf(a, i + 1); + } else if (begs.length === 1) { + const r = begs.pop(); + if (r !== void 0) + result = [r, bi]; + } else { + beg = begs.pop(); + if (beg !== void 0 && beg < left) { + left = beg; + right = bi; + } + bi = str.indexOf(b, i + 1); + } + i = ai < bi && ai >= 0 ? ai : bi; + } + if (begs.length && right !== void 0) { + result = [left, right]; + } + } + return result; + }; + exports2.range = range; + } +}); + +// scripts/node-portable/node_modules/brace-expansion/dist/commonjs/index.js +var require_commonjs2 = __commonJS({ + "scripts/node-portable/node_modules/brace-expansion/dist/commonjs/index.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.EXPANSION_MAX_REWRITES = exports2.EXPANSION_MAX_DEPTH = exports2.EXPANSION_MAX_LENGTH = exports2.EXPANSION_MAX = void 0; + exports2.expand = expand; + var balanced_match_1 = require_commonjs(); + var escSlash = "\0SLASH" + Math.random() + "\0"; + var escOpen = "\0OPEN" + Math.random() + "\0"; + var escClose = "\0CLOSE" + Math.random() + "\0"; + var escComma = "\0COMMA" + Math.random() + "\0"; + var escPeriod = "\0PERIOD" + Math.random() + "\0"; + var escSlashPattern = new RegExp(escSlash, "g"); + var escOpenPattern = new RegExp(escOpen, "g"); + var escClosePattern = new RegExp(escClose, "g"); + var escCommaPattern = new RegExp(escComma, "g"); + var escPeriodPattern = new RegExp(escPeriod, "g"); + var slashPattern = /\\\\/g; + var openPattern = /\\{/g; + var closePattern = /\\}/g; + var commaPattern = /\\,/g; + var periodPattern = /\\\./g; + exports2.EXPANSION_MAX = 1e5; + exports2.EXPANSION_MAX_LENGTH = 4e6; + exports2.EXPANSION_MAX_DEPTH = 1e3; + exports2.EXPANSION_MAX_REWRITES = 1e3; + function numeric(str) { + return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0); + } + function escapeBraces(str) { + return str.replace(slashPattern, escSlash).replace(openPattern, escOpen).replace(closePattern, escClose).replace(commaPattern, escComma).replace(periodPattern, escPeriod); + } + function unescapeBraces(str) { + return str.replace(escSlashPattern, "\\").replace(escOpenPattern, "{").replace(escClosePattern, "}").replace(escCommaPattern, ",").replace(escPeriodPattern, "."); + } + function pushAll(target, items) { + for (let i = 0; i < items.length; i++) { + target.push(items[i]); + } + } + function parseCommaParts(str) { + const parts = []; + let carry = ""; + for (; ; ) { + const m = (0, balanced_match_1.balanced)("{", "}", str); + if (!m) { + const tail = str.split(","); + tail[0] = carry + tail[0]; + pushAll(parts, tail); + return parts; + } + const { pre, body, post } = m; + const p = pre.split(","); + p[0] = carry + p[0]; + p[p.length - 1] += "{" + body + "}"; + if (!post.length) { + pushAll(parts, p); + return parts; + } + carry = p.pop(); + pushAll(parts, p); + str = post; + } + } + function expand(str, options = {}) { + if (!str) { + return []; + } + const { max = exports2.EXPANSION_MAX, maxLength = exports2.EXPANSION_MAX_LENGTH, maxDepth = exports2.EXPANSION_MAX_DEPTH, maxRewrites = exports2.EXPANSION_MAX_REWRITES } = options; + if (str.slice(0, 2) === "{}") { + str = "\\{\\}" + str.slice(2); + } + return expand_(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces); + } + function embrace(str) { + return "{" + str + "}"; + } + function isPadded(el) { + return /^-?0\d/.test(el); + } + function lte(i, y) { + return i <= y; + } + function gte(i, y) { + return i >= y; + } + function combine(acc, pre, values, max, maxLength, dropEmpties) { + const out = []; + let length = 0; + for (let a = 0; a < acc.length; a++) { + for (let v = 0; v < values.length; v++) { + if (out.length >= max) + return out; + const expansion = acc[a] + pre + values[v]; + if (dropEmpties && !expansion) + continue; + if (length + expansion.length > maxLength) + return out; + out.push(expansion); + length += expansion.length; + } + } + return out; + } + function expandSequence(body, isAlphaSequence, max, maxLength) { + const n = body.split(/\.\./); + const N = []; + if (n[0] === void 0 || n[1] === void 0) { + return N; + } + const x = numeric(n[0]); + const y = numeric(n[1]); + const width = Math.max(n[0].length, n[1].length); + let incr = n.length === 3 && n[2] !== void 0 ? Math.max(Math.abs(numeric(n[2])), 1) : 1; + let test = lte; + const reverse = y < x; + if (reverse) { + incr *= -1; + test = gte; + } + const pad = n.some(isPadded); + let length = 0; + for (let i = x; test(i, y) && N.length < max; i += incr) { + let c; + if (isAlphaSequence) { + c = String.fromCharCode(i); + if (c === "\\") { + c = ""; + } + } else { + c = String(i); + if (pad) { + const need = width - c.length; + if (need > 0) { + const z = new Array(need + 1).join("0"); + if (i < 0) { + c = "-" + z + c.slice(1); + } else { + c = z + c; + } + } + } + } + if (length + c.length > maxLength) + break; + N.push(c); + length += c.length; + } + return N; + } + function expand_(str, max, maxLength, maxDepth, depth, maxRewrites, isTop) { + if (depth > maxDepth) { + return [str]; + } + let acc = [""]; + let rewrites = 0; + let dropEmpties = false; + let firstGroup = true; + for (; ; ) { + const m = (0, balanced_match_1.balanced)("{", "}", str); + if (!m) { + return combine(acc, str, [""], max, maxLength, dropEmpties); + } + const pre = m.pre; + if (/\$$/.test(pre)) { + acc = combine(acc, pre + "{" + m.body + "}", [""], max, maxLength, dropEmpties && !m.post.length); + firstGroup = false; + if (!m.post.length) + break; + str = m.post; + continue; + } + const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); + const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); + const isSequence = isNumericSequence || isAlphaSequence; + const isOptions = m.body.indexOf(",") >= 0; + if (!isSequence && !isOptions) { + if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) { + rewrites++; + str = m.pre + "{" + m.body + escClose + m.post; + isTop = true; + continue; + } + return combine(acc, pre + "{" + m.body + "}" + m.post, [""], max, maxLength, dropEmpties); + } + if (firstGroup) { + dropEmpties = isTop && !isSequence; + firstGroup = false; + } + let values; + if (isSequence) { + values = expandSequence(m.body, isAlphaSequence, max, maxLength); + } else { + let n = parseCommaParts(m.body); + if (n.length === 1 && n[0] !== void 0) { + n = expand_(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace); + if (n.length === 1) { + acc = combine(acc, pre + n[0], [""], max, maxLength, dropEmpties && !m.post.length); + if (!m.post.length) + break; + str = m.post; + continue; + } + } + let dropsEmpties = dropEmpties && !m.post.length && !pre; + for (let d = 0; dropsEmpties && d < acc.length; d++) { + if (acc[d]) { + dropsEmpties = false; + } + } + values = []; + let valuesLength = 0; + outer: for (let j = 0; j < n.length; j++) { + const expanded = expand_(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false); + for (let k = 0; k < expanded.length; k++) { + const v = expanded[k]; + if (dropsEmpties && !v) + continue; + if (values.length >= max || valuesLength + v.length > maxLength) { + break outer; + } + values.push(v); + valuesLength += v.length; + } + } + } + acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length); + if (!m.post.length) + break; + str = m.post; + } + return acc; + } + } +}); + +// scripts/node-portable/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js +var require_assert_valid_pattern = __commonJS({ + "scripts/node-portable/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.assertValidPattern = void 0; + var MAX_PATTERN_LENGTH = 1024 * 64; + var assertValidPattern = (pattern) => { + if (typeof pattern !== "string") { + throw new TypeError("invalid pattern"); + } + if (pattern.length > MAX_PATTERN_LENGTH) { + throw new TypeError("pattern is too long"); + } + }; + exports2.assertValidPattern = assertValidPattern; + } +}); + +// scripts/node-portable/node_modules/minimatch/dist/commonjs/brace-expressions.js +var require_brace_expressions = __commonJS({ + "scripts/node-portable/node_modules/minimatch/dist/commonjs/brace-expressions.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.parseClass = void 0; + var posixClasses = { + "[:alnum:]": ["\\p{L}\\p{Nl}\\p{Nd}", true], + "[:alpha:]": ["\\p{L}\\p{Nl}", true], + "[:ascii:]": ["\\x00-\\x7f", false], + "[:blank:]": ["\\p{Zs}\\t", true], + "[:cntrl:]": ["\\p{Cc}", true], + "[:digit:]": ["\\p{Nd}", true], + "[:graph:]": ["\\p{Z}\\p{C}", true, true], + "[:lower:]": ["\\p{Ll}", true], + "[:print:]": ["\\p{C}", true], + "[:punct:]": ["\\p{P}", true], + "[:space:]": ["\\p{Z}\\t\\r\\n\\v\\f", true], + "[:upper:]": ["\\p{Lu}", true], + "[:word:]": ["\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}", true], + "[:xdigit:]": ["A-Fa-f0-9", false] + }; + var braceEscape = (s) => s.replace(/[[\]\\-]/g, "\\$&"); + var regexpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + var rangesToString = (ranges) => ranges.join(""); + var parseClass = (glob, position) => { + const pos = position; + if (glob.charAt(pos) !== "[") { + throw new Error("not in a brace expression"); + } + const ranges = []; + const negs = []; + let i = pos + 1; + let sawStart = false; + let uflag = false; + let escaping = false; + let negate = false; + let endPos = pos; + let rangeStart = ""; + WHILE: while (i < glob.length) { + const c = glob.charAt(i); + if ((c === "!" || c === "^") && i === pos + 1) { + negate = true; + i++; + continue; + } + if (c === "]" && sawStart && !escaping) { + endPos = i + 1; + break; + } + sawStart = true; + if (c === "\\") { + if (!escaping) { + escaping = true; + i++; + continue; + } + } + if (c === "[" && !escaping) { + for (const [cls, [unip, u, neg]] of Object.entries(posixClasses)) { + if (glob.startsWith(cls, i)) { + if (rangeStart) { + return ["$.", false, glob.length - pos, true]; + } + i += cls.length; + if (neg) + negs.push(unip); + else + ranges.push(unip); + uflag = uflag || u; + continue WHILE; + } + } + } + escaping = false; + if (rangeStart) { + if (c > rangeStart) { + ranges.push(braceEscape(rangeStart) + "-" + braceEscape(c)); + } else if (c === rangeStart) { + ranges.push(braceEscape(c)); + } + rangeStart = ""; + i++; + continue; + } + if (glob.startsWith("-]", i + 1)) { + ranges.push(braceEscape(c + "-")); + i += 2; + continue; + } + if (glob.startsWith("-", i + 1)) { + rangeStart = c; + i += 2; + continue; + } + ranges.push(braceEscape(c)); + i++; + } + if (endPos < i) { + return ["", false, 0, false]; + } + if (!ranges.length && !negs.length) { + return ["$.", false, glob.length - pos, true]; + } + if (negs.length === 0 && ranges.length === 1 && /^\\?.$/.test(ranges[0]) && !negate) { + const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0]; + return [regexpEscape(r), false, endPos - pos, false]; + } + const sranges = "[" + (negate ? "^" : "") + rangesToString(ranges) + "]"; + const snegs = "[" + (negate ? "" : "^") + rangesToString(negs) + "]"; + const comb = ranges.length && negs.length ? "(" + sranges + "|" + snegs + ")" : ranges.length ? sranges : snegs; + return [comb, uflag, endPos - pos, true]; + }; + exports2.parseClass = parseClass; + } +}); + +// scripts/node-portable/node_modules/minimatch/dist/commonjs/unescape.js +var require_unescape = __commonJS({ + "scripts/node-portable/node_modules/minimatch/dist/commonjs/unescape.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.unescape = void 0; + var unescape = (s, { windowsPathsNoEscape = false, magicalBraces = true } = {}) => { + if (magicalBraces) { + return windowsPathsNoEscape ? s.replace(/\[([^\/\\])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\])\]/g, "$1$2").replace(/\\([^\/])/g, "$1"); + } + return windowsPathsNoEscape ? s.replace(/\[([^\/\\{}])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\{}])\]/g, "$1$2").replace(/\\([^\/{}])/g, "$1"); + }; + exports2.unescape = unescape; + } +}); + +// scripts/node-portable/node_modules/minimatch/dist/commonjs/ast.js +var require_ast = __commonJS({ + "scripts/node-portable/node_modules/minimatch/dist/commonjs/ast.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.AST = void 0; + var brace_expressions_js_1 = require_brace_expressions(); + var unescape_js_1 = require_unescape(); + var types = /* @__PURE__ */ new Set(["!", "?", "+", "*", "@"]); + var isExtglobType = (c) => types.has(c); + var startNoTraversal = "(?!(?:^|/)\\.\\.?(?:$|/))"; + var startNoDot = "(?!\\.)"; + var addPatternStart = /* @__PURE__ */ new Set(["[", "."]); + var justDots = /* @__PURE__ */ new Set(["..", "."]); + var reSpecials = new Set("().*{}+?[]^$\\!"); + var regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + var qmark = "[^/]"; + var star = qmark + "*?"; + var starNoEmpty = qmark + "+?"; + var AST = class _AST { + type; + #root; + #hasMagic; + #uflag = false; + #parts = []; + #parent; + #parentIndex; + #negs; + #filledNegs = false; + #options; + #toString; + // set to true if it's an extglob with no children + // (which really means one child of '') + #emptyExt = false; + constructor(type, parent, options = {}) { + this.type = type; + if (type) + this.#hasMagic = true; + this.#parent = parent; + this.#root = this.#parent ? this.#parent.#root : this; + this.#options = this.#root === this ? options : this.#root.#options; + this.#negs = this.#root === this ? [] : this.#root.#negs; + if (type === "!" && !this.#root.#filledNegs) + this.#negs.push(this); + this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0; + } + get hasMagic() { + if (this.#hasMagic !== void 0) + return this.#hasMagic; + for (const p of this.#parts) { + if (typeof p === "string") + continue; + if (p.type || p.hasMagic) + return this.#hasMagic = true; + } + return this.#hasMagic; + } + // reconstructs the pattern + toString() { + if (this.#toString !== void 0) + return this.#toString; + if (!this.type) { + return this.#toString = this.#parts.map((p) => String(p)).join(""); + } else { + return this.#toString = this.type + "(" + this.#parts.map((p) => String(p)).join("|") + ")"; + } + } + #fillNegs() { + if (this !== this.#root) + throw new Error("should only call on root"); + if (this.#filledNegs) + return this; + this.toString(); + this.#filledNegs = true; + let n; + while (n = this.#negs.pop()) { + if (n.type !== "!") + continue; + let p = n; + let pp = p.#parent; + while (pp) { + for (let i = p.#parentIndex + 1; !pp.type && i < pp.#parts.length; i++) { + for (const part of n.#parts) { + if (typeof part === "string") { + throw new Error("string part in extglob AST??"); + } + part.copyIn(pp.#parts[i]); + } + } + p = pp; + pp = p.#parent; + } + } + return this; + } + push(...parts) { + for (const p of parts) { + if (p === "") + continue; + if (typeof p !== "string" && !(p instanceof _AST && p.#parent === this)) { + throw new Error("invalid part: " + p); + } + this.#parts.push(p); + } + } + toJSON() { + const ret = this.type === null ? this.#parts.slice().map((p) => typeof p === "string" ? p : p.toJSON()) : [this.type, ...this.#parts.map((p) => p.toJSON())]; + if (this.isStart() && !this.type) + ret.unshift([]); + if (this.isEnd() && (this === this.#root || this.#root.#filledNegs && this.#parent?.type === "!")) { + ret.push({}); + } + return ret; + } + isStart() { + if (this.#root === this) + return true; + if (!this.#parent?.isStart()) + return false; + if (this.#parentIndex === 0) + return true; + const p = this.#parent; + for (let i = 0; i < this.#parentIndex; i++) { + const pp = p.#parts[i]; + if (!(pp instanceof _AST && pp.type === "!")) { + return false; + } + } + return true; + } + isEnd() { + if (this.#root === this) + return true; + if (this.#parent?.type === "!") + return true; + if (!this.#parent?.isEnd()) + return false; + if (!this.type) + return this.#parent?.isEnd(); + const pl = this.#parent ? this.#parent.#parts.length : 0; + return this.#parentIndex === pl - 1; + } + copyIn(part) { + if (typeof part === "string") + this.push(part); + else + this.push(part.clone(this)); + } + clone(parent) { + const c = new _AST(this.type, parent); + for (const p of this.#parts) { + c.copyIn(p); + } + return c; + } + static #parseAST(str, ast, pos, opt) { + let escaping = false; + let inBrace = false; + let braceStart = -1; + let braceNeg = false; + if (ast.type === null) { + let i2 = pos; + let acc2 = ""; + while (i2 < str.length) { + const c = str.charAt(i2++); + if (escaping || c === "\\") { + escaping = !escaping; + acc2 += c; + continue; + } + if (inBrace) { + if (i2 === braceStart + 1) { + if (c === "^" || c === "!") { + braceNeg = true; + } + } else if (c === "]" && !(i2 === braceStart + 2 && braceNeg)) { + inBrace = false; + } + acc2 += c; + continue; + } else if (c === "[") { + inBrace = true; + braceStart = i2; + braceNeg = false; + acc2 += c; + continue; + } + if (!opt.noext && isExtglobType(c) && str.charAt(i2) === "(") { + ast.push(acc2); + acc2 = ""; + const ext = new _AST(c, ast); + i2 = _AST.#parseAST(str, ext, i2, opt); + ast.push(ext); + continue; + } + acc2 += c; + } + ast.push(acc2); + return i2; + } + let i = pos + 1; + let part = new _AST(null, ast); + const parts = []; + let acc = ""; + while (i < str.length) { + const c = str.charAt(i++); + if (escaping || c === "\\") { + escaping = !escaping; + acc += c; + continue; + } + if (inBrace) { + if (i === braceStart + 1) { + if (c === "^" || c === "!") { + braceNeg = true; + } + } else if (c === "]" && !(i === braceStart + 2 && braceNeg)) { + inBrace = false; + } + acc += c; + continue; + } else if (c === "[") { + inBrace = true; + braceStart = i; + braceNeg = false; + acc += c; + continue; + } + if (isExtglobType(c) && str.charAt(i) === "(") { + part.push(acc); + acc = ""; + const ext = new _AST(c, part); + part.push(ext); + i = _AST.#parseAST(str, ext, i, opt); + continue; + } + if (c === "|") { + part.push(acc); + acc = ""; + parts.push(part); + part = new _AST(null, ast); + continue; + } + if (c === ")") { + if (acc === "" && ast.#parts.length === 0) { + ast.#emptyExt = true; + } + part.push(acc); + acc = ""; + ast.push(...parts, part); + return i; + } + acc += c; + } + ast.type = null; + ast.#hasMagic = void 0; + ast.#parts = [str.substring(pos - 1)]; + return i; + } + static fromGlob(pattern, options = {}) { + const ast = new _AST(null, void 0, options); + _AST.#parseAST(pattern, ast, 0, options); + return ast; + } + // returns the regular expression if there's magic, or the unescaped + // string if not. + toMMPattern() { + if (this !== this.#root) + return this.#root.toMMPattern(); + const glob = this.toString(); + const [re, body, hasMagic, uflag] = this.toRegExpSource(); + const anyMagic = hasMagic || this.#hasMagic || this.#options.nocase && !this.#options.nocaseMagicOnly && glob.toUpperCase() !== glob.toLowerCase(); + if (!anyMagic) { + return body; + } + const flags = (this.#options.nocase ? "i" : "") + (uflag ? "u" : ""); + return Object.assign(new RegExp(`^${re}$`, flags), { + _src: re, + _glob: glob + }); + } + get options() { + return this.#options; + } + // returns the string match, the regexp source, whether there's magic + // in the regexp (so a regular expression is required) and whether or + // not the uflag is needed for the regular expression (for posix classes) + // TODO: instead of injecting the start/end at this point, just return + // the BODY of the regexp, along with the start/end portions suitable + // for binding the start/end in either a joined full-path makeRe context + // (where we bind to (^|/), or a standalone matchPart context (where + // we bind to ^, and not /). Otherwise slashes get duped! + // + // In part-matching mode, the start is: + // - if not isStart: nothing + // - if traversal possible, but not allowed: ^(?!\.\.?$) + // - if dots allowed or not possible: ^ + // - if dots possible and not allowed: ^(?!\.) + // end is: + // - if not isEnd(): nothing + // - else: $ + // + // In full-path matching mode, we put the slash at the START of the + // pattern, so start is: + // - if first pattern: same as part-matching mode + // - if not isStart(): nothing + // - if traversal possible, but not allowed: /(?!\.\.?(?:$|/)) + // - if dots allowed or not possible: / + // - if dots possible and not allowed: /(?!\.) + // end is: + // - if last pattern, same as part-matching mode + // - else nothing + // + // Always put the (?:$|/) on negated tails, though, because that has to be + // there to bind the end of the negated pattern portion, and it's easier to + // just stick it in now rather than try to inject it later in the middle of + // the pattern. + // + // We can just always return the same end, and leave it up to the caller + // to know whether it's going to be used joined or in parts. + // And, if the start is adjusted slightly, can do the same there: + // - if not isStart: nothing + // - if traversal possible, but not allowed: (?:/|^)(?!\.\.?$) + // - if dots allowed or not possible: (?:/|^) + // - if dots possible and not allowed: (?:/|^)(?!\.) + // + // But it's better to have a simpler binding without a conditional, for + // performance, so probably better to return both start options. + // + // Then the caller just ignores the end if it's not the first pattern, + // and the start always gets applied. + // + // But that's always going to be $ if it's the ending pattern, or nothing, + // so the caller can just attach $ at the end of the pattern when building. + // + // So the todo is: + // - better detect what kind of start is needed + // - return both flavors of starting pattern + // - attach $ at the end of the pattern when creating the actual RegExp + // + // Ah, but wait, no, that all only applies to the root when the first pattern + // is not an extglob. If the first pattern IS an extglob, then we need all + // that dot prevention biz to live in the extglob portions, because eg + // +(*|.x*) can match .xy but not .yx. + // + // So, return the two flavors if it's #root and the first child is not an + // AST, otherwise leave it to the child AST to handle it, and there, + // use the (?:^|/) style of start binding. + // + // Even simplified further: + // - Since the start for a join is eg /(?!\.) and the start for a part + // is ^(?!\.), we can just prepend (?!\.) to the pattern (either root + // or start or whatever) and prepend ^ or / at the Regexp construction. + toRegExpSource(allowDot) { + const dot = allowDot ?? !!this.#options.dot; + if (this.#root === this) + this.#fillNegs(); + if (!this.type) { + const noEmpty = this.isStart() && this.isEnd() && !this.#parts.some((s) => typeof s !== "string"); + const src = this.#parts.map((p) => { + const [re, _, hasMagic, uflag] = typeof p === "string" ? _AST.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot); + this.#hasMagic = this.#hasMagic || hasMagic; + this.#uflag = this.#uflag || uflag; + return re; + }).join(""); + let start2 = ""; + if (this.isStart()) { + if (typeof this.#parts[0] === "string") { + const dotTravAllowed = this.#parts.length === 1 && justDots.has(this.#parts[0]); + if (!dotTravAllowed) { + const aps = addPatternStart; + const needNoTrav = ( + // dots are allowed, and the pattern starts with [ or . + dot && aps.has(src.charAt(0)) || // the pattern starts with \., and then [ or . + src.startsWith("\\.") && aps.has(src.charAt(2)) || // the pattern starts with \.\., and then [ or . + src.startsWith("\\.\\.") && aps.has(src.charAt(4)) + ); + const needNoDot = !dot && !allowDot && aps.has(src.charAt(0)); + start2 = needNoTrav ? startNoTraversal : needNoDot ? startNoDot : ""; + } + } + } + let end = ""; + if (this.isEnd() && this.#root.#filledNegs && this.#parent?.type === "!") { + end = "(?:$|\\/)"; + } + const final2 = start2 + src + end; + return [ + final2, + (0, unescape_js_1.unescape)(src), + this.#hasMagic = !!this.#hasMagic, + this.#uflag + ]; + } + const repeated = this.type === "*" || this.type === "+"; + const start = this.type === "!" ? "(?:(?!(?:" : "(?:"; + let body = this.#partsToRegExp(dot); + if (this.isStart() && this.isEnd() && !body && this.type !== "!") { + const s = this.toString(); + this.#parts = [s]; + this.type = null; + this.#hasMagic = void 0; + return [s, (0, unescape_js_1.unescape)(this.toString()), false, false]; + } + let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ? "" : this.#partsToRegExp(true); + if (bodyDotAllowed === body) { + bodyDotAllowed = ""; + } + if (bodyDotAllowed) { + body = `(?:${body})(?:${bodyDotAllowed})*?`; + } + let final = ""; + if (this.type === "!" && this.#emptyExt) { + final = (this.isStart() && !dot ? startNoDot : "") + starNoEmpty; + } else { + const close = this.type === "!" ? ( + // !() must match something,but !(x) can match '' + "))" + (this.isStart() && !dot && !allowDot ? startNoDot : "") + star + ")" + ) : this.type === "@" ? ")" : this.type === "?" ? ")?" : this.type === "+" && bodyDotAllowed ? ")" : this.type === "*" && bodyDotAllowed ? `)?` : `)${this.type}`; + final = start + body + close; + } + return [ + final, + (0, unescape_js_1.unescape)(body), + this.#hasMagic = !!this.#hasMagic, + this.#uflag + ]; + } + #partsToRegExp(dot) { + return this.#parts.map((p) => { + if (typeof p === "string") { + throw new Error("string type in extglob ast??"); + } + const [re, _, _hasMagic, uflag] = p.toRegExpSource(dot); + this.#uflag = this.#uflag || uflag; + return re; + }).filter((p) => !(this.isStart() && this.isEnd()) || !!p).join("|"); + } + static #parseGlob(glob, hasMagic, noEmpty = false) { + let escaping = false; + let re = ""; + let uflag = false; + let inStar = false; + for (let i = 0; i < glob.length; i++) { + const c = glob.charAt(i); + if (escaping) { + escaping = false; + re += (reSpecials.has(c) ? "\\" : "") + c; + continue; + } + if (c === "*") { + if (inStar) + continue; + inStar = true; + re += noEmpty && /^[*]+$/.test(glob) ? starNoEmpty : star; + hasMagic = true; + continue; + } else { + inStar = false; + } + if (c === "\\") { + if (i === glob.length - 1) { + re += "\\\\"; + } else { + escaping = true; + } + continue; + } + if (c === "[") { + const [src, needUflag, consumed, magic] = (0, brace_expressions_js_1.parseClass)(glob, i); + if (consumed) { + re += src; + uflag = uflag || needUflag; + i += consumed - 1; + hasMagic = hasMagic || magic; + continue; + } + } + if (c === "?") { + re += qmark; + hasMagic = true; + continue; + } + re += regExpEscape(c); + } + return [re, (0, unescape_js_1.unescape)(glob), !!hasMagic, uflag]; + } + }; + exports2.AST = AST; + } +}); + +// scripts/node-portable/node_modules/minimatch/dist/commonjs/escape.js +var require_escape = __commonJS({ + "scripts/node-portable/node_modules/minimatch/dist/commonjs/escape.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.escape = void 0; + var escape = (s, { windowsPathsNoEscape = false, magicalBraces = false } = {}) => { + if (magicalBraces) { + return windowsPathsNoEscape ? s.replace(/[?*()[\]{}]/g, "[$&]") : s.replace(/[?*()[\]\\{}]/g, "\\$&"); + } + return windowsPathsNoEscape ? s.replace(/[?*()[\]]/g, "[$&]") : s.replace(/[?*()[\]\\]/g, "\\$&"); + }; + exports2.escape = escape; + } +}); + +// scripts/node-portable/node_modules/minimatch/dist/commonjs/index.js +var require_commonjs3 = __commonJS({ + "scripts/node-portable/node_modules/minimatch/dist/commonjs/index.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.unescape = exports2.escape = exports2.AST = exports2.Minimatch = exports2.match = exports2.makeRe = exports2.braceExpand = exports2.defaults = exports2.filter = exports2.GLOBSTAR = exports2.sep = exports2.minimatch = void 0; + var brace_expansion_1 = require_commonjs2(); + var assert_valid_pattern_js_1 = require_assert_valid_pattern(); + var ast_js_1 = require_ast(); + var escape_js_1 = require_escape(); + var unescape_js_1 = require_unescape(); + var minimatch = (p, pattern, options = {}) => { + (0, assert_valid_pattern_js_1.assertValidPattern)(pattern); + if (!options.nocomment && pattern.charAt(0) === "#") { + return false; + } + return new Minimatch(pattern, options).match(p); + }; + exports2.minimatch = minimatch; + var starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/; + var starDotExtTest = (ext2) => (f) => !f.startsWith(".") && f.endsWith(ext2); + var starDotExtTestDot = (ext2) => (f) => f.endsWith(ext2); + var starDotExtTestNocase = (ext2) => { + ext2 = ext2.toLowerCase(); + return (f) => !f.startsWith(".") && f.toLowerCase().endsWith(ext2); + }; + var starDotExtTestNocaseDot = (ext2) => { + ext2 = ext2.toLowerCase(); + return (f) => f.toLowerCase().endsWith(ext2); + }; + var starDotStarRE = /^\*+\.\*+$/; + var starDotStarTest = (f) => !f.startsWith(".") && f.includes("."); + var starDotStarTestDot = (f) => f !== "." && f !== ".." && f.includes("."); + var dotStarRE = /^\.\*+$/; + var dotStarTest = (f) => f !== "." && f !== ".." && f.startsWith("."); + var starRE = /^\*+$/; + var starTest = (f) => f.length !== 0 && !f.startsWith("."); + var starTestDot = (f) => f.length !== 0 && f !== "." && f !== ".."; + var qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/; + var qmarksTestNocase = ([$0, ext2 = ""]) => { + const noext = qmarksTestNoExt([$0]); + if (!ext2) + return noext; + ext2 = ext2.toLowerCase(); + return (f) => noext(f) && f.toLowerCase().endsWith(ext2); + }; + var qmarksTestNocaseDot = ([$0, ext2 = ""]) => { + const noext = qmarksTestNoExtDot([$0]); + if (!ext2) + return noext; + ext2 = ext2.toLowerCase(); + return (f) => noext(f) && f.toLowerCase().endsWith(ext2); + }; + var qmarksTestDot = ([$0, ext2 = ""]) => { + const noext = qmarksTestNoExtDot([$0]); + return !ext2 ? noext : (f) => noext(f) && f.endsWith(ext2); + }; + var qmarksTest = ([$0, ext2 = ""]) => { + const noext = qmarksTestNoExt([$0]); + return !ext2 ? noext : (f) => noext(f) && f.endsWith(ext2); + }; + var qmarksTestNoExt = ([$0]) => { + const len = $0.length; + return (f) => f.length === len && !f.startsWith("."); + }; + var qmarksTestNoExtDot = ([$0]) => { + const len = $0.length; + return (f) => f.length === len && f !== "." && f !== ".."; + }; + var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix"; + var path = { + win32: { sep: "\\" }, + posix: { sep: "/" } + }; + exports2.sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep; + exports2.minimatch.sep = exports2.sep; + exports2.GLOBSTAR = Symbol("globstar **"); + exports2.minimatch.GLOBSTAR = exports2.GLOBSTAR; + var qmark = "[^/]"; + var star = qmark + "*?"; + var twoStarDot = "(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?"; + var twoStarNoDot = "(?:(?!(?:\\/|^)\\.).)*?"; + var filter = (pattern, options = {}) => (p) => (0, exports2.minimatch)(p, pattern, options); + exports2.filter = filter; + exports2.minimatch.filter = exports2.filter; + var ext = (a, b = {}) => Object.assign({}, a, b); + var defaults = (def) => { + if (!def || typeof def !== "object" || !Object.keys(def).length) { + return exports2.minimatch; + } + const orig = exports2.minimatch; + const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options)); + return Object.assign(m, { + Minimatch: class Minimatch extends orig.Minimatch { + constructor(pattern, options = {}) { + super(pattern, ext(def, options)); + } + static defaults(options) { + return orig.defaults(ext(def, options)).Minimatch; + } + }, + AST: class AST extends orig.AST { + /* c8 ignore start */ + constructor(type, parent, options = {}) { + super(type, parent, ext(def, options)); + } + /* c8 ignore stop */ + static fromGlob(pattern, options = {}) { + return orig.AST.fromGlob(pattern, ext(def, options)); + } + }, + unescape: (s, options = {}) => orig.unescape(s, ext(def, options)), + escape: (s, options = {}) => orig.escape(s, ext(def, options)), + filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)), + defaults: (options) => orig.defaults(ext(def, options)), + makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)), + braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)), + match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)), + sep: orig.sep, + GLOBSTAR: exports2.GLOBSTAR + }); + }; + exports2.defaults = defaults; + exports2.minimatch.defaults = exports2.defaults; + var braceExpand = (pattern, options = {}) => { + (0, assert_valid_pattern_js_1.assertValidPattern)(pattern); + if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) { + return [pattern]; + } + return (0, brace_expansion_1.expand)(pattern, { max: options.braceExpandMax }); + }; + exports2.braceExpand = braceExpand; + exports2.minimatch.braceExpand = exports2.braceExpand; + var makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe(); + exports2.makeRe = makeRe; + exports2.minimatch.makeRe = exports2.makeRe; + var match = (list, pattern, options = {}) => { + const mm = new Minimatch(pattern, options); + list = list.filter((f) => mm.match(f)); + if (mm.options.nonull && !list.length) { + list.push(pattern); + } + return list; + }; + exports2.match = match; + exports2.minimatch.match = exports2.match; + var globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/; + var regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + var Minimatch = class { + options; + set; + pattern; + windowsPathsNoEscape; + nonegate; + negate; + comment; + empty; + preserveMultipleSlashes; + partial; + globSet; + globParts; + nocase; + isWindows; + platform; + windowsNoMagicRoot; + regexp; + constructor(pattern, options = {}) { + (0, assert_valid_pattern_js_1.assertValidPattern)(pattern); + options = options || {}; + this.options = options; + this.pattern = pattern; + this.platform = options.platform || defaultPlatform; + this.isWindows = this.platform === "win32"; + const awe = "allowWindowsEscape"; + this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || options[awe] === false; + if (this.windowsPathsNoEscape) { + this.pattern = this.pattern.replace(/\\/g, "/"); + } + this.preserveMultipleSlashes = !!options.preserveMultipleSlashes; + this.regexp = null; + this.negate = false; + this.nonegate = !!options.nonegate; + this.comment = false; + this.empty = false; + this.partial = !!options.partial; + this.nocase = !!this.options.nocase; + this.windowsNoMagicRoot = options.windowsNoMagicRoot !== void 0 ? options.windowsNoMagicRoot : !!(this.isWindows && this.nocase); + this.globSet = []; + this.globParts = []; + this.set = []; + this.make(); + } + hasMagic() { + if (this.options.magicalBraces && this.set.length > 1) { + return true; + } + for (const pattern of this.set) { + for (const part of pattern) { + if (typeof part !== "string") + return true; + } + } + return false; + } + debug(..._) { + } + make() { + const pattern = this.pattern; + const options = this.options; + if (!options.nocomment && pattern.charAt(0) === "#") { + this.comment = true; + return; + } + if (!pattern) { + this.empty = true; + return; + } + this.parseNegate(); + this.globSet = [...new Set(this.braceExpand())]; + if (options.debug) { + this.debug = (...args) => console.error(...args); + } + this.debug(this.pattern, this.globSet); + const rawGlobParts = this.globSet.map((s) => this.slashSplit(s)); + this.globParts = this.preprocess(rawGlobParts); + this.debug(this.pattern, this.globParts); + let set = this.globParts.map((s, _, __) => { + if (this.isWindows && this.windowsNoMagicRoot) { + const isUNC = s[0] === "" && s[1] === "" && (s[2] === "?" || !globMagic.test(s[2])) && !globMagic.test(s[3]); + const isDrive = /^[a-z]:/i.test(s[0]); + if (isUNC) { + return [ + ...s.slice(0, 4), + ...s.slice(4).map((ss) => this.parse(ss)) + ]; + } else if (isDrive) { + return [s[0], ...s.slice(1).map((ss) => this.parse(ss))]; + } + } + return s.map((ss) => this.parse(ss)); + }); + this.debug(this.pattern, set); + this.set = set.filter((s) => s.indexOf(false) === -1); + if (this.isWindows) { + for (let i = 0; i < this.set.length; i++) { + const p = this.set[i]; + if (p[0] === "" && p[1] === "" && this.globParts[i][2] === "?" && typeof p[3] === "string" && /^[a-z]:$/i.test(p[3])) { + p[2] = "?"; + } + } + } + this.debug(this.pattern, this.set); + } + // various transforms to equivalent pattern sets that are + // faster to process in a filesystem walk. The goal is to + // eliminate what we can, and push all ** patterns as far + // to the right as possible, even if it increases the number + // of patterns that we have to process. + preprocess(globParts) { + if (this.options.noglobstar) { + for (let i = 0; i < globParts.length; i++) { + for (let j = 0; j < globParts[i].length; j++) { + if (globParts[i][j] === "**") { + globParts[i][j] = "*"; + } + } + } + } + const { optimizationLevel = 1 } = this.options; + if (optimizationLevel >= 2) { + globParts = this.firstPhasePreProcess(globParts); + globParts = this.secondPhasePreProcess(globParts); + } else if (optimizationLevel >= 1) { + globParts = this.levelOneOptimize(globParts); + } else { + globParts = this.adjascentGlobstarOptimize(globParts); + } + return globParts; + } + // just get rid of adjascent ** portions + adjascentGlobstarOptimize(globParts) { + return globParts.map((parts) => { + let gs = -1; + while (-1 !== (gs = parts.indexOf("**", gs + 1))) { + let i = gs; + while (parts[i + 1] === "**") { + i++; + } + if (i !== gs) { + parts.splice(gs, i - gs); + } + } + return parts; + }); + } + // get rid of adjascent ** and resolve .. portions + levelOneOptimize(globParts) { + return globParts.map((parts) => { + parts = parts.reduce((set, part) => { + const prev = set[set.length - 1]; + if (part === "**" && prev === "**") { + return set; + } + if (part === "..") { + if (prev && prev !== ".." && prev !== "." && prev !== "**") { + set.pop(); + return set; + } + } + set.push(part); + return set; + }, []); + return parts.length === 0 ? [""] : parts; + }); + } + levelTwoFileOptimize(parts) { + if (!Array.isArray(parts)) { + parts = this.slashSplit(parts); + } + let didSomething = false; + do { + didSomething = false; + if (!this.preserveMultipleSlashes) { + for (let i = 1; i < parts.length - 1; i++) { + const p = parts[i]; + if (i === 1 && p === "" && parts[0] === "") + continue; + if (p === "." || p === "") { + didSomething = true; + parts.splice(i, 1); + i--; + } + } + if (parts[0] === "." && parts.length === 2 && (parts[1] === "." || parts[1] === "")) { + didSomething = true; + parts.pop(); + } + } + let dd = 0; + while (-1 !== (dd = parts.indexOf("..", dd + 1))) { + const p = parts[dd - 1]; + if (p && p !== "." && p !== ".." && p !== "**") { + didSomething = true; + parts.splice(dd - 1, 2); + dd -= 2; + } + } + } while (didSomething); + return parts.length === 0 ? [""] : parts; + } + // First phase: single-pattern processing + //
 is 1 or more portions
+      //  is 1 or more portions
+      // 

is any portion other than ., .., '', or ** + // is . or '' + // + // **/.. is *brutal* for filesystem walking performance, because + // it effectively resets the recursive walk each time it occurs, + // and ** cannot be reduced out by a .. pattern part like a regexp + // or most strings (other than .., ., and '') can be. + // + //

/**/../

/

/ -> {

/../

/

/,

/**/

/

/} + //

// -> 
/
+      // 
/

/../ ->

/
+      // **/**/ -> **/
+      //
+      // **/*/ -> */**/ <== not valid because ** doesn't follow
+      // this WOULD be allowed if ** did follow symlinks, or * didn't
+      firstPhasePreProcess(globParts) {
+        let didSomething = false;
+        do {
+          didSomething = false;
+          for (let parts of globParts) {
+            let gs = -1;
+            while (-1 !== (gs = parts.indexOf("**", gs + 1))) {
+              let gss = gs;
+              while (parts[gss + 1] === "**") {
+                gss++;
+              }
+              if (gss > gs) {
+                parts.splice(gs + 1, gss - gs);
+              }
+              let next = parts[gs + 1];
+              const p = parts[gs + 2];
+              const p2 = parts[gs + 3];
+              if (next !== "..")
+                continue;
+              if (!p || p === "." || p === ".." || !p2 || p2 === "." || p2 === "..") {
+                continue;
+              }
+              didSomething = true;
+              parts.splice(gs, 1);
+              const other = parts.slice(0);
+              other[gs] = "**";
+              globParts.push(other);
+              gs--;
+            }
+            if (!this.preserveMultipleSlashes) {
+              for (let i = 1; i < parts.length - 1; i++) {
+                const p = parts[i];
+                if (i === 1 && p === "" && parts[0] === "")
+                  continue;
+                if (p === "." || p === "") {
+                  didSomething = true;
+                  parts.splice(i, 1);
+                  i--;
+                }
+              }
+              if (parts[0] === "." && parts.length === 2 && (parts[1] === "." || parts[1] === "")) {
+                didSomething = true;
+                parts.pop();
+              }
+            }
+            let dd = 0;
+            while (-1 !== (dd = parts.indexOf("..", dd + 1))) {
+              const p = parts[dd - 1];
+              if (p && p !== "." && p !== ".." && p !== "**") {
+                didSomething = true;
+                const needDot = dd === 1 && parts[dd + 1] === "**";
+                const splin = needDot ? ["."] : [];
+                parts.splice(dd - 1, 2, ...splin);
+                if (parts.length === 0)
+                  parts.push("");
+                dd -= 2;
+              }
+            }
+          }
+        } while (didSomething);
+        return globParts;
+      }
+      // second phase: multi-pattern dedupes
+      // {
/*/,
/

/} ->

/*/
+      // {
/,
/} -> 
/
+      // {
/**/,
/} -> 
/**/
+      //
+      // {
/**/,
/**/

/} ->

/**/
+      // ^-- not valid because ** doens't follow symlinks
+      secondPhasePreProcess(globParts) {
+        for (let i = 0; i < globParts.length - 1; i++) {
+          for (let j = i + 1; j < globParts.length; j++) {
+            const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
+            if (matched) {
+              globParts[i] = [];
+              globParts[j] = matched;
+              break;
+            }
+          }
+        }
+        return globParts.filter((gs) => gs.length);
+      }
+      partsMatch(a, b, emptyGSMatch = false) {
+        let ai = 0;
+        let bi = 0;
+        let result = [];
+        let which = "";
+        while (ai < a.length && bi < b.length) {
+          if (a[ai] === b[bi]) {
+            result.push(which === "b" ? b[bi] : a[ai]);
+            ai++;
+            bi++;
+          } else if (emptyGSMatch && a[ai] === "**" && b[bi] === a[ai + 1]) {
+            result.push(a[ai]);
+            ai++;
+          } else if (emptyGSMatch && b[bi] === "**" && a[ai] === b[bi + 1]) {
+            result.push(b[bi]);
+            bi++;
+          } else if (a[ai] === "*" && b[bi] && (this.options.dot || !b[bi].startsWith(".")) && b[bi] !== "**") {
+            if (which === "b")
+              return false;
+            which = "a";
+            result.push(a[ai]);
+            ai++;
+            bi++;
+          } else if (b[bi] === "*" && a[ai] && (this.options.dot || !a[ai].startsWith(".")) && a[ai] !== "**") {
+            if (which === "a")
+              return false;
+            which = "b";
+            result.push(b[bi]);
+            ai++;
+            bi++;
+          } else {
+            return false;
+          }
+        }
+        return a.length === b.length && result;
+      }
+      parseNegate() {
+        if (this.nonegate)
+          return;
+        const pattern = this.pattern;
+        let negate = false;
+        let negateOffset = 0;
+        for (let i = 0; i < pattern.length && pattern.charAt(i) === "!"; i++) {
+          negate = !negate;
+          negateOffset++;
+        }
+        if (negateOffset)
+          this.pattern = pattern.slice(negateOffset);
+        this.negate = negate;
+      }
+      // set partial to true to test if, for example,
+      // "/a/b" matches the start of "/*/b/*/d"
+      // Partial means, if you run out of file before you run
+      // out of pattern, then that's fine, as long as all
+      // the parts match.
+      matchOne(file, pattern, partial = false) {
+        const options = this.options;
+        if (this.isWindows) {
+          const fileDrive = typeof file[0] === "string" && /^[a-z]:$/i.test(file[0]);
+          const fileUNC = !fileDrive && file[0] === "" && file[1] === "" && file[2] === "?" && /^[a-z]:$/i.test(file[3]);
+          const patternDrive = typeof pattern[0] === "string" && /^[a-z]:$/i.test(pattern[0]);
+          const patternUNC = !patternDrive && pattern[0] === "" && pattern[1] === "" && pattern[2] === "?" && typeof pattern[3] === "string" && /^[a-z]:$/i.test(pattern[3]);
+          const fdi = fileUNC ? 3 : fileDrive ? 0 : void 0;
+          const pdi = patternUNC ? 3 : patternDrive ? 0 : void 0;
+          if (typeof fdi === "number" && typeof pdi === "number") {
+            const [fd, pd] = [
+              file[fdi],
+              pattern[pdi]
+            ];
+            if (fd.toLowerCase() === pd.toLowerCase()) {
+              pattern[pdi] = fd;
+              if (pdi > fdi) {
+                pattern = pattern.slice(pdi);
+              } else if (fdi > pdi) {
+                file = file.slice(fdi);
+              }
+            }
+          }
+        }
+        const { optimizationLevel = 1 } = this.options;
+        if (optimizationLevel >= 2) {
+          file = this.levelTwoFileOptimize(file);
+        }
+        this.debug("matchOne", this, { file, pattern });
+        this.debug("matchOne", file.length, pattern.length);
+        for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
+          this.debug("matchOne loop");
+          var p = pattern[pi];
+          var f = file[fi];
+          this.debug(pattern, p, f);
+          if (p === false) {
+            return false;
+          }
+          if (p === exports2.GLOBSTAR) {
+            this.debug("GLOBSTAR", [pattern, p, f]);
+            var fr = fi;
+            var pr = pi + 1;
+            if (pr === pl) {
+              this.debug("** at the end");
+              for (; fi < fl; fi++) {
+                if (file[fi] === "." || file[fi] === ".." || !options.dot && file[fi].charAt(0) === ".")
+                  return false;
+              }
+              return true;
+            }
+            while (fr < fl) {
+              var swallowee = file[fr];
+              this.debug("\nglobstar while", file, fr, pattern, pr, swallowee);
+              if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
+                this.debug("globstar found match!", fr, fl, swallowee);
+                return true;
+              } else {
+                if (swallowee === "." || swallowee === ".." || !options.dot && swallowee.charAt(0) === ".") {
+                  this.debug("dot detected!", file, fr, pattern, pr);
+                  break;
+                }
+                this.debug("globstar swallow a segment, and continue");
+                fr++;
+              }
+            }
+            if (partial) {
+              this.debug("\n>>> no match, partial?", file, fr, pattern, pr);
+              if (fr === fl) {
+                return true;
+              }
+            }
+            return false;
+          }
+          let hit;
+          if (typeof p === "string") {
+            hit = f === p;
+            this.debug("string match", p, f, hit);
+          } else {
+            hit = p.test(f);
+            this.debug("pattern match", p, f, hit);
+          }
+          if (!hit)
+            return false;
+        }
+        if (fi === fl && pi === pl) {
+          return true;
+        } else if (fi === fl) {
+          return partial;
+        } else if (pi === pl) {
+          return fi === fl - 1 && file[fi] === "";
+        } else {
+          throw new Error("wtf?");
+        }
+      }
+      braceExpand() {
+        return (0, exports2.braceExpand)(this.pattern, this.options);
+      }
+      parse(pattern) {
+        (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
+        const options = this.options;
+        if (pattern === "**")
+          return exports2.GLOBSTAR;
+        if (pattern === "")
+          return "";
+        let m;
+        let fastTest = null;
+        if (m = pattern.match(starRE)) {
+          fastTest = options.dot ? starTestDot : starTest;
+        } else if (m = pattern.match(starDotExtRE)) {
+          fastTest = (options.nocase ? options.dot ? starDotExtTestNocaseDot : starDotExtTestNocase : options.dot ? starDotExtTestDot : starDotExtTest)(m[1]);
+        } else if (m = pattern.match(qmarksRE)) {
+          fastTest = (options.nocase ? options.dot ? qmarksTestNocaseDot : qmarksTestNocase : options.dot ? qmarksTestDot : qmarksTest)(m);
+        } else if (m = pattern.match(starDotStarRE)) {
+          fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
+        } else if (m = pattern.match(dotStarRE)) {
+          fastTest = dotStarTest;
+        }
+        const re = ast_js_1.AST.fromGlob(pattern, this.options).toMMPattern();
+        if (fastTest && typeof re === "object") {
+          Reflect.defineProperty(re, "test", { value: fastTest });
+        }
+        return re;
+      }
+      makeRe() {
+        if (this.regexp || this.regexp === false)
+          return this.regexp;
+        const set = this.set;
+        if (!set.length) {
+          this.regexp = false;
+          return this.regexp;
+        }
+        const options = this.options;
+        const twoStar = options.noglobstar ? star : options.dot ? twoStarDot : twoStarNoDot;
+        const flags = new Set(options.nocase ? ["i"] : []);
+        let re = set.map((pattern) => {
+          const pp = pattern.map((p) => {
+            if (p instanceof RegExp) {
+              for (const f of p.flags.split(""))
+                flags.add(f);
+            }
+            return typeof p === "string" ? regExpEscape(p) : p === exports2.GLOBSTAR ? exports2.GLOBSTAR : p._src;
+          });
+          pp.forEach((p, i) => {
+            const next = pp[i + 1];
+            const prev = pp[i - 1];
+            if (p !== exports2.GLOBSTAR || prev === exports2.GLOBSTAR) {
+              return;
+            }
+            if (prev === void 0) {
+              if (next !== void 0 && next !== exports2.GLOBSTAR) {
+                pp[i + 1] = "(?:\\/|" + twoStar + "\\/)?" + next;
+              } else {
+                pp[i] = twoStar;
+              }
+            } else if (next === void 0) {
+              pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + ")?";
+            } else if (next !== exports2.GLOBSTAR) {
+              pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + "\\/)" + next;
+              pp[i + 1] = exports2.GLOBSTAR;
+            }
+          });
+          const filtered = pp.filter((p) => p !== exports2.GLOBSTAR);
+          if (this.partial && filtered.length >= 1) {
+            const prefixes = [];
+            for (let i = 1; i <= filtered.length; i++) {
+              prefixes.push(filtered.slice(0, i).join("/"));
+            }
+            return "(?:" + prefixes.join("|") + ")";
+          }
+          return filtered.join("/");
+        }).join("|");
+        const [open, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
+        re = "^" + open + re + close + "$";
+        if (this.partial) {
+          re = "^(?:\\/|" + open + re.slice(1, -1) + close + ")$";
+        }
+        if (this.negate)
+          re = "^(?!" + re + ").+$";
+        try {
+          this.regexp = new RegExp(re, [...flags].join(""));
+        } catch (ex) {
+          this.regexp = false;
+        }
+        return this.regexp;
+      }
+      slashSplit(p) {
+        if (this.preserveMultipleSlashes) {
+          return p.split("/");
+        } else if (this.isWindows && /^\/\/[^\/]+/.test(p)) {
+          return ["", ...p.split(/\/+/)];
+        } else {
+          return p.split(/\/+/);
+        }
+      }
+      match(f, partial = this.partial) {
+        this.debug("match", f, this.pattern);
+        if (this.comment) {
+          return false;
+        }
+        if (this.empty) {
+          return f === "";
+        }
+        if (f === "/" && partial) {
+          return true;
+        }
+        const options = this.options;
+        if (this.isWindows) {
+          f = f.split("\\").join("/");
+        }
+        const ff = this.slashSplit(f);
+        this.debug(this.pattern, "split", ff);
+        const set = this.set;
+        this.debug(this.pattern, "set", set);
+        let filename = ff[ff.length - 1];
+        if (!filename) {
+          for (let i = ff.length - 2; !filename && i >= 0; i--) {
+            filename = ff[i];
+          }
+        }
+        for (let i = 0; i < set.length; i++) {
+          const pattern = set[i];
+          let file = ff;
+          if (options.matchBase && pattern.length === 1) {
+            file = [filename];
+          }
+          const hit = this.matchOne(file, pattern, partial);
+          if (hit) {
+            if (options.flipNegate) {
+              return true;
+            }
+            return !this.negate;
+          }
+        }
+        if (options.flipNegate) {
+          return false;
+        }
+        return this.negate;
+      }
+      static defaults(def) {
+        return exports2.minimatch.defaults(def).Minimatch;
+      }
+    };
+    exports2.Minimatch = Minimatch;
+    var ast_js_2 = require_ast();
+    Object.defineProperty(exports2, "AST", { enumerable: true, get: function() {
+      return ast_js_2.AST;
+    } });
+    var escape_js_2 = require_escape();
+    Object.defineProperty(exports2, "escape", { enumerable: true, get: function() {
+      return escape_js_2.escape;
+    } });
+    var unescape_js_2 = require_unescape();
+    Object.defineProperty(exports2, "unescape", { enumerable: true, get: function() {
+      return unescape_js_2.unescape;
+    } });
+    exports2.minimatch.AST = ast_js_1.AST;
+    exports2.minimatch.Minimatch = Minimatch;
+    exports2.minimatch.escape = escape_js_1.escape;
+    exports2.minimatch.unescape = unescape_js_1.unescape;
+  }
+});
+
+// scripts/node-portable/.entry-minimatch.cjs
+module.exports = require_commonjs3();
diff --git a/src/Node/Lib/portable/primordials.cjs b/src/Node/Lib/portable/primordials.cjs
new file mode 100644
index 00000000..78efea2a
--- /dev/null
+++ b/src/Node/Lib/portable/primordials.cjs
@@ -0,0 +1,33 @@
+'use strict';
+
+// Capture intrinsics before user code can replace their prototype methods.
+module.exports = {
+  Array: Array,
+  ArrayIsArray: Array.isArray,
+  ArrayPrototypeIncludes: Function.call.bind(Array.prototype.includes),
+  ArrayPrototypeJoin: Function.call.bind(Array.prototype.join),
+  ArrayPrototypePush: Function.call.bind(Array.prototype.push),
+  ArrayPrototypeSlice: Function.call.bind(Array.prototype.slice),
+  Boolean: Boolean,
+  FunctionPrototypeBind: Function.call.bind(Function.prototype.bind),
+  Int8Array: Int8Array,
+  MathAbs: Math.abs,
+  NumberIsFinite: Number.isFinite,
+  NumberPrototypeToString: Function.call.bind(Number.prototype.toString),
+  ObjectAssign: Object.assign,
+  ObjectKeys: Object.keys,
+  String: String,
+  StringPrototypeAt: Function.call.bind(String.prototype.at),
+  StringPrototypeCharCodeAt: Function.call.bind(String.prototype.charCodeAt),
+  StringPrototypeIncludes: Function.call.bind(String.prototype.includes),
+  StringPrototypeIndexOf: Function.call.bind(String.prototype.indexOf),
+  StringPrototypeLastIndexOf: Function.call.bind(String.prototype.lastIndexOf),
+  StringPrototypeRepeat: Function.call.bind(String.prototype.repeat),
+  StringPrototypeReplace: Function.call.bind(String.prototype.replace),
+  StringPrototypeReplaceAll: Function.call.bind(String.prototype.replaceAll),
+  StringPrototypeSlice: Function.call.bind(String.prototype.slice),
+  StringPrototypeSplit: Function.call.bind(String.prototype.split),
+  StringPrototypeToLowerCase: Function.call.bind(String.prototype.toLowerCase),
+  StringPrototypeToUpperCase: Function.call.bind(String.prototype.toUpperCase),
+  decodeURIComponent: decodeURIComponent,
+};
diff --git a/src/Node/Lib/portable/punycode.cjs b/src/Node/Lib/portable/punycode.cjs
new file mode 100644
index 00000000..79d3ebda
--- /dev/null
+++ b/src/Node/Lib/portable/punycode.cjs
@@ -0,0 +1,254 @@
+var __getOwnPropNames = Object.getOwnPropertyNames;
+var __commonJS = (cb, mod) => function __require() {
+  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
+};
+
+// scripts/node-portable/node_modules/punycode/punycode.js
+var require_punycode = __commonJS({
+  "scripts/node-portable/node_modules/punycode/punycode.js"(exports2, module2) {
+    /*! https://mths.be/punycode v1.4.1 by @mathias */
+    (function(root) {
+      var freeExports = typeof exports2 == "object" && exports2 && !exports2.nodeType && exports2;
+      var freeModule = typeof module2 == "object" && module2 && !module2.nodeType && module2;
+      var freeGlobal = typeof global == "object" && global;
+      if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal) {
+        root = freeGlobal;
+      }
+      var punycode, maxInt = 2147483647, base = 36, tMin = 1, tMax = 26, skew = 38, damp = 700, initialBias = 72, initialN = 128, delimiter = "-", regexPunycode = /^xn--/, regexNonASCII = /[^\x20-\x7E]/, regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, errors = {
+        "overflow": "Overflow: input needs wider integers to process",
+        "not-basic": "Illegal input >= 0x80 (not a basic code point)",
+        "invalid-input": "Invalid input"
+      }, baseMinusTMin = base - tMin, floor = Math.floor, stringFromCharCode = String.fromCharCode, key;
+      function error(type) {
+        throw new RangeError(errors[type]);
+      }
+      function map(array, fn) {
+        var length = array.length;
+        var result = [];
+        while (length--) {
+          result[length] = fn(array[length]);
+        }
+        return result;
+      }
+      function mapDomain(string, fn) {
+        var parts = string.split("@");
+        var result = "";
+        if (parts.length > 1) {
+          result = parts[0] + "@";
+          string = parts[1];
+        }
+        string = string.replace(regexSeparators, ".");
+        var labels = string.split(".");
+        var encoded = map(labels, fn).join(".");
+        return result + encoded;
+      }
+      function ucs2decode(string) {
+        var output = [], counter = 0, length = string.length, value, extra;
+        while (counter < length) {
+          value = string.charCodeAt(counter++);
+          if (value >= 55296 && value <= 56319 && counter < length) {
+            extra = string.charCodeAt(counter++);
+            if ((extra & 64512) == 56320) {
+              output.push(((value & 1023) << 10) + (extra & 1023) + 65536);
+            } else {
+              output.push(value);
+              counter--;
+            }
+          } else {
+            output.push(value);
+          }
+        }
+        return output;
+      }
+      function ucs2encode(array) {
+        return map(array, function(value) {
+          var output = "";
+          if (value > 65535) {
+            value -= 65536;
+            output += stringFromCharCode(value >>> 10 & 1023 | 55296);
+            value = 56320 | value & 1023;
+          }
+          output += stringFromCharCode(value);
+          return output;
+        }).join("");
+      }
+      function basicToDigit(codePoint) {
+        if (codePoint - 48 < 10) {
+          return codePoint - 22;
+        }
+        if (codePoint - 65 < 26) {
+          return codePoint - 65;
+        }
+        if (codePoint - 97 < 26) {
+          return codePoint - 97;
+        }
+        return base;
+      }
+      function digitToBasic(digit, flag) {
+        return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+      }
+      function adapt(delta, numPoints, firstTime) {
+        var k = 0;
+        delta = firstTime ? floor(delta / damp) : delta >> 1;
+        delta += floor(delta / numPoints);
+        for (; delta > baseMinusTMin * tMax >> 1; k += base) {
+          delta = floor(delta / baseMinusTMin);
+        }
+        return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+      }
+      function decode(input) {
+        var output = [], inputLength = input.length, out, i = 0, n = initialN, bias = initialBias, basic, j, index, oldi, w, k, digit, t, baseMinusT;
+        basic = input.lastIndexOf(delimiter);
+        if (basic < 0) {
+          basic = 0;
+        }
+        for (j = 0; j < basic; ++j) {
+          if (input.charCodeAt(j) >= 128) {
+            error("not-basic");
+          }
+          output.push(input.charCodeAt(j));
+        }
+        for (index = basic > 0 ? basic + 1 : 0; index < inputLength; ) {
+          for (oldi = i, w = 1, k = base; ; k += base) {
+            if (index >= inputLength) {
+              error("invalid-input");
+            }
+            digit = basicToDigit(input.charCodeAt(index++));
+            if (digit >= base || digit > floor((maxInt - i) / w)) {
+              error("overflow");
+            }
+            i += digit * w;
+            t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
+            if (digit < t) {
+              break;
+            }
+            baseMinusT = base - t;
+            if (w > floor(maxInt / baseMinusT)) {
+              error("overflow");
+            }
+            w *= baseMinusT;
+          }
+          out = output.length + 1;
+          bias = adapt(i - oldi, out, oldi == 0);
+          if (floor(i / out) > maxInt - n) {
+            error("overflow");
+          }
+          n += floor(i / out);
+          i %= out;
+          output.splice(i++, 0, n);
+        }
+        return ucs2encode(output);
+      }
+      function encode(input) {
+        var n, delta, handledCPCount, basicLength, bias, j, m, q, k, t, currentValue, output = [], inputLength, handledCPCountPlusOne, baseMinusT, qMinusT;
+        input = ucs2decode(input);
+        inputLength = input.length;
+        n = initialN;
+        delta = 0;
+        bias = initialBias;
+        for (j = 0; j < inputLength; ++j) {
+          currentValue = input[j];
+          if (currentValue < 128) {
+            output.push(stringFromCharCode(currentValue));
+          }
+        }
+        handledCPCount = basicLength = output.length;
+        if (basicLength) {
+          output.push(delimiter);
+        }
+        while (handledCPCount < inputLength) {
+          for (m = maxInt, j = 0; j < inputLength; ++j) {
+            currentValue = input[j];
+            if (currentValue >= n && currentValue < m) {
+              m = currentValue;
+            }
+          }
+          handledCPCountPlusOne = handledCPCount + 1;
+          if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+            error("overflow");
+          }
+          delta += (m - n) * handledCPCountPlusOne;
+          n = m;
+          for (j = 0; j < inputLength; ++j) {
+            currentValue = input[j];
+            if (currentValue < n && ++delta > maxInt) {
+              error("overflow");
+            }
+            if (currentValue == n) {
+              for (q = delta, k = base; ; k += base) {
+                t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
+                if (q < t) {
+                  break;
+                }
+                qMinusT = q - t;
+                baseMinusT = base - t;
+                output.push(
+                  stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+                );
+                q = floor(qMinusT / baseMinusT);
+              }
+              output.push(stringFromCharCode(digitToBasic(q, 0)));
+              bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+              delta = 0;
+              ++handledCPCount;
+            }
+          }
+          ++delta;
+          ++n;
+        }
+        return output.join("");
+      }
+      function toUnicode(input) {
+        return mapDomain(input, function(string) {
+          return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string;
+        });
+      }
+      function toASCII(input) {
+        return mapDomain(input, function(string) {
+          return regexNonASCII.test(string) ? "xn--" + encode(string) : string;
+        });
+      }
+      punycode = {
+        /**
+         * A string representing the current Punycode.js version number.
+         * @memberOf punycode
+         * @type String
+         */
+        "version": "1.4.1",
+        /**
+         * An object of methods to convert from JavaScript's internal character
+         * representation (UCS-2) to Unicode code points, and back.
+         * @see 
+         * @memberOf punycode
+         * @type Object
+         */
+        "ucs2": {
+          "decode": ucs2decode,
+          "encode": ucs2encode
+        },
+        "decode": decode,
+        "encode": encode,
+        "toASCII": toASCII,
+        "toUnicode": toUnicode
+      };
+      if (typeof define == "function" && typeof define.amd == "object" && define.amd) {
+        define("punycode", function() {
+          return punycode;
+        });
+      } else if (freeExports && freeModule) {
+        if (module2.exports == freeExports) {
+          freeModule.exports = punycode;
+        } else {
+          for (key in punycode) {
+            punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+          }
+        }
+      } else {
+        root.punycode = punycode;
+      }
+    })(exports2);
+  }
+});
+
+// scripts/node-portable/.entry-punycode.cjs
+module.exports = require_punycode();
diff --git a/src/Node/Lib/portable/sources.json b/src/Node/Lib/portable/sources.json
new file mode 100644
index 00000000..21a14397
--- /dev/null
+++ b/src/Node/Lib/portable/sources.json
@@ -0,0 +1,30 @@
+{
+  "node": "v26.12.0",
+  "sources": {
+    "path": {
+      "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/path.js",
+      "sha256": "f05ab2a1f33102880bb8c5052cb0e634a001112883da897f3498492bef67f3f6"
+    },
+    "querystring": {
+      "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/querystring.js",
+      "sha256": "35c87b8230aef78ab162579a6820e78a4de8266a2983e36272ad3b248a357441"
+    },
+    "url": {
+      "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/url.js",
+      "sha256": "9037c1cae0efe6af02ea18da109ff0c406496cccaf9df4c3308ef057d009150f"
+    },
+    "internal/querystring": {
+      "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/internal/querystring.js",
+      "sha256": "92d0cbd561d7cce93936b083d56d2a41063d177f3aa6772ae2c1871f160163d1"
+    },
+    "internal/constants": {
+      "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/lib/internal/constants.js",
+      "sha256": "4548f10f15035b415bfa69a158e7bcf7e320355625d744d7318715c9acc21212"
+    },
+    "LICENSE": {
+      "url": "https://raw.githubusercontent.com/nodejs/node/v26.12.0/LICENSE",
+      "sha256": "8e603aa87c70d36e497004f0dec63111511cb61b7d65ace12e10ea791599286c"
+    }
+  },
+  "npmLockSha256": "893966b143afc47f0a9a3b9734ea594747b3e786c38f320291e4a47de3be803b"
+}
diff --git a/src/Node/Lib/portable/tr46.cjs b/src/Node/Lib/portable/tr46.cjs
new file mode 100644
index 00000000..6a62394c
--- /dev/null
+++ b/src/Node/Lib/portable/tr46.cjs
@@ -0,0 +1,578 @@
+var __getOwnPropNames = Object.getOwnPropertyNames;
+var __commonJS = (cb, mod) => function __require() {
+  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
+};
+
+// scripts/node-portable/node_modules/tr46/node_modules/punycode/punycode.js
+var require_punycode = __commonJS({
+  "scripts/node-portable/node_modules/tr46/node_modules/punycode/punycode.js"(exports2, module2) {
+    "use strict";
+    var maxInt = 2147483647;
+    var base = 36;
+    var tMin = 1;
+    var tMax = 26;
+    var skew = 38;
+    var damp = 700;
+    var initialBias = 72;
+    var initialN = 128;
+    var delimiter = "-";
+    var regexPunycode = /^xn--/;
+    var regexNonASCII = /[^\0-\x7F]/;
+    var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g;
+    var errors = {
+      "overflow": "Overflow: input needs wider integers to process",
+      "not-basic": "Illegal input >= 0x80 (not a basic code point)",
+      "invalid-input": "Invalid input"
+    };
+    var baseMinusTMin = base - tMin;
+    var floor = Math.floor;
+    var stringFromCharCode = String.fromCharCode;
+    function error(type) {
+      throw new RangeError(errors[type]);
+    }
+    function map(array, callback) {
+      const result = [];
+      let length = array.length;
+      while (length--) {
+        result[length] = callback(array[length]);
+      }
+      return result;
+    }
+    function mapDomain(domain, callback) {
+      const parts = domain.split("@");
+      let result = "";
+      if (parts.length > 1) {
+        result = parts[0] + "@";
+        domain = parts[1];
+      }
+      domain = domain.replace(regexSeparators, ".");
+      const labels = domain.split(".");
+      const encoded = map(labels, callback).join(".");
+      return result + encoded;
+    }
+    function ucs2decode(string) {
+      const output = [];
+      let counter = 0;
+      const length = string.length;
+      while (counter < length) {
+        const value = string.charCodeAt(counter++);
+        if (value >= 55296 && value <= 56319 && counter < length) {
+          const extra = string.charCodeAt(counter++);
+          if ((extra & 64512) == 56320) {
+            output.push(((value & 1023) << 10) + (extra & 1023) + 65536);
+          } else {
+            output.push(value);
+            counter--;
+          }
+        } else {
+          output.push(value);
+        }
+      }
+      return output;
+    }
+    var ucs2encode = (codePoints) => String.fromCodePoint(...codePoints);
+    var basicToDigit = function(codePoint) {
+      if (codePoint >= 48 && codePoint < 58) {
+        return 26 + (codePoint - 48);
+      }
+      if (codePoint >= 65 && codePoint < 91) {
+        return codePoint - 65;
+      }
+      if (codePoint >= 97 && codePoint < 123) {
+        return codePoint - 97;
+      }
+      return base;
+    };
+    var digitToBasic = function(digit, flag) {
+      return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+    };
+    var adapt = function(delta, numPoints, firstTime) {
+      let k = 0;
+      delta = firstTime ? floor(delta / damp) : delta >> 1;
+      delta += floor(delta / numPoints);
+      for (; delta > baseMinusTMin * tMax >> 1; k += base) {
+        delta = floor(delta / baseMinusTMin);
+      }
+      return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+    };
+    var decode = function(input) {
+      const output = [];
+      const inputLength = input.length;
+      let i = 0;
+      let n = initialN;
+      let bias = initialBias;
+      let basic = input.lastIndexOf(delimiter);
+      if (basic < 0) {
+        basic = 0;
+      }
+      for (let j = 0; j < basic; ++j) {
+        if (input.charCodeAt(j) >= 128) {
+          error("not-basic");
+        }
+        output.push(input.charCodeAt(j));
+      }
+      for (let index = basic > 0 ? basic + 1 : 0; index < inputLength; ) {
+        const oldi = i;
+        for (let w = 1, k = base; ; k += base) {
+          if (index >= inputLength) {
+            error("invalid-input");
+          }
+          const digit = basicToDigit(input.charCodeAt(index++));
+          if (digit >= base) {
+            error("invalid-input");
+          }
+          if (digit > floor((maxInt - i) / w)) {
+            error("overflow");
+          }
+          i += digit * w;
+          const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
+          if (digit < t) {
+            break;
+          }
+          const baseMinusT = base - t;
+          if (w > floor(maxInt / baseMinusT)) {
+            error("overflow");
+          }
+          w *= baseMinusT;
+        }
+        const out = output.length + 1;
+        bias = adapt(i - oldi, out, oldi == 0);
+        if (floor(i / out) > maxInt - n) {
+          error("overflow");
+        }
+        n += floor(i / out);
+        i %= out;
+        output.splice(i++, 0, n);
+      }
+      return String.fromCodePoint(...output);
+    };
+    var encode = function(input) {
+      const output = [];
+      input = ucs2decode(input);
+      const inputLength = input.length;
+      let n = initialN;
+      let delta = 0;
+      let bias = initialBias;
+      for (const currentValue of input) {
+        if (currentValue < 128) {
+          output.push(stringFromCharCode(currentValue));
+        }
+      }
+      const basicLength = output.length;
+      let handledCPCount = basicLength;
+      if (basicLength) {
+        output.push(delimiter);
+      }
+      while (handledCPCount < inputLength) {
+        let m = maxInt;
+        for (const currentValue of input) {
+          if (currentValue >= n && currentValue < m) {
+            m = currentValue;
+          }
+        }
+        const handledCPCountPlusOne = handledCPCount + 1;
+        if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+          error("overflow");
+        }
+        delta += (m - n) * handledCPCountPlusOne;
+        n = m;
+        for (const currentValue of input) {
+          if (currentValue < n && ++delta > maxInt) {
+            error("overflow");
+          }
+          if (currentValue === n) {
+            let q = delta;
+            for (let k = base; ; k += base) {
+              const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
+              if (q < t) {
+                break;
+              }
+              const qMinusT = q - t;
+              const baseMinusT = base - t;
+              output.push(
+                stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+              );
+              q = floor(qMinusT / baseMinusT);
+            }
+            output.push(stringFromCharCode(digitToBasic(q, 0)));
+            bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);
+            delta = 0;
+            ++handledCPCount;
+          }
+        }
+        ++delta;
+        ++n;
+      }
+      return output.join("");
+    };
+    var toUnicode = function(input) {
+      return mapDomain(input, function(string) {
+        return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string;
+      });
+    };
+    var toASCII = function(input) {
+      return mapDomain(input, function(string) {
+        return regexNonASCII.test(string) ? "xn--" + encode(string) : string;
+      });
+    };
+    var punycode = {
+      /**
+       * A string representing the current Punycode.js version number.
+       * @memberOf punycode
+       * @type String
+       */
+      "version": "2.3.1",
+      /**
+       * An object of methods to convert from JavaScript's internal character
+       * representation (UCS-2) to Unicode code points, and back.
+       * @see 
+       * @memberOf punycode
+       * @type Object
+       */
+      "ucs2": {
+        "decode": ucs2decode,
+        "encode": ucs2encode
+      },
+      "decode": decode,
+      "encode": encode,
+      "toASCII": toASCII,
+      "toUnicode": toUnicode
+    };
+    module2.exports = punycode;
+  }
+});
+
+// scripts/node-portable/node_modules/tr46/lib/regexes.js
+var require_regexes = __commonJS({
+  "scripts/node-portable/node_modules/tr46/lib/regexes.js"(exports2, module2) {
+    "use strict";
+    var combiningMarks = /[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7-\u05C9\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0897-\u089F\u08CA-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u09FE\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B53-\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C04\u0C3C\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0CF3\u0D00-\u0D03\u0D3B\u0D3C\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D81-\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECE\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u180F\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1AF0\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF4\u1CF7-\u1CF9\u1DC0-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA82C\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F\u{101FD}\u{102E0}\u{10376}-\u{1037A}\u{10A01}-\u{10A03}\u{10A05}\u{10A06}\u{10A0C}-\u{10A0F}\u{10A38}-\u{10A3A}\u{10A3F}\u{10AE5}\u{10AE6}\u{10D24}-\u{10D27}\u{10D69}-\u{10D6D}\u{10EAB}\u{10EAC}\u{10ECB}-\u{10ECF}\u{10EF0}-\u{10EFF}\u{10F46}-\u{10F50}\u{10F82}-\u{10F85}\u{11000}-\u{11002}\u{11038}-\u{11046}\u{11070}\u{11073}\u{11074}\u{1107F}-\u{11082}\u{110B0}-\u{110BA}\u{110C2}\u{11100}-\u{11102}\u{11127}-\u{11134}\u{11145}\u{11146}\u{11173}\u{11180}-\u{11182}\u{111B3}-\u{111C0}\u{111C9}-\u{111CC}\u{111CE}\u{111CF}\u{1122C}-\u{11237}\u{1123E}\u{11241}\u{112DF}-\u{112EA}\u{11300}-\u{11303}\u{1133B}\u{1133C}\u{1133E}-\u{11344}\u{11347}\u{11348}\u{1134B}-\u{1134D}\u{11357}\u{11362}\u{11363}\u{11366}-\u{1136C}\u{11370}-\u{11374}\u{113B8}-\u{113C0}\u{113C2}\u{113C5}\u{113C7}-\u{113CA}\u{113CC}-\u{113D0}\u{113D2}\u{113E1}\u{113E2}\u{11435}-\u{11446}\u{1145E}\u{114B0}-\u{114C3}\u{115AF}-\u{115B5}\u{115B8}-\u{115C0}\u{115DC}\u{115DD}\u{11630}-\u{11640}\u{116AB}-\u{116B7}\u{1171D}-\u{1172B}\u{1182C}-\u{1183A}\u{11930}-\u{11935}\u{11937}\u{11938}\u{1193B}-\u{1193E}\u{11940}\u{11942}\u{11943}\u{119D1}-\u{119D7}\u{119DA}-\u{119E0}\u{119E4}\u{11A01}-\u{11A0A}\u{11A33}-\u{11A39}\u{11A3B}-\u{11A3E}\u{11A47}\u{11A51}-\u{11A5B}\u{11A8A}-\u{11A99}\u{11B60}-\u{11B67}\u{11C2F}-\u{11C36}\u{11C38}-\u{11C3F}\u{11C92}-\u{11CA7}\u{11CA9}-\u{11CB6}\u{11D31}-\u{11D36}\u{11D3A}\u{11D3C}\u{11D3D}\u{11D3F}-\u{11D45}\u{11D47}\u{11D8A}-\u{11D8E}\u{11D90}\u{11D91}\u{11D93}-\u{11D97}\u{11DF0}\u{11EF3}-\u{11EF6}\u{11F00}\u{11F01}\u{11F03}\u{11F34}-\u{11F3A}\u{11F3E}-\u{11F42}\u{11F5A}\u{13440}\u{13447}-\u{13455}\u{1611E}-\u{1612F}\u{16AF0}-\u{16AF4}\u{16B30}-\u{16B36}\u{16F4F}\u{16F51}-\u{16F87}\u{16F8F}-\u{16F92}\u{16FE4}\u{16FF0}\u{16FF1}\u{1BC9D}\u{1BC9E}\u{1CF00}-\u{1CF2D}\u{1CF30}-\u{1CF46}\u{1D127}\u{1D128}\u{1D165}-\u{1D169}\u{1D16D}-\u{1D172}\u{1D17B}-\u{1D182}\u{1D185}-\u{1D18B}\u{1D1AA}-\u{1D1AD}\u{1D242}-\u{1D244}\u{1D250}-\u{1D252}\u{1D25B}\u{1D25C}\u{1D25F}\u{1D280}\u{1D281}\u{1DA00}-\u{1DA36}\u{1DA3B}-\u{1DA6C}\u{1DA75}\u{1DA84}\u{1DA9B}-\u{1DA9F}\u{1DAA1}-\u{1DAAF}\u{1E000}-\u{1E006}\u{1E008}-\u{1E018}\u{1E01B}-\u{1E021}\u{1E023}\u{1E024}\u{1E026}-\u{1E02A}\u{1E08F}\u{1E130}-\u{1E136}\u{1E2AE}\u{1E2EC}-\u{1E2EF}\u{1E4EC}-\u{1E4EF}\u{1E5EE}\u{1E5EF}\u{1E6E3}\u{1E6E6}\u{1E6EE}\u{1E6EF}\u{1E6F5}\u{1E8D0}-\u{1E8D6}\u{1E944}-\u{1E94A}\u{E0100}-\u{E01EF}]/u;
+    var combiningClassVirama = /[\u094D\u09CD\u0A4D\u0ACD\u0B4D\u0BCD\u0C4D\u0CCD\u0D3B\u0D3C\u0D4D\u0DCA\u0E3A\u0EBA\u0F84\u1039\u103A\u1714\u1715\u1734\u17D2\u1A60\u1B44\u1BAA\u1BAB\u1BF2\u1BF3\u2D7F\uA806\uA82C\uA8C4\uA953\uA9C0\uAAF6\uABED\u{10A3F}\u{11046}\u{11070}\u{1107F}\u{110B9}\u{11133}\u{11134}\u{111C0}\u{11235}\u{112EA}\u{1134D}\u{113CE}-\u{113D0}\u{11442}\u{114C2}\u{115BF}\u{1163F}\u{116B6}\u{1172B}\u{11839}\u{1193D}\u{1193E}\u{119E0}\u{11A34}\u{11A47}\u{11A99}\u{11C3F}\u{11D44}\u{11D45}\u{11D97}\u{11F41}\u{11F42}\u{1612F}]/u;
+    var validZWNJ = /[\u0620\u0626\u0628\u062A-\u062E\u0633-\u063F\u0641-\u0647\u0649\u064A\u066E\u066F\u0678-\u0687\u069A-\u06BF\u06C1\u06C2\u06CC\u06CE\u06D0\u06D1\u06FA-\u06FC\u06FF\u0712-\u0714\u071A-\u071D\u071F-\u0727\u0729\u072B\u072D\u072E\u074E-\u0758\u075C-\u076A\u076D-\u0770\u0772\u0775-\u0777\u077A-\u077F\u07CA-\u07EA\u0841-\u0845\u0848\u084A-\u0853\u0855\u0860\u0862-\u0865\u0868\u0886\u0889-\u088D\u088F\u08A0-\u08A9\u08AF\u08B0\u08B3-\u08B8\u08BA-\u08C8\u1807\u1820-\u1878\u1887-\u18A8\u18AA\uA840-\uA872\u{10AC0}-\u{10AC4}\u{10ACD}\u{10AD3}-\u{10ADC}\u{10ADE}-\u{10AE0}\u{10AEB}-\u{10AEE}\u{10B80}\u{10B82}\u{10B86}-\u{10B88}\u{10B8A}\u{10B8B}\u{10B8D}\u{10B90}\u{10BAD}\u{10BAE}\u{10D00}-\u{10D21}\u{10D23}\u{10EC3}\u{10EC4}\u{10EC6}\u{10EC7}\u{10ED9}-\u{10EEE}\u{10F30}-\u{10F32}\u{10F34}-\u{10F44}\u{10F51}-\u{10F53}\u{10F70}-\u{10F73}\u{10F76}-\u{10F81}\u{10FB0}\u{10FB2}\u{10FB3}\u{10FB8}\u{10FBB}\u{10FBC}\u{10FBE}\u{10FBF}\u{10FC1}\u{10FC4}\u{10FCA}\u{10FCB}\u{1E900}-\u{1E943}][\xAD\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7-\u05C9\u0610-\u061A\u061C\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u070F\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0897-\u089F\u08CA-\u08E1\u08E3-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962\u0963\u0981\u09BC\u09C1-\u09C4\u09CD\u09E2\u09E3\u09FE\u0A01\u0A02\u0A3C\u0A41\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7\u0AC8\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01\u0B3C\u0B3F\u0B41-\u0B44\u0B4D\u0B53-\u0B56\u0B62\u0B63\u0B82\u0BC0\u0BCD\u0C00\u0C04\u0C3C\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81\u0CBC\u0CBF\u0CC6\u0CCC\u0CCD\u0CE2\u0CE3\u0D00\u0D01\u0D3B\u0D3C\u0D41-\u0D44\u0D4D\u0D62\u0D63\u0D81\u0DCA\u0DD2-\u0DD4\u0DD6\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECE\u0F18\u0F19\u0F35\u0F37\u0F39\u0F71-\u0F7E\u0F80-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039\u103A\u103D\u103E\u1058\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085\u1086\u108D\u109D\u135D-\u135F\u1712-\u1714\u1732\u1733\u1752\u1753\u1772\u1773\u17B4\u17B5\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DD\u180B-\u180D\u180F\u1885\u1886\u18A9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193B\u1A17\u1A18\u1A1B\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1AB0-\u1AF0\u1B00-\u1B03\u1B34\u1B36-\u1B3A\u1B3C\u1B42\u1B6B-\u1B73\u1B80\u1B81\u1BA2-\u1BA5\u1BA8\u1BA9\u1BAB-\u1BAD\u1BE6\u1BE8\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1CF8\u1CF9\u1DC0-\u1DFF\u200B\u200E\u200F\u202A-\u202E\u2060-\u2064\u206A-\u206F\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302D\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA825\uA826\uA82C\uA8C4\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uA9BD\uA9E5\uAA29-\uAA2E\uAA31\uAA32\uAA35\uAA36\uAA43\uAA4C\uAA7C\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEC\uAAED\uAAF6\uABE5\uABE8\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F\uFEFF\uFFF9-\uFFFB\u{101FD}\u{102E0}\u{10376}-\u{1037A}\u{10A01}-\u{10A03}\u{10A05}\u{10A06}\u{10A0C}-\u{10A0F}\u{10A38}-\u{10A3A}\u{10A3F}\u{10AE5}\u{10AE6}\u{10D24}-\u{10D27}\u{10D69}-\u{10D6D}\u{10EAB}\u{10EAC}\u{10ECB}-\u{10ECF}\u{10EF0}-\u{10EFF}\u{10F46}-\u{10F50}\u{10F82}-\u{10F85}\u{11001}\u{11038}-\u{11046}\u{11070}\u{11073}\u{11074}\u{1107F}-\u{11081}\u{110B3}-\u{110B6}\u{110B9}\u{110BA}\u{110C2}\u{11100}-\u{11102}\u{11127}-\u{1112B}\u{1112D}-\u{11134}\u{11173}\u{11180}\u{11181}\u{111B6}-\u{111BE}\u{111C9}-\u{111CC}\u{111CF}\u{1122F}-\u{11231}\u{11234}\u{11236}\u{11237}\u{1123E}\u{11241}\u{112DF}\u{112E3}-\u{112EA}\u{11300}\u{11301}\u{1133B}\u{1133C}\u{11340}\u{11366}-\u{1136C}\u{11370}-\u{11374}\u{113BB}-\u{113C0}\u{113CE}\u{113D0}\u{113D2}\u{113E1}\u{113E2}\u{11438}-\u{1143F}\u{11442}-\u{11444}\u{11446}\u{1145E}\u{114B3}-\u{114B8}\u{114BA}\u{114BF}\u{114C0}\u{114C2}\u{114C3}\u{115B2}-\u{115B5}\u{115BC}\u{115BD}\u{115BF}\u{115C0}\u{115DC}\u{115DD}\u{11633}-\u{1163A}\u{1163D}\u{1163F}\u{11640}\u{116AB}\u{116AD}\u{116B0}-\u{116B5}\u{116B7}\u{1171D}\u{1171F}\u{11722}-\u{11725}\u{11727}-\u{1172B}\u{1182F}-\u{11837}\u{11839}\u{1183A}\u{1193B}\u{1193C}\u{1193E}\u{11943}\u{119D4}-\u{119D7}\u{119DA}\u{119DB}\u{119E0}\u{11A01}-\u{11A0A}\u{11A33}-\u{11A38}\u{11A3B}-\u{11A3E}\u{11A47}\u{11A51}-\u{11A56}\u{11A59}-\u{11A5B}\u{11A8A}-\u{11A96}\u{11A98}\u{11A99}\u{11B60}\u{11B62}-\u{11B64}\u{11B66}\u{11C30}-\u{11C36}\u{11C38}-\u{11C3D}\u{11C3F}\u{11C92}-\u{11CA7}\u{11CAA}-\u{11CB0}\u{11CB2}\u{11CB3}\u{11CB5}\u{11CB6}\u{11D31}-\u{11D36}\u{11D3A}\u{11D3C}\u{11D3D}\u{11D3F}-\u{11D45}\u{11D47}\u{11D90}\u{11D91}\u{11D95}\u{11D97}\u{11DF0}\u{11EF3}\u{11EF4}\u{11F00}\u{11F01}\u{11F36}-\u{11F3A}\u{11F40}\u{11F42}\u{11F5A}\u{13430}-\u{13440}\u{13447}-\u{13455}\u{1611E}-\u{16129}\u{1612D}-\u{1612F}\u{16AF0}-\u{16AF4}\u{16B30}-\u{16B36}\u{16F4F}\u{16F8F}-\u{16F92}\u{16FE4}\u{1BC9D}\u{1BC9E}\u{1BCA0}-\u{1BCA3}\u{1CF00}-\u{1CF2D}\u{1CF30}-\u{1CF46}\u{1D127}\u{1D128}\u{1D167}-\u{1D169}\u{1D173}-\u{1D182}\u{1D185}-\u{1D18B}\u{1D1AA}-\u{1D1AD}\u{1D242}-\u{1D244}\u{1D25B}\u{1D25C}\u{1DA00}-\u{1DA36}\u{1DA3B}-\u{1DA6C}\u{1DA75}\u{1DA84}\u{1DA9B}-\u{1DA9F}\u{1DAA1}-\u{1DAAF}\u{1E000}-\u{1E006}\u{1E008}-\u{1E018}\u{1E01B}-\u{1E021}\u{1E023}\u{1E024}\u{1E026}-\u{1E02A}\u{1E08F}\u{1E130}-\u{1E136}\u{1E2AE}\u{1E2EC}-\u{1E2EF}\u{1E4EC}-\u{1E4EF}\u{1E5EE}\u{1E5EF}\u{1E6E3}\u{1E6E6}\u{1E6EE}\u{1E6EF}\u{1E6F5}\u{1E8D0}-\u{1E8D6}\u{1E944}-\u{1E94B}\u{E0001}\u{E0020}-\u{E007F}\u{E0100}-\u{E01EF}]*\u200C[\xAD\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7-\u05C9\u0610-\u061A\u061C\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u070F\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0897-\u089F\u08CA-\u08E1\u08E3-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962\u0963\u0981\u09BC\u09C1-\u09C4\u09CD\u09E2\u09E3\u09FE\u0A01\u0A02\u0A3C\u0A41\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7\u0AC8\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01\u0B3C\u0B3F\u0B41-\u0B44\u0B4D\u0B53-\u0B56\u0B62\u0B63\u0B82\u0BC0\u0BCD\u0C00\u0C04\u0C3C\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81\u0CBC\u0CBF\u0CC6\u0CCC\u0CCD\u0CE2\u0CE3\u0D00\u0D01\u0D3B\u0D3C\u0D41-\u0D44\u0D4D\u0D62\u0D63\u0D81\u0DCA\u0DD2-\u0DD4\u0DD6\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECE\u0F18\u0F19\u0F35\u0F37\u0F39\u0F71-\u0F7E\u0F80-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039\u103A\u103D\u103E\u1058\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085\u1086\u108D\u109D\u135D-\u135F\u1712-\u1714\u1732\u1733\u1752\u1753\u1772\u1773\u17B4\u17B5\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DD\u180B-\u180D\u180F\u1885\u1886\u18A9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193B\u1A17\u1A18\u1A1B\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1AB0-\u1AF0\u1B00-\u1B03\u1B34\u1B36-\u1B3A\u1B3C\u1B42\u1B6B-\u1B73\u1B80\u1B81\u1BA2-\u1BA5\u1BA8\u1BA9\u1BAB-\u1BAD\u1BE6\u1BE8\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1CF8\u1CF9\u1DC0-\u1DFF\u200B\u200E\u200F\u202A-\u202E\u2060-\u2064\u206A-\u206F\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302D\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA825\uA826\uA82C\uA8C4\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uA9BD\uA9E5\uAA29-\uAA2E\uAA31\uAA32\uAA35\uAA36\uAA43\uAA4C\uAA7C\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEC\uAAED\uAAF6\uABE5\uABE8\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F\uFEFF\uFFF9-\uFFFB\u{101FD}\u{102E0}\u{10376}-\u{1037A}\u{10A01}-\u{10A03}\u{10A05}\u{10A06}\u{10A0C}-\u{10A0F}\u{10A38}-\u{10A3A}\u{10A3F}\u{10AE5}\u{10AE6}\u{10D24}-\u{10D27}\u{10D69}-\u{10D6D}\u{10EAB}\u{10EAC}\u{10ECB}-\u{10ECF}\u{10EF0}-\u{10EFF}\u{10F46}-\u{10F50}\u{10F82}-\u{10F85}\u{11001}\u{11038}-\u{11046}\u{11070}\u{11073}\u{11074}\u{1107F}-\u{11081}\u{110B3}-\u{110B6}\u{110B9}\u{110BA}\u{110C2}\u{11100}-\u{11102}\u{11127}-\u{1112B}\u{1112D}-\u{11134}\u{11173}\u{11180}\u{11181}\u{111B6}-\u{111BE}\u{111C9}-\u{111CC}\u{111CF}\u{1122F}-\u{11231}\u{11234}\u{11236}\u{11237}\u{1123E}\u{11241}\u{112DF}\u{112E3}-\u{112EA}\u{11300}\u{11301}\u{1133B}\u{1133C}\u{11340}\u{11366}-\u{1136C}\u{11370}-\u{11374}\u{113BB}-\u{113C0}\u{113CE}\u{113D0}\u{113D2}\u{113E1}\u{113E2}\u{11438}-\u{1143F}\u{11442}-\u{11444}\u{11446}\u{1145E}\u{114B3}-\u{114B8}\u{114BA}\u{114BF}\u{114C0}\u{114C2}\u{114C3}\u{115B2}-\u{115B5}\u{115BC}\u{115BD}\u{115BF}\u{115C0}\u{115DC}\u{115DD}\u{11633}-\u{1163A}\u{1163D}\u{1163F}\u{11640}\u{116AB}\u{116AD}\u{116B0}-\u{116B5}\u{116B7}\u{1171D}\u{1171F}\u{11722}-\u{11725}\u{11727}-\u{1172B}\u{1182F}-\u{11837}\u{11839}\u{1183A}\u{1193B}\u{1193C}\u{1193E}\u{11943}\u{119D4}-\u{119D7}\u{119DA}\u{119DB}\u{119E0}\u{11A01}-\u{11A0A}\u{11A33}-\u{11A38}\u{11A3B}-\u{11A3E}\u{11A47}\u{11A51}-\u{11A56}\u{11A59}-\u{11A5B}\u{11A8A}-\u{11A96}\u{11A98}\u{11A99}\u{11B60}\u{11B62}-\u{11B64}\u{11B66}\u{11C30}-\u{11C36}\u{11C38}-\u{11C3D}\u{11C3F}\u{11C92}-\u{11CA7}\u{11CAA}-\u{11CB0}\u{11CB2}\u{11CB3}\u{11CB5}\u{11CB6}\u{11D31}-\u{11D36}\u{11D3A}\u{11D3C}\u{11D3D}\u{11D3F}-\u{11D45}\u{11D47}\u{11D90}\u{11D91}\u{11D95}\u{11D97}\u{11DF0}\u{11EF3}\u{11EF4}\u{11F00}\u{11F01}\u{11F36}-\u{11F3A}\u{11F40}\u{11F42}\u{11F5A}\u{13430}-\u{13440}\u{13447}-\u{13455}\u{1611E}-\u{16129}\u{1612D}-\u{1612F}\u{16AF0}-\u{16AF4}\u{16B30}-\u{16B36}\u{16F4F}\u{16F8F}-\u{16F92}\u{16FE4}\u{1BC9D}\u{1BC9E}\u{1BCA0}-\u{1BCA3}\u{1CF00}-\u{1CF2D}\u{1CF30}-\u{1CF46}\u{1D127}\u{1D128}\u{1D167}-\u{1D169}\u{1D173}-\u{1D182}\u{1D185}-\u{1D18B}\u{1D1AA}-\u{1D1AD}\u{1D242}-\u{1D244}\u{1D25B}\u{1D25C}\u{1DA00}-\u{1DA36}\u{1DA3B}-\u{1DA6C}\u{1DA75}\u{1DA84}\u{1DA9B}-\u{1DA9F}\u{1DAA1}-\u{1DAAF}\u{1E000}-\u{1E006}\u{1E008}-\u{1E018}\u{1E01B}-\u{1E021}\u{1E023}\u{1E024}\u{1E026}-\u{1E02A}\u{1E08F}\u{1E130}-\u{1E136}\u{1E2AE}\u{1E2EC}-\u{1E2EF}\u{1E4EC}-\u{1E4EF}\u{1E5EE}\u{1E5EF}\u{1E6E3}\u{1E6E6}\u{1E6EE}\u{1E6EF}\u{1E6F5}\u{1E8D0}-\u{1E8D6}\u{1E944}-\u{1E94B}\u{E0001}\u{E0020}-\u{E007F}\u{E0100}-\u{E01EF}]*[\u0620\u0622-\u063F\u0641-\u064A\u066E\u066F\u0671-\u0673\u0675-\u06D3\u06D5\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u077F\u07CA-\u07EA\u0840-\u0858\u0860\u0862-\u0865\u0867-\u086A\u0870-\u0882\u0886\u0889-\u088F\u08A0-\u08AC\u08AE-\u08C8\u1807\u1820-\u1878\u1887-\u18A8\u18AA\uA840-\uA871\u{10AC0}-\u{10AC5}\u{10AC7}\u{10AC9}\u{10ACA}\u{10ACE}-\u{10AD6}\u{10AD8}-\u{10AE1}\u{10AE4}\u{10AEB}-\u{10AEF}\u{10B80}-\u{10B91}\u{10BA9}-\u{10BAE}\u{10D01}-\u{10D23}\u{10EC2}-\u{10EC4}\u{10EC6}\u{10EC7}\u{10F30}-\u{10F44}\u{10F51}-\u{10F54}\u{10F70}-\u{10F81}\u{10FB0}\u{10FB2}-\u{10FB6}\u{10FB8}-\u{10FBF}\u{10FC1}-\u{10FC4}\u{10FC9}\u{10FCA}\u{1E900}-\u{1E943}]/u;
+    var bidiDomain = /[\u05BE\u05C0\u05C3\u05C6\u05D0-\u05EA\u05EF-\u05F4\u0600-\u0605\u0608\u060B\u060D\u061B-\u064A\u0660-\u0669\u066B-\u066F\u0671-\u06D5\u06DD\u06E5\u06E6\u06EE\u06EF\u06FA-\u070D\u070F\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u07FE-\u0815\u081A\u0824\u0828\u0830-\u083E\u0840-\u0858\u085E\u0860-\u086A\u0870-\u0891\u08A0-\u08C9\u08E2\u200F\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBC2\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFC\uFE70-\uFE74\uFE76-\uFEFC\u{10800}-\u{10805}\u{10808}\u{1080A}-\u{10835}\u{10837}\u{10838}\u{1083C}\u{1083F}-\u{10855}\u{10857}-\u{1089E}\u{108A7}-\u{108AF}\u{108E0}-\u{108F2}\u{108F4}\u{108F5}\u{108FB}-\u{1091B}\u{10920}-\u{10939}\u{1093F}-\u{10959}\u{10980}-\u{109B7}\u{109BC}-\u{109CF}\u{109D2}-\u{10A00}\u{10A10}-\u{10A13}\u{10A15}-\u{10A17}\u{10A19}-\u{10A35}\u{10A40}-\u{10A48}\u{10A50}-\u{10A58}\u{10A60}-\u{10A9F}\u{10AC0}-\u{10AE4}\u{10AEB}-\u{10AF6}\u{10B00}-\u{10B35}\u{10B40}-\u{10B55}\u{10B58}-\u{10B72}\u{10B78}-\u{10B91}\u{10B99}-\u{10B9C}\u{10BA9}-\u{10BAF}\u{10C00}-\u{10C48}\u{10C80}-\u{10CB2}\u{10CC0}-\u{10CF2}\u{10CFA}-\u{10D23}\u{10D30}-\u{10D39}\u{10D40}-\u{10D65}\u{10D6F}-\u{10D85}\u{10D8E}\u{10D8F}\u{10E60}-\u{10E7E}\u{10E80}-\u{10EA9}\u{10EAD}\u{10EB0}\u{10EB1}\u{10EC2}-\u{10EC7}\u{10EC9}\u{10ECA}\u{10ED9}-\u{10EEE}\u{10F00}-\u{10F27}\u{10F30}-\u{10F45}\u{10F51}-\u{10F59}\u{10F70}-\u{10F81}\u{10F86}-\u{10F89}\u{10FB0}-\u{10FCB}\u{10FE0}-\u{10FF6}\u{1E800}-\u{1E8C4}\u{1E8C7}-\u{1E8CF}\u{1E900}-\u{1E943}\u{1E94B}\u{1E950}-\u{1E959}\u{1E95E}\u{1E95F}\u{1EC71}-\u{1ECB4}\u{1ED01}-\u{1ED3D}\u{1EE00}-\u{1EE03}\u{1EE05}-\u{1EE1F}\u{1EE21}\u{1EE22}\u{1EE24}\u{1EE27}\u{1EE29}-\u{1EE32}\u{1EE34}-\u{1EE37}\u{1EE39}\u{1EE3B}\u{1EE42}\u{1EE47}\u{1EE49}\u{1EE4B}\u{1EE4D}-\u{1EE4F}\u{1EE51}\u{1EE52}\u{1EE54}\u{1EE57}\u{1EE59}\u{1EE5B}\u{1EE5D}\u{1EE5F}\u{1EE61}\u{1EE62}\u{1EE64}\u{1EE67}-\u{1EE6A}\u{1EE6C}-\u{1EE72}\u{1EE74}-\u{1EE77}\u{1EE79}-\u{1EE7C}\u{1EE7E}\u{1EE80}-\u{1EE89}\u{1EE8B}-\u{1EE9B}\u{1EEA1}-\u{1EEA3}\u{1EEA5}-\u{1EEA9}\u{1EEAB}-\u{1EEBB}]/u;
+    var bidiS1LTR = /[A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02B8\u02BB-\u02C1\u02D0\u02D1\u02E0-\u02E4\u02EE\u0370-\u0373\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0482\u048A-\u052F\u0531-\u0556\u0558-\u0589\u058B\u058C\u0903-\u0939\u093B\u093D-\u0940\u0949-\u094C\u094E-\u0950\u0958-\u0961\u0964-\u0980\u0982\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD-\u09C0\u09C7\u09C8\u09CB\u09CC\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09FA\u09FC\u09FD\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A40\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A76\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD-\u0AC0\u0AC9\u0ACB\u0ACC\u0AD0\u0AE0\u0AE1\u0AE6-\u0AF0\u0AF9\u0B02\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B3E\u0B40\u0B47\u0B48\u0B4B\u0B4C\u0B57\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE\u0BBF\u0BC1\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0BD0\u0BD7\u0BE6-\u0BF2\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C41-\u0C44\u0C58-\u0C5A\u0C5C\u0C5D\u0C60\u0C61\u0C66-\u0C6F\u0C77\u0C7F\u0C80\u0C82-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD-\u0CC4\u0CC6-\u0CC8\u0CCA\u0CCB\u0CD5\u0CD6\u0CDC-\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1-\u0CF3\u0D02-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D40\u0D46-\u0D48\u0D4A-\u0D4C\u0D4E\u0D4F\u0D54-\u0D61\u0D66-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCF-\u0DD1\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2-\u0DF4\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E4F-\u0E5B\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00-\u0F17\u0F1A-\u0F34\u0F36\u0F38\u0F3E-\u0F47\u0F49-\u0F6C\u0F7F\u0F85\u0F88-\u0F8C\u0FBE-\u0FC5\u0FC7-\u0FCC\u0FCE-\u0FDA\u1000-\u102C\u1031\u1038\u103B\u103C\u103F-\u1057\u105A-\u105D\u1061-\u1070\u1075-\u1081\u1083\u1084\u1087-\u108C\u108E-\u109C\u109E-\u10C5\u10C7\u10CD\u10D0-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1360-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u167F\u1681-\u169A\u16A0-\u16F8\u1700-\u1711\u1715\u171F-\u1731\u1734-\u1736\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17B6\u17BE-\u17C5\u17C7\u17C8\u17D4-\u17DA\u17DC\u17E0-\u17E9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1923-\u1926\u1929-\u192B\u1930\u1931\u1933-\u1938\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A19\u1A1A\u1A1E-\u1A55\u1A57\u1A61\u1A63\u1A64\u1A6D-\u1A72\u1A80-\u1A89\u1A90-\u1A99\u1AA0-\u1AAD\u1B04-\u1B33\u1B35\u1B3A-\u1B4C\u1B4E-\u1B6A\u1B74-\u1B7F\u1B82-\u1BA1\u1BA6\u1BA7\u1BAA\u1BAE-\u1BE5\u1BE7\u1BEA-\u1BEC\u1BEE\u1BF2\u1BF3\u1BFC-\u1C2B\u1C34\u1C35\u1C3B-\u1C49\u1C4D-\u1C8A\u1C90-\u1CBA\u1CBD-\u1CC7\u1CD3\u1CE1\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5-\u1CF7\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200E\u2071\u207F\u2090-\u209F\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u214F\u2160-\u2188\u2336-\u237A\u2395\u249C-\u24E9\u26AC\u2800-\u28FF\u2C00-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D70\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u302E\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3190-\u31BF\u31F0-\u321C\u3220-\u324F\u3260-\u327B\u327F-\u32B0\u32C0-\u32CB\u32D0-\u3376\u337B-\u33DD\u33E0-\u33FE\u3400-\u4DBF\u4E00-\uA48C\uA4D0-\uA60C\uA610-\uA62B\uA640-\uA66E\uA680-\uA69D\uA6A0-\uA6EF\uA6F2-\uA6F7\uA722-\uA787\uA789-\uA7DD\uA7E2\uA7F1-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA824\uA827\uA830-\uA837\uA840-\uA873\uA880-\uA8C3\uA8CE-\uA8D9\uA8F2-\uA8FE\uA900-\uA925\uA92E-\uA946\uA952\uA953\uA95F-\uA97C\uA983-\uA9B2\uA9B4\uA9B5\uA9BA\uA9BB\uA9BE-\uA9CD\uA9CF-\uA9D9\uA9DE-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA2F\uAA30\uAA33\uAA34\uAA40-\uAA42\uAA44-\uAA4B\uAA4D\uAA50-\uAA59\uAA5C-\uAA7B\uAA7D-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAAEB\uAAEE-\uAAF5\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB69\uAB6C\uAB6D\uAB70-\uABE4\uABE6\uABE7\uABE9-\uABEC\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uD800-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC\u{10000}-\u{1000B}\u{1000D}-\u{10026}\u{10028}-\u{1003A}\u{1003C}\u{1003D}\u{1003F}-\u{1004D}\u{10050}-\u{1005D}\u{10080}-\u{100FA}\u{10100}\u{10102}\u{10107}-\u{10133}\u{10137}-\u{1013F}\u{1018D}\u{1018E}\u{101D0}-\u{101FC}\u{10280}-\u{1029C}\u{102A0}-\u{102D0}\u{10300}-\u{10323}\u{1032D}-\u{1034A}\u{10350}-\u{10375}\u{10380}-\u{1039D}\u{1039F}-\u{103C3}\u{103C8}-\u{103D5}\u{10400}-\u{1049D}\u{104A0}-\u{104A9}\u{104B0}-\u{104D3}\u{104D8}-\u{104FB}\u{10500}-\u{10527}\u{10530}-\u{10563}\u{1056F}-\u{1057A}\u{1057C}-\u{1058A}\u{1058C}-\u{10592}\u{10594}\u{10595}\u{10597}-\u{105A1}\u{105A3}-\u{105B1}\u{105B3}-\u{105B9}\u{105BB}\u{105BC}\u{105C0}-\u{105F3}\u{10600}-\u{10736}\u{10740}-\u{10755}\u{10760}-\u{10767}\u{10780}-\u{10785}\u{10787}-\u{107B0}\u{107B2}-\u{107BF}\u{11000}\u{11002}-\u{11037}\u{11047}-\u{1104D}\u{11066}-\u{1106F}\u{11071}\u{11072}\u{11075}\u{11082}-\u{110B2}\u{110B7}\u{110B8}\u{110BB}-\u{110C1}\u{110CD}\u{110D0}-\u{110E8}\u{110F0}-\u{110F9}\u{11103}-\u{11126}\u{1112C}\u{11136}-\u{11147}\u{11150}-\u{11172}\u{11174}-\u{11176}\u{11182}-\u{111B5}\u{111BF}-\u{111C8}\u{111CD}\u{111CE}\u{111D0}-\u{111DF}\u{111E1}-\u{111F4}\u{11200}-\u{11211}\u{11213}-\u{1122E}\u{11232}\u{11233}\u{11235}\u{11238}-\u{1123D}\u{1123F}\u{11240}\u{11280}-\u{11286}\u{11288}\u{1128A}-\u{1128D}\u{1128F}-\u{1129D}\u{1129F}-\u{112A9}\u{112B0}-\u{112DE}\u{112E0}-\u{112E2}\u{112F0}-\u{112F9}\u{11302}\u{11303}\u{11305}-\u{1130C}\u{1130F}\u{11310}\u{11313}-\u{11328}\u{1132A}-\u{11330}\u{11332}\u{11333}\u{11335}-\u{11339}\u{1133D}-\u{1133F}\u{11341}-\u{11344}\u{11347}\u{11348}\u{1134B}-\u{1134D}\u{11350}\u{11357}\u{1135D}-\u{11363}\u{11380}-\u{11389}\u{1138B}\u{1138E}\u{11390}-\u{113B5}\u{113B7}-\u{113BA}\u{113C2}\u{113C5}\u{113C7}-\u{113CA}\u{113CC}\u{113CD}\u{113CF}\u{113D1}\u{113D3}-\u{113D5}\u{113D7}\u{113D8}\u{11400}-\u{11437}\u{11440}\u{11441}\u{11445}\u{11447}-\u{1145B}\u{1145D}\u{1145F}-\u{11461}\u{11480}-\u{114B2}\u{114B9}\u{114BB}-\u{114BE}\u{114C1}\u{114C4}-\u{114C7}\u{114D0}-\u{114D9}\u{11580}-\u{115B1}\u{115B8}-\u{115BB}\u{115BE}\u{115C1}-\u{115DB}\u{11600}-\u{11632}\u{1163B}\u{1163C}\u{1163E}\u{11641}-\u{11644}\u{11650}-\u{11659}\u{11680}-\u{116AA}\u{116AC}\u{116AE}\u{116AF}\u{116B6}\u{116B8}\u{116B9}\u{116C0}-\u{116C9}\u{116D0}-\u{116E3}\u{11700}-\u{1171A}\u{1171E}\u{11720}\u{11721}\u{11726}\u{11730}-\u{11746}\u{11800}-\u{1182E}\u{11838}\u{1183B}\u{118A0}-\u{118F2}\u{118FF}-\u{11906}\u{11909}\u{1190C}-\u{11913}\u{11915}\u{11916}\u{11918}-\u{11935}\u{11937}\u{11938}\u{1193D}\u{1193F}-\u{11942}\u{11944}-\u{11946}\u{11950}-\u{11959}\u{119A0}-\u{119A7}\u{119AA}-\u{119D3}\u{119DC}-\u{119DF}\u{119E1}-\u{119E4}\u{11A00}\u{11A07}\u{11A08}\u{11A0B}-\u{11A32}\u{11A39}\u{11A3A}\u{11A3F}-\u{11A46}\u{11A50}\u{11A57}\u{11A58}\u{11A5C}-\u{11A89}\u{11A97}\u{11A9A}-\u{11AA2}\u{11AB0}-\u{11AF8}\u{11B00}-\u{11B0A}\u{11B61}\u{11B65}\u{11B67}\u{11BC0}-\u{11BE1}\u{11BF0}-\u{11BF9}\u{11C00}-\u{11C08}\u{11C0A}-\u{11C2F}\u{11C3E}-\u{11C45}\u{11C50}-\u{11C6C}\u{11C70}-\u{11C8F}\u{11CA9}\u{11CB1}\u{11CB4}\u{11D00}-\u{11D06}\u{11D08}\u{11D09}\u{11D0B}-\u{11D30}\u{11D46}\u{11D50}-\u{11D59}\u{11D60}-\u{11D65}\u{11D67}\u{11D68}\u{11D6A}-\u{11D8E}\u{11D93}\u{11D94}\u{11D96}\u{11D98}\u{11DA0}-\u{11DA9}\u{11DB0}-\u{11DDB}\u{11DE0}-\u{11DE9}\u{11DF1}\u{11EE0}-\u{11EF2}\u{11EF5}-\u{11EF8}\u{11F02}-\u{11F10}\u{11F12}-\u{11F35}\u{11F3E}\u{11F3F}\u{11F41}\u{11F43}-\u{11F59}\u{11FB0}\u{11FC0}-\u{11FD4}\u{11FFF}-\u{12399}\u{12400}-\u{12543}\u{12550}-\u{12686}\u{12F90}-\u{12FF2}\u{13000}-\u{1343F}\u{13441}-\u{13446}\u{13460}-\u{143FA}\u{14400}-\u{14646}\u{16100}-\u{1611D}\u{1612A}-\u{1612C}\u{16130}-\u{16139}\u{16800}-\u{16A38}\u{16A40}-\u{16A5E}\u{16A60}-\u{16A69}\u{16A6E}-\u{16ABE}\u{16AC0}-\u{16AC9}\u{16AD0}-\u{16AED}\u{16AF5}\u{16B00}-\u{16B2F}\u{16B37}-\u{16B45}\u{16B50}-\u{16B59}\u{16B5B}-\u{16B61}\u{16B63}-\u{16B77}\u{16B7D}-\u{16B8F}\u{16D40}-\u{16D79}\u{16E40}-\u{16E9A}\u{16EA0}-\u{16EB8}\u{16EBB}-\u{16ED3}\u{16F00}-\u{16F4A}\u{16F50}-\u{16F87}\u{16F93}-\u{16F9F}\u{16FE0}\u{16FE1}\u{16FE3}\u{16FF0}-\u{16FF6}\u{17000}-\u{18CDA}\u{18CFF}-\u{18D20}\u{18D80}-\u{18DF2}\u{18E00}-\u{19191}\u{191A0}-\u{191D2}\u{1AFF0}-\u{1AFF3}\u{1AFF5}-\u{1AFFB}\u{1AFFD}\u{1AFFE}\u{1B000}-\u{1B128}\u{1B132}\u{1B150}-\u{1B152}\u{1B155}\u{1B164}-\u{1B168}\u{1B170}-\u{1B2FB}\u{1BC00}-\u{1BC6A}\u{1BC70}-\u{1BC7C}\u{1BC80}-\u{1BC88}\u{1BC90}-\u{1BC99}\u{1BC9C}\u{1BC9F}\u{1CCD6}-\u{1CCEF}\u{1CF50}-\u{1CFC3}\u{1D000}-\u{1D0F5}\u{1D100}-\u{1D126}\u{1D129}-\u{1D166}\u{1D16A}-\u{1D172}\u{1D183}\u{1D184}\u{1D18C}-\u{1D1A9}\u{1D1AE}-\u{1D1E8}\u{1D1EB}-\u{1D1FF}\u{1D250}-\u{1D25A}\u{1D25D}-\u{1D281}\u{1D2C0}-\u{1D2D3}\u{1D2E0}-\u{1D2F3}\u{1D360}-\u{1D378}\u{1D400}-\u{1D454}\u{1D456}-\u{1D49C}\u{1D49E}\u{1D49F}\u{1D4A2}\u{1D4A5}\u{1D4A6}\u{1D4A9}-\u{1D4AC}\u{1D4AE}-\u{1D4B9}\u{1D4BB}\u{1D4BD}-\u{1D4C3}\u{1D4C5}-\u{1D505}\u{1D507}-\u{1D50A}\u{1D50D}-\u{1D514}\u{1D516}-\u{1D51C}\u{1D51E}-\u{1D539}\u{1D53B}-\u{1D53E}\u{1D540}-\u{1D544}\u{1D546}\u{1D54A}-\u{1D550}\u{1D552}-\u{1D6A6}\u{1D6A8}-\u{1D6C0}\u{1D6C2}-\u{1D6DA}\u{1D6DC}-\u{1D6FA}\u{1D6FC}-\u{1D714}\u{1D716}-\u{1D734}\u{1D736}-\u{1D74E}\u{1D750}-\u{1D76E}\u{1D770}-\u{1D788}\u{1D78A}-\u{1D7A8}\u{1D7AA}-\u{1D7C2}\u{1D7C4}-\u{1D7CB}\u{1D800}-\u{1D9FF}\u{1DA37}-\u{1DA3A}\u{1DA6D}-\u{1DA74}\u{1DA76}-\u{1DA83}\u{1DA85}-\u{1DA8B}\u{1DF00}-\u{1DF81}\u{1DF90}-\u{1DF96}\u{1DFCD}-\u{1DFFF}\u{1E030}-\u{1E06D}\u{1E100}-\u{1E12C}\u{1E137}-\u{1E13D}\u{1E140}-\u{1E149}\u{1E14E}\u{1E14F}\u{1E290}-\u{1E2AD}\u{1E2C0}-\u{1E2EB}\u{1E2F0}-\u{1E2F9}\u{1E4D0}-\u{1E4EB}\u{1E4F0}-\u{1E4F9}\u{1E5D0}-\u{1E5ED}\u{1E5F0}-\u{1E5FA}\u{1E5FF}\u{1E6C0}-\u{1E6DE}\u{1E6E0}-\u{1E6E2}\u{1E6E4}\u{1E6E5}\u{1E6E7}-\u{1E6ED}\u{1E6F0}-\u{1E6F4}\u{1E6FE}\u{1E6FF}\u{1E7E0}-\u{1E7E6}\u{1E7E8}-\u{1E7EB}\u{1E7ED}\u{1E7EE}\u{1E7F0}-\u{1E7FE}\u{1F110}-\u{1F12E}\u{1F130}-\u{1F169}\u{1F170}-\u{1F1AC}\u{1F1AE}\u{1F1E6}-\u{1F202}\u{1F210}-\u{1F23B}\u{1F240}-\u{1F248}\u{1F250}\u{1F251}\u{1F7DA}\u{20000}-\u{2A6DF}\u{2A700}-\u{2B81E}\u{2B820}-\u{2CEAD}\u{2CEB0}-\u{2EBE0}\u{2EBF0}-\u{2EE5D}\u{2F800}-\u{2FA1D}\u{30000}-\u{3134A}\u{31350}-\u{33479}\u{3D000}-\u{3FC3F}\u{F0000}-\u{FFFFD}\u{100000}-\u{10FFFD}]/u;
+    var bidiS1RTL = /[\u05BE\u05C0\u05C3\u05C6\u05D0-\u05EA\u05EF-\u05F4\u0608\u060B\u060D\u061B-\u064A\u066D-\u066F\u0671-\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u070D\u070F\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u07FE-\u0815\u081A\u0824\u0828\u0830-\u083E\u0840-\u0858\u085E\u0860-\u086A\u0870-\u088F\u08A0-\u08C9\u200F\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBC2\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFC\uFE70-\uFE74\uFE76-\uFEFC\u{10800}-\u{10805}\u{10808}\u{1080A}-\u{10835}\u{10837}\u{10838}\u{1083C}\u{1083F}-\u{10855}\u{10857}-\u{1089E}\u{108A7}-\u{108AF}\u{108E0}-\u{108F2}\u{108F4}\u{108F5}\u{108FB}-\u{1091B}\u{10920}-\u{10939}\u{1093F}-\u{10959}\u{10980}-\u{109B7}\u{109BC}-\u{109CF}\u{109D2}-\u{10A00}\u{10A10}-\u{10A13}\u{10A15}-\u{10A17}\u{10A19}-\u{10A35}\u{10A40}-\u{10A48}\u{10A50}-\u{10A58}\u{10A60}-\u{10A9F}\u{10AC0}-\u{10AE4}\u{10AEB}-\u{10AF6}\u{10B00}-\u{10B35}\u{10B40}-\u{10B55}\u{10B58}-\u{10B72}\u{10B78}-\u{10B91}\u{10B99}-\u{10B9C}\u{10BA9}-\u{10BAF}\u{10C00}-\u{10C48}\u{10C80}-\u{10CB2}\u{10CC0}-\u{10CF2}\u{10CFA}-\u{10D23}\u{10D4A}-\u{10D65}\u{10D6F}-\u{10D85}\u{10D8E}\u{10D8F}\u{10E80}-\u{10EA9}\u{10EAD}\u{10EB0}\u{10EB1}\u{10EC2}-\u{10EC7}\u{10EC9}\u{10ECA}\u{10ED9}-\u{10EEE}\u{10F00}-\u{10F27}\u{10F30}-\u{10F45}\u{10F51}-\u{10F59}\u{10F70}-\u{10F81}\u{10F86}-\u{10F89}\u{10FB0}-\u{10FCB}\u{10FE0}-\u{10FF6}\u{1E800}-\u{1E8C4}\u{1E8C7}-\u{1E8CF}\u{1E900}-\u{1E943}\u{1E94B}\u{1E950}-\u{1E959}\u{1E95E}\u{1E95F}\u{1EC71}-\u{1ECB4}\u{1ED01}-\u{1ED3D}\u{1EE00}-\u{1EE03}\u{1EE05}-\u{1EE1F}\u{1EE21}\u{1EE22}\u{1EE24}\u{1EE27}\u{1EE29}-\u{1EE32}\u{1EE34}-\u{1EE37}\u{1EE39}\u{1EE3B}\u{1EE42}\u{1EE47}\u{1EE49}\u{1EE4B}\u{1EE4D}-\u{1EE4F}\u{1EE51}\u{1EE52}\u{1EE54}\u{1EE57}\u{1EE59}\u{1EE5B}\u{1EE5D}\u{1EE5F}\u{1EE61}\u{1EE62}\u{1EE64}\u{1EE67}-\u{1EE6A}\u{1EE6C}-\u{1EE72}\u{1EE74}-\u{1EE77}\u{1EE79}-\u{1EE7C}\u{1EE7E}\u{1EE80}-\u{1EE89}\u{1EE8B}-\u{1EE9B}\u{1EEA1}-\u{1EEA3}\u{1EEA5}-\u{1EEA9}\u{1EEAB}-\u{1EEBB}]/u;
+    var bidiS2 = /^[\0-\x08\x0E-\x1B!-@\[-`\{-\x84\x86-\xA9\xAB-\xB4\xB6-\xB9\xBB-\xBF\xD7\xF7\u02B9\u02BA\u02C2-\u02CF\u02D2-\u02DF\u02E5-\u02ED\u02EF-\u036F\u0374\u0375\u037E\u0384\u0385\u0387\u03F6\u0483-\u0489\u058A\u058D-\u058F\u0591-\u05C9\u05D0-\u05EA\u05EF-\u05F4\u0600-\u070D\u070F-\u074A\u074D-\u07B1\u07C0-\u07FA\u07FD-\u082D\u0830-\u083E\u0840-\u085B\u085E\u0860-\u086A\u0870-\u0891\u0897-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962\u0963\u0981\u09BC\u09C1-\u09C4\u09CD\u09E2\u09E3\u09F2\u09F3\u09FB\u09FE\u0A01\u0A02\u0A3C\u0A41\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7\u0AC8\u0ACD\u0AE2\u0AE3\u0AF1\u0AFA-\u0AFF\u0B01\u0B3C\u0B3F\u0B41-\u0B44\u0B4D\u0B53-\u0B56\u0B62\u0B63\u0B82\u0BC0\u0BCD\u0BF3-\u0BFA\u0C00\u0C04\u0C3C\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C78-\u0C7E\u0C81\u0CBC\u0CCC\u0CCD\u0CE2\u0CE3\u0D00\u0D01\u0D3B\u0D3C\u0D41-\u0D44\u0D4D\u0D62\u0D63\u0D81\u0DCA\u0DD2-\u0DD4\u0DD6\u0E31\u0E34-\u0E3A\u0E3F\u0E47-\u0E4E\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECE\u0F18\u0F19\u0F35\u0F37\u0F39-\u0F3D\u0F71-\u0F7E\u0F80-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039\u103A\u103D\u103E\u1058\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085\u1086\u108D\u109D\u135D-\u135F\u1390-\u1399\u1400\u169B\u169C\u1712-\u1714\u1732\u1733\u1752\u1753\u1772\u1773\u17B4\u17B5\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DB\u17DD\u17F0-\u17F9\u1800-\u180F\u1885\u1886\u18A9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193B\u1940\u1944\u1945\u19DE-\u19FF\u1A17\u1A18\u1A1B\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1AB0-\u1AF0\u1B00-\u1B03\u1B34\u1B36-\u1B39\u1B6B-\u1B73\u1B80\u1B81\u1BA2-\u1BA5\u1BA8\u1BA9\u1BAB-\u1BAD\u1BE6\u1BE8\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1CF8\u1CF9\u1DC0-\u1DFF\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u200B-\u200D\u200F-\u2027\u202F-\u205E\u2060-\u2064\u206A-\u2070\u2074-\u207E\u2080-\u208F\u20A0-\u20C4\u20D0-\u20F0\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u2140-\u2144\u214A-\u214D\u2150-\u215F\u2189-\u218B\u2190-\u2335\u237B-\u2394\u2396-\u2429\u2440-\u244A\u2460-\u249B\u24EA-\u26AB\u26AD-\u27FF\u2900-\u2B73\u2B76-\u2BFF\u2CE5-\u2CEA\u2CEF-\u2CF1\u2CF9-\u2CFF\u2D7F\u2DE0-\u2E5D\u2E60-\u2E63\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFF\u3001-\u3004\u3008-\u3020\u302A-\u302D\u3030\u3036\u3037\u303D-\u303F\u3099-\u309C\u30A0\u30FB\u31C0-\u31E5\u31EF\u321D\u321E\u3250-\u325F\u327C-\u327E\u32B1-\u32BF\u32CC-\u32CF\u3377-\u337A\u33DE\u33DF\u33FF\u4DC0-\u4DFF\uA490-\uA4C6\uA60D-\uA60F\uA66F-\uA67F\uA69E\uA69F\uA6F0\uA6F1\uA700-\uA721\uA788\uA802\uA806\uA80B\uA825\uA826\uA828-\uA82C\uA838\uA839\uA874-\uA877\uA8C4\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uA9BD\uA9E5\uAA29-\uAA2E\uAA31\uAA32\uAA35\uAA36\uAA43\uAA4C\uAA7C\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEC\uAAED\uAAF6\uAB6A\uAB6B\uABE5\uABE8\uABED\uFB1D-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFDCF\uFDF0-\uFE19\uFE20-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFE70-\uFE74\uFE76-\uFEFC\uFEFF\uFF01-\uFF20\uFF3B-\uFF40\uFF5B-\uFF65\uFFE0-\uFFE6\uFFE8-\uFFEE\uFFF9-\uFFFD\u{10101}\u{10140}-\u{1018C}\u{10190}-\u{1019C}\u{101A0}\u{101FD}\u{102E0}-\u{102FB}\u{10376}-\u{1037A}\u{10800}-\u{10805}\u{10808}\u{1080A}-\u{10835}\u{10837}\u{10838}\u{1083C}\u{1083F}-\u{10855}\u{10857}-\u{1089E}\u{108A7}-\u{108AF}\u{108E0}-\u{108F2}\u{108F4}\u{108F5}\u{108FB}-\u{1091B}\u{1091F}-\u{10939}\u{1093F}-\u{10959}\u{10980}-\u{109B7}\u{109BC}-\u{109CF}\u{109D2}-\u{10A03}\u{10A05}\u{10A06}\u{10A0C}-\u{10A13}\u{10A15}-\u{10A17}\u{10A19}-\u{10A35}\u{10A38}-\u{10A3A}\u{10A3F}-\u{10A48}\u{10A50}-\u{10A58}\u{10A60}-\u{10A9F}\u{10AC0}-\u{10AE6}\u{10AEB}-\u{10AF6}\u{10B00}-\u{10B35}\u{10B39}-\u{10B55}\u{10B58}-\u{10B72}\u{10B78}-\u{10B91}\u{10B99}-\u{10B9C}\u{10BA9}-\u{10BAF}\u{10C00}-\u{10C48}\u{10C80}-\u{10CB2}\u{10CC0}-\u{10CF2}\u{10CFA}-\u{10D27}\u{10D30}-\u{10D39}\u{10D40}-\u{10D65}\u{10D69}-\u{10D85}\u{10D8E}\u{10D8F}\u{10E60}-\u{10E7E}\u{10E80}-\u{10EA9}\u{10EAB}-\u{10EAD}\u{10EB0}\u{10EB1}\u{10EC2}-\u{10EC7}\u{10EC9}-\u{10EEE}\u{10EF0}-\u{10F27}\u{10F30}-\u{10F59}\u{10F70}-\u{10F89}\u{10FB0}-\u{10FCB}\u{10FE0}-\u{10FF6}\u{11001}\u{11038}-\u{11046}\u{11052}-\u{11065}\u{11070}\u{11073}\u{11074}\u{1107F}-\u{11081}\u{110B3}-\u{110B6}\u{110B9}\u{110BA}\u{110C2}\u{11100}-\u{11102}\u{11127}-\u{1112B}\u{1112D}-\u{11134}\u{11173}\u{11180}\u{11181}\u{111B6}-\u{111BE}\u{111C9}-\u{111CC}\u{111CF}\u{1122F}-\u{11231}\u{11234}\u{11236}\u{11237}\u{1123E}\u{11241}\u{112DF}\u{112E3}-\u{112EA}\u{11300}\u{11301}\u{1133B}\u{1133C}\u{11340}\u{11366}-\u{1136C}\u{11370}-\u{11374}\u{113BB}-\u{113C0}\u{113CE}\u{113D0}\u{113D2}\u{113E1}\u{113E2}\u{11438}-\u{1143F}\u{11442}-\u{11444}\u{11446}\u{1145E}\u{114B3}-\u{114B8}\u{114BA}\u{114BF}\u{114C0}\u{114C2}\u{114C3}\u{115B2}-\u{115B5}\u{115BC}\u{115BD}\u{115BF}\u{115C0}\u{115DC}\u{115DD}\u{11633}-\u{1163A}\u{1163D}\u{1163F}\u{11640}\u{11660}-\u{1166C}\u{116AB}\u{116AD}\u{116B0}-\u{116B5}\u{116B7}\u{1171D}\u{1171F}\u{11722}-\u{11725}\u{11727}-\u{1172B}\u{1182F}-\u{11837}\u{11839}\u{1183A}\u{1193B}\u{1193C}\u{1193E}\u{11943}\u{119D4}-\u{119D7}\u{119DA}\u{119DB}\u{119E0}\u{11A01}-\u{11A06}\u{11A09}\u{11A0A}\u{11A33}-\u{11A38}\u{11A3B}-\u{11A3E}\u{11A47}\u{11A51}-\u{11A56}\u{11A59}-\u{11A5B}\u{11A8A}-\u{11A96}\u{11A98}\u{11A99}\u{11B60}\u{11B62}-\u{11B64}\u{11B66}\u{11C30}-\u{11C36}\u{11C38}-\u{11C3D}\u{11C92}-\u{11CA7}\u{11CAA}-\u{11CB0}\u{11CB2}\u{11CB3}\u{11CB5}\u{11CB6}\u{11D31}-\u{11D36}\u{11D3A}\u{11D3C}\u{11D3D}\u{11D3F}-\u{11D45}\u{11D47}\u{11D90}\u{11D91}\u{11D95}\u{11D97}\u{11DF0}\u{11EF3}\u{11EF4}\u{11F00}\u{11F01}\u{11F36}-\u{11F3A}\u{11F40}\u{11F42}\u{11F5A}\u{11FD5}-\u{11FF1}\u{13440}\u{13447}-\u{13455}\u{1611E}-\u{16129}\u{1612D}-\u{1612F}\u{16AF0}-\u{16AF4}\u{16B30}-\u{16B36}\u{16F4F}\u{16F8F}-\u{16F92}\u{16FE2}\u{16FE4}\u{1BC9D}\u{1BC9E}\u{1BCA0}-\u{1BCA3}\u{1CC00}-\u{1CCD5}\u{1CCF0}-\u{1CCFC}\u{1CD00}-\u{1CEB3}\u{1CEBA}-\u{1CED0}\u{1CED2}-\u{1CED4}\u{1CEDD}-\u{1CEFD}\u{1CF00}-\u{1CF2D}\u{1CF30}-\u{1CF46}\u{1D127}\u{1D128}\u{1D167}-\u{1D169}\u{1D173}-\u{1D182}\u{1D185}-\u{1D18B}\u{1D1AA}-\u{1D1AD}\u{1D1E9}\u{1D1EA}\u{1D200}-\u{1D245}\u{1D25B}\u{1D25C}\u{1D300}-\u{1D356}\u{1D6C1}\u{1D6DB}\u{1D6FB}\u{1D715}\u{1D735}\u{1D74F}\u{1D76F}\u{1D789}\u{1D7A9}\u{1D7C3}\u{1D7CE}-\u{1D7FF}\u{1DA00}-\u{1DA36}\u{1DA3B}-\u{1DA6C}\u{1DA75}\u{1DA84}\u{1DA9B}-\u{1DA9F}\u{1DAA1}-\u{1DAAF}\u{1DB00}-\u{1DB1C}\u{1E000}-\u{1E006}\u{1E008}-\u{1E018}\u{1E01B}-\u{1E021}\u{1E023}\u{1E024}\u{1E026}-\u{1E02A}\u{1E08F}\u{1E130}-\u{1E136}\u{1E2AE}\u{1E2EC}-\u{1E2EF}\u{1E2FF}\u{1E4EC}-\u{1E4EF}\u{1E5EE}\u{1E5EF}\u{1E6E3}\u{1E6E6}\u{1E6EE}\u{1E6EF}\u{1E6F5}\u{1E800}-\u{1E8C4}\u{1E8C7}-\u{1E8D6}\u{1E900}-\u{1E94B}\u{1E950}-\u{1E959}\u{1E95E}\u{1E95F}\u{1EC71}-\u{1ECB4}\u{1ED01}-\u{1ED3D}\u{1EE00}-\u{1EE03}\u{1EE05}-\u{1EE1F}\u{1EE21}\u{1EE22}\u{1EE24}\u{1EE27}\u{1EE29}-\u{1EE32}\u{1EE34}-\u{1EE37}\u{1EE39}\u{1EE3B}\u{1EE42}\u{1EE47}\u{1EE49}\u{1EE4B}\u{1EE4D}-\u{1EE4F}\u{1EE51}\u{1EE52}\u{1EE54}\u{1EE57}\u{1EE59}\u{1EE5B}\u{1EE5D}\u{1EE5F}\u{1EE61}\u{1EE62}\u{1EE64}\u{1EE67}-\u{1EE6A}\u{1EE6C}-\u{1EE72}\u{1EE74}-\u{1EE77}\u{1EE79}-\u{1EE7C}\u{1EE7E}\u{1EE80}-\u{1EE89}\u{1EE8B}-\u{1EE9B}\u{1EEA1}-\u{1EEA3}\u{1EEA5}-\u{1EEA9}\u{1EEAB}-\u{1EEBB}\u{1EEF0}\u{1EEF1}\u{1F000}-\u{1F02B}\u{1F030}-\u{1F093}\u{1F0A0}-\u{1F0AE}\u{1F0B1}-\u{1F0BF}\u{1F0C1}-\u{1F0CF}\u{1F0D1}-\u{1F0F5}\u{1F100}-\u{1F10F}\u{1F12F}\u{1F16A}-\u{1F16F}\u{1F1AD}\u{1F260}-\u{1F265}\u{1F300}-\u{1F6D9}\u{1F6DC}-\u{1F6EC}\u{1F6F0}-\u{1F6FC}\u{1F700}-\u{1F7D9}\u{1F7DB}\u{1F7E0}-\u{1F7EB}\u{1F7F0}-\u{1F80B}\u{1F810}-\u{1F847}\u{1F850}-\u{1F859}\u{1F860}-\u{1F887}\u{1F890}-\u{1F8AD}\u{1F8B0}-\u{1F8BB}\u{1F8C0}\u{1F8C1}\u{1F8D0}-\u{1F8D8}\u{1F900}-\u{1FA57}\u{1FA60}-\u{1FA6D}\u{1FA70}-\u{1FA7C}\u{1FA80}-\u{1FAC6}\u{1FAC8}\u{1FACC}-\u{1FADD}\u{1FADF}-\u{1FAEB}\u{1FAEF}-\u{1FAFA}\u{1FB00}-\u{1FB92}\u{1FB94}-\u{1FBFA}\u{E0001}\u{E0020}-\u{E007F}\u{E0100}-\u{E01EF}]*$/u;
+    var bidiS3 = /[0-9\xB2\xB3\xB9\u05BE\u05C0\u05C3\u05C6\u05D0-\u05EA\u05EF-\u05F4\u0600-\u0605\u0608\u060B\u060D\u061B-\u064A\u0660-\u0669\u066B-\u066F\u0671-\u06D5\u06DD\u06E5\u06E6\u06EE-\u070D\u070F\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u07FE-\u0815\u081A\u0824\u0828\u0830-\u083E\u0840-\u0858\u085E\u0860-\u086A\u0870-\u0891\u08A0-\u08C9\u08E2\u200F\u2070\u2074-\u2079\u2080-\u2089\u2488-\u249B\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBC2\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFC\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\u{102E1}-\u{102FB}\u{10800}-\u{10805}\u{10808}\u{1080A}-\u{10835}\u{10837}\u{10838}\u{1083C}\u{1083F}-\u{10855}\u{10857}-\u{1089E}\u{108A7}-\u{108AF}\u{108E0}-\u{108F2}\u{108F4}\u{108F5}\u{108FB}-\u{1091B}\u{10920}-\u{10939}\u{1093F}-\u{10959}\u{10980}-\u{109B7}\u{109BC}-\u{109CF}\u{109D2}-\u{10A00}\u{10A10}-\u{10A13}\u{10A15}-\u{10A17}\u{10A19}-\u{10A35}\u{10A40}-\u{10A48}\u{10A50}-\u{10A58}\u{10A60}-\u{10A9F}\u{10AC0}-\u{10AE4}\u{10AEB}-\u{10AF6}\u{10B00}-\u{10B35}\u{10B40}-\u{10B55}\u{10B58}-\u{10B72}\u{10B78}-\u{10B91}\u{10B99}-\u{10B9C}\u{10BA9}-\u{10BAF}\u{10C00}-\u{10C48}\u{10C80}-\u{10CB2}\u{10CC0}-\u{10CF2}\u{10CFA}-\u{10D23}\u{10D30}-\u{10D39}\u{10D40}-\u{10D65}\u{10D6F}-\u{10D85}\u{10D8E}\u{10D8F}\u{10E60}-\u{10E7E}\u{10E80}-\u{10EA9}\u{10EAD}\u{10EB0}\u{10EB1}\u{10EC2}-\u{10EC7}\u{10EC9}\u{10ECA}\u{10ED9}-\u{10EEE}\u{10F00}-\u{10F27}\u{10F30}-\u{10F45}\u{10F51}-\u{10F59}\u{10F70}-\u{10F81}\u{10F86}-\u{10F89}\u{10FB0}-\u{10FCB}\u{10FE0}-\u{10FF6}\u{1CCF0}-\u{1CCF9}\u{1D7CE}-\u{1D7FF}\u{1E800}-\u{1E8C4}\u{1E8C7}-\u{1E8CF}\u{1E900}-\u{1E943}\u{1E94B}\u{1E950}-\u{1E959}\u{1E95E}\u{1E95F}\u{1EC71}-\u{1ECB4}\u{1ED01}-\u{1ED3D}\u{1EE00}-\u{1EE03}\u{1EE05}-\u{1EE1F}\u{1EE21}\u{1EE22}\u{1EE24}\u{1EE27}\u{1EE29}-\u{1EE32}\u{1EE34}-\u{1EE37}\u{1EE39}\u{1EE3B}\u{1EE42}\u{1EE47}\u{1EE49}\u{1EE4B}\u{1EE4D}-\u{1EE4F}\u{1EE51}\u{1EE52}\u{1EE54}\u{1EE57}\u{1EE59}\u{1EE5B}\u{1EE5D}\u{1EE5F}\u{1EE61}\u{1EE62}\u{1EE64}\u{1EE67}-\u{1EE6A}\u{1EE6C}-\u{1EE72}\u{1EE74}-\u{1EE77}\u{1EE79}-\u{1EE7C}\u{1EE7E}\u{1EE80}-\u{1EE89}\u{1EE8B}-\u{1EE9B}\u{1EEA1}-\u{1EEA3}\u{1EEA5}-\u{1EEA9}\u{1EEAB}-\u{1EEBB}\u{1F100}-\u{1F10A}\u{1FBF0}-\u{1FBF9}][\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7-\u05C9\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0897-\u089F\u08CA-\u08E1\u08E3-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962\u0963\u0981\u09BC\u09C1-\u09C4\u09CD\u09E2\u09E3\u09FE\u0A01\u0A02\u0A3C\u0A41\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7\u0AC8\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01\u0B3C\u0B3F\u0B41-\u0B44\u0B4D\u0B53-\u0B56\u0B62\u0B63\u0B82\u0BC0\u0BCD\u0C00\u0C04\u0C3C\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81\u0CBC\u0CCC\u0CCD\u0CE2\u0CE3\u0D00\u0D01\u0D3B\u0D3C\u0D41-\u0D44\u0D4D\u0D62\u0D63\u0D81\u0DCA\u0DD2-\u0DD4\u0DD6\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECE\u0F18\u0F19\u0F35\u0F37\u0F39\u0F71-\u0F7E\u0F80-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039\u103A\u103D\u103E\u1058\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085\u1086\u108D\u109D\u135D-\u135F\u1712-\u1714\u1732\u1733\u1752\u1753\u1772\u1773\u17B4\u17B5\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DD\u180B-\u180D\u180F\u1885\u1886\u18A9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193B\u1A17\u1A18\u1A1B\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1AB0-\u1AF0\u1B00-\u1B03\u1B34\u1B36-\u1B39\u1B6B-\u1B73\u1B80\u1B81\u1BA2-\u1BA5\u1BA8\u1BA9\u1BAB-\u1BAD\u1BE6\u1BE8\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1CF8\u1CF9\u1DC0-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302D\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA825\uA826\uA82C\uA8C4\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uA9BD\uA9E5\uAA29-\uAA2E\uAA31\uAA32\uAA35\uAA36\uAA43\uAA4C\uAA7C\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEC\uAAED\uAAF6\uABE5\uABE8\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F\u{101FD}\u{102E0}\u{10376}-\u{1037A}\u{10A01}-\u{10A03}\u{10A05}\u{10A06}\u{10A0C}-\u{10A0F}\u{10A38}-\u{10A3A}\u{10A3F}\u{10AE5}\u{10AE6}\u{10D24}-\u{10D27}\u{10D69}-\u{10D6D}\u{10EAB}\u{10EAC}\u{10ECB}-\u{10ECF}\u{10EF0}-\u{10EFF}\u{10F46}-\u{10F50}\u{10F82}-\u{10F85}\u{11001}\u{11038}-\u{11046}\u{11070}\u{11073}\u{11074}\u{1107F}-\u{11081}\u{110B3}-\u{110B6}\u{110B9}\u{110BA}\u{110C2}\u{11100}-\u{11102}\u{11127}-\u{1112B}\u{1112D}-\u{11134}\u{11173}\u{11180}\u{11181}\u{111B6}-\u{111BE}\u{111C9}-\u{111CC}\u{111CF}\u{1122F}-\u{11231}\u{11234}\u{11236}\u{11237}\u{1123E}\u{11241}\u{112DF}\u{112E3}-\u{112EA}\u{11300}\u{11301}\u{1133B}\u{1133C}\u{11340}\u{11366}-\u{1136C}\u{11370}-\u{11374}\u{113BB}-\u{113C0}\u{113CE}\u{113D0}\u{113D2}\u{113E1}\u{113E2}\u{11438}-\u{1143F}\u{11442}-\u{11444}\u{11446}\u{1145E}\u{114B3}-\u{114B8}\u{114BA}\u{114BF}\u{114C0}\u{114C2}\u{114C3}\u{115B2}-\u{115B5}\u{115BC}\u{115BD}\u{115BF}\u{115C0}\u{115DC}\u{115DD}\u{11633}-\u{1163A}\u{1163D}\u{1163F}\u{11640}\u{116AB}\u{116AD}\u{116B0}-\u{116B5}\u{116B7}\u{1171D}\u{1171F}\u{11722}-\u{11725}\u{11727}-\u{1172B}\u{1182F}-\u{11837}\u{11839}\u{1183A}\u{1193B}\u{1193C}\u{1193E}\u{11943}\u{119D4}-\u{119D7}\u{119DA}\u{119DB}\u{119E0}\u{11A01}-\u{11A06}\u{11A09}\u{11A0A}\u{11A33}-\u{11A38}\u{11A3B}-\u{11A3E}\u{11A47}\u{11A51}-\u{11A56}\u{11A59}-\u{11A5B}\u{11A8A}-\u{11A96}\u{11A98}\u{11A99}\u{11B60}\u{11B62}-\u{11B64}\u{11B66}\u{11C30}-\u{11C36}\u{11C38}-\u{11C3D}\u{11C92}-\u{11CA7}\u{11CAA}-\u{11CB0}\u{11CB2}\u{11CB3}\u{11CB5}\u{11CB6}\u{11D31}-\u{11D36}\u{11D3A}\u{11D3C}\u{11D3D}\u{11D3F}-\u{11D45}\u{11D47}\u{11D90}\u{11D91}\u{11D95}\u{11D97}\u{11DF0}\u{11EF3}\u{11EF4}\u{11F00}\u{11F01}\u{11F36}-\u{11F3A}\u{11F40}\u{11F42}\u{11F5A}\u{13440}\u{13447}-\u{13455}\u{1611E}-\u{16129}\u{1612D}-\u{1612F}\u{16AF0}-\u{16AF4}\u{16B30}-\u{16B36}\u{16F4F}\u{16F8F}-\u{16F92}\u{16FE4}\u{1BC9D}\u{1BC9E}\u{1CF00}-\u{1CF2D}\u{1CF30}-\u{1CF46}\u{1D127}\u{1D128}\u{1D167}-\u{1D169}\u{1D17B}-\u{1D182}\u{1D185}-\u{1D18B}\u{1D1AA}-\u{1D1AD}\u{1D242}-\u{1D244}\u{1D25B}\u{1D25C}\u{1DA00}-\u{1DA36}\u{1DA3B}-\u{1DA6C}\u{1DA75}\u{1DA84}\u{1DA9B}-\u{1DA9F}\u{1DAA1}-\u{1DAAF}\u{1E000}-\u{1E006}\u{1E008}-\u{1E018}\u{1E01B}-\u{1E021}\u{1E023}\u{1E024}\u{1E026}-\u{1E02A}\u{1E08F}\u{1E130}-\u{1E136}\u{1E2AE}\u{1E2EC}-\u{1E2EF}\u{1E4EC}-\u{1E4EF}\u{1E5EE}\u{1E5EF}\u{1E6E3}\u{1E6E6}\u{1E6EE}\u{1E6EF}\u{1E6F5}\u{1E8D0}-\u{1E8D6}\u{1E944}-\u{1E94A}\u{E0100}-\u{E01EF}]*$/u;
+    var bidiS4EN = /[0-9\xB2\xB3\xB9\u06F0-\u06F9\u2070\u2074-\u2079\u2080-\u2089\u2488-\u249B\uFF10-\uFF19\u{102E1}-\u{102FB}\u{1CCF0}-\u{1CCF9}\u{1D7CE}-\u{1D7FF}\u{1F100}-\u{1F10A}\u{1FBF0}-\u{1FBF9}]/u;
+    var bidiS4AN = /[\u0600-\u0605\u0660-\u0669\u066B\u066C\u06DD\u0890\u0891\u08E2\u{10D30}-\u{10D39}\u{10D40}-\u{10D49}\u{10E60}-\u{10E7E}]/u;
+    var bidiS5 = /^[\0-\x08\x0E-\x1B!-\x84\x86-\u0377\u037A-\u037F\u0384-\u038A\u038C\u038E-\u03A1\u03A3-\u052F\u0531-\u0556\u0558-\u058F\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7-\u05C9\u0606\u0607\u0609\u060A\u060C\u060E-\u061A\u064B-\u065F\u066A\u0670\u06D6-\u06DC\u06DE-\u06E4\u06E7-\u06ED\u06F0-\u06F9\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07F6-\u07F9\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0897-\u089F\u08CA-\u08E1\u08E3-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09FE\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A76\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AF1\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B53-\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B77\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BFA\u0C00-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3C-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C5C\u0C5D\u0C60-\u0C63\u0C66-\u0C6F\u0C77-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDC-\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1-\u0CF3\u0D00-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4F\u0D54-\u0D63\u0D66-\u0D7F\u0D81-\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2-\u0DF4\u0E01-\u0E3A\u0E3F-\u0E5B\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECE\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00-\u0F47\u0F49-\u0F6C\u0F71-\u0F97\u0F99-\u0FBC\u0FBE-\u0FCC\u0FCE-\u0FDA\u1000-\u10C5\u10C7\u10CD\u10D0-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u137C\u1380-\u1399\u13A0-\u13F5\u13F8-\u13FD\u1400-\u167F\u1681-\u169C\u16A0-\u16F8\u1700-\u1715\u171F-\u1736\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17DD\u17E0-\u17E9\u17F0-\u17F9\u1800-\u1819\u1820-\u1878\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1940\u1944-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u19DE-\u1A1B\u1A1E-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA0-\u1AAD\u1AB0-\u1AF0\u1B00-\u1B4C\u1B4E-\u1BF3\u1BFC-\u1C37\u1C3B-\u1C49\u1C4D-\u1C8A\u1C90-\u1CBA\u1CBD-\u1CC7\u1CD0-\u1CFA\u1D00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FC4\u1FC6-\u1FD3\u1FD6-\u1FDB\u1FDD-\u1FEF\u1FF2-\u1FF4\u1FF6-\u1FFE\u200B-\u200E\u2010-\u2027\u202F-\u205E\u2060-\u2064\u206A-\u2071\u2074-\u20C4\u20D0-\u20F0\u2100-\u218B\u2190-\u2429\u2440-\u244A\u2460-\u2B73\u2B76-\u2CF3\u2CF9-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D70\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2E5D\u2E60-\u2E63\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFF\u3001-\u303F\u3041-\u3096\u3099-\u30FF\u3105-\u312F\u3131-\u318E\u3190-\u31E5\u31EF-\u321E\u3220-\uA48C\uA490-\uA4C6\uA4D0-\uA62B\uA640-\uA6F7\uA700-\uA7DD\uA7E2\uA7F1-\uA82C\uA830-\uA839\uA840-\uA877\uA880-\uA8C5\uA8CE-\uA8D9\uA8E0-\uA953\uA95F-\uA97C\uA980-\uA9CD\uA9CF-\uA9D9\uA9DE-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA5C-\uAAC2\uAADB-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB6D\uAB70-\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uD800-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1E\uFB29\uFBC3-\uFBD2\uFD3E-\uFD4F\uFD90\uFD91\uFDC8-\uFDCF\uFDFD-\uFE19\uFE20-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFEFF\uFF01-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC\uFFE0-\uFFE6\uFFE8-\uFFEE\uFFF9-\uFFFD\u{10000}-\u{1000B}\u{1000D}-\u{10026}\u{10028}-\u{1003A}\u{1003C}\u{1003D}\u{1003F}-\u{1004D}\u{10050}-\u{1005D}\u{10080}-\u{100FA}\u{10100}-\u{10102}\u{10107}-\u{10133}\u{10137}-\u{1018E}\u{10190}-\u{1019C}\u{101A0}\u{101D0}-\u{101FD}\u{10280}-\u{1029C}\u{102A0}-\u{102D0}\u{102E0}-\u{102FB}\u{10300}-\u{10323}\u{1032D}-\u{1034A}\u{10350}-\u{1037A}\u{10380}-\u{1039D}\u{1039F}-\u{103C3}\u{103C8}-\u{103D5}\u{10400}-\u{1049D}\u{104A0}-\u{104A9}\u{104B0}-\u{104D3}\u{104D8}-\u{104FB}\u{10500}-\u{10527}\u{10530}-\u{10563}\u{1056F}-\u{1057A}\u{1057C}-\u{1058A}\u{1058C}-\u{10592}\u{10594}\u{10595}\u{10597}-\u{105A1}\u{105A3}-\u{105B1}\u{105B3}-\u{105B9}\u{105BB}\u{105BC}\u{105C0}-\u{105F3}\u{10600}-\u{10736}\u{10740}-\u{10755}\u{10760}-\u{10767}\u{10780}-\u{10785}\u{10787}-\u{107B0}\u{107B2}-\u{107BF}\u{1091F}\u{10A01}-\u{10A03}\u{10A05}\u{10A06}\u{10A0C}-\u{10A0F}\u{10A38}-\u{10A3A}\u{10A3F}\u{10AE5}\u{10AE6}\u{10B39}-\u{10B3F}\u{10D24}-\u{10D27}\u{10D69}-\u{10D6E}\u{10EAB}\u{10EAC}\u{10ECB}-\u{10ED8}\u{10EF0}-\u{10EFF}\u{10F46}-\u{10F50}\u{10F82}-\u{10F85}\u{11000}-\u{1104D}\u{11052}-\u{11075}\u{1107F}-\u{110C2}\u{110CD}\u{110D0}-\u{110E8}\u{110F0}-\u{110F9}\u{11100}-\u{11134}\u{11136}-\u{11147}\u{11150}-\u{11176}\u{11180}-\u{111DF}\u{111E1}-\u{111F4}\u{11200}-\u{11211}\u{11213}-\u{11241}\u{11280}-\u{11286}\u{11288}\u{1128A}-\u{1128D}\u{1128F}-\u{1129D}\u{1129F}-\u{112A9}\u{112B0}-\u{112EA}\u{112F0}-\u{112F9}\u{11300}-\u{11303}\u{11305}-\u{1130C}\u{1130F}\u{11310}\u{11313}-\u{11328}\u{1132A}-\u{11330}\u{11332}\u{11333}\u{11335}-\u{11339}\u{1133B}-\u{11344}\u{11347}\u{11348}\u{1134B}-\u{1134D}\u{11350}\u{11357}\u{1135D}-\u{11363}\u{11366}-\u{1136C}\u{11370}-\u{11374}\u{11380}-\u{11389}\u{1138B}\u{1138E}\u{11390}-\u{113B5}\u{113B7}-\u{113C0}\u{113C2}\u{113C5}\u{113C7}-\u{113CA}\u{113CC}-\u{113D5}\u{113D7}\u{113D8}\u{113E1}\u{113E2}\u{11400}-\u{1145B}\u{1145D}-\u{11461}\u{11480}-\u{114C7}\u{114D0}-\u{114D9}\u{11580}-\u{115B5}\u{115B8}-\u{115DD}\u{11600}-\u{11644}\u{11650}-\u{11659}\u{11660}-\u{1166C}\u{11680}-\u{116B9}\u{116C0}-\u{116C9}\u{116D0}-\u{116E3}\u{11700}-\u{1171A}\u{1171D}-\u{1172B}\u{11730}-\u{11746}\u{11800}-\u{1183B}\u{118A0}-\u{118F2}\u{118FF}-\u{11906}\u{11909}\u{1190C}-\u{11913}\u{11915}\u{11916}\u{11918}-\u{11935}\u{11937}\u{11938}\u{1193B}-\u{11946}\u{11950}-\u{11959}\u{119A0}-\u{119A7}\u{119AA}-\u{119D7}\u{119DA}-\u{119E4}\u{11A00}-\u{11A47}\u{11A50}-\u{11AA2}\u{11AB0}-\u{11AF8}\u{11B00}-\u{11B0A}\u{11B60}-\u{11B67}\u{11BC0}-\u{11BE1}\u{11BF0}-\u{11BF9}\u{11C00}-\u{11C08}\u{11C0A}-\u{11C36}\u{11C38}-\u{11C45}\u{11C50}-\u{11C6C}\u{11C70}-\u{11C8F}\u{11C92}-\u{11CA7}\u{11CA9}-\u{11CB6}\u{11D00}-\u{11D06}\u{11D08}\u{11D09}\u{11D0B}-\u{11D36}\u{11D3A}\u{11D3C}\u{11D3D}\u{11D3F}-\u{11D47}\u{11D50}-\u{11D59}\u{11D60}-\u{11D65}\u{11D67}\u{11D68}\u{11D6A}-\u{11D8E}\u{11D90}\u{11D91}\u{11D93}-\u{11D98}\u{11DA0}-\u{11DA9}\u{11DB0}-\u{11DDB}\u{11DE0}-\u{11DE9}\u{11DF0}\u{11DF1}\u{11EE0}-\u{11EF8}\u{11F00}-\u{11F10}\u{11F12}-\u{11F3A}\u{11F3E}-\u{11F5A}\u{11FB0}\u{11FC0}-\u{11FF1}\u{11FFF}-\u{12399}\u{12400}-\u{12543}\u{12550}-\u{12686}\u{12F90}-\u{12FF2}\u{13000}-\u{13455}\u{13460}-\u{143FA}\u{14400}-\u{14646}\u{16100}-\u{16139}\u{16800}-\u{16A38}\u{16A40}-\u{16A5E}\u{16A60}-\u{16A69}\u{16A6E}-\u{16ABE}\u{16AC0}-\u{16AC9}\u{16AD0}-\u{16AED}\u{16AF0}-\u{16AF5}\u{16B00}-\u{16B45}\u{16B50}-\u{16B59}\u{16B5B}-\u{16B61}\u{16B63}-\u{16B77}\u{16B7D}-\u{16B8F}\u{16D40}-\u{16D79}\u{16E40}-\u{16E9A}\u{16EA0}-\u{16EB8}\u{16EBB}-\u{16ED3}\u{16F00}-\u{16F4A}\u{16F4F}-\u{16F87}\u{16F8F}-\u{16F9F}\u{16FE0}-\u{16FE4}\u{16FF0}-\u{16FF6}\u{17000}-\u{18CDA}\u{18CFF}-\u{18D20}\u{18D80}-\u{18DF2}\u{18E00}-\u{19191}\u{191A0}-\u{191D2}\u{1AFF0}-\u{1AFF3}\u{1AFF5}-\u{1AFFB}\u{1AFFD}\u{1AFFE}\u{1B000}-\u{1B128}\u{1B132}\u{1B150}-\u{1B152}\u{1B155}\u{1B164}-\u{1B168}\u{1B170}-\u{1B2FB}\u{1BC00}-\u{1BC6A}\u{1BC70}-\u{1BC7C}\u{1BC80}-\u{1BC88}\u{1BC90}-\u{1BC99}\u{1BC9C}-\u{1BCA3}\u{1CC00}-\u{1CCFC}\u{1CD00}-\u{1CEB3}\u{1CEBA}-\u{1CED0}\u{1CED2}-\u{1CED4}\u{1CEDD}-\u{1CEFD}\u{1CF00}-\u{1CF2D}\u{1CF30}-\u{1CF46}\u{1CF50}-\u{1CFC3}\u{1D000}-\u{1D0F5}\u{1D100}-\u{1D245}\u{1D250}-\u{1D281}\u{1D2C0}-\u{1D2D3}\u{1D2E0}-\u{1D2F3}\u{1D300}-\u{1D356}\u{1D360}-\u{1D378}\u{1D400}-\u{1D454}\u{1D456}-\u{1D49C}\u{1D49E}\u{1D49F}\u{1D4A2}\u{1D4A5}\u{1D4A6}\u{1D4A9}-\u{1D4AC}\u{1D4AE}-\u{1D4B9}\u{1D4BB}\u{1D4BD}-\u{1D4C3}\u{1D4C5}-\u{1D505}\u{1D507}-\u{1D50A}\u{1D50D}-\u{1D514}\u{1D516}-\u{1D51C}\u{1D51E}-\u{1D539}\u{1D53B}-\u{1D53E}\u{1D540}-\u{1D544}\u{1D546}\u{1D54A}-\u{1D550}\u{1D552}-\u{1D6A6}\u{1D6A8}-\u{1D7CB}\u{1D7CE}-\u{1DA8B}\u{1DA9B}-\u{1DA9F}\u{1DAA1}-\u{1DAAF}\u{1DB00}-\u{1DB1C}\u{1DF00}-\u{1DF81}\u{1DF90}-\u{1DF96}\u{1DFCD}-\u{1E006}\u{1E008}-\u{1E018}\u{1E01B}-\u{1E021}\u{1E023}\u{1E024}\u{1E026}-\u{1E02A}\u{1E030}-\u{1E06D}\u{1E08F}\u{1E100}-\u{1E12C}\u{1E130}-\u{1E13D}\u{1E140}-\u{1E149}\u{1E14E}\u{1E14F}\u{1E290}-\u{1E2AE}\u{1E2C0}-\u{1E2F9}\u{1E2FF}\u{1E4D0}-\u{1E4F9}\u{1E5D0}-\u{1E5FA}\u{1E5FF}\u{1E6C0}-\u{1E6DE}\u{1E6E0}-\u{1E6F5}\u{1E6FE}\u{1E6FF}\u{1E7E0}-\u{1E7E6}\u{1E7E8}-\u{1E7EB}\u{1E7ED}\u{1E7EE}\u{1E7F0}-\u{1E7FE}\u{1E8D0}-\u{1E8D6}\u{1E944}-\u{1E94A}\u{1EEF0}\u{1EEF1}\u{1F000}-\u{1F02B}\u{1F030}-\u{1F093}\u{1F0A0}-\u{1F0AE}\u{1F0B1}-\u{1F0BF}\u{1F0C1}-\u{1F0CF}\u{1F0D1}-\u{1F0F5}\u{1F100}-\u{1F1AE}\u{1F1E6}-\u{1F202}\u{1F210}-\u{1F23B}\u{1F240}-\u{1F248}\u{1F250}\u{1F251}\u{1F260}-\u{1F265}\u{1F300}-\u{1F6D9}\u{1F6DC}-\u{1F6EC}\u{1F6F0}-\u{1F6FC}\u{1F700}-\u{1F7DB}\u{1F7E0}-\u{1F7EB}\u{1F7F0}-\u{1F80B}\u{1F810}-\u{1F847}\u{1F850}-\u{1F859}\u{1F860}-\u{1F887}\u{1F890}-\u{1F8AD}\u{1F8B0}-\u{1F8BB}\u{1F8C0}\u{1F8C1}\u{1F8D0}-\u{1F8D8}\u{1F900}-\u{1FA57}\u{1FA60}-\u{1FA6D}\u{1FA70}-\u{1FA7C}\u{1FA80}-\u{1FAC6}\u{1FAC8}\u{1FACC}-\u{1FADD}\u{1FADF}-\u{1FAEB}\u{1FAEF}-\u{1FAFA}\u{1FB00}-\u{1FB92}\u{1FB94}-\u{1FBFA}\u{20000}-\u{2A6DF}\u{2A700}-\u{2B81E}\u{2B820}-\u{2CEAD}\u{2CEB0}-\u{2EBE0}\u{2EBF0}-\u{2EE5D}\u{2F800}-\u{2FA1D}\u{30000}-\u{3134A}\u{31350}-\u{33479}\u{3D000}-\u{3FC3F}\u{E0001}\u{E0020}-\u{E007F}\u{E0100}-\u{E01EF}\u{F0000}-\u{FFFFD}\u{100000}-\u{10FFFD}]*$/u;
+    var bidiS6 = /[0-9A-Za-z\xAA\xB2\xB3\xB5\xB9\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02B8\u02BB-\u02C1\u02D0\u02D1\u02E0-\u02E4\u02EE\u0370-\u0373\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0482\u048A-\u052F\u0531-\u0556\u0558-\u0589\u058B\u058C\u06F0-\u06F9\u0903-\u0939\u093B\u093D-\u0940\u0949-\u094C\u094E-\u0950\u0958-\u0961\u0964-\u0980\u0982\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD-\u09C0\u09C7\u09C8\u09CB\u09CC\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09FA\u09FC\u09FD\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A40\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A76\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD-\u0AC0\u0AC9\u0ACB\u0ACC\u0AD0\u0AE0\u0AE1\u0AE6-\u0AF0\u0AF9\u0B02\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B3E\u0B40\u0B47\u0B48\u0B4B\u0B4C\u0B57\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE\u0BBF\u0BC1\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0BD0\u0BD7\u0BE6-\u0BF2\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C41-\u0C44\u0C58-\u0C5A\u0C5C\u0C5D\u0C60\u0C61\u0C66-\u0C6F\u0C77\u0C7F\u0C80\u0C82-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD-\u0CC4\u0CC6-\u0CC8\u0CCA\u0CCB\u0CD5\u0CD6\u0CDC-\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1-\u0CF3\u0D02-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D40\u0D46-\u0D48\u0D4A-\u0D4C\u0D4E\u0D4F\u0D54-\u0D61\u0D66-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCF-\u0DD1\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2-\u0DF4\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E4F-\u0E5B\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00-\u0F17\u0F1A-\u0F34\u0F36\u0F38\u0F3E-\u0F47\u0F49-\u0F6C\u0F7F\u0F85\u0F88-\u0F8C\u0FBE-\u0FC5\u0FC7-\u0FCC\u0FCE-\u0FDA\u1000-\u102C\u1031\u1038\u103B\u103C\u103F-\u1057\u105A-\u105D\u1061-\u1070\u1075-\u1081\u1083\u1084\u1087-\u108C\u108E-\u109C\u109E-\u10C5\u10C7\u10CD\u10D0-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1360-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u167F\u1681-\u169A\u16A0-\u16F8\u1700-\u1711\u1715\u171F-\u1731\u1734-\u1736\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17B6\u17BE-\u17C5\u17C7\u17C8\u17D4-\u17DA\u17DC\u17E0-\u17E9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1923-\u1926\u1929-\u192B\u1930\u1931\u1933-\u1938\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A19\u1A1A\u1A1E-\u1A55\u1A57\u1A61\u1A63\u1A64\u1A6D-\u1A72\u1A80-\u1A89\u1A90-\u1A99\u1AA0-\u1AAD\u1B04-\u1B33\u1B35\u1B3A-\u1B4C\u1B4E-\u1B6A\u1B74-\u1B7F\u1B82-\u1BA1\u1BA6\u1BA7\u1BAA\u1BAE-\u1BE5\u1BE7\u1BEA-\u1BEC\u1BEE\u1BF2\u1BF3\u1BFC-\u1C2B\u1C34\u1C35\u1C3B-\u1C49\u1C4D-\u1C8A\u1C90-\u1CBA\u1CBD-\u1CC7\u1CD3\u1CE1\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5-\u1CF7\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200E\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209F\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u214F\u2160-\u2188\u2336-\u237A\u2395\u2488-\u24E9\u26AC\u2800-\u28FF\u2C00-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D70\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u302E\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3190-\u31BF\u31F0-\u321C\u3220-\u324F\u3260-\u327B\u327F-\u32B0\u32C0-\u32CB\u32D0-\u3376\u337B-\u33DD\u33E0-\u33FE\u3400-\u4DBF\u4E00-\uA48C\uA4D0-\uA60C\uA610-\uA62B\uA640-\uA66E\uA680-\uA69D\uA6A0-\uA6EF\uA6F2-\uA6F7\uA722-\uA787\uA789-\uA7DD\uA7E2\uA7F1-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA824\uA827\uA830-\uA837\uA840-\uA873\uA880-\uA8C3\uA8CE-\uA8D9\uA8F2-\uA8FE\uA900-\uA925\uA92E-\uA946\uA952\uA953\uA95F-\uA97C\uA983-\uA9B2\uA9B4\uA9B5\uA9BA\uA9BB\uA9BE-\uA9CD\uA9CF-\uA9D9\uA9DE-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA2F\uAA30\uAA33\uAA34\uAA40-\uAA42\uAA44-\uAA4B\uAA4D\uAA50-\uAA59\uAA5C-\uAA7B\uAA7D-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAAEB\uAAEE-\uAAF5\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB69\uAB6C\uAB6D\uAB70-\uABE4\uABE6\uABE7\uABE9-\uABEC\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uD800-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC\u{10000}-\u{1000B}\u{1000D}-\u{10026}\u{10028}-\u{1003A}\u{1003C}\u{1003D}\u{1003F}-\u{1004D}\u{10050}-\u{1005D}\u{10080}-\u{100FA}\u{10100}\u{10102}\u{10107}-\u{10133}\u{10137}-\u{1013F}\u{1018D}\u{1018E}\u{101D0}-\u{101FC}\u{10280}-\u{1029C}\u{102A0}-\u{102D0}\u{102E1}-\u{102FB}\u{10300}-\u{10323}\u{1032D}-\u{1034A}\u{10350}-\u{10375}\u{10380}-\u{1039D}\u{1039F}-\u{103C3}\u{103C8}-\u{103D5}\u{10400}-\u{1049D}\u{104A0}-\u{104A9}\u{104B0}-\u{104D3}\u{104D8}-\u{104FB}\u{10500}-\u{10527}\u{10530}-\u{10563}\u{1056F}-\u{1057A}\u{1057C}-\u{1058A}\u{1058C}-\u{10592}\u{10594}\u{10595}\u{10597}-\u{105A1}\u{105A3}-\u{105B1}\u{105B3}-\u{105B9}\u{105BB}\u{105BC}\u{105C0}-\u{105F3}\u{10600}-\u{10736}\u{10740}-\u{10755}\u{10760}-\u{10767}\u{10780}-\u{10785}\u{10787}-\u{107B0}\u{107B2}-\u{107BF}\u{11000}\u{11002}-\u{11037}\u{11047}-\u{1104D}\u{11066}-\u{1106F}\u{11071}\u{11072}\u{11075}\u{11082}-\u{110B2}\u{110B7}\u{110B8}\u{110BB}-\u{110C1}\u{110CD}\u{110D0}-\u{110E8}\u{110F0}-\u{110F9}\u{11103}-\u{11126}\u{1112C}\u{11136}-\u{11147}\u{11150}-\u{11172}\u{11174}-\u{11176}\u{11182}-\u{111B5}\u{111BF}-\u{111C8}\u{111CD}\u{111CE}\u{111D0}-\u{111DF}\u{111E1}-\u{111F4}\u{11200}-\u{11211}\u{11213}-\u{1122E}\u{11232}\u{11233}\u{11235}\u{11238}-\u{1123D}\u{1123F}\u{11240}\u{11280}-\u{11286}\u{11288}\u{1128A}-\u{1128D}\u{1128F}-\u{1129D}\u{1129F}-\u{112A9}\u{112B0}-\u{112DE}\u{112E0}-\u{112E2}\u{112F0}-\u{112F9}\u{11302}\u{11303}\u{11305}-\u{1130C}\u{1130F}\u{11310}\u{11313}-\u{11328}\u{1132A}-\u{11330}\u{11332}\u{11333}\u{11335}-\u{11339}\u{1133D}-\u{1133F}\u{11341}-\u{11344}\u{11347}\u{11348}\u{1134B}-\u{1134D}\u{11350}\u{11357}\u{1135D}-\u{11363}\u{11380}-\u{11389}\u{1138B}\u{1138E}\u{11390}-\u{113B5}\u{113B7}-\u{113BA}\u{113C2}\u{113C5}\u{113C7}-\u{113CA}\u{113CC}\u{113CD}\u{113CF}\u{113D1}\u{113D3}-\u{113D5}\u{113D7}\u{113D8}\u{11400}-\u{11437}\u{11440}\u{11441}\u{11445}\u{11447}-\u{1145B}\u{1145D}\u{1145F}-\u{11461}\u{11480}-\u{114B2}\u{114B9}\u{114BB}-\u{114BE}\u{114C1}\u{114C4}-\u{114C7}\u{114D0}-\u{114D9}\u{11580}-\u{115B1}\u{115B8}-\u{115BB}\u{115BE}\u{115C1}-\u{115DB}\u{11600}-\u{11632}\u{1163B}\u{1163C}\u{1163E}\u{11641}-\u{11644}\u{11650}-\u{11659}\u{11680}-\u{116AA}\u{116AC}\u{116AE}\u{116AF}\u{116B6}\u{116B8}\u{116B9}\u{116C0}-\u{116C9}\u{116D0}-\u{116E3}\u{11700}-\u{1171A}\u{1171E}\u{11720}\u{11721}\u{11726}\u{11730}-\u{11746}\u{11800}-\u{1182E}\u{11838}\u{1183B}\u{118A0}-\u{118F2}\u{118FF}-\u{11906}\u{11909}\u{1190C}-\u{11913}\u{11915}\u{11916}\u{11918}-\u{11935}\u{11937}\u{11938}\u{1193D}\u{1193F}-\u{11942}\u{11944}-\u{11946}\u{11950}-\u{11959}\u{119A0}-\u{119A7}\u{119AA}-\u{119D3}\u{119DC}-\u{119DF}\u{119E1}-\u{119E4}\u{11A00}\u{11A07}\u{11A08}\u{11A0B}-\u{11A32}\u{11A39}\u{11A3A}\u{11A3F}-\u{11A46}\u{11A50}\u{11A57}\u{11A58}\u{11A5C}-\u{11A89}\u{11A97}\u{11A9A}-\u{11AA2}\u{11AB0}-\u{11AF8}\u{11B00}-\u{11B0A}\u{11B61}\u{11B65}\u{11B67}\u{11BC0}-\u{11BE1}\u{11BF0}-\u{11BF9}\u{11C00}-\u{11C08}\u{11C0A}-\u{11C2F}\u{11C3E}-\u{11C45}\u{11C50}-\u{11C6C}\u{11C70}-\u{11C8F}\u{11CA9}\u{11CB1}\u{11CB4}\u{11D00}-\u{11D06}\u{11D08}\u{11D09}\u{11D0B}-\u{11D30}\u{11D46}\u{11D50}-\u{11D59}\u{11D60}-\u{11D65}\u{11D67}\u{11D68}\u{11D6A}-\u{11D8E}\u{11D93}\u{11D94}\u{11D96}\u{11D98}\u{11DA0}-\u{11DA9}\u{11DB0}-\u{11DDB}\u{11DE0}-\u{11DE9}\u{11DF1}\u{11EE0}-\u{11EF2}\u{11EF5}-\u{11EF8}\u{11F02}-\u{11F10}\u{11F12}-\u{11F35}\u{11F3E}\u{11F3F}\u{11F41}\u{11F43}-\u{11F59}\u{11FB0}\u{11FC0}-\u{11FD4}\u{11FFF}-\u{12399}\u{12400}-\u{12543}\u{12550}-\u{12686}\u{12F90}-\u{12FF2}\u{13000}-\u{1343F}\u{13441}-\u{13446}\u{13460}-\u{143FA}\u{14400}-\u{14646}\u{16100}-\u{1611D}\u{1612A}-\u{1612C}\u{16130}-\u{16139}\u{16800}-\u{16A38}\u{16A40}-\u{16A5E}\u{16A60}-\u{16A69}\u{16A6E}-\u{16ABE}\u{16AC0}-\u{16AC9}\u{16AD0}-\u{16AED}\u{16AF5}\u{16B00}-\u{16B2F}\u{16B37}-\u{16B45}\u{16B50}-\u{16B59}\u{16B5B}-\u{16B61}\u{16B63}-\u{16B77}\u{16B7D}-\u{16B8F}\u{16D40}-\u{16D79}\u{16E40}-\u{16E9A}\u{16EA0}-\u{16EB8}\u{16EBB}-\u{16ED3}\u{16F00}-\u{16F4A}\u{16F50}-\u{16F87}\u{16F93}-\u{16F9F}\u{16FE0}\u{16FE1}\u{16FE3}\u{16FF0}-\u{16FF6}\u{17000}-\u{18CDA}\u{18CFF}-\u{18D20}\u{18D80}-\u{18DF2}\u{18E00}-\u{19191}\u{191A0}-\u{191D2}\u{1AFF0}-\u{1AFF3}\u{1AFF5}-\u{1AFFB}\u{1AFFD}\u{1AFFE}\u{1B000}-\u{1B128}\u{1B132}\u{1B150}-\u{1B152}\u{1B155}\u{1B164}-\u{1B168}\u{1B170}-\u{1B2FB}\u{1BC00}-\u{1BC6A}\u{1BC70}-\u{1BC7C}\u{1BC80}-\u{1BC88}\u{1BC90}-\u{1BC99}\u{1BC9C}\u{1BC9F}\u{1CCD6}-\u{1CCF9}\u{1CF50}-\u{1CFC3}\u{1D000}-\u{1D0F5}\u{1D100}-\u{1D126}\u{1D129}-\u{1D166}\u{1D16A}-\u{1D172}\u{1D183}\u{1D184}\u{1D18C}-\u{1D1A9}\u{1D1AE}-\u{1D1E8}\u{1D1EB}-\u{1D1FF}\u{1D250}-\u{1D25A}\u{1D25D}-\u{1D281}\u{1D2C0}-\u{1D2D3}\u{1D2E0}-\u{1D2F3}\u{1D360}-\u{1D378}\u{1D400}-\u{1D454}\u{1D456}-\u{1D49C}\u{1D49E}\u{1D49F}\u{1D4A2}\u{1D4A5}\u{1D4A6}\u{1D4A9}-\u{1D4AC}\u{1D4AE}-\u{1D4B9}\u{1D4BB}\u{1D4BD}-\u{1D4C3}\u{1D4C5}-\u{1D505}\u{1D507}-\u{1D50A}\u{1D50D}-\u{1D514}\u{1D516}-\u{1D51C}\u{1D51E}-\u{1D539}\u{1D53B}-\u{1D53E}\u{1D540}-\u{1D544}\u{1D546}\u{1D54A}-\u{1D550}\u{1D552}-\u{1D6A6}\u{1D6A8}-\u{1D6C0}\u{1D6C2}-\u{1D6DA}\u{1D6DC}-\u{1D6FA}\u{1D6FC}-\u{1D714}\u{1D716}-\u{1D734}\u{1D736}-\u{1D74E}\u{1D750}-\u{1D76E}\u{1D770}-\u{1D788}\u{1D78A}-\u{1D7A8}\u{1D7AA}-\u{1D7C2}\u{1D7C4}-\u{1D7CB}\u{1D7CE}-\u{1D9FF}\u{1DA37}-\u{1DA3A}\u{1DA6D}-\u{1DA74}\u{1DA76}-\u{1DA83}\u{1DA85}-\u{1DA8B}\u{1DF00}-\u{1DF81}\u{1DF90}-\u{1DF96}\u{1DFCD}-\u{1DFFF}\u{1E030}-\u{1E06D}\u{1E100}-\u{1E12C}\u{1E137}-\u{1E13D}\u{1E140}-\u{1E149}\u{1E14E}\u{1E14F}\u{1E290}-\u{1E2AD}\u{1E2C0}-\u{1E2EB}\u{1E2F0}-\u{1E2F9}\u{1E4D0}-\u{1E4EB}\u{1E4F0}-\u{1E4F9}\u{1E5D0}-\u{1E5ED}\u{1E5F0}-\u{1E5FA}\u{1E5FF}\u{1E6C0}-\u{1E6DE}\u{1E6E0}-\u{1E6E2}\u{1E6E4}\u{1E6E5}\u{1E6E7}-\u{1E6ED}\u{1E6F0}-\u{1E6F4}\u{1E6FE}\u{1E6FF}\u{1E7E0}-\u{1E7E6}\u{1E7E8}-\u{1E7EB}\u{1E7ED}\u{1E7EE}\u{1E7F0}-\u{1E7FE}\u{1F100}-\u{1F10A}\u{1F110}-\u{1F12E}\u{1F130}-\u{1F169}\u{1F170}-\u{1F1AC}\u{1F1AE}\u{1F1E6}-\u{1F202}\u{1F210}-\u{1F23B}\u{1F240}-\u{1F248}\u{1F250}\u{1F251}\u{1F7DA}\u{1FBF0}-\u{1FBF9}\u{20000}-\u{2A6DF}\u{2A700}-\u{2B81E}\u{2B820}-\u{2CEAD}\u{2CEB0}-\u{2EBE0}\u{2EBF0}-\u{2EE5D}\u{2F800}-\u{2FA1D}\u{30000}-\u{3134A}\u{31350}-\u{33479}\u{3D000}-\u{3FC3F}\u{F0000}-\u{FFFFD}\u{100000}-\u{10FFFD}][\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7-\u05C9\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u07FD\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u0897-\u089F\u08CA-\u08E1\u08E3-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962\u0963\u0981\u09BC\u09C1-\u09C4\u09CD\u09E2\u09E3\u09FE\u0A01\u0A02\u0A3C\u0A41\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7\u0AC8\u0ACD\u0AE2\u0AE3\u0AFA-\u0AFF\u0B01\u0B3C\u0B3F\u0B41-\u0B44\u0B4D\u0B53-\u0B56\u0B62\u0B63\u0B82\u0BC0\u0BCD\u0C00\u0C04\u0C3C\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81\u0CBC\u0CCC\u0CCD\u0CE2\u0CE3\u0D00\u0D01\u0D3B\u0D3C\u0D41-\u0D44\u0D4D\u0D62\u0D63\u0D81\u0DCA\u0DD2-\u0DD4\u0DD6\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EBC\u0EC8-\u0ECE\u0F18\u0F19\u0F35\u0F37\u0F39\u0F71-\u0F7E\u0F80-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039\u103A\u103D\u103E\u1058\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085\u1086\u108D\u109D\u135D-\u135F\u1712-\u1714\u1732\u1733\u1752\u1753\u1772\u1773\u17B4\u17B5\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DD\u180B-\u180D\u180F\u1885\u1886\u18A9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193B\u1A17\u1A18\u1A1B\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1AB0-\u1AF0\u1B00-\u1B03\u1B34\u1B36-\u1B39\u1B6B-\u1B73\u1B80\u1B81\u1BA2-\u1BA5\u1BA8\u1BA9\u1BAB-\u1BAD\u1BE6\u1BE8\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1CF8\u1CF9\u1DC0-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302D\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA825\uA826\uA82C\uA8C4\uA8C5\uA8E0-\uA8F1\uA8FF\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uA9BD\uA9E5\uAA29-\uAA2E\uAA31\uAA32\uAA35\uAA36\uAA43\uAA4C\uAA7C\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEC\uAAED\uAAF6\uABE5\uABE8\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F\u{101FD}\u{102E0}\u{10376}-\u{1037A}\u{10A01}-\u{10A03}\u{10A05}\u{10A06}\u{10A0C}-\u{10A0F}\u{10A38}-\u{10A3A}\u{10A3F}\u{10AE5}\u{10AE6}\u{10D24}-\u{10D27}\u{10D69}-\u{10D6D}\u{10EAB}\u{10EAC}\u{10ECB}-\u{10ECF}\u{10EF0}-\u{10EFF}\u{10F46}-\u{10F50}\u{10F82}-\u{10F85}\u{11001}\u{11038}-\u{11046}\u{11070}\u{11073}\u{11074}\u{1107F}-\u{11081}\u{110B3}-\u{110B6}\u{110B9}\u{110BA}\u{110C2}\u{11100}-\u{11102}\u{11127}-\u{1112B}\u{1112D}-\u{11134}\u{11173}\u{11180}\u{11181}\u{111B6}-\u{111BE}\u{111C9}-\u{111CC}\u{111CF}\u{1122F}-\u{11231}\u{11234}\u{11236}\u{11237}\u{1123E}\u{11241}\u{112DF}\u{112E3}-\u{112EA}\u{11300}\u{11301}\u{1133B}\u{1133C}\u{11340}\u{11366}-\u{1136C}\u{11370}-\u{11374}\u{113BB}-\u{113C0}\u{113CE}\u{113D0}\u{113D2}\u{113E1}\u{113E2}\u{11438}-\u{1143F}\u{11442}-\u{11444}\u{11446}\u{1145E}\u{114B3}-\u{114B8}\u{114BA}\u{114BF}\u{114C0}\u{114C2}\u{114C3}\u{115B2}-\u{115B5}\u{115BC}\u{115BD}\u{115BF}\u{115C0}\u{115DC}\u{115DD}\u{11633}-\u{1163A}\u{1163D}\u{1163F}\u{11640}\u{116AB}\u{116AD}\u{116B0}-\u{116B5}\u{116B7}\u{1171D}\u{1171F}\u{11722}-\u{11725}\u{11727}-\u{1172B}\u{1182F}-\u{11837}\u{11839}\u{1183A}\u{1193B}\u{1193C}\u{1193E}\u{11943}\u{119D4}-\u{119D7}\u{119DA}\u{119DB}\u{119E0}\u{11A01}-\u{11A06}\u{11A09}\u{11A0A}\u{11A33}-\u{11A38}\u{11A3B}-\u{11A3E}\u{11A47}\u{11A51}-\u{11A56}\u{11A59}-\u{11A5B}\u{11A8A}-\u{11A96}\u{11A98}\u{11A99}\u{11B60}\u{11B62}-\u{11B64}\u{11B66}\u{11C30}-\u{11C36}\u{11C38}-\u{11C3D}\u{11C92}-\u{11CA7}\u{11CAA}-\u{11CB0}\u{11CB2}\u{11CB3}\u{11CB5}\u{11CB6}\u{11D31}-\u{11D36}\u{11D3A}\u{11D3C}\u{11D3D}\u{11D3F}-\u{11D45}\u{11D47}\u{11D90}\u{11D91}\u{11D95}\u{11D97}\u{11DF0}\u{11EF3}\u{11EF4}\u{11F00}\u{11F01}\u{11F36}-\u{11F3A}\u{11F40}\u{11F42}\u{11F5A}\u{13440}\u{13447}-\u{13455}\u{1611E}-\u{16129}\u{1612D}-\u{1612F}\u{16AF0}-\u{16AF4}\u{16B30}-\u{16B36}\u{16F4F}\u{16F8F}-\u{16F92}\u{16FE4}\u{1BC9D}\u{1BC9E}\u{1CF00}-\u{1CF2D}\u{1CF30}-\u{1CF46}\u{1D127}\u{1D128}\u{1D167}-\u{1D169}\u{1D17B}-\u{1D182}\u{1D185}-\u{1D18B}\u{1D1AA}-\u{1D1AD}\u{1D242}-\u{1D244}\u{1D25B}\u{1D25C}\u{1DA00}-\u{1DA36}\u{1DA3B}-\u{1DA6C}\u{1DA75}\u{1DA84}\u{1DA9B}-\u{1DA9F}\u{1DAA1}-\u{1DAAF}\u{1E000}-\u{1E006}\u{1E008}-\u{1E018}\u{1E01B}-\u{1E021}\u{1E023}\u{1E024}\u{1E026}-\u{1E02A}\u{1E08F}\u{1E130}-\u{1E136}\u{1E2AE}\u{1E2EC}-\u{1E2EF}\u{1E4EC}-\u{1E4EF}\u{1E5EE}\u{1E5EF}\u{1E6E3}\u{1E6E6}\u{1E6EE}\u{1E6EF}\u{1E6F5}\u{1E8D0}-\u{1E8D6}\u{1E944}-\u{1E94A}\u{E0100}-\u{E01EF}]*$/u;
+    module2.exports = {
+      combiningMarks,
+      combiningClassVirama,
+      validZWNJ,
+      bidiDomain,
+      bidiS1LTR,
+      bidiS1RTL,
+      bidiS2,
+      bidiS3,
+      bidiS4EN,
+      bidiS4AN,
+      bidiS5,
+      bidiS6
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/tr46/lib/mappingTable.json
+var require_mappingTable = __commonJS({
+  "scripts/node-portable/node_modules/tr46/lib/mappingTable.json"(exports2, module2) {
+    module2.exports = [[[0, 44], 2], [[45, 46], 2], [47, 2], [[48, 57], 2], [[58, 64], 2], [65, 1, "a"], [66, 1, "b"], [67, 1, "c"], [68, 1, "d"], [69, 1, "e"], [70, 1, "f"], [71, 1, "g"], [72, 1, "h"], [73, 1, "i"], [74, 1, "j"], [75, 1, "k"], [76, 1, "l"], [77, 1, "m"], [78, 1, "n"], [79, 1, "o"], [80, 1, "p"], [81, 1, "q"], [82, 1, "r"], [83, 1, "s"], [84, 1, "t"], [85, 1, "u"], [86, 1, "v"], [87, 1, "w"], [88, 1, "x"], [89, 1, "y"], [90, 1, "z"], [[91, 96], 2], [[97, 122], 2], [[123, 127], 2], [[128, 159], 3], [160, 1, " "], [[161, 167], 2], [168, 1, " \u0308"], [169, 2], [170, 1, "a"], [[171, 172], 2], [173, 7], [174, 2], [175, 1, " \u0304"], [[176, 177], 2], [178, 1, "2"], [179, 1, "3"], [180, 1, " \u0301"], [181, 1, "\u03BC"], [182, 2], [183, 2], [184, 1, " \u0327"], [185, 1, "1"], [186, 1, "o"], [187, 2], [188, 1, "1\u20444"], [189, 1, "1\u20442"], [190, 1, "3\u20444"], [191, 2], [192, 1, "\xE0"], [193, 1, "\xE1"], [194, 1, "\xE2"], [195, 1, "\xE3"], [196, 1, "\xE4"], [197, 1, "\xE5"], [198, 1, "\xE6"], [199, 1, "\xE7"], [200, 1, "\xE8"], [201, 1, "\xE9"], [202, 1, "\xEA"], [203, 1, "\xEB"], [204, 1, "\xEC"], [205, 1, "\xED"], [206, 1, "\xEE"], [207, 1, "\xEF"], [208, 1, "\xF0"], [209, 1, "\xF1"], [210, 1, "\xF2"], [211, 1, "\xF3"], [212, 1, "\xF4"], [213, 1, "\xF5"], [214, 1, "\xF6"], [215, 2], [216, 1, "\xF8"], [217, 1, "\xF9"], [218, 1, "\xFA"], [219, 1, "\xFB"], [220, 1, "\xFC"], [221, 1, "\xFD"], [222, 1, "\xFE"], [223, 6, "ss"], [[224, 246], 2], [247, 2], [[248, 255], 2], [256, 1, "\u0101"], [257, 2], [258, 1, "\u0103"], [259, 2], [260, 1, "\u0105"], [261, 2], [262, 1, "\u0107"], [263, 2], [264, 1, "\u0109"], [265, 2], [266, 1, "\u010B"], [267, 2], [268, 1, "\u010D"], [269, 2], [270, 1, "\u010F"], [271, 2], [272, 1, "\u0111"], [273, 2], [274, 1, "\u0113"], [275, 2], [276, 1, "\u0115"], [277, 2], [278, 1, "\u0117"], [279, 2], [280, 1, "\u0119"], [281, 2], [282, 1, "\u011B"], [283, 2], [284, 1, "\u011D"], [285, 2], [286, 1, "\u011F"], [287, 2], [288, 1, "\u0121"], [289, 2], [290, 1, "\u0123"], [291, 2], [292, 1, "\u0125"], [293, 2], [294, 1, "\u0127"], [295, 2], [296, 1, "\u0129"], [297, 2], [298, 1, "\u012B"], [299, 2], [300, 1, "\u012D"], [301, 2], [302, 1, "\u012F"], [303, 2], [304, 1, "i\u0307"], [305, 2], [[306, 307], 1, "ij"], [308, 1, "\u0135"], [309, 2], [310, 1, "\u0137"], [[311, 312], 2], [313, 1, "\u013A"], [314, 2], [315, 1, "\u013C"], [316, 2], [317, 1, "\u013E"], [318, 2], [[319, 320], 1, "l\xB7"], [321, 1, "\u0142"], [322, 2], [323, 1, "\u0144"], [324, 2], [325, 1, "\u0146"], [326, 2], [327, 1, "\u0148"], [328, 2], [329, 1, "\u02BCn"], [330, 1, "\u014B"], [331, 2], [332, 1, "\u014D"], [333, 2], [334, 1, "\u014F"], [335, 2], [336, 1, "\u0151"], [337, 2], [338, 1, "\u0153"], [339, 2], [340, 1, "\u0155"], [341, 2], [342, 1, "\u0157"], [343, 2], [344, 1, "\u0159"], [345, 2], [346, 1, "\u015B"], [347, 2], [348, 1, "\u015D"], [349, 2], [350, 1, "\u015F"], [351, 2], [352, 1, "\u0161"], [353, 2], [354, 1, "\u0163"], [355, 2], [356, 1, "\u0165"], [357, 2], [358, 1, "\u0167"], [359, 2], [360, 1, "\u0169"], [361, 2], [362, 1, "\u016B"], [363, 2], [364, 1, "\u016D"], [365, 2], [366, 1, "\u016F"], [367, 2], [368, 1, "\u0171"], [369, 2], [370, 1, "\u0173"], [371, 2], [372, 1, "\u0175"], [373, 2], [374, 1, "\u0177"], [375, 2], [376, 1, "\xFF"], [377, 1, "\u017A"], [378, 2], [379, 1, "\u017C"], [380, 2], [381, 1, "\u017E"], [382, 2], [383, 1, "s"], [384, 2], [385, 1, "\u0253"], [386, 1, "\u0183"], [387, 2], [388, 1, "\u0185"], [389, 2], [390, 1, "\u0254"], [391, 1, "\u0188"], [392, 2], [393, 1, "\u0256"], [394, 1, "\u0257"], [395, 1, "\u018C"], [[396, 397], 2], [398, 1, "\u01DD"], [399, 1, "\u0259"], [400, 1, "\u025B"], [401, 1, "\u0192"], [402, 2], [403, 1, "\u0260"], [404, 1, "\u0263"], [405, 2], [406, 1, "\u0269"], [407, 1, "\u0268"], [408, 1, "\u0199"], [[409, 411], 2], [412, 1, "\u026F"], [413, 1, "\u0272"], [414, 2], [415, 1, "\u0275"], [416, 1, "\u01A1"], [417, 2], [418, 1, "\u01A3"], [419, 2], [420, 1, "\u01A5"], [421, 2], [422, 1, "\u0280"], [423, 1, "\u01A8"], [424, 2], [425, 1, "\u0283"], [[426, 427], 2], [428, 1, "\u01AD"], [429, 2], [430, 1, "\u0288"], [431, 1, "\u01B0"], [432, 2], [433, 1, "\u028A"], [434, 1, "\u028B"], [435, 1, "\u01B4"], [436, 2], [437, 1, "\u01B6"], [438, 2], [439, 1, "\u0292"], [440, 1, "\u01B9"], [[441, 443], 2], [444, 1, "\u01BD"], [[445, 451], 2], [[452, 454], 1, "d\u017E"], [[455, 457], 1, "lj"], [[458, 460], 1, "nj"], [461, 1, "\u01CE"], [462, 2], [463, 1, "\u01D0"], [464, 2], [465, 1, "\u01D2"], [466, 2], [467, 1, "\u01D4"], [468, 2], [469, 1, "\u01D6"], [470, 2], [471, 1, "\u01D8"], [472, 2], [473, 1, "\u01DA"], [474, 2], [475, 1, "\u01DC"], [[476, 477], 2], [478, 1, "\u01DF"], [479, 2], [480, 1, "\u01E1"], [481, 2], [482, 1, "\u01E3"], [483, 2], [484, 1, "\u01E5"], [485, 2], [486, 1, "\u01E7"], [487, 2], [488, 1, "\u01E9"], [489, 2], [490, 1, "\u01EB"], [491, 2], [492, 1, "\u01ED"], [493, 2], [494, 1, "\u01EF"], [[495, 496], 2], [[497, 499], 1, "dz"], [500, 1, "\u01F5"], [501, 2], [502, 1, "\u0195"], [503, 1, "\u01BF"], [504, 1, "\u01F9"], [505, 2], [506, 1, "\u01FB"], [507, 2], [508, 1, "\u01FD"], [509, 2], [510, 1, "\u01FF"], [511, 2], [512, 1, "\u0201"], [513, 2], [514, 1, "\u0203"], [515, 2], [516, 1, "\u0205"], [517, 2], [518, 1, "\u0207"], [519, 2], [520, 1, "\u0209"], [521, 2], [522, 1, "\u020B"], [523, 2], [524, 1, "\u020D"], [525, 2], [526, 1, "\u020F"], [527, 2], [528, 1, "\u0211"], [529, 2], [530, 1, "\u0213"], [531, 2], [532, 1, "\u0215"], [533, 2], [534, 1, "\u0217"], [535, 2], [536, 1, "\u0219"], [537, 2], [538, 1, "\u021B"], [539, 2], [540, 1, "\u021D"], [541, 2], [542, 1, "\u021F"], [543, 2], [544, 1, "\u019E"], [545, 2], [546, 1, "\u0223"], [547, 2], [548, 1, "\u0225"], [549, 2], [550, 1, "\u0227"], [551, 2], [552, 1, "\u0229"], [553, 2], [554, 1, "\u022B"], [555, 2], [556, 1, "\u022D"], [557, 2], [558, 1, "\u022F"], [559, 2], [560, 1, "\u0231"], [561, 2], [562, 1, "\u0233"], [563, 2], [[564, 566], 2], [[567, 569], 2], [570, 1, "\u2C65"], [571, 1, "\u023C"], [572, 2], [573, 1, "\u019A"], [574, 1, "\u2C66"], [[575, 576], 2], [577, 1, "\u0242"], [578, 2], [579, 1, "\u0180"], [580, 1, "\u0289"], [581, 1, "\u028C"], [582, 1, "\u0247"], [583, 2], [584, 1, "\u0249"], [585, 2], [586, 1, "\u024B"], [587, 2], [588, 1, "\u024D"], [589, 2], [590, 1, "\u024F"], [591, 2], [[592, 680], 2], [[681, 685], 2], [[686, 687], 2], [688, 1, "h"], [689, 1, "\u0266"], [690, 1, "j"], [691, 1, "r"], [692, 1, "\u0279"], [693, 1, "\u027B"], [694, 1, "\u0281"], [695, 1, "w"], [696, 1, "y"], [[697, 705], 2], [[706, 709], 2], [[710, 721], 2], [[722, 727], 2], [728, 1, " \u0306"], [729, 1, " \u0307"], [730, 1, " \u030A"], [731, 1, " \u0328"], [732, 1, " \u0303"], [733, 1, " \u030B"], [734, 2], [735, 2], [736, 1, "\u0263"], [737, 1, "l"], [738, 1, "s"], [739, 1, "x"], [740, 1, "\u0295"], [[741, 745], 2], [[746, 747], 2], [748, 2], [749, 2], [750, 2], [[751, 767], 2], [[768, 831], 2], [832, 1, "\u0300"], [833, 1, "\u0301"], [834, 2], [835, 1, "\u0313"], [836, 1, "\u0308\u0301"], [837, 1, "\u03B9"], [[838, 846], 2], [847, 7], [[848, 855], 2], [[856, 860], 2], [[861, 863], 2], [[864, 865], 2], [866, 2], [[867, 879], 2], [880, 1, "\u0371"], [881, 2], [882, 1, "\u0373"], [883, 2], [884, 1, "\u02B9"], [885, 2], [886, 1, "\u0377"], [887, 2], [[888, 889], 3], [890, 1, " \u03B9"], [[891, 893], 2], [894, 1, ";"], [895, 1, "\u03F3"], [[896, 899], 3], [900, 1, " \u0301"], [901, 1, " \u0308\u0301"], [902, 1, "\u03AC"], [903, 1, "\xB7"], [904, 1, "\u03AD"], [905, 1, "\u03AE"], [906, 1, "\u03AF"], [907, 3], [908, 1, "\u03CC"], [909, 3], [910, 1, "\u03CD"], [911, 1, "\u03CE"], [912, 2], [913, 1, "\u03B1"], [914, 1, "\u03B2"], [915, 1, "\u03B3"], [916, 1, "\u03B4"], [917, 1, "\u03B5"], [918, 1, "\u03B6"], [919, 1, "\u03B7"], [920, 1, "\u03B8"], [921, 1, "\u03B9"], [922, 1, "\u03BA"], [923, 1, "\u03BB"], [924, 1, "\u03BC"], [925, 1, "\u03BD"], [926, 1, "\u03BE"], [927, 1, "\u03BF"], [928, 1, "\u03C0"], [929, 1, "\u03C1"], [930, 3], [931, 1, "\u03C3"], [932, 1, "\u03C4"], [933, 1, "\u03C5"], [934, 1, "\u03C6"], [935, 1, "\u03C7"], [936, 1, "\u03C8"], [937, 1, "\u03C9"], [938, 1, "\u03CA"], [939, 1, "\u03CB"], [[940, 961], 2], [962, 6, "\u03C3"], [[963, 974], 2], [975, 1, "\u03D7"], [976, 1, "\u03B2"], [977, 1, "\u03B8"], [978, 1, "\u03C5"], [979, 1, "\u03CD"], [980, 1, "\u03CB"], [981, 1, "\u03C6"], [982, 1, "\u03C0"], [983, 2], [984, 1, "\u03D9"], [985, 2], [986, 1, "\u03DB"], [987, 2], [988, 1, "\u03DD"], [989, 2], [990, 1, "\u03DF"], [991, 2], [992, 1, "\u03E1"], [993, 2], [994, 1, "\u03E3"], [995, 2], [996, 1, "\u03E5"], [997, 2], [998, 1, "\u03E7"], [999, 2], [1e3, 1, "\u03E9"], [1001, 2], [1002, 1, "\u03EB"], [1003, 2], [1004, 1, "\u03ED"], [1005, 2], [1006, 1, "\u03EF"], [1007, 2], [1008, 1, "\u03BA"], [1009, 1, "\u03C1"], [1010, 1, "\u03C3"], [1011, 2], [1012, 1, "\u03B8"], [1013, 1, "\u03B5"], [1014, 2], [1015, 1, "\u03F8"], [1016, 2], [1017, 1, "\u03C3"], [1018, 1, "\u03FB"], [1019, 2], [1020, 2], [1021, 1, "\u037B"], [1022, 1, "\u037C"], [1023, 1, "\u037D"], [1024, 1, "\u0450"], [1025, 1, "\u0451"], [1026, 1, "\u0452"], [1027, 1, "\u0453"], [1028, 1, "\u0454"], [1029, 1, "\u0455"], [1030, 1, "\u0456"], [1031, 1, "\u0457"], [1032, 1, "\u0458"], [1033, 1, "\u0459"], [1034, 1, "\u045A"], [1035, 1, "\u045B"], [1036, 1, "\u045C"], [1037, 1, "\u045D"], [1038, 1, "\u045E"], [1039, 1, "\u045F"], [1040, 1, "\u0430"], [1041, 1, "\u0431"], [1042, 1, "\u0432"], [1043, 1, "\u0433"], [1044, 1, "\u0434"], [1045, 1, "\u0435"], [1046, 1, "\u0436"], [1047, 1, "\u0437"], [1048, 1, "\u0438"], [1049, 1, "\u0439"], [1050, 1, "\u043A"], [1051, 1, "\u043B"], [1052, 1, "\u043C"], [1053, 1, "\u043D"], [1054, 1, "\u043E"], [1055, 1, "\u043F"], [1056, 1, "\u0440"], [1057, 1, "\u0441"], [1058, 1, "\u0442"], [1059, 1, "\u0443"], [1060, 1, "\u0444"], [1061, 1, "\u0445"], [1062, 1, "\u0446"], [1063, 1, "\u0447"], [1064, 1, "\u0448"], [1065, 1, "\u0449"], [1066, 1, "\u044A"], [1067, 1, "\u044B"], [1068, 1, "\u044C"], [1069, 1, "\u044D"], [1070, 1, "\u044E"], [1071, 1, "\u044F"], [[1072, 1103], 2], [1104, 2], [[1105, 1116], 2], [1117, 2], [[1118, 1119], 2], [1120, 1, "\u0461"], [1121, 2], [1122, 1, "\u0463"], [1123, 2], [1124, 1, "\u0465"], [1125, 2], [1126, 1, "\u0467"], [1127, 2], [1128, 1, "\u0469"], [1129, 2], [1130, 1, "\u046B"], [1131, 2], [1132, 1, "\u046D"], [1133, 2], [1134, 1, "\u046F"], [1135, 2], [1136, 1, "\u0471"], [1137, 2], [1138, 1, "\u0473"], [1139, 2], [1140, 1, "\u0475"], [1141, 2], [1142, 1, "\u0477"], [1143, 2], [1144, 1, "\u0479"], [1145, 2], [1146, 1, "\u047B"], [1147, 2], [1148, 1, "\u047D"], [1149, 2], [1150, 1, "\u047F"], [1151, 2], [1152, 1, "\u0481"], [1153, 2], [1154, 2], [[1155, 1158], 2], [1159, 2], [[1160, 1161], 2], [1162, 1, "\u048B"], [1163, 2], [1164, 1, "\u048D"], [1165, 2], [1166, 1, "\u048F"], [1167, 2], [1168, 1, "\u0491"], [1169, 2], [1170, 1, "\u0493"], [1171, 2], [1172, 1, "\u0495"], [1173, 2], [1174, 1, "\u0497"], [1175, 2], [1176, 1, "\u0499"], [1177, 2], [1178, 1, "\u049B"], [1179, 2], [1180, 1, "\u049D"], [1181, 2], [1182, 1, "\u049F"], [1183, 2], [1184, 1, "\u04A1"], [1185, 2], [1186, 1, "\u04A3"], [1187, 2], [1188, 1, "\u04A5"], [1189, 2], [1190, 1, "\u04A7"], [1191, 2], [1192, 1, "\u04A9"], [1193, 2], [1194, 1, "\u04AB"], [1195, 2], [1196, 1, "\u04AD"], [1197, 2], [1198, 1, "\u04AF"], [1199, 2], [1200, 1, "\u04B1"], [1201, 2], [1202, 1, "\u04B3"], [1203, 2], [1204, 1, "\u04B5"], [1205, 2], [1206, 1, "\u04B7"], [1207, 2], [1208, 1, "\u04B9"], [1209, 2], [1210, 1, "\u04BB"], [1211, 2], [1212, 1, "\u04BD"], [1213, 2], [1214, 1, "\u04BF"], [1215, 2], [1216, 1, "\u04CF"], [1217, 1, "\u04C2"], [1218, 2], [1219, 1, "\u04C4"], [1220, 2], [1221, 1, "\u04C6"], [1222, 2], [1223, 1, "\u04C8"], [1224, 2], [1225, 1, "\u04CA"], [1226, 2], [1227, 1, "\u04CC"], [1228, 2], [1229, 1, "\u04CE"], [1230, 2], [1231, 2], [1232, 1, "\u04D1"], [1233, 2], [1234, 1, "\u04D3"], [1235, 2], [1236, 1, "\u04D5"], [1237, 2], [1238, 1, "\u04D7"], [1239, 2], [1240, 1, "\u04D9"], [1241, 2], [1242, 1, "\u04DB"], [1243, 2], [1244, 1, "\u04DD"], [1245, 2], [1246, 1, "\u04DF"], [1247, 2], [1248, 1, "\u04E1"], [1249, 2], [1250, 1, "\u04E3"], [1251, 2], [1252, 1, "\u04E5"], [1253, 2], [1254, 1, "\u04E7"], [1255, 2], [1256, 1, "\u04E9"], [1257, 2], [1258, 1, "\u04EB"], [1259, 2], [1260, 1, "\u04ED"], [1261, 2], [1262, 1, "\u04EF"], [1263, 2], [1264, 1, "\u04F1"], [1265, 2], [1266, 1, "\u04F3"], [1267, 2], [1268, 1, "\u04F5"], [1269, 2], [1270, 1, "\u04F7"], [1271, 2], [1272, 1, "\u04F9"], [1273, 2], [1274, 1, "\u04FB"], [1275, 2], [1276, 1, "\u04FD"], [1277, 2], [1278, 1, "\u04FF"], [1279, 2], [1280, 1, "\u0501"], [1281, 2], [1282, 1, "\u0503"], [1283, 2], [1284, 1, "\u0505"], [1285, 2], [1286, 1, "\u0507"], [1287, 2], [1288, 1, "\u0509"], [1289, 2], [1290, 1, "\u050B"], [1291, 2], [1292, 1, "\u050D"], [1293, 2], [1294, 1, "\u050F"], [1295, 2], [1296, 1, "\u0511"], [1297, 2], [1298, 1, "\u0513"], [1299, 2], [1300, 1, "\u0515"], [1301, 2], [1302, 1, "\u0517"], [1303, 2], [1304, 1, "\u0519"], [1305, 2], [1306, 1, "\u051B"], [1307, 2], [1308, 1, "\u051D"], [1309, 2], [1310, 1, "\u051F"], [1311, 2], [1312, 1, "\u0521"], [1313, 2], [1314, 1, "\u0523"], [1315, 2], [1316, 1, "\u0525"], [1317, 2], [1318, 1, "\u0527"], [1319, 2], [1320, 1, "\u0529"], [1321, 2], [1322, 1, "\u052B"], [1323, 2], [1324, 1, "\u052D"], [1325, 2], [1326, 1, "\u052F"], [1327, 2], [1328, 3], [1329, 1, "\u0561"], [1330, 1, "\u0562"], [1331, 1, "\u0563"], [1332, 1, "\u0564"], [1333, 1, "\u0565"], [1334, 1, "\u0566"], [1335, 1, "\u0567"], [1336, 1, "\u0568"], [1337, 1, "\u0569"], [1338, 1, "\u056A"], [1339, 1, "\u056B"], [1340, 1, "\u056C"], [1341, 1, "\u056D"], [1342, 1, "\u056E"], [1343, 1, "\u056F"], [1344, 1, "\u0570"], [1345, 1, "\u0571"], [1346, 1, "\u0572"], [1347, 1, "\u0573"], [1348, 1, "\u0574"], [1349, 1, "\u0575"], [1350, 1, "\u0576"], [1351, 1, "\u0577"], [1352, 1, "\u0578"], [1353, 1, "\u0579"], [1354, 1, "\u057A"], [1355, 1, "\u057B"], [1356, 1, "\u057C"], [1357, 1, "\u057D"], [1358, 1, "\u057E"], [1359, 1, "\u057F"], [1360, 1, "\u0580"], [1361, 1, "\u0581"], [1362, 1, "\u0582"], [1363, 1, "\u0583"], [1364, 1, "\u0584"], [1365, 1, "\u0585"], [1366, 1, "\u0586"], [1367, 3], [1368, 1, "\u0567"], [1369, 2], [[1370, 1375], 2], [1376, 2], [[1377, 1414], 2], [1415, 1, "\u0565\u0582"], [1416, 2], [1417, 2], [1418, 2], [1419, 1, "\u056B"], [1420, 1, "\u0575"], [[1421, 1422], 2], [1423, 2], [1424, 3], [[1425, 1441], 2], [1442, 2], [[1443, 1455], 2], [[1456, 1465], 2], [1466, 2], [[1467, 1469], 2], [1470, 2], [1471, 2], [1472, 2], [[1473, 1474], 2], [1475, 2], [1476, 2], [1477, 2], [1478, 2], [1479, 2], [[1480, 1481], 2], [[1482, 1487], 3], [[1488, 1514], 2], [[1515, 1518], 3], [1519, 2], [[1520, 1524], 2], [[1525, 1535], 3], [[1536, 1539], 3], [1540, 3], [1541, 3], [[1542, 1546], 2], [1547, 2], [1548, 2], [[1549, 1551], 2], [[1552, 1557], 2], [[1558, 1562], 2], [1563, 2], [1564, 3], [1565, 2], [1566, 2], [1567, 2], [1568, 2], [[1569, 1594], 2], [[1595, 1599], 2], [1600, 2], [[1601, 1618], 2], [[1619, 1621], 2], [[1622, 1624], 2], [[1625, 1630], 2], [1631, 2], [[1632, 1641], 2], [[1642, 1645], 2], [[1646, 1647], 2], [[1648, 1652], 2], [1653, 1, "\u0627\u0674"], [1654, 1, "\u0648\u0674"], [1655, 1, "\u06C7\u0674"], [1656, 1, "\u064A\u0674"], [[1657, 1719], 2], [[1720, 1721], 2], [[1722, 1726], 2], [1727, 2], [[1728, 1742], 2], [1743, 2], [[1744, 1747], 2], [1748, 2], [[1749, 1756], 2], [1757, 3], [1758, 2], [[1759, 1768], 2], [1769, 2], [[1770, 1773], 2], [[1774, 1775], 2], [[1776, 1785], 2], [[1786, 1790], 2], [1791, 2], [[1792, 1805], 2], [1806, 3], [1807, 3], [[1808, 1836], 2], [[1837, 1839], 2], [[1840, 1866], 2], [[1867, 1868], 3], [[1869, 1871], 2], [[1872, 1901], 2], [[1902, 1919], 2], [[1920, 1968], 2], [1969, 2], [[1970, 1983], 3], [[1984, 2037], 2], [[2038, 2042], 2], [[2043, 2044], 3], [2045, 2], [[2046, 2047], 2], [[2048, 2093], 2], [[2094, 2095], 3], [[2096, 2110], 2], [2111, 3], [[2112, 2139], 2], [[2140, 2141], 3], [2142, 2], [2143, 3], [[2144, 2154], 2], [[2155, 2159], 3], [[2160, 2183], 2], [2184, 2], [[2185, 2190], 2], [2191, 2], [[2192, 2193], 3], [[2194, 2198], 3], [2199, 2], [[2200, 2207], 2], [2208, 2], [2209, 2], [[2210, 2220], 2], [[2221, 2226], 2], [[2227, 2228], 2], [2229, 2], [[2230, 2237], 2], [[2238, 2247], 2], [[2248, 2258], 2], [2259, 2], [[2260, 2273], 2], [2274, 3], [2275, 2], [[2276, 2302], 2], [2303, 2], [2304, 2], [[2305, 2307], 2], [2308, 2], [[2309, 2361], 2], [[2362, 2363], 2], [[2364, 2381], 2], [2382, 2], [2383, 2], [[2384, 2388], 2], [2389, 2], [[2390, 2391], 2], [2392, 1, "\u0915\u093C"], [2393, 1, "\u0916\u093C"], [2394, 1, "\u0917\u093C"], [2395, 1, "\u091C\u093C"], [2396, 1, "\u0921\u093C"], [2397, 1, "\u0922\u093C"], [2398, 1, "\u092B\u093C"], [2399, 1, "\u092F\u093C"], [[2400, 2403], 2], [[2404, 2405], 2], [[2406, 2415], 2], [2416, 2], [[2417, 2418], 2], [[2419, 2423], 2], [2424, 2], [[2425, 2426], 2], [[2427, 2428], 2], [2429, 2], [[2430, 2431], 2], [2432, 2], [[2433, 2435], 2], [2436, 3], [[2437, 2444], 2], [[2445, 2446], 3], [[2447, 2448], 2], [[2449, 2450], 3], [[2451, 2472], 2], [2473, 3], [[2474, 2480], 2], [2481, 3], [2482, 2], [[2483, 2485], 3], [[2486, 2489], 2], [[2490, 2491], 3], [2492, 2], [2493, 2], [[2494, 2500], 2], [[2501, 2502], 3], [[2503, 2504], 2], [[2505, 2506], 3], [[2507, 2509], 2], [2510, 2], [[2511, 2518], 3], [2519, 2], [[2520, 2523], 3], [2524, 1, "\u09A1\u09BC"], [2525, 1, "\u09A2\u09BC"], [2526, 3], [2527, 1, "\u09AF\u09BC"], [[2528, 2531], 2], [[2532, 2533], 3], [[2534, 2545], 2], [[2546, 2554], 2], [2555, 2], [2556, 2], [2557, 2], [2558, 2], [[2559, 2560], 3], [2561, 2], [2562, 2], [2563, 2], [2564, 3], [[2565, 2570], 2], [[2571, 2574], 3], [[2575, 2576], 2], [[2577, 2578], 3], [[2579, 2600], 2], [2601, 3], [[2602, 2608], 2], [2609, 3], [2610, 2], [2611, 1, "\u0A32\u0A3C"], [2612, 3], [2613, 2], [2614, 1, "\u0A38\u0A3C"], [2615, 3], [[2616, 2617], 2], [[2618, 2619], 3], [2620, 2], [2621, 3], [[2622, 2626], 2], [[2627, 2630], 3], [[2631, 2632], 2], [[2633, 2634], 3], [[2635, 2637], 2], [[2638, 2640], 3], [2641, 2], [[2642, 2648], 3], [2649, 1, "\u0A16\u0A3C"], [2650, 1, "\u0A17\u0A3C"], [2651, 1, "\u0A1C\u0A3C"], [2652, 2], [2653, 3], [2654, 1, "\u0A2B\u0A3C"], [[2655, 2661], 3], [[2662, 2676], 2], [2677, 2], [2678, 2], [[2679, 2688], 3], [[2689, 2691], 2], [2692, 3], [[2693, 2699], 2], [2700, 2], [2701, 2], [2702, 3], [[2703, 2705], 2], [2706, 3], [[2707, 2728], 2], [2729, 3], [[2730, 2736], 2], [2737, 3], [[2738, 2739], 2], [2740, 3], [[2741, 2745], 2], [[2746, 2747], 3], [[2748, 2757], 2], [2758, 3], [[2759, 2761], 2], [2762, 3], [[2763, 2765], 2], [[2766, 2767], 3], [2768, 2], [[2769, 2783], 3], [2784, 2], [[2785, 2787], 2], [[2788, 2789], 3], [[2790, 2799], 2], [2800, 2], [2801, 2], [[2802, 2808], 3], [2809, 2], [[2810, 2815], 2], [2816, 3], [[2817, 2819], 2], [2820, 3], [[2821, 2828], 2], [[2829, 2830], 3], [[2831, 2832], 2], [[2833, 2834], 3], [[2835, 2856], 2], [2857, 3], [[2858, 2864], 2], [2865, 3], [[2866, 2867], 2], [2868, 3], [2869, 2], [[2870, 2873], 2], [[2874, 2875], 3], [[2876, 2883], 2], [2884, 2], [[2885, 2886], 3], [[2887, 2888], 2], [[2889, 2890], 3], [[2891, 2893], 2], [[2894, 2898], 3], [[2899, 2900], 2], [2901, 2], [[2902, 2903], 2], [[2904, 2907], 3], [2908, 1, "\u0B21\u0B3C"], [2909, 1, "\u0B22\u0B3C"], [2910, 3], [[2911, 2913], 2], [[2914, 2915], 2], [[2916, 2917], 3], [[2918, 2927], 2], [2928, 2], [2929, 2], [[2930, 2935], 2], [[2936, 2945], 3], [[2946, 2947], 2], [2948, 3], [[2949, 2954], 2], [[2955, 2957], 3], [[2958, 2960], 2], [2961, 3], [[2962, 2965], 2], [[2966, 2968], 3], [[2969, 2970], 2], [2971, 3], [2972, 2], [2973, 3], [[2974, 2975], 2], [[2976, 2978], 3], [[2979, 2980], 2], [[2981, 2983], 3], [[2984, 2986], 2], [[2987, 2989], 3], [[2990, 2997], 2], [2998, 2], [[2999, 3001], 2], [[3002, 3005], 3], [[3006, 3010], 2], [[3011, 3013], 3], [[3014, 3016], 2], [3017, 3], [[3018, 3021], 2], [[3022, 3023], 3], [3024, 2], [[3025, 3030], 3], [3031, 2], [[3032, 3045], 3], [3046, 2], [[3047, 3055], 2], [[3056, 3058], 2], [[3059, 3066], 2], [[3067, 3071], 3], [3072, 2], [[3073, 3075], 2], [3076, 2], [[3077, 3084], 2], [3085, 3], [[3086, 3088], 2], [3089, 3], [[3090, 3112], 2], [3113, 3], [[3114, 3123], 2], [3124, 2], [[3125, 3129], 2], [[3130, 3131], 3], [3132, 2], [3133, 2], [[3134, 3140], 2], [3141, 3], [[3142, 3144], 2], [3145, 3], [[3146, 3149], 2], [[3150, 3156], 3], [[3157, 3158], 2], [3159, 3], [[3160, 3161], 2], [3162, 2], [3163, 3], [3164, 2], [3165, 2], [[3166, 3167], 3], [[3168, 3169], 2], [[3170, 3171], 2], [[3172, 3173], 3], [[3174, 3183], 2], [[3184, 3190], 3], [3191, 2], [[3192, 3199], 2], [3200, 2], [3201, 2], [[3202, 3203], 2], [3204, 2], [[3205, 3212], 2], [3213, 3], [[3214, 3216], 2], [3217, 3], [[3218, 3240], 2], [3241, 3], [[3242, 3251], 2], [3252, 3], [[3253, 3257], 2], [[3258, 3259], 3], [[3260, 3261], 2], [[3262, 3268], 2], [3269, 3], [[3270, 3272], 2], [3273, 3], [[3274, 3277], 2], [[3278, 3284], 3], [[3285, 3286], 2], [[3287, 3291], 3], [3292, 2], [3293, 2], [3294, 2], [3295, 3], [[3296, 3297], 2], [[3298, 3299], 2], [[3300, 3301], 3], [[3302, 3311], 2], [3312, 3], [[3313, 3314], 2], [3315, 2], [[3316, 3327], 3], [3328, 2], [3329, 2], [[3330, 3331], 2], [3332, 2], [[3333, 3340], 2], [3341, 3], [[3342, 3344], 2], [3345, 3], [[3346, 3368], 2], [3369, 2], [[3370, 3385], 2], [3386, 2], [[3387, 3388], 2], [3389, 2], [[3390, 3395], 2], [3396, 2], [3397, 3], [[3398, 3400], 2], [3401, 3], [[3402, 3405], 2], [3406, 2], [3407, 2], [[3408, 3411], 3], [[3412, 3414], 2], [3415, 2], [[3416, 3422], 2], [3423, 2], [[3424, 3425], 2], [[3426, 3427], 2], [[3428, 3429], 3], [[3430, 3439], 2], [[3440, 3445], 2], [[3446, 3448], 2], [3449, 2], [[3450, 3455], 2], [3456, 3], [3457, 2], [[3458, 3459], 2], [3460, 3], [[3461, 3478], 2], [[3479, 3481], 3], [[3482, 3505], 2], [3506, 3], [[3507, 3515], 2], [3516, 3], [3517, 2], [[3518, 3519], 3], [[3520, 3526], 2], [[3527, 3529], 3], [3530, 2], [[3531, 3534], 3], [[3535, 3540], 2], [3541, 3], [3542, 2], [3543, 3], [[3544, 3551], 2], [[3552, 3557], 3], [[3558, 3567], 2], [[3568, 3569], 3], [[3570, 3571], 2], [3572, 2], [[3573, 3584], 3], [[3585, 3634], 2], [3635, 1, "\u0E4D\u0E32"], [[3636, 3642], 2], [[3643, 3646], 3], [3647, 2], [[3648, 3662], 2], [3663, 2], [[3664, 3673], 2], [[3674, 3675], 2], [[3676, 3712], 3], [[3713, 3714], 2], [3715, 3], [3716, 2], [3717, 3], [3718, 2], [[3719, 3720], 2], [3721, 2], [3722, 2], [3723, 3], [3724, 2], [3725, 2], [[3726, 3731], 2], [[3732, 3735], 2], [3736, 2], [[3737, 3743], 2], [3744, 2], [[3745, 3747], 2], [3748, 3], [3749, 2], [3750, 3], [3751, 2], [[3752, 3753], 2], [[3754, 3755], 2], [3756, 2], [[3757, 3762], 2], [3763, 1, "\u0ECD\u0EB2"], [[3764, 3769], 2], [3770, 2], [[3771, 3773], 2], [[3774, 3775], 3], [[3776, 3780], 2], [3781, 3], [3782, 2], [3783, 3], [[3784, 3789], 2], [3790, 2], [3791, 3], [[3792, 3801], 2], [[3802, 3803], 3], [3804, 1, "\u0EAB\u0E99"], [3805, 1, "\u0EAB\u0EA1"], [[3806, 3807], 2], [[3808, 3839], 3], [3840, 2], [[3841, 3850], 2], [3851, 2], [3852, 1, "\u0F0B"], [[3853, 3863], 2], [[3864, 3865], 2], [[3866, 3871], 2], [[3872, 3881], 2], [[3882, 3892], 2], [3893, 2], [3894, 2], [3895, 2], [3896, 2], [3897, 2], [[3898, 3901], 2], [[3902, 3906], 2], [3907, 1, "\u0F42\u0FB7"], [[3908, 3911], 2], [3912, 3], [[3913, 3916], 2], [3917, 1, "\u0F4C\u0FB7"], [[3918, 3921], 2], [3922, 1, "\u0F51\u0FB7"], [[3923, 3926], 2], [3927, 1, "\u0F56\u0FB7"], [[3928, 3931], 2], [3932, 1, "\u0F5B\u0FB7"], [[3933, 3944], 2], [3945, 1, "\u0F40\u0FB5"], [3946, 2], [[3947, 3948], 2], [[3949, 3952], 3], [[3953, 3954], 2], [3955, 1, "\u0F71\u0F72"], [3956, 2], [3957, 1, "\u0F71\u0F74"], [3958, 1, "\u0FB2\u0F80"], [3959, 1, "\u0FB2\u0F71\u0F80"], [3960, 1, "\u0FB3\u0F80"], [3961, 1, "\u0FB3\u0F71\u0F80"], [[3962, 3968], 2], [3969, 1, "\u0F71\u0F80"], [[3970, 3972], 2], [3973, 2], [[3974, 3979], 2], [[3980, 3983], 2], [[3984, 3986], 2], [3987, 1, "\u0F92\u0FB7"], [[3988, 3989], 2], [3990, 2], [3991, 2], [3992, 3], [[3993, 3996], 2], [3997, 1, "\u0F9C\u0FB7"], [[3998, 4001], 2], [4002, 1, "\u0FA1\u0FB7"], [[4003, 4006], 2], [4007, 1, "\u0FA6\u0FB7"], [[4008, 4011], 2], [4012, 1, "\u0FAB\u0FB7"], [4013, 2], [[4014, 4016], 2], [[4017, 4023], 2], [4024, 2], [4025, 1, "\u0F90\u0FB5"], [[4026, 4028], 2], [4029, 3], [[4030, 4037], 2], [4038, 2], [[4039, 4044], 2], [4045, 3], [4046, 2], [4047, 2], [[4048, 4049], 2], [[4050, 4052], 2], [[4053, 4056], 2], [[4057, 4058], 2], [[4059, 4095], 3], [[4096, 4129], 2], [4130, 2], [[4131, 4135], 2], [4136, 2], [[4137, 4138], 2], [4139, 2], [[4140, 4146], 2], [[4147, 4149], 2], [[4150, 4153], 2], [[4154, 4159], 2], [[4160, 4169], 2], [[4170, 4175], 2], [[4176, 4185], 2], [[4186, 4249], 2], [[4250, 4253], 2], [[4254, 4255], 2], [4256, 1, "\u2D00"], [4257, 1, "\u2D01"], [4258, 1, "\u2D02"], [4259, 1, "\u2D03"], [4260, 1, "\u2D04"], [4261, 1, "\u2D05"], [4262, 1, "\u2D06"], [4263, 1, "\u2D07"], [4264, 1, "\u2D08"], [4265, 1, "\u2D09"], [4266, 1, "\u2D0A"], [4267, 1, "\u2D0B"], [4268, 1, "\u2D0C"], [4269, 1, "\u2D0D"], [4270, 1, "\u2D0E"], [4271, 1, "\u2D0F"], [4272, 1, "\u2D10"], [4273, 1, "\u2D11"], [4274, 1, "\u2D12"], [4275, 1, "\u2D13"], [4276, 1, "\u2D14"], [4277, 1, "\u2D15"], [4278, 1, "\u2D16"], [4279, 1, "\u2D17"], [4280, 1, "\u2D18"], [4281, 1, "\u2D19"], [4282, 1, "\u2D1A"], [4283, 1, "\u2D1B"], [4284, 1, "\u2D1C"], [4285, 1, "\u2D1D"], [4286, 1, "\u2D1E"], [4287, 1, "\u2D1F"], [4288, 1, "\u2D20"], [4289, 1, "\u2D21"], [4290, 1, "\u2D22"], [4291, 1, "\u2D23"], [4292, 1, "\u2D24"], [4293, 1, "\u2D25"], [4294, 3], [4295, 1, "\u2D27"], [[4296, 4300], 3], [4301, 1, "\u2D2D"], [[4302, 4303], 3], [[4304, 4342], 2], [[4343, 4344], 2], [[4345, 4346], 2], [4347, 2], [4348, 1, "\u10DC"], [[4349, 4351], 2], [[4352, 4441], 2], [[4442, 4446], 2], [[4447, 4448], 7], [[4449, 4514], 2], [[4515, 4519], 2], [[4520, 4601], 2], [[4602, 4607], 2], [[4608, 4614], 2], [4615, 2], [[4616, 4678], 2], [4679, 2], [4680, 2], [4681, 3], [[4682, 4685], 2], [[4686, 4687], 3], [[4688, 4694], 2], [4695, 3], [4696, 2], [4697, 3], [[4698, 4701], 2], [[4702, 4703], 3], [[4704, 4742], 2], [4743, 2], [4744, 2], [4745, 3], [[4746, 4749], 2], [[4750, 4751], 3], [[4752, 4782], 2], [4783, 2], [4784, 2], [4785, 3], [[4786, 4789], 2], [[4790, 4791], 3], [[4792, 4798], 2], [4799, 3], [4800, 2], [4801, 3], [[4802, 4805], 2], [[4806, 4807], 3], [[4808, 4814], 2], [4815, 2], [[4816, 4822], 2], [4823, 3], [[4824, 4846], 2], [4847, 2], [[4848, 4878], 2], [4879, 2], [4880, 2], [4881, 3], [[4882, 4885], 2], [[4886, 4887], 3], [[4888, 4894], 2], [4895, 2], [[4896, 4934], 2], [4935, 2], [[4936, 4954], 2], [[4955, 4956], 3], [[4957, 4958], 2], [4959, 2], [4960, 2], [[4961, 4988], 2], [[4989, 4991], 3], [[4992, 5007], 2], [[5008, 5017], 2], [[5018, 5023], 3], [[5024, 5108], 2], [5109, 2], [[5110, 5111], 3], [5112, 1, "\u13F0"], [5113, 1, "\u13F1"], [5114, 1, "\u13F2"], [5115, 1, "\u13F3"], [5116, 1, "\u13F4"], [5117, 1, "\u13F5"], [[5118, 5119], 3], [5120, 2], [[5121, 5740], 2], [[5741, 5742], 2], [[5743, 5750], 2], [[5751, 5759], 2], [5760, 3], [[5761, 5786], 2], [[5787, 5788], 2], [[5789, 5791], 3], [[5792, 5866], 2], [[5867, 5872], 2], [[5873, 5880], 2], [[5881, 5887], 3], [[5888, 5900], 2], [5901, 2], [[5902, 5908], 2], [5909, 2], [[5910, 5918], 3], [5919, 2], [[5920, 5940], 2], [[5941, 5942], 2], [[5943, 5951], 3], [[5952, 5971], 2], [[5972, 5983], 3], [[5984, 5996], 2], [5997, 3], [[5998, 6e3], 2], [6001, 3], [[6002, 6003], 2], [[6004, 6015], 3], [[6016, 6067], 2], [[6068, 6069], 7], [[6070, 6099], 2], [[6100, 6102], 2], [6103, 2], [[6104, 6107], 2], [6108, 2], [6109, 2], [[6110, 6111], 3], [[6112, 6121], 2], [[6122, 6127], 3], [[6128, 6137], 2], [[6138, 6143], 3], [[6144, 6154], 2], [[6155, 6158], 7], [6159, 7], [[6160, 6169], 2], [[6170, 6175], 3], [[6176, 6263], 2], [6264, 2], [[6265, 6271], 3], [[6272, 6313], 2], [6314, 2], [[6315, 6319], 3], [[6320, 6389], 2], [[6390, 6399], 3], [[6400, 6428], 2], [[6429, 6430], 2], [6431, 3], [[6432, 6443], 2], [[6444, 6447], 3], [[6448, 6459], 2], [[6460, 6463], 3], [6464, 2], [[6465, 6467], 3], [[6468, 6469], 2], [[6470, 6509], 2], [[6510, 6511], 3], [[6512, 6516], 2], [[6517, 6527], 3], [[6528, 6569], 2], [[6570, 6571], 2], [[6572, 6575], 3], [[6576, 6601], 2], [[6602, 6607], 3], [[6608, 6617], 2], [6618, 2], [[6619, 6621], 3], [[6622, 6623], 2], [[6624, 6655], 2], [[6656, 6683], 2], [[6684, 6685], 3], [[6686, 6687], 2], [[6688, 6750], 2], [6751, 3], [[6752, 6780], 2], [[6781, 6782], 3], [[6783, 6793], 2], [[6794, 6799], 3], [[6800, 6809], 2], [[6810, 6815], 3], [[6816, 6822], 2], [6823, 2], [[6824, 6829], 2], [[6830, 6831], 3], [[6832, 6845], 2], [6846, 2], [[6847, 6848], 2], [[6849, 6862], 2], [[6863, 6877], 2], [[6878, 6879], 2], [[6880, 6891], 2], [[6892, 6896], 2], [[6897, 6911], 3], [[6912, 6987], 2], [6988, 2], [6989, 3], [[6990, 6991], 2], [[6992, 7001], 2], [[7002, 7018], 2], [[7019, 7027], 2], [[7028, 7036], 2], [[7037, 7038], 2], [7039, 2], [[7040, 7082], 2], [[7083, 7085], 2], [[7086, 7097], 2], [[7098, 7103], 2], [[7104, 7155], 2], [[7156, 7163], 3], [[7164, 7167], 2], [[7168, 7223], 2], [[7224, 7226], 3], [[7227, 7231], 2], [[7232, 7241], 2], [[7242, 7244], 3], [[7245, 7293], 2], [[7294, 7295], 2], [7296, 1, "\u0432"], [7297, 1, "\u0434"], [7298, 1, "\u043E"], [7299, 1, "\u0441"], [[7300, 7301], 1, "\u0442"], [7302, 1, "\u044A"], [7303, 1, "\u0463"], [7304, 1, "\uA64B"], [7305, 1, "\u1C8A"], [7306, 2], [[7307, 7311], 3], [7312, 1, "\u10D0"], [7313, 1, "\u10D1"], [7314, 1, "\u10D2"], [7315, 1, "\u10D3"], [7316, 1, "\u10D4"], [7317, 1, "\u10D5"], [7318, 1, "\u10D6"], [7319, 1, "\u10D7"], [7320, 1, "\u10D8"], [7321, 1, "\u10D9"], [7322, 1, "\u10DA"], [7323, 1, "\u10DB"], [7324, 1, "\u10DC"], [7325, 1, "\u10DD"], [7326, 1, "\u10DE"], [7327, 1, "\u10DF"], [7328, 1, "\u10E0"], [7329, 1, "\u10E1"], [7330, 1, "\u10E2"], [7331, 1, "\u10E3"], [7332, 1, "\u10E4"], [7333, 1, "\u10E5"], [7334, 1, "\u10E6"], [7335, 1, "\u10E7"], [7336, 1, "\u10E8"], [7337, 1, "\u10E9"], [7338, 1, "\u10EA"], [7339, 1, "\u10EB"], [7340, 1, "\u10EC"], [7341, 1, "\u10ED"], [7342, 1, "\u10EE"], [7343, 1, "\u10EF"], [7344, 1, "\u10F0"], [7345, 1, "\u10F1"], [7346, 1, "\u10F2"], [7347, 1, "\u10F3"], [7348, 1, "\u10F4"], [7349, 1, "\u10F5"], [7350, 1, "\u10F6"], [7351, 1, "\u10F7"], [7352, 1, "\u10F8"], [7353, 1, "\u10F9"], [7354, 1, "\u10FA"], [[7355, 7356], 3], [7357, 1, "\u10FD"], [7358, 1, "\u10FE"], [7359, 1, "\u10FF"], [[7360, 7367], 2], [[7368, 7375], 3], [[7376, 7378], 2], [7379, 2], [[7380, 7410], 2], [[7411, 7414], 2], [7415, 2], [[7416, 7417], 2], [7418, 2], [[7419, 7423], 3], [[7424, 7467], 2], [7468, 1, "a"], [7469, 1, "\xE6"], [7470, 1, "b"], [7471, 2], [7472, 1, "d"], [7473, 1, "e"], [7474, 1, "\u01DD"], [7475, 1, "g"], [7476, 1, "h"], [7477, 1, "i"], [7478, 1, "j"], [7479, 1, "k"], [7480, 1, "l"], [7481, 1, "m"], [7482, 1, "n"], [7483, 2], [7484, 1, "o"], [7485, 1, "\u0223"], [7486, 1, "p"], [7487, 1, "r"], [7488, 1, "t"], [7489, 1, "u"], [7490, 1, "w"], [7491, 1, "a"], [7492, 1, "\u0250"], [7493, 1, "\u0251"], [7494, 1, "\u1D02"], [7495, 1, "b"], [7496, 1, "d"], [7497, 1, "e"], [7498, 1, "\u0259"], [7499, 1, "\u025B"], [7500, 1, "\u025C"], [7501, 1, "g"], [7502, 2], [7503, 1, "k"], [7504, 1, "m"], [7505, 1, "\u014B"], [7506, 1, "o"], [7507, 1, "\u0254"], [7508, 1, "\u1D16"], [7509, 1, "\u1D17"], [7510, 1, "p"], [7511, 1, "t"], [7512, 1, "u"], [7513, 1, "\u1D1D"], [7514, 1, "\u026F"], [7515, 1, "v"], [7516, 1, "\u1D25"], [7517, 1, "\u03B2"], [7518, 1, "\u03B3"], [7519, 1, "\u03B4"], [7520, 1, "\u03C6"], [7521, 1, "\u03C7"], [7522, 1, "i"], [7523, 1, "r"], [7524, 1, "u"], [7525, 1, "v"], [7526, 1, "\u03B2"], [7527, 1, "\u03B3"], [7528, 1, "\u03C1"], [7529, 1, "\u03C6"], [7530, 1, "\u03C7"], [7531, 2], [[7532, 7543], 2], [7544, 1, "\u043D"], [[7545, 7578], 2], [7579, 1, "\u0252"], [7580, 1, "c"], [7581, 1, "\u0255"], [7582, 1, "\xF0"], [7583, 1, "\u025C"], [7584, 1, "f"], [7585, 1, "\u025F"], [7586, 1, "\u0261"], [7587, 1, "\u0265"], [7588, 1, "\u0268"], [7589, 1, "\u0269"], [7590, 1, "\u026A"], [7591, 1, "\u1D7B"], [7592, 1, "\u029D"], [7593, 1, "\u026D"], [7594, 1, "\u1D85"], [7595, 1, "\u029F"], [7596, 1, "\u0271"], [7597, 1, "\u0270"], [7598, 1, "\u0272"], [7599, 1, "\u0273"], [7600, 1, "\u0274"], [7601, 1, "\u0275"], [7602, 1, "\u0278"], [7603, 1, "\u0282"], [7604, 1, "\u0283"], [7605, 1, "\u01AB"], [7606, 1, "\u0289"], [7607, 1, "\u028A"], [7608, 1, "\u1D1C"], [7609, 1, "\u028B"], [7610, 1, "\u028C"], [7611, 1, "z"], [7612, 1, "\u0290"], [7613, 1, "\u0291"], [7614, 1, "\u0292"], [7615, 1, "\u03B8"], [[7616, 7619], 2], [[7620, 7626], 2], [[7627, 7654], 2], [[7655, 7669], 2], [[7670, 7673], 2], [7674, 2], [7675, 2], [7676, 2], [7677, 2], [[7678, 7679], 2], [7680, 1, "\u1E01"], [7681, 2], [7682, 1, "\u1E03"], [7683, 2], [7684, 1, "\u1E05"], [7685, 2], [7686, 1, "\u1E07"], [7687, 2], [7688, 1, "\u1E09"], [7689, 2], [7690, 1, "\u1E0B"], [7691, 2], [7692, 1, "\u1E0D"], [7693, 2], [7694, 1, "\u1E0F"], [7695, 2], [7696, 1, "\u1E11"], [7697, 2], [7698, 1, "\u1E13"], [7699, 2], [7700, 1, "\u1E15"], [7701, 2], [7702, 1, "\u1E17"], [7703, 2], [7704, 1, "\u1E19"], [7705, 2], [7706, 1, "\u1E1B"], [7707, 2], [7708, 1, "\u1E1D"], [7709, 2], [7710, 1, "\u1E1F"], [7711, 2], [7712, 1, "\u1E21"], [7713, 2], [7714, 1, "\u1E23"], [7715, 2], [7716, 1, "\u1E25"], [7717, 2], [7718, 1, "\u1E27"], [7719, 2], [7720, 1, "\u1E29"], [7721, 2], [7722, 1, "\u1E2B"], [7723, 2], [7724, 1, "\u1E2D"], [7725, 2], [7726, 1, "\u1E2F"], [7727, 2], [7728, 1, "\u1E31"], [7729, 2], [7730, 1, "\u1E33"], [7731, 2], [7732, 1, "\u1E35"], [7733, 2], [7734, 1, "\u1E37"], [7735, 2], [7736, 1, "\u1E39"], [7737, 2], [7738, 1, "\u1E3B"], [7739, 2], [7740, 1, "\u1E3D"], [7741, 2], [7742, 1, "\u1E3F"], [7743, 2], [7744, 1, "\u1E41"], [7745, 2], [7746, 1, "\u1E43"], [7747, 2], [7748, 1, "\u1E45"], [7749, 2], [7750, 1, "\u1E47"], [7751, 2], [7752, 1, "\u1E49"], [7753, 2], [7754, 1, "\u1E4B"], [7755, 2], [7756, 1, "\u1E4D"], [7757, 2], [7758, 1, "\u1E4F"], [7759, 2], [7760, 1, "\u1E51"], [7761, 2], [7762, 1, "\u1E53"], [7763, 2], [7764, 1, "\u1E55"], [7765, 2], [7766, 1, "\u1E57"], [7767, 2], [7768, 1, "\u1E59"], [7769, 2], [7770, 1, "\u1E5B"], [7771, 2], [7772, 1, "\u1E5D"], [7773, 2], [7774, 1, "\u1E5F"], [7775, 2], [7776, 1, "\u1E61"], [7777, 2], [7778, 1, "\u1E63"], [7779, 2], [7780, 1, "\u1E65"], [7781, 2], [7782, 1, "\u1E67"], [7783, 2], [7784, 1, "\u1E69"], [7785, 2], [7786, 1, "\u1E6B"], [7787, 2], [7788, 1, "\u1E6D"], [7789, 2], [7790, 1, "\u1E6F"], [7791, 2], [7792, 1, "\u1E71"], [7793, 2], [7794, 1, "\u1E73"], [7795, 2], [7796, 1, "\u1E75"], [7797, 2], [7798, 1, "\u1E77"], [7799, 2], [7800, 1, "\u1E79"], [7801, 2], [7802, 1, "\u1E7B"], [7803, 2], [7804, 1, "\u1E7D"], [7805, 2], [7806, 1, "\u1E7F"], [7807, 2], [7808, 1, "\u1E81"], [7809, 2], [7810, 1, "\u1E83"], [7811, 2], [7812, 1, "\u1E85"], [7813, 2], [7814, 1, "\u1E87"], [7815, 2], [7816, 1, "\u1E89"], [7817, 2], [7818, 1, "\u1E8B"], [7819, 2], [7820, 1, "\u1E8D"], [7821, 2], [7822, 1, "\u1E8F"], [7823, 2], [7824, 1, "\u1E91"], [7825, 2], [7826, 1, "\u1E93"], [7827, 2], [7828, 1, "\u1E95"], [[7829, 7833], 2], [7834, 1, "a\u02BE"], [7835, 1, "\u1E61"], [[7836, 7837], 2], [7838, 1, "\xDF"], [7839, 2], [7840, 1, "\u1EA1"], [7841, 2], [7842, 1, "\u1EA3"], [7843, 2], [7844, 1, "\u1EA5"], [7845, 2], [7846, 1, "\u1EA7"], [7847, 2], [7848, 1, "\u1EA9"], [7849, 2], [7850, 1, "\u1EAB"], [7851, 2], [7852, 1, "\u1EAD"], [7853, 2], [7854, 1, "\u1EAF"], [7855, 2], [7856, 1, "\u1EB1"], [7857, 2], [7858, 1, "\u1EB3"], [7859, 2], [7860, 1, "\u1EB5"], [7861, 2], [7862, 1, "\u1EB7"], [7863, 2], [7864, 1, "\u1EB9"], [7865, 2], [7866, 1, "\u1EBB"], [7867, 2], [7868, 1, "\u1EBD"], [7869, 2], [7870, 1, "\u1EBF"], [7871, 2], [7872, 1, "\u1EC1"], [7873, 2], [7874, 1, "\u1EC3"], [7875, 2], [7876, 1, "\u1EC5"], [7877, 2], [7878, 1, "\u1EC7"], [7879, 2], [7880, 1, "\u1EC9"], [7881, 2], [7882, 1, "\u1ECB"], [7883, 2], [7884, 1, "\u1ECD"], [7885, 2], [7886, 1, "\u1ECF"], [7887, 2], [7888, 1, "\u1ED1"], [7889, 2], [7890, 1, "\u1ED3"], [7891, 2], [7892, 1, "\u1ED5"], [7893, 2], [7894, 1, "\u1ED7"], [7895, 2], [7896, 1, "\u1ED9"], [7897, 2], [7898, 1, "\u1EDB"], [7899, 2], [7900, 1, "\u1EDD"], [7901, 2], [7902, 1, "\u1EDF"], [7903, 2], [7904, 1, "\u1EE1"], [7905, 2], [7906, 1, "\u1EE3"], [7907, 2], [7908, 1, "\u1EE5"], [7909, 2], [7910, 1, "\u1EE7"], [7911, 2], [7912, 1, "\u1EE9"], [7913, 2], [7914, 1, "\u1EEB"], [7915, 2], [7916, 1, "\u1EED"], [7917, 2], [7918, 1, "\u1EEF"], [7919, 2], [7920, 1, "\u1EF1"], [7921, 2], [7922, 1, "\u1EF3"], [7923, 2], [7924, 1, "\u1EF5"], [7925, 2], [7926, 1, "\u1EF7"], [7927, 2], [7928, 1, "\u1EF9"], [7929, 2], [7930, 1, "\u1EFB"], [7931, 2], [7932, 1, "\u1EFD"], [7933, 2], [7934, 1, "\u1EFF"], [7935, 2], [[7936, 7943], 2], [7944, 1, "\u1F00"], [7945, 1, "\u1F01"], [7946, 1, "\u1F02"], [7947, 1, "\u1F03"], [7948, 1, "\u1F04"], [7949, 1, "\u1F05"], [7950, 1, "\u1F06"], [7951, 1, "\u1F07"], [[7952, 7957], 2], [[7958, 7959], 3], [7960, 1, "\u1F10"], [7961, 1, "\u1F11"], [7962, 1, "\u1F12"], [7963, 1, "\u1F13"], [7964, 1, "\u1F14"], [7965, 1, "\u1F15"], [[7966, 7967], 3], [[7968, 7975], 2], [7976, 1, "\u1F20"], [7977, 1, "\u1F21"], [7978, 1, "\u1F22"], [7979, 1, "\u1F23"], [7980, 1, "\u1F24"], [7981, 1, "\u1F25"], [7982, 1, "\u1F26"], [7983, 1, "\u1F27"], [[7984, 7991], 2], [7992, 1, "\u1F30"], [7993, 1, "\u1F31"], [7994, 1, "\u1F32"], [7995, 1, "\u1F33"], [7996, 1, "\u1F34"], [7997, 1, "\u1F35"], [7998, 1, "\u1F36"], [7999, 1, "\u1F37"], [[8e3, 8005], 2], [[8006, 8007], 3], [8008, 1, "\u1F40"], [8009, 1, "\u1F41"], [8010, 1, "\u1F42"], [8011, 1, "\u1F43"], [8012, 1, "\u1F44"], [8013, 1, "\u1F45"], [[8014, 8015], 3], [[8016, 8023], 2], [8024, 3], [8025, 1, "\u1F51"], [8026, 3], [8027, 1, "\u1F53"], [8028, 3], [8029, 1, "\u1F55"], [8030, 3], [8031, 1, "\u1F57"], [[8032, 8039], 2], [8040, 1, "\u1F60"], [8041, 1, "\u1F61"], [8042, 1, "\u1F62"], [8043, 1, "\u1F63"], [8044, 1, "\u1F64"], [8045, 1, "\u1F65"], [8046, 1, "\u1F66"], [8047, 1, "\u1F67"], [8048, 2], [8049, 1, "\u03AC"], [8050, 2], [8051, 1, "\u03AD"], [8052, 2], [8053, 1, "\u03AE"], [8054, 2], [8055, 1, "\u03AF"], [8056, 2], [8057, 1, "\u03CC"], [8058, 2], [8059, 1, "\u03CD"], [8060, 2], [8061, 1, "\u03CE"], [[8062, 8063], 3], [8064, 1, "\u1F00\u03B9"], [8065, 1, "\u1F01\u03B9"], [8066, 1, "\u1F02\u03B9"], [8067, 1, "\u1F03\u03B9"], [8068, 1, "\u1F04\u03B9"], [8069, 1, "\u1F05\u03B9"], [8070, 1, "\u1F06\u03B9"], [8071, 1, "\u1F07\u03B9"], [8072, 1, "\u1F00\u03B9"], [8073, 1, "\u1F01\u03B9"], [8074, 1, "\u1F02\u03B9"], [8075, 1, "\u1F03\u03B9"], [8076, 1, "\u1F04\u03B9"], [8077, 1, "\u1F05\u03B9"], [8078, 1, "\u1F06\u03B9"], [8079, 1, "\u1F07\u03B9"], [8080, 1, "\u1F20\u03B9"], [8081, 1, "\u1F21\u03B9"], [8082, 1, "\u1F22\u03B9"], [8083, 1, "\u1F23\u03B9"], [8084, 1, "\u1F24\u03B9"], [8085, 1, "\u1F25\u03B9"], [8086, 1, "\u1F26\u03B9"], [8087, 1, "\u1F27\u03B9"], [8088, 1, "\u1F20\u03B9"], [8089, 1, "\u1F21\u03B9"], [8090, 1, "\u1F22\u03B9"], [8091, 1, "\u1F23\u03B9"], [8092, 1, "\u1F24\u03B9"], [8093, 1, "\u1F25\u03B9"], [8094, 1, "\u1F26\u03B9"], [8095, 1, "\u1F27\u03B9"], [8096, 1, "\u1F60\u03B9"], [8097, 1, "\u1F61\u03B9"], [8098, 1, "\u1F62\u03B9"], [8099, 1, "\u1F63\u03B9"], [8100, 1, "\u1F64\u03B9"], [8101, 1, "\u1F65\u03B9"], [8102, 1, "\u1F66\u03B9"], [8103, 1, "\u1F67\u03B9"], [8104, 1, "\u1F60\u03B9"], [8105, 1, "\u1F61\u03B9"], [8106, 1, "\u1F62\u03B9"], [8107, 1, "\u1F63\u03B9"], [8108, 1, "\u1F64\u03B9"], [8109, 1, "\u1F65\u03B9"], [8110, 1, "\u1F66\u03B9"], [8111, 1, "\u1F67\u03B9"], [[8112, 8113], 2], [8114, 1, "\u1F70\u03B9"], [8115, 1, "\u03B1\u03B9"], [8116, 1, "\u03AC\u03B9"], [8117, 3], [8118, 2], [8119, 1, "\u1FB6\u03B9"], [8120, 1, "\u1FB0"], [8121, 1, "\u1FB1"], [8122, 1, "\u1F70"], [8123, 1, "\u03AC"], [8124, 1, "\u03B1\u03B9"], [8125, 1, " \u0313"], [8126, 1, "\u03B9"], [8127, 1, " \u0313"], [8128, 1, " \u0342"], [8129, 1, " \u0308\u0342"], [8130, 1, "\u1F74\u03B9"], [8131, 1, "\u03B7\u03B9"], [8132, 1, "\u03AE\u03B9"], [8133, 3], [8134, 2], [8135, 1, "\u1FC6\u03B9"], [8136, 1, "\u1F72"], [8137, 1, "\u03AD"], [8138, 1, "\u1F74"], [8139, 1, "\u03AE"], [8140, 1, "\u03B7\u03B9"], [8141, 1, " \u0313\u0300"], [8142, 1, " \u0313\u0301"], [8143, 1, " \u0313\u0342"], [[8144, 8146], 2], [8147, 1, "\u0390"], [[8148, 8149], 3], [[8150, 8151], 2], [8152, 1, "\u1FD0"], [8153, 1, "\u1FD1"], [8154, 1, "\u1F76"], [8155, 1, "\u03AF"], [8156, 3], [8157, 1, " \u0314\u0300"], [8158, 1, " \u0314\u0301"], [8159, 1, " \u0314\u0342"], [[8160, 8162], 2], [8163, 1, "\u03B0"], [[8164, 8167], 2], [8168, 1, "\u1FE0"], [8169, 1, "\u1FE1"], [8170, 1, "\u1F7A"], [8171, 1, "\u03CD"], [8172, 1, "\u1FE5"], [8173, 1, " \u0308\u0300"], [8174, 1, " \u0308\u0301"], [8175, 1, "`"], [[8176, 8177], 3], [8178, 1, "\u1F7C\u03B9"], [8179, 1, "\u03C9\u03B9"], [8180, 1, "\u03CE\u03B9"], [8181, 3], [8182, 2], [8183, 1, "\u1FF6\u03B9"], [8184, 1, "\u1F78"], [8185, 1, "\u03CC"], [8186, 1, "\u1F7C"], [8187, 1, "\u03CE"], [8188, 1, "\u03C9\u03B9"], [8189, 1, " \u0301"], [8190, 1, " \u0314"], [8191, 3], [[8192, 8202], 1, " "], [8203, 7], [[8204, 8205], 6, ""], [[8206, 8207], 3], [8208, 2], [8209, 1, "\u2010"], [[8210, 8214], 2], [8215, 1, " \u0333"], [[8216, 8227], 2], [[8228, 8230], 3], [8231, 2], [[8232, 8238], 3], [8239, 1, " "], [[8240, 8242], 2], [8243, 1, "\u2032\u2032"], [8244, 1, "\u2032\u2032\u2032"], [8245, 2], [8246, 1, "\u2035\u2035"], [8247, 1, "\u2035\u2035\u2035"], [[8248, 8251], 2], [8252, 1, "!!"], [8253, 2], [8254, 1, " \u0305"], [[8255, 8262], 2], [8263, 1, "??"], [8264, 1, "?!"], [8265, 1, "!?"], [[8266, 8269], 2], [[8270, 8274], 2], [[8275, 8276], 2], [[8277, 8278], 2], [8279, 1, "\u2032\u2032\u2032\u2032"], [[8280, 8286], 2], [8287, 1, " "], [[8288, 8291], 7], [8292, 7], [8293, 3], [[8294, 8297], 3], [[8298, 8303], 7], [8304, 1, "0"], [8305, 1, "i"], [[8306, 8307], 3], [8308, 1, "4"], [8309, 1, "5"], [8310, 1, "6"], [8311, 1, "7"], [8312, 1, "8"], [8313, 1, "9"], [8314, 1, "+"], [8315, 1, "\u2212"], [8316, 1, "="], [8317, 1, "("], [8318, 1, ")"], [8319, 1, "n"], [8320, 1, "0"], [8321, 1, "1"], [8322, 1, "2"], [8323, 1, "3"], [8324, 1, "4"], [8325, 1, "5"], [8326, 1, "6"], [8327, 1, "7"], [8328, 1, "8"], [8329, 1, "9"], [8330, 1, "+"], [8331, 1, "\u2212"], [8332, 1, "="], [8333, 1, "("], [8334, 1, ")"], [8335, 2], [8336, 1, "a"], [8337, 1, "e"], [8338, 1, "o"], [8339, 1, "x"], [8340, 1, "\u0259"], [8341, 1, "h"], [8342, 1, "k"], [8343, 1, "l"], [8344, 1, "m"], [8345, 1, "n"], [8346, 1, "p"], [8347, 1, "s"], [8348, 1, "t"], [8349, 1, "w"], [8350, 1, "y"], [8351, 1, "z"], [[8352, 8359], 2], [8360, 1, "rs"], [[8361, 8362], 2], [8363, 2], [8364, 2], [[8365, 8367], 2], [[8368, 8369], 2], [[8370, 8373], 2], [[8374, 8376], 2], [8377, 2], [8378, 2], [[8379, 8381], 2], [8382, 2], [8383, 2], [8384, 2], [8385, 2], [[8386, 8388], 2], [[8389, 8399], 3], [[8400, 8417], 2], [[8418, 8419], 2], [[8420, 8426], 2], [8427, 2], [[8428, 8431], 2], [8432, 2], [[8433, 8447], 3], [8448, 1, "a/c"], [8449, 1, "a/s"], [8450, 1, "c"], [8451, 1, "\xB0c"], [8452, 2], [8453, 1, "c/o"], [8454, 1, "c/u"], [8455, 1, "\u025B"], [8456, 2], [8457, 1, "\xB0f"], [8458, 1, "g"], [[8459, 8462], 1, "h"], [8463, 1, "\u0127"], [[8464, 8465], 1, "i"], [[8466, 8467], 1, "l"], [8468, 2], [8469, 1, "n"], [8470, 1, "no"], [[8471, 8472], 2], [8473, 1, "p"], [8474, 1, "q"], [[8475, 8477], 1, "r"], [[8478, 8479], 2], [8480, 1, "sm"], [8481, 1, "tel"], [8482, 1, "tm"], [8483, 2], [8484, 1, "z"], [8485, 2], [8486, 1, "\u03C9"], [8487, 2], [8488, 1, "z"], [8489, 2], [8490, 1, "k"], [8491, 1, "\xE5"], [8492, 1, "b"], [8493, 1, "c"], [8494, 2], [[8495, 8496], 1, "e"], [8497, 1, "f"], [8498, 1, "\u214E"], [8499, 1, "m"], [8500, 1, "o"], [8501, 1, "\u05D0"], [8502, 1, "\u05D1"], [8503, 1, "\u05D2"], [8504, 1, "\u05D3"], [8505, 1, "i"], [8506, 2], [8507, 1, "fax"], [8508, 1, "\u03C0"], [[8509, 8510], 1, "\u03B3"], [8511, 1, "\u03C0"], [8512, 1, "\u2211"], [[8513, 8516], 2], [[8517, 8518], 1, "d"], [8519, 1, "e"], [8520, 1, "i"], [8521, 1, "j"], [[8522, 8523], 2], [8524, 2], [8525, 2], [8526, 2], [8527, 2], [8528, 1, "1\u20447"], [8529, 1, "1\u20449"], [8530, 1, "1\u204410"], [8531, 1, "1\u20443"], [8532, 1, "2\u20443"], [8533, 1, "1\u20445"], [8534, 1, "2\u20445"], [8535, 1, "3\u20445"], [8536, 1, "4\u20445"], [8537, 1, "1\u20446"], [8538, 1, "5\u20446"], [8539, 1, "1\u20448"], [8540, 1, "3\u20448"], [8541, 1, "5\u20448"], [8542, 1, "7\u20448"], [8543, 1, "1\u2044"], [8544, 1, "i"], [8545, 1, "ii"], [8546, 1, "iii"], [8547, 1, "iv"], [8548, 1, "v"], [8549, 1, "vi"], [8550, 1, "vii"], [8551, 1, "viii"], [8552, 1, "ix"], [8553, 1, "x"], [8554, 1, "xi"], [8555, 1, "xii"], [8556, 1, "l"], [8557, 1, "c"], [8558, 1, "d"], [8559, 1, "m"], [8560, 1, "i"], [8561, 1, "ii"], [8562, 1, "iii"], [8563, 1, "iv"], [8564, 1, "v"], [8565, 1, "vi"], [8566, 1, "vii"], [8567, 1, "viii"], [8568, 1, "ix"], [8569, 1, "x"], [8570, 1, "xi"], [8571, 1, "xii"], [8572, 1, "l"], [8573, 1, "c"], [8574, 1, "d"], [8575, 1, "m"], [[8576, 8578], 2], [8579, 1, "\u2184"], [8580, 2], [[8581, 8584], 2], [8585, 1, "0\u20443"], [[8586, 8587], 2], [[8588, 8591], 3], [[8592, 8682], 2], [[8683, 8691], 2], [[8692, 8703], 2], [[8704, 8747], 2], [8748, 1, "\u222B\u222B"], [8749, 1, "\u222B\u222B\u222B"], [8750, 2], [8751, 1, "\u222E\u222E"], [8752, 1, "\u222E\u222E\u222E"], [[8753, 8945], 2], [[8946, 8959], 2], [8960, 2], [8961, 2], [[8962, 9e3], 2], [9001, 1, "\u3008"], [9002, 1, "\u3009"], [[9003, 9082], 2], [9083, 2], [9084, 2], [[9085, 9114], 2], [[9115, 9166], 2], [[9167, 9168], 2], [[9169, 9179], 2], [[9180, 9191], 2], [9192, 2], [[9193, 9203], 2], [[9204, 9210], 2], [[9211, 9214], 2], [9215, 2], [[9216, 9252], 2], [[9253, 9254], 2], [[9255, 9257], 2], [[9258, 9279], 3], [[9280, 9290], 2], [[9291, 9311], 3], [9312, 1, "1"], [9313, 1, "2"], [9314, 1, "3"], [9315, 1, "4"], [9316, 1, "5"], [9317, 1, "6"], [9318, 1, "7"], [9319, 1, "8"], [9320, 1, "9"], [9321, 1, "10"], [9322, 1, "11"], [9323, 1, "12"], [9324, 1, "13"], [9325, 1, "14"], [9326, 1, "15"], [9327, 1, "16"], [9328, 1, "17"], [9329, 1, "18"], [9330, 1, "19"], [9331, 1, "20"], [9332, 1, "(1)"], [9333, 1, "(2)"], [9334, 1, "(3)"], [9335, 1, "(4)"], [9336, 1, "(5)"], [9337, 1, "(6)"], [9338, 1, "(7)"], [9339, 1, "(8)"], [9340, 1, "(9)"], [9341, 1, "(10)"], [9342, 1, "(11)"], [9343, 1, "(12)"], [9344, 1, "(13)"], [9345, 1, "(14)"], [9346, 1, "(15)"], [9347, 1, "(16)"], [9348, 1, "(17)"], [9349, 1, "(18)"], [9350, 1, "(19)"], [9351, 1, "(20)"], [[9352, 9371], 3], [9372, 1, "(a)"], [9373, 1, "(b)"], [9374, 1, "(c)"], [9375, 1, "(d)"], [9376, 1, "(e)"], [9377, 1, "(f)"], [9378, 1, "(g)"], [9379, 1, "(h)"], [9380, 1, "(i)"], [9381, 1, "(j)"], [9382, 1, "(k)"], [9383, 1, "(l)"], [9384, 1, "(m)"], [9385, 1, "(n)"], [9386, 1, "(o)"], [9387, 1, "(p)"], [9388, 1, "(q)"], [9389, 1, "(r)"], [9390, 1, "(s)"], [9391, 1, "(t)"], [9392, 1, "(u)"], [9393, 1, "(v)"], [9394, 1, "(w)"], [9395, 1, "(x)"], [9396, 1, "(y)"], [9397, 1, "(z)"], [9398, 1, "a"], [9399, 1, "b"], [9400, 1, "c"], [9401, 1, "d"], [9402, 1, "e"], [9403, 1, "f"], [9404, 1, "g"], [9405, 1, "h"], [9406, 1, "i"], [9407, 1, "j"], [9408, 1, "k"], [9409, 1, "l"], [9410, 1, "m"], [9411, 1, "n"], [9412, 1, "o"], [9413, 1, "p"], [9414, 1, "q"], [9415, 1, "r"], [9416, 1, "s"], [9417, 1, "t"], [9418, 1, "u"], [9419, 1, "v"], [9420, 1, "w"], [9421, 1, "x"], [9422, 1, "y"], [9423, 1, "z"], [9424, 1, "a"], [9425, 1, "b"], [9426, 1, "c"], [9427, 1, "d"], [9428, 1, "e"], [9429, 1, "f"], [9430, 1, "g"], [9431, 1, "h"], [9432, 1, "i"], [9433, 1, "j"], [9434, 1, "k"], [9435, 1, "l"], [9436, 1, "m"], [9437, 1, "n"], [9438, 1, "o"], [9439, 1, "p"], [9440, 1, "q"], [9441, 1, "r"], [9442, 1, "s"], [9443, 1, "t"], [9444, 1, "u"], [9445, 1, "v"], [9446, 1, "w"], [9447, 1, "x"], [9448, 1, "y"], [9449, 1, "z"], [9450, 1, "0"], [[9451, 9470], 2], [9471, 2], [[9472, 9621], 2], [[9622, 9631], 2], [[9632, 9711], 2], [[9712, 9719], 2], [[9720, 9727], 2], [[9728, 9747], 2], [[9748, 9749], 2], [[9750, 9751], 2], [9752, 2], [9753, 2], [[9754, 9839], 2], [[9840, 9841], 2], [[9842, 9853], 2], [[9854, 9855], 2], [[9856, 9865], 2], [[9866, 9873], 2], [[9874, 9884], 2], [9885, 2], [[9886, 9887], 2], [[9888, 9889], 2], [[9890, 9905], 2], [9906, 2], [[9907, 9916], 2], [[9917, 9919], 2], [[9920, 9923], 2], [[9924, 9933], 2], [9934, 2], [[9935, 9953], 2], [9954, 2], [9955, 2], [[9956, 9959], 2], [[9960, 9983], 2], [9984, 2], [[9985, 9988], 2], [9989, 2], [[9990, 9993], 2], [[9994, 9995], 2], [[9996, 10023], 2], [10024, 2], [[10025, 10059], 2], [10060, 2], [10061, 2], [10062, 2], [[10063, 10066], 2], [[10067, 10069], 2], [10070, 2], [10071, 2], [[10072, 10078], 2], [[10079, 10080], 2], [[10081, 10087], 2], [[10088, 10101], 2], [[10102, 10132], 2], [[10133, 10135], 2], [[10136, 10159], 2], [10160, 2], [[10161, 10174], 2], [10175, 2], [[10176, 10182], 2], [[10183, 10186], 2], [10187, 2], [10188, 2], [10189, 2], [[10190, 10191], 2], [[10192, 10219], 2], [[10220, 10223], 2], [[10224, 10239], 2], [[10240, 10495], 2], [[10496, 10763], 2], [10764, 1, "\u222B\u222B\u222B\u222B"], [[10765, 10867], 2], [10868, 1, "::="], [10869, 1, "=="], [10870, 1, "==="], [[10871, 10971], 2], [10972, 1, "\u2ADD\u0338"], [[10973, 11007], 2], [[11008, 11021], 2], [[11022, 11027], 2], [[11028, 11034], 2], [[11035, 11039], 2], [[11040, 11043], 2], [[11044, 11084], 2], [[11085, 11087], 2], [[11088, 11092], 2], [[11093, 11097], 2], [[11098, 11123], 2], [[11124, 11125], 3], [[11126, 11157], 2], [11158, 2], [11159, 2], [[11160, 11193], 2], [[11194, 11196], 2], [[11197, 11208], 2], [11209, 2], [[11210, 11217], 2], [11218, 2], [[11219, 11243], 2], [[11244, 11247], 2], [[11248, 11262], 2], [11263, 2], [11264, 1, "\u2C30"], [11265, 1, "\u2C31"], [11266, 1, "\u2C32"], [11267, 1, "\u2C33"], [11268, 1, "\u2C34"], [11269, 1, "\u2C35"], [11270, 1, "\u2C36"], [11271, 1, "\u2C37"], [11272, 1, "\u2C38"], [11273, 1, "\u2C39"], [11274, 1, "\u2C3A"], [11275, 1, "\u2C3B"], [11276, 1, "\u2C3C"], [11277, 1, "\u2C3D"], [11278, 1, "\u2C3E"], [11279, 1, "\u2C3F"], [11280, 1, "\u2C40"], [11281, 1, "\u2C41"], [11282, 1, "\u2C42"], [11283, 1, "\u2C43"], [11284, 1, "\u2C44"], [11285, 1, "\u2C45"], [11286, 1, "\u2C46"], [11287, 1, "\u2C47"], [11288, 1, "\u2C48"], [11289, 1, "\u2C49"], [11290, 1, "\u2C4A"], [11291, 1, "\u2C4B"], [11292, 1, "\u2C4C"], [11293, 1, "\u2C4D"], [11294, 1, "\u2C4E"], [11295, 1, "\u2C4F"], [11296, 1, "\u2C50"], [11297, 1, "\u2C51"], [11298, 1, "\u2C52"], [11299, 1, "\u2C53"], [11300, 1, "\u2C54"], [11301, 1, "\u2C55"], [11302, 1, "\u2C56"], [11303, 1, "\u2C57"], [11304, 1, "\u2C58"], [11305, 1, "\u2C59"], [11306, 1, "\u2C5A"], [11307, 1, "\u2C5B"], [11308, 1, "\u2C5C"], [11309, 1, "\u2C5D"], [11310, 1, "\u2C5E"], [11311, 1, "\u2C5F"], [[11312, 11358], 2], [11359, 2], [11360, 1, "\u2C61"], [11361, 2], [11362, 1, "\u026B"], [11363, 1, "\u1D7D"], [11364, 1, "\u027D"], [[11365, 11366], 2], [11367, 1, "\u2C68"], [11368, 2], [11369, 1, "\u2C6A"], [11370, 2], [11371, 1, "\u2C6C"], [11372, 2], [11373, 1, "\u0251"], [11374, 1, "\u0271"], [11375, 1, "\u0250"], [11376, 1, "\u0252"], [11377, 2], [11378, 1, "\u2C73"], [11379, 2], [11380, 2], [11381, 1, "\u2C76"], [[11382, 11383], 2], [[11384, 11387], 2], [11388, 1, "j"], [11389, 1, "v"], [11390, 1, "\u023F"], [11391, 1, "\u0240"], [11392, 1, "\u2C81"], [11393, 2], [11394, 1, "\u2C83"], [11395, 2], [11396, 1, "\u2C85"], [11397, 2], [11398, 1, "\u2C87"], [11399, 2], [11400, 1, "\u2C89"], [11401, 2], [11402, 1, "\u2C8B"], [11403, 2], [11404, 1, "\u2C8D"], [11405, 2], [11406, 1, "\u2C8F"], [11407, 2], [11408, 1, "\u2C91"], [11409, 2], [11410, 1, "\u2C93"], [11411, 2], [11412, 1, "\u2C95"], [11413, 2], [11414, 1, "\u2C97"], [11415, 2], [11416, 1, "\u2C99"], [11417, 2], [11418, 1, "\u2C9B"], [11419, 2], [11420, 1, "\u2C9D"], [11421, 2], [11422, 1, "\u2C9F"], [11423, 2], [11424, 1, "\u2CA1"], [11425, 2], [11426, 1, "\u2CA3"], [11427, 2], [11428, 1, "\u2CA5"], [11429, 2], [11430, 1, "\u2CA7"], [11431, 2], [11432, 1, "\u2CA9"], [11433, 2], [11434, 1, "\u2CAB"], [11435, 2], [11436, 1, "\u2CAD"], [11437, 2], [11438, 1, "\u2CAF"], [11439, 2], [11440, 1, "\u2CB1"], [11441, 2], [11442, 1, "\u2CB3"], [11443, 2], [11444, 1, "\u2CB5"], [11445, 2], [11446, 1, "\u2CB7"], [11447, 2], [11448, 1, "\u2CB9"], [11449, 2], [11450, 1, "\u2CBB"], [11451, 2], [11452, 1, "\u2CBD"], [11453, 2], [11454, 1, "\u2CBF"], [11455, 2], [11456, 1, "\u2CC1"], [11457, 2], [11458, 1, "\u2CC3"], [11459, 2], [11460, 1, "\u2CC5"], [11461, 2], [11462, 1, "\u2CC7"], [11463, 2], [11464, 1, "\u2CC9"], [11465, 2], [11466, 1, "\u2CCB"], [11467, 2], [11468, 1, "\u2CCD"], [11469, 2], [11470, 1, "\u2CCF"], [11471, 2], [11472, 1, "\u2CD1"], [11473, 2], [11474, 1, "\u2CD3"], [11475, 2], [11476, 1, "\u2CD5"], [11477, 2], [11478, 1, "\u2CD7"], [11479, 2], [11480, 1, "\u2CD9"], [11481, 2], [11482, 1, "\u2CDB"], [11483, 2], [11484, 1, "\u2CDD"], [11485, 2], [11486, 1, "\u2CDF"], [11487, 2], [11488, 1, "\u2CE1"], [11489, 2], [11490, 1, "\u2CE3"], [[11491, 11492], 2], [[11493, 11498], 2], [11499, 1, "\u2CEC"], [11500, 2], [11501, 1, "\u2CEE"], [[11502, 11505], 2], [11506, 1, "\u2CF3"], [11507, 2], [[11508, 11512], 3], [[11513, 11519], 2], [[11520, 11557], 2], [11558, 3], [11559, 2], [[11560, 11564], 3], [11565, 2], [[11566, 11567], 3], [[11568, 11621], 2], [[11622, 11623], 2], [[11624, 11630], 3], [11631, 1, "\u2D61"], [11632, 2], [[11633, 11646], 3], [11647, 2], [[11648, 11670], 2], [[11671, 11679], 3], [[11680, 11686], 2], [11687, 3], [[11688, 11694], 2], [11695, 3], [[11696, 11702], 2], [11703, 3], [[11704, 11710], 2], [11711, 3], [[11712, 11718], 2], [11719, 3], [[11720, 11726], 2], [11727, 3], [[11728, 11734], 2], [11735, 3], [[11736, 11742], 2], [11743, 3], [[11744, 11775], 2], [[11776, 11799], 2], [[11800, 11803], 2], [[11804, 11805], 2], [[11806, 11822], 2], [11823, 2], [11824, 2], [11825, 2], [[11826, 11835], 2], [[11836, 11842], 2], [[11843, 11844], 2], [[11845, 11849], 2], [[11850, 11854], 2], [11855, 2], [[11856, 11858], 2], [[11859, 11869], 2], [[11870, 11871], 3], [[11872, 11875], 2], [[11876, 11903], 3], [[11904, 11929], 2], [11930, 3], [[11931, 11934], 2], [11935, 1, "\u6BCD"], [[11936, 12018], 2], [12019, 1, "\u9F9F"], [[12020, 12031], 3], [12032, 1, "\u4E00"], [12033, 1, "\u4E28"], [12034, 1, "\u4E36"], [12035, 1, "\u4E3F"], [12036, 1, "\u4E59"], [12037, 1, "\u4E85"], [12038, 1, "\u4E8C"], [12039, 1, "\u4EA0"], [12040, 1, "\u4EBA"], [12041, 1, "\u513F"], [12042, 1, "\u5165"], [12043, 1, "\u516B"], [12044, 1, "\u5182"], [12045, 1, "\u5196"], [12046, 1, "\u51AB"], [12047, 1, "\u51E0"], [12048, 1, "\u51F5"], [12049, 1, "\u5200"], [12050, 1, "\u529B"], [12051, 1, "\u52F9"], [12052, 1, "\u5315"], [12053, 1, "\u531A"], [12054, 1, "\u5338"], [12055, 1, "\u5341"], [12056, 1, "\u535C"], [12057, 1, "\u5369"], [12058, 1, "\u5382"], [12059, 1, "\u53B6"], [12060, 1, "\u53C8"], [12061, 1, "\u53E3"], [12062, 1, "\u56D7"], [12063, 1, "\u571F"], [12064, 1, "\u58EB"], [12065, 1, "\u5902"], [12066, 1, "\u590A"], [12067, 1, "\u5915"], [12068, 1, "\u5927"], [12069, 1, "\u5973"], [12070, 1, "\u5B50"], [12071, 1, "\u5B80"], [12072, 1, "\u5BF8"], [12073, 1, "\u5C0F"], [12074, 1, "\u5C22"], [12075, 1, "\u5C38"], [12076, 1, "\u5C6E"], [12077, 1, "\u5C71"], [12078, 1, "\u5DDB"], [12079, 1, "\u5DE5"], [12080, 1, "\u5DF1"], [12081, 1, "\u5DFE"], [12082, 1, "\u5E72"], [12083, 1, "\u5E7A"], [12084, 1, "\u5E7F"], [12085, 1, "\u5EF4"], [12086, 1, "\u5EFE"], [12087, 1, "\u5F0B"], [12088, 1, "\u5F13"], [12089, 1, "\u5F50"], [12090, 1, "\u5F61"], [12091, 1, "\u5F73"], [12092, 1, "\u5FC3"], [12093, 1, "\u6208"], [12094, 1, "\u6236"], [12095, 1, "\u624B"], [12096, 1, "\u652F"], [12097, 1, "\u6534"], [12098, 1, "\u6587"], [12099, 1, "\u6597"], [12100, 1, "\u65A4"], [12101, 1, "\u65B9"], [12102, 1, "\u65E0"], [12103, 1, "\u65E5"], [12104, 1, "\u66F0"], [12105, 1, "\u6708"], [12106, 1, "\u6728"], [12107, 1, "\u6B20"], [12108, 1, "\u6B62"], [12109, 1, "\u6B79"], [12110, 1, "\u6BB3"], [12111, 1, "\u6BCB"], [12112, 1, "\u6BD4"], [12113, 1, "\u6BDB"], [12114, 1, "\u6C0F"], [12115, 1, "\u6C14"], [12116, 1, "\u6C34"], [12117, 1, "\u706B"], [12118, 1, "\u722A"], [12119, 1, "\u7236"], [12120, 1, "\u723B"], [12121, 1, "\u723F"], [12122, 1, "\u7247"], [12123, 1, "\u7259"], [12124, 1, "\u725B"], [12125, 1, "\u72AC"], [12126, 1, "\u7384"], [12127, 1, "\u7389"], [12128, 1, "\u74DC"], [12129, 1, "\u74E6"], [12130, 1, "\u7518"], [12131, 1, "\u751F"], [12132, 1, "\u7528"], [12133, 1, "\u7530"], [12134, 1, "\u758B"], [12135, 1, "\u7592"], [12136, 1, "\u7676"], [12137, 1, "\u767D"], [12138, 1, "\u76AE"], [12139, 1, "\u76BF"], [12140, 1, "\u76EE"], [12141, 1, "\u77DB"], [12142, 1, "\u77E2"], [12143, 1, "\u77F3"], [12144, 1, "\u793A"], [12145, 1, "\u79B8"], [12146, 1, "\u79BE"], [12147, 1, "\u7A74"], [12148, 1, "\u7ACB"], [12149, 1, "\u7AF9"], [12150, 1, "\u7C73"], [12151, 1, "\u7CF8"], [12152, 1, "\u7F36"], [12153, 1, "\u7F51"], [12154, 1, "\u7F8A"], [12155, 1, "\u7FBD"], [12156, 1, "\u8001"], [12157, 1, "\u800C"], [12158, 1, "\u8012"], [12159, 1, "\u8033"], [12160, 1, "\u807F"], [12161, 1, "\u8089"], [12162, 1, "\u81E3"], [12163, 1, "\u81EA"], [12164, 1, "\u81F3"], [12165, 1, "\u81FC"], [12166, 1, "\u820C"], [12167, 1, "\u821B"], [12168, 1, "\u821F"], [12169, 1, "\u826E"], [12170, 1, "\u8272"], [12171, 1, "\u8278"], [12172, 1, "\u864D"], [12173, 1, "\u866B"], [12174, 1, "\u8840"], [12175, 1, "\u884C"], [12176, 1, "\u8863"], [12177, 1, "\u897E"], [12178, 1, "\u898B"], [12179, 1, "\u89D2"], [12180, 1, "\u8A00"], [12181, 1, "\u8C37"], [12182, 1, "\u8C46"], [12183, 1, "\u8C55"], [12184, 1, "\u8C78"], [12185, 1, "\u8C9D"], [12186, 1, "\u8D64"], [12187, 1, "\u8D70"], [12188, 1, "\u8DB3"], [12189, 1, "\u8EAB"], [12190, 1, "\u8ECA"], [12191, 1, "\u8F9B"], [12192, 1, "\u8FB0"], [12193, 1, "\u8FB5"], [12194, 1, "\u9091"], [12195, 1, "\u9149"], [12196, 1, "\u91C6"], [12197, 1, "\u91CC"], [12198, 1, "\u91D1"], [12199, 1, "\u9577"], [12200, 1, "\u9580"], [12201, 1, "\u961C"], [12202, 1, "\u96B6"], [12203, 1, "\u96B9"], [12204, 1, "\u96E8"], [12205, 1, "\u9751"], [12206, 1, "\u975E"], [12207, 1, "\u9762"], [12208, 1, "\u9769"], [12209, 1, "\u97CB"], [12210, 1, "\u97ED"], [12211, 1, "\u97F3"], [12212, 1, "\u9801"], [12213, 1, "\u98A8"], [12214, 1, "\u98DB"], [12215, 1, "\u98DF"], [12216, 1, "\u9996"], [12217, 1, "\u9999"], [12218, 1, "\u99AC"], [12219, 1, "\u9AA8"], [12220, 1, "\u9AD8"], [12221, 1, "\u9ADF"], [12222, 1, "\u9B25"], [12223, 1, "\u9B2F"], [12224, 1, "\u9B32"], [12225, 1, "\u9B3C"], [12226, 1, "\u9B5A"], [12227, 1, "\u9CE5"], [12228, 1, "\u9E75"], [12229, 1, "\u9E7F"], [12230, 1, "\u9EA5"], [12231, 1, "\u9EBB"], [12232, 1, "\u9EC3"], [12233, 1, "\u9ECD"], [12234, 1, "\u9ED1"], [12235, 1, "\u9EF9"], [12236, 1, "\u9EFD"], [12237, 1, "\u9F0E"], [12238, 1, "\u9F13"], [12239, 1, "\u9F20"], [12240, 1, "\u9F3B"], [12241, 1, "\u9F4A"], [12242, 1, "\u9F52"], [12243, 1, "\u9F8D"], [12244, 1, "\u9F9C"], [12245, 1, "\u9FA0"], [[12246, 12271], 3], [[12272, 12283], 3], [[12284, 12287], 3], [12288, 1, " "], [12289, 2], [12290, 1, "."], [[12291, 12292], 2], [[12293, 12295], 2], [[12296, 12329], 2], [[12330, 12333], 2], [[12334, 12341], 2], [12342, 1, "\u3012"], [12343, 2], [12344, 1, "\u5341"], [12345, 1, "\u5344"], [12346, 1, "\u5345"], [12347, 2], [12348, 2], [12349, 2], [12350, 2], [12351, 2], [12352, 3], [[12353, 12436], 2], [[12437, 12438], 2], [[12439, 12440], 3], [[12441, 12442], 2], [12443, 1, " \u3099"], [12444, 1, " \u309A"], [[12445, 12446], 2], [12447, 1, "\u3088\u308A"], [12448, 2], [[12449, 12542], 2], [12543, 1, "\u30B3\u30C8"], [[12544, 12548], 3], [[12549, 12588], 2], [12589, 2], [12590, 2], [12591, 2], [12592, 3], [12593, 1, "\u1100"], [12594, 1, "\u1101"], [12595, 1, "\u11AA"], [12596, 1, "\u1102"], [12597, 1, "\u11AC"], [12598, 1, "\u11AD"], [12599, 1, "\u1103"], [12600, 1, "\u1104"], [12601, 1, "\u1105"], [12602, 1, "\u11B0"], [12603, 1, "\u11B1"], [12604, 1, "\u11B2"], [12605, 1, "\u11B3"], [12606, 1, "\u11B4"], [12607, 1, "\u11B5"], [12608, 1, "\u111A"], [12609, 1, "\u1106"], [12610, 1, "\u1107"], [12611, 1, "\u1108"], [12612, 1, "\u1121"], [12613, 1, "\u1109"], [12614, 1, "\u110A"], [12615, 1, "\u110B"], [12616, 1, "\u110C"], [12617, 1, "\u110D"], [12618, 1, "\u110E"], [12619, 1, "\u110F"], [12620, 1, "\u1110"], [12621, 1, "\u1111"], [12622, 1, "\u1112"], [12623, 1, "\u1161"], [12624, 1, "\u1162"], [12625, 1, "\u1163"], [12626, 1, "\u1164"], [12627, 1, "\u1165"], [12628, 1, "\u1166"], [12629, 1, "\u1167"], [12630, 1, "\u1168"], [12631, 1, "\u1169"], [12632, 1, "\u116A"], [12633, 1, "\u116B"], [12634, 1, "\u116C"], [12635, 1, "\u116D"], [12636, 1, "\u116E"], [12637, 1, "\u116F"], [12638, 1, "\u1170"], [12639, 1, "\u1171"], [12640, 1, "\u1172"], [12641, 1, "\u1173"], [12642, 1, "\u1174"], [12643, 1, "\u1175"], [12644, 7], [12645, 1, "\u1114"], [12646, 1, "\u1115"], [12647, 1, "\u11C7"], [12648, 1, "\u11C8"], [12649, 1, "\u11CC"], [12650, 1, "\u11CE"], [12651, 1, "\u11D3"], [12652, 1, "\u11D7"], [12653, 1, "\u11D9"], [12654, 1, "\u111C"], [12655, 1, "\u11DD"], [12656, 1, "\u11DF"], [12657, 1, "\u111D"], [12658, 1, "\u111E"], [12659, 1, "\u1120"], [12660, 1, "\u1122"], [12661, 1, "\u1123"], [12662, 1, "\u1127"], [12663, 1, "\u1129"], [12664, 1, "\u112B"], [12665, 1, "\u112C"], [12666, 1, "\u112D"], [12667, 1, "\u112E"], [12668, 1, "\u112F"], [12669, 1, "\u1132"], [12670, 1, "\u1136"], [12671, 1, "\u1140"], [12672, 1, "\u1147"], [12673, 1, "\u114C"], [12674, 1, "\u11F1"], [12675, 1, "\u11F2"], [12676, 1, "\u1157"], [12677, 1, "\u1158"], [12678, 1, "\u1159"], [12679, 1, "\u1184"], [12680, 1, "\u1185"], [12681, 1, "\u1188"], [12682, 1, "\u1191"], [12683, 1, "\u1192"], [12684, 1, "\u1194"], [12685, 1, "\u119E"], [12686, 1, "\u11A1"], [12687, 3], [[12688, 12689], 2], [12690, 1, "\u4E00"], [12691, 1, "\u4E8C"], [12692, 1, "\u4E09"], [12693, 1, "\u56DB"], [12694, 1, "\u4E0A"], [12695, 1, "\u4E2D"], [12696, 1, "\u4E0B"], [12697, 1, "\u7532"], [12698, 1, "\u4E59"], [12699, 1, "\u4E19"], [12700, 1, "\u4E01"], [12701, 1, "\u5929"], [12702, 1, "\u5730"], [12703, 1, "\u4EBA"], [[12704, 12727], 2], [[12728, 12730], 2], [[12731, 12735], 2], [[12736, 12751], 2], [[12752, 12771], 2], [[12772, 12773], 2], [[12774, 12782], 3], [12783, 3], [[12784, 12799], 2], [12800, 1, "(\u1100)"], [12801, 1, "(\u1102)"], [12802, 1, "(\u1103)"], [12803, 1, "(\u1105)"], [12804, 1, "(\u1106)"], [12805, 1, "(\u1107)"], [12806, 1, "(\u1109)"], [12807, 1, "(\u110B)"], [12808, 1, "(\u110C)"], [12809, 1, "(\u110E)"], [12810, 1, "(\u110F)"], [12811, 1, "(\u1110)"], [12812, 1, "(\u1111)"], [12813, 1, "(\u1112)"], [12814, 1, "(\uAC00)"], [12815, 1, "(\uB098)"], [12816, 1, "(\uB2E4)"], [12817, 1, "(\uB77C)"], [12818, 1, "(\uB9C8)"], [12819, 1, "(\uBC14)"], [12820, 1, "(\uC0AC)"], [12821, 1, "(\uC544)"], [12822, 1, "(\uC790)"], [12823, 1, "(\uCC28)"], [12824, 1, "(\uCE74)"], [12825, 1, "(\uD0C0)"], [12826, 1, "(\uD30C)"], [12827, 1, "(\uD558)"], [12828, 1, "(\uC8FC)"], [12829, 1, "(\uC624\uC804)"], [12830, 1, "(\uC624\uD6C4)"], [12831, 3], [12832, 1, "(\u4E00)"], [12833, 1, "(\u4E8C)"], [12834, 1, "(\u4E09)"], [12835, 1, "(\u56DB)"], [12836, 1, "(\u4E94)"], [12837, 1, "(\u516D)"], [12838, 1, "(\u4E03)"], [12839, 1, "(\u516B)"], [12840, 1, "(\u4E5D)"], [12841, 1, "(\u5341)"], [12842, 1, "(\u6708)"], [12843, 1, "(\u706B)"], [12844, 1, "(\u6C34)"], [12845, 1, "(\u6728)"], [12846, 1, "(\u91D1)"], [12847, 1, "(\u571F)"], [12848, 1, "(\u65E5)"], [12849, 1, "(\u682A)"], [12850, 1, "(\u6709)"], [12851, 1, "(\u793E)"], [12852, 1, "(\u540D)"], [12853, 1, "(\u7279)"], [12854, 1, "(\u8CA1)"], [12855, 1, "(\u795D)"], [12856, 1, "(\u52B4)"], [12857, 1, "(\u4EE3)"], [12858, 1, "(\u547C)"], [12859, 1, "(\u5B66)"], [12860, 1, "(\u76E3)"], [12861, 1, "(\u4F01)"], [12862, 1, "(\u8CC7)"], [12863, 1, "(\u5354)"], [12864, 1, "(\u796D)"], [12865, 1, "(\u4F11)"], [12866, 1, "(\u81EA)"], [12867, 1, "(\u81F3)"], [12868, 1, "\u554F"], [12869, 1, "\u5E7C"], [12870, 1, "\u6587"], [12871, 1, "\u7B8F"], [[12872, 12879], 2], [12880, 1, "pte"], [12881, 1, "21"], [12882, 1, "22"], [12883, 1, "23"], [12884, 1, "24"], [12885, 1, "25"], [12886, 1, "26"], [12887, 1, "27"], [12888, 1, "28"], [12889, 1, "29"], [12890, 1, "30"], [12891, 1, "31"], [12892, 1, "32"], [12893, 1, "33"], [12894, 1, "34"], [12895, 1, "35"], [12896, 1, "\u1100"], [12897, 1, "\u1102"], [12898, 1, "\u1103"], [12899, 1, "\u1105"], [12900, 1, "\u1106"], [12901, 1, "\u1107"], [12902, 1, "\u1109"], [12903, 1, "\u110B"], [12904, 1, "\u110C"], [12905, 1, "\u110E"], [12906, 1, "\u110F"], [12907, 1, "\u1110"], [12908, 1, "\u1111"], [12909, 1, "\u1112"], [12910, 1, "\uAC00"], [12911, 1, "\uB098"], [12912, 1, "\uB2E4"], [12913, 1, "\uB77C"], [12914, 1, "\uB9C8"], [12915, 1, "\uBC14"], [12916, 1, "\uC0AC"], [12917, 1, "\uC544"], [12918, 1, "\uC790"], [12919, 1, "\uCC28"], [12920, 1, "\uCE74"], [12921, 1, "\uD0C0"], [12922, 1, "\uD30C"], [12923, 1, "\uD558"], [12924, 1, "\uCC38\uACE0"], [12925, 1, "\uC8FC\uC758"], [12926, 1, "\uC6B0"], [12927, 2], [12928, 1, "\u4E00"], [12929, 1, "\u4E8C"], [12930, 1, "\u4E09"], [12931, 1, "\u56DB"], [12932, 1, "\u4E94"], [12933, 1, "\u516D"], [12934, 1, "\u4E03"], [12935, 1, "\u516B"], [12936, 1, "\u4E5D"], [12937, 1, "\u5341"], [12938, 1, "\u6708"], [12939, 1, "\u706B"], [12940, 1, "\u6C34"], [12941, 1, "\u6728"], [12942, 1, "\u91D1"], [12943, 1, "\u571F"], [12944, 1, "\u65E5"], [12945, 1, "\u682A"], [12946, 1, "\u6709"], [12947, 1, "\u793E"], [12948, 1, "\u540D"], [12949, 1, "\u7279"], [12950, 1, "\u8CA1"], [12951, 1, "\u795D"], [12952, 1, "\u52B4"], [12953, 1, "\u79D8"], [12954, 1, "\u7537"], [12955, 1, "\u5973"], [12956, 1, "\u9069"], [12957, 1, "\u512A"], [12958, 1, "\u5370"], [12959, 1, "\u6CE8"], [12960, 1, "\u9805"], [12961, 1, "\u4F11"], [12962, 1, "\u5199"], [12963, 1, "\u6B63"], [12964, 1, "\u4E0A"], [12965, 1, "\u4E2D"], [12966, 1, "\u4E0B"], [12967, 1, "\u5DE6"], [12968, 1, "\u53F3"], [12969, 1, "\u533B"], [12970, 1, "\u5B97"], [12971, 1, "\u5B66"], [12972, 1, "\u76E3"], [12973, 1, "\u4F01"], [12974, 1, "\u8CC7"], [12975, 1, "\u5354"], [12976, 1, "\u591C"], [12977, 1, "36"], [12978, 1, "37"], [12979, 1, "38"], [12980, 1, "39"], [12981, 1, "40"], [12982, 1, "41"], [12983, 1, "42"], [12984, 1, "43"], [12985, 1, "44"], [12986, 1, "45"], [12987, 1, "46"], [12988, 1, "47"], [12989, 1, "48"], [12990, 1, "49"], [12991, 1, "50"], [12992, 1, "1\u6708"], [12993, 1, "2\u6708"], [12994, 1, "3\u6708"], [12995, 1, "4\u6708"], [12996, 1, "5\u6708"], [12997, 1, "6\u6708"], [12998, 1, "7\u6708"], [12999, 1, "8\u6708"], [13e3, 1, "9\u6708"], [13001, 1, "10\u6708"], [13002, 1, "11\u6708"], [13003, 1, "12\u6708"], [13004, 1, "hg"], [13005, 1, "erg"], [13006, 1, "ev"], [13007, 1, "ltd"], [13008, 1, "\u30A2"], [13009, 1, "\u30A4"], [13010, 1, "\u30A6"], [13011, 1, "\u30A8"], [13012, 1, "\u30AA"], [13013, 1, "\u30AB"], [13014, 1, "\u30AD"], [13015, 1, "\u30AF"], [13016, 1, "\u30B1"], [13017, 1, "\u30B3"], [13018, 1, "\u30B5"], [13019, 1, "\u30B7"], [13020, 1, "\u30B9"], [13021, 1, "\u30BB"], [13022, 1, "\u30BD"], [13023, 1, "\u30BF"], [13024, 1, "\u30C1"], [13025, 1, "\u30C4"], [13026, 1, "\u30C6"], [13027, 1, "\u30C8"], [13028, 1, "\u30CA"], [13029, 1, "\u30CB"], [13030, 1, "\u30CC"], [13031, 1, "\u30CD"], [13032, 1, "\u30CE"], [13033, 1, "\u30CF"], [13034, 1, "\u30D2"], [13035, 1, "\u30D5"], [13036, 1, "\u30D8"], [13037, 1, "\u30DB"], [13038, 1, "\u30DE"], [13039, 1, "\u30DF"], [13040, 1, "\u30E0"], [13041, 1, "\u30E1"], [13042, 1, "\u30E2"], [13043, 1, "\u30E4"], [13044, 1, "\u30E6"], [13045, 1, "\u30E8"], [13046, 1, "\u30E9"], [13047, 1, "\u30EA"], [13048, 1, "\u30EB"], [13049, 1, "\u30EC"], [13050, 1, "\u30ED"], [13051, 1, "\u30EF"], [13052, 1, "\u30F0"], [13053, 1, "\u30F1"], [13054, 1, "\u30F2"], [13055, 1, "\u4EE4\u548C"], [13056, 1, "\u30A2\u30D1\u30FC\u30C8"], [13057, 1, "\u30A2\u30EB\u30D5\u30A1"], [13058, 1, "\u30A2\u30F3\u30DA\u30A2"], [13059, 1, "\u30A2\u30FC\u30EB"], [13060, 1, "\u30A4\u30CB\u30F3\u30B0"], [13061, 1, "\u30A4\u30F3\u30C1"], [13062, 1, "\u30A6\u30A9\u30F3"], [13063, 1, "\u30A8\u30B9\u30AF\u30FC\u30C9"], [13064, 1, "\u30A8\u30FC\u30AB\u30FC"], [13065, 1, "\u30AA\u30F3\u30B9"], [13066, 1, "\u30AA\u30FC\u30E0"], [13067, 1, "\u30AB\u30A4\u30EA"], [13068, 1, "\u30AB\u30E9\u30C3\u30C8"], [13069, 1, "\u30AB\u30ED\u30EA\u30FC"], [13070, 1, "\u30AC\u30ED\u30F3"], [13071, 1, "\u30AC\u30F3\u30DE"], [13072, 1, "\u30AE\u30AC"], [13073, 1, "\u30AE\u30CB\u30FC"], [13074, 1, "\u30AD\u30E5\u30EA\u30FC"], [13075, 1, "\u30AE\u30EB\u30C0\u30FC"], [13076, 1, "\u30AD\u30ED"], [13077, 1, "\u30AD\u30ED\u30B0\u30E9\u30E0"], [13078, 1, "\u30AD\u30ED\u30E1\u30FC\u30C8\u30EB"], [13079, 1, "\u30AD\u30ED\u30EF\u30C3\u30C8"], [13080, 1, "\u30B0\u30E9\u30E0"], [13081, 1, "\u30B0\u30E9\u30E0\u30C8\u30F3"], [13082, 1, "\u30AF\u30EB\u30BC\u30A4\u30ED"], [13083, 1, "\u30AF\u30ED\u30FC\u30CD"], [13084, 1, "\u30B1\u30FC\u30B9"], [13085, 1, "\u30B3\u30EB\u30CA"], [13086, 1, "\u30B3\u30FC\u30DD"], [13087, 1, "\u30B5\u30A4\u30AF\u30EB"], [13088, 1, "\u30B5\u30F3\u30C1\u30FC\u30E0"], [13089, 1, "\u30B7\u30EA\u30F3\u30B0"], [13090, 1, "\u30BB\u30F3\u30C1"], [13091, 1, "\u30BB\u30F3\u30C8"], [13092, 1, "\u30C0\u30FC\u30B9"], [13093, 1, "\u30C7\u30B7"], [13094, 1, "\u30C9\u30EB"], [13095, 1, "\u30C8\u30F3"], [13096, 1, "\u30CA\u30CE"], [13097, 1, "\u30CE\u30C3\u30C8"], [13098, 1, "\u30CF\u30A4\u30C4"], [13099, 1, "\u30D1\u30FC\u30BB\u30F3\u30C8"], [13100, 1, "\u30D1\u30FC\u30C4"], [13101, 1, "\u30D0\u30FC\u30EC\u30EB"], [13102, 1, "\u30D4\u30A2\u30B9\u30C8\u30EB"], [13103, 1, "\u30D4\u30AF\u30EB"], [13104, 1, "\u30D4\u30B3"], [13105, 1, "\u30D3\u30EB"], [13106, 1, "\u30D5\u30A1\u30E9\u30C3\u30C9"], [13107, 1, "\u30D5\u30A3\u30FC\u30C8"], [13108, 1, "\u30D6\u30C3\u30B7\u30A7\u30EB"], [13109, 1, "\u30D5\u30E9\u30F3"], [13110, 1, "\u30D8\u30AF\u30BF\u30FC\u30EB"], [13111, 1, "\u30DA\u30BD"], [13112, 1, "\u30DA\u30CB\u30D2"], [13113, 1, "\u30D8\u30EB\u30C4"], [13114, 1, "\u30DA\u30F3\u30B9"], [13115, 1, "\u30DA\u30FC\u30B8"], [13116, 1, "\u30D9\u30FC\u30BF"], [13117, 1, "\u30DD\u30A4\u30F3\u30C8"], [13118, 1, "\u30DC\u30EB\u30C8"], [13119, 1, "\u30DB\u30F3"], [13120, 1, "\u30DD\u30F3\u30C9"], [13121, 1, "\u30DB\u30FC\u30EB"], [13122, 1, "\u30DB\u30FC\u30F3"], [13123, 1, "\u30DE\u30A4\u30AF\u30ED"], [13124, 1, "\u30DE\u30A4\u30EB"], [13125, 1, "\u30DE\u30C3\u30CF"], [13126, 1, "\u30DE\u30EB\u30AF"], [13127, 1, "\u30DE\u30F3\u30B7\u30E7\u30F3"], [13128, 1, "\u30DF\u30AF\u30ED\u30F3"], [13129, 1, "\u30DF\u30EA"], [13130, 1, "\u30DF\u30EA\u30D0\u30FC\u30EB"], [13131, 1, "\u30E1\u30AC"], [13132, 1, "\u30E1\u30AC\u30C8\u30F3"], [13133, 1, "\u30E1\u30FC\u30C8\u30EB"], [13134, 1, "\u30E4\u30FC\u30C9"], [13135, 1, "\u30E4\u30FC\u30EB"], [13136, 1, "\u30E6\u30A2\u30F3"], [13137, 1, "\u30EA\u30C3\u30C8\u30EB"], [13138, 1, "\u30EA\u30E9"], [13139, 1, "\u30EB\u30D4\u30FC"], [13140, 1, "\u30EB\u30FC\u30D6\u30EB"], [13141, 1, "\u30EC\u30E0"], [13142, 1, "\u30EC\u30F3\u30C8\u30B2\u30F3"], [13143, 1, "\u30EF\u30C3\u30C8"], [13144, 1, "0\u70B9"], [13145, 1, "1\u70B9"], [13146, 1, "2\u70B9"], [13147, 1, "3\u70B9"], [13148, 1, "4\u70B9"], [13149, 1, "5\u70B9"], [13150, 1, "6\u70B9"], [13151, 1, "7\u70B9"], [13152, 1, "8\u70B9"], [13153, 1, "9\u70B9"], [13154, 1, "10\u70B9"], [13155, 1, "11\u70B9"], [13156, 1, "12\u70B9"], [13157, 1, "13\u70B9"], [13158, 1, "14\u70B9"], [13159, 1, "15\u70B9"], [13160, 1, "16\u70B9"], [13161, 1, "17\u70B9"], [13162, 1, "18\u70B9"], [13163, 1, "19\u70B9"], [13164, 1, "20\u70B9"], [13165, 1, "21\u70B9"], [13166, 1, "22\u70B9"], [13167, 1, "23\u70B9"], [13168, 1, "24\u70B9"], [13169, 1, "hpa"], [13170, 1, "da"], [13171, 1, "au"], [13172, 1, "bar"], [13173, 1, "ov"], [13174, 1, "pc"], [13175, 1, "dm"], [13176, 1, "dm2"], [13177, 1, "dm3"], [13178, 1, "iu"], [13179, 1, "\u5E73\u6210"], [13180, 1, "\u662D\u548C"], [13181, 1, "\u5927\u6B63"], [13182, 1, "\u660E\u6CBB"], [13183, 1, "\u682A\u5F0F\u4F1A\u793E"], [13184, 1, "pa"], [13185, 1, "na"], [13186, 1, "\u03BCa"], [13187, 1, "ma"], [13188, 1, "ka"], [13189, 1, "kb"], [13190, 1, "mb"], [13191, 1, "gb"], [13192, 1, "cal"], [13193, 1, "kcal"], [13194, 1, "pf"], [13195, 1, "nf"], [13196, 1, "\u03BCf"], [13197, 1, "\u03BCg"], [13198, 1, "mg"], [13199, 1, "kg"], [13200, 1, "hz"], [13201, 1, "khz"], [13202, 1, "mhz"], [13203, 1, "ghz"], [13204, 1, "thz"], [13205, 1, "\u03BCl"], [13206, 1, "ml"], [13207, 1, "dl"], [13208, 1, "kl"], [13209, 1, "fm"], [13210, 1, "nm"], [13211, 1, "\u03BCm"], [13212, 1, "mm"], [13213, 1, "cm"], [13214, 1, "km"], [13215, 1, "mm2"], [13216, 1, "cm2"], [13217, 1, "m2"], [13218, 1, "km2"], [13219, 1, "mm3"], [13220, 1, "cm3"], [13221, 1, "m3"], [13222, 1, "km3"], [13223, 1, "m\u2215s"], [13224, 1, "m\u2215s2"], [13225, 1, "pa"], [13226, 1, "kpa"], [13227, 1, "mpa"], [13228, 1, "gpa"], [13229, 1, "rad"], [13230, 1, "rad\u2215s"], [13231, 1, "rad\u2215s2"], [13232, 1, "ps"], [13233, 1, "ns"], [13234, 1, "\u03BCs"], [13235, 1, "ms"], [13236, 1, "pv"], [13237, 1, "nv"], [13238, 1, "\u03BCv"], [13239, 1, "mv"], [13240, 1, "kv"], [13241, 1, "mv"], [13242, 1, "pw"], [13243, 1, "nw"], [13244, 1, "\u03BCw"], [13245, 1, "mw"], [13246, 1, "kw"], [13247, 1, "mw"], [13248, 1, "k\u03C9"], [13249, 1, "m\u03C9"], [13250, 3], [13251, 1, "bq"], [13252, 1, "cc"], [13253, 1, "cd"], [13254, 1, "c\u2215kg"], [13255, 3], [13256, 1, "db"], [13257, 1, "gy"], [13258, 1, "ha"], [13259, 1, "hp"], [13260, 1, "in"], [13261, 1, "kk"], [13262, 1, "km"], [13263, 1, "kt"], [13264, 1, "lm"], [13265, 1, "ln"], [13266, 1, "log"], [13267, 1, "lx"], [13268, 1, "mb"], [13269, 1, "mil"], [13270, 1, "mol"], [13271, 1, "ph"], [13272, 3], [13273, 1, "ppm"], [13274, 1, "pr"], [13275, 1, "sr"], [13276, 1, "sv"], [13277, 1, "wb"], [13278, 1, "v\u2215m"], [13279, 1, "a\u2215m"], [13280, 1, "1\u65E5"], [13281, 1, "2\u65E5"], [13282, 1, "3\u65E5"], [13283, 1, "4\u65E5"], [13284, 1, "5\u65E5"], [13285, 1, "6\u65E5"], [13286, 1, "7\u65E5"], [13287, 1, "8\u65E5"], [13288, 1, "9\u65E5"], [13289, 1, "10\u65E5"], [13290, 1, "11\u65E5"], [13291, 1, "12\u65E5"], [13292, 1, "13\u65E5"], [13293, 1, "14\u65E5"], [13294, 1, "15\u65E5"], [13295, 1, "16\u65E5"], [13296, 1, "17\u65E5"], [13297, 1, "18\u65E5"], [13298, 1, "19\u65E5"], [13299, 1, "20\u65E5"], [13300, 1, "21\u65E5"], [13301, 1, "22\u65E5"], [13302, 1, "23\u65E5"], [13303, 1, "24\u65E5"], [13304, 1, "25\u65E5"], [13305, 1, "26\u65E5"], [13306, 1, "27\u65E5"], [13307, 1, "28\u65E5"], [13308, 1, "29\u65E5"], [13309, 1, "30\u65E5"], [13310, 1, "31\u65E5"], [13311, 1, "gal"], [[13312, 19893], 2], [[19894, 19903], 2], [[19904, 19967], 2], [[19968, 40869], 2], [[40870, 40891], 2], [[40892, 40899], 2], [[40900, 40907], 2], [40908, 2], [[40909, 40917], 2], [[40918, 40938], 2], [[40939, 40943], 2], [[40944, 40956], 2], [[40957, 40959], 2], [[40960, 42124], 2], [[42125, 42127], 3], [[42128, 42145], 2], [[42146, 42147], 2], [[42148, 42163], 2], [42164, 2], [[42165, 42176], 2], [42177, 2], [[42178, 42180], 2], [42181, 2], [42182, 2], [[42183, 42191], 3], [[42192, 42237], 2], [[42238, 42239], 2], [[42240, 42508], 2], [[42509, 42511], 2], [[42512, 42539], 2], [[42540, 42559], 3], [42560, 1, "\uA641"], [42561, 2], [42562, 1, "\uA643"], [42563, 2], [42564, 1, "\uA645"], [42565, 2], [42566, 1, "\uA647"], [42567, 2], [42568, 1, "\uA649"], [42569, 2], [42570, 1, "\uA64B"], [42571, 2], [42572, 1, "\uA64D"], [42573, 2], [42574, 1, "\uA64F"], [42575, 2], [42576, 1, "\uA651"], [42577, 2], [42578, 1, "\uA653"], [42579, 2], [42580, 1, "\uA655"], [42581, 2], [42582, 1, "\uA657"], [42583, 2], [42584, 1, "\uA659"], [42585, 2], [42586, 1, "\uA65B"], [42587, 2], [42588, 1, "\uA65D"], [42589, 2], [42590, 1, "\uA65F"], [42591, 2], [42592, 1, "\uA661"], [42593, 2], [42594, 1, "\uA663"], [42595, 2], [42596, 1, "\uA665"], [42597, 2], [42598, 1, "\uA667"], [42599, 2], [42600, 1, "\uA669"], [42601, 2], [42602, 1, "\uA66B"], [42603, 2], [42604, 1, "\uA66D"], [[42605, 42607], 2], [[42608, 42611], 2], [[42612, 42619], 2], [[42620, 42621], 2], [42622, 2], [42623, 2], [42624, 1, "\uA681"], [42625, 2], [42626, 1, "\uA683"], [42627, 2], [42628, 1, "\uA685"], [42629, 2], [42630, 1, "\uA687"], [42631, 2], [42632, 1, "\uA689"], [42633, 2], [42634, 1, "\uA68B"], [42635, 2], [42636, 1, "\uA68D"], [42637, 2], [42638, 1, "\uA68F"], [42639, 2], [42640, 1, "\uA691"], [42641, 2], [42642, 1, "\uA693"], [42643, 2], [42644, 1, "\uA695"], [42645, 2], [42646, 1, "\uA697"], [42647, 2], [42648, 1, "\uA699"], [42649, 2], [42650, 1, "\uA69B"], [42651, 2], [42652, 1, "\u044A"], [42653, 1, "\u044C"], [42654, 2], [42655, 2], [[42656, 42725], 2], [[42726, 42735], 2], [[42736, 42737], 2], [[42738, 42743], 2], [[42744, 42751], 3], [[42752, 42774], 2], [[42775, 42778], 2], [[42779, 42783], 2], [[42784, 42785], 2], [42786, 1, "\uA723"], [42787, 2], [42788, 1, "\uA725"], [42789, 2], [42790, 1, "\uA727"], [42791, 2], [42792, 1, "\uA729"], [42793, 2], [42794, 1, "\uA72B"], [42795, 2], [42796, 1, "\uA72D"], [42797, 2], [42798, 1, "\uA72F"], [[42799, 42801], 2], [42802, 1, "\uA733"], [42803, 2], [42804, 1, "\uA735"], [42805, 2], [42806, 1, "\uA737"], [42807, 2], [42808, 1, "\uA739"], [42809, 2], [42810, 1, "\uA73B"], [42811, 2], [42812, 1, "\uA73D"], [42813, 2], [42814, 1, "\uA73F"], [42815, 2], [42816, 1, "\uA741"], [42817, 2], [42818, 1, "\uA743"], [42819, 2], [42820, 1, "\uA745"], [42821, 2], [42822, 1, "\uA747"], [42823, 2], [42824, 1, "\uA749"], [42825, 2], [42826, 1, "\uA74B"], [42827, 2], [42828, 1, "\uA74D"], [42829, 2], [42830, 1, "\uA74F"], [42831, 2], [42832, 1, "\uA751"], [42833, 2], [42834, 1, "\uA753"], [42835, 2], [42836, 1, "\uA755"], [42837, 2], [42838, 1, "\uA757"], [42839, 2], [42840, 1, "\uA759"], [42841, 2], [42842, 1, "\uA75B"], [42843, 2], [42844, 1, "\uA75D"], [42845, 2], [42846, 1, "\uA75F"], [42847, 2], [42848, 1, "\uA761"], [42849, 2], [42850, 1, "\uA763"], [42851, 2], [42852, 1, "\uA765"], [42853, 2], [42854, 1, "\uA767"], [42855, 2], [42856, 1, "\uA769"], [42857, 2], [42858, 1, "\uA76B"], [42859, 2], [42860, 1, "\uA76D"], [42861, 2], [42862, 1, "\uA76F"], [42863, 2], [42864, 1, "\uA76F"], [[42865, 42872], 2], [42873, 1, "\uA77A"], [42874, 2], [42875, 1, "\uA77C"], [42876, 2], [42877, 1, "\u1D79"], [42878, 1, "\uA77F"], [42879, 2], [42880, 1, "\uA781"], [42881, 2], [42882, 1, "\uA783"], [42883, 2], [42884, 1, "\uA785"], [42885, 2], [42886, 1, "\uA787"], [[42887, 42888], 2], [[42889, 42890], 2], [42891, 1, "\uA78C"], [42892, 2], [42893, 1, "\u0265"], [42894, 2], [42895, 2], [42896, 1, "\uA791"], [42897, 2], [42898, 1, "\uA793"], [42899, 2], [[42900, 42901], 2], [42902, 1, "\uA797"], [42903, 2], [42904, 1, "\uA799"], [42905, 2], [42906, 1, "\uA79B"], [42907, 2], [42908, 1, "\uA79D"], [42909, 2], [42910, 1, "\uA79F"], [42911, 2], [42912, 1, "\uA7A1"], [42913, 2], [42914, 1, "\uA7A3"], [42915, 2], [42916, 1, "\uA7A5"], [42917, 2], [42918, 1, "\uA7A7"], [42919, 2], [42920, 1, "\uA7A9"], [42921, 2], [42922, 1, "\u0266"], [42923, 1, "\u025C"], [42924, 1, "\u0261"], [42925, 1, "\u026C"], [42926, 1, "\u026A"], [42927, 2], [42928, 1, "\u029E"], [42929, 1, "\u0287"], [42930, 1, "\u029D"], [42931, 1, "\uAB53"], [42932, 1, "\uA7B5"], [42933, 2], [42934, 1, "\uA7B7"], [42935, 2], [42936, 1, "\uA7B9"], [42937, 2], [42938, 1, "\uA7BB"], [42939, 2], [42940, 1, "\uA7BD"], [42941, 2], [42942, 1, "\uA7BF"], [42943, 2], [42944, 1, "\uA7C1"], [42945, 2], [42946, 1, "\uA7C3"], [42947, 2], [42948, 1, "\uA794"], [42949, 1, "\u0282"], [42950, 1, "\u1D8E"], [42951, 1, "\uA7C8"], [42952, 2], [42953, 1, "\uA7CA"], [42954, 2], [42955, 1, "\u0264"], [42956, 1, "\uA7CD"], [42957, 2], [42958, 1, "\uA7CF"], [42959, 2], [42960, 1, "\uA7D1"], [42961, 2], [42962, 1, "\uA7D3"], [42963, 2], [42964, 1, "\uA7D5"], [42965, 2], [42966, 1, "\uA7D7"], [42967, 2], [42968, 1, "\uA7D9"], [42969, 2], [42970, 1, "\uA7DB"], [42971, 2], [42972, 1, "\u019B"], [42973, 1, "\u0277"], [[42974, 42977], 3], [42978, 1, "\u027C"], [[42979, 42992], 3], [42993, 1, "s"], [42994, 1, "c"], [42995, 1, "f"], [42996, 1, "q"], [42997, 1, "\uA7F6"], [42998, 2], [42999, 2], [43e3, 1, "\u0127"], [43001, 1, "\u0153"], [43002, 2], [[43003, 43007], 2], [[43008, 43047], 2], [[43048, 43051], 2], [43052, 2], [[43053, 43055], 3], [[43056, 43065], 2], [[43066, 43071], 3], [[43072, 43123], 2], [[43124, 43127], 2], [[43128, 43135], 3], [[43136, 43204], 2], [43205, 2], [[43206, 43213], 3], [[43214, 43215], 2], [[43216, 43225], 2], [[43226, 43231], 3], [[43232, 43255], 2], [[43256, 43258], 2], [43259, 2], [43260, 2], [43261, 2], [[43262, 43263], 2], [[43264, 43309], 2], [[43310, 43311], 2], [[43312, 43347], 2], [[43348, 43358], 3], [43359, 2], [[43360, 43388], 2], [[43389, 43391], 3], [[43392, 43456], 2], [[43457, 43469], 2], [43470, 3], [[43471, 43481], 2], [[43482, 43485], 3], [[43486, 43487], 2], [[43488, 43518], 2], [43519, 3], [[43520, 43574], 2], [[43575, 43583], 3], [[43584, 43597], 2], [[43598, 43599], 3], [[43600, 43609], 2], [[43610, 43611], 3], [[43612, 43615], 2], [[43616, 43638], 2], [[43639, 43641], 2], [[43642, 43643], 2], [[43644, 43647], 2], [[43648, 43714], 2], [[43715, 43738], 3], [[43739, 43741], 2], [[43742, 43743], 2], [[43744, 43759], 2], [[43760, 43761], 2], [[43762, 43766], 2], [[43767, 43776], 3], [[43777, 43782], 2], [[43783, 43784], 3], [[43785, 43790], 2], [[43791, 43792], 3], [[43793, 43798], 2], [[43799, 43807], 3], [[43808, 43814], 2], [43815, 3], [[43816, 43822], 2], [43823, 3], [[43824, 43866], 2], [43867, 2], [43868, 1, "\uA727"], [43869, 1, "\uAB37"], [43870, 1, "\u026B"], [43871, 1, "\uAB52"], [[43872, 43875], 2], [[43876, 43877], 2], [[43878, 43879], 2], [43880, 2], [43881, 1, "\u028D"], [[43882, 43883], 2], [43884, 1, "\uAB4B"], [43885, 1, "\uAB4C"], [[43886, 43887], 3], [43888, 1, "\u13A0"], [43889, 1, "\u13A1"], [43890, 1, "\u13A2"], [43891, 1, "\u13A3"], [43892, 1, "\u13A4"], [43893, 1, "\u13A5"], [43894, 1, "\u13A6"], [43895, 1, "\u13A7"], [43896, 1, "\u13A8"], [43897, 1, "\u13A9"], [43898, 1, "\u13AA"], [43899, 1, "\u13AB"], [43900, 1, "\u13AC"], [43901, 1, "\u13AD"], [43902, 1, "\u13AE"], [43903, 1, "\u13AF"], [43904, 1, "\u13B0"], [43905, 1, "\u13B1"], [43906, 1, "\u13B2"], [43907, 1, "\u13B3"], [43908, 1, "\u13B4"], [43909, 1, "\u13B5"], [43910, 1, "\u13B6"], [43911, 1, "\u13B7"], [43912, 1, "\u13B8"], [43913, 1, "\u13B9"], [43914, 1, "\u13BA"], [43915, 1, "\u13BB"], [43916, 1, "\u13BC"], [43917, 1, "\u13BD"], [43918, 1, "\u13BE"], [43919, 1, "\u13BF"], [43920, 1, "\u13C0"], [43921, 1, "\u13C1"], [43922, 1, "\u13C2"], [43923, 1, "\u13C3"], [43924, 1, "\u13C4"], [43925, 1, "\u13C5"], [43926, 1, "\u13C6"], [43927, 1, "\u13C7"], [43928, 1, "\u13C8"], [43929, 1, "\u13C9"], [43930, 1, "\u13CA"], [43931, 1, "\u13CB"], [43932, 1, "\u13CC"], [43933, 1, "\u13CD"], [43934, 1, "\u13CE"], [43935, 1, "\u13CF"], [43936, 1, "\u13D0"], [43937, 1, "\u13D1"], [43938, 1, "\u13D2"], [43939, 1, "\u13D3"], [43940, 1, "\u13D4"], [43941, 1, "\u13D5"], [43942, 1, "\u13D6"], [43943, 1, "\u13D7"], [43944, 1, "\u13D8"], [43945, 1, "\u13D9"], [43946, 1, "\u13DA"], [43947, 1, "\u13DB"], [43948, 1, "\u13DC"], [43949, 1, "\u13DD"], [43950, 1, "\u13DE"], [43951, 1, "\u13DF"], [43952, 1, "\u13E0"], [43953, 1, "\u13E1"], [43954, 1, "\u13E2"], [43955, 1, "\u13E3"], [43956, 1, "\u13E4"], [43957, 1, "\u13E5"], [43958, 1, "\u13E6"], [43959, 1, "\u13E7"], [43960, 1, "\u13E8"], [43961, 1, "\u13E9"], [43962, 1, "\u13EA"], [43963, 1, "\u13EB"], [43964, 1, "\u13EC"], [43965, 1, "\u13ED"], [43966, 1, "\u13EE"], [43967, 1, "\u13EF"], [[43968, 44010], 2], [44011, 2], [[44012, 44013], 2], [[44014, 44015], 3], [[44016, 44025], 2], [[44026, 44031], 3], [[44032, 55203], 2], [[55204, 55215], 3], [[55216, 55238], 2], [[55239, 55242], 3], [[55243, 55291], 2], [[55292, 55295], 3], [[55296, 57343], 3], [[57344, 63743], 3], [63744, 1, "\u8C48"], [63745, 1, "\u66F4"], [63746, 1, "\u8ECA"], [63747, 1, "\u8CC8"], [63748, 1, "\u6ED1"], [63749, 1, "\u4E32"], [63750, 1, "\u53E5"], [[63751, 63752], 1, "\u9F9C"], [63753, 1, "\u5951"], [63754, 1, "\u91D1"], [63755, 1, "\u5587"], [63756, 1, "\u5948"], [63757, 1, "\u61F6"], [63758, 1, "\u7669"], [63759, 1, "\u7F85"], [63760, 1, "\u863F"], [63761, 1, "\u87BA"], [63762, 1, "\u88F8"], [63763, 1, "\u908F"], [63764, 1, "\u6A02"], [63765, 1, "\u6D1B"], [63766, 1, "\u70D9"], [63767, 1, "\u73DE"], [63768, 1, "\u843D"], [63769, 1, "\u916A"], [63770, 1, "\u99F1"], [63771, 1, "\u4E82"], [63772, 1, "\u5375"], [63773, 1, "\u6B04"], [63774, 1, "\u721B"], [63775, 1, "\u862D"], [63776, 1, "\u9E1E"], [63777, 1, "\u5D50"], [63778, 1, "\u6FEB"], [63779, 1, "\u85CD"], [63780, 1, "\u8964"], [63781, 1, "\u62C9"], [63782, 1, "\u81D8"], [63783, 1, "\u881F"], [63784, 1, "\u5ECA"], [63785, 1, "\u6717"], [63786, 1, "\u6D6A"], [63787, 1, "\u72FC"], [63788, 1, "\u90CE"], [63789, 1, "\u4F86"], [63790, 1, "\u51B7"], [63791, 1, "\u52DE"], [63792, 1, "\u64C4"], [63793, 1, "\u6AD3"], [63794, 1, "\u7210"], [63795, 1, "\u76E7"], [63796, 1, "\u8001"], [63797, 1, "\u8606"], [63798, 1, "\u865C"], [63799, 1, "\u8DEF"], [63800, 1, "\u9732"], [63801, 1, "\u9B6F"], [63802, 1, "\u9DFA"], [63803, 1, "\u788C"], [63804, 1, "\u797F"], [63805, 1, "\u7DA0"], [63806, 1, "\u83C9"], [63807, 1, "\u9304"], [63808, 1, "\u9E7F"], [63809, 1, "\u8AD6"], [63810, 1, "\u58DF"], [63811, 1, "\u5F04"], [63812, 1, "\u7C60"], [63813, 1, "\u807E"], [63814, 1, "\u7262"], [63815, 1, "\u78CA"], [63816, 1, "\u8CC2"], [63817, 1, "\u96F7"], [63818, 1, "\u58D8"], [63819, 1, "\u5C62"], [63820, 1, "\u6A13"], [63821, 1, "\u6DDA"], [63822, 1, "\u6F0F"], [63823, 1, "\u7D2F"], [63824, 1, "\u7E37"], [63825, 1, "\u964B"], [63826, 1, "\u52D2"], [63827, 1, "\u808B"], [63828, 1, "\u51DC"], [63829, 1, "\u51CC"], [63830, 1, "\u7A1C"], [63831, 1, "\u7DBE"], [63832, 1, "\u83F1"], [63833, 1, "\u9675"], [63834, 1, "\u8B80"], [63835, 1, "\u62CF"], [63836, 1, "\u6A02"], [63837, 1, "\u8AFE"], [63838, 1, "\u4E39"], [63839, 1, "\u5BE7"], [63840, 1, "\u6012"], [63841, 1, "\u7387"], [63842, 1, "\u7570"], [63843, 1, "\u5317"], [63844, 1, "\u78FB"], [63845, 1, "\u4FBF"], [63846, 1, "\u5FA9"], [63847, 1, "\u4E0D"], [63848, 1, "\u6CCC"], [63849, 1, "\u6578"], [63850, 1, "\u7D22"], [63851, 1, "\u53C3"], [63852, 1, "\u585E"], [63853, 1, "\u7701"], [63854, 1, "\u8449"], [63855, 1, "\u8AAA"], [63856, 1, "\u6BBA"], [63857, 1, "\u8FB0"], [63858, 1, "\u6C88"], [63859, 1, "\u62FE"], [63860, 1, "\u82E5"], [63861, 1, "\u63A0"], [63862, 1, "\u7565"], [63863, 1, "\u4EAE"], [63864, 1, "\u5169"], [63865, 1, "\u51C9"], [63866, 1, "\u6881"], [63867, 1, "\u7CE7"], [63868, 1, "\u826F"], [63869, 1, "\u8AD2"], [63870, 1, "\u91CF"], [63871, 1, "\u52F5"], [63872, 1, "\u5442"], [63873, 1, "\u5973"], [63874, 1, "\u5EEC"], [63875, 1, "\u65C5"], [63876, 1, "\u6FFE"], [63877, 1, "\u792A"], [63878, 1, "\u95AD"], [63879, 1, "\u9A6A"], [63880, 1, "\u9E97"], [63881, 1, "\u9ECE"], [63882, 1, "\u529B"], [63883, 1, "\u66C6"], [63884, 1, "\u6B77"], [63885, 1, "\u8F62"], [63886, 1, "\u5E74"], [63887, 1, "\u6190"], [63888, 1, "\u6200"], [63889, 1, "\u649A"], [63890, 1, "\u6F23"], [63891, 1, "\u7149"], [63892, 1, "\u7489"], [63893, 1, "\u79CA"], [63894, 1, "\u7DF4"], [63895, 1, "\u806F"], [63896, 1, "\u8F26"], [63897, 1, "\u84EE"], [63898, 1, "\u9023"], [63899, 1, "\u934A"], [63900, 1, "\u5217"], [63901, 1, "\u52A3"], [63902, 1, "\u54BD"], [63903, 1, "\u70C8"], [63904, 1, "\u88C2"], [63905, 1, "\u8AAA"], [63906, 1, "\u5EC9"], [63907, 1, "\u5FF5"], [63908, 1, "\u637B"], [63909, 1, "\u6BAE"], [63910, 1, "\u7C3E"], [63911, 1, "\u7375"], [63912, 1, "\u4EE4"], [63913, 1, "\u56F9"], [63914, 1, "\u5BE7"], [63915, 1, "\u5DBA"], [63916, 1, "\u601C"], [63917, 1, "\u73B2"], [63918, 1, "\u7469"], [63919, 1, "\u7F9A"], [63920, 1, "\u8046"], [63921, 1, "\u9234"], [63922, 1, "\u96F6"], [63923, 1, "\u9748"], [63924, 1, "\u9818"], [63925, 1, "\u4F8B"], [63926, 1, "\u79AE"], [63927, 1, "\u91B4"], [63928, 1, "\u96B8"], [63929, 1, "\u60E1"], [63930, 1, "\u4E86"], [63931, 1, "\u50DA"], [63932, 1, "\u5BEE"], [63933, 1, "\u5C3F"], [63934, 1, "\u6599"], [63935, 1, "\u6A02"], [63936, 1, "\u71CE"], [63937, 1, "\u7642"], [63938, 1, "\u84FC"], [63939, 1, "\u907C"], [63940, 1, "\u9F8D"], [63941, 1, "\u6688"], [63942, 1, "\u962E"], [63943, 1, "\u5289"], [63944, 1, "\u677B"], [63945, 1, "\u67F3"], [63946, 1, "\u6D41"], [63947, 1, "\u6E9C"], [63948, 1, "\u7409"], [63949, 1, "\u7559"], [63950, 1, "\u786B"], [63951, 1, "\u7D10"], [63952, 1, "\u985E"], [63953, 1, "\u516D"], [63954, 1, "\u622E"], [63955, 1, "\u9678"], [63956, 1, "\u502B"], [63957, 1, "\u5D19"], [63958, 1, "\u6DEA"], [63959, 1, "\u8F2A"], [63960, 1, "\u5F8B"], [63961, 1, "\u6144"], [63962, 1, "\u6817"], [63963, 1, "\u7387"], [63964, 1, "\u9686"], [63965, 1, "\u5229"], [63966, 1, "\u540F"], [63967, 1, "\u5C65"], [63968, 1, "\u6613"], [63969, 1, "\u674E"], [63970, 1, "\u68A8"], [63971, 1, "\u6CE5"], [63972, 1, "\u7406"], [63973, 1, "\u75E2"], [63974, 1, "\u7F79"], [63975, 1, "\u88CF"], [63976, 1, "\u88E1"], [63977, 1, "\u91CC"], [63978, 1, "\u96E2"], [63979, 1, "\u533F"], [63980, 1, "\u6EBA"], [63981, 1, "\u541D"], [63982, 1, "\u71D0"], [63983, 1, "\u7498"], [63984, 1, "\u85FA"], [63985, 1, "\u96A3"], [63986, 1, "\u9C57"], [63987, 1, "\u9E9F"], [63988, 1, "\u6797"], [63989, 1, "\u6DCB"], [63990, 1, "\u81E8"], [63991, 1, "\u7ACB"], [63992, 1, "\u7B20"], [63993, 1, "\u7C92"], [63994, 1, "\u72C0"], [63995, 1, "\u7099"], [63996, 1, "\u8B58"], [63997, 1, "\u4EC0"], [63998, 1, "\u8336"], [63999, 1, "\u523A"], [64e3, 1, "\u5207"], [64001, 1, "\u5EA6"], [64002, 1, "\u62D3"], [64003, 1, "\u7CD6"], [64004, 1, "\u5B85"], [64005, 1, "\u6D1E"], [64006, 1, "\u66B4"], [64007, 1, "\u8F3B"], [64008, 1, "\u884C"], [64009, 1, "\u964D"], [64010, 1, "\u898B"], [64011, 1, "\u5ED3"], [64012, 1, "\u5140"], [64013, 1, "\u55C0"], [[64014, 64015], 2], [64016, 1, "\u585A"], [64017, 2], [64018, 1, "\u6674"], [[64019, 64020], 2], [64021, 1, "\u51DE"], [64022, 1, "\u732A"], [64023, 1, "\u76CA"], [64024, 1, "\u793C"], [64025, 1, "\u795E"], [64026, 1, "\u7965"], [64027, 1, "\u798F"], [64028, 1, "\u9756"], [64029, 1, "\u7CBE"], [64030, 1, "\u7FBD"], [64031, 2], [64032, 1, "\u8612"], [64033, 2], [64034, 1, "\u8AF8"], [[64035, 64036], 2], [64037, 1, "\u9038"], [64038, 1, "\u90FD"], [[64039, 64041], 2], [64042, 1, "\u98EF"], [64043, 1, "\u98FC"], [64044, 1, "\u9928"], [64045, 1, "\u9DB4"], [64046, 1, "\u90DE"], [64047, 1, "\u96B7"], [64048, 1, "\u4FAE"], [64049, 1, "\u50E7"], [64050, 1, "\u514D"], [64051, 1, "\u52C9"], [64052, 1, "\u52E4"], [64053, 1, "\u5351"], [64054, 1, "\u559D"], [64055, 1, "\u5606"], [64056, 1, "\u5668"], [64057, 1, "\u5840"], [64058, 1, "\u58A8"], [64059, 1, "\u5C64"], [64060, 1, "\u5C6E"], [64061, 1, "\u6094"], [64062, 1, "\u6168"], [64063, 1, "\u618E"], [64064, 1, "\u61F2"], [64065, 1, "\u654F"], [64066, 1, "\u65E2"], [64067, 1, "\u6691"], [64068, 1, "\u6885"], [64069, 1, "\u6D77"], [64070, 1, "\u6E1A"], [64071, 1, "\u6F22"], [64072, 1, "\u716E"], [64073, 1, "\u722B"], [64074, 1, "\u7422"], [64075, 1, "\u7891"], [64076, 1, "\u793E"], [64077, 1, "\u7949"], [64078, 1, "\u7948"], [64079, 1, "\u7950"], [64080, 1, "\u7956"], [64081, 1, "\u795D"], [64082, 1, "\u798D"], [64083, 1, "\u798E"], [64084, 1, "\u7A40"], [64085, 1, "\u7A81"], [64086, 1, "\u7BC0"], [64087, 1, "\u7DF4"], [64088, 1, "\u7E09"], [64089, 1, "\u7E41"], [64090, 1, "\u7F72"], [64091, 1, "\u8005"], [64092, 1, "\u81ED"], [[64093, 64094], 1, "\u8279"], [64095, 1, "\u8457"], [64096, 1, "\u8910"], [64097, 1, "\u8996"], [64098, 1, "\u8B01"], [64099, 1, "\u8B39"], [64100, 1, "\u8CD3"], [64101, 1, "\u8D08"], [64102, 1, "\u8FB6"], [64103, 1, "\u9038"], [64104, 1, "\u96E3"], [64105, 1, "\u97FF"], [64106, 1, "\u983B"], [64107, 1, "\u6075"], [64108, 1, "\u{242EE}"], [64109, 1, "\u8218"], [[64110, 64111], 3], [64112, 1, "\u4E26"], [64113, 1, "\u51B5"], [64114, 1, "\u5168"], [64115, 1, "\u4F80"], [64116, 1, "\u5145"], [64117, 1, "\u5180"], [64118, 1, "\u52C7"], [64119, 1, "\u52FA"], [64120, 1, "\u559D"], [64121, 1, "\u5555"], [64122, 1, "\u5599"], [64123, 1, "\u55E2"], [64124, 1, "\u585A"], [64125, 1, "\u58B3"], [64126, 1, "\u5944"], [64127, 1, "\u5954"], [64128, 1, "\u5A62"], [64129, 1, "\u5B28"], [64130, 1, "\u5ED2"], [64131, 1, "\u5ED9"], [64132, 1, "\u5F69"], [64133, 1, "\u5FAD"], [64134, 1, "\u60D8"], [64135, 1, "\u614E"], [64136, 1, "\u6108"], [64137, 1, "\u618E"], [64138, 1, "\u6160"], [64139, 1, "\u61F2"], [64140, 1, "\u6234"], [64141, 1, "\u63C4"], [64142, 1, "\u641C"], [64143, 1, "\u6452"], [64144, 1, "\u6556"], [64145, 1, "\u6674"], [64146, 1, "\u6717"], [64147, 1, "\u671B"], [64148, 1, "\u6756"], [64149, 1, "\u6B79"], [64150, 1, "\u6BBA"], [64151, 1, "\u6D41"], [64152, 1, "\u6EDB"], [64153, 1, "\u6ECB"], [64154, 1, "\u6F22"], [64155, 1, "\u701E"], [64156, 1, "\u716E"], [64157, 1, "\u77A7"], [64158, 1, "\u7235"], [64159, 1, "\u72AF"], [64160, 1, "\u732A"], [64161, 1, "\u7471"], [64162, 1, "\u7506"], [64163, 1, "\u753B"], [64164, 1, "\u761D"], [64165, 1, "\u761F"], [64166, 1, "\u76CA"], [64167, 1, "\u76DB"], [64168, 1, "\u76F4"], [64169, 1, "\u774A"], [64170, 1, "\u7740"], [64171, 1, "\u78CC"], [64172, 1, "\u7AB1"], [64173, 1, "\u7BC0"], [64174, 1, "\u7C7B"], [64175, 1, "\u7D5B"], [64176, 1, "\u7DF4"], [64177, 1, "\u7F3E"], [64178, 1, "\u8005"], [64179, 1, "\u8352"], [64180, 1, "\u83EF"], [64181, 1, "\u8779"], [64182, 1, "\u8941"], [64183, 1, "\u8986"], [64184, 1, "\u8996"], [64185, 1, "\u8ABF"], [64186, 1, "\u8AF8"], [64187, 1, "\u8ACB"], [64188, 1, "\u8B01"], [64189, 1, "\u8AFE"], [64190, 1, "\u8AED"], [64191, 1, "\u8B39"], [64192, 1, "\u8B8A"], [64193, 1, "\u8D08"], [64194, 1, "\u8F38"], [64195, 1, "\u9072"], [64196, 1, "\u9199"], [64197, 1, "\u9276"], [64198, 1, "\u967C"], [64199, 1, "\u96E3"], [64200, 1, "\u9756"], [64201, 1, "\u97DB"], [64202, 1, "\u97FF"], [64203, 1, "\u980B"], [64204, 1, "\u983B"], [64205, 1, "\u9B12"], [64206, 1, "\u9F9C"], [64207, 1, "\u{2284A}"], [64208, 1, "\u{22844}"], [64209, 1, "\u{233D5}"], [64210, 1, "\u3B9D"], [64211, 1, "\u4018"], [64212, 1, "\u4039"], [64213, 1, "\u{25249}"], [64214, 1, "\u{25CD0}"], [64215, 1, "\u{27ED3}"], [64216, 1, "\u9F43"], [64217, 1, "\u9F8E"], [[64218, 64255], 3], [64256, 1, "ff"], [64257, 1, "fi"], [64258, 1, "fl"], [64259, 1, "ffi"], [64260, 1, "ffl"], [[64261, 64262], 1, "st"], [[64263, 64274], 3], [64275, 1, "\u0574\u0576"], [64276, 1, "\u0574\u0565"], [64277, 1, "\u0574\u056B"], [64278, 1, "\u057E\u0576"], [64279, 1, "\u0574\u056D"], [[64280, 64284], 3], [64285, 1, "\u05D9\u05B4"], [64286, 2], [64287, 1, "\u05F2\u05B7"], [64288, 1, "\u05E2"], [64289, 1, "\u05D0"], [64290, 1, "\u05D3"], [64291, 1, "\u05D4"], [64292, 1, "\u05DB"], [64293, 1, "\u05DC"], [64294, 1, "\u05DD"], [64295, 1, "\u05E8"], [64296, 1, "\u05EA"], [64297, 1, "+"], [64298, 1, "\u05E9\u05C1"], [64299, 1, "\u05E9\u05C2"], [64300, 1, "\u05E9\u05BC\u05C1"], [64301, 1, "\u05E9\u05BC\u05C2"], [64302, 1, "\u05D0\u05B7"], [64303, 1, "\u05D0\u05B8"], [64304, 1, "\u05D0\u05BC"], [64305, 1, "\u05D1\u05BC"], [64306, 1, "\u05D2\u05BC"], [64307, 1, "\u05D3\u05BC"], [64308, 1, "\u05D4\u05BC"], [64309, 1, "\u05D5\u05BC"], [64310, 1, "\u05D6\u05BC"], [64311, 3], [64312, 1, "\u05D8\u05BC"], [64313, 1, "\u05D9\u05BC"], [64314, 1, "\u05DA\u05BC"], [64315, 1, "\u05DB\u05BC"], [64316, 1, "\u05DC\u05BC"], [64317, 3], [64318, 1, "\u05DE\u05BC"], [64319, 3], [64320, 1, "\u05E0\u05BC"], [64321, 1, "\u05E1\u05BC"], [64322, 3], [64323, 1, "\u05E3\u05BC"], [64324, 1, "\u05E4\u05BC"], [64325, 3], [64326, 1, "\u05E6\u05BC"], [64327, 1, "\u05E7\u05BC"], [64328, 1, "\u05E8\u05BC"], [64329, 1, "\u05E9\u05BC"], [64330, 1, "\u05EA\u05BC"], [64331, 1, "\u05D5\u05B9"], [64332, 1, "\u05D1\u05BF"], [64333, 1, "\u05DB\u05BF"], [64334, 1, "\u05E4\u05BF"], [64335, 1, "\u05D0\u05DC"], [[64336, 64337], 1, "\u0671"], [[64338, 64341], 1, "\u067B"], [[64342, 64345], 1, "\u067E"], [[64346, 64349], 1, "\u0680"], [[64350, 64353], 1, "\u067A"], [[64354, 64357], 1, "\u067F"], [[64358, 64361], 1, "\u0679"], [[64362, 64365], 1, "\u06A4"], [[64366, 64369], 1, "\u06A6"], [[64370, 64373], 1, "\u0684"], [[64374, 64377], 1, "\u0683"], [[64378, 64381], 1, "\u0686"], [[64382, 64385], 1, "\u0687"], [[64386, 64387], 1, "\u068D"], [[64388, 64389], 1, "\u068C"], [[64390, 64391], 1, "\u068E"], [[64392, 64393], 1, "\u0688"], [[64394, 64395], 1, "\u0698"], [[64396, 64397], 1, "\u0691"], [[64398, 64401], 1, "\u06A9"], [[64402, 64405], 1, "\u06AF"], [[64406, 64409], 1, "\u06B3"], [[64410, 64413], 1, "\u06B1"], [[64414, 64415], 1, "\u06BA"], [[64416, 64419], 1, "\u06BB"], [[64420, 64421], 1, "\u06C0"], [[64422, 64425], 1, "\u06C1"], [[64426, 64429], 1, "\u06BE"], [[64430, 64431], 1, "\u06D2"], [[64432, 64433], 1, "\u06D3"], [[64434, 64449], 2], [64450, 2], [[64451, 64466], 2], [[64467, 64470], 1, "\u06AD"], [[64471, 64472], 1, "\u06C7"], [[64473, 64474], 1, "\u06C6"], [[64475, 64476], 1, "\u06C8"], [64477, 1, "\u06C7\u0674"], [[64478, 64479], 1, "\u06CB"], [[64480, 64481], 1, "\u06C5"], [[64482, 64483], 1, "\u06C9"], [[64484, 64487], 1, "\u06D0"], [[64488, 64489], 1, "\u0649"], [[64490, 64491], 1, "\u0626\u0627"], [[64492, 64493], 1, "\u0626\u06D5"], [[64494, 64495], 1, "\u0626\u0648"], [[64496, 64497], 1, "\u0626\u06C7"], [[64498, 64499], 1, "\u0626\u06C6"], [[64500, 64501], 1, "\u0626\u06C8"], [[64502, 64504], 1, "\u0626\u06D0"], [[64505, 64507], 1, "\u0626\u0649"], [[64508, 64511], 1, "\u06CC"], [64512, 1, "\u0626\u062C"], [64513, 1, "\u0626\u062D"], [64514, 1, "\u0626\u0645"], [64515, 1, "\u0626\u0649"], [64516, 1, "\u0626\u064A"], [64517, 1, "\u0628\u062C"], [64518, 1, "\u0628\u062D"], [64519, 1, "\u0628\u062E"], [64520, 1, "\u0628\u0645"], [64521, 1, "\u0628\u0649"], [64522, 1, "\u0628\u064A"], [64523, 1, "\u062A\u062C"], [64524, 1, "\u062A\u062D"], [64525, 1, "\u062A\u062E"], [64526, 1, "\u062A\u0645"], [64527, 1, "\u062A\u0649"], [64528, 1, "\u062A\u064A"], [64529, 1, "\u062B\u062C"], [64530, 1, "\u062B\u0645"], [64531, 1, "\u062B\u0649"], [64532, 1, "\u062B\u064A"], [64533, 1, "\u062C\u062D"], [64534, 1, "\u062C\u0645"], [64535, 1, "\u062D\u062C"], [64536, 1, "\u062D\u0645"], [64537, 1, "\u062E\u062C"], [64538, 1, "\u062E\u062D"], [64539, 1, "\u062E\u0645"], [64540, 1, "\u0633\u062C"], [64541, 1, "\u0633\u062D"], [64542, 1, "\u0633\u062E"], [64543, 1, "\u0633\u0645"], [64544, 1, "\u0635\u062D"], [64545, 1, "\u0635\u0645"], [64546, 1, "\u0636\u062C"], [64547, 1, "\u0636\u062D"], [64548, 1, "\u0636\u062E"], [64549, 1, "\u0636\u0645"], [64550, 1, "\u0637\u062D"], [64551, 1, "\u0637\u0645"], [64552, 1, "\u0638\u0645"], [64553, 1, "\u0639\u062C"], [64554, 1, "\u0639\u0645"], [64555, 1, "\u063A\u062C"], [64556, 1, "\u063A\u0645"], [64557, 1, "\u0641\u062C"], [64558, 1, "\u0641\u062D"], [64559, 1, "\u0641\u062E"], [64560, 1, "\u0641\u0645"], [64561, 1, "\u0641\u0649"], [64562, 1, "\u0641\u064A"], [64563, 1, "\u0642\u062D"], [64564, 1, "\u0642\u0645"], [64565, 1, "\u0642\u0649"], [64566, 1, "\u0642\u064A"], [64567, 1, "\u0643\u0627"], [64568, 1, "\u0643\u062C"], [64569, 1, "\u0643\u062D"], [64570, 1, "\u0643\u062E"], [64571, 1, "\u0643\u0644"], [64572, 1, "\u0643\u0645"], [64573, 1, "\u0643\u0649"], [64574, 1, "\u0643\u064A"], [64575, 1, "\u0644\u062C"], [64576, 1, "\u0644\u062D"], [64577, 1, "\u0644\u062E"], [64578, 1, "\u0644\u0645"], [64579, 1, "\u0644\u0649"], [64580, 1, "\u0644\u064A"], [64581, 1, "\u0645\u062C"], [64582, 1, "\u0645\u062D"], [64583, 1, "\u0645\u062E"], [64584, 1, "\u0645\u0645"], [64585, 1, "\u0645\u0649"], [64586, 1, "\u0645\u064A"], [64587, 1, "\u0646\u062C"], [64588, 1, "\u0646\u062D"], [64589, 1, "\u0646\u062E"], [64590, 1, "\u0646\u0645"], [64591, 1, "\u0646\u0649"], [64592, 1, "\u0646\u064A"], [64593, 1, "\u0647\u062C"], [64594, 1, "\u0647\u0645"], [64595, 1, "\u0647\u0649"], [64596, 1, "\u0647\u064A"], [64597, 1, "\u064A\u062C"], [64598, 1, "\u064A\u062D"], [64599, 1, "\u064A\u062E"], [64600, 1, "\u064A\u0645"], [64601, 1, "\u064A\u0649"], [64602, 1, "\u064A\u064A"], [64603, 1, "\u0630\u0670"], [64604, 1, "\u0631\u0670"], [64605, 1, "\u0649\u0670"], [64606, 1, " \u064C\u0651"], [64607, 1, " \u064D\u0651"], [64608, 1, " \u064E\u0651"], [64609, 1, " \u064F\u0651"], [64610, 1, " \u0650\u0651"], [64611, 1, " \u0651\u0670"], [64612, 1, "\u0626\u0631"], [64613, 1, "\u0626\u0632"], [64614, 1, "\u0626\u0645"], [64615, 1, "\u0626\u0646"], [64616, 1, "\u0626\u0649"], [64617, 1, "\u0626\u064A"], [64618, 1, "\u0628\u0631"], [64619, 1, "\u0628\u0632"], [64620, 1, "\u0628\u0645"], [64621, 1, "\u0628\u0646"], [64622, 1, "\u0628\u0649"], [64623, 1, "\u0628\u064A"], [64624, 1, "\u062A\u0631"], [64625, 1, "\u062A\u0632"], [64626, 1, "\u062A\u0645"], [64627, 1, "\u062A\u0646"], [64628, 1, "\u062A\u0649"], [64629, 1, "\u062A\u064A"], [64630, 1, "\u062B\u0631"], [64631, 1, "\u062B\u0632"], [64632, 1, "\u062B\u0645"], [64633, 1, "\u062B\u0646"], [64634, 1, "\u062B\u0649"], [64635, 1, "\u062B\u064A"], [64636, 1, "\u0641\u0649"], [64637, 1, "\u0641\u064A"], [64638, 1, "\u0642\u0649"], [64639, 1, "\u0642\u064A"], [64640, 1, "\u0643\u0627"], [64641, 1, "\u0643\u0644"], [64642, 1, "\u0643\u0645"], [64643, 1, "\u0643\u0649"], [64644, 1, "\u0643\u064A"], [64645, 1, "\u0644\u0645"], [64646, 1, "\u0644\u0649"], [64647, 1, "\u0644\u064A"], [64648, 1, "\u0645\u0627"], [64649, 1, "\u0645\u0645"], [64650, 1, "\u0646\u0631"], [64651, 1, "\u0646\u0632"], [64652, 1, "\u0646\u0645"], [64653, 1, "\u0646\u0646"], [64654, 1, "\u0646\u0649"], [64655, 1, "\u0646\u064A"], [64656, 1, "\u0649\u0670"], [64657, 1, "\u064A\u0631"], [64658, 1, "\u064A\u0632"], [64659, 1, "\u064A\u0645"], [64660, 1, "\u064A\u0646"], [64661, 1, "\u064A\u0649"], [64662, 1, "\u064A\u064A"], [64663, 1, "\u0626\u062C"], [64664, 1, "\u0626\u062D"], [64665, 1, "\u0626\u062E"], [64666, 1, "\u0626\u0645"], [64667, 1, "\u0626\u0647"], [64668, 1, "\u0628\u062C"], [64669, 1, "\u0628\u062D"], [64670, 1, "\u0628\u062E"], [64671, 1, "\u0628\u0645"], [64672, 1, "\u0628\u0647"], [64673, 1, "\u062A\u062C"], [64674, 1, "\u062A\u062D"], [64675, 1, "\u062A\u062E"], [64676, 1, "\u062A\u0645"], [64677, 1, "\u062A\u0647"], [64678, 1, "\u062B\u0645"], [64679, 1, "\u062C\u062D"], [64680, 1, "\u062C\u0645"], [64681, 1, "\u062D\u062C"], [64682, 1, "\u062D\u0645"], [64683, 1, "\u062E\u062C"], [64684, 1, "\u062E\u0645"], [64685, 1, "\u0633\u062C"], [64686, 1, "\u0633\u062D"], [64687, 1, "\u0633\u062E"], [64688, 1, "\u0633\u0645"], [64689, 1, "\u0635\u062D"], [64690, 1, "\u0635\u062E"], [64691, 1, "\u0635\u0645"], [64692, 1, "\u0636\u062C"], [64693, 1, "\u0636\u062D"], [64694, 1, "\u0636\u062E"], [64695, 1, "\u0636\u0645"], [64696, 1, "\u0637\u062D"], [64697, 1, "\u0638\u0645"], [64698, 1, "\u0639\u062C"], [64699, 1, "\u0639\u0645"], [64700, 1, "\u063A\u062C"], [64701, 1, "\u063A\u0645"], [64702, 1, "\u0641\u062C"], [64703, 1, "\u0641\u062D"], [64704, 1, "\u0641\u062E"], [64705, 1, "\u0641\u0645"], [64706, 1, "\u0642\u062D"], [64707, 1, "\u0642\u0645"], [64708, 1, "\u0643\u062C"], [64709, 1, "\u0643\u062D"], [64710, 1, "\u0643\u062E"], [64711, 1, "\u0643\u0644"], [64712, 1, "\u0643\u0645"], [64713, 1, "\u0644\u062C"], [64714, 1, "\u0644\u062D"], [64715, 1, "\u0644\u062E"], [64716, 1, "\u0644\u0645"], [64717, 1, "\u0644\u0647"], [64718, 1, "\u0645\u062C"], [64719, 1, "\u0645\u062D"], [64720, 1, "\u0645\u062E"], [64721, 1, "\u0645\u0645"], [64722, 1, "\u0646\u062C"], [64723, 1, "\u0646\u062D"], [64724, 1, "\u0646\u062E"], [64725, 1, "\u0646\u0645"], [64726, 1, "\u0646\u0647"], [64727, 1, "\u0647\u062C"], [64728, 1, "\u0647\u0645"], [64729, 1, "\u0647\u0670"], [64730, 1, "\u064A\u062C"], [64731, 1, "\u064A\u062D"], [64732, 1, "\u064A\u062E"], [64733, 1, "\u064A\u0645"], [64734, 1, "\u064A\u0647"], [64735, 1, "\u0626\u0645"], [64736, 1, "\u0626\u0647"], [64737, 1, "\u0628\u0645"], [64738, 1, "\u0628\u0647"], [64739, 1, "\u062A\u0645"], [64740, 1, "\u062A\u0647"], [64741, 1, "\u062B\u0645"], [64742, 1, "\u062B\u0647"], [64743, 1, "\u0633\u0645"], [64744, 1, "\u0633\u0647"], [64745, 1, "\u0634\u0645"], [64746, 1, "\u0634\u0647"], [64747, 1, "\u0643\u0644"], [64748, 1, "\u0643\u0645"], [64749, 1, "\u0644\u0645"], [64750, 1, "\u0646\u0645"], [64751, 1, "\u0646\u0647"], [64752, 1, "\u064A\u0645"], [64753, 1, "\u064A\u0647"], [64754, 1, "\u0640\u064E\u0651"], [64755, 1, "\u0640\u064F\u0651"], [64756, 1, "\u0640\u0650\u0651"], [64757, 1, "\u0637\u0649"], [64758, 1, "\u0637\u064A"], [64759, 1, "\u0639\u0649"], [64760, 1, "\u0639\u064A"], [64761, 1, "\u063A\u0649"], [64762, 1, "\u063A\u064A"], [64763, 1, "\u0633\u0649"], [64764, 1, "\u0633\u064A"], [64765, 1, "\u0634\u0649"], [64766, 1, "\u0634\u064A"], [64767, 1, "\u062D\u0649"], [64768, 1, "\u062D\u064A"], [64769, 1, "\u062C\u0649"], [64770, 1, "\u062C\u064A"], [64771, 1, "\u062E\u0649"], [64772, 1, "\u062E\u064A"], [64773, 1, "\u0635\u0649"], [64774, 1, "\u0635\u064A"], [64775, 1, "\u0636\u0649"], [64776, 1, "\u0636\u064A"], [64777, 1, "\u0634\u062C"], [64778, 1, "\u0634\u062D"], [64779, 1, "\u0634\u062E"], [64780, 1, "\u0634\u0645"], [64781, 1, "\u0634\u0631"], [64782, 1, "\u0633\u0631"], [64783, 1, "\u0635\u0631"], [64784, 1, "\u0636\u0631"], [64785, 1, "\u0637\u0649"], [64786, 1, "\u0637\u064A"], [64787, 1, "\u0639\u0649"], [64788, 1, "\u0639\u064A"], [64789, 1, "\u063A\u0649"], [64790, 1, "\u063A\u064A"], [64791, 1, "\u0633\u0649"], [64792, 1, "\u0633\u064A"], [64793, 1, "\u0634\u0649"], [64794, 1, "\u0634\u064A"], [64795, 1, "\u062D\u0649"], [64796, 1, "\u062D\u064A"], [64797, 1, "\u062C\u0649"], [64798, 1, "\u062C\u064A"], [64799, 1, "\u062E\u0649"], [64800, 1, "\u062E\u064A"], [64801, 1, "\u0635\u0649"], [64802, 1, "\u0635\u064A"], [64803, 1, "\u0636\u0649"], [64804, 1, "\u0636\u064A"], [64805, 1, "\u0634\u062C"], [64806, 1, "\u0634\u062D"], [64807, 1, "\u0634\u062E"], [64808, 1, "\u0634\u0645"], [64809, 1, "\u0634\u0631"], [64810, 1, "\u0633\u0631"], [64811, 1, "\u0635\u0631"], [64812, 1, "\u0636\u0631"], [64813, 1, "\u0634\u062C"], [64814, 1, "\u0634\u062D"], [64815, 1, "\u0634\u062E"], [64816, 1, "\u0634\u0645"], [64817, 1, "\u0633\u0647"], [64818, 1, "\u0634\u0647"], [64819, 1, "\u0637\u0645"], [64820, 1, "\u0633\u062C"], [64821, 1, "\u0633\u062D"], [64822, 1, "\u0633\u062E"], [64823, 1, "\u0634\u062C"], [64824, 1, "\u0634\u062D"], [64825, 1, "\u0634\u062E"], [64826, 1, "\u0637\u0645"], [64827, 1, "\u0638\u0645"], [[64828, 64829], 1, "\u0627\u064B"], [[64830, 64831], 2], [[64832, 64847], 2], [64848, 1, "\u062A\u062C\u0645"], [[64849, 64850], 1, "\u062A\u062D\u062C"], [64851, 1, "\u062A\u062D\u0645"], [64852, 1, "\u062A\u062E\u0645"], [64853, 1, "\u062A\u0645\u062C"], [64854, 1, "\u062A\u0645\u062D"], [64855, 1, "\u062A\u0645\u062E"], [[64856, 64857], 1, "\u062C\u0645\u062D"], [64858, 1, "\u062D\u0645\u064A"], [64859, 1, "\u062D\u0645\u0649"], [64860, 1, "\u0633\u062D\u062C"], [64861, 1, "\u0633\u062C\u062D"], [64862, 1, "\u0633\u062C\u0649"], [[64863, 64864], 1, "\u0633\u0645\u062D"], [64865, 1, "\u0633\u0645\u062C"], [[64866, 64867], 1, "\u0633\u0645\u0645"], [[64868, 64869], 1, "\u0635\u062D\u062D"], [64870, 1, "\u0635\u0645\u0645"], [[64871, 64872], 1, "\u0634\u062D\u0645"], [64873, 1, "\u0634\u062C\u064A"], [[64874, 64875], 1, "\u0634\u0645\u062E"], [[64876, 64877], 1, "\u0634\u0645\u0645"], [64878, 1, "\u0636\u062D\u0649"], [[64879, 64880], 1, "\u0636\u062E\u0645"], [[64881, 64882], 1, "\u0637\u0645\u062D"], [64883, 1, "\u0637\u0645\u0645"], [64884, 1, "\u0637\u0645\u064A"], [64885, 1, "\u0639\u062C\u0645"], [[64886, 64887], 1, "\u0639\u0645\u0645"], [64888, 1, "\u0639\u0645\u0649"], [64889, 1, "\u063A\u0645\u0645"], [64890, 1, "\u063A\u0645\u064A"], [64891, 1, "\u063A\u0645\u0649"], [[64892, 64893], 1, "\u0641\u062E\u0645"], [64894, 1, "\u0642\u0645\u062D"], [64895, 1, "\u0642\u0645\u0645"], [64896, 1, "\u0644\u062D\u0645"], [64897, 1, "\u0644\u062D\u064A"], [64898, 1, "\u0644\u062D\u0649"], [[64899, 64900], 1, "\u0644\u062C\u062C"], [[64901, 64902], 1, "\u0644\u062E\u0645"], [[64903, 64904], 1, "\u0644\u0645\u062D"], [64905, 1, "\u0645\u062D\u062C"], [64906, 1, "\u0645\u062D\u0645"], [64907, 1, "\u0645\u062D\u064A"], [64908, 1, "\u0645\u062C\u062D"], [64909, 1, "\u0645\u062C\u0645"], [64910, 1, "\u0645\u062E\u062C"], [64911, 1, "\u0645\u062E\u0645"], [[64912, 64913], 2], [64914, 1, "\u0645\u062C\u062E"], [64915, 1, "\u0647\u0645\u062C"], [64916, 1, "\u0647\u0645\u0645"], [64917, 1, "\u0646\u062D\u0645"], [64918, 1, "\u0646\u062D\u0649"], [[64919, 64920], 1, "\u0646\u062C\u0645"], [64921, 1, "\u0646\u062C\u0649"], [64922, 1, "\u0646\u0645\u064A"], [64923, 1, "\u0646\u0645\u0649"], [[64924, 64925], 1, "\u064A\u0645\u0645"], [64926, 1, "\u0628\u062E\u064A"], [64927, 1, "\u062A\u062C\u064A"], [64928, 1, "\u062A\u062C\u0649"], [64929, 1, "\u062A\u062E\u064A"], [64930, 1, "\u062A\u062E\u0649"], [64931, 1, "\u062A\u0645\u064A"], [64932, 1, "\u062A\u0645\u0649"], [64933, 1, "\u062C\u0645\u064A"], [64934, 1, "\u062C\u062D\u0649"], [64935, 1, "\u062C\u0645\u0649"], [64936, 1, "\u0633\u062E\u0649"], [64937, 1, "\u0635\u062D\u064A"], [64938, 1, "\u0634\u062D\u064A"], [64939, 1, "\u0636\u062D\u064A"], [64940, 1, "\u0644\u062C\u064A"], [64941, 1, "\u0644\u0645\u064A"], [64942, 1, "\u064A\u062D\u064A"], [64943, 1, "\u064A\u062C\u064A"], [64944, 1, "\u064A\u0645\u064A"], [64945, 1, "\u0645\u0645\u064A"], [64946, 1, "\u0642\u0645\u064A"], [64947, 1, "\u0646\u062D\u064A"], [64948, 1, "\u0642\u0645\u062D"], [64949, 1, "\u0644\u062D\u0645"], [64950, 1, "\u0639\u0645\u064A"], [64951, 1, "\u0643\u0645\u064A"], [64952, 1, "\u0646\u062C\u062D"], [64953, 1, "\u0645\u062E\u064A"], [64954, 1, "\u0644\u062C\u0645"], [64955, 1, "\u0643\u0645\u0645"], [64956, 1, "\u0644\u062C\u0645"], [64957, 1, "\u0646\u062C\u062D"], [64958, 1, "\u062C\u062D\u064A"], [64959, 1, "\u062D\u062C\u064A"], [64960, 1, "\u0645\u062C\u064A"], [64961, 1, "\u0641\u0645\u064A"], [64962, 1, "\u0628\u062D\u064A"], [64963, 1, "\u0643\u0645\u0645"], [64964, 1, "\u0639\u062C\u0645"], [64965, 1, "\u0635\u0645\u0645"], [64966, 1, "\u0633\u062E\u064A"], [64967, 1, "\u0646\u062C\u064A"], [[64968, 64974], 2], [64975, 2], [[64976, 65007], 3], [65008, 1, "\u0635\u0644\u06D2"], [65009, 1, "\u0642\u0644\u06D2"], [65010, 1, "\u0627\u0644\u0644\u0647"], [65011, 1, "\u0627\u0643\u0628\u0631"], [65012, 1, "\u0645\u062D\u0645\u062F"], [65013, 1, "\u0635\u0644\u0639\u0645"], [65014, 1, "\u0631\u0633\u0648\u0644"], [65015, 1, "\u0639\u0644\u064A\u0647"], [65016, 1, "\u0648\u0633\u0644\u0645"], [65017, 1, "\u0635\u0644\u0649"], [65018, 1, "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064A\u0647 \u0648\u0633\u0644\u0645"], [65019, 1, "\u062C\u0644 \u062C\u0644\u0627\u0644\u0647"], [65020, 1, "\u0631\u06CC\u0627\u0644"], [65021, 2], [[65022, 65023], 2], [[65024, 65039], 7], [65040, 1, ","], [65041, 1, "\u3001"], [65042, 3], [65043, 1, ":"], [65044, 1, ";"], [65045, 1, "!"], [65046, 1, "?"], [65047, 1, "\u3016"], [65048, 1, "\u3017"], [65049, 3], [[65050, 65055], 3], [[65056, 65059], 2], [[65060, 65062], 2], [[65063, 65069], 2], [[65070, 65071], 2], [65072, 3], [65073, 1, "\u2014"], [65074, 1, "\u2013"], [[65075, 65076], 1, "_"], [65077, 1, "("], [65078, 1, ")"], [65079, 1, "{"], [65080, 1, "}"], [65081, 1, "\u3014"], [65082, 1, "\u3015"], [65083, 1, "\u3010"], [65084, 1, "\u3011"], [65085, 1, "\u300A"], [65086, 1, "\u300B"], [65087, 1, "\u3008"], [65088, 1, "\u3009"], [65089, 1, "\u300C"], [65090, 1, "\u300D"], [65091, 1, "\u300E"], [65092, 1, "\u300F"], [[65093, 65094], 2], [65095, 1, "["], [65096, 1, "]"], [[65097, 65100], 1, " \u0305"], [[65101, 65103], 1, "_"], [65104, 1, ","], [65105, 1, "\u3001"], [65106, 3], [65107, 3], [65108, 1, ";"], [65109, 1, ":"], [65110, 1, "?"], [65111, 1, "!"], [65112, 1, "\u2014"], [65113, 1, "("], [65114, 1, ")"], [65115, 1, "{"], [65116, 1, "}"], [65117, 1, "\u3014"], [65118, 1, "\u3015"], [65119, 1, "#"], [65120, 1, "&"], [65121, 1, "*"], [65122, 1, "+"], [65123, 1, "-"], [65124, 1, "<"], [65125, 1, ">"], [65126, 1, "="], [65127, 3], [65128, 1, "\\"], [65129, 1, "$"], [65130, 1, "%"], [65131, 1, "@"], [[65132, 65135], 3], [65136, 1, " \u064B"], [65137, 1, "\u0640\u064B"], [65138, 1, " \u064C"], [65139, 2], [65140, 1, " \u064D"], [65141, 3], [65142, 1, " \u064E"], [65143, 1, "\u0640\u064E"], [65144, 1, " \u064F"], [65145, 1, "\u0640\u064F"], [65146, 1, " \u0650"], [65147, 1, "\u0640\u0650"], [65148, 1, " \u0651"], [65149, 1, "\u0640\u0651"], [65150, 1, " \u0652"], [65151, 1, "\u0640\u0652"], [65152, 1, "\u0621"], [[65153, 65154], 1, "\u0622"], [[65155, 65156], 1, "\u0623"], [[65157, 65158], 1, "\u0624"], [[65159, 65160], 1, "\u0625"], [[65161, 65164], 1, "\u0626"], [[65165, 65166], 1, "\u0627"], [[65167, 65170], 1, "\u0628"], [[65171, 65172], 1, "\u0629"], [[65173, 65176], 1, "\u062A"], [[65177, 65180], 1, "\u062B"], [[65181, 65184], 1, "\u062C"], [[65185, 65188], 1, "\u062D"], [[65189, 65192], 1, "\u062E"], [[65193, 65194], 1, "\u062F"], [[65195, 65196], 1, "\u0630"], [[65197, 65198], 1, "\u0631"], [[65199, 65200], 1, "\u0632"], [[65201, 65204], 1, "\u0633"], [[65205, 65208], 1, "\u0634"], [[65209, 65212], 1, "\u0635"], [[65213, 65216], 1, "\u0636"], [[65217, 65220], 1, "\u0637"], [[65221, 65224], 1, "\u0638"], [[65225, 65228], 1, "\u0639"], [[65229, 65232], 1, "\u063A"], [[65233, 65236], 1, "\u0641"], [[65237, 65240], 1, "\u0642"], [[65241, 65244], 1, "\u0643"], [[65245, 65248], 1, "\u0644"], [[65249, 65252], 1, "\u0645"], [[65253, 65256], 1, "\u0646"], [[65257, 65260], 1, "\u0647"], [[65261, 65262], 1, "\u0648"], [[65263, 65264], 1, "\u0649"], [[65265, 65268], 1, "\u064A"], [[65269, 65270], 1, "\u0644\u0622"], [[65271, 65272], 1, "\u0644\u0623"], [[65273, 65274], 1, "\u0644\u0625"], [[65275, 65276], 1, "\u0644\u0627"], [[65277, 65278], 3], [65279, 7], [65280, 3], [65281, 1, "!"], [65282, 1, '"'], [65283, 1, "#"], [65284, 1, "$"], [65285, 1, "%"], [65286, 1, "&"], [65287, 1, "'"], [65288, 1, "("], [65289, 1, ")"], [65290, 1, "*"], [65291, 1, "+"], [65292, 1, ","], [65293, 1, "-"], [65294, 1, "."], [65295, 1, "/"], [65296, 1, "0"], [65297, 1, "1"], [65298, 1, "2"], [65299, 1, "3"], [65300, 1, "4"], [65301, 1, "5"], [65302, 1, "6"], [65303, 1, "7"], [65304, 1, "8"], [65305, 1, "9"], [65306, 1, ":"], [65307, 1, ";"], [65308, 1, "<"], [65309, 1, "="], [65310, 1, ">"], [65311, 1, "?"], [65312, 1, "@"], [65313, 1, "a"], [65314, 1, "b"], [65315, 1, "c"], [65316, 1, "d"], [65317, 1, "e"], [65318, 1, "f"], [65319, 1, "g"], [65320, 1, "h"], [65321, 1, "i"], [65322, 1, "j"], [65323, 1, "k"], [65324, 1, "l"], [65325, 1, "m"], [65326, 1, "n"], [65327, 1, "o"], [65328, 1, "p"], [65329, 1, "q"], [65330, 1, "r"], [65331, 1, "s"], [65332, 1, "t"], [65333, 1, "u"], [65334, 1, "v"], [65335, 1, "w"], [65336, 1, "x"], [65337, 1, "y"], [65338, 1, "z"], [65339, 1, "["], [65340, 1, "\\"], [65341, 1, "]"], [65342, 1, "^"], [65343, 1, "_"], [65344, 1, "`"], [65345, 1, "a"], [65346, 1, "b"], [65347, 1, "c"], [65348, 1, "d"], [65349, 1, "e"], [65350, 1, "f"], [65351, 1, "g"], [65352, 1, "h"], [65353, 1, "i"], [65354, 1, "j"], [65355, 1, "k"], [65356, 1, "l"], [65357, 1, "m"], [65358, 1, "n"], [65359, 1, "o"], [65360, 1, "p"], [65361, 1, "q"], [65362, 1, "r"], [65363, 1, "s"], [65364, 1, "t"], [65365, 1, "u"], [65366, 1, "v"], [65367, 1, "w"], [65368, 1, "x"], [65369, 1, "y"], [65370, 1, "z"], [65371, 1, "{"], [65372, 1, "|"], [65373, 1, "}"], [65374, 1, "~"], [65375, 1, "\u2985"], [65376, 1, "\u2986"], [65377, 1, "."], [65378, 1, "\u300C"], [65379, 1, "\u300D"], [65380, 1, "\u3001"], [65381, 1, "\u30FB"], [65382, 1, "\u30F2"], [65383, 1, "\u30A1"], [65384, 1, "\u30A3"], [65385, 1, "\u30A5"], [65386, 1, "\u30A7"], [65387, 1, "\u30A9"], [65388, 1, "\u30E3"], [65389, 1, "\u30E5"], [65390, 1, "\u30E7"], [65391, 1, "\u30C3"], [65392, 1, "\u30FC"], [65393, 1, "\u30A2"], [65394, 1, "\u30A4"], [65395, 1, "\u30A6"], [65396, 1, "\u30A8"], [65397, 1, "\u30AA"], [65398, 1, "\u30AB"], [65399, 1, "\u30AD"], [65400, 1, "\u30AF"], [65401, 1, "\u30B1"], [65402, 1, "\u30B3"], [65403, 1, "\u30B5"], [65404, 1, "\u30B7"], [65405, 1, "\u30B9"], [65406, 1, "\u30BB"], [65407, 1, "\u30BD"], [65408, 1, "\u30BF"], [65409, 1, "\u30C1"], [65410, 1, "\u30C4"], [65411, 1, "\u30C6"], [65412, 1, "\u30C8"], [65413, 1, "\u30CA"], [65414, 1, "\u30CB"], [65415, 1, "\u30CC"], [65416, 1, "\u30CD"], [65417, 1, "\u30CE"], [65418, 1, "\u30CF"], [65419, 1, "\u30D2"], [65420, 1, "\u30D5"], [65421, 1, "\u30D8"], [65422, 1, "\u30DB"], [65423, 1, "\u30DE"], [65424, 1, "\u30DF"], [65425, 1, "\u30E0"], [65426, 1, "\u30E1"], [65427, 1, "\u30E2"], [65428, 1, "\u30E4"], [65429, 1, "\u30E6"], [65430, 1, "\u30E8"], [65431, 1, "\u30E9"], [65432, 1, "\u30EA"], [65433, 1, "\u30EB"], [65434, 1, "\u30EC"], [65435, 1, "\u30ED"], [65436, 1, "\u30EF"], [65437, 1, "\u30F3"], [65438, 1, "\u3099"], [65439, 1, "\u309A"], [65440, 7], [65441, 1, "\u1100"], [65442, 1, "\u1101"], [65443, 1, "\u11AA"], [65444, 1, "\u1102"], [65445, 1, "\u11AC"], [65446, 1, "\u11AD"], [65447, 1, "\u1103"], [65448, 1, "\u1104"], [65449, 1, "\u1105"], [65450, 1, "\u11B0"], [65451, 1, "\u11B1"], [65452, 1, "\u11B2"], [65453, 1, "\u11B3"], [65454, 1, "\u11B4"], [65455, 1, "\u11B5"], [65456, 1, "\u111A"], [65457, 1, "\u1106"], [65458, 1, "\u1107"], [65459, 1, "\u1108"], [65460, 1, "\u1121"], [65461, 1, "\u1109"], [65462, 1, "\u110A"], [65463, 1, "\u110B"], [65464, 1, "\u110C"], [65465, 1, "\u110D"], [65466, 1, "\u110E"], [65467, 1, "\u110F"], [65468, 1, "\u1110"], [65469, 1, "\u1111"], [65470, 1, "\u1112"], [[65471, 65473], 3], [65474, 1, "\u1161"], [65475, 1, "\u1162"], [65476, 1, "\u1163"], [65477, 1, "\u1164"], [65478, 1, "\u1165"], [65479, 1, "\u1166"], [[65480, 65481], 3], [65482, 1, "\u1167"], [65483, 1, "\u1168"], [65484, 1, "\u1169"], [65485, 1, "\u116A"], [65486, 1, "\u116B"], [65487, 1, "\u116C"], [[65488, 65489], 3], [65490, 1, "\u116D"], [65491, 1, "\u116E"], [65492, 1, "\u116F"], [65493, 1, "\u1170"], [65494, 1, "\u1171"], [65495, 1, "\u1172"], [[65496, 65497], 3], [65498, 1, "\u1173"], [65499, 1, "\u1174"], [65500, 1, "\u1175"], [[65501, 65503], 3], [65504, 1, "\xA2"], [65505, 1, "\xA3"], [65506, 1, "\xAC"], [65507, 1, " \u0304"], [65508, 1, "\xA6"], [65509, 1, "\xA5"], [65510, 1, "\u20A9"], [65511, 3], [65512, 1, "\u2502"], [65513, 1, "\u2190"], [65514, 1, "\u2191"], [65515, 1, "\u2192"], [65516, 1, "\u2193"], [65517, 1, "\u25A0"], [65518, 1, "\u25CB"], [[65519, 65528], 3], [[65529, 65531], 3], [65532, 3], [65533, 3], [[65534, 65535], 3], [[65536, 65547], 2], [65548, 3], [[65549, 65574], 2], [65575, 3], [[65576, 65594], 2], [65595, 3], [[65596, 65597], 2], [65598, 3], [[65599, 65613], 2], [[65614, 65615], 3], [[65616, 65629], 2], [[65630, 65663], 3], [[65664, 65786], 2], [[65787, 65791], 3], [[65792, 65794], 2], [[65795, 65798], 3], [[65799, 65843], 2], [[65844, 65846], 3], [[65847, 65855], 2], [[65856, 65930], 2], [[65931, 65932], 2], [[65933, 65934], 2], [65935, 3], [[65936, 65947], 2], [65948, 2], [[65949, 65951], 3], [65952, 2], [[65953, 65999], 3], [[66e3, 66044], 2], [66045, 2], [[66046, 66175], 3], [[66176, 66204], 2], [[66205, 66207], 3], [[66208, 66256], 2], [[66257, 66271], 3], [66272, 2], [[66273, 66299], 2], [[66300, 66303], 3], [[66304, 66334], 2], [66335, 2], [[66336, 66339], 2], [[66340, 66348], 3], [[66349, 66351], 2], [[66352, 66368], 2], [66369, 2], [[66370, 66377], 2], [66378, 2], [[66379, 66383], 3], [[66384, 66426], 2], [[66427, 66431], 3], [[66432, 66461], 2], [66462, 3], [66463, 2], [[66464, 66499], 2], [[66500, 66503], 3], [[66504, 66511], 2], [[66512, 66517], 2], [[66518, 66559], 3], [66560, 1, "\u{10428}"], [66561, 1, "\u{10429}"], [66562, 1, "\u{1042A}"], [66563, 1, "\u{1042B}"], [66564, 1, "\u{1042C}"], [66565, 1, "\u{1042D}"], [66566, 1, "\u{1042E}"], [66567, 1, "\u{1042F}"], [66568, 1, "\u{10430}"], [66569, 1, "\u{10431}"], [66570, 1, "\u{10432}"], [66571, 1, "\u{10433}"], [66572, 1, "\u{10434}"], [66573, 1, "\u{10435}"], [66574, 1, "\u{10436}"], [66575, 1, "\u{10437}"], [66576, 1, "\u{10438}"], [66577, 1, "\u{10439}"], [66578, 1, "\u{1043A}"], [66579, 1, "\u{1043B}"], [66580, 1, "\u{1043C}"], [66581, 1, "\u{1043D}"], [66582, 1, "\u{1043E}"], [66583, 1, "\u{1043F}"], [66584, 1, "\u{10440}"], [66585, 1, "\u{10441}"], [66586, 1, "\u{10442}"], [66587, 1, "\u{10443}"], [66588, 1, "\u{10444}"], [66589, 1, "\u{10445}"], [66590, 1, "\u{10446}"], [66591, 1, "\u{10447}"], [66592, 1, "\u{10448}"], [66593, 1, "\u{10449}"], [66594, 1, "\u{1044A}"], [66595, 1, "\u{1044B}"], [66596, 1, "\u{1044C}"], [66597, 1, "\u{1044D}"], [66598, 1, "\u{1044E}"], [66599, 1, "\u{1044F}"], [[66600, 66637], 2], [[66638, 66717], 2], [[66718, 66719], 3], [[66720, 66729], 2], [[66730, 66735], 3], [66736, 1, "\u{104D8}"], [66737, 1, "\u{104D9}"], [66738, 1, "\u{104DA}"], [66739, 1, "\u{104DB}"], [66740, 1, "\u{104DC}"], [66741, 1, "\u{104DD}"], [66742, 1, "\u{104DE}"], [66743, 1, "\u{104DF}"], [66744, 1, "\u{104E0}"], [66745, 1, "\u{104E1}"], [66746, 1, "\u{104E2}"], [66747, 1, "\u{104E3}"], [66748, 1, "\u{104E4}"], [66749, 1, "\u{104E5}"], [66750, 1, "\u{104E6}"], [66751, 1, "\u{104E7}"], [66752, 1, "\u{104E8}"], [66753, 1, "\u{104E9}"], [66754, 1, "\u{104EA}"], [66755, 1, "\u{104EB}"], [66756, 1, "\u{104EC}"], [66757, 1, "\u{104ED}"], [66758, 1, "\u{104EE}"], [66759, 1, "\u{104EF}"], [66760, 1, "\u{104F0}"], [66761, 1, "\u{104F1}"], [66762, 1, "\u{104F2}"], [66763, 1, "\u{104F3}"], [66764, 1, "\u{104F4}"], [66765, 1, "\u{104F5}"], [66766, 1, "\u{104F6}"], [66767, 1, "\u{104F7}"], [66768, 1, "\u{104F8}"], [66769, 1, "\u{104F9}"], [66770, 1, "\u{104FA}"], [66771, 1, "\u{104FB}"], [[66772, 66775], 3], [[66776, 66811], 2], [[66812, 66815], 3], [[66816, 66855], 2], [[66856, 66863], 3], [[66864, 66915], 2], [[66916, 66926], 3], [66927, 2], [66928, 1, "\u{10597}"], [66929, 1, "\u{10598}"], [66930, 1, "\u{10599}"], [66931, 1, "\u{1059A}"], [66932, 1, "\u{1059B}"], [66933, 1, "\u{1059C}"], [66934, 1, "\u{1059D}"], [66935, 1, "\u{1059E}"], [66936, 1, "\u{1059F}"], [66937, 1, "\u{105A0}"], [66938, 1, "\u{105A1}"], [66939, 3], [66940, 1, "\u{105A3}"], [66941, 1, "\u{105A4}"], [66942, 1, "\u{105A5}"], [66943, 1, "\u{105A6}"], [66944, 1, "\u{105A7}"], [66945, 1, "\u{105A8}"], [66946, 1, "\u{105A9}"], [66947, 1, "\u{105AA}"], [66948, 1, "\u{105AB}"], [66949, 1, "\u{105AC}"], [66950, 1, "\u{105AD}"], [66951, 1, "\u{105AE}"], [66952, 1, "\u{105AF}"], [66953, 1, "\u{105B0}"], [66954, 1, "\u{105B1}"], [66955, 3], [66956, 1, "\u{105B3}"], [66957, 1, "\u{105B4}"], [66958, 1, "\u{105B5}"], [66959, 1, "\u{105B6}"], [66960, 1, "\u{105B7}"], [66961, 1, "\u{105B8}"], [66962, 1, "\u{105B9}"], [66963, 3], [66964, 1, "\u{105BB}"], [66965, 1, "\u{105BC}"], [66966, 3], [[66967, 66977], 2], [66978, 3], [[66979, 66993], 2], [66994, 3], [[66995, 67001], 2], [67002, 3], [[67003, 67004], 2], [[67005, 67007], 3], [[67008, 67059], 2], [[67060, 67071], 3], [[67072, 67382], 2], [[67383, 67391], 3], [[67392, 67413], 2], [[67414, 67423], 3], [[67424, 67431], 2], [[67432, 67455], 3], [67456, 2], [67457, 1, "\u02D0"], [67458, 1, "\u02D1"], [67459, 1, "\xE6"], [67460, 1, "\u0299"], [67461, 1, "\u0253"], [67462, 3], [67463, 1, "\u02A3"], [67464, 1, "\uAB66"], [67465, 1, "\u02A5"], [67466, 1, "\u02A4"], [67467, 1, "\u0256"], [67468, 1, "\u0257"], [67469, 1, "\u1D91"], [67470, 1, "\u0258"], [67471, 1, "\u025E"], [67472, 1, "\u02A9"], [67473, 1, "\u0264"], [67474, 1, "\u0262"], [67475, 1, "\u0260"], [67476, 1, "\u029B"], [67477, 1, "\u0127"], [67478, 1, "\u029C"], [67479, 1, "\u0267"], [67480, 1, "\u0284"], [67481, 1, "\u02AA"], [67482, 1, "\u02AB"], [67483, 1, "\u026C"], [67484, 1, "\u{1DF04}"], [67485, 1, "\uA78E"], [67486, 1, "\u026E"], [67487, 1, "\u{1DF05}"], [67488, 1, "\u028E"], [67489, 1, "\u{1DF06}"], [67490, 1, "\xF8"], [67491, 1, "\u0276"], [67492, 1, "\u0277"], [67493, 1, "q"], [67494, 1, "\u027A"], [67495, 1, "\u{1DF08}"], [67496, 1, "\u027D"], [67497, 1, "\u027E"], [67498, 1, "\u0280"], [67499, 1, "\u02A8"], [67500, 1, "\u02A6"], [67501, 1, "\uAB67"], [67502, 1, "\u02A7"], [67503, 1, "\u0288"], [67504, 1, "\u2C71"], [67505, 3], [67506, 1, "\u028F"], [67507, 1, "\u02A1"], [67508, 1, "\u02A2"], [67509, 1, "\u0298"], [67510, 1, "\u01C0"], [67511, 1, "\u01C1"], [67512, 1, "\u01C2"], [67513, 1, "\u{1DF0A}"], [67514, 1, "\u{1DF1E}"], [67515, 1, "\u0287"], [67516, 1, "\u0296"], [67517, 1, "\u0297"], [67518, 1, "\u029E"], [67519, 1, "\u{1DF0B}"], [[67520, 67583], 3], [[67584, 67589], 2], [[67590, 67591], 3], [67592, 2], [67593, 3], [[67594, 67637], 2], [67638, 3], [[67639, 67640], 2], [[67641, 67643], 3], [67644, 2], [[67645, 67646], 3], [67647, 2], [[67648, 67669], 2], [67670, 3], [[67671, 67679], 2], [[67680, 67702], 2], [[67703, 67711], 2], [[67712, 67742], 2], [[67743, 67750], 3], [[67751, 67759], 2], [[67760, 67807], 3], [[67808, 67826], 2], [67827, 3], [[67828, 67829], 2], [[67830, 67834], 3], [[67835, 67839], 2], [[67840, 67861], 2], [[67862, 67865], 2], [[67866, 67867], 2], [[67868, 67870], 3], [67871, 2], [[67872, 67897], 2], [[67898, 67902], 3], [67903, 2], [[67904, 67929], 2], [[67930, 67967], 3], [[67968, 68023], 2], [[68024, 68027], 3], [[68028, 68029], 2], [[68030, 68031], 2], [[68032, 68047], 2], [[68048, 68049], 3], [[68050, 68095], 2], [[68096, 68099], 2], [68100, 3], [[68101, 68102], 2], [[68103, 68107], 3], [[68108, 68115], 2], [68116, 3], [[68117, 68119], 2], [68120, 3], [[68121, 68147], 2], [[68148, 68149], 2], [[68150, 68151], 3], [[68152, 68154], 2], [[68155, 68158], 3], [68159, 2], [[68160, 68167], 2], [68168, 2], [[68169, 68175], 3], [[68176, 68184], 2], [[68185, 68191], 3], [[68192, 68220], 2], [[68221, 68223], 2], [[68224, 68252], 2], [[68253, 68255], 2], [[68256, 68287], 3], [[68288, 68295], 2], [68296, 2], [[68297, 68326], 2], [[68327, 68330], 3], [[68331, 68342], 2], [[68343, 68351], 3], [[68352, 68405], 2], [[68406, 68408], 3], [[68409, 68415], 2], [[68416, 68437], 2], [[68438, 68439], 3], [[68440, 68447], 2], [[68448, 68466], 2], [[68467, 68471], 3], [[68472, 68479], 2], [[68480, 68497], 2], [[68498, 68504], 3], [[68505, 68508], 2], [[68509, 68520], 3], [[68521, 68527], 2], [[68528, 68607], 3], [[68608, 68680], 2], [[68681, 68735], 3], [68736, 1, "\u{10CC0}"], [68737, 1, "\u{10CC1}"], [68738, 1, "\u{10CC2}"], [68739, 1, "\u{10CC3}"], [68740, 1, "\u{10CC4}"], [68741, 1, "\u{10CC5}"], [68742, 1, "\u{10CC6}"], [68743, 1, "\u{10CC7}"], [68744, 1, "\u{10CC8}"], [68745, 1, "\u{10CC9}"], [68746, 1, "\u{10CCA}"], [68747, 1, "\u{10CCB}"], [68748, 1, "\u{10CCC}"], [68749, 1, "\u{10CCD}"], [68750, 1, "\u{10CCE}"], [68751, 1, "\u{10CCF}"], [68752, 1, "\u{10CD0}"], [68753, 1, "\u{10CD1}"], [68754, 1, "\u{10CD2}"], [68755, 1, "\u{10CD3}"], [68756, 1, "\u{10CD4}"], [68757, 1, "\u{10CD5}"], [68758, 1, "\u{10CD6}"], [68759, 1, "\u{10CD7}"], [68760, 1, "\u{10CD8}"], [68761, 1, "\u{10CD9}"], [68762, 1, "\u{10CDA}"], [68763, 1, "\u{10CDB}"], [68764, 1, "\u{10CDC}"], [68765, 1, "\u{10CDD}"], [68766, 1, "\u{10CDE}"], [68767, 1, "\u{10CDF}"], [68768, 1, "\u{10CE0}"], [68769, 1, "\u{10CE1}"], [68770, 1, "\u{10CE2}"], [68771, 1, "\u{10CE3}"], [68772, 1, "\u{10CE4}"], [68773, 1, "\u{10CE5}"], [68774, 1, "\u{10CE6}"], [68775, 1, "\u{10CE7}"], [68776, 1, "\u{10CE8}"], [68777, 1, "\u{10CE9}"], [68778, 1, "\u{10CEA}"], [68779, 1, "\u{10CEB}"], [68780, 1, "\u{10CEC}"], [68781, 1, "\u{10CED}"], [68782, 1, "\u{10CEE}"], [68783, 1, "\u{10CEF}"], [68784, 1, "\u{10CF0}"], [68785, 1, "\u{10CF1}"], [68786, 1, "\u{10CF2}"], [[68787, 68799], 3], [[68800, 68850], 2], [[68851, 68857], 3], [[68858, 68863], 2], [[68864, 68903], 2], [[68904, 68911], 3], [[68912, 68921], 2], [[68922, 68927], 3], [[68928, 68943], 2], [68944, 1, "\u{10D70}"], [68945, 1, "\u{10D71}"], [68946, 1, "\u{10D72}"], [68947, 1, "\u{10D73}"], [68948, 1, "\u{10D74}"], [68949, 1, "\u{10D75}"], [68950, 1, "\u{10D76}"], [68951, 1, "\u{10D77}"], [68952, 1, "\u{10D78}"], [68953, 1, "\u{10D79}"], [68954, 1, "\u{10D7A}"], [68955, 1, "\u{10D7B}"], [68956, 1, "\u{10D7C}"], [68957, 1, "\u{10D7D}"], [68958, 1, "\u{10D7E}"], [68959, 1, "\u{10D7F}"], [68960, 1, "\u{10D80}"], [68961, 1, "\u{10D81}"], [68962, 1, "\u{10D82}"], [68963, 1, "\u{10D83}"], [68964, 1, "\u{10D84}"], [68965, 1, "\u{10D85}"], [[68966, 68968], 3], [[68969, 68973], 2], [68974, 2], [[68975, 68997], 2], [[68998, 69005], 3], [[69006, 69007], 2], [[69008, 69215], 3], [[69216, 69246], 2], [69247, 3], [[69248, 69289], 2], [69290, 3], [[69291, 69292], 2], [69293, 2], [[69294, 69295], 3], [[69296, 69297], 2], [[69298, 69313], 3], [[69314, 69316], 2], [[69317, 69319], 2], [69320, 3], [[69321, 69322], 2], [[69323, 69327], 2], [[69328, 69336], 2], [[69337, 69358], 2], [69359, 3], [[69360, 69369], 2], [[69370, 69371], 2], [69372, 2], [[69373, 69375], 2], [[69376, 69404], 2], [[69405, 69414], 2], [69415, 2], [[69416, 69423], 3], [[69424, 69456], 2], [[69457, 69465], 2], [[69466, 69487], 3], [[69488, 69509], 2], [[69510, 69513], 2], [[69514, 69551], 3], [[69552, 69572], 2], [[69573, 69579], 2], [[69580, 69599], 3], [[69600, 69622], 2], [[69623, 69631], 3], [[69632, 69702], 2], [[69703, 69709], 2], [[69710, 69713], 3], [[69714, 69733], 2], [[69734, 69743], 2], [[69744, 69749], 2], [[69750, 69758], 3], [69759, 2], [[69760, 69818], 2], [[69819, 69820], 2], [69821, 3], [[69822, 69825], 2], [69826, 2], [[69827, 69836], 3], [69837, 3], [[69838, 69839], 3], [[69840, 69864], 2], [[69865, 69871], 3], [[69872, 69881], 2], [[69882, 69887], 3], [[69888, 69940], 2], [69941, 3], [[69942, 69951], 2], [[69952, 69955], 2], [[69956, 69958], 2], [69959, 2], [[69960, 69967], 3], [[69968, 70003], 2], [[70004, 70005], 2], [70006, 2], [[70007, 70015], 3], [[70016, 70084], 2], [[70085, 70088], 2], [[70089, 70092], 2], [70093, 2], [[70094, 70095], 2], [[70096, 70105], 2], [70106, 2], [70107, 2], [70108, 2], [[70109, 70111], 2], [70112, 3], [[70113, 70132], 2], [[70133, 70143], 3], [[70144, 70161], 2], [70162, 3], [[70163, 70199], 2], [[70200, 70205], 2], [70206, 2], [[70207, 70209], 2], [[70210, 70271], 3], [[70272, 70278], 2], [70279, 3], [70280, 2], [70281, 3], [[70282, 70285], 2], [70286, 3], [[70287, 70301], 2], [70302, 3], [[70303, 70312], 2], [70313, 2], [[70314, 70319], 3], [[70320, 70378], 2], [[70379, 70383], 3], [[70384, 70393], 2], [[70394, 70399], 3], [70400, 2], [[70401, 70403], 2], [70404, 3], [[70405, 70412], 2], [[70413, 70414], 3], [[70415, 70416], 2], [[70417, 70418], 3], [[70419, 70440], 2], [70441, 3], [[70442, 70448], 2], [70449, 3], [[70450, 70451], 2], [70452, 3], [[70453, 70457], 2], [70458, 3], [70459, 2], [[70460, 70468], 2], [[70469, 70470], 3], [[70471, 70472], 2], [[70473, 70474], 3], [[70475, 70477], 2], [[70478, 70479], 3], [70480, 2], [[70481, 70486], 3], [70487, 2], [[70488, 70492], 3], [[70493, 70499], 2], [[70500, 70501], 3], [[70502, 70508], 2], [[70509, 70511], 3], [[70512, 70516], 2], [[70517, 70527], 3], [[70528, 70537], 2], [70538, 3], [70539, 2], [[70540, 70541], 3], [70542, 2], [70543, 3], [[70544, 70581], 2], [70582, 3], [[70583, 70592], 2], [70593, 3], [70594, 2], [[70595, 70596], 3], [70597, 2], [70598, 3], [[70599, 70602], 2], [70603, 3], [[70604, 70611], 2], [[70612, 70613], 2], [70614, 3], [[70615, 70616], 2], [[70617, 70624], 3], [[70625, 70626], 2], [[70627, 70655], 3], [[70656, 70730], 2], [[70731, 70735], 2], [[70736, 70745], 2], [70746, 2], [70747, 2], [70748, 3], [70749, 2], [70750, 2], [70751, 2], [[70752, 70753], 2], [[70754, 70783], 3], [[70784, 70853], 2], [70854, 2], [70855, 2], [[70856, 70863], 3], [[70864, 70873], 2], [[70874, 71039], 3], [[71040, 71093], 2], [[71094, 71095], 3], [[71096, 71104], 2], [[71105, 71113], 2], [[71114, 71127], 2], [[71128, 71133], 2], [[71134, 71167], 3], [[71168, 71232], 2], [[71233, 71235], 2], [71236, 2], [[71237, 71247], 3], [[71248, 71257], 2], [[71258, 71263], 3], [[71264, 71276], 2], [[71277, 71295], 3], [[71296, 71351], 2], [71352, 2], [71353, 2], [[71354, 71359], 3], [[71360, 71369], 2], [[71370, 71375], 3], [[71376, 71395], 2], [[71396, 71423], 3], [[71424, 71449], 2], [71450, 2], [[71451, 71452], 3], [[71453, 71467], 2], [[71468, 71471], 3], [[71472, 71481], 2], [[71482, 71487], 2], [[71488, 71494], 2], [[71495, 71679], 3], [[71680, 71738], 2], [71739, 2], [[71740, 71839], 3], [71840, 1, "\u{118C0}"], [71841, 1, "\u{118C1}"], [71842, 1, "\u{118C2}"], [71843, 1, "\u{118C3}"], [71844, 1, "\u{118C4}"], [71845, 1, "\u{118C5}"], [71846, 1, "\u{118C6}"], [71847, 1, "\u{118C7}"], [71848, 1, "\u{118C8}"], [71849, 1, "\u{118C9}"], [71850, 1, "\u{118CA}"], [71851, 1, "\u{118CB}"], [71852, 1, "\u{118CC}"], [71853, 1, "\u{118CD}"], [71854, 1, "\u{118CE}"], [71855, 1, "\u{118CF}"], [71856, 1, "\u{118D0}"], [71857, 1, "\u{118D1}"], [71858, 1, "\u{118D2}"], [71859, 1, "\u{118D3}"], [71860, 1, "\u{118D4}"], [71861, 1, "\u{118D5}"], [71862, 1, "\u{118D6}"], [71863, 1, "\u{118D7}"], [71864, 1, "\u{118D8}"], [71865, 1, "\u{118D9}"], [71866, 1, "\u{118DA}"], [71867, 1, "\u{118DB}"], [71868, 1, "\u{118DC}"], [71869, 1, "\u{118DD}"], [71870, 1, "\u{118DE}"], [71871, 1, "\u{118DF}"], [[71872, 71913], 2], [[71914, 71922], 2], [[71923, 71934], 3], [71935, 2], [[71936, 71942], 2], [[71943, 71944], 3], [71945, 2], [[71946, 71947], 3], [[71948, 71955], 2], [71956, 3], [[71957, 71958], 2], [71959, 3], [[71960, 71989], 2], [71990, 3], [[71991, 71992], 2], [[71993, 71994], 3], [[71995, 72003], 2], [[72004, 72006], 2], [[72007, 72015], 3], [[72016, 72025], 2], [[72026, 72095], 3], [[72096, 72103], 2], [[72104, 72105], 3], [[72106, 72151], 2], [[72152, 72153], 3], [[72154, 72161], 2], [72162, 2], [[72163, 72164], 2], [[72165, 72191], 3], [[72192, 72254], 2], [[72255, 72262], 2], [72263, 2], [[72264, 72271], 3], [[72272, 72323], 2], [[72324, 72325], 2], [[72326, 72345], 2], [[72346, 72348], 2], [72349, 2], [[72350, 72354], 2], [[72355, 72367], 3], [[72368, 72383], 2], [[72384, 72440], 2], [[72441, 72447], 3], [[72448, 72457], 2], [72458, 2], [[72459, 72543], 3], [[72544, 72551], 2], [[72552, 72639], 3], [[72640, 72672], 2], [72673, 2], [[72674, 72687], 3], [[72688, 72697], 2], [[72698, 72703], 3], [[72704, 72712], 2], [72713, 3], [[72714, 72758], 2], [72759, 3], [[72760, 72768], 2], [[72769, 72773], 2], [[72774, 72783], 3], [[72784, 72793], 2], [[72794, 72812], 2], [[72813, 72815], 3], [[72816, 72817], 2], [[72818, 72847], 2], [[72848, 72849], 3], [[72850, 72871], 2], [72872, 3], [[72873, 72886], 2], [[72887, 72959], 3], [[72960, 72966], 2], [72967, 3], [[72968, 72969], 2], [72970, 3], [[72971, 73014], 2], [[73015, 73017], 3], [73018, 2], [73019, 3], [[73020, 73021], 2], [73022, 3], [[73023, 73031], 2], [[73032, 73039], 3], [[73040, 73049], 2], [[73050, 73055], 3], [[73056, 73061], 2], [73062, 3], [[73063, 73064], 2], [73065, 3], [[73066, 73102], 2], [73103, 3], [[73104, 73105], 2], [73106, 3], [[73107, 73112], 2], [[73113, 73119], 3], [[73120, 73129], 2], [[73130, 73135], 3], [[73136, 73179], 2], [[73180, 73183], 3], [[73184, 73193], 2], [[73194, 73199], 3], [[73200, 73201], 2], [[73202, 73439], 3], [[73440, 73462], 2], [[73463, 73464], 2], [[73465, 73471], 3], [[73472, 73488], 2], [73489, 3], [[73490, 73530], 2], [[73531, 73533], 3], [[73534, 73538], 2], [[73539, 73551], 2], [[73552, 73561], 2], [73562, 2], [[73563, 73647], 3], [73648, 2], [[73649, 73663], 3], [[73664, 73713], 2], [[73714, 73726], 3], [73727, 2], [[73728, 74606], 2], [[74607, 74648], 2], [74649, 2], [[74650, 74751], 3], [[74752, 74850], 2], [[74851, 74862], 2], [74863, 2], [[74864, 74867], 2], [74868, 2], [[74869, 74879], 2], [[74880, 75075], 2], [[75076, 75087], 3], [[75088, 75398], 2], [[75399, 77711], 3], [[77712, 77808], 2], [[77809, 77810], 2], [[77811, 77823], 3], [[77824, 78894], 2], [78895, 2], [[78896, 78904], 3], [[78905, 78911], 3], [[78912, 78933], 2], [[78934, 78943], 3], [[78944, 82938], 2], [[82939, 82943], 3], [[82944, 83526], 2], [[83527, 90367], 3], [[90368, 90425], 2], [[90426, 92159], 3], [[92160, 92728], 2], [[92729, 92735], 3], [[92736, 92766], 2], [92767, 3], [[92768, 92777], 2], [[92778, 92781], 3], [[92782, 92783], 2], [[92784, 92862], 2], [92863, 3], [[92864, 92873], 2], [[92874, 92879], 3], [[92880, 92909], 2], [[92910, 92911], 3], [[92912, 92916], 2], [92917, 2], [[92918, 92927], 3], [[92928, 92982], 2], [[92983, 92991], 2], [[92992, 92995], 2], [[92996, 92997], 2], [[92998, 93007], 3], [[93008, 93017], 2], [93018, 3], [[93019, 93025], 2], [93026, 3], [[93027, 93047], 2], [[93048, 93052], 3], [[93053, 93071], 2], [[93072, 93503], 3], [[93504, 93548], 2], [[93549, 93551], 2], [[93552, 93561], 2], [[93562, 93759], 3], [93760, 1, "\u{16E60}"], [93761, 1, "\u{16E61}"], [93762, 1, "\u{16E62}"], [93763, 1, "\u{16E63}"], [93764, 1, "\u{16E64}"], [93765, 1, "\u{16E65}"], [93766, 1, "\u{16E66}"], [93767, 1, "\u{16E67}"], [93768, 1, "\u{16E68}"], [93769, 1, "\u{16E69}"], [93770, 1, "\u{16E6A}"], [93771, 1, "\u{16E6B}"], [93772, 1, "\u{16E6C}"], [93773, 1, "\u{16E6D}"], [93774, 1, "\u{16E6E}"], [93775, 1, "\u{16E6F}"], [93776, 1, "\u{16E70}"], [93777, 1, "\u{16E71}"], [93778, 1, "\u{16E72}"], [93779, 1, "\u{16E73}"], [93780, 1, "\u{16E74}"], [93781, 1, "\u{16E75}"], [93782, 1, "\u{16E76}"], [93783, 1, "\u{16E77}"], [93784, 1, "\u{16E78}"], [93785, 1, "\u{16E79}"], [93786, 1, "\u{16E7A}"], [93787, 1, "\u{16E7B}"], [93788, 1, "\u{16E7C}"], [93789, 1, "\u{16E7D}"], [93790, 1, "\u{16E7E}"], [93791, 1, "\u{16E7F}"], [[93792, 93823], 2], [[93824, 93850], 2], [[93851, 93855], 3], [93856, 1, "\u{16EBB}"], [93857, 1, "\u{16EBC}"], [93858, 1, "\u{16EBD}"], [93859, 1, "\u{16EBE}"], [93860, 1, "\u{16EBF}"], [93861, 1, "\u{16EC0}"], [93862, 1, "\u{16EC1}"], [93863, 1, "\u{16EC2}"], [93864, 1, "\u{16EC3}"], [93865, 1, "\u{16EC4}"], [93866, 1, "\u{16EC5}"], [93867, 1, "\u{16EC6}"], [93868, 1, "\u{16EC7}"], [93869, 1, "\u{16EC8}"], [93870, 1, "\u{16EC9}"], [93871, 1, "\u{16ECA}"], [93872, 1, "\u{16ECB}"], [93873, 1, "\u{16ECC}"], [93874, 1, "\u{16ECD}"], [93875, 1, "\u{16ECE}"], [93876, 1, "\u{16ECF}"], [93877, 1, "\u{16ED0}"], [93878, 1, "\u{16ED1}"], [93879, 1, "\u{16ED2}"], [93880, 1, "\u{16ED3}"], [[93881, 93882], 3], [[93883, 93907], 2], [[93908, 93951], 3], [[93952, 94020], 2], [[94021, 94026], 2], [[94027, 94030], 3], [94031, 2], [[94032, 94078], 2], [[94079, 94087], 2], [[94088, 94094], 3], [[94095, 94111], 2], [[94112, 94175], 3], [94176, 2], [94177, 2], [94178, 2], [94179, 2], [94180, 2], [[94181, 94191], 3], [[94192, 94193], 2], [[94194, 94195], 2], [[94196, 94198], 2], [[94199, 94207], 3], [[94208, 100332], 2], [[100333, 100337], 2], [[100338, 100343], 2], [[100344, 100351], 2], [[100352, 101106], 2], [[101107, 101589], 2], [[101590, 101594], 2], [[101595, 101630], 3], [101631, 2], [[101632, 101640], 2], [[101641, 101662], 2], [[101663, 101664], 2], [[101665, 101759], 3], [[101760, 101874], 2], [[101875, 101887], 3], [[101888, 102801], 2], [[102802, 102815], 3], [[102816, 102866], 2], [[102867, 110575], 3], [[110576, 110579], 2], [110580, 3], [[110581, 110587], 2], [110588, 3], [[110589, 110590], 2], [110591, 3], [[110592, 110593], 2], [[110594, 110878], 2], [[110879, 110882], 2], [110883, 1, "\u3053\u3068"], [110884, 1, "\u30C8\u30AD"], [110885, 1, "\u30C8\u30C6"], [110886, 1, "\u30E8\u30EA"], [[110887, 110888], 2], [[110889, 110897], 3], [110898, 2], [[110899, 110927], 3], [[110928, 110930], 2], [[110931, 110932], 3], [110933, 2], [[110934, 110947], 3], [[110948, 110951], 2], [110952, 2], [[110953, 110959], 3], [[110960, 111355], 2], [[111356, 113663], 3], [[113664, 113770], 2], [[113771, 113775], 3], [[113776, 113788], 2], [[113789, 113791], 3], [[113792, 113800], 2], [[113801, 113807], 3], [[113808, 113817], 2], [[113818, 113819], 3], [113820, 2], [[113821, 113822], 2], [113823, 2], [[113824, 113827], 7], [[113828, 117759], 3], [[117760, 117973], 2], [117974, 1, "a"], [117975, 1, "b"], [117976, 1, "c"], [117977, 1, "d"], [117978, 1, "e"], [117979, 1, "f"], [117980, 1, "g"], [117981, 1, "h"], [117982, 1, "i"], [117983, 1, "j"], [117984, 1, "k"], [117985, 1, "l"], [117986, 1, "m"], [117987, 1, "n"], [117988, 1, "o"], [117989, 1, "p"], [117990, 1, "q"], [117991, 1, "r"], [117992, 1, "s"], [117993, 1, "t"], [117994, 1, "u"], [117995, 1, "v"], [117996, 1, "w"], [117997, 1, "x"], [117998, 1, "y"], [117999, 1, "z"], [118e3, 1, "0"], [118001, 1, "1"], [118002, 1, "2"], [118003, 1, "3"], [118004, 1, "4"], [118005, 1, "5"], [118006, 1, "6"], [118007, 1, "7"], [118008, 1, "8"], [118009, 1, "9"], [[118010, 118012], 2], [[118013, 118015], 3], [[118016, 118451], 2], [[118452, 118457], 3], [[118458, 118480], 2], [118481, 3], [[118482, 118484], 2], [[118485, 118492], 3], [[118493, 118495], 2], [[118496, 118512], 2], [[118513, 118525], 2], [[118526, 118527], 3], [[118528, 118573], 2], [[118574, 118575], 3], [[118576, 118598], 2], [[118599, 118607], 3], [[118608, 118723], 2], [[118724, 118783], 3], [[118784, 119029], 2], [[119030, 119039], 3], [[119040, 119078], 2], [[119079, 119080], 2], [119081, 2], [[119082, 119133], 2], [119134, 1, "\u{1D157}\u{1D165}"], [119135, 1, "\u{1D158}\u{1D165}"], [119136, 1, "\u{1D158}\u{1D165}\u{1D16E}"], [119137, 1, "\u{1D158}\u{1D165}\u{1D16F}"], [119138, 1, "\u{1D158}\u{1D165}\u{1D170}"], [119139, 1, "\u{1D158}\u{1D165}\u{1D171}"], [119140, 1, "\u{1D158}\u{1D165}\u{1D172}"], [[119141, 119154], 2], [[119155, 119162], 7], [[119163, 119226], 2], [119227, 1, "\u{1D1B9}\u{1D165}"], [119228, 1, "\u{1D1BA}\u{1D165}"], [119229, 1, "\u{1D1B9}\u{1D165}\u{1D16E}"], [119230, 1, "\u{1D1BA}\u{1D165}\u{1D16E}"], [119231, 1, "\u{1D1B9}\u{1D165}\u{1D16F}"], [119232, 1, "\u{1D1BA}\u{1D165}\u{1D16F}"], [[119233, 119261], 2], [[119262, 119272], 2], [[119273, 119274], 2], [[119275, 119295], 2], [[119296, 119365], 2], [[119366, 119375], 3], [[119376, 119378], 2], [[119379, 119386], 2], [[119387, 119388], 2], [[119389, 119390], 2], [119391, 2], [[119392, 119423], 2], [[119424, 119425], 2], [[119426, 119487], 3], [[119488, 119507], 2], [[119508, 119519], 3], [[119520, 119539], 2], [[119540, 119551], 3], [[119552, 119638], 2], [[119639, 119647], 3], [[119648, 119665], 2], [[119666, 119672], 2], [[119673, 119807], 3], [119808, 1, "a"], [119809, 1, "b"], [119810, 1, "c"], [119811, 1, "d"], [119812, 1, "e"], [119813, 1, "f"], [119814, 1, "g"], [119815, 1, "h"], [119816, 1, "i"], [119817, 1, "j"], [119818, 1, "k"], [119819, 1, "l"], [119820, 1, "m"], [119821, 1, "n"], [119822, 1, "o"], [119823, 1, "p"], [119824, 1, "q"], [119825, 1, "r"], [119826, 1, "s"], [119827, 1, "t"], [119828, 1, "u"], [119829, 1, "v"], [119830, 1, "w"], [119831, 1, "x"], [119832, 1, "y"], [119833, 1, "z"], [119834, 1, "a"], [119835, 1, "b"], [119836, 1, "c"], [119837, 1, "d"], [119838, 1, "e"], [119839, 1, "f"], [119840, 1, "g"], [119841, 1, "h"], [119842, 1, "i"], [119843, 1, "j"], [119844, 1, "k"], [119845, 1, "l"], [119846, 1, "m"], [119847, 1, "n"], [119848, 1, "o"], [119849, 1, "p"], [119850, 1, "q"], [119851, 1, "r"], [119852, 1, "s"], [119853, 1, "t"], [119854, 1, "u"], [119855, 1, "v"], [119856, 1, "w"], [119857, 1, "x"], [119858, 1, "y"], [119859, 1, "z"], [119860, 1, "a"], [119861, 1, "b"], [119862, 1, "c"], [119863, 1, "d"], [119864, 1, "e"], [119865, 1, "f"], [119866, 1, "g"], [119867, 1, "h"], [119868, 1, "i"], [119869, 1, "j"], [119870, 1, "k"], [119871, 1, "l"], [119872, 1, "m"], [119873, 1, "n"], [119874, 1, "o"], [119875, 1, "p"], [119876, 1, "q"], [119877, 1, "r"], [119878, 1, "s"], [119879, 1, "t"], [119880, 1, "u"], [119881, 1, "v"], [119882, 1, "w"], [119883, 1, "x"], [119884, 1, "y"], [119885, 1, "z"], [119886, 1, "a"], [119887, 1, "b"], [119888, 1, "c"], [119889, 1, "d"], [119890, 1, "e"], [119891, 1, "f"], [119892, 1, "g"], [119893, 3], [119894, 1, "i"], [119895, 1, "j"], [119896, 1, "k"], [119897, 1, "l"], [119898, 1, "m"], [119899, 1, "n"], [119900, 1, "o"], [119901, 1, "p"], [119902, 1, "q"], [119903, 1, "r"], [119904, 1, "s"], [119905, 1, "t"], [119906, 1, "u"], [119907, 1, "v"], [119908, 1, "w"], [119909, 1, "x"], [119910, 1, "y"], [119911, 1, "z"], [119912, 1, "a"], [119913, 1, "b"], [119914, 1, "c"], [119915, 1, "d"], [119916, 1, "e"], [119917, 1, "f"], [119918, 1, "g"], [119919, 1, "h"], [119920, 1, "i"], [119921, 1, "j"], [119922, 1, "k"], [119923, 1, "l"], [119924, 1, "m"], [119925, 1, "n"], [119926, 1, "o"], [119927, 1, "p"], [119928, 1, "q"], [119929, 1, "r"], [119930, 1, "s"], [119931, 1, "t"], [119932, 1, "u"], [119933, 1, "v"], [119934, 1, "w"], [119935, 1, "x"], [119936, 1, "y"], [119937, 1, "z"], [119938, 1, "a"], [119939, 1, "b"], [119940, 1, "c"], [119941, 1, "d"], [119942, 1, "e"], [119943, 1, "f"], [119944, 1, "g"], [119945, 1, "h"], [119946, 1, "i"], [119947, 1, "j"], [119948, 1, "k"], [119949, 1, "l"], [119950, 1, "m"], [119951, 1, "n"], [119952, 1, "o"], [119953, 1, "p"], [119954, 1, "q"], [119955, 1, "r"], [119956, 1, "s"], [119957, 1, "t"], [119958, 1, "u"], [119959, 1, "v"], [119960, 1, "w"], [119961, 1, "x"], [119962, 1, "y"], [119963, 1, "z"], [119964, 1, "a"], [119965, 3], [119966, 1, "c"], [119967, 1, "d"], [[119968, 119969], 3], [119970, 1, "g"], [[119971, 119972], 3], [119973, 1, "j"], [119974, 1, "k"], [[119975, 119976], 3], [119977, 1, "n"], [119978, 1, "o"], [119979, 1, "p"], [119980, 1, "q"], [119981, 3], [119982, 1, "s"], [119983, 1, "t"], [119984, 1, "u"], [119985, 1, "v"], [119986, 1, "w"], [119987, 1, "x"], [119988, 1, "y"], [119989, 1, "z"], [119990, 1, "a"], [119991, 1, "b"], [119992, 1, "c"], [119993, 1, "d"], [119994, 3], [119995, 1, "f"], [119996, 3], [119997, 1, "h"], [119998, 1, "i"], [119999, 1, "j"], [12e4, 1, "k"], [120001, 1, "l"], [120002, 1, "m"], [120003, 1, "n"], [120004, 3], [120005, 1, "p"], [120006, 1, "q"], [120007, 1, "r"], [120008, 1, "s"], [120009, 1, "t"], [120010, 1, "u"], [120011, 1, "v"], [120012, 1, "w"], [120013, 1, "x"], [120014, 1, "y"], [120015, 1, "z"], [120016, 1, "a"], [120017, 1, "b"], [120018, 1, "c"], [120019, 1, "d"], [120020, 1, "e"], [120021, 1, "f"], [120022, 1, "g"], [120023, 1, "h"], [120024, 1, "i"], [120025, 1, "j"], [120026, 1, "k"], [120027, 1, "l"], [120028, 1, "m"], [120029, 1, "n"], [120030, 1, "o"], [120031, 1, "p"], [120032, 1, "q"], [120033, 1, "r"], [120034, 1, "s"], [120035, 1, "t"], [120036, 1, "u"], [120037, 1, "v"], [120038, 1, "w"], [120039, 1, "x"], [120040, 1, "y"], [120041, 1, "z"], [120042, 1, "a"], [120043, 1, "b"], [120044, 1, "c"], [120045, 1, "d"], [120046, 1, "e"], [120047, 1, "f"], [120048, 1, "g"], [120049, 1, "h"], [120050, 1, "i"], [120051, 1, "j"], [120052, 1, "k"], [120053, 1, "l"], [120054, 1, "m"], [120055, 1, "n"], [120056, 1, "o"], [120057, 1, "p"], [120058, 1, "q"], [120059, 1, "r"], [120060, 1, "s"], [120061, 1, "t"], [120062, 1, "u"], [120063, 1, "v"], [120064, 1, "w"], [120065, 1, "x"], [120066, 1, "y"], [120067, 1, "z"], [120068, 1, "a"], [120069, 1, "b"], [120070, 3], [120071, 1, "d"], [120072, 1, "e"], [120073, 1, "f"], [120074, 1, "g"], [[120075, 120076], 3], [120077, 1, "j"], [120078, 1, "k"], [120079, 1, "l"], [120080, 1, "m"], [120081, 1, "n"], [120082, 1, "o"], [120083, 1, "p"], [120084, 1, "q"], [120085, 3], [120086, 1, "s"], [120087, 1, "t"], [120088, 1, "u"], [120089, 1, "v"], [120090, 1, "w"], [120091, 1, "x"], [120092, 1, "y"], [120093, 3], [120094, 1, "a"], [120095, 1, "b"], [120096, 1, "c"], [120097, 1, "d"], [120098, 1, "e"], [120099, 1, "f"], [120100, 1, "g"], [120101, 1, "h"], [120102, 1, "i"], [120103, 1, "j"], [120104, 1, "k"], [120105, 1, "l"], [120106, 1, "m"], [120107, 1, "n"], [120108, 1, "o"], [120109, 1, "p"], [120110, 1, "q"], [120111, 1, "r"], [120112, 1, "s"], [120113, 1, "t"], [120114, 1, "u"], [120115, 1, "v"], [120116, 1, "w"], [120117, 1, "x"], [120118, 1, "y"], [120119, 1, "z"], [120120, 1, "a"], [120121, 1, "b"], [120122, 3], [120123, 1, "d"], [120124, 1, "e"], [120125, 1, "f"], [120126, 1, "g"], [120127, 3], [120128, 1, "i"], [120129, 1, "j"], [120130, 1, "k"], [120131, 1, "l"], [120132, 1, "m"], [120133, 3], [120134, 1, "o"], [[120135, 120137], 3], [120138, 1, "s"], [120139, 1, "t"], [120140, 1, "u"], [120141, 1, "v"], [120142, 1, "w"], [120143, 1, "x"], [120144, 1, "y"], [120145, 3], [120146, 1, "a"], [120147, 1, "b"], [120148, 1, "c"], [120149, 1, "d"], [120150, 1, "e"], [120151, 1, "f"], [120152, 1, "g"], [120153, 1, "h"], [120154, 1, "i"], [120155, 1, "j"], [120156, 1, "k"], [120157, 1, "l"], [120158, 1, "m"], [120159, 1, "n"], [120160, 1, "o"], [120161, 1, "p"], [120162, 1, "q"], [120163, 1, "r"], [120164, 1, "s"], [120165, 1, "t"], [120166, 1, "u"], [120167, 1, "v"], [120168, 1, "w"], [120169, 1, "x"], [120170, 1, "y"], [120171, 1, "z"], [120172, 1, "a"], [120173, 1, "b"], [120174, 1, "c"], [120175, 1, "d"], [120176, 1, "e"], [120177, 1, "f"], [120178, 1, "g"], [120179, 1, "h"], [120180, 1, "i"], [120181, 1, "j"], [120182, 1, "k"], [120183, 1, "l"], [120184, 1, "m"], [120185, 1, "n"], [120186, 1, "o"], [120187, 1, "p"], [120188, 1, "q"], [120189, 1, "r"], [120190, 1, "s"], [120191, 1, "t"], [120192, 1, "u"], [120193, 1, "v"], [120194, 1, "w"], [120195, 1, "x"], [120196, 1, "y"], [120197, 1, "z"], [120198, 1, "a"], [120199, 1, "b"], [120200, 1, "c"], [120201, 1, "d"], [120202, 1, "e"], [120203, 1, "f"], [120204, 1, "g"], [120205, 1, "h"], [120206, 1, "i"], [120207, 1, "j"], [120208, 1, "k"], [120209, 1, "l"], [120210, 1, "m"], [120211, 1, "n"], [120212, 1, "o"], [120213, 1, "p"], [120214, 1, "q"], [120215, 1, "r"], [120216, 1, "s"], [120217, 1, "t"], [120218, 1, "u"], [120219, 1, "v"], [120220, 1, "w"], [120221, 1, "x"], [120222, 1, "y"], [120223, 1, "z"], [120224, 1, "a"], [120225, 1, "b"], [120226, 1, "c"], [120227, 1, "d"], [120228, 1, "e"], [120229, 1, "f"], [120230, 1, "g"], [120231, 1, "h"], [120232, 1, "i"], [120233, 1, "j"], [120234, 1, "k"], [120235, 1, "l"], [120236, 1, "m"], [120237, 1, "n"], [120238, 1, "o"], [120239, 1, "p"], [120240, 1, "q"], [120241, 1, "r"], [120242, 1, "s"], [120243, 1, "t"], [120244, 1, "u"], [120245, 1, "v"], [120246, 1, "w"], [120247, 1, "x"], [120248, 1, "y"], [120249, 1, "z"], [120250, 1, "a"], [120251, 1, "b"], [120252, 1, "c"], [120253, 1, "d"], [120254, 1, "e"], [120255, 1, "f"], [120256, 1, "g"], [120257, 1, "h"], [120258, 1, "i"], [120259, 1, "j"], [120260, 1, "k"], [120261, 1, "l"], [120262, 1, "m"], [120263, 1, "n"], [120264, 1, "o"], [120265, 1, "p"], [120266, 1, "q"], [120267, 1, "r"], [120268, 1, "s"], [120269, 1, "t"], [120270, 1, "u"], [120271, 1, "v"], [120272, 1, "w"], [120273, 1, "x"], [120274, 1, "y"], [120275, 1, "z"], [120276, 1, "a"], [120277, 1, "b"], [120278, 1, "c"], [120279, 1, "d"], [120280, 1, "e"], [120281, 1, "f"], [120282, 1, "g"], [120283, 1, "h"], [120284, 1, "i"], [120285, 1, "j"], [120286, 1, "k"], [120287, 1, "l"], [120288, 1, "m"], [120289, 1, "n"], [120290, 1, "o"], [120291, 1, "p"], [120292, 1, "q"], [120293, 1, "r"], [120294, 1, "s"], [120295, 1, "t"], [120296, 1, "u"], [120297, 1, "v"], [120298, 1, "w"], [120299, 1, "x"], [120300, 1, "y"], [120301, 1, "z"], [120302, 1, "a"], [120303, 1, "b"], [120304, 1, "c"], [120305, 1, "d"], [120306, 1, "e"], [120307, 1, "f"], [120308, 1, "g"], [120309, 1, "h"], [120310, 1, "i"], [120311, 1, "j"], [120312, 1, "k"], [120313, 1, "l"], [120314, 1, "m"], [120315, 1, "n"], [120316, 1, "o"], [120317, 1, "p"], [120318, 1, "q"], [120319, 1, "r"], [120320, 1, "s"], [120321, 1, "t"], [120322, 1, "u"], [120323, 1, "v"], [120324, 1, "w"], [120325, 1, "x"], [120326, 1, "y"], [120327, 1, "z"], [120328, 1, "a"], [120329, 1, "b"], [120330, 1, "c"], [120331, 1, "d"], [120332, 1, "e"], [120333, 1, "f"], [120334, 1, "g"], [120335, 1, "h"], [120336, 1, "i"], [120337, 1, "j"], [120338, 1, "k"], [120339, 1, "l"], [120340, 1, "m"], [120341, 1, "n"], [120342, 1, "o"], [120343, 1, "p"], [120344, 1, "q"], [120345, 1, "r"], [120346, 1, "s"], [120347, 1, "t"], [120348, 1, "u"], [120349, 1, "v"], [120350, 1, "w"], [120351, 1, "x"], [120352, 1, "y"], [120353, 1, "z"], [120354, 1, "a"], [120355, 1, "b"], [120356, 1, "c"], [120357, 1, "d"], [120358, 1, "e"], [120359, 1, "f"], [120360, 1, "g"], [120361, 1, "h"], [120362, 1, "i"], [120363, 1, "j"], [120364, 1, "k"], [120365, 1, "l"], [120366, 1, "m"], [120367, 1, "n"], [120368, 1, "o"], [120369, 1, "p"], [120370, 1, "q"], [120371, 1, "r"], [120372, 1, "s"], [120373, 1, "t"], [120374, 1, "u"], [120375, 1, "v"], [120376, 1, "w"], [120377, 1, "x"], [120378, 1, "y"], [120379, 1, "z"], [120380, 1, "a"], [120381, 1, "b"], [120382, 1, "c"], [120383, 1, "d"], [120384, 1, "e"], [120385, 1, "f"], [120386, 1, "g"], [120387, 1, "h"], [120388, 1, "i"], [120389, 1, "j"], [120390, 1, "k"], [120391, 1, "l"], [120392, 1, "m"], [120393, 1, "n"], [120394, 1, "o"], [120395, 1, "p"], [120396, 1, "q"], [120397, 1, "r"], [120398, 1, "s"], [120399, 1, "t"], [120400, 1, "u"], [120401, 1, "v"], [120402, 1, "w"], [120403, 1, "x"], [120404, 1, "y"], [120405, 1, "z"], [120406, 1, "a"], [120407, 1, "b"], [120408, 1, "c"], [120409, 1, "d"], [120410, 1, "e"], [120411, 1, "f"], [120412, 1, "g"], [120413, 1, "h"], [120414, 1, "i"], [120415, 1, "j"], [120416, 1, "k"], [120417, 1, "l"], [120418, 1, "m"], [120419, 1, "n"], [120420, 1, "o"], [120421, 1, "p"], [120422, 1, "q"], [120423, 1, "r"], [120424, 1, "s"], [120425, 1, "t"], [120426, 1, "u"], [120427, 1, "v"], [120428, 1, "w"], [120429, 1, "x"], [120430, 1, "y"], [120431, 1, "z"], [120432, 1, "a"], [120433, 1, "b"], [120434, 1, "c"], [120435, 1, "d"], [120436, 1, "e"], [120437, 1, "f"], [120438, 1, "g"], [120439, 1, "h"], [120440, 1, "i"], [120441, 1, "j"], [120442, 1, "k"], [120443, 1, "l"], [120444, 1, "m"], [120445, 1, "n"], [120446, 1, "o"], [120447, 1, "p"], [120448, 1, "q"], [120449, 1, "r"], [120450, 1, "s"], [120451, 1, "t"], [120452, 1, "u"], [120453, 1, "v"], [120454, 1, "w"], [120455, 1, "x"], [120456, 1, "y"], [120457, 1, "z"], [120458, 1, "a"], [120459, 1, "b"], [120460, 1, "c"], [120461, 1, "d"], [120462, 1, "e"], [120463, 1, "f"], [120464, 1, "g"], [120465, 1, "h"], [120466, 1, "i"], [120467, 1, "j"], [120468, 1, "k"], [120469, 1, "l"], [120470, 1, "m"], [120471, 1, "n"], [120472, 1, "o"], [120473, 1, "p"], [120474, 1, "q"], [120475, 1, "r"], [120476, 1, "s"], [120477, 1, "t"], [120478, 1, "u"], [120479, 1, "v"], [120480, 1, "w"], [120481, 1, "x"], [120482, 1, "y"], [120483, 1, "z"], [120484, 1, "\u0131"], [120485, 1, "\u0237"], [120486, 1, "ss"], [120487, 3], [120488, 1, "\u03B1"], [120489, 1, "\u03B2"], [120490, 1, "\u03B3"], [120491, 1, "\u03B4"], [120492, 1, "\u03B5"], [120493, 1, "\u03B6"], [120494, 1, "\u03B7"], [120495, 1, "\u03B8"], [120496, 1, "\u03B9"], [120497, 1, "\u03BA"], [120498, 1, "\u03BB"], [120499, 1, "\u03BC"], [120500, 1, "\u03BD"], [120501, 1, "\u03BE"], [120502, 1, "\u03BF"], [120503, 1, "\u03C0"], [120504, 1, "\u03C1"], [120505, 1, "\u03B8"], [120506, 1, "\u03C3"], [120507, 1, "\u03C4"], [120508, 1, "\u03C5"], [120509, 1, "\u03C6"], [120510, 1, "\u03C7"], [120511, 1, "\u03C8"], [120512, 1, "\u03C9"], [120513, 1, "\u2207"], [120514, 1, "\u03B1"], [120515, 1, "\u03B2"], [120516, 1, "\u03B3"], [120517, 1, "\u03B4"], [120518, 1, "\u03B5"], [120519, 1, "\u03B6"], [120520, 1, "\u03B7"], [120521, 1, "\u03B8"], [120522, 1, "\u03B9"], [120523, 1, "\u03BA"], [120524, 1, "\u03BB"], [120525, 1, "\u03BC"], [120526, 1, "\u03BD"], [120527, 1, "\u03BE"], [120528, 1, "\u03BF"], [120529, 1, "\u03C0"], [120530, 1, "\u03C1"], [[120531, 120532], 1, "\u03C3"], [120533, 1, "\u03C4"], [120534, 1, "\u03C5"], [120535, 1, "\u03C6"], [120536, 1, "\u03C7"], [120537, 1, "\u03C8"], [120538, 1, "\u03C9"], [120539, 1, "\u2202"], [120540, 1, "\u03B5"], [120541, 1, "\u03B8"], [120542, 1, "\u03BA"], [120543, 1, "\u03C6"], [120544, 1, "\u03C1"], [120545, 1, "\u03C0"], [120546, 1, "\u03B1"], [120547, 1, "\u03B2"], [120548, 1, "\u03B3"], [120549, 1, "\u03B4"], [120550, 1, "\u03B5"], [120551, 1, "\u03B6"], [120552, 1, "\u03B7"], [120553, 1, "\u03B8"], [120554, 1, "\u03B9"], [120555, 1, "\u03BA"], [120556, 1, "\u03BB"], [120557, 1, "\u03BC"], [120558, 1, "\u03BD"], [120559, 1, "\u03BE"], [120560, 1, "\u03BF"], [120561, 1, "\u03C0"], [120562, 1, "\u03C1"], [120563, 1, "\u03B8"], [120564, 1, "\u03C3"], [120565, 1, "\u03C4"], [120566, 1, "\u03C5"], [120567, 1, "\u03C6"], [120568, 1, "\u03C7"], [120569, 1, "\u03C8"], [120570, 1, "\u03C9"], [120571, 1, "\u2207"], [120572, 1, "\u03B1"], [120573, 1, "\u03B2"], [120574, 1, "\u03B3"], [120575, 1, "\u03B4"], [120576, 1, "\u03B5"], [120577, 1, "\u03B6"], [120578, 1, "\u03B7"], [120579, 1, "\u03B8"], [120580, 1, "\u03B9"], [120581, 1, "\u03BA"], [120582, 1, "\u03BB"], [120583, 1, "\u03BC"], [120584, 1, "\u03BD"], [120585, 1, "\u03BE"], [120586, 1, "\u03BF"], [120587, 1, "\u03C0"], [120588, 1, "\u03C1"], [[120589, 120590], 1, "\u03C3"], [120591, 1, "\u03C4"], [120592, 1, "\u03C5"], [120593, 1, "\u03C6"], [120594, 1, "\u03C7"], [120595, 1, "\u03C8"], [120596, 1, "\u03C9"], [120597, 1, "\u2202"], [120598, 1, "\u03B5"], [120599, 1, "\u03B8"], [120600, 1, "\u03BA"], [120601, 1, "\u03C6"], [120602, 1, "\u03C1"], [120603, 1, "\u03C0"], [120604, 1, "\u03B1"], [120605, 1, "\u03B2"], [120606, 1, "\u03B3"], [120607, 1, "\u03B4"], [120608, 1, "\u03B5"], [120609, 1, "\u03B6"], [120610, 1, "\u03B7"], [120611, 1, "\u03B8"], [120612, 1, "\u03B9"], [120613, 1, "\u03BA"], [120614, 1, "\u03BB"], [120615, 1, "\u03BC"], [120616, 1, "\u03BD"], [120617, 1, "\u03BE"], [120618, 1, "\u03BF"], [120619, 1, "\u03C0"], [120620, 1, "\u03C1"], [120621, 1, "\u03B8"], [120622, 1, "\u03C3"], [120623, 1, "\u03C4"], [120624, 1, "\u03C5"], [120625, 1, "\u03C6"], [120626, 1, "\u03C7"], [120627, 1, "\u03C8"], [120628, 1, "\u03C9"], [120629, 1, "\u2207"], [120630, 1, "\u03B1"], [120631, 1, "\u03B2"], [120632, 1, "\u03B3"], [120633, 1, "\u03B4"], [120634, 1, "\u03B5"], [120635, 1, "\u03B6"], [120636, 1, "\u03B7"], [120637, 1, "\u03B8"], [120638, 1, "\u03B9"], [120639, 1, "\u03BA"], [120640, 1, "\u03BB"], [120641, 1, "\u03BC"], [120642, 1, "\u03BD"], [120643, 1, "\u03BE"], [120644, 1, "\u03BF"], [120645, 1, "\u03C0"], [120646, 1, "\u03C1"], [[120647, 120648], 1, "\u03C3"], [120649, 1, "\u03C4"], [120650, 1, "\u03C5"], [120651, 1, "\u03C6"], [120652, 1, "\u03C7"], [120653, 1, "\u03C8"], [120654, 1, "\u03C9"], [120655, 1, "\u2202"], [120656, 1, "\u03B5"], [120657, 1, "\u03B8"], [120658, 1, "\u03BA"], [120659, 1, "\u03C6"], [120660, 1, "\u03C1"], [120661, 1, "\u03C0"], [120662, 1, "\u03B1"], [120663, 1, "\u03B2"], [120664, 1, "\u03B3"], [120665, 1, "\u03B4"], [120666, 1, "\u03B5"], [120667, 1, "\u03B6"], [120668, 1, "\u03B7"], [120669, 1, "\u03B8"], [120670, 1, "\u03B9"], [120671, 1, "\u03BA"], [120672, 1, "\u03BB"], [120673, 1, "\u03BC"], [120674, 1, "\u03BD"], [120675, 1, "\u03BE"], [120676, 1, "\u03BF"], [120677, 1, "\u03C0"], [120678, 1, "\u03C1"], [120679, 1, "\u03B8"], [120680, 1, "\u03C3"], [120681, 1, "\u03C4"], [120682, 1, "\u03C5"], [120683, 1, "\u03C6"], [120684, 1, "\u03C7"], [120685, 1, "\u03C8"], [120686, 1, "\u03C9"], [120687, 1, "\u2207"], [120688, 1, "\u03B1"], [120689, 1, "\u03B2"], [120690, 1, "\u03B3"], [120691, 1, "\u03B4"], [120692, 1, "\u03B5"], [120693, 1, "\u03B6"], [120694, 1, "\u03B7"], [120695, 1, "\u03B8"], [120696, 1, "\u03B9"], [120697, 1, "\u03BA"], [120698, 1, "\u03BB"], [120699, 1, "\u03BC"], [120700, 1, "\u03BD"], [120701, 1, "\u03BE"], [120702, 1, "\u03BF"], [120703, 1, "\u03C0"], [120704, 1, "\u03C1"], [[120705, 120706], 1, "\u03C3"], [120707, 1, "\u03C4"], [120708, 1, "\u03C5"], [120709, 1, "\u03C6"], [120710, 1, "\u03C7"], [120711, 1, "\u03C8"], [120712, 1, "\u03C9"], [120713, 1, "\u2202"], [120714, 1, "\u03B5"], [120715, 1, "\u03B8"], [120716, 1, "\u03BA"], [120717, 1, "\u03C6"], [120718, 1, "\u03C1"], [120719, 1, "\u03C0"], [120720, 1, "\u03B1"], [120721, 1, "\u03B2"], [120722, 1, "\u03B3"], [120723, 1, "\u03B4"], [120724, 1, "\u03B5"], [120725, 1, "\u03B6"], [120726, 1, "\u03B7"], [120727, 1, "\u03B8"], [120728, 1, "\u03B9"], [120729, 1, "\u03BA"], [120730, 1, "\u03BB"], [120731, 1, "\u03BC"], [120732, 1, "\u03BD"], [120733, 1, "\u03BE"], [120734, 1, "\u03BF"], [120735, 1, "\u03C0"], [120736, 1, "\u03C1"], [120737, 1, "\u03B8"], [120738, 1, "\u03C3"], [120739, 1, "\u03C4"], [120740, 1, "\u03C5"], [120741, 1, "\u03C6"], [120742, 1, "\u03C7"], [120743, 1, "\u03C8"], [120744, 1, "\u03C9"], [120745, 1, "\u2207"], [120746, 1, "\u03B1"], [120747, 1, "\u03B2"], [120748, 1, "\u03B3"], [120749, 1, "\u03B4"], [120750, 1, "\u03B5"], [120751, 1, "\u03B6"], [120752, 1, "\u03B7"], [120753, 1, "\u03B8"], [120754, 1, "\u03B9"], [120755, 1, "\u03BA"], [120756, 1, "\u03BB"], [120757, 1, "\u03BC"], [120758, 1, "\u03BD"], [120759, 1, "\u03BE"], [120760, 1, "\u03BF"], [120761, 1, "\u03C0"], [120762, 1, "\u03C1"], [[120763, 120764], 1, "\u03C3"], [120765, 1, "\u03C4"], [120766, 1, "\u03C5"], [120767, 1, "\u03C6"], [120768, 1, "\u03C7"], [120769, 1, "\u03C8"], [120770, 1, "\u03C9"], [120771, 1, "\u2202"], [120772, 1, "\u03B5"], [120773, 1, "\u03B8"], [120774, 1, "\u03BA"], [120775, 1, "\u03C6"], [120776, 1, "\u03C1"], [120777, 1, "\u03C0"], [[120778, 120779], 1, "\u03DD"], [[120780, 120781], 3], [120782, 1, "0"], [120783, 1, "1"], [120784, 1, "2"], [120785, 1, "3"], [120786, 1, "4"], [120787, 1, "5"], [120788, 1, "6"], [120789, 1, "7"], [120790, 1, "8"], [120791, 1, "9"], [120792, 1, "0"], [120793, 1, "1"], [120794, 1, "2"], [120795, 1, "3"], [120796, 1, "4"], [120797, 1, "5"], [120798, 1, "6"], [120799, 1, "7"], [120800, 1, "8"], [120801, 1, "9"], [120802, 1, "0"], [120803, 1, "1"], [120804, 1, "2"], [120805, 1, "3"], [120806, 1, "4"], [120807, 1, "5"], [120808, 1, "6"], [120809, 1, "7"], [120810, 1, "8"], [120811, 1, "9"], [120812, 1, "0"], [120813, 1, "1"], [120814, 1, "2"], [120815, 1, "3"], [120816, 1, "4"], [120817, 1, "5"], [120818, 1, "6"], [120819, 1, "7"], [120820, 1, "8"], [120821, 1, "9"], [120822, 1, "0"], [120823, 1, "1"], [120824, 1, "2"], [120825, 1, "3"], [120826, 1, "4"], [120827, 1, "5"], [120828, 1, "6"], [120829, 1, "7"], [120830, 1, "8"], [120831, 1, "9"], [[120832, 121343], 2], [[121344, 121398], 2], [[121399, 121402], 2], [[121403, 121452], 2], [[121453, 121460], 2], [121461, 2], [[121462, 121475], 2], [121476, 2], [[121477, 121483], 2], [[121484, 121498], 3], [[121499, 121503], 2], [121504, 3], [[121505, 121519], 2], [[121520, 121599], 3], [[121600, 121628], 2], [[121629, 122623], 3], [[122624, 122654], 2], [[122655, 122660], 2], [[122661, 122666], 2], [[122667, 122687], 2], [122688, 1, "\u{1DF41}"], [[122689, 122695], 2], [122696, 1, "\u{1DF49}"], [122697, 2], [122698, 1, "\u{1DF4B}"], [[122699, 122700], 2], [122701, 1, "\u{1DF4E}"], [[122702, 122704], 2], [122705, 1, "\u{1DF52}"], [[122706, 122727], 2], [122728, 1, "\u{1DF69}"], [122729, 2], [122730, 1, "\u{1DF6B}"], [122731, 2], [122732, 1, "\u{1DF6D}"], [122733, 2], [122734, 1, "\u{1DF6F}"], [[122735, 122737], 2], [122738, 1, "\u{1DF73}"], [122739, 2], [122740, 1, "\u{1DF75}"], [122741, 2], [122742, 1, "\u{1DF77}"], [122743, 2], [122744, 1, "\u{1DF79}"], [122745, 2], [122746, 1, "\u{1DF7B}"], [122747, 2], [122748, 1, "\u{1DF7D}"], [122749, 2], [122750, 1, "\u{1DF7F}"], [[122751, 122753], 2], [[122754, 122767], 3], [[122768, 122772], 2], [122773, 1, "ss"], [122774, 2], [[122775, 122828], 3], [122829, 1, "\u{1DF57}"], [122830, 1, "\u{1DF58}"], [122831, 1, "\u{1DF59}"], [122832, 1, "\u0263"], [122833, 1, "\u1D18"], [122834, 1, "\u0180"], [122835, 1, "\u0111"], [122836, 1, "\u01E5"], [122837, 1, "\u0142"], [122838, 1, "\u019A"], [122839, 1, "\u{1DF50}"], [122840, 1, "\u{1DF3E}"], [122841, 1, "\u0249"], [122842, 1, "\u1D7F"], [122843, 1, "\u{1DF3F}"], [122844, 1, "\u019E"], [122845, 1, "\u027C"], [122846, 1, "\u0238"], [122847, 1, "\u0239"], [122848, 1, "\u{1DF2B}"], [122849, 1, "\u{1DF19}"], [122850, 1, "\u0286"], [122851, 1, "\u1D98"], [122852, 1, "\u{1DF2C}"], [122853, 1, "\u{1DF1C}"], [122854, 1, "\u0293"], [122855, 1, "\u1D9A"], [122856, 1, "\u1D05"], [122857, 1, "\u1D00"], [122858, 1, "\u1D07"], [122859, 1, "\u027F"], [122860, 1, "\u0285"], [122861, 1, "\u02AE"], [122862, 1, "\u02AF"], [122863, 1, "\u0221"], [122864, 1, "\u0234"], [122865, 1, "\u0235"], [122866, 1, "\u0236"], [122867, 1, "\u03C8"], [122868, 1, "\u03C9"], [122869, 1, "\u1D81"], [122870, 1, "\uA795"], [122871, 1, "\u1D87"], [122872, 1, "\u1D8A"], [122873, 1, "\u1D8E"], [122874, 1, "\u0188"], [122875, 1, "\u0199"], [122876, 1, "\u01A5"], [122877, 1, "\u02A0"], [122878, 1, "\u01AD"], [122879, 1, "\u{1DF09}"], [[122880, 122886], 2], [122887, 3], [[122888, 122904], 2], [[122905, 122906], 3], [[122907, 122913], 2], [122914, 3], [[122915, 122916], 2], [122917, 3], [[122918, 122922], 2], [[122923, 122927], 3], [122928, 1, "\u0430"], [122929, 1, "\u0431"], [122930, 1, "\u0432"], [122931, 1, "\u0433"], [122932, 1, "\u0434"], [122933, 1, "\u0435"], [122934, 1, "\u0436"], [122935, 1, "\u0437"], [122936, 1, "\u0438"], [122937, 1, "\u043A"], [122938, 1, "\u043B"], [122939, 1, "\u043C"], [122940, 1, "\u043E"], [122941, 1, "\u043F"], [122942, 1, "\u0440"], [122943, 1, "\u0441"], [122944, 1, "\u0442"], [122945, 1, "\u0443"], [122946, 1, "\u0444"], [122947, 1, "\u0445"], [122948, 1, "\u0446"], [122949, 1, "\u0447"], [122950, 1, "\u0448"], [122951, 1, "\u044B"], [122952, 1, "\u044D"], [122953, 1, "\u044E"], [122954, 1, "\uA689"], [122955, 1, "\u04D9"], [122956, 1, "\u0456"], [122957, 1, "\u0458"], [122958, 1, "\u04E9"], [122959, 1, "\u04AF"], [122960, 1, "\u04CF"], [122961, 1, "\u0430"], [122962, 1, "\u0431"], [122963, 1, "\u0432"], [122964, 1, "\u0433"], [122965, 1, "\u0434"], [122966, 1, "\u0435"], [122967, 1, "\u0436"], [122968, 1, "\u0437"], [122969, 1, "\u0438"], [122970, 1, "\u043A"], [122971, 1, "\u043B"], [122972, 1, "\u043E"], [122973, 1, "\u043F"], [122974, 1, "\u0441"], [122975, 1, "\u0443"], [122976, 1, "\u0444"], [122977, 1, "\u0445"], [122978, 1, "\u0446"], [122979, 1, "\u0447"], [122980, 1, "\u0448"], [122981, 1, "\u044A"], [122982, 1, "\u044B"], [122983, 1, "\u0491"], [122984, 1, "\u0456"], [122985, 1, "\u0455"], [122986, 1, "\u045F"], [122987, 1, "\u04AB"], [122988, 1, "\uA651"], [122989, 1, "\u04B1"], [[122990, 123022], 3], [123023, 2], [[123024, 123135], 3], [[123136, 123180], 2], [[123181, 123183], 3], [[123184, 123197], 2], [[123198, 123199], 3], [[123200, 123209], 2], [[123210, 123213], 3], [123214, 2], [123215, 2], [[123216, 123535], 3], [[123536, 123566], 2], [[123567, 123583], 3], [[123584, 123641], 2], [[123642, 123646], 3], [123647, 2], [[123648, 124111], 3], [[124112, 124153], 2], [[124154, 124367], 3], [[124368, 124410], 2], [[124411, 124414], 3], [124415, 2], [[124416, 124607], 3], [[124608, 124638], 2], [124639, 3], [[124640, 124661], 2], [[124662, 124669], 3], [[124670, 124671], 2], [[124672, 124895], 3], [[124896, 124902], 2], [124903, 3], [[124904, 124907], 2], [124908, 3], [[124909, 124910], 2], [124911, 3], [[124912, 124926], 2], [124927, 3], [[124928, 125124], 2], [[125125, 125126], 3], [[125127, 125135], 2], [[125136, 125142], 2], [[125143, 125183], 3], [125184, 1, "\u{1E922}"], [125185, 1, "\u{1E923}"], [125186, 1, "\u{1E924}"], [125187, 1, "\u{1E925}"], [125188, 1, "\u{1E926}"], [125189, 1, "\u{1E927}"], [125190, 1, "\u{1E928}"], [125191, 1, "\u{1E929}"], [125192, 1, "\u{1E92A}"], [125193, 1, "\u{1E92B}"], [125194, 1, "\u{1E92C}"], [125195, 1, "\u{1E92D}"], [125196, 1, "\u{1E92E}"], [125197, 1, "\u{1E92F}"], [125198, 1, "\u{1E930}"], [125199, 1, "\u{1E931}"], [125200, 1, "\u{1E932}"], [125201, 1, "\u{1E933}"], [125202, 1, "\u{1E934}"], [125203, 1, "\u{1E935}"], [125204, 1, "\u{1E936}"], [125205, 1, "\u{1E937}"], [125206, 1, "\u{1E938}"], [125207, 1, "\u{1E939}"], [125208, 1, "\u{1E93A}"], [125209, 1, "\u{1E93B}"], [125210, 1, "\u{1E93C}"], [125211, 1, "\u{1E93D}"], [125212, 1, "\u{1E93E}"], [125213, 1, "\u{1E93F}"], [125214, 1, "\u{1E940}"], [125215, 1, "\u{1E941}"], [125216, 1, "\u{1E942}"], [125217, 1, "\u{1E943}"], [[125218, 125258], 2], [125259, 2], [[125260, 125263], 3], [[125264, 125273], 2], [[125274, 125277], 3], [[125278, 125279], 2], [[125280, 126064], 3], [[126065, 126132], 2], [[126133, 126208], 3], [[126209, 126269], 2], [[126270, 126463], 3], [126464, 1, "\u0627"], [126465, 1, "\u0628"], [126466, 1, "\u062C"], [126467, 1, "\u062F"], [126468, 3], [126469, 1, "\u0648"], [126470, 1, "\u0632"], [126471, 1, "\u062D"], [126472, 1, "\u0637"], [126473, 1, "\u064A"], [126474, 1, "\u0643"], [126475, 1, "\u0644"], [126476, 1, "\u0645"], [126477, 1, "\u0646"], [126478, 1, "\u0633"], [126479, 1, "\u0639"], [126480, 1, "\u0641"], [126481, 1, "\u0635"], [126482, 1, "\u0642"], [126483, 1, "\u0631"], [126484, 1, "\u0634"], [126485, 1, "\u062A"], [126486, 1, "\u062B"], [126487, 1, "\u062E"], [126488, 1, "\u0630"], [126489, 1, "\u0636"], [126490, 1, "\u0638"], [126491, 1, "\u063A"], [126492, 1, "\u066E"], [126493, 1, "\u06BA"], [126494, 1, "\u06A1"], [126495, 1, "\u066F"], [126496, 3], [126497, 1, "\u0628"], [126498, 1, "\u062C"], [126499, 3], [126500, 1, "\u0647"], [[126501, 126502], 3], [126503, 1, "\u062D"], [126504, 3], [126505, 1, "\u064A"], [126506, 1, "\u0643"], [126507, 1, "\u0644"], [126508, 1, "\u0645"], [126509, 1, "\u0646"], [126510, 1, "\u0633"], [126511, 1, "\u0639"], [126512, 1, "\u0641"], [126513, 1, "\u0635"], [126514, 1, "\u0642"], [126515, 3], [126516, 1, "\u0634"], [126517, 1, "\u062A"], [126518, 1, "\u062B"], [126519, 1, "\u062E"], [126520, 3], [126521, 1, "\u0636"], [126522, 3], [126523, 1, "\u063A"], [[126524, 126529], 3], [126530, 1, "\u062C"], [[126531, 126534], 3], [126535, 1, "\u062D"], [126536, 3], [126537, 1, "\u064A"], [126538, 3], [126539, 1, "\u0644"], [126540, 3], [126541, 1, "\u0646"], [126542, 1, "\u0633"], [126543, 1, "\u0639"], [126544, 3], [126545, 1, "\u0635"], [126546, 1, "\u0642"], [126547, 3], [126548, 1, "\u0634"], [[126549, 126550], 3], [126551, 1, "\u062E"], [126552, 3], [126553, 1, "\u0636"], [126554, 3], [126555, 1, "\u063A"], [126556, 3], [126557, 1, "\u06BA"], [126558, 3], [126559, 1, "\u066F"], [126560, 3], [126561, 1, "\u0628"], [126562, 1, "\u062C"], [126563, 3], [126564, 1, "\u0647"], [[126565, 126566], 3], [126567, 1, "\u062D"], [126568, 1, "\u0637"], [126569, 1, "\u064A"], [126570, 1, "\u0643"], [126571, 3], [126572, 1, "\u0645"], [126573, 1, "\u0646"], [126574, 1, "\u0633"], [126575, 1, "\u0639"], [126576, 1, "\u0641"], [126577, 1, "\u0635"], [126578, 1, "\u0642"], [126579, 3], [126580, 1, "\u0634"], [126581, 1, "\u062A"], [126582, 1, "\u062B"], [126583, 1, "\u062E"], [126584, 3], [126585, 1, "\u0636"], [126586, 1, "\u0638"], [126587, 1, "\u063A"], [126588, 1, "\u066E"], [126589, 3], [126590, 1, "\u06A1"], [126591, 3], [126592, 1, "\u0627"], [126593, 1, "\u0628"], [126594, 1, "\u062C"], [126595, 1, "\u062F"], [126596, 1, "\u0647"], [126597, 1, "\u0648"], [126598, 1, "\u0632"], [126599, 1, "\u062D"], [126600, 1, "\u0637"], [126601, 1, "\u064A"], [126602, 3], [126603, 1, "\u0644"], [126604, 1, "\u0645"], [126605, 1, "\u0646"], [126606, 1, "\u0633"], [126607, 1, "\u0639"], [126608, 1, "\u0641"], [126609, 1, "\u0635"], [126610, 1, "\u0642"], [126611, 1, "\u0631"], [126612, 1, "\u0634"], [126613, 1, "\u062A"], [126614, 1, "\u062B"], [126615, 1, "\u062E"], [126616, 1, "\u0630"], [126617, 1, "\u0636"], [126618, 1, "\u0638"], [126619, 1, "\u063A"], [[126620, 126624], 3], [126625, 1, "\u0628"], [126626, 1, "\u062C"], [126627, 1, "\u062F"], [126628, 3], [126629, 1, "\u0648"], [126630, 1, "\u0632"], [126631, 1, "\u062D"], [126632, 1, "\u0637"], [126633, 1, "\u064A"], [126634, 3], [126635, 1, "\u0644"], [126636, 1, "\u0645"], [126637, 1, "\u0646"], [126638, 1, "\u0633"], [126639, 1, "\u0639"], [126640, 1, "\u0641"], [126641, 1, "\u0635"], [126642, 1, "\u0642"], [126643, 1, "\u0631"], [126644, 1, "\u0634"], [126645, 1, "\u062A"], [126646, 1, "\u062B"], [126647, 1, "\u062E"], [126648, 1, "\u0630"], [126649, 1, "\u0636"], [126650, 1, "\u0638"], [126651, 1, "\u063A"], [[126652, 126703], 3], [[126704, 126705], 2], [[126706, 126975], 3], [[126976, 127019], 2], [[127020, 127023], 3], [[127024, 127123], 2], [[127124, 127135], 3], [[127136, 127150], 2], [[127151, 127152], 3], [[127153, 127166], 2], [127167, 2], [127168, 3], [[127169, 127183], 2], [127184, 3], [[127185, 127199], 2], [[127200, 127221], 2], [[127222, 127231], 3], [127232, 3], [127233, 1, "0,"], [127234, 1, "1,"], [127235, 1, "2,"], [127236, 1, "3,"], [127237, 1, "4,"], [127238, 1, "5,"], [127239, 1, "6,"], [127240, 1, "7,"], [127241, 1, "8,"], [127242, 1, "9,"], [[127243, 127244], 2], [[127245, 127247], 2], [127248, 1, "(a)"], [127249, 1, "(b)"], [127250, 1, "(c)"], [127251, 1, "(d)"], [127252, 1, "(e)"], [127253, 1, "(f)"], [127254, 1, "(g)"], [127255, 1, "(h)"], [127256, 1, "(i)"], [127257, 1, "(j)"], [127258, 1, "(k)"], [127259, 1, "(l)"], [127260, 1, "(m)"], [127261, 1, "(n)"], [127262, 1, "(o)"], [127263, 1, "(p)"], [127264, 1, "(q)"], [127265, 1, "(r)"], [127266, 1, "(s)"], [127267, 1, "(t)"], [127268, 1, "(u)"], [127269, 1, "(v)"], [127270, 1, "(w)"], [127271, 1, "(x)"], [127272, 1, "(y)"], [127273, 1, "(z)"], [127274, 1, "\u3014s\u3015"], [127275, 1, "c"], [127276, 1, "r"], [127277, 1, "cd"], [127278, 1, "wz"], [127279, 2], [127280, 1, "a"], [127281, 1, "b"], [127282, 1, "c"], [127283, 1, "d"], [127284, 1, "e"], [127285, 1, "f"], [127286, 1, "g"], [127287, 1, "h"], [127288, 1, "i"], [127289, 1, "j"], [127290, 1, "k"], [127291, 1, "l"], [127292, 1, "m"], [127293, 1, "n"], [127294, 1, "o"], [127295, 1, "p"], [127296, 1, "q"], [127297, 1, "r"], [127298, 1, "s"], [127299, 1, "t"], [127300, 1, "u"], [127301, 1, "v"], [127302, 1, "w"], [127303, 1, "x"], [127304, 1, "y"], [127305, 1, "z"], [127306, 1, "hv"], [127307, 1, "mv"], [127308, 1, "sd"], [127309, 1, "ss"], [127310, 1, "ppv"], [127311, 1, "wc"], [[127312, 127318], 2], [127319, 2], [[127320, 127326], 2], [127327, 2], [[127328, 127337], 2], [127338, 1, "mc"], [127339, 1, "md"], [127340, 1, "mr"], [[127341, 127343], 2], [[127344, 127352], 2], [127353, 2], [127354, 2], [[127355, 127356], 2], [[127357, 127358], 2], [127359, 2], [[127360, 127369], 2], [[127370, 127373], 2], [[127374, 127375], 2], [127376, 1, "dj"], [[127377, 127386], 2], [[127387, 127404], 2], [127405, 2], [127406, 2], [[127407, 127461], 3], [[127462, 127487], 2], [127488, 1, "\u307B\u304B"], [127489, 1, "\u30B3\u30B3"], [127490, 1, "\u30B5"], [[127491, 127503], 3], [127504, 1, "\u624B"], [127505, 1, "\u5B57"], [127506, 1, "\u53CC"], [127507, 1, "\u30C7"], [127508, 1, "\u4E8C"], [127509, 1, "\u591A"], [127510, 1, "\u89E3"], [127511, 1, "\u5929"], [127512, 1, "\u4EA4"], [127513, 1, "\u6620"], [127514, 1, "\u7121"], [127515, 1, "\u6599"], [127516, 1, "\u524D"], [127517, 1, "\u5F8C"], [127518, 1, "\u518D"], [127519, 1, "\u65B0"], [127520, 1, "\u521D"], [127521, 1, "\u7D42"], [127522, 1, "\u751F"], [127523, 1, "\u8CA9"], [127524, 1, "\u58F0"], [127525, 1, "\u5439"], [127526, 1, "\u6F14"], [127527, 1, "\u6295"], [127528, 1, "\u6355"], [127529, 1, "\u4E00"], [127530, 1, "\u4E09"], [127531, 1, "\u904A"], [127532, 1, "\u5DE6"], [127533, 1, "\u4E2D"], [127534, 1, "\u53F3"], [127535, 1, "\u6307"], [127536, 1, "\u8D70"], [127537, 1, "\u6253"], [127538, 1, "\u7981"], [127539, 1, "\u7A7A"], [127540, 1, "\u5408"], [127541, 1, "\u6E80"], [127542, 1, "\u6709"], [127543, 1, "\u6708"], [127544, 1, "\u7533"], [127545, 1, "\u5272"], [127546, 1, "\u55B6"], [127547, 1, "\u914D"], [[127548, 127551], 3], [127552, 1, "\u3014\u672C\u3015"], [127553, 1, "\u3014\u4E09\u3015"], [127554, 1, "\u3014\u4E8C\u3015"], [127555, 1, "\u3014\u5B89\u3015"], [127556, 1, "\u3014\u70B9\u3015"], [127557, 1, "\u3014\u6253\u3015"], [127558, 1, "\u3014\u76D7\u3015"], [127559, 1, "\u3014\u52DD\u3015"], [127560, 1, "\u3014\u6557\u3015"], [[127561, 127567], 3], [127568, 1, "\u5F97"], [127569, 1, "\u53EF"], [[127570, 127583], 3], [[127584, 127589], 2], [[127590, 127743], 3], [[127744, 127776], 2], [[127777, 127788], 2], [[127789, 127791], 2], [[127792, 127797], 2], [127798, 2], [[127799, 127868], 2], [127869, 2], [[127870, 127871], 2], [[127872, 127891], 2], [[127892, 127903], 2], [[127904, 127940], 2], [127941, 2], [[127942, 127946], 2], [[127947, 127950], 2], [[127951, 127955], 2], [[127956, 127967], 2], [[127968, 127984], 2], [[127985, 127991], 2], [[127992, 127999], 2], [[128e3, 128062], 2], [128063, 2], [128064, 2], [128065, 2], [[128066, 128247], 2], [128248, 2], [[128249, 128252], 2], [[128253, 128254], 2], [128255, 2], [[128256, 128317], 2], [[128318, 128319], 2], [[128320, 128323], 2], [[128324, 128330], 2], [[128331, 128335], 2], [[128336, 128359], 2], [[128360, 128377], 2], [128378, 2], [[128379, 128419], 2], [128420, 2], [[128421, 128506], 2], [[128507, 128511], 2], [128512, 2], [[128513, 128528], 2], [128529, 2], [[128530, 128532], 2], [128533, 2], [128534, 2], [128535, 2], [128536, 2], [128537, 2], [128538, 2], [128539, 2], [[128540, 128542], 2], [128543, 2], [[128544, 128549], 2], [[128550, 128551], 2], [[128552, 128555], 2], [128556, 2], [128557, 2], [[128558, 128559], 2], [[128560, 128563], 2], [128564, 2], [[128565, 128576], 2], [[128577, 128578], 2], [[128579, 128580], 2], [[128581, 128591], 2], [[128592, 128639], 2], [[128640, 128709], 2], [[128710, 128719], 2], [128720, 2], [[128721, 128722], 2], [[128723, 128724], 2], [128725, 2], [[128726, 128727], 2], [128728, 2], [128729, 2], [[128730, 128731], 3], [128732, 2], [[128733, 128735], 2], [[128736, 128748], 2], [[128749, 128751], 3], [[128752, 128755], 2], [[128756, 128758], 2], [[128759, 128760], 2], [128761, 2], [128762, 2], [[128763, 128764], 2], [[128765, 128767], 3], [[128768, 128883], 2], [[128884, 128886], 2], [[128887, 128890], 2], [[128891, 128895], 2], [[128896, 128980], 2], [[128981, 128984], 2], [128985, 2], [[128986, 128987], 2], [[128988, 128991], 3], [[128992, 129003], 2], [[129004, 129007], 3], [129008, 2], [[129009, 129023], 2], [[129024, 129035], 2], [[129036, 129039], 3], [[129040, 129095], 2], [[129096, 129103], 3], [[129104, 129113], 2], [[129114, 129119], 3], [[129120, 129159], 2], [[129160, 129167], 3], [[129168, 129197], 2], [[129198, 129199], 3], [[129200, 129201], 2], [[129202, 129211], 2], [[129212, 129215], 3], [[129216, 129217], 2], [[129218, 129231], 3], [[129232, 129240], 2], [[129241, 129279], 3], [[129280, 129291], 2], [129292, 2], [[129293, 129295], 2], [[129296, 129304], 2], [[129305, 129310], 2], [129311, 2], [[129312, 129319], 2], [[129320, 129327], 2], [129328, 2], [[129329, 129330], 2], [[129331, 129342], 2], [129343, 2], [[129344, 129355], 2], [129356, 2], [[129357, 129359], 2], [[129360, 129374], 2], [[129375, 129387], 2], [[129388, 129392], 2], [129393, 2], [129394, 2], [[129395, 129398], 2], [[129399, 129400], 2], [129401, 2], [129402, 2], [129403, 2], [[129404, 129407], 2], [[129408, 129412], 2], [[129413, 129425], 2], [[129426, 129431], 2], [[129432, 129442], 2], [[129443, 129444], 2], [[129445, 129450], 2], [[129451, 129453], 2], [[129454, 129455], 2], [[129456, 129465], 2], [[129466, 129471], 2], [129472, 2], [[129473, 129474], 2], [[129475, 129482], 2], [129483, 2], [129484, 2], [[129485, 129487], 2], [[129488, 129510], 2], [[129511, 129535], 2], [[129536, 129619], 2], [[129620, 129623], 2], [[129624, 129631], 3], [[129632, 129645], 2], [[129646, 129647], 3], [[129648, 129651], 2], [129652, 2], [[129653, 129655], 2], [[129656, 129658], 2], [[129659, 129660], 2], [[129661, 129663], 3], [[129664, 129666], 2], [[129667, 129670], 2], [[129671, 129672], 2], [129673, 2], [129674, 2], [[129675, 129677], 2], [129678, 2], [129679, 2], [[129680, 129685], 2], [[129686, 129704], 2], [[129705, 129708], 2], [[129709, 129711], 2], [[129712, 129718], 2], [[129719, 129722], 2], [[129723, 129725], 2], [129726, 2], [129727, 2], [[129728, 129730], 2], [[129731, 129733], 2], [129734, 2], [129735, 3], [129736, 2], [[129737, 129739], 3], [129740, 2], [129741, 2], [[129742, 129743], 2], [[129744, 129750], 2], [[129751, 129753], 2], [[129754, 129755], 2], [129756, 2], [129757, 2], [129758, 3], [129759, 2], [[129760, 129767], 2], [129768, 2], [129769, 2], [129770, 2], [129771, 2], [[129772, 129774], 3], [129775, 2], [[129776, 129782], 2], [[129783, 129784], 2], [[129785, 129786], 2], [[129787, 129791], 3], [[129792, 129938], 2], [129939, 3], [[129940, 129994], 2], [[129995, 130031], 2], [130032, 1, "0"], [130033, 1, "1"], [130034, 1, "2"], [130035, 1, "3"], [130036, 1, "4"], [130037, 1, "5"], [130038, 1, "6"], [130039, 1, "7"], [130040, 1, "8"], [130041, 1, "9"], [130042, 2], [[130043, 131069], 3], [[131070, 131071], 3], [[131072, 173782], 2], [[173783, 173789], 2], [[173790, 173791], 2], [[173792, 173823], 3], [[173824, 177972], 2], [[177973, 177976], 2], [177977, 2], [[177978, 177983], 2], [[177984, 178205], 2], [178206, 2], [178207, 3], [[178208, 183969], 2], [[183970, 183981], 2], [[183982, 183983], 3], [[183984, 191456], 2], [[191457, 191471], 3], [[191472, 192093], 2], [[192094, 194559], 3], [194560, 1, "\u4E3D"], [194561, 1, "\u4E38"], [194562, 1, "\u4E41"], [194563, 1, "\u{20122}"], [194564, 1, "\u4F60"], [194565, 1, "\u4FAE"], [194566, 1, "\u4FBB"], [194567, 1, "\u5002"], [194568, 1, "\u507A"], [194569, 1, "\u5099"], [194570, 1, "\u50E7"], [194571, 1, "\u50CF"], [194572, 1, "\u349E"], [194573, 1, "\u{2063A}"], [194574, 1, "\u514D"], [194575, 1, "\u5154"], [194576, 1, "\u5164"], [194577, 1, "\u5177"], [194578, 1, "\u{2051C}"], [194579, 1, "\u34B9"], [194580, 1, "\u5167"], [194581, 1, "\u518D"], [194582, 1, "\u{2054B}"], [194583, 1, "\u5197"], [194584, 1, "\u51A4"], [194585, 1, "\u4ECC"], [194586, 1, "\u51AC"], [194587, 1, "\u51B5"], [194588, 1, "\u{291DF}"], [194589, 1, "\u51F5"], [194590, 1, "\u5203"], [194591, 1, "\u34DF"], [194592, 1, "\u523B"], [194593, 1, "\u5246"], [194594, 1, "\u5272"], [194595, 1, "\u5277"], [194596, 1, "\u3515"], [194597, 1, "\u52C7"], [194598, 1, "\u52C9"], [194599, 1, "\u52E4"], [194600, 1, "\u52FA"], [194601, 1, "\u5305"], [194602, 1, "\u5306"], [194603, 1, "\u5317"], [194604, 1, "\u5349"], [194605, 1, "\u5351"], [194606, 1, "\u535A"], [194607, 1, "\u5373"], [194608, 1, "\u537D"], [[194609, 194611], 1, "\u537F"], [194612, 1, "\u{20A2C}"], [194613, 1, "\u7070"], [194614, 1, "\u53CA"], [194615, 1, "\u53DF"], [194616, 1, "\u{20B63}"], [194617, 1, "\u53EB"], [194618, 1, "\u53F1"], [194619, 1, "\u5406"], [194620, 1, "\u549E"], [194621, 1, "\u5438"], [194622, 1, "\u5448"], [194623, 1, "\u5468"], [194624, 1, "\u54A2"], [194625, 1, "\u54F6"], [194626, 1, "\u5510"], [194627, 1, "\u5553"], [194628, 1, "\u5563"], [[194629, 194630], 1, "\u5584"], [194631, 1, "\u5599"], [194632, 1, "\u55AB"], [194633, 1, "\u55B3"], [194634, 1, "\u55C2"], [194635, 1, "\u5716"], [194636, 1, "\u5606"], [194637, 1, "\u5717"], [194638, 1, "\u5651"], [194639, 1, "\u5674"], [194640, 1, "\u5207"], [194641, 1, "\u58EE"], [194642, 1, "\u57CE"], [194643, 1, "\u57F4"], [194644, 1, "\u580D"], [194645, 1, "\u578B"], [194646, 1, "\u5832"], [194647, 1, "\u5831"], [194648, 1, "\u58AC"], [194649, 1, "\u{214E4}"], [194650, 1, "\u58F2"], [194651, 1, "\u58F7"], [194652, 1, "\u5906"], [194653, 1, "\u591A"], [194654, 1, "\u5922"], [194655, 1, "\u5962"], [194656, 1, "\u{216A8}"], [194657, 1, "\u{216EA}"], [194658, 1, "\u59EC"], [194659, 1, "\u5A1B"], [194660, 1, "\u5A27"], [194661, 1, "\u59D8"], [194662, 1, "\u5A66"], [194663, 1, "\u36EE"], [194664, 1, "\u36FC"], [194665, 1, "\u5B08"], [[194666, 194667], 1, "\u5B3E"], [194668, 1, "\u{219C8}"], [194669, 1, "\u5BC3"], [194670, 1, "\u5BD8"], [194671, 1, "\u5BE7"], [194672, 1, "\u5BF3"], [194673, 1, "\u{21B18}"], [194674, 1, "\u5BFF"], [194675, 1, "\u5C06"], [194676, 1, "\u5F53"], [194677, 1, "\u5C22"], [194678, 1, "\u3781"], [194679, 1, "\u5C60"], [194680, 1, "\u5C6E"], [194681, 1, "\u5CC0"], [194682, 1, "\u5C8D"], [194683, 1, "\u{21DE4}"], [194684, 1, "\u5D43"], [194685, 1, "\u{21DE6}"], [194686, 1, "\u5D6E"], [194687, 1, "\u5D6B"], [194688, 1, "\u5D7C"], [194689, 1, "\u5DE1"], [194690, 1, "\u5DE2"], [194691, 1, "\u382F"], [194692, 1, "\u5DFD"], [194693, 1, "\u5E28"], [194694, 1, "\u5E3D"], [194695, 1, "\u5E69"], [194696, 1, "\u3862"], [194697, 1, "\u{22183}"], [194698, 1, "\u387C"], [194699, 1, "\u5EB0"], [194700, 1, "\u5EB3"], [194701, 1, "\u5EB6"], [194702, 1, "\u5ECA"], [194703, 1, "\u{2A392}"], [194704, 1, "\u5EFE"], [[194705, 194706], 1, "\u{22331}"], [194707, 1, "\u8201"], [[194708, 194709], 1, "\u5F22"], [194710, 1, "\u38C7"], [194711, 1, "\u{232B8}"], [194712, 1, "\u{261DA}"], [194713, 1, "\u5F62"], [194714, 1, "\u5F6B"], [194715, 1, "\u38E3"], [194716, 1, "\u5F9A"], [194717, 1, "\u5FCD"], [194718, 1, "\u5FD7"], [194719, 1, "\u5FF9"], [194720, 1, "\u6081"], [194721, 1, "\u393A"], [194722, 1, "\u391C"], [194723, 1, "\u6094"], [194724, 1, "\u{226D4}"], [194725, 1, "\u60C7"], [194726, 1, "\u6148"], [194727, 1, "\u614C"], [194728, 1, "\u614E"], [194729, 1, "\u614C"], [194730, 1, "\u617A"], [194731, 1, "\u618E"], [194732, 1, "\u61B2"], [194733, 1, "\u61A4"], [194734, 1, "\u61AF"], [194735, 1, "\u61DE"], [194736, 1, "\u61F2"], [194737, 1, "\u61F6"], [194738, 1, "\u6210"], [194739, 1, "\u621B"], [194740, 1, "\u625D"], [194741, 1, "\u62B1"], [194742, 1, "\u62D4"], [194743, 1, "\u6350"], [194744, 1, "\u{22B0C}"], [194745, 1, "\u633D"], [194746, 1, "\u62FC"], [194747, 1, "\u6368"], [194748, 1, "\u6383"], [194749, 1, "\u63E4"], [194750, 1, "\u{22BF1}"], [194751, 1, "\u6422"], [194752, 1, "\u63C5"], [194753, 1, "\u63A9"], [194754, 1, "\u3A2E"], [194755, 1, "\u6469"], [194756, 1, "\u647E"], [194757, 1, "\u649D"], [194758, 1, "\u6477"], [194759, 1, "\u3A6C"], [194760, 1, "\u654F"], [194761, 1, "\u656C"], [194762, 1, "\u{2300A}"], [194763, 1, "\u65E3"], [194764, 1, "\u66F8"], [194765, 1, "\u6649"], [194766, 1, "\u3B19"], [194767, 1, "\u6691"], [194768, 1, "\u3B08"], [194769, 1, "\u3AE4"], [194770, 1, "\u5192"], [194771, 1, "\u5195"], [194772, 1, "\u6700"], [194773, 1, "\u669C"], [194774, 1, "\u80AD"], [194775, 1, "\u43D9"], [194776, 1, "\u6717"], [194777, 1, "\u671B"], [194778, 1, "\u6721"], [194779, 1, "\u675E"], [194780, 1, "\u6753"], [194781, 1, "\u{233C3}"], [194782, 1, "\u3B49"], [194783, 1, "\u67FA"], [194784, 1, "\u6785"], [194785, 1, "\u6852"], [194786, 1, "\u6885"], [194787, 1, "\u{2346D}"], [194788, 1, "\u688E"], [194789, 1, "\u681F"], [194790, 1, "\u6914"], [194791, 1, "\u3B9D"], [194792, 1, "\u6942"], [194793, 1, "\u69A3"], [194794, 1, "\u69EA"], [194795, 1, "\u6AA8"], [194796, 1, "\u{236A3}"], [194797, 1, "\u6ADB"], [194798, 1, "\u3C18"], [194799, 1, "\u6B21"], [194800, 1, "\u{238A7}"], [194801, 1, "\u6B54"], [194802, 1, "\u3C4E"], [194803, 1, "\u6B72"], [194804, 1, "\u6B9F"], [194805, 1, "\u6BBA"], [194806, 1, "\u6BBB"], [194807, 1, "\u{23A8D}"], [194808, 1, "\u{21D0B}"], [194809, 1, "\u{23AFA}"], [194810, 1, "\u6C4E"], [194811, 1, "\u{23CBC}"], [194812, 1, "\u6CBF"], [194813, 1, "\u6CCD"], [194814, 1, "\u6C67"], [194815, 1, "\u6D16"], [194816, 1, "\u6D3E"], [194817, 1, "\u6D77"], [194818, 1, "\u6D41"], [194819, 1, "\u6D69"], [194820, 1, "\u6D78"], [194821, 1, "\u6D85"], [194822, 1, "\u{23D1E}"], [194823, 1, "\u6D34"], [194824, 1, "\u6E2F"], [194825, 1, "\u6E6E"], [194826, 1, "\u3D33"], [194827, 1, "\u6ECB"], [194828, 1, "\u6EC7"], [194829, 1, "\u{23ED1}"], [194830, 1, "\u6DF9"], [194831, 1, "\u6F6E"], [194832, 1, "\u{23F5E}"], [194833, 1, "\u{23F8E}"], [194834, 1, "\u6FC6"], [194835, 1, "\u7039"], [194836, 1, "\u701E"], [194837, 1, "\u701B"], [194838, 1, "\u3D96"], [194839, 1, "\u704A"], [194840, 1, "\u707D"], [194841, 1, "\u7077"], [194842, 1, "\u70AD"], [194843, 1, "\u{20525}"], [194844, 1, "\u7145"], [194845, 1, "\u{24263}"], [194846, 1, "\u719C"], [194847, 1, "\u{243AB}"], [194848, 1, "\u7228"], [194849, 1, "\u7235"], [194850, 1, "\u7250"], [194851, 1, "\u{24608}"], [194852, 1, "\u7280"], [194853, 1, "\u7295"], [194854, 1, "\u{24735}"], [194855, 1, "\u{24814}"], [194856, 1, "\u737A"], [194857, 1, "\u738B"], [194858, 1, "\u3EAC"], [194859, 1, "\u73A5"], [[194860, 194861], 1, "\u3EB8"], [194862, 1, "\u7447"], [194863, 1, "\u745C"], [194864, 1, "\u7471"], [194865, 1, "\u7485"], [194866, 1, "\u74CA"], [194867, 1, "\u3F1B"], [194868, 1, "\u7524"], [194869, 1, "\u{24C36}"], [194870, 1, "\u753E"], [194871, 1, "\u{24C92}"], [194872, 1, "\u7570"], [194873, 1, "\u{2219F}"], [194874, 1, "\u7610"], [194875, 1, "\u{24FA1}"], [194876, 1, "\u{24FB8}"], [194877, 1, "\u{25044}"], [194878, 1, "\u3FFC"], [194879, 1, "\u4008"], [194880, 1, "\u76F4"], [194881, 1, "\u{250F3}"], [194882, 1, "\u{250F2}"], [194883, 1, "\u{25119}"], [194884, 1, "\u{25133}"], [194885, 1, "\u771E"], [[194886, 194887], 1, "\u771F"], [194888, 1, "\u774A"], [194889, 1, "\u4039"], [194890, 1, "\u778B"], [194891, 1, "\u4046"], [194892, 1, "\u4096"], [194893, 1, "\u{2541D}"], [194894, 1, "\u784E"], [194895, 1, "\u788C"], [194896, 1, "\u78CC"], [194897, 1, "\u40E3"], [194898, 1, "\u{25626}"], [194899, 1, "\u7956"], [194900, 1, "\u{2569A}"], [194901, 1, "\u{256C5}"], [194902, 1, "\u798F"], [194903, 1, "\u79EB"], [194904, 1, "\u412F"], [194905, 1, "\u7A40"], [194906, 1, "\u7A4A"], [194907, 1, "\u7A4F"], [194908, 1, "\u{2597C}"], [[194909, 194910], 1, "\u{25AA7}"], [194911, 1, "\u7AEE"], [194912, 1, "\u4202"], [194913, 1, "\u{25BAB}"], [194914, 1, "\u7BC6"], [194915, 1, "\u7BC9"], [194916, 1, "\u4227"], [194917, 1, "\u{25C80}"], [194918, 1, "\u7CD2"], [194919, 1, "\u42A0"], [194920, 1, "\u7CE8"], [194921, 1, "\u7CE3"], [194922, 1, "\u7D00"], [194923, 1, "\u{25F86}"], [194924, 1, "\u7D63"], [194925, 1, "\u4301"], [194926, 1, "\u7DC7"], [194927, 1, "\u7E02"], [194928, 1, "\u7E45"], [194929, 1, "\u4334"], [194930, 1, "\u{26228}"], [194931, 1, "\u{26247}"], [194932, 1, "\u4359"], [194933, 1, "\u{262D9}"], [194934, 1, "\u7F7A"], [194935, 1, "\u{2633E}"], [194936, 1, "\u7F95"], [194937, 1, "\u7FFA"], [194938, 1, "\u8005"], [194939, 1, "\u{264DA}"], [194940, 1, "\u{26523}"], [194941, 1, "\u8060"], [194942, 1, "\u{265A8}"], [194943, 1, "\u8070"], [194944, 1, "\u{2335F}"], [194945, 1, "\u43D5"], [194946, 1, "\u80B2"], [194947, 1, "\u8103"], [194948, 1, "\u440B"], [194949, 1, "\u813E"], [194950, 1, "\u5AB5"], [194951, 1, "\u{267A7}"], [194952, 1, "\u{267B5}"], [194953, 1, "\u{23393}"], [194954, 1, "\u{2339C}"], [194955, 1, "\u8201"], [194956, 1, "\u8204"], [194957, 1, "\u8F9E"], [194958, 1, "\u446B"], [194959, 1, "\u8291"], [194960, 1, "\u828B"], [194961, 1, "\u829D"], [194962, 1, "\u52B3"], [194963, 1, "\u82B1"], [194964, 1, "\u82B3"], [194965, 1, "\u82BD"], [194966, 1, "\u82E6"], [194967, 1, "\u{26B3C}"], [194968, 1, "\u82E5"], [194969, 1, "\u831D"], [194970, 1, "\u8363"], [194971, 1, "\u83AD"], [194972, 1, "\u8323"], [194973, 1, "\u83BD"], [194974, 1, "\u83E7"], [194975, 1, "\u8457"], [194976, 1, "\u8353"], [194977, 1, "\u83CA"], [194978, 1, "\u83CC"], [194979, 1, "\u83DC"], [194980, 1, "\u{26C36}"], [194981, 1, "\u{26D6B}"], [194982, 1, "\u{26CD5}"], [194983, 1, "\u452B"], [194984, 1, "\u84F1"], [194985, 1, "\u84F3"], [194986, 1, "\u8516"], [194987, 1, "\u{273CA}"], [194988, 1, "\u8564"], [194989, 1, "\u{26F2C}"], [194990, 1, "\u455D"], [194991, 1, "\u4561"], [194992, 1, "\u{26FB1}"], [194993, 1, "\u{270D2}"], [194994, 1, "\u456B"], [194995, 1, "\u8650"], [194996, 1, "\u865C"], [194997, 1, "\u8667"], [194998, 1, "\u8669"], [194999, 1, "\u86A9"], [195e3, 1, "\u8688"], [195001, 1, "\u870E"], [195002, 1, "\u86E2"], [195003, 1, "\u8779"], [195004, 1, "\u8728"], [195005, 1, "\u876B"], [195006, 1, "\u8786"], [195007, 1, "\u45D7"], [195008, 1, "\u87E1"], [195009, 1, "\u8801"], [195010, 1, "\u45F9"], [195011, 1, "\u8860"], [195012, 1, "\u8863"], [195013, 1, "\u{27667}"], [195014, 1, "\u88D7"], [195015, 1, "\u88DE"], [195016, 1, "\u4635"], [195017, 1, "\u88FA"], [195018, 1, "\u34BB"], [195019, 1, "\u{278AE}"], [195020, 1, "\u{27966}"], [195021, 1, "\u46BE"], [195022, 1, "\u46C7"], [195023, 1, "\u8AA0"], [195024, 1, "\u8AED"], [195025, 1, "\u8B8A"], [195026, 1, "\u8C55"], [195027, 1, "\u{27CA8}"], [195028, 1, "\u8CAB"], [195029, 1, "\u8CC1"], [195030, 1, "\u8D1B"], [195031, 1, "\u8D77"], [195032, 1, "\u{27F2F}"], [195033, 1, "\u{20804}"], [195034, 1, "\u8DCB"], [195035, 1, "\u8DBC"], [195036, 1, "\u8DF0"], [195037, 1, "\u{208DE}"], [195038, 1, "\u8ED4"], [195039, 1, "\u8F38"], [195040, 1, "\u{285D2}"], [195041, 1, "\u{285ED}"], [195042, 1, "\u9094"], [195043, 1, "\u90F1"], [195044, 1, "\u9111"], [195045, 1, "\u{2872E}"], [195046, 1, "\u911B"], [195047, 1, "\u9238"], [195048, 1, "\u92D7"], [195049, 1, "\u92D8"], [195050, 1, "\u927C"], [195051, 1, "\u93F9"], [195052, 1, "\u9415"], [195053, 1, "\u{28BFA}"], [195054, 1, "\u958B"], [195055, 1, "\u4995"], [195056, 1, "\u95B7"], [195057, 1, "\u{28D77}"], [195058, 1, "\u49E6"], [195059, 1, "\u96C3"], [195060, 1, "\u5DB2"], [195061, 1, "\u9723"], [195062, 1, "\u{29145}"], [195063, 1, "\u{2921A}"], [195064, 1, "\u4A6E"], [195065, 1, "\u4A76"], [195066, 1, "\u97E0"], [195067, 1, "\u{2940A}"], [195068, 1, "\u4AB2"], [195069, 1, "\u{29496}"], [[195070, 195071], 1, "\u980B"], [195072, 1, "\u9829"], [195073, 1, "\u{295B6}"], [195074, 1, "\u98E2"], [195075, 1, "\u4B33"], [195076, 1, "\u9929"], [195077, 1, "\u99A7"], [195078, 1, "\u99C2"], [195079, 1, "\u99FE"], [195080, 1, "\u4BCE"], [195081, 1, "\u{29B30}"], [195082, 1, "\u9B12"], [195083, 1, "\u9C40"], [195084, 1, "\u9CFD"], [195085, 1, "\u4CCE"], [195086, 1, "\u4CED"], [195087, 1, "\u9D67"], [195088, 1, "\u{2A0CE}"], [195089, 1, "\u4CF8"], [195090, 1, "\u{2A105}"], [195091, 1, "\u{2A20E}"], [195092, 1, "\u{2A291}"], [195093, 1, "\u9EBB"], [195094, 1, "\u4D56"], [195095, 1, "\u9EF9"], [195096, 1, "\u9EFE"], [195097, 1, "\u9F05"], [195098, 1, "\u9F0F"], [195099, 1, "\u9F16"], [195100, 1, "\u9F3B"], [195101, 1, "\u{2A600}"], [[195102, 196605], 3], [[196606, 196607], 3], [[196608, 201546], 2], [[201547, 201551], 3], [[201552, 205743], 2], [[205744, 210041], 2], [[210042, 249855], 3], [[249856, 261183], 2], [[261184, 262141], 3], [[262142, 262143], 3], [[262144, 327677], 3], [[327678, 327679], 3], [[327680, 393213], 3], [[393214, 393215], 3], [[393216, 458749], 3], [[458750, 458751], 3], [[458752, 524285], 3], [[524286, 524287], 3], [[524288, 589821], 3], [[589822, 589823], 3], [[589824, 655357], 3], [[655358, 655359], 3], [[655360, 720893], 3], [[720894, 720895], 3], [[720896, 786429], 3], [[786430, 786431], 3], [[786432, 851965], 3], [[851966, 851967], 3], [[851968, 917501], 3], [[917502, 917503], 3], [917504, 3], [917505, 3], [[917506, 917535], 3], [[917536, 917631], 3], [[917632, 917759], 3], [[917760, 917999], 7], [[918e3, 983037], 3], [[983038, 983039], 3], [[983040, 1048573], 3], [[1048574, 1048575], 3], [[1048576, 1114109], 3], [[1114110, 1114111], 3]];
+  }
+});
+
+// scripts/node-portable/node_modules/tr46/lib/statusMapping.js
+var require_statusMapping = __commonJS({
+  "scripts/node-portable/node_modules/tr46/lib/statusMapping.js"(exports2, module2) {
+    "use strict";
+    module2.exports.STATUS_MAPPING = {
+      mapped: 1,
+      valid: 2,
+      disallowed: 3,
+      deviation: 6,
+      ignored: 7
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/tr46/index.js
+var require_tr46 = __commonJS({
+  "scripts/node-portable/node_modules/tr46/index.js"(exports2, module2) {
+    "use strict";
+    var punycode = require_punycode();
+    var regexes = require_regexes();
+    var mappingTable = require_mappingTable();
+    var { STATUS_MAPPING } = require_statusMapping();
+    function containsNonASCII(str) {
+      return /[^\x00-\x7F]/u.test(str);
+    }
+    function findStatus(val) {
+      let start = 0;
+      let end = mappingTable.length - 1;
+      while (start <= end) {
+        const mid = Math.floor((start + end) / 2);
+        const target = mappingTable[mid];
+        const min = Array.isArray(target[0]) ? target[0][0] : target[0];
+        const max = Array.isArray(target[0]) ? target[0][1] : target[0];
+        if (min <= val && max >= val) {
+          return target.slice(1);
+        } else if (min > val) {
+          end = mid - 1;
+        } else {
+          start = mid + 1;
+        }
+      }
+      return null;
+    }
+    function mapChars(domainName, { transitionalProcessing }) {
+      let processed = "";
+      for (const ch of domainName) {
+        const [status, mapping] = findStatus(ch.codePointAt(0));
+        switch (status) {
+          case STATUS_MAPPING.disallowed:
+            processed += ch;
+            break;
+          case STATUS_MAPPING.ignored:
+            break;
+          case STATUS_MAPPING.mapped:
+            if (transitionalProcessing && ch === "\u1E9E") {
+              processed += "ss";
+            } else {
+              processed += mapping;
+            }
+            break;
+          case STATUS_MAPPING.deviation:
+            if (transitionalProcessing) {
+              processed += mapping;
+            } else {
+              processed += ch;
+            }
+            break;
+          case STATUS_MAPPING.valid:
+            processed += ch;
+            break;
+        }
+      }
+      return processed;
+    }
+    function validateLabel(label, {
+      checkHyphens,
+      checkBidi,
+      checkJoiners,
+      transitionalProcessing,
+      useSTD3ASCIIRules,
+      isBidi
+    }) {
+      if (label.length === 0) {
+        return true;
+      }
+      if (label.normalize("NFC") !== label) {
+        return false;
+      }
+      const codePoints = Array.from(label);
+      if (checkHyphens) {
+        if (codePoints[2] === "-" && codePoints[3] === "-" || (label.startsWith("-") || label.endsWith("-"))) {
+          return false;
+        }
+      }
+      if (!checkHyphens) {
+        if (label.startsWith("xn--")) {
+          return false;
+        }
+      }
+      if (label.includes(".")) {
+        return false;
+      }
+      if (regexes.combiningMarks.test(codePoints[0])) {
+        return false;
+      }
+      for (const ch of codePoints) {
+        const codePoint = ch.codePointAt(0);
+        const [status] = findStatus(codePoint);
+        if (transitionalProcessing) {
+          if (status !== STATUS_MAPPING.valid) {
+            return false;
+          }
+        } else if (status !== STATUS_MAPPING.valid && status !== STATUS_MAPPING.deviation) {
+          return false;
+        }
+        if (useSTD3ASCIIRules && codePoint <= 127) {
+          if (!/^(?:[a-z]|[0-9]|-)$/u.test(ch)) {
+            return false;
+          }
+        }
+      }
+      if (checkJoiners) {
+        let last = 0;
+        for (const [i, ch] of codePoints.entries()) {
+          if (ch === "\u200C" || ch === "\u200D") {
+            if (i > 0) {
+              if (regexes.combiningClassVirama.test(codePoints[i - 1])) {
+                continue;
+              }
+              if (ch === "\u200C") {
+                const next = codePoints.indexOf("\u200C", i + 1);
+                const test = next < 0 ? codePoints.slice(last) : codePoints.slice(last, next);
+                if (regexes.validZWNJ.test(test.join(""))) {
+                  last = i + 1;
+                  continue;
+                }
+              }
+            }
+            return false;
+          }
+        }
+      }
+      if (checkBidi && isBidi) {
+        let rtl;
+        if (regexes.bidiS1LTR.test(codePoints[0])) {
+          rtl = false;
+        } else if (regexes.bidiS1RTL.test(codePoints[0])) {
+          rtl = true;
+        } else {
+          return false;
+        }
+        if (rtl) {
+          if (!regexes.bidiS2.test(label) || !regexes.bidiS3.test(label) || regexes.bidiS4EN.test(label) && regexes.bidiS4AN.test(label)) {
+            return false;
+          }
+        } else if (!regexes.bidiS5.test(label) || !regexes.bidiS6.test(label)) {
+          return false;
+        }
+      }
+      return true;
+    }
+    function isBidiDomain(labels) {
+      const domain = labels.map((label) => {
+        if (label.startsWith("xn--")) {
+          try {
+            return punycode.decode(label.substring(4));
+          } catch {
+            return "";
+          }
+        }
+        return label;
+      }).join(".");
+      return regexes.bidiDomain.test(domain);
+    }
+    function processing(domainName, options) {
+      let string = mapChars(domainName, options);
+      string = string.normalize("NFC");
+      const labels = string.split(".");
+      const isBidi = isBidiDomain(labels);
+      let error = false;
+      for (const [i, origLabel] of labels.entries()) {
+        let label = origLabel;
+        let transitionalProcessingForThisLabel = options.transitionalProcessing;
+        if (label.startsWith("xn--")) {
+          if (containsNonASCII(label)) {
+            error = true;
+            continue;
+          }
+          try {
+            label = punycode.decode(label.substring(4));
+          } catch {
+            if (!options.ignoreInvalidPunycode) {
+              error = true;
+              continue;
+            }
+          }
+          labels[i] = label;
+          if (label === "" || !containsNonASCII(label)) {
+            error = true;
+          }
+          transitionalProcessingForThisLabel = false;
+        }
+        if (error) {
+          continue;
+        }
+        const validation = validateLabel(label, {
+          ...options,
+          transitionalProcessing: transitionalProcessingForThisLabel,
+          isBidi
+        });
+        if (!validation) {
+          error = true;
+        }
+      }
+      return {
+        string: labels.join("."),
+        error
+      };
+    }
+    function toASCII(domainName, {
+      checkHyphens = false,
+      checkBidi = false,
+      checkJoiners = false,
+      useSTD3ASCIIRules = false,
+      verifyDNSLength = false,
+      transitionalProcessing = false,
+      ignoreInvalidPunycode = false
+    } = {}) {
+      const result = processing(domainName, {
+        checkHyphens,
+        checkBidi,
+        checkJoiners,
+        useSTD3ASCIIRules,
+        transitionalProcessing,
+        ignoreInvalidPunycode
+      });
+      let labels = result.string.split(".");
+      labels = labels.map((l) => {
+        if (containsNonASCII(l)) {
+          try {
+            return `xn--${punycode.encode(l)}`;
+          } catch {
+            result.error = true;
+          }
+        }
+        return l;
+      });
+      if (verifyDNSLength) {
+        const total = labels.join(".").length;
+        if (total > 253 || total === 0) {
+          result.error = true;
+        }
+        for (let i = 0; i < labels.length; ++i) {
+          if (labels[i].length > 63 || labels[i].length === 0) {
+            result.error = true;
+            break;
+          }
+        }
+      }
+      if (result.error) {
+        return null;
+      }
+      return labels.join(".");
+    }
+    function toUnicode(domainName, {
+      checkHyphens = false,
+      checkBidi = false,
+      checkJoiners = false,
+      useSTD3ASCIIRules = false,
+      transitionalProcessing = false,
+      ignoreInvalidPunycode = false
+    } = {}) {
+      const result = processing(domainName, {
+        checkHyphens,
+        checkBidi,
+        checkJoiners,
+        useSTD3ASCIIRules,
+        transitionalProcessing,
+        ignoreInvalidPunycode
+      });
+      return {
+        domain: result.string,
+        error: result.error
+      };
+    }
+    module2.exports = {
+      toASCII,
+      toUnicode
+    };
+  }
+});
+
+// scripts/node-portable/.entry-tr46.cjs
+module.exports = require_tr46();
diff --git a/src/Node/Lib/portable/util-base.cjs b/src/Node/Lib/portable/util-base.cjs
new file mode 100644
index 00000000..d9508a9f
--- /dev/null
+++ b/src/Node/Lib/portable/util-base.cjs
@@ -0,0 +1,2362 @@
+var __getOwnPropNames = Object.getOwnPropertyNames;
+var __commonJS = (cb, mod) => function __require() {
+  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
+};
+
+// scripts/node-portable/node_modules/has-symbols/shams.js
+var require_shams = __commonJS({
+  "scripts/node-portable/node_modules/has-symbols/shams.js"(exports2, module2) {
+    "use strict";
+    module2.exports = function hasSymbols() {
+      if (typeof Symbol !== "function" || typeof Object.getOwnPropertySymbols !== "function") {
+        return false;
+      }
+      if (typeof Symbol.iterator === "symbol") {
+        return true;
+      }
+      var obj = {};
+      var sym = Symbol("test");
+      var symObj = Object(sym);
+      if (typeof sym === "string") {
+        return false;
+      }
+      if (Object.prototype.toString.call(sym) !== "[object Symbol]") {
+        return false;
+      }
+      if (Object.prototype.toString.call(symObj) !== "[object Symbol]") {
+        return false;
+      }
+      var symVal = 42;
+      obj[sym] = symVal;
+      for (var _ in obj) {
+        return false;
+      }
+      if (typeof Object.keys === "function" && Object.keys(obj).length !== 0) {
+        return false;
+      }
+      if (typeof Object.getOwnPropertyNames === "function" && Object.getOwnPropertyNames(obj).length !== 0) {
+        return false;
+      }
+      var syms = Object.getOwnPropertySymbols(obj);
+      if (syms.length !== 1 || syms[0] !== sym) {
+        return false;
+      }
+      if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) {
+        return false;
+      }
+      if (typeof Object.getOwnPropertyDescriptor === "function") {
+        var descriptor = (
+          /** @type {PropertyDescriptor} */
+          Object.getOwnPropertyDescriptor(obj, sym)
+        );
+        if (descriptor.value !== symVal || descriptor.enumerable !== true) {
+          return false;
+        }
+      }
+      return true;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/has-tostringtag/shams.js
+var require_shams2 = __commonJS({
+  "scripts/node-portable/node_modules/has-tostringtag/shams.js"(exports2, module2) {
+    "use strict";
+    var hasSymbols = require_shams();
+    module2.exports = function hasToStringTagShams() {
+      return hasSymbols() && !!Symbol.toStringTag;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/es-object-atoms/index.js
+var require_es_object_atoms = __commonJS({
+  "scripts/node-portable/node_modules/es-object-atoms/index.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Object;
+  }
+});
+
+// scripts/node-portable/node_modules/es-errors/index.js
+var require_es_errors = __commonJS({
+  "scripts/node-portable/node_modules/es-errors/index.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Error;
+  }
+});
+
+// scripts/node-portable/node_modules/es-errors/eval.js
+var require_eval = __commonJS({
+  "scripts/node-portable/node_modules/es-errors/eval.js"(exports2, module2) {
+    "use strict";
+    module2.exports = EvalError;
+  }
+});
+
+// scripts/node-portable/node_modules/es-errors/range.js
+var require_range = __commonJS({
+  "scripts/node-portable/node_modules/es-errors/range.js"(exports2, module2) {
+    "use strict";
+    module2.exports = RangeError;
+  }
+});
+
+// scripts/node-portable/node_modules/es-errors/ref.js
+var require_ref = __commonJS({
+  "scripts/node-portable/node_modules/es-errors/ref.js"(exports2, module2) {
+    "use strict";
+    module2.exports = ReferenceError;
+  }
+});
+
+// scripts/node-portable/node_modules/es-errors/syntax.js
+var require_syntax = __commonJS({
+  "scripts/node-portable/node_modules/es-errors/syntax.js"(exports2, module2) {
+    "use strict";
+    module2.exports = SyntaxError;
+  }
+});
+
+// scripts/node-portable/node_modules/es-errors/type.js
+var require_type = __commonJS({
+  "scripts/node-portable/node_modules/es-errors/type.js"(exports2, module2) {
+    "use strict";
+    module2.exports = TypeError;
+  }
+});
+
+// scripts/node-portable/node_modules/es-errors/uri.js
+var require_uri = __commonJS({
+  "scripts/node-portable/node_modules/es-errors/uri.js"(exports2, module2) {
+    "use strict";
+    module2.exports = URIError;
+  }
+});
+
+// scripts/node-portable/node_modules/math-intrinsics/abs.js
+var require_abs = __commonJS({
+  "scripts/node-portable/node_modules/math-intrinsics/abs.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Math.abs;
+  }
+});
+
+// scripts/node-portable/node_modules/math-intrinsics/floor.js
+var require_floor = __commonJS({
+  "scripts/node-portable/node_modules/math-intrinsics/floor.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Math.floor;
+  }
+});
+
+// scripts/node-portable/node_modules/math-intrinsics/max.js
+var require_max = __commonJS({
+  "scripts/node-portable/node_modules/math-intrinsics/max.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Math.max;
+  }
+});
+
+// scripts/node-portable/node_modules/math-intrinsics/min.js
+var require_min = __commonJS({
+  "scripts/node-portable/node_modules/math-intrinsics/min.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Math.min;
+  }
+});
+
+// scripts/node-portable/node_modules/math-intrinsics/pow.js
+var require_pow = __commonJS({
+  "scripts/node-portable/node_modules/math-intrinsics/pow.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Math.pow;
+  }
+});
+
+// scripts/node-portable/node_modules/math-intrinsics/round.js
+var require_round = __commonJS({
+  "scripts/node-portable/node_modules/math-intrinsics/round.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Math.round;
+  }
+});
+
+// scripts/node-portable/node_modules/math-intrinsics/isNaN.js
+var require_isNaN = __commonJS({
+  "scripts/node-portable/node_modules/math-intrinsics/isNaN.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Number.isNaN || function isNaN2(a) {
+      return a !== a;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/math-intrinsics/sign.js
+var require_sign = __commonJS({
+  "scripts/node-portable/node_modules/math-intrinsics/sign.js"(exports2, module2) {
+    "use strict";
+    var $isNaN = require_isNaN();
+    module2.exports = function sign(number) {
+      if ($isNaN(number) || number === 0) {
+        return number;
+      }
+      return number < 0 ? -1 : 1;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/gopd/gOPD.js
+var require_gOPD = __commonJS({
+  "scripts/node-portable/node_modules/gopd/gOPD.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Object.getOwnPropertyDescriptor;
+  }
+});
+
+// scripts/node-portable/node_modules/gopd/index.js
+var require_gopd = __commonJS({
+  "scripts/node-portable/node_modules/gopd/index.js"(exports2, module2) {
+    "use strict";
+    var $gOPD = require_gOPD();
+    if ($gOPD) {
+      try {
+        $gOPD([], "length");
+      } catch (e) {
+        $gOPD = null;
+      }
+    }
+    module2.exports = $gOPD;
+  }
+});
+
+// scripts/node-portable/node_modules/es-define-property/index.js
+var require_es_define_property = __commonJS({
+  "scripts/node-portable/node_modules/es-define-property/index.js"(exports2, module2) {
+    "use strict";
+    var $defineProperty = Object.defineProperty || false;
+    if ($defineProperty) {
+      try {
+        $defineProperty({}, "a", { value: 1 });
+      } catch (e) {
+        $defineProperty = false;
+      }
+    }
+    module2.exports = $defineProperty;
+  }
+});
+
+// scripts/node-portable/node_modules/has-symbols/index.js
+var require_has_symbols = __commonJS({
+  "scripts/node-portable/node_modules/has-symbols/index.js"(exports2, module2) {
+    "use strict";
+    var origSymbol = typeof Symbol !== "undefined" && Symbol;
+    var hasSymbolSham = require_shams();
+    module2.exports = function hasNativeSymbols() {
+      if (typeof origSymbol !== "function") {
+        return false;
+      }
+      if (typeof Symbol !== "function") {
+        return false;
+      }
+      if (typeof origSymbol("foo") !== "symbol") {
+        return false;
+      }
+      if (typeof Symbol("bar") !== "symbol") {
+        return false;
+      }
+      return hasSymbolSham();
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/get-proto/Reflect.getPrototypeOf.js
+var require_Reflect_getPrototypeOf = __commonJS({
+  "scripts/node-portable/node_modules/get-proto/Reflect.getPrototypeOf.js"(exports2, module2) {
+    "use strict";
+    module2.exports = typeof Reflect !== "undefined" && Reflect.getPrototypeOf || null;
+  }
+});
+
+// scripts/node-portable/node_modules/get-proto/Object.getPrototypeOf.js
+var require_Object_getPrototypeOf = __commonJS({
+  "scripts/node-portable/node_modules/get-proto/Object.getPrototypeOf.js"(exports2, module2) {
+    "use strict";
+    var $Object = require_es_object_atoms();
+    module2.exports = $Object.getPrototypeOf || null;
+  }
+});
+
+// scripts/node-portable/node_modules/function-bind/implementation.js
+var require_implementation = __commonJS({
+  "scripts/node-portable/node_modules/function-bind/implementation.js"(exports2, module2) {
+    "use strict";
+    var ERROR_MESSAGE = "Function.prototype.bind called on incompatible ";
+    var toStr = Object.prototype.toString;
+    var max = Math.max;
+    var funcType = "[object Function]";
+    var concatty = function concatty2(a, b) {
+      var arr = [];
+      for (var i = 0; i < a.length; i += 1) {
+        arr[i] = a[i];
+      }
+      for (var j = 0; j < b.length; j += 1) {
+        arr[j + a.length] = b[j];
+      }
+      return arr;
+    };
+    var slicy = function slicy2(arrLike, offset) {
+      var arr = [];
+      for (var i = offset || 0, j = 0; i < arrLike.length; i += 1, j += 1) {
+        arr[j] = arrLike[i];
+      }
+      return arr;
+    };
+    var joiny = function(arr, joiner) {
+      var str = "";
+      for (var i = 0; i < arr.length; i += 1) {
+        str += arr[i];
+        if (i + 1 < arr.length) {
+          str += joiner;
+        }
+      }
+      return str;
+    };
+    module2.exports = function bind(that) {
+      var target = this;
+      if (typeof target !== "function" || toStr.apply(target) !== funcType) {
+        throw new TypeError(ERROR_MESSAGE + target);
+      }
+      var args = slicy(arguments, 1);
+      var bound;
+      var binder = function() {
+        if (this instanceof bound) {
+          var result = target.apply(
+            this,
+            concatty(args, arguments)
+          );
+          if (Object(result) === result) {
+            return result;
+          }
+          return this;
+        }
+        return target.apply(
+          that,
+          concatty(args, arguments)
+        );
+      };
+      var boundLength = max(0, target.length - args.length);
+      var boundArgs = [];
+      for (var i = 0; i < boundLength; i++) {
+        boundArgs[i] = "$" + i;
+      }
+      bound = Function("binder", "return function (" + joiny(boundArgs, ",") + "){ return binder.apply(this,arguments); }")(binder);
+      if (target.prototype) {
+        var Empty = function Empty2() {
+        };
+        Empty.prototype = target.prototype;
+        bound.prototype = new Empty();
+        Empty.prototype = null;
+      }
+      return bound;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/function-bind/index.js
+var require_function_bind = __commonJS({
+  "scripts/node-portable/node_modules/function-bind/index.js"(exports2, module2) {
+    "use strict";
+    var implementation = require_implementation();
+    module2.exports = Function.prototype.bind || implementation;
+  }
+});
+
+// scripts/node-portable/node_modules/call-bind-apply-helpers/functionCall.js
+var require_functionCall = __commonJS({
+  "scripts/node-portable/node_modules/call-bind-apply-helpers/functionCall.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Function.prototype.call;
+  }
+});
+
+// scripts/node-portable/node_modules/call-bind-apply-helpers/functionApply.js
+var require_functionApply = __commonJS({
+  "scripts/node-portable/node_modules/call-bind-apply-helpers/functionApply.js"(exports2, module2) {
+    "use strict";
+    module2.exports = Function.prototype.apply;
+  }
+});
+
+// scripts/node-portable/node_modules/call-bind-apply-helpers/reflectApply.js
+var require_reflectApply = __commonJS({
+  "scripts/node-portable/node_modules/call-bind-apply-helpers/reflectApply.js"(exports2, module2) {
+    "use strict";
+    module2.exports = typeof Reflect !== "undefined" && Reflect && Reflect.apply;
+  }
+});
+
+// scripts/node-portable/node_modules/call-bind-apply-helpers/actualApply.js
+var require_actualApply = __commonJS({
+  "scripts/node-portable/node_modules/call-bind-apply-helpers/actualApply.js"(exports2, module2) {
+    "use strict";
+    var bind = require_function_bind();
+    var $apply = require_functionApply();
+    var $call = require_functionCall();
+    var $reflectApply = require_reflectApply();
+    module2.exports = $reflectApply || bind.call($call, $apply);
+  }
+});
+
+// scripts/node-portable/node_modules/call-bind-apply-helpers/index.js
+var require_call_bind_apply_helpers = __commonJS({
+  "scripts/node-portable/node_modules/call-bind-apply-helpers/index.js"(exports2, module2) {
+    "use strict";
+    var bind = require_function_bind();
+    var $TypeError = require_type();
+    var $call = require_functionCall();
+    var $actualApply = require_actualApply();
+    module2.exports = function callBindBasic(args) {
+      if (args.length < 1 || typeof args[0] !== "function") {
+        throw new $TypeError("a function is required");
+      }
+      return $actualApply(bind, $call, args);
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/dunder-proto/get.js
+var require_get = __commonJS({
+  "scripts/node-portable/node_modules/dunder-proto/get.js"(exports2, module2) {
+    "use strict";
+    var callBind = require_call_bind_apply_helpers();
+    var gOPD = require_gopd();
+    var hasProtoAccessor;
+    try {
+      hasProtoAccessor = /** @type {{ __proto__?: typeof Array.prototype }} */
+      [].__proto__ === Array.prototype;
+    } catch (e) {
+      if (!e || typeof e !== "object" || !("code" in e) || e.code !== "ERR_PROTO_ACCESS") {
+        throw e;
+      }
+    }
+    var desc = !!hasProtoAccessor && gOPD && gOPD(
+      Object.prototype,
+      /** @type {keyof typeof Object.prototype} */
+      "__proto__"
+    );
+    var $Object = Object;
+    var $getPrototypeOf = $Object.getPrototypeOf;
+    module2.exports = desc && typeof desc.get === "function" ? callBind([desc.get]) : typeof $getPrototypeOf === "function" ? (
+      /** @type {import('./get')} */
+      function getDunder(value) {
+        return $getPrototypeOf(value == null ? value : $Object(value));
+      }
+    ) : false;
+  }
+});
+
+// scripts/node-portable/node_modules/get-proto/index.js
+var require_get_proto = __commonJS({
+  "scripts/node-portable/node_modules/get-proto/index.js"(exports2, module2) {
+    "use strict";
+    var reflectGetProto = require_Reflect_getPrototypeOf();
+    var originalGetProto = require_Object_getPrototypeOf();
+    var getDunderProto = require_get();
+    module2.exports = reflectGetProto ? function getProto(O) {
+      return reflectGetProto(O);
+    } : originalGetProto ? function getProto(O) {
+      if (!O || typeof O !== "object" && typeof O !== "function") {
+        throw new TypeError("getProto: not an object");
+      }
+      return originalGetProto(O);
+    } : getDunderProto ? function getProto(O) {
+      return getDunderProto(O);
+    } : null;
+  }
+});
+
+// scripts/node-portable/node_modules/hasown/index.js
+var require_hasown = __commonJS({
+  "scripts/node-portable/node_modules/hasown/index.js"(exports2, module2) {
+    "use strict";
+    var call = Function.prototype.call;
+    var $hasOwn = Object.prototype.hasOwnProperty;
+    var bind = require_function_bind();
+    module2.exports = bind.call(call, $hasOwn);
+  }
+});
+
+// scripts/node-portable/node_modules/get-intrinsic/index.js
+var require_get_intrinsic = __commonJS({
+  "scripts/node-portable/node_modules/get-intrinsic/index.js"(exports2, module2) {
+    "use strict";
+    var undefined2;
+    var $Object = require_es_object_atoms();
+    var $Error = require_es_errors();
+    var $EvalError = require_eval();
+    var $RangeError = require_range();
+    var $ReferenceError = require_ref();
+    var $SyntaxError = require_syntax();
+    var $TypeError = require_type();
+    var $URIError = require_uri();
+    var abs = require_abs();
+    var floor = require_floor();
+    var max = require_max();
+    var min = require_min();
+    var pow = require_pow();
+    var round = require_round();
+    var sign = require_sign();
+    var $Function = Function;
+    var getEvalledConstructor = function(expressionSyntax) {
+      try {
+        return $Function('"use strict"; return (' + expressionSyntax + ").constructor;")();
+      } catch (e) {
+      }
+    };
+    var $gOPD = require_gopd();
+    var $defineProperty = require_es_define_property();
+    var throwTypeError = function() {
+      throw new $TypeError();
+    };
+    var ThrowTypeError = $gOPD ? (function() {
+      try {
+        arguments.callee;
+        return throwTypeError;
+      } catch (calleeThrows) {
+        try {
+          return $gOPD(arguments, "callee").get;
+        } catch (gOPDthrows) {
+          return throwTypeError;
+        }
+      }
+    })() : throwTypeError;
+    var hasSymbols = require_has_symbols()();
+    var getProto = require_get_proto();
+    var $ObjectGPO = require_Object_getPrototypeOf();
+    var $ReflectGPO = require_Reflect_getPrototypeOf();
+    var $apply = require_functionApply();
+    var $call = require_functionCall();
+    var needsEval = {};
+    var TypedArray = typeof Uint8Array === "undefined" || !getProto ? undefined2 : getProto(Uint8Array);
+    var INTRINSICS = {
+      __proto__: null,
+      "%AggregateError%": typeof AggregateError === "undefined" ? undefined2 : AggregateError,
+      "%Array%": Array,
+      "%ArrayBuffer%": typeof ArrayBuffer === "undefined" ? undefined2 : ArrayBuffer,
+      "%ArrayIteratorPrototype%": hasSymbols && getProto ? getProto([][Symbol.iterator]()) : undefined2,
+      "%AsyncFromSyncIteratorPrototype%": undefined2,
+      "%AsyncFunction%": needsEval,
+      "%AsyncGenerator%": needsEval,
+      "%AsyncGeneratorFunction%": needsEval,
+      "%AsyncIteratorPrototype%": needsEval,
+      "%Atomics%": typeof Atomics === "undefined" ? undefined2 : Atomics,
+      "%BigInt%": typeof BigInt === "undefined" ? undefined2 : BigInt,
+      "%BigInt64Array%": typeof BigInt64Array === "undefined" ? undefined2 : BigInt64Array,
+      "%BigUint64Array%": typeof BigUint64Array === "undefined" ? undefined2 : BigUint64Array,
+      "%Boolean%": Boolean,
+      "%DataView%": typeof DataView === "undefined" ? undefined2 : DataView,
+      "%Date%": Date,
+      "%decodeURI%": decodeURI,
+      "%decodeURIComponent%": decodeURIComponent,
+      "%encodeURI%": encodeURI,
+      "%encodeURIComponent%": encodeURIComponent,
+      "%Error%": $Error,
+      "%eval%": eval,
+      // eslint-disable-line no-eval
+      "%EvalError%": $EvalError,
+      "%Float16Array%": typeof Float16Array === "undefined" ? undefined2 : Float16Array,
+      "%Float32Array%": typeof Float32Array === "undefined" ? undefined2 : Float32Array,
+      "%Float64Array%": typeof Float64Array === "undefined" ? undefined2 : Float64Array,
+      "%FinalizationRegistry%": typeof FinalizationRegistry === "undefined" ? undefined2 : FinalizationRegistry,
+      "%Function%": $Function,
+      "%GeneratorFunction%": needsEval,
+      "%Int8Array%": typeof Int8Array === "undefined" ? undefined2 : Int8Array,
+      "%Int16Array%": typeof Int16Array === "undefined" ? undefined2 : Int16Array,
+      "%Int32Array%": typeof Int32Array === "undefined" ? undefined2 : Int32Array,
+      "%isFinite%": isFinite,
+      "%isNaN%": isNaN,
+      "%IteratorPrototype%": hasSymbols && getProto ? getProto(getProto([][Symbol.iterator]())) : undefined2,
+      "%JSON%": typeof JSON === "object" ? JSON : undefined2,
+      "%Map%": typeof Map === "undefined" ? undefined2 : Map,
+      "%MapIteratorPrototype%": typeof Map === "undefined" || !hasSymbols || !getProto ? undefined2 : getProto((/* @__PURE__ */ new Map())[Symbol.iterator]()),
+      "%Math%": Math,
+      "%Number%": Number,
+      "%Object%": $Object,
+      "%Object.getOwnPropertyDescriptor%": $gOPD,
+      "%parseFloat%": parseFloat,
+      "%parseInt%": parseInt,
+      "%Promise%": typeof Promise === "undefined" ? undefined2 : Promise,
+      "%Proxy%": typeof Proxy === "undefined" ? undefined2 : Proxy,
+      "%RangeError%": $RangeError,
+      "%ReferenceError%": $ReferenceError,
+      "%Reflect%": typeof Reflect === "undefined" ? undefined2 : Reflect,
+      "%RegExp%": RegExp,
+      "%Set%": typeof Set === "undefined" ? undefined2 : Set,
+      "%SetIteratorPrototype%": typeof Set === "undefined" || !hasSymbols || !getProto ? undefined2 : getProto((/* @__PURE__ */ new Set())[Symbol.iterator]()),
+      "%SharedArrayBuffer%": typeof SharedArrayBuffer === "undefined" ? undefined2 : SharedArrayBuffer,
+      "%String%": String,
+      "%StringIteratorPrototype%": hasSymbols && getProto ? getProto(""[Symbol.iterator]()) : undefined2,
+      "%Symbol%": hasSymbols ? Symbol : undefined2,
+      "%SyntaxError%": $SyntaxError,
+      "%ThrowTypeError%": ThrowTypeError,
+      "%TypedArray%": TypedArray,
+      "%TypeError%": $TypeError,
+      "%Uint8Array%": typeof Uint8Array === "undefined" ? undefined2 : Uint8Array,
+      "%Uint8ClampedArray%": typeof Uint8ClampedArray === "undefined" ? undefined2 : Uint8ClampedArray,
+      "%Uint16Array%": typeof Uint16Array === "undefined" ? undefined2 : Uint16Array,
+      "%Uint32Array%": typeof Uint32Array === "undefined" ? undefined2 : Uint32Array,
+      "%URIError%": $URIError,
+      "%WeakMap%": typeof WeakMap === "undefined" ? undefined2 : WeakMap,
+      "%WeakRef%": typeof WeakRef === "undefined" ? undefined2 : WeakRef,
+      "%WeakSet%": typeof WeakSet === "undefined" ? undefined2 : WeakSet,
+      "%Function.prototype.call%": $call,
+      "%Function.prototype.apply%": $apply,
+      "%Object.defineProperty%": $defineProperty,
+      "%Object.getPrototypeOf%": $ObjectGPO,
+      "%Math.abs%": abs,
+      "%Math.floor%": floor,
+      "%Math.max%": max,
+      "%Math.min%": min,
+      "%Math.pow%": pow,
+      "%Math.round%": round,
+      "%Math.sign%": sign,
+      "%Reflect.getPrototypeOf%": $ReflectGPO
+    };
+    if (getProto) {
+      try {
+        null.error;
+      } catch (e) {
+        errorProto = getProto(getProto(e));
+        INTRINSICS["%Error.prototype%"] = errorProto;
+      }
+    }
+    var errorProto;
+    var doEval = function doEval2(name) {
+      var value;
+      if (name === "%AsyncFunction%") {
+        value = getEvalledConstructor("async function () {}");
+      } else if (name === "%GeneratorFunction%") {
+        value = getEvalledConstructor("function* () {}");
+      } else if (name === "%AsyncGeneratorFunction%") {
+        value = getEvalledConstructor("async function* () {}");
+      } else if (name === "%AsyncGenerator%") {
+        var fn = doEval2("%AsyncGeneratorFunction%");
+        if (fn) {
+          value = fn.prototype;
+        }
+      } else if (name === "%AsyncIteratorPrototype%") {
+        var gen = doEval2("%AsyncGenerator%");
+        if (gen && getProto) {
+          value = getProto(gen.prototype);
+        }
+      }
+      INTRINSICS[name] = value;
+      return value;
+    };
+    var LEGACY_ALIASES = {
+      __proto__: null,
+      "%ArrayBufferPrototype%": ["ArrayBuffer", "prototype"],
+      "%ArrayPrototype%": ["Array", "prototype"],
+      "%ArrayProto_entries%": ["Array", "prototype", "entries"],
+      "%ArrayProto_forEach%": ["Array", "prototype", "forEach"],
+      "%ArrayProto_keys%": ["Array", "prototype", "keys"],
+      "%ArrayProto_values%": ["Array", "prototype", "values"],
+      "%AsyncFunctionPrototype%": ["AsyncFunction", "prototype"],
+      "%AsyncGenerator%": ["AsyncGeneratorFunction", "prototype"],
+      "%AsyncGeneratorPrototype%": ["AsyncGeneratorFunction", "prototype", "prototype"],
+      "%BooleanPrototype%": ["Boolean", "prototype"],
+      "%DataViewPrototype%": ["DataView", "prototype"],
+      "%DatePrototype%": ["Date", "prototype"],
+      "%ErrorPrototype%": ["Error", "prototype"],
+      "%EvalErrorPrototype%": ["EvalError", "prototype"],
+      "%Float32ArrayPrototype%": ["Float32Array", "prototype"],
+      "%Float64ArrayPrototype%": ["Float64Array", "prototype"],
+      "%FunctionPrototype%": ["Function", "prototype"],
+      "%Generator%": ["GeneratorFunction", "prototype"],
+      "%GeneratorPrototype%": ["GeneratorFunction", "prototype", "prototype"],
+      "%Int8ArrayPrototype%": ["Int8Array", "prototype"],
+      "%Int16ArrayPrototype%": ["Int16Array", "prototype"],
+      "%Int32ArrayPrototype%": ["Int32Array", "prototype"],
+      "%JSONParse%": ["JSON", "parse"],
+      "%JSONStringify%": ["JSON", "stringify"],
+      "%MapPrototype%": ["Map", "prototype"],
+      "%NumberPrototype%": ["Number", "prototype"],
+      "%ObjectPrototype%": ["Object", "prototype"],
+      "%ObjProto_toString%": ["Object", "prototype", "toString"],
+      "%ObjProto_valueOf%": ["Object", "prototype", "valueOf"],
+      "%PromisePrototype%": ["Promise", "prototype"],
+      "%PromiseProto_then%": ["Promise", "prototype", "then"],
+      "%Promise_all%": ["Promise", "all"],
+      "%Promise_reject%": ["Promise", "reject"],
+      "%Promise_resolve%": ["Promise", "resolve"],
+      "%RangeErrorPrototype%": ["RangeError", "prototype"],
+      "%ReferenceErrorPrototype%": ["ReferenceError", "prototype"],
+      "%RegExpPrototype%": ["RegExp", "prototype"],
+      "%SetPrototype%": ["Set", "prototype"],
+      "%SharedArrayBufferPrototype%": ["SharedArrayBuffer", "prototype"],
+      "%StringPrototype%": ["String", "prototype"],
+      "%SymbolPrototype%": ["Symbol", "prototype"],
+      "%SyntaxErrorPrototype%": ["SyntaxError", "prototype"],
+      "%TypedArrayPrototype%": ["TypedArray", "prototype"],
+      "%TypeErrorPrototype%": ["TypeError", "prototype"],
+      "%Uint8ArrayPrototype%": ["Uint8Array", "prototype"],
+      "%Uint8ClampedArrayPrototype%": ["Uint8ClampedArray", "prototype"],
+      "%Uint16ArrayPrototype%": ["Uint16Array", "prototype"],
+      "%Uint32ArrayPrototype%": ["Uint32Array", "prototype"],
+      "%URIErrorPrototype%": ["URIError", "prototype"],
+      "%WeakMapPrototype%": ["WeakMap", "prototype"],
+      "%WeakSetPrototype%": ["WeakSet", "prototype"]
+    };
+    var bind = require_function_bind();
+    var hasOwn = require_hasown();
+    var $concat = bind.call($call, Array.prototype.concat);
+    var $spliceApply = bind.call($apply, Array.prototype.splice);
+    var $replace = bind.call($call, String.prototype.replace);
+    var $strSlice = bind.call($call, String.prototype.slice);
+    var $exec = bind.call($call, RegExp.prototype.exec);
+    var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g;
+    var reEscapeChar = /\\(\\)?/g;
+    var stringToPath = function stringToPath2(string) {
+      var first = $strSlice(string, 0, 1);
+      var last = $strSlice(string, -1);
+      if (first === "%" && last !== "%") {
+        throw new $SyntaxError("invalid intrinsic syntax, expected closing `%`");
+      } else if (last === "%" && first !== "%") {
+        throw new $SyntaxError("invalid intrinsic syntax, expected opening `%`");
+      }
+      var result = [];
+      $replace(string, rePropName, function(match, number, quote, subString) {
+        result[result.length] = quote ? $replace(subString, reEscapeChar, "$1") : number || match;
+      });
+      return result;
+    };
+    var getBaseIntrinsic = function getBaseIntrinsic2(name, allowMissing) {
+      var intrinsicName = name;
+      var alias;
+      if (hasOwn(LEGACY_ALIASES, intrinsicName)) {
+        alias = LEGACY_ALIASES[intrinsicName];
+        intrinsicName = "%" + alias[0] + "%";
+      }
+      if (hasOwn(INTRINSICS, intrinsicName)) {
+        var value = INTRINSICS[intrinsicName];
+        if (value === needsEval) {
+          value = doEval(intrinsicName);
+        }
+        if (typeof value === "undefined" && !allowMissing) {
+          throw new $TypeError("intrinsic " + name + " exists, but is not available. Please file an issue!");
+        }
+        return {
+          alias,
+          name: intrinsicName,
+          value
+        };
+      }
+      throw new $SyntaxError("intrinsic " + name + " does not exist!");
+    };
+    module2.exports = function GetIntrinsic(name, allowMissing) {
+      if (typeof name !== "string" || name.length === 0) {
+        throw new $TypeError("intrinsic name must be a non-empty string");
+      }
+      if (arguments.length > 1 && typeof allowMissing !== "boolean") {
+        throw new $TypeError('"allowMissing" argument must be a boolean');
+      }
+      if ($exec(/^%?[^%]*%?$/, name) === null) {
+        throw new $SyntaxError("`%` may not be present anywhere but at the beginning and end of the intrinsic name");
+      }
+      var parts = stringToPath(name);
+      var intrinsicBaseName = parts.length > 0 ? parts[0] : "";
+      var intrinsic = getBaseIntrinsic("%" + intrinsicBaseName + "%", allowMissing);
+      var intrinsicRealName = intrinsic.name;
+      var value = intrinsic.value;
+      var skipFurtherCaching = false;
+      var alias = intrinsic.alias;
+      if (alias) {
+        intrinsicBaseName = alias[0];
+        $spliceApply(parts, $concat([0, 1], alias));
+      }
+      for (var i = 1, isOwn = true; i < parts.length; i += 1) {
+        var part = parts[i];
+        var first = $strSlice(part, 0, 1);
+        var last = $strSlice(part, -1);
+        if ((first === '"' || first === "'" || first === "`" || (last === '"' || last === "'" || last === "`")) && first !== last) {
+          throw new $SyntaxError("property names with quotes must have matching quotes");
+        }
+        if (part === "constructor" || !isOwn) {
+          skipFurtherCaching = true;
+        }
+        intrinsicBaseName += "." + part;
+        intrinsicRealName = "%" + intrinsicBaseName + "%";
+        if (hasOwn(INTRINSICS, intrinsicRealName)) {
+          value = INTRINSICS[intrinsicRealName];
+        } else if (value != null) {
+          if (!(part in value)) {
+            if (!allowMissing) {
+              throw new $TypeError("base intrinsic for " + name + " exists, but the property is not available.");
+            }
+            return void undefined2;
+          }
+          if ($gOPD && i + 1 >= parts.length) {
+            var desc = $gOPD(value, part);
+            isOwn = !!desc;
+            if (isOwn && "get" in desc && !("originalValue" in desc.get)) {
+              value = desc.get;
+            } else {
+              value = value[part];
+            }
+          } else {
+            isOwn = hasOwn(value, part);
+            value = value[part];
+          }
+          if (isOwn && !skipFurtherCaching) {
+            INTRINSICS[intrinsicRealName] = value;
+          }
+        }
+      }
+      return value;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/call-bound/index.js
+var require_call_bound = __commonJS({
+  "scripts/node-portable/node_modules/call-bound/index.js"(exports2, module2) {
+    "use strict";
+    var GetIntrinsic = require_get_intrinsic();
+    var callBindBasic = require_call_bind_apply_helpers();
+    var $indexOf = callBindBasic([GetIntrinsic("%String.prototype.indexOf%")]);
+    module2.exports = function callBoundIntrinsic(name, allowMissing) {
+      var intrinsic = (
+        /** @type {(this: unknown, ...args: unknown[]) => unknown} */
+        GetIntrinsic(name, !!allowMissing)
+      );
+      if (typeof intrinsic === "function" && $indexOf(name, ".prototype.") > -1) {
+        return callBindBasic(
+          /** @type {const} */
+          [intrinsic]
+        );
+      }
+      return intrinsic;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/is-arguments/index.js
+var require_is_arguments = __commonJS({
+  "scripts/node-portable/node_modules/is-arguments/index.js"(exports2, module2) {
+    "use strict";
+    var hasToStringTag = require_shams2()();
+    var callBound = require_call_bound();
+    var $toString = callBound("Object.prototype.toString");
+    var isStandardArguments = function isArguments(value) {
+      if (hasToStringTag && value && typeof value === "object" && Symbol.toStringTag in value) {
+        return false;
+      }
+      return $toString(value) === "[object Arguments]";
+    };
+    var isLegacyArguments = function isArguments(value) {
+      if (isStandardArguments(value)) {
+        return true;
+      }
+      return value !== null && typeof value === "object" && "length" in value && typeof value.length === "number" && value.length >= 0 && $toString(value) !== "[object Array]" && "callee" in value && $toString(value.callee) === "[object Function]";
+    };
+    var supportsStandardArguments = (function() {
+      return isStandardArguments(arguments);
+    })();
+    isStandardArguments.isLegacyArguments = isLegacyArguments;
+    module2.exports = supportsStandardArguments ? isStandardArguments : isLegacyArguments;
+  }
+});
+
+// scripts/node-portable/node_modules/is-regex/index.js
+var require_is_regex = __commonJS({
+  "scripts/node-portable/node_modules/is-regex/index.js"(exports2, module2) {
+    "use strict";
+    var callBound = require_call_bound();
+    var hasToStringTag = require_shams2()();
+    var hasOwn = require_hasown();
+    var gOPD = require_gopd();
+    var fn;
+    if (hasToStringTag) {
+      $exec = callBound("RegExp.prototype.exec");
+      isRegexMarker = {};
+      throwRegexMarker = function() {
+        throw isRegexMarker;
+      };
+      badStringifier = {
+        toString: throwRegexMarker,
+        valueOf: throwRegexMarker
+      };
+      if (typeof Symbol.toPrimitive === "symbol") {
+        badStringifier[Symbol.toPrimitive] = throwRegexMarker;
+      }
+      fn = function isRegex(value) {
+        if (!value || typeof value !== "object") {
+          return false;
+        }
+        var descriptor = (
+          /** @type {NonNullable} */
+          gOPD(
+            /** @type {{ lastIndex?: unknown }} */
+            value,
+            "lastIndex"
+          )
+        );
+        var hasLastIndexDataProperty = descriptor && hasOwn(descriptor, "value");
+        if (!hasLastIndexDataProperty) {
+          return false;
+        }
+        try {
+          $exec(
+            value,
+            /** @type {string} */
+            /** @type {unknown} */
+            badStringifier
+          );
+        } catch (e) {
+          return e === isRegexMarker;
+        }
+      };
+    } else {
+      $toString = callBound("Object.prototype.toString");
+      regexClass = "[object RegExp]";
+      fn = function isRegex(value) {
+        if (!value || typeof value !== "object" && typeof value !== "function") {
+          return false;
+        }
+        return $toString(value) === regexClass;
+      };
+    }
+    var $exec;
+    var isRegexMarker;
+    var throwRegexMarker;
+    var badStringifier;
+    var $toString;
+    var regexClass;
+    module2.exports = fn;
+  }
+});
+
+// scripts/node-portable/node_modules/safe-regex-test/index.js
+var require_safe_regex_test = __commonJS({
+  "scripts/node-portable/node_modules/safe-regex-test/index.js"(exports2, module2) {
+    "use strict";
+    var callBound = require_call_bound();
+    var isRegex = require_is_regex();
+    var $exec = callBound("RegExp.prototype.exec");
+    var $TypeError = require_type();
+    module2.exports = function regexTester(regex) {
+      if (!isRegex(regex)) {
+        throw new $TypeError("`regex` must be a RegExp");
+      }
+      return function test(s) {
+        return $exec(regex, s) !== null;
+      };
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/generator-function/index.js
+var require_generator_function = __commonJS({
+  "scripts/node-portable/node_modules/generator-function/index.js"(exports2, module2) {
+    "use strict";
+    var cached = (
+      /** @type {GeneratorFunctionConstructor} */
+      function* () {
+      }.constructor
+    );
+    module2.exports = () => cached;
+  }
+});
+
+// scripts/node-portable/node_modules/is-generator-function/index.js
+var require_is_generator_function = __commonJS({
+  "scripts/node-portable/node_modules/is-generator-function/index.js"(exports2, module2) {
+    "use strict";
+    var callBound = require_call_bound();
+    var safeRegexTest = require_safe_regex_test();
+    var isFnRegex = safeRegexTest(/^\s*(?:function)?\*/);
+    var hasToStringTag = require_shams2()();
+    var getProto = require_get_proto();
+    var toStr = callBound("Object.prototype.toString");
+    var fnToStr = callBound("Function.prototype.toString");
+    var getGeneratorFunction = require_generator_function();
+    module2.exports = function isGeneratorFunction(fn) {
+      if (typeof fn !== "function") {
+        return false;
+      }
+      if (isFnRegex(fnToStr(fn))) {
+        return true;
+      }
+      if (!hasToStringTag) {
+        var str = toStr(fn);
+        return str === "[object GeneratorFunction]";
+      }
+      if (!getProto) {
+        return false;
+      }
+      var GeneratorFunction = getGeneratorFunction();
+      return GeneratorFunction && getProto(fn) === GeneratorFunction.prototype;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/is-callable/index.js
+var require_is_callable = __commonJS({
+  "scripts/node-portable/node_modules/is-callable/index.js"(exports2, module2) {
+    "use strict";
+    var fnToStr = Function.prototype.toString;
+    var reflectApply = typeof Reflect === "object" && Reflect !== null && Reflect.apply;
+    var badArrayLike;
+    var isCallableMarker;
+    if (typeof reflectApply === "function" && typeof Object.defineProperty === "function") {
+      try {
+        badArrayLike = Object.defineProperty({}, "length", {
+          get: function() {
+            throw isCallableMarker;
+          }
+        });
+        isCallableMarker = {};
+        reflectApply(function() {
+          throw 42;
+        }, null, badArrayLike);
+      } catch (_) {
+        if (_ !== isCallableMarker) {
+          reflectApply = null;
+        }
+      }
+    } else {
+      reflectApply = null;
+    }
+    var constructorRegex = /^\s*class\b/;
+    var isES6ClassFn = function isES6ClassFunction(value) {
+      try {
+        var fnStr = fnToStr.call(value);
+        return constructorRegex.test(fnStr);
+      } catch (e) {
+        return false;
+      }
+    };
+    var tryFunctionObject = function tryFunctionToStr(value) {
+      try {
+        if (isES6ClassFn(value)) {
+          return false;
+        }
+        fnToStr.call(value);
+        return true;
+      } catch (e) {
+        return false;
+      }
+    };
+    var toStr = Object.prototype.toString;
+    var objectClass = "[object Object]";
+    var fnClass = "[object Function]";
+    var genClass = "[object GeneratorFunction]";
+    var ddaClass = "[object HTMLAllCollection]";
+    var ddaClass2 = "[object HTML document.all class]";
+    var ddaClass3 = "[object HTMLCollection]";
+    var hasToStringTag = typeof Symbol === "function" && !!Symbol.toStringTag;
+    var isIE68 = !(0 in [,]);
+    var isDDA = function isDocumentDotAll() {
+      return false;
+    };
+    if (typeof document === "object") {
+      all = document.all;
+      if (toStr.call(all) === toStr.call(document.all)) {
+        isDDA = function isDocumentDotAll(value) {
+          if ((isIE68 || !value) && (typeof value === "undefined" || typeof value === "object")) {
+            try {
+              var str = toStr.call(value);
+              return (str === ddaClass || str === ddaClass2 || str === ddaClass3 || str === objectClass) && value("") == null;
+            } catch (e) {
+            }
+          }
+          return false;
+        };
+      }
+    }
+    var all;
+    module2.exports = reflectApply ? function isCallable(value) {
+      if (isDDA(value)) {
+        return true;
+      }
+      if (!value) {
+        return false;
+      }
+      if (typeof value !== "function" && typeof value !== "object") {
+        return false;
+      }
+      try {
+        reflectApply(value, null, badArrayLike);
+      } catch (e) {
+        if (e !== isCallableMarker) {
+          return false;
+        }
+      }
+      return !isES6ClassFn(value) && tryFunctionObject(value);
+    } : function isCallable(value) {
+      if (isDDA(value)) {
+        return true;
+      }
+      if (!value) {
+        return false;
+      }
+      if (typeof value !== "function" && typeof value !== "object") {
+        return false;
+      }
+      if (hasToStringTag) {
+        return tryFunctionObject(value);
+      }
+      if (isES6ClassFn(value)) {
+        return false;
+      }
+      var strClass = toStr.call(value);
+      if (strClass !== fnClass && strClass !== genClass && !/^\[object HTML/.test(strClass)) {
+        return false;
+      }
+      return tryFunctionObject(value);
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/for-each/index.js
+var require_for_each = __commonJS({
+  "scripts/node-portable/node_modules/for-each/index.js"(exports2, module2) {
+    "use strict";
+    var isCallable = require_is_callable();
+    var toStr = Object.prototype.toString;
+    var hasOwnProperty = Object.prototype.hasOwnProperty;
+    var forEachArray = function forEachArray2(array, iterator, receiver) {
+      for (var i = 0, len = array.length; i < len; i++) {
+        if (hasOwnProperty.call(array, i)) {
+          if (receiver == null) {
+            iterator(array[i], i, array);
+          } else {
+            iterator.call(receiver, array[i], i, array);
+          }
+        }
+      }
+    };
+    var forEachString = function forEachString2(string, iterator, receiver) {
+      for (var i = 0, len = string.length; i < len; i++) {
+        if (receiver == null) {
+          iterator(string.charAt(i), i, string);
+        } else {
+          iterator.call(receiver, string.charAt(i), i, string);
+        }
+      }
+    };
+    var forEachObject = function forEachObject2(object, iterator, receiver) {
+      for (var k in object) {
+        if (hasOwnProperty.call(object, k)) {
+          if (receiver == null) {
+            iterator(object[k], k, object);
+          } else {
+            iterator.call(receiver, object[k], k, object);
+          }
+        }
+      }
+    };
+    function isArray(x) {
+      return toStr.call(x) === "[object Array]";
+    }
+    module2.exports = function forEach(list, iterator, thisArg) {
+      if (!isCallable(iterator)) {
+        throw new TypeError("iterator must be a function");
+      }
+      var receiver;
+      if (arguments.length >= 3) {
+        receiver = thisArg;
+      }
+      if (isArray(list)) {
+        forEachArray(list, iterator, receiver);
+      } else if (typeof list === "string") {
+        forEachString(list, iterator, receiver);
+      } else {
+        forEachObject(list, iterator, receiver);
+      }
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/possible-typed-array-names/index.js
+var require_possible_typed_array_names = __commonJS({
+  "scripts/node-portable/node_modules/possible-typed-array-names/index.js"(exports2, module2) {
+    "use strict";
+    module2.exports = [
+      "Float16Array",
+      "Float32Array",
+      "Float64Array",
+      "Int8Array",
+      "Int16Array",
+      "Int32Array",
+      "Uint8Array",
+      "Uint8ClampedArray",
+      "Uint16Array",
+      "Uint32Array",
+      "BigInt64Array",
+      "BigUint64Array"
+    ];
+  }
+});
+
+// scripts/node-portable/node_modules/available-typed-arrays/index.js
+var require_available_typed_arrays = __commonJS({
+  "scripts/node-portable/node_modules/available-typed-arrays/index.js"(exports2, module2) {
+    "use strict";
+    var possibleNames = require_possible_typed_array_names();
+    var g = typeof globalThis === "undefined" ? global : globalThis;
+    module2.exports = function availableTypedArrays() {
+      var out = [];
+      for (var i = 0; i < possibleNames.length; i++) {
+        if (typeof g[possibleNames[i]] === "function") {
+          out[out.length] = possibleNames[i];
+        }
+      }
+      return out;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/define-data-property/index.js
+var require_define_data_property = __commonJS({
+  "scripts/node-portable/node_modules/define-data-property/index.js"(exports2, module2) {
+    "use strict";
+    var $defineProperty = require_es_define_property();
+    var $SyntaxError = require_syntax();
+    var $TypeError = require_type();
+    var gopd = require_gopd();
+    module2.exports = function defineDataProperty(obj, property, value) {
+      if (!obj || typeof obj !== "object" && typeof obj !== "function") {
+        throw new $TypeError("`obj` must be an object or a function`");
+      }
+      if (typeof property !== "string" && typeof property !== "symbol") {
+        throw new $TypeError("`property` must be a string or a symbol`");
+      }
+      if (arguments.length > 3 && typeof arguments[3] !== "boolean" && arguments[3] !== null) {
+        throw new $TypeError("`nonEnumerable`, if provided, must be a boolean or null");
+      }
+      if (arguments.length > 4 && typeof arguments[4] !== "boolean" && arguments[4] !== null) {
+        throw new $TypeError("`nonWritable`, if provided, must be a boolean or null");
+      }
+      if (arguments.length > 5 && typeof arguments[5] !== "boolean" && arguments[5] !== null) {
+        throw new $TypeError("`nonConfigurable`, if provided, must be a boolean or null");
+      }
+      if (arguments.length > 6 && typeof arguments[6] !== "boolean") {
+        throw new $TypeError("`loose`, if provided, must be a boolean");
+      }
+      var nonEnumerable = arguments.length > 3 ? arguments[3] : null;
+      var nonWritable = arguments.length > 4 ? arguments[4] : null;
+      var nonConfigurable = arguments.length > 5 ? arguments[5] : null;
+      var loose = arguments.length > 6 ? arguments[6] : false;
+      var desc = !!gopd && gopd(obj, property);
+      if ($defineProperty) {
+        $defineProperty(obj, property, {
+          configurable: nonConfigurable === null && desc ? desc.configurable : !nonConfigurable,
+          enumerable: nonEnumerable === null && desc ? desc.enumerable : !nonEnumerable,
+          value,
+          writable: nonWritable === null && desc ? desc.writable : !nonWritable
+        });
+      } else if (loose || !nonEnumerable && !nonWritable && !nonConfigurable) {
+        obj[property] = value;
+      } else {
+        throw new $SyntaxError("This environment does not support defining a property as non-configurable, non-writable, or non-enumerable.");
+      }
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/has-property-descriptors/index.js
+var require_has_property_descriptors = __commonJS({
+  "scripts/node-portable/node_modules/has-property-descriptors/index.js"(exports2, module2) {
+    "use strict";
+    var $defineProperty = require_es_define_property();
+    var hasPropertyDescriptors = function hasPropertyDescriptors2() {
+      return !!$defineProperty;
+    };
+    hasPropertyDescriptors.hasArrayLengthDefineBug = function hasArrayLengthDefineBug() {
+      if (!$defineProperty) {
+        return null;
+      }
+      try {
+        return $defineProperty([], "length", { value: 1 }).length !== 1;
+      } catch (e) {
+        return true;
+      }
+    };
+    module2.exports = hasPropertyDescriptors;
+  }
+});
+
+// scripts/node-portable/node_modules/set-function-length/index.js
+var require_set_function_length = __commonJS({
+  "scripts/node-portable/node_modules/set-function-length/index.js"(exports2, module2) {
+    "use strict";
+    var GetIntrinsic = require_get_intrinsic();
+    var define = require_define_data_property();
+    var hasDescriptors = require_has_property_descriptors()();
+    var gOPD = require_gopd();
+    var $TypeError = require_type();
+    var $floor = GetIntrinsic("%Math.floor%");
+    module2.exports = function setFunctionLength(fn, length) {
+      if (typeof fn !== "function") {
+        throw new $TypeError("`fn` is not a function");
+      }
+      if (typeof length !== "number" || length < 0 || length > 4294967295 || $floor(length) !== length) {
+        throw new $TypeError("`length` must be a positive 32-bit integer");
+      }
+      var loose = arguments.length > 2 && !!arguments[2];
+      var functionLengthIsConfigurable = true;
+      var functionLengthIsWritable = true;
+      if ("length" in fn && gOPD) {
+        var desc = gOPD(fn, "length");
+        if (desc && !desc.configurable) {
+          functionLengthIsConfigurable = false;
+        }
+        if (desc && !desc.writable) {
+          functionLengthIsWritable = false;
+        }
+      }
+      if (functionLengthIsConfigurable || functionLengthIsWritable || !loose) {
+        if (hasDescriptors) {
+          define(
+            /** @type {Parameters[0]} */
+            fn,
+            "length",
+            length,
+            true,
+            true
+          );
+        } else {
+          define(
+            /** @type {Parameters[0]} */
+            fn,
+            "length",
+            length
+          );
+        }
+      }
+      return fn;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/call-bind-apply-helpers/applyBind.js
+var require_applyBind = __commonJS({
+  "scripts/node-portable/node_modules/call-bind-apply-helpers/applyBind.js"(exports2, module2) {
+    "use strict";
+    var bind = require_function_bind();
+    var $apply = require_functionApply();
+    var actualApply = require_actualApply();
+    module2.exports = function applyBind() {
+      return actualApply(bind, $apply, arguments);
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/call-bind/index.js
+var require_call_bind = __commonJS({
+  "scripts/node-portable/node_modules/call-bind/index.js"(exports2, module2) {
+    "use strict";
+    var setFunctionLength = require_set_function_length();
+    var $defineProperty = require_es_define_property();
+    var callBindBasic = require_call_bind_apply_helpers();
+    var applyBind = require_applyBind();
+    module2.exports = function callBind(originalFunction) {
+      var func = callBindBasic(arguments);
+      var adjustedLength = 1 + originalFunction.length - (arguments.length - 1);
+      return setFunctionLength(
+        func,
+        adjustedLength > 0 ? adjustedLength : 0,
+        true
+      );
+    };
+    if ($defineProperty) {
+      $defineProperty(module2.exports, "apply", { value: applyBind });
+    } else {
+      module2.exports.apply = applyBind;
+    }
+  }
+});
+
+// scripts/node-portable/node_modules/which-typed-array/index.js
+var require_which_typed_array = __commonJS({
+  "scripts/node-portable/node_modules/which-typed-array/index.js"(exports2, module2) {
+    "use strict";
+    var forEach = require_for_each();
+    var availableTypedArrays = require_available_typed_arrays();
+    var callBind = require_call_bind();
+    var callBound = require_call_bound();
+    var gOPD = require_gopd();
+    var getProto = require_get_proto();
+    var $toString = callBound("Object.prototype.toString");
+    var hasToStringTag = require_shams2()();
+    var g = typeof globalThis === "undefined" ? global : globalThis;
+    var typedArrays = availableTypedArrays();
+    var $slice = callBound("String.prototype.slice");
+    var $indexOf = callBound("Array.prototype.indexOf", true) || function indexOf(array, value) {
+      for (var i = 0; i < array.length; i += 1) {
+        if (array[i] === value) {
+          return i;
+        }
+      }
+      return -1;
+    };
+    var cache = { __proto__: null };
+    if (hasToStringTag && gOPD && getProto) {
+      forEach(typedArrays, function(typedArray) {
+        var arr = new g[typedArray]();
+        if (Symbol.toStringTag in arr && getProto) {
+          var proto = getProto(arr);
+          var descriptor = gOPD(proto, Symbol.toStringTag);
+          if (!descriptor && proto) {
+            var superProto = getProto(proto);
+            descriptor = gOPD(superProto, Symbol.toStringTag);
+          }
+          if (descriptor && descriptor.get) {
+            var bound = callBind(descriptor.get);
+            cache[
+              /** @type {`$${TypedArrayName}`} */
+              "$" + typedArray
+            ] = bound;
+          }
+        }
+      });
+    } else {
+      forEach(typedArrays, function(typedArray) {
+        var arr = new g[typedArray]();
+        var fn = arr.slice || arr.set;
+        if (fn) {
+          var bound = (
+            /** @type {typeof BoundSlice | typeof BoundSet} */
+            // @ts-expect-error TODO FIXME
+            callBind(fn)
+          );
+          cache[
+            /** @type {`$${TypedArrayName}`} */
+            "$" + typedArray
+          ] = bound;
+        }
+      });
+    }
+    function tryTypedArrays(value) {
+      var found = false;
+      forEach(
+        /** @type {Record<`$${TypedArrayName}`, Getter>} */
+        cache,
+        /** @param {Getter} getter @param {`$${TypedArrayName}`} typedArray */
+        function(getter, typedArray) {
+          if (!found) {
+            try {
+              if ("$" + getter(value) === typedArray) {
+                found = /** @type {TypedArrayName} */
+                $slice(typedArray, 1);
+              }
+            } catch (e) {
+            }
+          }
+        }
+      );
+      return found;
+    }
+    function trySlices(value) {
+      var found = false;
+      forEach(
+        /** @type {Record<`$${TypedArrayName}`, Getter>} */
+        cache,
+        /** @param {Getter} getter @param {`$${TypedArrayName}`} name */
+        function(getter, name) {
+          if (!found) {
+            try {
+              getter(value);
+              found = /** @type {TypedArrayName} */
+              $slice(name, 1);
+            } catch (e) {
+            }
+          }
+        }
+      );
+      return found;
+    }
+    function isTATag(tag) {
+      return $indexOf(typedArrays, tag) > -1;
+    }
+    function whichTypedArray(value) {
+      if (!value || typeof value !== "object") {
+        return false;
+      }
+      if (!hasToStringTag) {
+        var tag = $slice($toString(value), 8, -1);
+        if (isTATag(tag)) {
+          return tag;
+        }
+        if (tag !== "Object") {
+          return false;
+        }
+        return trySlices(value);
+      }
+      if (!gOPD) {
+        return null;
+      }
+      return tryTypedArrays(value);
+    }
+    module2.exports = whichTypedArray;
+  }
+});
+
+// scripts/node-portable/node_modules/is-typed-array/index.js
+var require_is_typed_array = __commonJS({
+  "scripts/node-portable/node_modules/is-typed-array/index.js"(exports2, module2) {
+    "use strict";
+    var whichTypedArray = require_which_typed_array();
+    module2.exports = function isTypedArray(value) {
+      return !!whichTypedArray(value);
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/util/support/types.js
+var require_types = __commonJS({
+  "scripts/node-portable/node_modules/util/support/types.js"(exports2) {
+    "use strict";
+    var isArgumentsObject = require_is_arguments();
+    var isGeneratorFunction = require_is_generator_function();
+    var whichTypedArray = require_which_typed_array();
+    var isTypedArray = require_is_typed_array();
+    function uncurryThis(f) {
+      return f.call.bind(f);
+    }
+    var BigIntSupported = typeof BigInt !== "undefined";
+    var SymbolSupported = typeof Symbol !== "undefined";
+    var ObjectToString = uncurryThis(Object.prototype.toString);
+    var numberValue = uncurryThis(Number.prototype.valueOf);
+    var stringValue = uncurryThis(String.prototype.valueOf);
+    var booleanValue = uncurryThis(Boolean.prototype.valueOf);
+    if (BigIntSupported) {
+      bigIntValue = uncurryThis(BigInt.prototype.valueOf);
+    }
+    var bigIntValue;
+    if (SymbolSupported) {
+      symbolValue = uncurryThis(Symbol.prototype.valueOf);
+    }
+    var symbolValue;
+    function checkBoxedPrimitive(value, prototypeValueOf) {
+      if (typeof value !== "object") {
+        return false;
+      }
+      try {
+        prototypeValueOf(value);
+        return true;
+      } catch (e) {
+        return false;
+      }
+    }
+    exports2.isArgumentsObject = isArgumentsObject;
+    exports2.isGeneratorFunction = isGeneratorFunction;
+    exports2.isTypedArray = isTypedArray;
+    function isPromise(input) {
+      return typeof Promise !== "undefined" && input instanceof Promise || input !== null && typeof input === "object" && typeof input.then === "function" && typeof input.catch === "function";
+    }
+    exports2.isPromise = isPromise;
+    function isArrayBufferView(value) {
+      if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView) {
+        return ArrayBuffer.isView(value);
+      }
+      return isTypedArray(value) || isDataView(value);
+    }
+    exports2.isArrayBufferView = isArrayBufferView;
+    function isUint8Array(value) {
+      return whichTypedArray(value) === "Uint8Array";
+    }
+    exports2.isUint8Array = isUint8Array;
+    function isUint8ClampedArray(value) {
+      return whichTypedArray(value) === "Uint8ClampedArray";
+    }
+    exports2.isUint8ClampedArray = isUint8ClampedArray;
+    function isUint16Array(value) {
+      return whichTypedArray(value) === "Uint16Array";
+    }
+    exports2.isUint16Array = isUint16Array;
+    function isUint32Array(value) {
+      return whichTypedArray(value) === "Uint32Array";
+    }
+    exports2.isUint32Array = isUint32Array;
+    function isInt8Array(value) {
+      return whichTypedArray(value) === "Int8Array";
+    }
+    exports2.isInt8Array = isInt8Array;
+    function isInt16Array(value) {
+      return whichTypedArray(value) === "Int16Array";
+    }
+    exports2.isInt16Array = isInt16Array;
+    function isInt32Array(value) {
+      return whichTypedArray(value) === "Int32Array";
+    }
+    exports2.isInt32Array = isInt32Array;
+    function isFloat32Array(value) {
+      return whichTypedArray(value) === "Float32Array";
+    }
+    exports2.isFloat32Array = isFloat32Array;
+    function isFloat64Array(value) {
+      return whichTypedArray(value) === "Float64Array";
+    }
+    exports2.isFloat64Array = isFloat64Array;
+    function isBigInt64Array(value) {
+      return whichTypedArray(value) === "BigInt64Array";
+    }
+    exports2.isBigInt64Array = isBigInt64Array;
+    function isBigUint64Array(value) {
+      return whichTypedArray(value) === "BigUint64Array";
+    }
+    exports2.isBigUint64Array = isBigUint64Array;
+    function isMapToString(value) {
+      return ObjectToString(value) === "[object Map]";
+    }
+    isMapToString.working = typeof Map !== "undefined" && isMapToString(/* @__PURE__ */ new Map());
+    function isMap(value) {
+      if (typeof Map === "undefined") {
+        return false;
+      }
+      return isMapToString.working ? isMapToString(value) : value instanceof Map;
+    }
+    exports2.isMap = isMap;
+    function isSetToString(value) {
+      return ObjectToString(value) === "[object Set]";
+    }
+    isSetToString.working = typeof Set !== "undefined" && isSetToString(/* @__PURE__ */ new Set());
+    function isSet(value) {
+      if (typeof Set === "undefined") {
+        return false;
+      }
+      return isSetToString.working ? isSetToString(value) : value instanceof Set;
+    }
+    exports2.isSet = isSet;
+    function isWeakMapToString(value) {
+      return ObjectToString(value) === "[object WeakMap]";
+    }
+    isWeakMapToString.working = typeof WeakMap !== "undefined" && isWeakMapToString(/* @__PURE__ */ new WeakMap());
+    function isWeakMap(value) {
+      if (typeof WeakMap === "undefined") {
+        return false;
+      }
+      return isWeakMapToString.working ? isWeakMapToString(value) : value instanceof WeakMap;
+    }
+    exports2.isWeakMap = isWeakMap;
+    function isWeakSetToString(value) {
+      return ObjectToString(value) === "[object WeakSet]";
+    }
+    isWeakSetToString.working = typeof WeakSet !== "undefined" && isWeakSetToString(/* @__PURE__ */ new WeakSet());
+    function isWeakSet(value) {
+      return isWeakSetToString(value);
+    }
+    exports2.isWeakSet = isWeakSet;
+    function isArrayBufferToString(value) {
+      return ObjectToString(value) === "[object ArrayBuffer]";
+    }
+    isArrayBufferToString.working = typeof ArrayBuffer !== "undefined" && isArrayBufferToString(new ArrayBuffer());
+    function isArrayBuffer(value) {
+      if (typeof ArrayBuffer === "undefined") {
+        return false;
+      }
+      return isArrayBufferToString.working ? isArrayBufferToString(value) : value instanceof ArrayBuffer;
+    }
+    exports2.isArrayBuffer = isArrayBuffer;
+    function isDataViewToString(value) {
+      return ObjectToString(value) === "[object DataView]";
+    }
+    isDataViewToString.working = typeof ArrayBuffer !== "undefined" && typeof DataView !== "undefined" && isDataViewToString(new DataView(new ArrayBuffer(1), 0, 1));
+    function isDataView(value) {
+      if (typeof DataView === "undefined") {
+        return false;
+      }
+      return isDataViewToString.working ? isDataViewToString(value) : value instanceof DataView;
+    }
+    exports2.isDataView = isDataView;
+    var SharedArrayBufferCopy = typeof SharedArrayBuffer !== "undefined" ? SharedArrayBuffer : void 0;
+    function isSharedArrayBufferToString(value) {
+      return ObjectToString(value) === "[object SharedArrayBuffer]";
+    }
+    function isSharedArrayBuffer(value) {
+      if (typeof SharedArrayBufferCopy === "undefined") {
+        return false;
+      }
+      if (typeof isSharedArrayBufferToString.working === "undefined") {
+        isSharedArrayBufferToString.working = isSharedArrayBufferToString(new SharedArrayBufferCopy());
+      }
+      return isSharedArrayBufferToString.working ? isSharedArrayBufferToString(value) : value instanceof SharedArrayBufferCopy;
+    }
+    exports2.isSharedArrayBuffer = isSharedArrayBuffer;
+    function isAsyncFunction(value) {
+      return ObjectToString(value) === "[object AsyncFunction]";
+    }
+    exports2.isAsyncFunction = isAsyncFunction;
+    function isMapIterator(value) {
+      return ObjectToString(value) === "[object Map Iterator]";
+    }
+    exports2.isMapIterator = isMapIterator;
+    function isSetIterator(value) {
+      return ObjectToString(value) === "[object Set Iterator]";
+    }
+    exports2.isSetIterator = isSetIterator;
+    function isGeneratorObject(value) {
+      return ObjectToString(value) === "[object Generator]";
+    }
+    exports2.isGeneratorObject = isGeneratorObject;
+    function isWebAssemblyCompiledModule(value) {
+      return ObjectToString(value) === "[object WebAssembly.Module]";
+    }
+    exports2.isWebAssemblyCompiledModule = isWebAssemblyCompiledModule;
+    function isNumberObject(value) {
+      return checkBoxedPrimitive(value, numberValue);
+    }
+    exports2.isNumberObject = isNumberObject;
+    function isStringObject(value) {
+      return checkBoxedPrimitive(value, stringValue);
+    }
+    exports2.isStringObject = isStringObject;
+    function isBooleanObject(value) {
+      return checkBoxedPrimitive(value, booleanValue);
+    }
+    exports2.isBooleanObject = isBooleanObject;
+    function isBigIntObject(value) {
+      return BigIntSupported && checkBoxedPrimitive(value, bigIntValue);
+    }
+    exports2.isBigIntObject = isBigIntObject;
+    function isSymbolObject(value) {
+      return SymbolSupported && checkBoxedPrimitive(value, symbolValue);
+    }
+    exports2.isSymbolObject = isSymbolObject;
+    function isBoxedPrimitive(value) {
+      return isNumberObject(value) || isStringObject(value) || isBooleanObject(value) || isBigIntObject(value) || isSymbolObject(value);
+    }
+    exports2.isBoxedPrimitive = isBoxedPrimitive;
+    function isAnyArrayBuffer(value) {
+      return typeof Uint8Array !== "undefined" && (isArrayBuffer(value) || isSharedArrayBuffer(value));
+    }
+    exports2.isAnyArrayBuffer = isAnyArrayBuffer;
+    ["isProxy", "isExternal", "isModuleNamespaceObject"].forEach(function(method) {
+      Object.defineProperty(exports2, method, {
+        enumerable: false,
+        value: function() {
+          throw new Error(method + " is not supported in userland");
+        }
+      });
+    });
+  }
+});
+
+// scripts/node-portable/node_modules/util/support/isBuffer.js
+var require_isBuffer = __commonJS({
+  "scripts/node-portable/node_modules/util/support/isBuffer.js"(exports2, module2) {
+    module2.exports = function isBuffer(arg) {
+      return arg instanceof Buffer;
+    };
+  }
+});
+
+// scripts/node-portable/node_modules/inherits/inherits_browser.js
+var require_inherits_browser = __commonJS({
+  "scripts/node-portable/node_modules/inherits/inherits_browser.js"(exports2, module2) {
+    if (typeof Object.create === "function") {
+      module2.exports = function inherits(ctor, superCtor) {
+        if (superCtor) {
+          ctor.super_ = superCtor;
+          ctor.prototype = Object.create(superCtor.prototype, {
+            constructor: {
+              value: ctor,
+              enumerable: false,
+              writable: true,
+              configurable: true
+            }
+          });
+        }
+      };
+    } else {
+      module2.exports = function inherits(ctor, superCtor) {
+        if (superCtor) {
+          ctor.super_ = superCtor;
+          var TempCtor = function() {
+          };
+          TempCtor.prototype = superCtor.prototype;
+          ctor.prototype = new TempCtor();
+          ctor.prototype.constructor = ctor;
+        }
+      };
+    }
+  }
+});
+
+// scripts/node-portable/node_modules/inherits/inherits.js
+var require_inherits = __commonJS({
+  "scripts/node-portable/node_modules/inherits/inherits.js"(exports2, module2) {
+    try {
+      util = require("util");
+      if (typeof util.inherits !== "function") throw "";
+      module2.exports = util.inherits;
+    } catch (e) {
+      module2.exports = require_inherits_browser();
+    }
+    var util;
+  }
+});
+
+// scripts/node-portable/node_modules/util/util.js
+var require_util = __commonJS({
+  "scripts/node-portable/node_modules/util/util.js"(exports2) {
+    var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function getOwnPropertyDescriptors2(obj) {
+      var keys = Object.keys(obj);
+      var descriptors = {};
+      for (var i = 0; i < keys.length; i++) {
+        descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj, keys[i]);
+      }
+      return descriptors;
+    };
+    var formatRegExp = /%[sdj%]/g;
+    exports2.format = function(f) {
+      if (!isString(f)) {
+        var objects = [];
+        for (var i = 0; i < arguments.length; i++) {
+          objects.push(inspect(arguments[i]));
+        }
+        return objects.join(" ");
+      }
+      var i = 1;
+      var args = arguments;
+      var len = args.length;
+      var str = String(f).replace(formatRegExp, function(x2) {
+        if (x2 === "%%") return "%";
+        if (i >= len) return x2;
+        switch (x2) {
+          case "%s":
+            return String(args[i++]);
+          case "%d":
+            return Number(args[i++]);
+          case "%j":
+            try {
+              return JSON.stringify(args[i++]);
+            } catch (_) {
+              return "[Circular]";
+            }
+          default:
+            return x2;
+        }
+      });
+      for (var x = args[i]; i < len; x = args[++i]) {
+        if (isNull(x) || !isObject(x)) {
+          str += " " + x;
+        } else {
+          str += " " + inspect(x);
+        }
+      }
+      return str;
+    };
+    exports2.deprecate = function(fn, msg) {
+      if (typeof process !== "undefined" && process.noDeprecation === true) {
+        return fn;
+      }
+      if (typeof process === "undefined") {
+        return function() {
+          return exports2.deprecate(fn, msg).apply(this, arguments);
+        };
+      }
+      var warned = false;
+      function deprecated() {
+        if (!warned) {
+          if (process.throwDeprecation) {
+            throw new Error(msg);
+          } else if (process.traceDeprecation) {
+            console.trace(msg);
+          } else {
+            console.error(msg);
+          }
+          warned = true;
+        }
+        return fn.apply(this, arguments);
+      }
+      return deprecated;
+    };
+    var debugs = {};
+    var debugEnvRegex = /^$/;
+    if (process.env.NODE_DEBUG) {
+      debugEnv = process.env.NODE_DEBUG;
+      debugEnv = debugEnv.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/\*/g, ".*").replace(/,/g, "$|^").toUpperCase();
+      debugEnvRegex = new RegExp("^" + debugEnv + "$", "i");
+    }
+    var debugEnv;
+    exports2.debuglog = function(set) {
+      set = set.toUpperCase();
+      if (!debugs[set]) {
+        if (debugEnvRegex.test(set)) {
+          var pid = process.pid;
+          debugs[set] = function() {
+            var msg = exports2.format.apply(exports2, arguments);
+            console.error("%s %d: %s", set, pid, msg);
+          };
+        } else {
+          debugs[set] = function() {
+          };
+        }
+      }
+      return debugs[set];
+    };
+    function inspect(obj, opts) {
+      var ctx = {
+        seen: [],
+        stylize: stylizeNoColor
+      };
+      if (arguments.length >= 3) ctx.depth = arguments[2];
+      if (arguments.length >= 4) ctx.colors = arguments[3];
+      if (isBoolean(opts)) {
+        ctx.showHidden = opts;
+      } else if (opts) {
+        exports2._extend(ctx, opts);
+      }
+      if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
+      if (isUndefined(ctx.depth)) ctx.depth = 2;
+      if (isUndefined(ctx.colors)) ctx.colors = false;
+      if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
+      if (ctx.colors) ctx.stylize = stylizeWithColor;
+      return formatValue(ctx, obj, ctx.depth);
+    }
+    exports2.inspect = inspect;
+    inspect.colors = {
+      "bold": [1, 22],
+      "italic": [3, 23],
+      "underline": [4, 24],
+      "inverse": [7, 27],
+      "white": [37, 39],
+      "grey": [90, 39],
+      "black": [30, 39],
+      "blue": [34, 39],
+      "cyan": [36, 39],
+      "green": [32, 39],
+      "magenta": [35, 39],
+      "red": [31, 39],
+      "yellow": [33, 39]
+    };
+    inspect.styles = {
+      "special": "cyan",
+      "number": "yellow",
+      "boolean": "yellow",
+      "undefined": "grey",
+      "null": "bold",
+      "string": "green",
+      "date": "magenta",
+      // "name": intentionally not styling
+      "regexp": "red"
+    };
+    function stylizeWithColor(str, styleType) {
+      var style = inspect.styles[styleType];
+      if (style) {
+        return "\x1B[" + inspect.colors[style][0] + "m" + str + "\x1B[" + inspect.colors[style][1] + "m";
+      } else {
+        return str;
+      }
+    }
+    function stylizeNoColor(str, styleType) {
+      return str;
+    }
+    function arrayToHash(array) {
+      var hash = {};
+      array.forEach(function(val, idx) {
+        hash[val] = true;
+      });
+      return hash;
+    }
+    function formatValue(ctx, value, recurseTimes) {
+      if (ctx.customInspect && value && isFunction(value.inspect) && // Filter out the util module, it's inspect function is special
+      value.inspect !== exports2.inspect && // Also filter out any prototype objects using the circular check.
+      !(value.constructor && value.constructor.prototype === value)) {
+        var ret = value.inspect(recurseTimes, ctx);
+        if (!isString(ret)) {
+          ret = formatValue(ctx, ret, recurseTimes);
+        }
+        return ret;
+      }
+      var primitive = formatPrimitive(ctx, value);
+      if (primitive) {
+        return primitive;
+      }
+      var keys = Object.keys(value);
+      var visibleKeys = arrayToHash(keys);
+      if (ctx.showHidden) {
+        keys = Object.getOwnPropertyNames(value);
+      }
+      if (isError(value) && (keys.indexOf("message") >= 0 || keys.indexOf("description") >= 0)) {
+        return formatError(value);
+      }
+      if (keys.length === 0) {
+        if (isFunction(value)) {
+          var name = value.name ? ": " + value.name : "";
+          return ctx.stylize("[Function" + name + "]", "special");
+        }
+        if (isRegExp(value)) {
+          return ctx.stylize(RegExp.prototype.toString.call(value), "regexp");
+        }
+        if (isDate(value)) {
+          return ctx.stylize(Date.prototype.toString.call(value), "date");
+        }
+        if (isError(value)) {
+          return formatError(value);
+        }
+      }
+      var base = "", array = false, braces = ["{", "}"];
+      if (isArray(value)) {
+        array = true;
+        braces = ["[", "]"];
+      }
+      if (isFunction(value)) {
+        var n = value.name ? ": " + value.name : "";
+        base = " [Function" + n + "]";
+      }
+      if (isRegExp(value)) {
+        base = " " + RegExp.prototype.toString.call(value);
+      }
+      if (isDate(value)) {
+        base = " " + Date.prototype.toUTCString.call(value);
+      }
+      if (isError(value)) {
+        base = " " + formatError(value);
+      }
+      if (keys.length === 0 && (!array || value.length == 0)) {
+        return braces[0] + base + braces[1];
+      }
+      if (recurseTimes < 0) {
+        if (isRegExp(value)) {
+          return ctx.stylize(RegExp.prototype.toString.call(value), "regexp");
+        } else {
+          return ctx.stylize("[Object]", "special");
+        }
+      }
+      ctx.seen.push(value);
+      var output;
+      if (array) {
+        output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
+      } else {
+        output = keys.map(function(key) {
+          return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
+        });
+      }
+      ctx.seen.pop();
+      return reduceToSingleString(output, base, braces);
+    }
+    function formatPrimitive(ctx, value) {
+      if (isUndefined(value))
+        return ctx.stylize("undefined", "undefined");
+      if (isString(value)) {
+        var simple = "'" + JSON.stringify(value).replace(/^"|"$/g, "").replace(/'/g, "\\'").replace(/\\"/g, '"') + "'";
+        return ctx.stylize(simple, "string");
+      }
+      if (isNumber(value))
+        return ctx.stylize("" + value, "number");
+      if (isBoolean(value))
+        return ctx.stylize("" + value, "boolean");
+      if (isNull(value))
+        return ctx.stylize("null", "null");
+    }
+    function formatError(value) {
+      return "[" + Error.prototype.toString.call(value) + "]";
+    }
+    function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
+      var output = [];
+      for (var i = 0, l = value.length; i < l; ++i) {
+        if (hasOwnProperty(value, String(i))) {
+          output.push(formatProperty(
+            ctx,
+            value,
+            recurseTimes,
+            visibleKeys,
+            String(i),
+            true
+          ));
+        } else {
+          output.push("");
+        }
+      }
+      keys.forEach(function(key) {
+        if (!key.match(/^\d+$/)) {
+          output.push(formatProperty(
+            ctx,
+            value,
+            recurseTimes,
+            visibleKeys,
+            key,
+            true
+          ));
+        }
+      });
+      return output;
+    }
+    function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
+      var name, str, desc;
+      desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
+      if (desc.get) {
+        if (desc.set) {
+          str = ctx.stylize("[Getter/Setter]", "special");
+        } else {
+          str = ctx.stylize("[Getter]", "special");
+        }
+      } else {
+        if (desc.set) {
+          str = ctx.stylize("[Setter]", "special");
+        }
+      }
+      if (!hasOwnProperty(visibleKeys, key)) {
+        name = "[" + key + "]";
+      }
+      if (!str) {
+        if (ctx.seen.indexOf(desc.value) < 0) {
+          if (isNull(recurseTimes)) {
+            str = formatValue(ctx, desc.value, null);
+          } else {
+            str = formatValue(ctx, desc.value, recurseTimes - 1);
+          }
+          if (str.indexOf("\n") > -1) {
+            if (array) {
+              str = str.split("\n").map(function(line) {
+                return "  " + line;
+              }).join("\n").slice(2);
+            } else {
+              str = "\n" + str.split("\n").map(function(line) {
+                return "   " + line;
+              }).join("\n");
+            }
+          }
+        } else {
+          str = ctx.stylize("[Circular]", "special");
+        }
+      }
+      if (isUndefined(name)) {
+        if (array && key.match(/^\d+$/)) {
+          return str;
+        }
+        name = JSON.stringify("" + key);
+        if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
+          name = name.slice(1, -1);
+          name = ctx.stylize(name, "name");
+        } else {
+          name = name.replace(/'/g, "\\'").replace(/\\"/g, '"').replace(/(^"|"$)/g, "'");
+          name = ctx.stylize(name, "string");
+        }
+      }
+      return name + ": " + str;
+    }
+    function reduceToSingleString(output, base, braces) {
+      var numLinesEst = 0;
+      var length = output.reduce(function(prev, cur) {
+        numLinesEst++;
+        if (cur.indexOf("\n") >= 0) numLinesEst++;
+        return prev + cur.replace(/\u001b\[\d\d?m/g, "").length + 1;
+      }, 0);
+      if (length > 60) {
+        return braces[0] + (base === "" ? "" : base + "\n ") + " " + output.join(",\n  ") + " " + braces[1];
+      }
+      return braces[0] + base + " " + output.join(", ") + " " + braces[1];
+    }
+    exports2.types = require_types();
+    function isArray(ar) {
+      return Array.isArray(ar);
+    }
+    exports2.isArray = isArray;
+    function isBoolean(arg) {
+      return typeof arg === "boolean";
+    }
+    exports2.isBoolean = isBoolean;
+    function isNull(arg) {
+      return arg === null;
+    }
+    exports2.isNull = isNull;
+    function isNullOrUndefined(arg) {
+      return arg == null;
+    }
+    exports2.isNullOrUndefined = isNullOrUndefined;
+    function isNumber(arg) {
+      return typeof arg === "number";
+    }
+    exports2.isNumber = isNumber;
+    function isString(arg) {
+      return typeof arg === "string";
+    }
+    exports2.isString = isString;
+    function isSymbol(arg) {
+      return typeof arg === "symbol";
+    }
+    exports2.isSymbol = isSymbol;
+    function isUndefined(arg) {
+      return arg === void 0;
+    }
+    exports2.isUndefined = isUndefined;
+    function isRegExp(re) {
+      return isObject(re) && objectToString(re) === "[object RegExp]";
+    }
+    exports2.isRegExp = isRegExp;
+    exports2.types.isRegExp = isRegExp;
+    function isObject(arg) {
+      return typeof arg === "object" && arg !== null;
+    }
+    exports2.isObject = isObject;
+    function isDate(d) {
+      return isObject(d) && objectToString(d) === "[object Date]";
+    }
+    exports2.isDate = isDate;
+    exports2.types.isDate = isDate;
+    function isError(e) {
+      return isObject(e) && (objectToString(e) === "[object Error]" || e instanceof Error);
+    }
+    exports2.isError = isError;
+    exports2.types.isNativeError = isError;
+    function isFunction(arg) {
+      return typeof arg === "function";
+    }
+    exports2.isFunction = isFunction;
+    function isPrimitive(arg) {
+      return arg === null || typeof arg === "boolean" || typeof arg === "number" || typeof arg === "string" || typeof arg === "symbol" || // ES6 symbol
+      typeof arg === "undefined";
+    }
+    exports2.isPrimitive = isPrimitive;
+    exports2.isBuffer = require_isBuffer();
+    function objectToString(o) {
+      return Object.prototype.toString.call(o);
+    }
+    function pad(n) {
+      return n < 10 ? "0" + n.toString(10) : n.toString(10);
+    }
+    var months = [
+      "Jan",
+      "Feb",
+      "Mar",
+      "Apr",
+      "May",
+      "Jun",
+      "Jul",
+      "Aug",
+      "Sep",
+      "Oct",
+      "Nov",
+      "Dec"
+    ];
+    function timestamp() {
+      var d = /* @__PURE__ */ new Date();
+      var time = [
+        pad(d.getHours()),
+        pad(d.getMinutes()),
+        pad(d.getSeconds())
+      ].join(":");
+      return [d.getDate(), months[d.getMonth()], time].join(" ");
+    }
+    exports2.log = function() {
+      console.log("%s - %s", timestamp(), exports2.format.apply(exports2, arguments));
+    };
+    exports2.inherits = require_inherits();
+    exports2._extend = function(origin, add) {
+      if (!add || !isObject(add)) return origin;
+      var keys = Object.keys(add);
+      var i = keys.length;
+      while (i--) {
+        origin[keys[i]] = add[keys[i]];
+      }
+      return origin;
+    };
+    function hasOwnProperty(obj, prop) {
+      return Object.prototype.hasOwnProperty.call(obj, prop);
+    }
+    var kCustomPromisifiedSymbol = typeof Symbol !== "undefined" ? Symbol("util.promisify.custom") : void 0;
+    exports2.promisify = function promisify(original) {
+      if (typeof original !== "function")
+        throw new TypeError('The "original" argument must be of type Function');
+      if (kCustomPromisifiedSymbol && original[kCustomPromisifiedSymbol]) {
+        var fn = original[kCustomPromisifiedSymbol];
+        if (typeof fn !== "function") {
+          throw new TypeError('The "util.promisify.custom" argument must be of type Function');
+        }
+        Object.defineProperty(fn, kCustomPromisifiedSymbol, {
+          value: fn,
+          enumerable: false,
+          writable: false,
+          configurable: true
+        });
+        return fn;
+      }
+      function fn() {
+        var promiseResolve, promiseReject;
+        var promise = new Promise(function(resolve, reject) {
+          promiseResolve = resolve;
+          promiseReject = reject;
+        });
+        var args = [];
+        for (var i = 0; i < arguments.length; i++) {
+          args.push(arguments[i]);
+        }
+        args.push(function(err, value) {
+          if (err) {
+            promiseReject(err);
+          } else {
+            promiseResolve(value);
+          }
+        });
+        try {
+          original.apply(this, args);
+        } catch (err) {
+          promiseReject(err);
+        }
+        return promise;
+      }
+      Object.setPrototypeOf(fn, Object.getPrototypeOf(original));
+      if (kCustomPromisifiedSymbol) Object.defineProperty(fn, kCustomPromisifiedSymbol, {
+        value: fn,
+        enumerable: false,
+        writable: false,
+        configurable: true
+      });
+      return Object.defineProperties(
+        fn,
+        getOwnPropertyDescriptors(original)
+      );
+    };
+    exports2.promisify.custom = kCustomPromisifiedSymbol;
+    function callbackifyOnRejected(reason, cb) {
+      if (!reason) {
+        var newReason = new Error("Promise was rejected with a falsy value");
+        newReason.reason = reason;
+        reason = newReason;
+      }
+      return cb(reason);
+    }
+    function callbackify(original) {
+      if (typeof original !== "function") {
+        throw new TypeError('The "original" argument must be of type Function');
+      }
+      function callbackified() {
+        var args = [];
+        for (var i = 0; i < arguments.length; i++) {
+          args.push(arguments[i]);
+        }
+        var maybeCb = args.pop();
+        if (typeof maybeCb !== "function") {
+          throw new TypeError("The last argument must be of type Function");
+        }
+        var self = this;
+        var cb = function() {
+          return maybeCb.apply(self, arguments);
+        };
+        original.apply(this, args).then(
+          function(ret) {
+            process.nextTick(cb.bind(null, null, ret));
+          },
+          function(rej) {
+            process.nextTick(callbackifyOnRejected.bind(null, rej, cb));
+          }
+        );
+      }
+      Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original));
+      Object.defineProperties(
+        callbackified,
+        getOwnPropertyDescriptors(original)
+      );
+      return callbackified;
+    }
+    exports2.callbackify = callbackify;
+  }
+});
+
+// scripts/node-portable/.entry-util-base.cjs
+module.exports = require_util();
diff --git a/src/Node/Lib/portable/validators.cjs b/src/Node/Lib/portable/validators.cjs
new file mode 100644
index 00000000..0b42a452
--- /dev/null
+++ b/src/Node/Lib/portable/validators.cjs
@@ -0,0 +1,15 @@
+'use strict';
+
+const { ERR_INVALID_ARG_TYPE } = require('./errors.cjs').codes;
+
+exports.validateString = function validateString(value, name) {
+  if (typeof value !== 'string') throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
+};
+
+exports.validateObject = function validateObject(value, name, options = {}) {
+  if ((value === null && !options.nullable) ||
+      (typeof value !== 'object' && !(options.allowFunction && typeof value === 'function')) ||
+      (!options.allowArray && Array.isArray(value))) {
+    throw new ERR_INVALID_ARG_TYPE(name, 'Object', value);
+  }
+};
diff --git a/src/Node/Lib/portable/whatwg-url.cjs b/src/Node/Lib/portable/whatwg-url.cjs
new file mode 100644
index 00000000..62dbefed
--- /dev/null
+++ b/src/Node/Lib/portable/whatwg-url.cjs
@@ -0,0 +1,123 @@
+'use strict';
+
+const punycode = require('./punycode.cjs');
+const { validateString } = require('./validators.cjs');
+const { ERR_INVALID_ARG_TYPE } = require('./errors.cjs').codes;
+
+exports.URL = globalThis.URL;
+exports.URLSearchParams = globalThis.URLSearchParams;
+exports.unsafeProtocol = new Set(['javascript', 'javascript:']);
+exports.hostlessProtocol = new Set(['javascript', 'javascript:']);
+exports.slashedProtocol = new Set(['http', 'https', 'ftp', 'gopher', 'file', 'ws', 'wss'].flatMap((value) => [value, value + ':']));
+
+exports.domainToASCII = function domainToASCII(domain) {
+  if (arguments.length === 0) throw new ERR_INVALID_ARG_TYPE('domain', 'string', undefined);
+  const text = String(domain).split(/[/?#]/, 1)[0];
+  if (text.includes('@') || text.includes(':') && !/^\[[\da-f:.]+\]$/i.test(text)) return '';
+  try {
+    const ascii = /^[\x00-\x7F]*$/.test(text) && !text.toLowerCase().includes('xn--') ? text : require('./tr46.cjs').toASCII(text, {
+      checkBidi: true, checkJoiners: true, transitionalProcessing: false, verifyDNSLength: false,
+    });
+    return ascii ? new URL('http://' + ascii).hostname : '';
+  } catch { return ''; }
+};
+
+exports.domainToUnicode = function domainToUnicode(domain) {
+  const ascii = exports.domainToASCII(domain);
+  return ascii ? punycode.toUnicode(ascii) : '';
+};
+
+function error(code, message) {
+  const result = new TypeError(message);
+  result.code = code;
+  return result;
+}
+
+function fileUrl(input, windows) {
+  const url = typeof input === 'string' ? new URL(input) : input;
+  if (!(url instanceof URL)) throw new ERR_INVALID_ARG_TYPE('path', 'string or an instance of URL', input);
+  if (url.protocol !== 'file:') throw error('ERR_INVALID_URL_SCHEME', 'The URL must be of scheme file');
+  if (/%2f/i.test(url.pathname) || (windows && /%5c/i.test(url.pathname))) {
+    throw error('ERR_INVALID_FILE_URL_PATH', 'File URL path must not include encoded / or \\ characters');
+  }
+  if (!windows && url.hostname !== '') {
+    throw error('ERR_INVALID_FILE_URL_HOST', 'File URL host must be "localhost" or empty on ' + process.platform);
+  }
+  return url;
+}
+
+function windowsOption(options) {
+  if (options && options.windows !== undefined && typeof options.windows !== 'boolean') {
+    throw new ERR_INVALID_ARG_TYPE('options.windows', 'boolean', options.windows);
+  }
+  return options && options.windows !== undefined ? options.windows : process.platform === 'win32';
+}
+
+exports.fileURLToPath = function fileURLToPath(input, options) {
+  const windows = windowsOption(options);
+  const url = fileUrl(input, windows);
+  let path = decodeURIComponent(url.pathname);
+  if (!windows) return path;
+  path = path.replaceAll('/', '\\');
+  if (url.hostname) return '\\\\' + exports.domainToUnicode(url.hostname) + path;
+  if (!/^\\[a-z]:/i.test(path)) throw error('ERR_INVALID_FILE_URL_PATH', 'File URL path must be absolute');
+  return path.slice(1);
+};
+
+exports.fileURLToPathBuffer = function fileURLToPathBuffer(input, options) {
+  const windows = windowsOption(options);
+  const url = fileUrl(input, windows);
+  if (windows) return Buffer.from(exports.fileURLToPath(url, options));
+  const chunks = [];
+  const text = url.pathname;
+  let start = 0;
+  for (let i = 0; i < text.length; i++) {
+    if (text[i] === '%' && /^[\da-f]{2}$/i.test(text.slice(i + 1, i + 3))) {
+      if (i > start) chunks.push(Buffer.from(text.slice(start, i)));
+      chunks.push(Buffer.from([parseInt(text.slice(i + 1, i + 3), 16)]));
+      i += 2;
+      start = i + 1;
+    }
+  }
+  if (start < text.length) chunks.push(Buffer.from(text.slice(start)));
+  return Buffer.concat(chunks);
+};
+
+exports.pathToFileURL = function pathToFileURL(input, options) {
+  validateString(input, 'path');
+  const windows = windowsOption(options);
+  const path = require('../path.cjs');
+  let resolved = (windows ? path.win32 : path.posix).resolve(input);
+  const trailingSlash = /[\\/]$/.test(input);
+  if (trailingSlash && !/[\\/]$/.test(resolved)) resolved += windows ? '\\' : '/';
+  if (windows) {
+    resolved = resolved.replaceAll('\\', '/');
+    if (resolved.startsWith('//')) {
+      const pieces = resolved.slice(2).split('/');
+      const host = pieces.shift();
+      return new URL('file://' + host + '/' + pieces.map(encodeURIComponent).join('/'));
+    }
+    resolved = '/' + resolved;
+  }
+  const encoded = resolved.split('/').map(encodeURIComponent).join('/').replace(/^\/([a-z])%3A/i, '/$1:');
+  return new URL('file://' + encoded);
+};
+
+exports.urlToHttpOptions = function urlToHttpOptions(url) {
+  const result = { ...url, protocol: url.protocol, hostname: url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname,
+    hash: url.hash, search: url.search, pathname: url.pathname, path: url.pathname + url.search, href: url.href };
+  if (url.port !== '') result.port = Number(url.port);
+  if (url.username || url.password) result.auth = decodeURIComponent(url.username) + ':' + decodeURIComponent(url.password);
+  return result;
+};
+
+exports.format = function format(href, fragment, unicode, search, auth) {
+  const url = new URL(href);
+  if (!fragment) url.hash = '';
+  if (!search) url.search = '';
+  if (!auth) { url.username = ''; url.password = ''; }
+  if (!unicode || !url.hostname) return url.href;
+  const credentials = url.username || url.password ? url.username + (url.password ? ':' + url.password : '') + '@' : '';
+  const offset = url.protocol.length + 2 + credentials.length;
+  return url.href.slice(0, offset) + exports.domainToUnicode(url.hostname) + url.href.slice(offset + url.hostname.length);
+};
diff --git a/src/Node/Lib/primitives-LICENSES.txt b/src/Node/Lib/primitives-LICENSES.txt
new file mode 100644
index 00000000..e5d47e1d
--- /dev/null
+++ b/src/Node/Lib/primitives-LICENSES.txt
@@ -0,0 +1,439 @@
+base64-js 1.5.1
+The MIT License (MIT)
+
+Copyright (c) 2014 Jameson Little
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+brotli 1.3.3
+brotli 1.3.3 by Devon Govett. The npm package declares MIT.
+The bundled Google decoder source retains its Apache-2.0 notices.
+Decoder copyright: Copyright 2013 Google Inc. All Rights Reserved.
+Phasis changes: compact dictionary and compiler-memory representation, a 64 MiB
+encoder heap, typed-array equivalents of C memory/table operations, removal of
+the process-wide Emscripten exception listener, and corrected output capacity.
+The compiled Google Brotli encoder is distributed under the following MIT license.
+
+Source: https://github.com/google/brotli/blob/master/LICENSE
+
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+Decoder source license: https://www.apache.org/licenses/LICENSE-2.0.txt
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+buffer 6.0.3
+The MIT License (MIT)
+
+Copyright (c) Feross Aboukhadijeh, and other contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+events 3.3.0
+MIT
+
+Copyright Joyent, Inc. and other Node contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ieee754 1.2.1
+Copyright 2008 Fair Oaks Labs, Inc.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+readable-stream 4.8.0
+Node.js is licensed for use as follows:
+
+"""
+Copyright Node.js contributors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+"""
+
+This license applies to parts of Node.js originating from the
+https://github.com/joyent/node repository:
+
+"""
+Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+"""
+
+safe-buffer 5.2.1
+The MIT License (MIT)
+
+Copyright (c) Feross Aboukhadijeh
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+string_decoder 1.3.0
+Node.js is licensed for use as follows:
+
+"""
+Copyright Node.js contributors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+"""
+
+This license applies to parts of Node.js originating from the
+https://github.com/joyent/node repository:
+
+"""
+Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+"""
diff --git a/src/Node/Lib/primitives-manifest.json b/src/Node/Lib/primitives-manifest.json
new file mode 100644
index 00000000..3768b8f9
--- /dev/null
+++ b/src/Node/Lib/primitives-manifest.json
@@ -0,0 +1,91 @@
+{
+  "upstream": {
+    "base64-js": {
+      "version": "1.5.1",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+    },
+    "brotli": {
+      "version": "1.3.3",
+      "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg=="
+    },
+    "buffer": {
+      "version": "6.0.3",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="
+    },
+    "events": {
+      "version": "3.3.0",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="
+    },
+    "ieee754": {
+      "version": "1.2.1",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+    },
+    "readable-stream": {
+      "version": "4.8.0",
+      "integrity": "sha512-2jhTTU3Eilp/2DMT71gbcoqC35eQHasMJH0RHkYxwlxIv3+FR6Y5xAFZIwEGLxKkjZYEFlsiMNIdwUqjK2lLHQ=="
+    },
+    "safe-buffer": {
+      "version": "5.2.1",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+    },
+    "string_decoder": {
+      "version": "1.3.0",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="
+    }
+  },
+  "outputs": {
+    "buffer": {
+      "bytes": 65785,
+      "requires": []
+    },
+    "events": {
+      "bytes": 22557,
+      "requires": [
+        "async_hooks"
+      ]
+    },
+    "stream": {
+      "bytes": 189835,
+      "requires": [
+        "abort-controller",
+        "buffer",
+        "events",
+        "process",
+        "string_decoder"
+      ]
+    },
+    "string_decoder": {
+      "bytes": 9496,
+      "requires": [
+        "buffer"
+      ]
+    },
+    "stream-promises": {
+      "bytes": 169,
+      "requires": [
+        "stream"
+      ]
+    },
+    "stream-consumers": {
+      "bytes": 844,
+      "requires": [
+        "buffer"
+      ]
+    },
+    "stream-web": {
+      "bytes": 2348,
+      "requires": []
+    },
+    "brotli-decoder": {
+      "bytes": 231951,
+      "requires": []
+    },
+    "brotli-encoder": {
+      "bytes": 1656413,
+      "requires": [
+        "fs",
+        "path"
+      ]
+    }
+  }
+}
diff --git a/src/Node/Lib/process.cjs b/src/Node/Lib/process.cjs
new file mode 100644
index 00000000..d4f1f5a5
--- /dev/null
+++ b/src/Node/Lib/process.cjs
@@ -0,0 +1,57 @@
+'use strict';
+
+const EventEmitter = require('events');
+const host = __phasisNodeHost;
+const process = globalThis.process;
+Object.setPrototypeOf(process, EventEmitter.prototype);
+EventEmitter.call(process);
+
+process.cwd = () => host.cwd();
+process.chdir = (path) => host.chdir(path);
+process.nextTick = (callback, ...args) => host.nextTick(callback, ...args);
+process.hrtime = (previous) => {
+  const now = host.hrtime();
+  if (previous === undefined) return now;
+  let seconds = now[0] - previous[0];
+  let nanoseconds = now[1] - previous[1];
+  if (nanoseconds < 0) { seconds--; nanoseconds += 1e9; }
+  return [seconds, nanoseconds];
+};
+process.hrtime.bigint = () => host.hrtimeBigInt();
+process.uptime = () => host.uptime();
+process.memoryUsage = () => host.memoryUsage();
+process.memoryUsage.rss = () => host.memoryUsage().rss;
+process.pid = host.pid();
+process.ppid = host.ppid();
+process.execArgv = [];
+for (const [name, fd] of [['stdin', 0], ['stdout', 1], ['stderr', 2]]) {
+  Object.defineProperty(process, name, { configurable: true, enumerable: true, get() {
+    const streams = require('./stdio.cjs');
+    const stream = fd === 0 ? new streams.ReadStream(fd) : new streams.WriteStream(fd);
+    Object.defineProperty(process, name, { value: stream, configurable: true, enumerable: true });
+    return stream;
+  } });
+}
+const builtinNames = new Set(host.builtinNames());
+process.getBuiltinModule = (name) => {
+  if (typeof name !== 'string') throw Object.assign(new TypeError('The id argument must be a string'), { code: 'ERR_INVALID_ARG_TYPE' });
+  const canonical = name.startsWith('node:') ? name.slice(5) : name;
+  return builtinNames.has(canonical) ? host.builtin(canonical) : undefined;
+};
+process.emitWarning = (warning, type, code) => {
+  if (!(warning instanceof Error)) {
+    const error = new Error(String(warning));
+    if (typeof type === 'object' && type !== null) {
+      error.name = type.type || 'Warning';
+      if (type.code !== undefined) error.code = type.code;
+    } else {
+      error.name = type || 'Warning';
+      if (code !== undefined) error.code = code;
+    }
+    warning = error;
+  }
+  process.nextTick(() => {
+    if (!process.emit('warning', warning)) console.warn(warning.toString());
+  });
+};
+module.exports = process;
diff --git a/src/Node/Lib/querystring.cjs b/src/Node/Lib/querystring.cjs
new file mode 100644
index 00000000..3b8b36ac
--- /dev/null
+++ b/src/Node/Lib/querystring.cjs
@@ -0,0 +1,615 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Query String Utilities
+
+'use strict';
+
+const {
+  Array,
+  ArrayIsArray,
+  Int8Array,
+  MathAbs,
+  NumberIsFinite,
+  ObjectKeys,
+  String,
+  StringPrototypeCharCodeAt,
+  StringPrototypeIndexOf,
+  StringPrototypeSlice,
+  decodeURIComponent,
+} = require('./portable/primordials.cjs');
+
+const { Buffer } = require('buffer');
+const {
+  encodeStr,
+  hexTable,
+  isHexTable,
+} = require('./portable/internal-querystring.cjs');
+const QueryString = module.exports = {
+  unescapeBuffer,
+  // `unescape()` is a JS global, so we need to use a different local name
+  unescape: qsUnescape,
+
+  // `escape()` is a JS global, so we need to use a different local name
+  escape: qsEscape,
+
+  stringify,
+  encode: stringify,
+
+  parse,
+  decode: parse,
+};
+
+const unhexTable = new Int8Array([
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0 - 15
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16 - 31
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32 - 47
+  +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, -1, -1, -1, -1, -1, -1, // 48 - 63
+  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 64 - 79
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80 - 95
+  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96 - 111
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 112 - 127
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128 ...
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  // ... 255
+]);
+/**
+ * A safe fast alternative to decodeURIComponent
+ * @param {string} s
+ * @param {boolean} decodeSpaces
+ * @returns {string}
+ */
+function unescapeBuffer(s, decodeSpaces) {
+  // No encoded bytes: latin1-copy the string without walking %XX.
+  if (StringPrototypeIndexOf(s, '%') === -1) {
+    if (!decodeSpaces || StringPrototypeIndexOf(s, '+') === -1)
+      return Buffer.from(s, 'latin1');
+  }
+  const out = Buffer.allocUnsafe(s.length);
+  let index = 0;
+  let outIndex = 0;
+  let currentChar;
+  let nextChar;
+  let hexHigh;
+  let hexLow;
+  const maxLength = s.length - 2;
+  // Flag to know if some hex chars have been decoded
+  let hasHex = false;
+  while (index < s.length) {
+    currentChar = StringPrototypeCharCodeAt(s, index);
+    if (currentChar === 43 /* '+' */ && decodeSpaces) {
+      out[outIndex++] = 32; // ' '
+      index++;
+      continue;
+    }
+    if (currentChar === 37 /* '%' */ && index < maxLength) {
+      currentChar = StringPrototypeCharCodeAt(s, ++index);
+      hexHigh = unhexTable[currentChar];
+      if (!(hexHigh >= 0)) {
+        out[outIndex++] = 37; // '%'
+        continue;
+      } else {
+        nextChar = StringPrototypeCharCodeAt(s, ++index);
+        hexLow = unhexTable[nextChar];
+        if (!(hexLow >= 0)) {
+          out[outIndex++] = 37; // '%'
+          index--;
+        } else {
+          hasHex = true;
+          currentChar = hexHigh * 16 + hexLow;
+        }
+      }
+    }
+    out[outIndex++] = currentChar;
+    index++;
+  }
+  return hasHex ? out.slice(0, outIndex) : out;
+}
+
+/**
+ * @param {string} s
+ * @param {boolean} decodeSpaces
+ * @returns {string}
+ */
+function qsUnescape(s, decodeSpaces) {
+  try {
+    return decodeURIComponent(s);
+  } catch {
+    return QueryString.unescapeBuffer(s, decodeSpaces).toString();
+  }
+}
+
+
+// These characters do not need escaping when generating query strings:
+// ! - . _ ~
+// ' ( ) *
+// digits
+// alpha (uppercase)
+// alpha (lowercase)
+const noEscape = new Int8Array([
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
+  0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, // 32 - 47
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 80 - 95
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,  // 112 - 127
+]);
+
+/**
+ * QueryString.escape() replaces encodeURIComponent()
+ * @see https://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4
+ * @param {any} str
+ * @returns {string}
+ */
+function qsEscape(str) {
+  if (typeof str !== 'string') {
+    if (typeof str === 'object')
+      str = String(str);
+    else
+      str += '';
+  }
+
+  return encodeStr(str, noEscape, hexTable);
+}
+
+/**
+ * @param {string | number | bigint | boolean | symbol | undefined | null} v
+ * @returns {string}
+ */
+function stringifyPrimitive(v) {
+  if (typeof v === 'string')
+    return v;
+  if (typeof v === 'number' && NumberIsFinite(v))
+    return '' + v;
+  if (typeof v === 'bigint')
+    return '' + v;
+  if (typeof v === 'boolean')
+    return v ? 'true' : 'false';
+  return '';
+}
+
+/**
+ * @param {string | number | bigint | boolean} v
+ * @param {(v: string) => string} encode
+ * @returns {string}
+ */
+function encodeStringified(v, encode) {
+  if (typeof v === 'string')
+    return (v.length ? encode(v) : '');
+  if (typeof v === 'number' && NumberIsFinite(v)) {
+    // Values >= 1e21 automatically switch to scientific notation which requires
+    // escaping due to the inclusion of a '+' in the output
+    return (MathAbs(v) < 1e21 ? '' + v : encode('' + v));
+  }
+  if (typeof v === 'bigint')
+    return '' + v;
+  if (typeof v === 'boolean')
+    return v ? 'true' : 'false';
+  return '';
+}
+
+/**
+ * @param {string | number | boolean | null} v
+ * @param {(v: string) => string} encode
+ * @returns {string}
+ */
+function encodeStringifiedCustom(v, encode) {
+  return encode(stringifyPrimitive(v));
+}
+
+/**
+ * @param {Record | null>} obj
+ * @param {string} [sep]
+ * @param {string} [eq]
+ * @param {{ encodeURIComponent?: (v: string) => string }} [options]
+ * @returns {string}
+ */
+function stringify(obj, sep, eq, options) {
+  sep ||= '&';
+  eq ||= '=';
+
+  let encode = QueryString.escape;
+  if (options && typeof options.encodeURIComponent === 'function') {
+    encode = options.encodeURIComponent;
+  }
+  const convert =
+    (encode === qsEscape ? encodeStringified : encodeStringifiedCustom);
+
+  if (obj !== null && typeof obj === 'object') {
+    const keys = ObjectKeys(obj);
+    const len = keys.length;
+    let fields = '';
+    for (let i = 0; i < len; ++i) {
+      const k = keys[i];
+      const v = obj[k];
+      let ks = convert(k, encode);
+      ks += eq;
+
+      if (ArrayIsArray(v)) {
+        const vlen = v.length;
+        if (vlen === 0) continue;
+        if (fields)
+          fields += sep;
+        for (let j = 0; j < vlen; ++j) {
+          if (j)
+            fields += sep;
+          fields += ks;
+          fields += convert(v[j], encode);
+        }
+      } else {
+        if (fields)
+          fields += sep;
+        fields += ks;
+        fields += convert(v, encode);
+      }
+    }
+    return fields;
+  }
+  return '';
+}
+
+/**
+ * @param {string} str
+ * @returns {number[]}
+ */
+function charCodes(str) {
+  if (str.length === 0) return [];
+  if (str.length === 1) return [StringPrototypeCharCodeAt(str, 0)];
+  const ret = new Array(str.length);
+  for (let i = 0; i < str.length; ++i)
+    ret[i] = StringPrototypeCharCodeAt(str, i);
+  return ret;
+}
+const defSepCodes = [38]; // &
+const defEqCodes = [61]; // =
+
+function addKeyVal(obj, key, value, keyEncoded, valEncoded, decode) {
+  if (key.length > 0 && keyEncoded)
+    key = decodeStr(key, decode);
+  if (value.length > 0 && valEncoded)
+    value = decodeStr(value, decode);
+
+  if (obj[key] === undefined) {
+    obj[key] = value;
+  } else {
+    const curValue = obj[key];
+    // A simple Array-specific property check is enough here to
+    // distinguish from a string value and is faster and still safe
+    // since we are generating all of the values being assigned.
+    if (curValue.pop)
+      curValue[curValue.length] = value;
+    else
+      obj[key] = [curValue, value];
+  }
+}
+
+/**
+ * Default querystring parser: separator '&', equals '=', native unescape.
+ * Single-character separators avoid the sep/eq index state machine.
+ * @param {string} qs
+ * @param {Record} obj
+ * @returns {Record}
+ */
+function parseAmpEq(qs, obj) {
+  let pairs = 1000;
+  let lastPos = 0;
+  let eqPos = -1;
+  let key = '';
+  let value = '';
+  let keyEncoded = false;
+  let valEncoded = false;
+  let encodeCheck = 0;
+  const plusChar = ' ';
+  const len = qs.length;
+
+  for (let i = 0; i < len; ++i) {
+    const code = StringPrototypeCharCodeAt(qs, i);
+
+    if (code === 38) { // '&'
+      const end = i;
+      if (eqPos === -1) {
+        if (lastPos < end)
+          key += StringPrototypeSlice(qs, lastPos, end);
+        else if (key.length === 0) {
+          if (--pairs === 0)
+            return obj;
+          lastPos = i + 1;
+          encodeCheck = 0;
+          continue;
+        }
+      } else if (lastPos < end) {
+        value += StringPrototypeSlice(qs, lastPos, end);
+      }
+
+      addKeyVal(obj, key, value, keyEncoded, valEncoded, qsUnescape);
+
+      if (--pairs === 0)
+        return obj;
+      keyEncoded = false;
+      valEncoded = false;
+      key = '';
+      value = '';
+      encodeCheck = 0;
+      lastPos = i + 1;
+      eqPos = -1;
+      continue;
+    }
+
+    if (eqPos === -1) {
+      if (code === 61) { // '='
+        if (lastPos < i)
+          key += StringPrototypeSlice(qs, lastPos, i);
+        encodeCheck = 0;
+        lastPos = i + 1;
+        eqPos = i;
+        continue;
+      }
+      if (!keyEncoded) {
+        if (code === 37) {
+          encodeCheck = 1;
+        } else if (encodeCheck > 0) {
+          if (isHexTable[code] === 1) {
+            if (++encodeCheck === 3)
+              keyEncoded = true;
+          } else {
+            encodeCheck = 0;
+          }
+        }
+      }
+      if (code === 43) {
+        if (lastPos < i)
+          key += StringPrototypeSlice(qs, lastPos, i);
+        key += plusChar;
+        lastPos = i + 1;
+      }
+      continue;
+    }
+
+    if (code === 43) {
+      if (lastPos < i)
+        value += StringPrototypeSlice(qs, lastPos, i);
+      value += plusChar;
+      lastPos = i + 1;
+    } else if (!valEncoded) {
+      if (code === 37) {
+        encodeCheck = 1;
+      } else if (encodeCheck > 0) {
+        if (isHexTable[code] === 1) {
+          if (++encodeCheck === 3)
+            valEncoded = true;
+        } else {
+          encodeCheck = 0;
+        }
+      }
+    }
+  }
+
+  if (lastPos < len) {
+    if (eqPos === -1)
+      key += StringPrototypeSlice(qs, lastPos);
+    else
+      value += StringPrototypeSlice(qs, lastPos);
+  } else if (eqPos === -1 && key.length === 0) {
+    return obj;
+  }
+
+  addKeyVal(obj, key, value, keyEncoded, valEncoded, qsUnescape);
+  return obj;
+}
+
+/**
+ * Parse a key/val string.
+ * @param {string} qs
+ * @param {string} sep
+ * @param {string} eq
+ * @param {{
+ *   maxKeys?: number,
+ *   decodeURIComponent?: (v: string) => string,
+ * }} [options]
+ * @returns {Record}
+ */
+function parse(qs, sep, eq, options) {
+  const obj = { __proto__: null };
+
+  if (typeof qs !== 'string' || qs.length === 0) {
+    return obj;
+  }
+
+  // Default '&' / '=' / unescape: single-char scanner, no sep/eq arrays.
+  if ((sep === undefined || sep === '&') &&
+      (eq === undefined || eq === '=') &&
+      QueryString.unescape === qsUnescape &&
+      (!options ||
+       (options.maxKeys === undefined &&
+        options.decodeURIComponent === undefined))) {
+    return parseAmpEq(qs, obj);
+  }
+
+  const sepCodes = (!sep ? defSepCodes : charCodes(String(sep)));
+  const eqCodes = (!eq ? defEqCodes : charCodes(String(eq)));
+  const sepLen = sepCodes.length;
+  const eqLen = eqCodes.length;
+
+  let pairs = 1000;
+  if (options && typeof options.maxKeys === 'number') {
+    // -1 is used in place of a value like Infinity for meaning
+    // "unlimited pairs" because of additional checks V8 (at least as of v5.4)
+    // has to do when using variables that contain values like Infinity. Since
+    // `pairs` is always decremented and checked explicitly for 0, -1 works
+    // effectively the same as Infinity, while providing a significant
+    // performance boost.
+    pairs = (options.maxKeys > 0 ? options.maxKeys : -1);
+  }
+
+  let decode = QueryString.unescape;
+  if (options && typeof options.decodeURIComponent === 'function') {
+    decode = options.decodeURIComponent;
+  }
+  const customDecode = (decode !== qsUnescape);
+
+  let lastPos = 0;
+  let sepIdx = 0;
+  let eqIdx = 0;
+  let key = '';
+  let value = '';
+  let keyEncoded = customDecode;
+  let valEncoded = customDecode;
+  const plusChar = (customDecode ? '%20' : ' ');
+  let encodeCheck = 0;
+  for (let i = 0; i < qs.length; ++i) {
+    const code = StringPrototypeCharCodeAt(qs, i);
+
+    // Try matching key/value pair separator (e.g. '&')
+    if (code === sepCodes[sepIdx]) {
+      if (++sepIdx === sepLen) {
+        // Key/value pair separator match!
+        const end = i - sepIdx + 1;
+        if (eqIdx < eqLen) {
+          // We didn't find the (entire) key/value separator
+          if (lastPos < end) {
+            // Treat the substring as part of the key instead of the value
+            key += StringPrototypeSlice(qs, lastPos, end);
+          } else if (key.length === 0) {
+            // We saw an empty substring between separators
+            if (--pairs === 0)
+              return obj;
+            lastPos = i + 1;
+            sepIdx = eqIdx = 0;
+            continue;
+          }
+        } else if (lastPos < end) {
+          value += StringPrototypeSlice(qs, lastPos, end);
+        }
+
+        addKeyVal(obj, key, value, keyEncoded, valEncoded, decode);
+
+        if (--pairs === 0)
+          return obj;
+        keyEncoded = valEncoded = customDecode;
+        key = value = '';
+        encodeCheck = 0;
+        lastPos = i + 1;
+        sepIdx = eqIdx = 0;
+      }
+    } else {
+      sepIdx = 0;
+      // Try matching key/value separator (e.g. '=') if we haven't already
+      if (eqIdx < eqLen) {
+        if (code === eqCodes[eqIdx]) {
+          if (++eqIdx === eqLen) {
+            // Key/value separator match!
+            const end = i - eqIdx + 1;
+            if (lastPos < end)
+              key += StringPrototypeSlice(qs, lastPos, end);
+            encodeCheck = 0;
+            lastPos = i + 1;
+          }
+          continue;
+        } else {
+          eqIdx = 0;
+          if (!keyEncoded) {
+            // Try to match an (valid) encoded byte once to minimize unnecessary
+            // calls to string decoding functions
+            if (code === 37/* % */) {
+              encodeCheck = 1;
+              continue;
+            } else if (encodeCheck > 0) {
+              if (isHexTable[code] === 1) {
+                if (++encodeCheck === 3)
+                  keyEncoded = true;
+                continue;
+              } else {
+                encodeCheck = 0;
+              }
+            }
+          }
+        }
+        if (code === 43/* + */) {
+          if (lastPos < i)
+            key += StringPrototypeSlice(qs, lastPos, i);
+          key += plusChar;
+          lastPos = i + 1;
+        }
+        // Don't let key characters affect value encoding.
+        continue;
+      }
+      if (code === 43/* + */) {
+        if (lastPos < i)
+          value += StringPrototypeSlice(qs, lastPos, i);
+        value += plusChar;
+        lastPos = i + 1;
+      } else if (!valEncoded) {
+        // Try to match an (valid) encoded byte (once) to minimize unnecessary
+        // calls to string decoding functions
+        if (code === 37/* % */) {
+          encodeCheck = 1;
+        } else if (encodeCheck > 0) {
+          if (isHexTable[code] === 1) {
+            if (++encodeCheck === 3)
+              valEncoded = true;
+          } else {
+            encodeCheck = 0;
+          }
+        }
+      }
+    }
+  }
+
+  // Deal with any leftover key or value data
+  if (lastPos < qs.length) {
+    if (eqIdx < eqLen)
+      key += StringPrototypeSlice(qs, lastPos);
+    else if (sepIdx < sepLen)
+      value += StringPrototypeSlice(qs, lastPos);
+  } else if (eqIdx === 0 && key.length === 0) {
+    // We ended on an empty substring
+    return obj;
+  }
+
+  addKeyVal(obj, key, value, keyEncoded, valEncoded, decode);
+
+  return obj;
+}
+
+
+/**
+ * V8 does not optimize functions with try-catch blocks, so we isolate them here
+ * to minimize the damage (Note: no longer true as of V8 5.4 -- but still will
+ * not be inlined).
+ * @param {string} s
+ * @param {(v: string) => string} decoder
+ * @returns {string}
+ */
+function decodeStr(s, decoder) {
+  try {
+    return decoder(s);
+  } catch {
+    return QueryString.unescape(s, true);
+  }
+}
diff --git a/src/Node/Lib/stdio.cjs b/src/Node/Lib/stdio.cjs
new file mode 100644
index 00000000..e9c86889
--- /dev/null
+++ b/src/Node/Lib/stdio.cjs
@@ -0,0 +1,43 @@
+'use strict';
+const { Readable, Writable } = require('stream');
+const { Buffer } = require('buffer');
+const host = __phasisNodeHost;
+
+class WriteStream extends Writable {
+  constructor(fd, options) {
+    super({ ...options, autoDestroy: false });
+    if (fd !== 1 && fd !== 2) throw Object.assign(new Error('Unsupported standard stream descriptor'), { code: 'EBADF' });
+    this.fd = fd;
+    this.isTTY = host.isatty(fd);
+  }
+  _write(chunk, encoding, callback) {
+    try {
+      if (!Buffer.isBuffer(chunk)) chunk = Buffer.from(chunk, encoding);
+      let offset = 0;
+      while (offset < chunk.length) {
+        const count = host.stdioWrite(this.fd, chunk.subarray(offset));
+        if (!count) throw Object.assign(new Error('Standard stream write made no progress'), { code: 'EIO' });
+        offset += count;
+      }
+      callback();
+    } catch (error) { callback(error); }
+  }
+}
+class ReadStream extends Readable {
+  constructor(fd = 0, options) {
+    super(options);
+    if (fd !== 0) throw Object.assign(new Error('Unsupported standard input descriptor'), { code: 'EBADF' });
+    this.fd = fd;
+    this.isTTY = host.isatty(fd);
+    this.isRaw = false;
+    this._timer = null;
+  }
+  _read() {
+    const data = host.stdioRead(this.fd);
+    if (data === undefined) this._timer = setTimeout(() => { this._timer = null; this._read(); }, 10);
+    else this.push(data === null ? null : Buffer.from(data));
+  }
+  _destroy(error, callback) { if (this._timer) clearTimeout(this._timer); callback(error); }
+  setRawMode() { throw Object.assign(new Error('Raw terminal mode is unavailable through PHP streams'), { code: 'ERR_FEATURE_UNAVAILABLE_ON_PLATFORM' }); }
+}
+module.exports = { WriteStream, ReadStream };
diff --git a/src/Node/Lib/stream-consumers.cjs b/src/Node/Lib/stream-consumers.cjs
new file mode 100644
index 00000000..6b680399
--- /dev/null
+++ b/src/Node/Lib/stream-consumers.cjs
@@ -0,0 +1,26 @@
+// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt.
+"use strict";
+
+// stream-consumers-entry.cjs
+var { Buffer } = require("buffer");
+async function blob(stream) {
+  const chunks = [];
+  for await (const chunk of stream) chunks.push(chunk);
+  return new Blob(chunks);
+}
+async function arrayBuffer(stream) {
+  return (await blob(stream)).arrayBuffer();
+}
+async function buffer(stream) {
+  return Buffer.from(await arrayBuffer(stream));
+}
+async function text(stream) {
+  const decoder = new TextDecoder();
+  let output = "";
+  for await (const chunk of stream) output += typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
+  return output + decoder.decode();
+}
+async function json(stream) {
+  return JSON.parse(await text(stream));
+}
+module.exports = { arrayBuffer, blob, buffer, json, text };
diff --git a/src/Node/Lib/stream-promises.cjs b/src/Node/Lib/stream-promises.cjs
new file mode 100644
index 00000000..6ad2a41b
--- /dev/null
+++ b/src/Node/Lib/stream-promises.cjs
@@ -0,0 +1,5 @@
+// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt.
+"use strict";
+
+// stream-promises-entry.cjs
+module.exports = require("stream").promises;
diff --git a/src/Node/Lib/stream-web.cjs b/src/Node/Lib/stream-web.cjs
new file mode 100644
index 00000000..e3fe7459
--- /dev/null
+++ b/src/Node/Lib/stream-web.cjs
@@ -0,0 +1,92 @@
+// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt.
+"use strict";
+
+// stream-web-entry.cjs
+var TextEncoderStream = class {
+  #stream;
+  constructor() {
+    const encoder = new TextEncoder();
+    let pending = "";
+    this.#stream = new TransformStream({
+      transform(value, controller) {
+        let text = pending + `${value}`;
+        pending = "";
+        if (text.length && text.charCodeAt(text.length - 1) >= 55296 && text.charCodeAt(text.length - 1) <= 56319) {
+          pending = text.slice(-1);
+          text = text.slice(0, -1);
+        }
+        if (text.length) controller.enqueue(encoder.encode(text));
+      },
+      flush(controller) {
+        if (pending) controller.enqueue(encoder.encode(pending));
+      }
+    });
+  }
+  get encoding() {
+    return "utf-8";
+  }
+  get readable() {
+    return this.#stream.readable;
+  }
+  get writable() {
+    return this.#stream.writable;
+  }
+  get [Symbol.toStringTag]() {
+    return "TextEncoderStream";
+  }
+};
+var TextDecoderStream = class {
+  #stream;
+  #decoder;
+  constructor(label = "utf-8", options = {}) {
+    this.#decoder = new TextDecoder(label, options);
+    const decoder = this.#decoder;
+    this.#stream = new TransformStream({
+      transform(value, controller) {
+        const text = decoder.decode(value, { stream: true });
+        if (text.length) controller.enqueue(text);
+      },
+      flush(controller) {
+        const text = decoder.decode();
+        if (text.length) controller.enqueue(text);
+      }
+    });
+  }
+  get encoding() {
+    return this.#decoder.encoding;
+  }
+  get fatal() {
+    return this.#decoder.fatal;
+  }
+  get ignoreBOM() {
+    return this.#decoder.ignoreBOM;
+  }
+  get readable() {
+    return this.#stream.readable;
+  }
+  get writable() {
+    return this.#stream.writable;
+  }
+  get [Symbol.toStringTag]() {
+    return "TextDecoderStream";
+  }
+};
+module.exports = {
+  ReadableStream,
+  ReadableStreamDefaultReader,
+  ReadableStreamBYOBReader,
+  ReadableStreamDefaultController,
+  ReadableByteStreamController,
+  ReadableStreamBYOBRequest,
+  WritableStream,
+  WritableStreamDefaultWriter,
+  WritableStreamDefaultController,
+  TransformStream,
+  TransformStreamDefaultController,
+  ByteLengthQueuingStrategy,
+  CountQueuingStrategy,
+  TextEncoderStream,
+  TextDecoderStream,
+  CompressionStream,
+  DecompressionStream
+};
diff --git a/src/Node/Lib/stream.cjs b/src/Node/Lib/stream.cjs
new file mode 100644
index 00000000..eef1bb5d
--- /dev/null
+++ b/src/Node/Lib/stream.cjs
@@ -0,0 +1,5636 @@
+// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt.
+"use strict";
+var __getOwnPropNames = Object.getOwnPropertyNames;
+var __commonJS = (cb, mod) => function __require() {
+  try {
+    return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
+  } catch (e) {
+    throw mod = 0, e;
+  }
+};
+
+// node_modules/readable-stream/lib/ours/primordials.js
+var require_primordials = __commonJS({
+  "node_modules/readable-stream/lib/ours/primordials.js"(exports2, module2) {
+    "use strict";
+    var AggregateError = class extends Error {
+      constructor(errors) {
+        if (!Array.isArray(errors)) {
+          throw new TypeError(`Expected input to be an Array, got ${typeof errors}`);
+        }
+        let message = "";
+        for (let i = 0; i < errors.length; i++) {
+          message += `    ${errors[i].stack}
+`;
+        }
+        super(message);
+        this.name = "AggregateError";
+        this.errors = errors;
+      }
+    };
+    module2.exports = {
+      AggregateError,
+      ArrayIsArray(self) {
+        return Array.isArray(self);
+      },
+      ArrayPrototypeIncludes(self, el) {
+        return self.includes(el);
+      },
+      ArrayPrototypeIndexOf(self, el) {
+        return self.indexOf(el);
+      },
+      ArrayPrototypeJoin(self, sep) {
+        return self.join(sep);
+      },
+      ArrayPrototypeMap(self, fn) {
+        return self.map(fn);
+      },
+      ArrayPrototypePop(self, el) {
+        return self.pop(el);
+      },
+      ArrayPrototypePush(self, el) {
+        return self.push(el);
+      },
+      ArrayPrototypeSlice(self, start, end) {
+        return self.slice(start, end);
+      },
+      Error,
+      FunctionPrototypeCall(fn, thisArgs, ...args) {
+        return fn.call(thisArgs, ...args);
+      },
+      FunctionPrototypeSymbolHasInstance(self, instance) {
+        return Function.prototype[Symbol.hasInstance].call(self, instance);
+      },
+      MathFloor: Math.floor,
+      Number,
+      NumberIsInteger: Number.isInteger,
+      NumberIsNaN: Number.isNaN,
+      NumberMAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER,
+      NumberMIN_SAFE_INTEGER: Number.MIN_SAFE_INTEGER,
+      NumberParseInt: Number.parseInt,
+      ObjectDefineProperties(self, props) {
+        return Object.defineProperties(self, props);
+      },
+      ObjectDefineProperty(self, name, prop) {
+        return Object.defineProperty(self, name, prop);
+      },
+      ObjectGetOwnPropertyDescriptor(self, name) {
+        return Object.getOwnPropertyDescriptor(self, name);
+      },
+      ObjectKeys(obj) {
+        return Object.keys(obj);
+      },
+      ObjectSetPrototypeOf(target, proto) {
+        return Object.setPrototypeOf(target, proto);
+      },
+      Promise,
+      PromisePrototypeCatch(self, fn) {
+        return self.catch(fn);
+      },
+      PromisePrototypeThen(self, thenFn, catchFn) {
+        return self.then(thenFn, catchFn);
+      },
+      PromiseReject(err) {
+        return Promise.reject(err);
+      },
+      PromiseResolve(val) {
+        return Promise.resolve(val);
+      },
+      ReflectApply: Reflect.apply,
+      RegExpPrototypeTest(self, value) {
+        return self.test(value);
+      },
+      SafeSet: Set,
+      String,
+      StringPrototypeSlice(self, start, end) {
+        return self.slice(start, end);
+      },
+      StringPrototypeToLowerCase(self) {
+        return self.toLowerCase();
+      },
+      StringPrototypeToUpperCase(self) {
+        return self.toUpperCase();
+      },
+      StringPrototypeTrim(self) {
+        return self.trim();
+      },
+      Symbol,
+      SymbolFor: Symbol.for,
+      SymbolAsyncIterator: Symbol.asyncIterator,
+      SymbolHasInstance: Symbol.hasInstance,
+      SymbolIterator: Symbol.iterator,
+      SymbolDispose: Symbol.dispose || /* @__PURE__ */ Symbol("Symbol.dispose"),
+      SymbolAsyncDispose: Symbol.asyncDispose || /* @__PURE__ */ Symbol("Symbol.asyncDispose"),
+      TypedArrayPrototypeSet(self, buf, len) {
+        return self.set(buf, len);
+      },
+      Boolean,
+      Uint8Array
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/ours/util/inspect.js
+var require_inspect = __commonJS({
+  "node_modules/readable-stream/lib/ours/util/inspect.js"(exports2, module2) {
+    "use strict";
+    module2.exports = {
+      format(format, ...args) {
+        return format.replace(/%([sdifj])/g, function(...[_unused, type]) {
+          const replacement = args.shift();
+          if (type === "f") {
+            return replacement.toFixed(6);
+          } else if (type === "j") {
+            return JSON.stringify(replacement);
+          } else if (type === "s" && typeof replacement === "object") {
+            const ctor = replacement.constructor !== Object ? replacement.constructor.name : "";
+            return `${ctor} {}`.trim();
+          } else {
+            return replacement.toString();
+          }
+        });
+      },
+      inspect(value) {
+        switch (typeof value) {
+          case "string":
+            if (value.includes("'")) {
+              if (!value.includes('"')) {
+                return `"${value}"`;
+              } else if (!value.includes("`") && !value.includes("${")) {
+                return `\`${value}\``;
+              }
+            }
+            return `'${value}'`;
+          case "number":
+            if (isNaN(value)) {
+              return "NaN";
+            } else if (Object.is(value, -0)) {
+              return String(value);
+            }
+            return value;
+          case "bigint":
+            return `${String(value)}n`;
+          case "boolean":
+          case "undefined":
+            return String(value);
+          case "object":
+            return "{}";
+        }
+      }
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/ours/errors.js
+var require_errors = __commonJS({
+  "node_modules/readable-stream/lib/ours/errors.js"(exports2, module2) {
+    "use strict";
+    var { format, inspect } = require_inspect();
+    var { AggregateError: CustomAggregateError } = require_primordials();
+    var AggregateError = globalThis.AggregateError || CustomAggregateError;
+    var kIsNodeError = /* @__PURE__ */ Symbol("kIsNodeError");
+    var kTypes = [
+      "string",
+      "function",
+      "number",
+      "object",
+      // Accept 'Function' and 'Object' as alternative to the lower cased version.
+      "Function",
+      "Object",
+      "boolean",
+      "bigint",
+      "symbol"
+    ];
+    var classRegExp = /^([A-Z][a-z0-9]*)+$/;
+    var nodeInternalPrefix = "__node_internal_";
+    var codes = {};
+    function assert(value, message) {
+      if (!value) {
+        throw new codes.ERR_INTERNAL_ASSERTION(message);
+      }
+    }
+    function addNumericalSeparator(val) {
+      let res = "";
+      let i = val.length;
+      const start = val[0] === "-" ? 1 : 0;
+      for (; i >= start + 4; i -= 3) {
+        res = `_${val.slice(i - 3, i)}${res}`;
+      }
+      return `${val.slice(0, i)}${res}`;
+    }
+    function getMessage(key, msg, args) {
+      if (typeof msg === "function") {
+        assert(
+          msg.length <= args.length,
+          // Default options do not count.
+          `Code: ${key}; The provided arguments length (${args.length}) does not match the required ones (${msg.length}).`
+        );
+        return msg(...args);
+      }
+      const expectedLength = (msg.match(/%[dfijoOs]/g) || []).length;
+      assert(
+        expectedLength === args.length,
+        `Code: ${key}; The provided arguments length (${args.length}) does not match the required ones (${expectedLength}).`
+      );
+      if (args.length === 0) {
+        return msg;
+      }
+      return format(msg, ...args);
+    }
+    function E(code, message, Base) {
+      if (!Base) {
+        Base = Error;
+      }
+      class NodeError extends Base {
+        constructor(...args) {
+          super(getMessage(code, message, args));
+        }
+        toString() {
+          return `${this.name} [${code}]: ${this.message}`;
+        }
+      }
+      Object.defineProperties(NodeError.prototype, {
+        name: {
+          value: Base.name,
+          writable: true,
+          enumerable: false,
+          configurable: true
+        },
+        toString: {
+          value() {
+            return `${this.name} [${code}]: ${this.message}`;
+          },
+          writable: true,
+          enumerable: false,
+          configurable: true
+        }
+      });
+      NodeError.prototype.code = code;
+      NodeError.prototype[kIsNodeError] = true;
+      codes[code] = NodeError;
+    }
+    function hideStackFrames(fn) {
+      const hidden = nodeInternalPrefix + fn.name;
+      Object.defineProperty(fn, "name", {
+        value: hidden
+      });
+      return fn;
+    }
+    function aggregateTwoErrors(innerError, outerError) {
+      if (innerError && outerError && innerError !== outerError) {
+        if (Array.isArray(outerError.errors)) {
+          outerError.errors.push(innerError);
+          return outerError;
+        }
+        const err = new AggregateError([outerError, innerError], outerError.message);
+        err.code = outerError.code;
+        return err;
+      }
+      return innerError || outerError;
+    }
+    var AbortError = class extends Error {
+      constructor(message = "The operation was aborted", options = void 0) {
+        if (options !== void 0 && typeof options !== "object") {
+          throw new codes.ERR_INVALID_ARG_TYPE("options", "Object", options);
+        }
+        super(message, options);
+        this.code = "ABORT_ERR";
+        this.name = "AbortError";
+      }
+    };
+    E("ERR_ASSERTION", "%s", Error);
+    E(
+      "ERR_INVALID_ARG_TYPE",
+      (name, expected, actual) => {
+        assert(typeof name === "string", "'name' must be a string");
+        if (!Array.isArray(expected)) {
+          expected = [expected];
+        }
+        let msg = "The ";
+        if (name.endsWith(" argument")) {
+          msg += `${name} `;
+        } else {
+          msg += `"${name}" ${name.includes(".") ? "property" : "argument"} `;
+        }
+        msg += "must be ";
+        const types = [];
+        const instances = [];
+        const other = [];
+        for (const value of expected) {
+          assert(typeof value === "string", "All expected entries have to be of type string");
+          if (kTypes.includes(value)) {
+            types.push(value.toLowerCase());
+          } else if (classRegExp.test(value)) {
+            instances.push(value);
+          } else {
+            assert(value !== "object", 'The value "object" should be written as "Object"');
+            other.push(value);
+          }
+        }
+        if (instances.length > 0) {
+          const pos = types.indexOf("object");
+          if (pos !== -1) {
+            types.splice(types, pos, 1);
+            instances.push("Object");
+          }
+        }
+        if (types.length > 0) {
+          switch (types.length) {
+            case 1:
+              msg += `of type ${types[0]}`;
+              break;
+            case 2:
+              msg += `one of type ${types[0]} or ${types[1]}`;
+              break;
+            default: {
+              const last = types.pop();
+              msg += `one of type ${types.join(", ")}, or ${last}`;
+            }
+          }
+          if (instances.length > 0 || other.length > 0) {
+            msg += " or ";
+          }
+        }
+        if (instances.length > 0) {
+          switch (instances.length) {
+            case 1:
+              msg += `an instance of ${instances[0]}`;
+              break;
+            case 2:
+              msg += `an instance of ${instances[0]} or ${instances[1]}`;
+              break;
+            default: {
+              const last = instances.pop();
+              msg += `an instance of ${instances.join(", ")}, or ${last}`;
+            }
+          }
+          if (other.length > 0) {
+            msg += " or ";
+          }
+        }
+        switch (other.length) {
+          case 0:
+            break;
+          case 1:
+            if (other[0].toLowerCase() !== other[0]) {
+              msg += "an ";
+            }
+            msg += `${other[0]}`;
+            break;
+          case 2:
+            msg += `one of ${other[0]} or ${other[1]}`;
+            break;
+          default: {
+            const last = other.pop();
+            msg += `one of ${other.join(", ")}, or ${last}`;
+          }
+        }
+        if (actual == null) {
+          msg += `. Received ${actual}`;
+        } else if (typeof actual === "function" && actual.name) {
+          msg += `. Received function ${actual.name}`;
+        } else if (typeof actual === "object") {
+          var _actual$constructor;
+          if ((_actual$constructor = actual.constructor) !== null && _actual$constructor !== void 0 && _actual$constructor.name) {
+            msg += `. Received an instance of ${actual.constructor.name}`;
+          } else {
+            const inspected = inspect(actual, {
+              depth: -1
+            });
+            msg += `. Received ${inspected}`;
+          }
+        } else {
+          let inspected = inspect(actual, {
+            colors: false
+          });
+          if (inspected.length > 25) {
+            inspected = `${inspected.slice(0, 25)}...`;
+          }
+          msg += `. Received type ${typeof actual} (${inspected})`;
+        }
+        return msg;
+      },
+      TypeError
+    );
+    E(
+      "ERR_INVALID_ARG_VALUE",
+      (name, value, reason = "is invalid") => {
+        let inspected = inspect(value);
+        if (inspected.length > 128) {
+          inspected = inspected.slice(0, 128) + "...";
+        }
+        const type = name.includes(".") ? "property" : "argument";
+        return `The ${type} '${name}' ${reason}. Received ${inspected}`;
+      },
+      TypeError
+    );
+    E(
+      "ERR_INVALID_RETURN_VALUE",
+      (input, name, value) => {
+        var _value$constructor;
+        const type = value !== null && value !== void 0 && (_value$constructor = value.constructor) !== null && _value$constructor !== void 0 && _value$constructor.name ? `instance of ${value.constructor.name}` : `type ${typeof value}`;
+        return `Expected ${input} to be returned from the "${name}" function but got ${type}.`;
+      },
+      TypeError
+    );
+    E(
+      "ERR_MISSING_ARGS",
+      (...args) => {
+        assert(args.length > 0, "At least one arg needs to be specified");
+        let msg;
+        const len = args.length;
+        args = (Array.isArray(args) ? args : [args]).map((a) => `"${a}"`).join(" or ");
+        switch (len) {
+          case 1:
+            msg += `The ${args[0]} argument`;
+            break;
+          case 2:
+            msg += `The ${args[0]} and ${args[1]} arguments`;
+            break;
+          default:
+            {
+              const last = args.pop();
+              msg += `The ${args.join(", ")}, and ${last} arguments`;
+            }
+            break;
+        }
+        return `${msg} must be specified`;
+      },
+      TypeError
+    );
+    E(
+      "ERR_OUT_OF_RANGE",
+      (str, range, input) => {
+        assert(range, 'Missing "range" argument');
+        let received;
+        if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) {
+          received = addNumericalSeparator(String(input));
+        } else if (typeof input === "bigint") {
+          received = String(input);
+          const limit = BigInt(2) ** BigInt(32);
+          if (input > limit || input < -limit) {
+            received = addNumericalSeparator(received);
+          }
+          received += "n";
+        } else {
+          received = inspect(input);
+        }
+        return `The value of "${str}" is out of range. It must be ${range}. Received ${received}`;
+      },
+      RangeError
+    );
+    E("ERR_MULTIPLE_CALLBACK", "Callback called multiple times", Error);
+    E("ERR_METHOD_NOT_IMPLEMENTED", "The %s method is not implemented", Error);
+    E("ERR_STREAM_ALREADY_FINISHED", "Cannot call %s after a stream was finished", Error);
+    E("ERR_STREAM_CANNOT_PIPE", "Cannot pipe, not readable", Error);
+    E("ERR_STREAM_DESTROYED", "Cannot call %s after a stream was destroyed", Error);
+    E("ERR_STREAM_NULL_VALUES", "May not write null values to stream", TypeError);
+    E("ERR_STREAM_PREMATURE_CLOSE", "Premature close", Error);
+    E("ERR_STREAM_PUSH_AFTER_EOF", "stream.push() after EOF", Error);
+    E("ERR_STREAM_UNSHIFT_AFTER_END_EVENT", "stream.unshift() after end event", Error);
+    E("ERR_STREAM_WRITE_AFTER_END", "write after end", Error);
+    E("ERR_UNKNOWN_ENCODING", "Unknown encoding: %s", TypeError);
+    module2.exports = {
+      AbortError,
+      aggregateTwoErrors: hideStackFrames(aggregateTwoErrors),
+      hideStackFrames,
+      codes
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/ours/util.js
+var require_util = __commonJS({
+  "node_modules/readable-stream/lib/ours/util.js"(exports2, module2) {
+    "use strict";
+    var bufferModule = require("buffer");
+    var { format, inspect } = require_inspect();
+    var {
+      codes: { ERR_INVALID_ARG_TYPE }
+    } = require_errors();
+    var { kResistStopPropagation, AggregateError, SymbolDispose } = require_primordials();
+    var AbortSignal = globalThis.AbortSignal || require("abort-controller").AbortSignal;
+    var AbortController = globalThis.AbortController || require("abort-controller").AbortController;
+    var AsyncFunction = Object.getPrototypeOf(async function() {
+    }).constructor;
+    var Blob = globalThis.Blob || bufferModule.Blob;
+    var isBlob = typeof Blob !== "undefined" ? function isBlob2(b) {
+      return b instanceof Blob;
+    } : function isBlob2(b) {
+      return false;
+    };
+    var validateAbortSignal = (signal, name) => {
+      if (signal !== void 0 && (signal === null || typeof signal !== "object" || !("aborted" in signal))) {
+        throw new ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal);
+      }
+    };
+    var validateFunction = (value, name) => {
+      if (typeof value !== "function") {
+        throw new ERR_INVALID_ARG_TYPE(name, "Function", value);
+      }
+    };
+    module2.exports = {
+      AggregateError,
+      kEmptyObject: Object.freeze({}),
+      once(callback) {
+        let called = false;
+        return function(...args) {
+          if (called) {
+            return;
+          }
+          called = true;
+          callback.apply(this, args);
+        };
+      },
+      createDeferredPromise: function() {
+        let resolve;
+        let reject;
+        const promise = new Promise((res, rej) => {
+          resolve = res;
+          reject = rej;
+        });
+        return {
+          promise,
+          resolve,
+          reject
+        };
+      },
+      promisify(fn) {
+        return new Promise((resolve, reject) => {
+          fn((err, ...args) => {
+            if (err) {
+              return reject(err);
+            }
+            return resolve(...args);
+          });
+        });
+      },
+      debuglog() {
+        return function() {
+        };
+      },
+      format,
+      inspect,
+      types: {
+        isAsyncFunction(fn) {
+          return fn instanceof AsyncFunction;
+        },
+        isArrayBufferView(arr) {
+          return ArrayBuffer.isView(arr);
+        }
+      },
+      isBlob,
+      deprecate(fn, message) {
+        return fn;
+      },
+      addAbortListener: require("events").addAbortListener || function addAbortListener(signal, listener) {
+        if (signal === void 0) {
+          throw new ERR_INVALID_ARG_TYPE("signal", "AbortSignal", signal);
+        }
+        validateAbortSignal(signal, "signal");
+        validateFunction(listener, "listener");
+        let removeEventListener;
+        if (signal.aborted) {
+          queueMicrotask(() => listener());
+        } else {
+          signal.addEventListener("abort", listener, {
+            __proto__: null,
+            once: true,
+            [kResistStopPropagation]: true
+          });
+          removeEventListener = () => {
+            signal.removeEventListener("abort", listener);
+          };
+        }
+        return {
+          __proto__: null,
+          [SymbolDispose]() {
+            var _removeEventListener;
+            (_removeEventListener = removeEventListener) === null || _removeEventListener === void 0 ? void 0 : _removeEventListener();
+          }
+        };
+      },
+      AbortSignalAny: AbortSignal.any || function AbortSignalAny(signals) {
+        if (signals.length === 1) {
+          return signals[0];
+        }
+        const ac = new AbortController();
+        const abort = () => ac.abort();
+        signals.forEach((signal) => {
+          validateAbortSignal(signal, "signals");
+          signal.addEventListener("abort", abort, {
+            once: true
+          });
+        });
+        ac.signal.addEventListener(
+          "abort",
+          () => {
+            signals.forEach((signal) => signal.removeEventListener("abort", abort));
+          },
+          {
+            once: true
+          }
+        );
+        return ac.signal;
+      }
+    };
+    module2.exports.promisify.custom = /* @__PURE__ */ Symbol.for("nodejs.util.promisify.custom");
+  }
+});
+
+// node_modules/readable-stream/lib/internal/validators.js
+var require_validators = __commonJS({
+  "node_modules/readable-stream/lib/internal/validators.js"(exports2, module2) {
+    "use strict";
+    var {
+      ArrayIsArray,
+      ArrayPrototypeIncludes,
+      ArrayPrototypeJoin,
+      ArrayPrototypeMap,
+      NumberIsInteger,
+      NumberIsNaN,
+      NumberMAX_SAFE_INTEGER,
+      NumberMIN_SAFE_INTEGER,
+      NumberParseInt,
+      ObjectPrototypeHasOwnProperty,
+      RegExpPrototypeExec,
+      String: String2,
+      StringPrototypeToUpperCase,
+      StringPrototypeTrim
+    } = require_primordials();
+    var {
+      hideStackFrames,
+      codes: { ERR_SOCKET_BAD_PORT, ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, ERR_OUT_OF_RANGE, ERR_UNKNOWN_SIGNAL }
+    } = require_errors();
+    var { normalizeEncoding } = require_util();
+    var { isAsyncFunction, isArrayBufferView } = require_util().types;
+    var signals = {};
+    function isInt32(value) {
+      return value === (value | 0);
+    }
+    function isUint32(value) {
+      return value === value >>> 0;
+    }
+    var octalReg = /^[0-7]+$/;
+    var modeDesc = "must be a 32-bit unsigned integer or an octal string";
+    function parseFileMode(value, name, def) {
+      if (typeof value === "undefined") {
+        value = def;
+      }
+      if (typeof value === "string") {
+        if (RegExpPrototypeExec(octalReg, value) === null) {
+          throw new ERR_INVALID_ARG_VALUE(name, value, modeDesc);
+        }
+        value = NumberParseInt(value, 8);
+      }
+      validateUint32(value, name);
+      return value;
+    }
+    var validateInteger = hideStackFrames((value, name, min = NumberMIN_SAFE_INTEGER, max = NumberMAX_SAFE_INTEGER) => {
+      if (typeof value !== "number") throw new ERR_INVALID_ARG_TYPE(name, "number", value);
+      if (!NumberIsInteger(value)) throw new ERR_OUT_OF_RANGE(name, "an integer", value);
+      if (value < min || value > max) throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+    });
+    var validateInt32 = hideStackFrames((value, name, min = -2147483648, max = 2147483647) => {
+      if (typeof value !== "number") {
+        throw new ERR_INVALID_ARG_TYPE(name, "number", value);
+      }
+      if (!NumberIsInteger(value)) {
+        throw new ERR_OUT_OF_RANGE(name, "an integer", value);
+      }
+      if (value < min || value > max) {
+        throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+      }
+    });
+    var validateUint32 = hideStackFrames((value, name, positive = false) => {
+      if (typeof value !== "number") {
+        throw new ERR_INVALID_ARG_TYPE(name, "number", value);
+      }
+      if (!NumberIsInteger(value)) {
+        throw new ERR_OUT_OF_RANGE(name, "an integer", value);
+      }
+      const min = positive ? 1 : 0;
+      const max = 4294967295;
+      if (value < min || value > max) {
+        throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
+      }
+    });
+    function validateString(value, name) {
+      if (typeof value !== "string") throw new ERR_INVALID_ARG_TYPE(name, "string", value);
+    }
+    function validateNumber(value, name, min = void 0, max) {
+      if (typeof value !== "number") throw new ERR_INVALID_ARG_TYPE(name, "number", value);
+      if (min != null && value < min || max != null && value > max || (min != null || max != null) && NumberIsNaN(value)) {
+        throw new ERR_OUT_OF_RANGE(
+          name,
+          `${min != null ? `>= ${min}` : ""}${min != null && max != null ? " && " : ""}${max != null ? `<= ${max}` : ""}`,
+          value
+        );
+      }
+    }
+    var validateOneOf = hideStackFrames((value, name, oneOf) => {
+      if (!ArrayPrototypeIncludes(oneOf, value)) {
+        const allowed = ArrayPrototypeJoin(
+          ArrayPrototypeMap(oneOf, (v) => typeof v === "string" ? `'${v}'` : String2(v)),
+          ", "
+        );
+        const reason = "must be one of: " + allowed;
+        throw new ERR_INVALID_ARG_VALUE(name, value, reason);
+      }
+    });
+    function validateBoolean(value, name) {
+      if (typeof value !== "boolean") throw new ERR_INVALID_ARG_TYPE(name, "boolean", value);
+    }
+    function getOwnPropertyValueOrDefault(options, key, defaultValue) {
+      return options == null || !ObjectPrototypeHasOwnProperty(options, key) ? defaultValue : options[key];
+    }
+    var validateObject = hideStackFrames((value, name, options = null) => {
+      const allowArray = getOwnPropertyValueOrDefault(options, "allowArray", false);
+      const allowFunction = getOwnPropertyValueOrDefault(options, "allowFunction", false);
+      const nullable = getOwnPropertyValueOrDefault(options, "nullable", false);
+      if (!nullable && value === null || !allowArray && ArrayIsArray(value) || typeof value !== "object" && (!allowFunction || typeof value !== "function")) {
+        throw new ERR_INVALID_ARG_TYPE(name, "Object", value);
+      }
+    });
+    var validateDictionary = hideStackFrames((value, name) => {
+      if (value != null && typeof value !== "object" && typeof value !== "function") {
+        throw new ERR_INVALID_ARG_TYPE(name, "a dictionary", value);
+      }
+    });
+    var validateArray = hideStackFrames((value, name, minLength = 0) => {
+      if (!ArrayIsArray(value)) {
+        throw new ERR_INVALID_ARG_TYPE(name, "Array", value);
+      }
+      if (value.length < minLength) {
+        const reason = `must be longer than ${minLength}`;
+        throw new ERR_INVALID_ARG_VALUE(name, value, reason);
+      }
+    });
+    function validateStringArray(value, name) {
+      validateArray(value, name);
+      for (let i = 0; i < value.length; i++) {
+        validateString(value[i], `${name}[${i}]`);
+      }
+    }
+    function validateBooleanArray(value, name) {
+      validateArray(value, name);
+      for (let i = 0; i < value.length; i++) {
+        validateBoolean(value[i], `${name}[${i}]`);
+      }
+    }
+    function validateAbortSignalArray(value, name) {
+      validateArray(value, name);
+      for (let i = 0; i < value.length; i++) {
+        const signal = value[i];
+        const indexedName = `${name}[${i}]`;
+        if (signal == null) {
+          throw new ERR_INVALID_ARG_TYPE(indexedName, "AbortSignal", signal);
+        }
+        validateAbortSignal(signal, indexedName);
+      }
+    }
+    function validateSignalName(signal, name = "signal") {
+      validateString(signal, name);
+      if (signals[signal] === void 0) {
+        if (signals[StringPrototypeToUpperCase(signal)] !== void 0) {
+          throw new ERR_UNKNOWN_SIGNAL(signal + " (signals must use all capital letters)");
+        }
+        throw new ERR_UNKNOWN_SIGNAL(signal);
+      }
+    }
+    var validateBuffer = hideStackFrames((buffer, name = "buffer") => {
+      if (!isArrayBufferView(buffer)) {
+        throw new ERR_INVALID_ARG_TYPE(name, ["Buffer", "TypedArray", "DataView"], buffer);
+      }
+    });
+    function validateEncoding(data, encoding) {
+      const normalizedEncoding = normalizeEncoding(encoding);
+      const length = data.length;
+      if (normalizedEncoding === "hex" && length % 2 !== 0) {
+        throw new ERR_INVALID_ARG_VALUE("encoding", encoding, `is invalid for data of length ${length}`);
+      }
+    }
+    function validatePort(port, name = "Port", allowZero = true) {
+      if (typeof port !== "number" && typeof port !== "string" || typeof port === "string" && StringPrototypeTrim(port).length === 0 || +port !== +port >>> 0 || port > 65535 || port === 0 && !allowZero) {
+        throw new ERR_SOCKET_BAD_PORT(name, port, allowZero);
+      }
+      return port | 0;
+    }
+    var validateAbortSignal = hideStackFrames((signal, name) => {
+      if (signal !== void 0 && (signal === null || typeof signal !== "object" || !("aborted" in signal))) {
+        throw new ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal);
+      }
+    });
+    var validateFunction = hideStackFrames((value, name) => {
+      if (typeof value !== "function") throw new ERR_INVALID_ARG_TYPE(name, "Function", value);
+    });
+    var validatePlainFunction = hideStackFrames((value, name) => {
+      if (typeof value !== "function" || isAsyncFunction(value)) throw new ERR_INVALID_ARG_TYPE(name, "Function", value);
+    });
+    var validateUndefined = hideStackFrames((value, name) => {
+      if (value !== void 0) throw new ERR_INVALID_ARG_TYPE(name, "undefined", value);
+    });
+    function validateUnion(value, name, union) {
+      if (!ArrayPrototypeIncludes(union, value)) {
+        throw new ERR_INVALID_ARG_TYPE(name, `('${ArrayPrototypeJoin(union, "|")}')`, value);
+      }
+    }
+    var linkValueRegExp = /^(?:<[^>]*>)(?:\s*;\s*[^;"\s]+(?:=(")?[^;"\s]*\1)?)*$/;
+    function validateLinkHeaderFormat(value, name) {
+      if (typeof value === "undefined" || !RegExpPrototypeExec(linkValueRegExp, value)) {
+        throw new ERR_INVALID_ARG_VALUE(
+          name,
+          value,
+          'must be an array or string of format "; rel=preload; as=style"'
+        );
+      }
+    }
+    function validateLinkHeaderValue(hints) {
+      if (typeof hints === "string") {
+        validateLinkHeaderFormat(hints, "hints");
+        return hints;
+      } else if (ArrayIsArray(hints)) {
+        const hintsLength = hints.length;
+        let result = "";
+        if (hintsLength === 0) {
+          return result;
+        }
+        for (let i = 0; i < hintsLength; i++) {
+          const link = hints[i];
+          validateLinkHeaderFormat(link, "hints");
+          result += link;
+          if (i !== hintsLength - 1) {
+            result += ", ";
+          }
+        }
+        return result;
+      }
+      throw new ERR_INVALID_ARG_VALUE(
+        "hints",
+        hints,
+        'must be an array or string of format "; rel=preload; as=style"'
+      );
+    }
+    module2.exports = {
+      isInt32,
+      isUint32,
+      parseFileMode,
+      validateArray,
+      validateStringArray,
+      validateBooleanArray,
+      validateAbortSignalArray,
+      validateBoolean,
+      validateBuffer,
+      validateDictionary,
+      validateEncoding,
+      validateFunction,
+      validateInt32,
+      validateInteger,
+      validateNumber,
+      validateObject,
+      validateOneOf,
+      validatePlainFunction,
+      validatePort,
+      validateSignalName,
+      validateString,
+      validateUint32,
+      validateUndefined,
+      validateUnion,
+      validateAbortSignal,
+      validateLinkHeaderValue
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/shims/process.js
+var require_process = __commonJS({
+  "node_modules/readable-stream/lib/internal/shims/process.js"(exports2, module2) {
+    "use strict";
+    var process2 = ((base, esmKey, keys, isValid) => {
+      if (esmKey in base && base[esmKey] === true) {
+        let candidate;
+        for (const key of keys) {
+          if (!(key in base)) {
+            continue;
+          }
+          candidate = base[key];
+          if (isValid(candidate)) {
+            return candidate;
+          }
+        }
+      }
+      return base;
+    })(require("process"), "__esModule", ["default", "process"], (candidate) => "nextTick" in candidate);
+    module2.exports = process2;
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/utils.js
+var require_utils = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/utils.js"(exports2, module2) {
+    "use strict";
+    var { SymbolAsyncIterator, SymbolIterator, SymbolFor } = require_primordials();
+    var kIsDestroyed = SymbolFor("nodejs.stream.destroyed");
+    var kIsErrored = SymbolFor("nodejs.stream.errored");
+    var kIsReadable = SymbolFor("nodejs.stream.readable");
+    var kIsWritable = SymbolFor("nodejs.stream.writable");
+    var kIsDisturbed = SymbolFor("nodejs.stream.disturbed");
+    var kIsClosedPromise = SymbolFor("nodejs.webstream.isClosedPromise");
+    var kControllerErrorFunction = SymbolFor("nodejs.webstream.controllerErrorFunction");
+    function isReadableNodeStream(obj, strict = false) {
+      var _obj$_readableState;
+      return !!(obj && typeof obj.pipe === "function" && typeof obj.on === "function" && (!strict || typeof obj.pause === "function" && typeof obj.resume === "function") && (!obj._writableState || ((_obj$_readableState = obj._readableState) === null || _obj$_readableState === void 0 ? void 0 : _obj$_readableState.readable) !== false) && // Duplex
+      (!obj._writableState || obj._readableState));
+    }
+    function isWritableNodeStream(obj) {
+      var _obj$_writableState;
+      return !!(obj && typeof obj.write === "function" && typeof obj.on === "function" && (!obj._readableState || ((_obj$_writableState = obj._writableState) === null || _obj$_writableState === void 0 ? void 0 : _obj$_writableState.writable) !== false));
+    }
+    function isDuplexNodeStream(obj) {
+      return !!(obj && typeof obj.pipe === "function" && obj._readableState && typeof obj.on === "function" && typeof obj.write === "function");
+    }
+    function isNodeStream(obj) {
+      return obj && (obj._readableState || obj._writableState || typeof obj.write === "function" && typeof obj.on === "function" || typeof obj.pipe === "function" && typeof obj.on === "function");
+    }
+    function isReadableStream(obj) {
+      return !!(obj && !isNodeStream(obj) && typeof obj.pipeThrough === "function" && typeof obj.getReader === "function" && typeof obj.cancel === "function");
+    }
+    function isWritableStream(obj) {
+      return !!(obj && !isNodeStream(obj) && typeof obj.getWriter === "function" && typeof obj.abort === "function");
+    }
+    function isTransformStream(obj) {
+      return !!(obj && !isNodeStream(obj) && typeof obj.readable === "object" && typeof obj.writable === "object");
+    }
+    function isWebStream(obj) {
+      return isReadableStream(obj) || isWritableStream(obj) || isTransformStream(obj);
+    }
+    function isIterable(obj, isAsync) {
+      if (obj == null) return false;
+      if (isAsync === true) return typeof obj[SymbolAsyncIterator] === "function";
+      if (isAsync === false) return typeof obj[SymbolIterator] === "function";
+      return typeof obj[SymbolAsyncIterator] === "function" || typeof obj[SymbolIterator] === "function";
+    }
+    function isDestroyed(stream) {
+      if (!isNodeStream(stream)) return null;
+      const wState = stream._writableState;
+      const rState = stream._readableState;
+      const state = wState || rState;
+      return !!(stream.destroyed || stream[kIsDestroyed] || state !== null && state !== void 0 && state.destroyed);
+    }
+    function isWritableEnded(stream) {
+      if (!isWritableNodeStream(stream)) return null;
+      if (stream.writableEnded === true) return true;
+      const wState = stream._writableState;
+      if (wState !== null && wState !== void 0 && wState.errored) return false;
+      if (typeof (wState === null || wState === void 0 ? void 0 : wState.ended) !== "boolean") return null;
+      return wState.ended;
+    }
+    function isWritableFinished(stream, strict) {
+      if (!isWritableNodeStream(stream)) return null;
+      if (stream.writableFinished === true) return true;
+      const wState = stream._writableState;
+      if (wState !== null && wState !== void 0 && wState.errored) return false;
+      if (typeof (wState === null || wState === void 0 ? void 0 : wState.finished) !== "boolean") return null;
+      return !!(wState.finished || strict === false && wState.ended === true && wState.length === 0);
+    }
+    function isReadableEnded(stream) {
+      if (!isReadableNodeStream(stream)) return null;
+      if (stream.readableEnded === true) return true;
+      const rState = stream._readableState;
+      if (!rState || rState.errored) return false;
+      if (typeof (rState === null || rState === void 0 ? void 0 : rState.ended) !== "boolean") return null;
+      return rState.ended;
+    }
+    function isReadableFinished(stream, strict) {
+      if (!isReadableNodeStream(stream)) return null;
+      const rState = stream._readableState;
+      if (rState !== null && rState !== void 0 && rState.errored) return false;
+      if (typeof (rState === null || rState === void 0 ? void 0 : rState.endEmitted) !== "boolean") return null;
+      return !!(rState.endEmitted || strict === false && rState.ended === true && rState.length === 0);
+    }
+    function isReadable(stream) {
+      if (stream && stream[kIsReadable] != null) return stream[kIsReadable];
+      if (typeof (stream === null || stream === void 0 ? void 0 : stream.readable) !== "boolean") return null;
+      if (isDestroyed(stream)) return false;
+      return isReadableNodeStream(stream) && stream.readable && !isReadableFinished(stream);
+    }
+    function isWritable(stream) {
+      if (stream && stream[kIsWritable] != null) return stream[kIsWritable];
+      if (typeof (stream === null || stream === void 0 ? void 0 : stream.writable) !== "boolean") return null;
+      if (isDestroyed(stream)) return false;
+      return isWritableNodeStream(stream) && stream.writable && !isWritableEnded(stream);
+    }
+    function isFinished(stream, opts) {
+      if (!isNodeStream(stream)) {
+        return null;
+      }
+      if (isDestroyed(stream)) {
+        return true;
+      }
+      if ((opts === null || opts === void 0 ? void 0 : opts.readable) !== false && isReadable(stream)) {
+        return false;
+      }
+      if ((opts === null || opts === void 0 ? void 0 : opts.writable) !== false && isWritable(stream)) {
+        return false;
+      }
+      return true;
+    }
+    function isWritableErrored(stream) {
+      var _stream$_writableStat, _stream$_writableStat2;
+      if (!isNodeStream(stream)) {
+        return null;
+      }
+      if (stream.writableErrored) {
+        return stream.writableErrored;
+      }
+      return (_stream$_writableStat = (_stream$_writableStat2 = stream._writableState) === null || _stream$_writableStat2 === void 0 ? void 0 : _stream$_writableStat2.errored) !== null && _stream$_writableStat !== void 0 ? _stream$_writableStat : null;
+    }
+    function isReadableErrored(stream) {
+      var _stream$_readableStat, _stream$_readableStat2;
+      if (!isNodeStream(stream)) {
+        return null;
+      }
+      if (stream.readableErrored) {
+        return stream.readableErrored;
+      }
+      return (_stream$_readableStat = (_stream$_readableStat2 = stream._readableState) === null || _stream$_readableStat2 === void 0 ? void 0 : _stream$_readableStat2.errored) !== null && _stream$_readableStat !== void 0 ? _stream$_readableStat : null;
+    }
+    function isClosed(stream) {
+      if (!isNodeStream(stream)) {
+        return null;
+      }
+      if (typeof stream.closed === "boolean") {
+        return stream.closed;
+      }
+      const wState = stream._writableState;
+      const rState = stream._readableState;
+      if (typeof (wState === null || wState === void 0 ? void 0 : wState.closed) === "boolean" || typeof (rState === null || rState === void 0 ? void 0 : rState.closed) === "boolean") {
+        return (wState === null || wState === void 0 ? void 0 : wState.closed) || (rState === null || rState === void 0 ? void 0 : rState.closed);
+      }
+      if (typeof stream._closed === "boolean" && isOutgoingMessage(stream)) {
+        return stream._closed;
+      }
+      return null;
+    }
+    function isOutgoingMessage(stream) {
+      return typeof stream._closed === "boolean" && typeof stream._defaultKeepAlive === "boolean" && typeof stream._removedConnection === "boolean" && typeof stream._removedContLen === "boolean";
+    }
+    function isServerResponse(stream) {
+      return typeof stream._sent100 === "boolean" && isOutgoingMessage(stream);
+    }
+    function isServerRequest(stream) {
+      var _stream$req;
+      return typeof stream._consuming === "boolean" && typeof stream._dumped === "boolean" && ((_stream$req = stream.req) === null || _stream$req === void 0 ? void 0 : _stream$req.upgradeOrConnect) === void 0;
+    }
+    function willEmitClose(stream) {
+      if (!isNodeStream(stream)) return null;
+      const wState = stream._writableState;
+      const rState = stream._readableState;
+      const state = wState || rState;
+      return !state && isServerResponse(stream) || !!(state && state.autoDestroy && state.emitClose && state.closed === false);
+    }
+    function isDisturbed(stream) {
+      var _stream$kIsDisturbed;
+      return !!(stream && ((_stream$kIsDisturbed = stream[kIsDisturbed]) !== null && _stream$kIsDisturbed !== void 0 ? _stream$kIsDisturbed : stream.readableDidRead || stream.readableAborted));
+    }
+    function isErrored(stream) {
+      var _ref, _ref2, _ref3, _ref4, _ref5, _stream$kIsErrored, _stream$_readableStat3, _stream$_writableStat3, _stream$_readableStat4, _stream$_writableStat4;
+      return !!(stream && ((_ref = (_ref2 = (_ref3 = (_ref4 = (_ref5 = (_stream$kIsErrored = stream[kIsErrored]) !== null && _stream$kIsErrored !== void 0 ? _stream$kIsErrored : stream.readableErrored) !== null && _ref5 !== void 0 ? _ref5 : stream.writableErrored) !== null && _ref4 !== void 0 ? _ref4 : (_stream$_readableStat3 = stream._readableState) === null || _stream$_readableStat3 === void 0 ? void 0 : _stream$_readableStat3.errorEmitted) !== null && _ref3 !== void 0 ? _ref3 : (_stream$_writableStat3 = stream._writableState) === null || _stream$_writableStat3 === void 0 ? void 0 : _stream$_writableStat3.errorEmitted) !== null && _ref2 !== void 0 ? _ref2 : (_stream$_readableStat4 = stream._readableState) === null || _stream$_readableStat4 === void 0 ? void 0 : _stream$_readableStat4.errored) !== null && _ref !== void 0 ? _ref : (_stream$_writableStat4 = stream._writableState) === null || _stream$_writableStat4 === void 0 ? void 0 : _stream$_writableStat4.errored));
+    }
+    module2.exports = {
+      isDestroyed,
+      kIsDestroyed,
+      isDisturbed,
+      kIsDisturbed,
+      isErrored,
+      kIsErrored,
+      isReadable,
+      kIsReadable,
+      kIsClosedPromise,
+      kControllerErrorFunction,
+      kIsWritable,
+      isClosed,
+      isDuplexNodeStream,
+      isFinished,
+      isIterable,
+      isReadableNodeStream,
+      isReadableStream,
+      isReadableEnded,
+      isReadableFinished,
+      isReadableErrored,
+      isNodeStream,
+      isWebStream,
+      isWritable,
+      isWritableNodeStream,
+      isWritableStream,
+      isWritableEnded,
+      isWritableFinished,
+      isWritableErrored,
+      isServerRequest,
+      isServerResponse,
+      willEmitClose,
+      isTransformStream
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/end-of-stream.js
+var require_end_of_stream = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/end-of-stream.js"(exports2, module2) {
+    "use strict";
+    var process2 = require_process();
+    var { AbortError, codes } = require_errors();
+    var { ERR_INVALID_ARG_TYPE, ERR_STREAM_PREMATURE_CLOSE } = codes;
+    var { kEmptyObject, once } = require_util();
+    var { validateAbortSignal, validateFunction, validateObject, validateBoolean } = require_validators();
+    var { Promise: Promise2, PromisePrototypeThen, SymbolDispose } = require_primordials();
+    var {
+      isClosed,
+      isReadable,
+      isReadableNodeStream,
+      isReadableStream,
+      isReadableFinished,
+      isReadableErrored,
+      isWritable,
+      isWritableNodeStream,
+      isWritableStream,
+      isWritableFinished,
+      isWritableErrored,
+      isNodeStream,
+      willEmitClose: _willEmitClose,
+      kIsClosedPromise
+    } = require_utils();
+    var addAbortListener;
+    function isRequest(stream) {
+      return stream.setHeader && typeof stream.abort === "function";
+    }
+    var nop = () => {
+    };
+    function eos(stream, options, callback) {
+      var _options$readable, _options$writable;
+      if (arguments.length === 2) {
+        callback = options;
+        options = kEmptyObject;
+      } else if (options == null) {
+        options = kEmptyObject;
+      } else {
+        validateObject(options, "options");
+      }
+      validateFunction(callback, "callback");
+      validateAbortSignal(options.signal, "options.signal");
+      callback = once(callback);
+      if (isReadableStream(stream) || isWritableStream(stream)) {
+        return eosWeb(stream, options, callback);
+      }
+      if (!isNodeStream(stream)) {
+        throw new ERR_INVALID_ARG_TYPE("stream", ["ReadableStream", "WritableStream", "Stream"], stream);
+      }
+      const readable = (_options$readable = options.readable) !== null && _options$readable !== void 0 ? _options$readable : isReadableNodeStream(stream);
+      const writable = (_options$writable = options.writable) !== null && _options$writable !== void 0 ? _options$writable : isWritableNodeStream(stream);
+      const wState = stream._writableState;
+      const rState = stream._readableState;
+      const onlegacyfinish = () => {
+        if (!stream.writable) {
+          onfinish();
+        }
+      };
+      let willEmitClose = _willEmitClose(stream) && isReadableNodeStream(stream) === readable && isWritableNodeStream(stream) === writable;
+      let writableFinished = isWritableFinished(stream, false);
+      const onfinish = () => {
+        writableFinished = true;
+        if (stream.destroyed) {
+          willEmitClose = false;
+        }
+        if (willEmitClose && (!stream.readable || readable)) {
+          return;
+        }
+        if (!readable || readableFinished) {
+          callback.call(stream);
+        }
+      };
+      let readableFinished = isReadableFinished(stream, false);
+      const onend = () => {
+        readableFinished = true;
+        if (stream.destroyed) {
+          willEmitClose = false;
+        }
+        if (willEmitClose && (!stream.writable || writable)) {
+          return;
+        }
+        if (!writable || writableFinished) {
+          callback.call(stream);
+        }
+      };
+      const onerror = (err) => {
+        callback.call(stream, err);
+      };
+      let closed = isClosed(stream);
+      const onclose = () => {
+        closed = true;
+        const errored = isWritableErrored(stream) || isReadableErrored(stream);
+        if (errored && typeof errored !== "boolean") {
+          return callback.call(stream, errored);
+        }
+        if (readable && !readableFinished && isReadableNodeStream(stream, true)) {
+          if (!isReadableFinished(stream, false)) return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE());
+        }
+        if (writable && !writableFinished) {
+          if (!isWritableFinished(stream, false)) return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE());
+        }
+        callback.call(stream);
+      };
+      const onclosed = () => {
+        closed = true;
+        const errored = isWritableErrored(stream) || isReadableErrored(stream);
+        if (errored && typeof errored !== "boolean") {
+          return callback.call(stream, errored);
+        }
+        callback.call(stream);
+      };
+      const onrequest = () => {
+        stream.req.on("finish", onfinish);
+      };
+      if (isRequest(stream)) {
+        stream.on("complete", onfinish);
+        if (!willEmitClose) {
+          stream.on("abort", onclose);
+        }
+        if (stream.req) {
+          onrequest();
+        } else {
+          stream.on("request", onrequest);
+        }
+      } else if (writable && !wState) {
+        stream.on("end", onlegacyfinish);
+        stream.on("close", onlegacyfinish);
+      }
+      if (!willEmitClose && typeof stream.aborted === "boolean") {
+        stream.on("aborted", onclose);
+      }
+      stream.on("end", onend);
+      stream.on("finish", onfinish);
+      if (options.error !== false) {
+        stream.on("error", onerror);
+      }
+      stream.on("close", onclose);
+      if (closed) {
+        process2.nextTick(onclose);
+      } else if (wState !== null && wState !== void 0 && wState.errorEmitted || rState !== null && rState !== void 0 && rState.errorEmitted) {
+        if (!willEmitClose) {
+          process2.nextTick(onclosed);
+        }
+      } else if (!readable && (!willEmitClose || isReadable(stream)) && (writableFinished || isWritable(stream) === false)) {
+        process2.nextTick(onclosed);
+      } else if (!writable && (!willEmitClose || isWritable(stream)) && (readableFinished || isReadable(stream) === false)) {
+        process2.nextTick(onclosed);
+      } else if (rState && stream.req && stream.aborted) {
+        process2.nextTick(onclosed);
+      }
+      const cleanup = () => {
+        callback = nop;
+        stream.removeListener("aborted", onclose);
+        stream.removeListener("complete", onfinish);
+        stream.removeListener("abort", onclose);
+        stream.removeListener("request", onrequest);
+        if (stream.req) stream.req.removeListener("finish", onfinish);
+        stream.removeListener("end", onlegacyfinish);
+        stream.removeListener("close", onlegacyfinish);
+        stream.removeListener("finish", onfinish);
+        stream.removeListener("end", onend);
+        stream.removeListener("error", onerror);
+        stream.removeListener("close", onclose);
+      };
+      if (options.signal && !closed) {
+        const abort = () => {
+          const endCallback = callback;
+          cleanup();
+          endCallback.call(
+            stream,
+            new AbortError(void 0, {
+              cause: options.signal.reason
+            })
+          );
+        };
+        if (options.signal.aborted) {
+          process2.nextTick(abort);
+        } else {
+          addAbortListener = addAbortListener || require_util().addAbortListener;
+          const disposable = addAbortListener(options.signal, abort);
+          const originalCallback = callback;
+          callback = once((...args) => {
+            disposable[SymbolDispose]();
+            originalCallback.apply(stream, args);
+          });
+        }
+      }
+      return cleanup;
+    }
+    function eosWeb(stream, options, callback) {
+      let isAborted = false;
+      let abort = nop;
+      if (options.signal) {
+        abort = () => {
+          isAborted = true;
+          callback.call(
+            stream,
+            new AbortError(void 0, {
+              cause: options.signal.reason
+            })
+          );
+        };
+        if (options.signal.aborted) {
+          process2.nextTick(abort);
+        } else {
+          addAbortListener = addAbortListener || require_util().addAbortListener;
+          const disposable = addAbortListener(options.signal, abort);
+          const originalCallback = callback;
+          callback = once((...args) => {
+            disposable[SymbolDispose]();
+            originalCallback.apply(stream, args);
+          });
+        }
+      }
+      const resolverFn = (...args) => {
+        if (!isAborted) {
+          process2.nextTick(() => callback.apply(stream, args));
+        }
+      };
+      PromisePrototypeThen(stream[kIsClosedPromise].promise, resolverFn, resolverFn);
+      return nop;
+    }
+    function finished(stream, opts) {
+      var _opts;
+      let autoCleanup = false;
+      if (opts === null) {
+        opts = kEmptyObject;
+      }
+      if ((_opts = opts) !== null && _opts !== void 0 && _opts.cleanup) {
+        validateBoolean(opts.cleanup, "cleanup");
+        autoCleanup = opts.cleanup;
+      }
+      return new Promise2((resolve, reject) => {
+        const cleanup = eos(stream, opts, (err) => {
+          if (autoCleanup) {
+            cleanup();
+          }
+          if (err) {
+            reject(err);
+          } else {
+            resolve();
+          }
+        });
+      });
+    }
+    module2.exports = eos;
+    module2.exports.finished = finished;
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/destroy.js
+var require_destroy = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/destroy.js"(exports2, module2) {
+    "use strict";
+    var process2 = require_process();
+    var {
+      aggregateTwoErrors,
+      codes: { ERR_MULTIPLE_CALLBACK },
+      AbortError
+    } = require_errors();
+    var { Symbol: Symbol2 } = require_primordials();
+    var { kIsDestroyed, isDestroyed, isFinished, isServerRequest } = require_utils();
+    var kDestroy = Symbol2("kDestroy");
+    var kConstruct = Symbol2("kConstruct");
+    function checkError(err, w, r) {
+      if (err) {
+        err.stack;
+        if (w && !w.errored) {
+          w.errored = err;
+        }
+        if (r && !r.errored) {
+          r.errored = err;
+        }
+      }
+    }
+    function destroy(err, cb) {
+      const r = this._readableState;
+      const w = this._writableState;
+      const s = w || r;
+      if (w !== null && w !== void 0 && w.destroyed || r !== null && r !== void 0 && r.destroyed) {
+        if (typeof cb === "function") {
+          cb();
+        }
+        return this;
+      }
+      checkError(err, w, r);
+      if (w) {
+        w.destroyed = true;
+      }
+      if (r) {
+        r.destroyed = true;
+      }
+      if (!s.constructed) {
+        this.once(kDestroy, function(er) {
+          _destroy(this, aggregateTwoErrors(er, err), cb);
+        });
+      } else {
+        _destroy(this, err, cb);
+      }
+      return this;
+    }
+    function _destroy(self, err, cb) {
+      let called = false;
+      function onDestroy(err2) {
+        if (called) {
+          return;
+        }
+        called = true;
+        const r = self._readableState;
+        const w = self._writableState;
+        checkError(err2, w, r);
+        if (w) {
+          w.closed = true;
+        }
+        if (r) {
+          r.closed = true;
+        }
+        if (typeof cb === "function") {
+          cb(err2);
+        }
+        if (err2) {
+          process2.nextTick(emitErrorCloseNT, self, err2);
+        } else {
+          process2.nextTick(emitCloseNT, self);
+        }
+      }
+      try {
+        self._destroy(err || null, onDestroy);
+      } catch (err2) {
+        onDestroy(err2);
+      }
+    }
+    function emitErrorCloseNT(self, err) {
+      emitErrorNT(self, err);
+      emitCloseNT(self);
+    }
+    function emitCloseNT(self) {
+      const r = self._readableState;
+      const w = self._writableState;
+      if (w) {
+        w.closeEmitted = true;
+      }
+      if (r) {
+        r.closeEmitted = true;
+      }
+      if (w !== null && w !== void 0 && w.emitClose || r !== null && r !== void 0 && r.emitClose) {
+        self.emit("close");
+      }
+    }
+    function emitErrorNT(self, err) {
+      const r = self._readableState;
+      const w = self._writableState;
+      if (w !== null && w !== void 0 && w.errorEmitted || r !== null && r !== void 0 && r.errorEmitted) {
+        return;
+      }
+      if (w) {
+        w.errorEmitted = true;
+      }
+      if (r) {
+        r.errorEmitted = true;
+      }
+      self.emit("error", err);
+    }
+    function undestroy() {
+      const r = this._readableState;
+      const w = this._writableState;
+      if (r) {
+        r.constructed = true;
+        r.closed = false;
+        r.closeEmitted = false;
+        r.destroyed = false;
+        r.errored = null;
+        r.errorEmitted = false;
+        r.reading = false;
+        r.ended = r.readable === false;
+        r.endEmitted = r.readable === false;
+      }
+      if (w) {
+        w.constructed = true;
+        w.destroyed = false;
+        w.closed = false;
+        w.closeEmitted = false;
+        w.errored = null;
+        w.errorEmitted = false;
+        w.finalCalled = false;
+        w.prefinished = false;
+        w.ended = w.writable === false;
+        w.ending = w.writable === false;
+        w.finished = w.writable === false;
+      }
+    }
+    function errorOrDestroy(stream, err, sync) {
+      const r = stream._readableState;
+      const w = stream._writableState;
+      if (w !== null && w !== void 0 && w.destroyed || r !== null && r !== void 0 && r.destroyed) {
+        return this;
+      }
+      if (r !== null && r !== void 0 && r.autoDestroy || w !== null && w !== void 0 && w.autoDestroy)
+        stream.destroy(err);
+      else if (err) {
+        err.stack;
+        if (w && !w.errored) {
+          w.errored = err;
+        }
+        if (r && !r.errored) {
+          r.errored = err;
+        }
+        if (sync) {
+          process2.nextTick(emitErrorNT, stream, err);
+        } else {
+          emitErrorNT(stream, err);
+        }
+      }
+    }
+    function construct(stream, cb) {
+      if (typeof stream._construct !== "function") {
+        return;
+      }
+      const r = stream._readableState;
+      const w = stream._writableState;
+      if (r) {
+        r.constructed = false;
+      }
+      if (w) {
+        w.constructed = false;
+      }
+      stream.once(kConstruct, cb);
+      if (stream.listenerCount(kConstruct) > 1) {
+        return;
+      }
+      process2.nextTick(constructNT, stream);
+    }
+    function constructNT(stream) {
+      let called = false;
+      function onConstruct(err) {
+        if (called) {
+          errorOrDestroy(stream, err !== null && err !== void 0 ? err : new ERR_MULTIPLE_CALLBACK());
+          return;
+        }
+        called = true;
+        const r = stream._readableState;
+        const w = stream._writableState;
+        const s = w || r;
+        if (r) {
+          r.constructed = true;
+        }
+        if (w) {
+          w.constructed = true;
+        }
+        if (s.destroyed) {
+          stream.emit(kDestroy, err);
+        } else if (err) {
+          errorOrDestroy(stream, err, true);
+        } else {
+          process2.nextTick(emitConstructNT, stream);
+        }
+      }
+      try {
+        stream._construct((err) => {
+          process2.nextTick(onConstruct, err);
+        });
+      } catch (err) {
+        process2.nextTick(onConstruct, err);
+      }
+    }
+    function emitConstructNT(stream) {
+      stream.emit(kConstruct);
+    }
+    function isRequest(stream) {
+      return (stream === null || stream === void 0 ? void 0 : stream.setHeader) && typeof stream.abort === "function";
+    }
+    function emitCloseLegacy(stream) {
+      stream.emit("close");
+    }
+    function emitErrorCloseLegacy(stream, err) {
+      stream.emit("error", err);
+      process2.nextTick(emitCloseLegacy, stream);
+    }
+    function destroyer(stream, err) {
+      if (!stream || isDestroyed(stream)) {
+        return;
+      }
+      if (!err && !isFinished(stream)) {
+        err = new AbortError();
+      }
+      if (isServerRequest(stream)) {
+        stream.socket = null;
+        stream.destroy(err);
+      } else if (isRequest(stream)) {
+        stream.abort();
+      } else if (isRequest(stream.req)) {
+        stream.req.abort();
+      } else if (typeof stream.destroy === "function") {
+        stream.destroy(err);
+      } else if (typeof stream.close === "function") {
+        stream.close();
+      } else if (err) {
+        process2.nextTick(emitErrorCloseLegacy, stream, err);
+      } else {
+        process2.nextTick(emitCloseLegacy, stream);
+      }
+      if (!stream.destroyed) {
+        stream[kIsDestroyed] = true;
+      }
+    }
+    module2.exports = {
+      construct,
+      destroyer,
+      destroy,
+      undestroy,
+      errorOrDestroy
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/legacy.js
+var require_legacy = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/legacy.js"(exports2, module2) {
+    "use strict";
+    var { ArrayIsArray, ObjectSetPrototypeOf } = require_primordials();
+    var { EventEmitter: EE } = require("events");
+    function Stream2(opts) {
+      EE.call(this, opts);
+    }
+    ObjectSetPrototypeOf(Stream2.prototype, EE.prototype);
+    ObjectSetPrototypeOf(Stream2, EE);
+    Stream2.prototype.pipe = function(dest, options) {
+      const source = this;
+      function ondata(chunk) {
+        if (dest.writable && dest.write(chunk) === false && source.pause) {
+          source.pause();
+        }
+      }
+      source.on("data", ondata);
+      function ondrain() {
+        if (source.readable && source.resume) {
+          source.resume();
+        }
+      }
+      dest.on("drain", ondrain);
+      if (!dest._isStdio && (!options || options.end !== false)) {
+        source.on("end", onend);
+        source.on("close", onclose);
+      }
+      let didOnEnd = false;
+      function onend() {
+        if (didOnEnd) return;
+        didOnEnd = true;
+        dest.end();
+      }
+      function onclose() {
+        if (didOnEnd) return;
+        didOnEnd = true;
+        if (typeof dest.destroy === "function") dest.destroy();
+      }
+      function onerror(er) {
+        var _this$listenerCount;
+        cleanup();
+        if (((_this$listenerCount = this.listenerCount) === null || _this$listenerCount === void 0 ? void 0 : _this$listenerCount.call(this, "error")) === 0) {
+          this.emit("error", er);
+        }
+      }
+      prependListener(source, "error", onerror);
+      prependListener(dest, "error", onerror);
+      function cleanup() {
+        source.removeListener("data", ondata);
+        dest.removeListener("drain", ondrain);
+        source.removeListener("end", onend);
+        source.removeListener("close", onclose);
+        source.removeListener("error", onerror);
+        dest.removeListener("error", onerror);
+        source.removeListener("end", cleanup);
+        source.removeListener("close", cleanup);
+        dest.removeListener("close", cleanup);
+      }
+      source.on("end", cleanup);
+      source.on("close", cleanup);
+      dest.on("close", cleanup);
+      dest.emit("pipe", source);
+      return dest;
+    };
+    function prependListener(emitter, event, fn) {
+      if (typeof emitter.prependListener === "function") return emitter.prependListener(event, fn);
+      if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);
+      else if (ArrayIsArray(emitter._events[event])) emitter._events[event].unshift(fn);
+      else emitter._events[event] = [fn, emitter._events[event]];
+    }
+    module2.exports = {
+      Stream: Stream2,
+      prependListener
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/add-abort-signal.js
+var require_add_abort_signal = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/add-abort-signal.js"(exports2, module2) {
+    "use strict";
+    var { SymbolDispose } = require_primordials();
+    var { AbortError, codes } = require_errors();
+    var { isNodeStream, isWebStream, kControllerErrorFunction } = require_utils();
+    var eos = require_end_of_stream();
+    var { ERR_INVALID_ARG_TYPE } = codes;
+    var addAbortListener;
+    var validateAbortSignal = (signal, name) => {
+      if (typeof signal !== "object" || !("aborted" in signal)) {
+        throw new ERR_INVALID_ARG_TYPE(name, "AbortSignal", signal);
+      }
+    };
+    module2.exports.addAbortSignal = function addAbortSignal(signal, stream) {
+      validateAbortSignal(signal, "signal");
+      if (!isNodeStream(stream) && !isWebStream(stream)) {
+        throw new ERR_INVALID_ARG_TYPE("stream", ["ReadableStream", "WritableStream", "Stream"], stream);
+      }
+      return module2.exports.addAbortSignalNoValidate(signal, stream);
+    };
+    module2.exports.addAbortSignalNoValidate = function(signal, stream) {
+      if (typeof signal !== "object" || !("aborted" in signal)) {
+        return stream;
+      }
+      const onAbort = isNodeStream(stream) ? () => {
+        stream.destroy(
+          new AbortError(void 0, {
+            cause: signal.reason
+          })
+        );
+      } : () => {
+        stream[kControllerErrorFunction](
+          new AbortError(void 0, {
+            cause: signal.reason
+          })
+        );
+      };
+      if (signal.aborted) {
+        onAbort();
+      } else {
+        addAbortListener = addAbortListener || require_util().addAbortListener;
+        const disposable = addAbortListener(signal, onAbort);
+        eos(stream, disposable[SymbolDispose]);
+      }
+      return stream;
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/buffer_list.js
+var require_buffer_list = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/buffer_list.js"(exports2, module2) {
+    "use strict";
+    var { StringPrototypeSlice, SymbolIterator, TypedArrayPrototypeSet, Uint8Array: Uint8Array2 } = require_primordials();
+    var { Buffer: Buffer3 } = require("buffer");
+    var { inspect } = require_util();
+    module2.exports = class BufferList {
+      constructor() {
+        this.head = null;
+        this.tail = null;
+        this.length = 0;
+      }
+      push(v) {
+        const entry = {
+          data: v,
+          next: null
+        };
+        if (this.length > 0) this.tail.next = entry;
+        else this.head = entry;
+        this.tail = entry;
+        ++this.length;
+      }
+      unshift(v) {
+        const entry = {
+          data: v,
+          next: this.head
+        };
+        if (this.length === 0) this.tail = entry;
+        this.head = entry;
+        ++this.length;
+      }
+      shift() {
+        if (this.length === 0) return;
+        const ret = this.head.data;
+        if (this.length === 1) this.head = this.tail = null;
+        else this.head = this.head.next;
+        --this.length;
+        return ret;
+      }
+      clear() {
+        this.head = this.tail = null;
+        this.length = 0;
+      }
+      join(s) {
+        if (this.length === 0) return "";
+        let p = this.head;
+        let ret = "" + p.data;
+        while ((p = p.next) !== null) ret += s + p.data;
+        return ret;
+      }
+      concat(n) {
+        if (this.length === 0) return Buffer3.alloc(0);
+        const ret = Buffer3.allocUnsafe(n >>> 0);
+        let p = this.head;
+        let i = 0;
+        while (p) {
+          TypedArrayPrototypeSet(ret, p.data, i);
+          i += p.data.length;
+          p = p.next;
+        }
+        return ret;
+      }
+      // Consumes a specified amount of bytes or characters from the buffered data.
+      consume(n, hasStrings) {
+        const data = this.head.data;
+        if (n < data.length) {
+          const slice = data.slice(0, n);
+          this.head.data = data.slice(n);
+          return slice;
+        }
+        if (n === data.length) {
+          return this.shift();
+        }
+        return hasStrings ? this._getString(n) : this._getBuffer(n);
+      }
+      first() {
+        return this.head.data;
+      }
+      *[SymbolIterator]() {
+        for (let p = this.head; p; p = p.next) {
+          yield p.data;
+        }
+      }
+      // Consumes a specified amount of characters from the buffered data.
+      _getString(n) {
+        let ret = "";
+        let p = this.head;
+        let c = 0;
+        do {
+          const str = p.data;
+          if (n > str.length) {
+            ret += str;
+            n -= str.length;
+          } else {
+            if (n === str.length) {
+              ret += str;
+              ++c;
+              if (p.next) this.head = p.next;
+              else this.head = this.tail = null;
+            } else {
+              ret += StringPrototypeSlice(str, 0, n);
+              this.head = p;
+              p.data = StringPrototypeSlice(str, n);
+            }
+            break;
+          }
+          ++c;
+        } while ((p = p.next) !== null);
+        this.length -= c;
+        return ret;
+      }
+      // Consumes a specified amount of bytes from the buffered data.
+      _getBuffer(n) {
+        const ret = Buffer3.allocUnsafe(n);
+        const retLen = n;
+        let p = this.head;
+        let c = 0;
+        do {
+          const buf = p.data;
+          if (n > buf.length) {
+            TypedArrayPrototypeSet(ret, buf, retLen - n);
+            n -= buf.length;
+          } else {
+            if (n === buf.length) {
+              TypedArrayPrototypeSet(ret, buf, retLen - n);
+              ++c;
+              if (p.next) this.head = p.next;
+              else this.head = this.tail = null;
+            } else {
+              TypedArrayPrototypeSet(ret, new Uint8Array2(buf.buffer, buf.byteOffset, n), retLen - n);
+              this.head = p;
+              p.data = buf.slice(n);
+            }
+            break;
+          }
+          ++c;
+        } while ((p = p.next) !== null);
+        this.length -= c;
+        return ret;
+      }
+      // Make sure the linked list only shows the minimal necessary information.
+      [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")](_, options) {
+        return inspect(this, {
+          ...options,
+          // Only inspect one level.
+          depth: 0,
+          // It should not recurse.
+          customInspect: false
+        });
+      }
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/state.js
+var require_state = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/state.js"(exports2, module2) {
+    "use strict";
+    var { MathFloor, NumberIsInteger } = require_primordials();
+    var { validateInteger } = require_validators();
+    var { ERR_INVALID_ARG_VALUE } = require_errors().codes;
+    var defaultHighWaterMarkBytes = 16 * 1024;
+    var defaultHighWaterMarkObjectMode = 16;
+    function highWaterMarkFrom(options, isDuplex, duplexKey) {
+      return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null;
+    }
+    function getDefaultHighWaterMark(objectMode) {
+      return objectMode ? defaultHighWaterMarkObjectMode : defaultHighWaterMarkBytes;
+    }
+    function setDefaultHighWaterMark(objectMode, value) {
+      validateInteger(value, "value", 0);
+      if (objectMode) {
+        defaultHighWaterMarkObjectMode = value;
+      } else {
+        defaultHighWaterMarkBytes = value;
+      }
+    }
+    function getHighWaterMark(state, options, duplexKey, isDuplex) {
+      const hwm = highWaterMarkFrom(options, isDuplex, duplexKey);
+      if (hwm != null) {
+        if (!NumberIsInteger(hwm) || hwm < 0) {
+          const name = isDuplex ? `options.${duplexKey}` : "options.highWaterMark";
+          throw new ERR_INVALID_ARG_VALUE(name, hwm);
+        }
+        return MathFloor(hwm);
+      }
+      return getDefaultHighWaterMark(state.objectMode);
+    }
+    module2.exports = {
+      getHighWaterMark,
+      getDefaultHighWaterMark,
+      setDefaultHighWaterMark
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/from.js
+var require_from = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/from.js"(exports2, module2) {
+    "use strict";
+    var process2 = require_process();
+    var { PromisePrototypeThen, SymbolAsyncIterator, SymbolIterator } = require_primordials();
+    var { Buffer: Buffer3 } = require("buffer");
+    var { ERR_INVALID_ARG_TYPE, ERR_STREAM_NULL_VALUES } = require_errors().codes;
+    function from(Readable, iterable, opts) {
+      let iterator;
+      if (typeof iterable === "string" || iterable instanceof Buffer3) {
+        return new Readable({
+          objectMode: true,
+          ...opts,
+          read() {
+            this.push(iterable);
+            this.push(null);
+          }
+        });
+      }
+      let isAsync;
+      if (iterable && iterable[SymbolAsyncIterator]) {
+        isAsync = true;
+        iterator = iterable[SymbolAsyncIterator]();
+      } else if (iterable && iterable[SymbolIterator]) {
+        isAsync = false;
+        iterator = iterable[SymbolIterator]();
+      } else {
+        throw new ERR_INVALID_ARG_TYPE("iterable", ["Iterable"], iterable);
+      }
+      const readable = new Readable({
+        objectMode: true,
+        highWaterMark: 1,
+        // TODO(ronag): What options should be allowed?
+        ...opts
+      });
+      let reading = false;
+      readable._read = function() {
+        if (!reading) {
+          reading = true;
+          next();
+        }
+      };
+      readable._destroy = function(error, cb) {
+        PromisePrototypeThen(
+          close(error),
+          () => process2.nextTick(cb, error),
+          // nextTick is here in case cb throws
+          (e) => process2.nextTick(cb, e || error)
+        );
+      };
+      async function close(error) {
+        const hadError = error !== void 0 && error !== null;
+        const hasThrow = typeof iterator.throw === "function";
+        if (hadError && hasThrow) {
+          const { value, done } = await iterator.throw(error);
+          await value;
+          if (done) {
+            return;
+          }
+        }
+        if (typeof iterator.return === "function") {
+          const { value } = await iterator.return();
+          await value;
+        }
+      }
+      async function next() {
+        for (; ; ) {
+          try {
+            const { value, done } = isAsync ? await iterator.next() : iterator.next();
+            if (done) {
+              readable.push(null);
+            } else {
+              const res = value && typeof value.then === "function" ? await value : value;
+              if (res === null) {
+                reading = false;
+                throw new ERR_STREAM_NULL_VALUES();
+              } else if (readable.push(res)) {
+                continue;
+              } else {
+                reading = false;
+              }
+            }
+          } catch (err) {
+            readable.destroy(err);
+          }
+          break;
+        }
+      }
+      return readable;
+    }
+    module2.exports = from;
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/readable.js
+var require_readable = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/readable.js"(exports2, module2) {
+    "use strict";
+    var process2 = require_process();
+    var {
+      ArrayPrototypeIndexOf,
+      NumberIsInteger,
+      NumberIsNaN,
+      NumberParseInt,
+      ObjectDefineProperties,
+      ObjectKeys,
+      ObjectSetPrototypeOf,
+      Promise: Promise2,
+      SafeSet,
+      SymbolAsyncDispose,
+      SymbolAsyncIterator,
+      Symbol: Symbol2
+    } = require_primordials();
+    module2.exports = Readable;
+    Readable.ReadableState = ReadableState;
+    var { EventEmitter: EE } = require("events");
+    var { Stream: Stream2, prependListener } = require_legacy();
+    var { Buffer: Buffer3 } = require("buffer");
+    var { addAbortSignal } = require_add_abort_signal();
+    var eos = require_end_of_stream();
+    var debug = require_util().debuglog("stream", (fn) => {
+      debug = fn;
+    });
+    var BufferList = require_buffer_list();
+    var destroyImpl = require_destroy();
+    var { getHighWaterMark, getDefaultHighWaterMark } = require_state();
+    var {
+      aggregateTwoErrors,
+      codes: {
+        ERR_INVALID_ARG_TYPE,
+        ERR_METHOD_NOT_IMPLEMENTED,
+        ERR_OUT_OF_RANGE,
+        ERR_STREAM_PUSH_AFTER_EOF,
+        ERR_STREAM_UNSHIFT_AFTER_END_EVENT
+      },
+      AbortError
+    } = require_errors();
+    var { validateObject } = require_validators();
+    var kPaused = Symbol2("kPaused");
+    var { StringDecoder } = require("string_decoder");
+    var from = require_from();
+    ObjectSetPrototypeOf(Readable.prototype, Stream2.prototype);
+    ObjectSetPrototypeOf(Readable, Stream2);
+    var nop = () => {
+    };
+    var { errorOrDestroy } = destroyImpl;
+    var kObjectMode = 1 << 0;
+    var kEnded = 1 << 1;
+    var kEndEmitted = 1 << 2;
+    var kReading = 1 << 3;
+    var kConstructed = 1 << 4;
+    var kSync = 1 << 5;
+    var kNeedReadable = 1 << 6;
+    var kEmittedReadable = 1 << 7;
+    var kReadableListening = 1 << 8;
+    var kResumeScheduled = 1 << 9;
+    var kErrorEmitted = 1 << 10;
+    var kEmitClose = 1 << 11;
+    var kAutoDestroy = 1 << 12;
+    var kDestroyed = 1 << 13;
+    var kClosed = 1 << 14;
+    var kCloseEmitted = 1 << 15;
+    var kMultiAwaitDrain = 1 << 16;
+    var kReadingMore = 1 << 17;
+    var kDataEmitted = 1 << 18;
+    function makeBitMapDescriptor(bit) {
+      return {
+        enumerable: false,
+        get() {
+          return (this.state & bit) !== 0;
+        },
+        set(value) {
+          if (value) this.state |= bit;
+          else this.state &= ~bit;
+        }
+      };
+    }
+    ObjectDefineProperties(ReadableState.prototype, {
+      objectMode: makeBitMapDescriptor(kObjectMode),
+      ended: makeBitMapDescriptor(kEnded),
+      endEmitted: makeBitMapDescriptor(kEndEmitted),
+      reading: makeBitMapDescriptor(kReading),
+      // Stream is still being constructed and cannot be
+      // destroyed until construction finished or failed.
+      // Async construction is opt in, therefore we start as
+      // constructed.
+      constructed: makeBitMapDescriptor(kConstructed),
+      // A flag to be able to tell if the event 'readable'/'data' is emitted
+      // immediately, or on a later tick.  We set this to true at first, because
+      // any actions that shouldn't happen until "later" should generally also
+      // not happen before the first read call.
+      sync: makeBitMapDescriptor(kSync),
+      // Whenever we return null, then we set a flag to say
+      // that we're awaiting a 'readable' event emission.
+      needReadable: makeBitMapDescriptor(kNeedReadable),
+      emittedReadable: makeBitMapDescriptor(kEmittedReadable),
+      readableListening: makeBitMapDescriptor(kReadableListening),
+      resumeScheduled: makeBitMapDescriptor(kResumeScheduled),
+      // True if the error was already emitted and should not be thrown again.
+      errorEmitted: makeBitMapDescriptor(kErrorEmitted),
+      emitClose: makeBitMapDescriptor(kEmitClose),
+      autoDestroy: makeBitMapDescriptor(kAutoDestroy),
+      // Has it been destroyed.
+      destroyed: makeBitMapDescriptor(kDestroyed),
+      // Indicates whether the stream has finished destroying.
+      closed: makeBitMapDescriptor(kClosed),
+      // True if close has been emitted or would have been emitted
+      // depending on emitClose.
+      closeEmitted: makeBitMapDescriptor(kCloseEmitted),
+      multiAwaitDrain: makeBitMapDescriptor(kMultiAwaitDrain),
+      // If true, a maybeReadMore has been scheduled.
+      readingMore: makeBitMapDescriptor(kReadingMore),
+      dataEmitted: makeBitMapDescriptor(kDataEmitted)
+    });
+    function ReadableState(options, stream, isDuplex) {
+      if (typeof isDuplex !== "boolean") isDuplex = stream instanceof require_duplex();
+      this.state = kEmitClose | kAutoDestroy | kConstructed | kSync;
+      if (options && options.objectMode) this.state |= kObjectMode;
+      if (isDuplex && options && options.readableObjectMode) this.state |= kObjectMode;
+      this.highWaterMark = options ? getHighWaterMark(this, options, "readableHighWaterMark", isDuplex) : getDefaultHighWaterMark(false);
+      this.buffer = new BufferList();
+      this.length = 0;
+      this.pipes = [];
+      this.flowing = null;
+      this[kPaused] = null;
+      if (options && options.emitClose === false) this.state &= ~kEmitClose;
+      if (options && options.autoDestroy === false) this.state &= ~kAutoDestroy;
+      this.errored = null;
+      this.defaultEncoding = options && options.defaultEncoding || "utf8";
+      this.awaitDrainWriters = null;
+      this.decoder = null;
+      this.encoding = null;
+      if (options && options.encoding) {
+        this.decoder = new StringDecoder(options.encoding);
+        this.encoding = options.encoding;
+      }
+    }
+    function Readable(options) {
+      if (!(this instanceof Readable)) return new Readable(options);
+      const isDuplex = this instanceof require_duplex();
+      this._readableState = new ReadableState(options, this, isDuplex);
+      if (options) {
+        if (typeof options.read === "function") this._read = options.read;
+        if (typeof options.destroy === "function") this._destroy = options.destroy;
+        if (typeof options.construct === "function") this._construct = options.construct;
+        if (options.signal && !isDuplex) addAbortSignal(options.signal, this);
+      }
+      Stream2.call(this, options);
+      destroyImpl.construct(this, () => {
+        if (this._readableState.needReadable) {
+          maybeReadMore(this, this._readableState);
+        }
+      });
+    }
+    Readable.prototype.destroy = destroyImpl.destroy;
+    Readable.prototype._undestroy = destroyImpl.undestroy;
+    Readable.prototype._destroy = function(err, cb) {
+      cb(err);
+    };
+    Readable.prototype[EE.captureRejectionSymbol] = function(err) {
+      this.destroy(err);
+    };
+    Readable.prototype[SymbolAsyncDispose] = function() {
+      let error;
+      if (!this.destroyed) {
+        error = this.readableEnded ? null : new AbortError();
+        this.destroy(error);
+      }
+      return new Promise2((resolve, reject) => eos(this, (err) => err && err !== error ? reject(err) : resolve(null)));
+    };
+    Readable.prototype.push = function(chunk, encoding) {
+      return readableAddChunk(this, chunk, encoding, false);
+    };
+    Readable.prototype.unshift = function(chunk, encoding) {
+      return readableAddChunk(this, chunk, encoding, true);
+    };
+    function readableAddChunk(stream, chunk, encoding, addToFront) {
+      debug("readableAddChunk", chunk);
+      const state = stream._readableState;
+      let err;
+      if ((state.state & kObjectMode) === 0) {
+        if (typeof chunk === "string") {
+          encoding = encoding || state.defaultEncoding;
+          if (state.encoding !== encoding) {
+            if (addToFront && state.encoding) {
+              chunk = Buffer3.from(chunk, encoding).toString(state.encoding);
+            } else {
+              chunk = Buffer3.from(chunk, encoding);
+              encoding = "";
+            }
+          }
+        } else if (chunk instanceof Buffer3) {
+          encoding = "";
+        } else if (Stream2._isUint8Array(chunk)) {
+          chunk = Stream2._uint8ArrayToBuffer(chunk);
+          encoding = "";
+        } else if (chunk != null) {
+          err = new ERR_INVALID_ARG_TYPE("chunk", ["string", "Buffer", "Uint8Array"], chunk);
+        }
+      }
+      if (err) {
+        errorOrDestroy(stream, err);
+      } else if (chunk === null) {
+        state.state &= ~kReading;
+        onEofChunk(stream, state);
+      } else if ((state.state & kObjectMode) !== 0 || chunk && chunk.length > 0) {
+        if (addToFront) {
+          if ((state.state & kEndEmitted) !== 0) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT());
+          else if (state.destroyed || state.errored) return false;
+          else addChunk(stream, state, chunk, true);
+        } else if (state.ended) {
+          errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF());
+        } else if (state.destroyed || state.errored) {
+          return false;
+        } else {
+          state.state &= ~kReading;
+          if (state.decoder && !encoding) {
+            chunk = state.decoder.write(chunk);
+            if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);
+            else maybeReadMore(stream, state);
+          } else {
+            addChunk(stream, state, chunk, false);
+          }
+        }
+      } else if (!addToFront) {
+        state.state &= ~kReading;
+        maybeReadMore(stream, state);
+      }
+      return !state.ended && (state.length < state.highWaterMark || state.length === 0);
+    }
+    function addChunk(stream, state, chunk, addToFront) {
+      if (state.flowing && state.length === 0 && !state.sync && stream.listenerCount("data") > 0) {
+        if ((state.state & kMultiAwaitDrain) !== 0) {
+          state.awaitDrainWriters.clear();
+        } else {
+          state.awaitDrainWriters = null;
+        }
+        state.dataEmitted = true;
+        stream.emit("data", chunk);
+      } else {
+        state.length += state.objectMode ? 1 : chunk.length;
+        if (addToFront) state.buffer.unshift(chunk);
+        else state.buffer.push(chunk);
+        if ((state.state & kNeedReadable) !== 0) emitReadable(stream);
+      }
+      maybeReadMore(stream, state);
+    }
+    Readable.prototype.isPaused = function() {
+      const state = this._readableState;
+      return state[kPaused] === true || state.flowing === false;
+    };
+    Readable.prototype.setEncoding = function(enc) {
+      const decoder = new StringDecoder(enc);
+      this._readableState.decoder = decoder;
+      this._readableState.encoding = this._readableState.decoder.encoding;
+      const buffer = this._readableState.buffer;
+      let content = "";
+      for (const data of buffer) {
+        content += decoder.write(data);
+      }
+      buffer.clear();
+      if (content !== "") buffer.push(content);
+      this._readableState.length = content.length;
+      return this;
+    };
+    var MAX_HWM = 1073741824;
+    function computeNewHighWaterMark(n) {
+      if (n > MAX_HWM) {
+        throw new ERR_OUT_OF_RANGE("size", "<= 1GiB", n);
+      } else {
+        n--;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
+        n++;
+      }
+      return n;
+    }
+    function howMuchToRead(n, state) {
+      if (n <= 0 || state.length === 0 && state.ended) return 0;
+      if ((state.state & kObjectMode) !== 0) return 1;
+      if (NumberIsNaN(n)) {
+        if (state.flowing && state.length) return state.buffer.first().length;
+        return state.length;
+      }
+      if (n <= state.length) return n;
+      return state.ended ? state.length : 0;
+    }
+    Readable.prototype.read = function(n) {
+      debug("read", n);
+      if (n === void 0) {
+        n = NaN;
+      } else if (!NumberIsInteger(n)) {
+        n = NumberParseInt(n, 10);
+      }
+      const state = this._readableState;
+      const nOrig = n;
+      if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);
+      if (n !== 0) state.state &= ~kEmittedReadable;
+      if (n === 0 && state.needReadable && ((state.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || state.ended)) {
+        debug("read: emitReadable", state.length, state.ended);
+        if (state.length === 0 && state.ended) endReadable(this);
+        else emitReadable(this);
+        return null;
+      }
+      n = howMuchToRead(n, state);
+      if (n === 0 && state.ended) {
+        if (state.length === 0) endReadable(this);
+        return null;
+      }
+      let doRead = (state.state & kNeedReadable) !== 0;
+      debug("need readable", doRead);
+      if (state.length === 0 || state.length - n < state.highWaterMark) {
+        doRead = true;
+        debug("length less than watermark", doRead);
+      }
+      if (state.ended || state.reading || state.destroyed || state.errored || !state.constructed) {
+        doRead = false;
+        debug("reading, ended or constructing", doRead);
+      } else if (doRead) {
+        debug("do read");
+        state.state |= kReading | kSync;
+        if (state.length === 0) state.state |= kNeedReadable;
+        try {
+          this._read(state.highWaterMark);
+        } catch (err) {
+          errorOrDestroy(this, err);
+        }
+        state.state &= ~kSync;
+        if (!state.reading) n = howMuchToRead(nOrig, state);
+      }
+      let ret;
+      if (n > 0) ret = fromList(n, state);
+      else ret = null;
+      if (ret === null) {
+        state.needReadable = state.length <= state.highWaterMark;
+        n = 0;
+      } else {
+        state.length -= n;
+        if (state.multiAwaitDrain) {
+          state.awaitDrainWriters.clear();
+        } else {
+          state.awaitDrainWriters = null;
+        }
+      }
+      if (state.length === 0) {
+        if (!state.ended) state.needReadable = true;
+        if (nOrig !== n && state.ended) endReadable(this);
+      }
+      if (ret !== null && !state.errorEmitted && !state.closeEmitted) {
+        state.dataEmitted = true;
+        this.emit("data", ret);
+      }
+      return ret;
+    };
+    function onEofChunk(stream, state) {
+      debug("onEofChunk");
+      if (state.ended) return;
+      if (state.decoder) {
+        const chunk = state.decoder.end();
+        if (chunk && chunk.length) {
+          state.buffer.push(chunk);
+          state.length += state.objectMode ? 1 : chunk.length;
+        }
+      }
+      state.ended = true;
+      if (state.sync) {
+        emitReadable(stream);
+      } else {
+        state.needReadable = false;
+        state.emittedReadable = true;
+        emitReadable_(stream);
+      }
+    }
+    function emitReadable(stream) {
+      const state = stream._readableState;
+      debug("emitReadable", state.needReadable, state.emittedReadable);
+      state.needReadable = false;
+      if (!state.emittedReadable) {
+        debug("emitReadable", state.flowing);
+        state.emittedReadable = true;
+        process2.nextTick(emitReadable_, stream);
+      }
+    }
+    function emitReadable_(stream) {
+      const state = stream._readableState;
+      debug("emitReadable_", state.destroyed, state.length, state.ended);
+      if (!state.destroyed && !state.errored && (state.length || state.ended)) {
+        stream.emit("readable");
+        state.emittedReadable = false;
+      }
+      state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark;
+      flow(stream);
+    }
+    function maybeReadMore(stream, state) {
+      if (!state.readingMore && state.constructed) {
+        state.readingMore = true;
+        process2.nextTick(maybeReadMore_, stream, state);
+      }
+    }
+    function maybeReadMore_(stream, state) {
+      while (!state.reading && !state.ended && (state.length < state.highWaterMark || state.flowing && state.length === 0)) {
+        const len = state.length;
+        debug("maybeReadMore read 0");
+        stream.read(0);
+        if (len === state.length)
+          break;
+      }
+      state.readingMore = false;
+    }
+    Readable.prototype._read = function(n) {
+      throw new ERR_METHOD_NOT_IMPLEMENTED("_read()");
+    };
+    Readable.prototype.pipe = function(dest, pipeOpts) {
+      const src = this;
+      const state = this._readableState;
+      if (state.pipes.length === 1) {
+        if (!state.multiAwaitDrain) {
+          state.multiAwaitDrain = true;
+          state.awaitDrainWriters = new SafeSet(state.awaitDrainWriters ? [state.awaitDrainWriters] : []);
+        }
+      }
+      state.pipes.push(dest);
+      debug("pipe count=%d opts=%j", state.pipes.length, pipeOpts);
+      const doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process2.stdout && dest !== process2.stderr;
+      const endFn = doEnd ? onend : unpipe;
+      if (state.endEmitted) process2.nextTick(endFn);
+      else src.once("end", endFn);
+      dest.on("unpipe", onunpipe);
+      function onunpipe(readable, unpipeInfo) {
+        debug("onunpipe");
+        if (readable === src) {
+          if (unpipeInfo && unpipeInfo.hasUnpiped === false) {
+            unpipeInfo.hasUnpiped = true;
+            cleanup();
+          }
+        }
+      }
+      function onend() {
+        debug("onend");
+        dest.end();
+      }
+      let ondrain;
+      let cleanedUp = false;
+      function cleanup() {
+        debug("cleanup");
+        dest.removeListener("close", onclose);
+        dest.removeListener("finish", onfinish);
+        if (ondrain) {
+          dest.removeListener("drain", ondrain);
+        }
+        dest.removeListener("error", onerror);
+        dest.removeListener("unpipe", onunpipe);
+        src.removeListener("end", onend);
+        src.removeListener("end", unpipe);
+        src.removeListener("data", ondata);
+        cleanedUp = true;
+        if (ondrain && state.awaitDrainWriters && (!dest._writableState || dest._writableState.needDrain)) ondrain();
+      }
+      function pause() {
+        if (!cleanedUp) {
+          if (state.pipes.length === 1 && state.pipes[0] === dest) {
+            debug("false write response, pause", 0);
+            state.awaitDrainWriters = dest;
+            state.multiAwaitDrain = false;
+          } else if (state.pipes.length > 1 && state.pipes.includes(dest)) {
+            debug("false write response, pause", state.awaitDrainWriters.size);
+            state.awaitDrainWriters.add(dest);
+          }
+          src.pause();
+        }
+        if (!ondrain) {
+          ondrain = pipeOnDrain(src, dest);
+          dest.on("drain", ondrain);
+        }
+      }
+      src.on("data", ondata);
+      function ondata(chunk) {
+        debug("ondata");
+        const ret = dest.write(chunk);
+        debug("dest.write", ret);
+        if (ret === false) {
+          pause();
+        }
+      }
+      function onerror(er) {
+        debug("onerror", er);
+        unpipe();
+        dest.removeListener("error", onerror);
+        if (dest.listenerCount("error") === 0) {
+          const s = dest._writableState || dest._readableState;
+          if (s && !s.errorEmitted) {
+            errorOrDestroy(dest, er);
+          } else {
+            dest.emit("error", er);
+          }
+        }
+      }
+      prependListener(dest, "error", onerror);
+      function onclose() {
+        dest.removeListener("finish", onfinish);
+        unpipe();
+      }
+      dest.once("close", onclose);
+      function onfinish() {
+        debug("onfinish");
+        dest.removeListener("close", onclose);
+        unpipe();
+      }
+      dest.once("finish", onfinish);
+      function unpipe() {
+        debug("unpipe");
+        src.unpipe(dest);
+      }
+      dest.emit("pipe", src);
+      if (dest.writableNeedDrain === true) {
+        pause();
+      } else if (!state.flowing) {
+        debug("pipe resume");
+        src.resume();
+      }
+      return dest;
+    };
+    function pipeOnDrain(src, dest) {
+      return function pipeOnDrainFunctionResult() {
+        const state = src._readableState;
+        if (state.awaitDrainWriters === dest) {
+          debug("pipeOnDrain", 1);
+          state.awaitDrainWriters = null;
+        } else if (state.multiAwaitDrain) {
+          debug("pipeOnDrain", state.awaitDrainWriters.size);
+          state.awaitDrainWriters.delete(dest);
+        }
+        if ((!state.awaitDrainWriters || state.awaitDrainWriters.size === 0) && src.listenerCount("data")) {
+          src.resume();
+        }
+      };
+    }
+    Readable.prototype.unpipe = function(dest) {
+      const state = this._readableState;
+      const unpipeInfo = {
+        hasUnpiped: false
+      };
+      if (state.pipes.length === 0) return this;
+      if (!dest) {
+        const dests = state.pipes;
+        state.pipes = [];
+        this.pause();
+        for (let i = 0; i < dests.length; i++)
+          dests[i].emit("unpipe", this, {
+            hasUnpiped: false
+          });
+        return this;
+      }
+      const index = ArrayPrototypeIndexOf(state.pipes, dest);
+      if (index === -1) return this;
+      state.pipes.splice(index, 1);
+      if (state.pipes.length === 0) this.pause();
+      dest.emit("unpipe", this, unpipeInfo);
+      return this;
+    };
+    Readable.prototype.on = function(ev, fn) {
+      const res = Stream2.prototype.on.call(this, ev, fn);
+      const state = this._readableState;
+      if (ev === "data") {
+        state.readableListening = this.listenerCount("readable") > 0;
+        if (state.flowing !== false) this.resume();
+      } else if (ev === "readable") {
+        if (!state.endEmitted && !state.readableListening) {
+          state.readableListening = state.needReadable = true;
+          state.flowing = false;
+          state.emittedReadable = false;
+          debug("on readable", state.length, state.reading);
+          if (state.length) {
+            emitReadable(this);
+          } else if (!state.reading) {
+            process2.nextTick(nReadingNextTick, this);
+          }
+        }
+      }
+      return res;
+    };
+    Readable.prototype.addListener = Readable.prototype.on;
+    Readable.prototype.removeListener = function(ev, fn) {
+      const res = Stream2.prototype.removeListener.call(this, ev, fn);
+      if (ev === "readable") {
+        process2.nextTick(updateReadableListening, this);
+      }
+      return res;
+    };
+    Readable.prototype.off = Readable.prototype.removeListener;
+    Readable.prototype.removeAllListeners = function(ev) {
+      const res = Stream2.prototype.removeAllListeners.apply(this, arguments);
+      if (ev === "readable" || ev === void 0) {
+        process2.nextTick(updateReadableListening, this);
+      }
+      return res;
+    };
+    function updateReadableListening(self) {
+      const state = self._readableState;
+      state.readableListening = self.listenerCount("readable") > 0;
+      if (state.resumeScheduled && state[kPaused] === false) {
+        state.flowing = true;
+      } else if (self.listenerCount("data") > 0) {
+        self.resume();
+      } else if (!state.readableListening) {
+        state.flowing = null;
+      }
+    }
+    function nReadingNextTick(self) {
+      debug("readable nexttick read 0");
+      self.read(0);
+    }
+    Readable.prototype.resume = function() {
+      const state = this._readableState;
+      if (!state.flowing) {
+        debug("resume");
+        state.flowing = !state.readableListening;
+        resume(this, state);
+      }
+      state[kPaused] = false;
+      return this;
+    };
+    function resume(stream, state) {
+      if (!state.resumeScheduled) {
+        state.resumeScheduled = true;
+        process2.nextTick(resume_, stream, state);
+      }
+    }
+    function resume_(stream, state) {
+      debug("resume", state.reading);
+      if (!state.reading) {
+        stream.read(0);
+      }
+      state.resumeScheduled = false;
+      stream.emit("resume");
+      flow(stream);
+      if (state.flowing && !state.reading) stream.read(0);
+    }
+    Readable.prototype.pause = function() {
+      debug("call pause flowing=%j", this._readableState.flowing);
+      if (this._readableState.flowing !== false) {
+        debug("pause");
+        this._readableState.flowing = false;
+        this.emit("pause");
+      }
+      this._readableState[kPaused] = true;
+      return this;
+    };
+    function flow(stream) {
+      const state = stream._readableState;
+      debug("flow", state.flowing);
+      while (state.flowing && stream.read() !== null) ;
+    }
+    Readable.prototype.wrap = function(stream) {
+      let paused = false;
+      stream.on("data", (chunk) => {
+        if (!this.push(chunk) && stream.pause) {
+          paused = true;
+          stream.pause();
+        }
+      });
+      stream.on("end", () => {
+        this.push(null);
+      });
+      stream.on("error", (err) => {
+        errorOrDestroy(this, err);
+      });
+      stream.on("close", () => {
+        this.destroy();
+      });
+      stream.on("destroy", () => {
+        this.destroy();
+      });
+      this._read = () => {
+        if (paused && stream.resume) {
+          paused = false;
+          stream.resume();
+        }
+      };
+      const streamKeys = ObjectKeys(stream);
+      for (let j = 1; j < streamKeys.length; j++) {
+        const i = streamKeys[j];
+        if (this[i] === void 0 && typeof stream[i] === "function") {
+          this[i] = stream[i].bind(stream);
+        }
+      }
+      return this;
+    };
+    Readable.prototype[SymbolAsyncIterator] = function() {
+      return streamToAsyncIterator(this);
+    };
+    Readable.prototype.iterator = function(options) {
+      if (options !== void 0) {
+        validateObject(options, "options");
+      }
+      return streamToAsyncIterator(this, options);
+    };
+    function streamToAsyncIterator(stream, options) {
+      if (typeof stream.read !== "function") {
+        stream = Readable.wrap(stream, {
+          objectMode: true
+        });
+      }
+      const iter = createAsyncIterator(stream, options);
+      iter.stream = stream;
+      return iter;
+    }
+    async function* createAsyncIterator(stream, options) {
+      let callback = nop;
+      function next(resolve) {
+        if (this === stream) {
+          callback();
+          callback = nop;
+        } else {
+          callback = resolve;
+        }
+      }
+      stream.on("readable", next);
+      let error;
+      const cleanup = eos(
+        stream,
+        {
+          writable: false
+        },
+        (err) => {
+          error = err ? aggregateTwoErrors(error, err) : null;
+          callback();
+          callback = nop;
+        }
+      );
+      try {
+        while (true) {
+          const chunk = stream.destroyed ? null : stream.read();
+          if (chunk !== null) {
+            yield chunk;
+          } else if (error) {
+            throw error;
+          } else if (error === null) {
+            return;
+          } else {
+            await new Promise2(next);
+          }
+        }
+      } catch (err) {
+        error = aggregateTwoErrors(error, err);
+        throw error;
+      } finally {
+        if ((error || (options === null || options === void 0 ? void 0 : options.destroyOnReturn) !== false) && (error === void 0 || stream._readableState.autoDestroy)) {
+          destroyImpl.destroyer(stream, null);
+        } else {
+          stream.off("readable", next);
+          cleanup();
+        }
+      }
+    }
+    ObjectDefineProperties(Readable.prototype, {
+      readable: {
+        __proto__: null,
+        get() {
+          const r = this._readableState;
+          return !!r && r.readable !== false && !r.destroyed && !r.errorEmitted && !r.endEmitted;
+        },
+        set(val) {
+          if (this._readableState) {
+            this._readableState.readable = !!val;
+          }
+        }
+      },
+      readableDidRead: {
+        __proto__: null,
+        enumerable: false,
+        get: function() {
+          return this._readableState.dataEmitted;
+        }
+      },
+      readableAborted: {
+        __proto__: null,
+        enumerable: false,
+        get: function() {
+          return !!(this._readableState.readable !== false && (this._readableState.destroyed || this._readableState.errored) && !this._readableState.endEmitted);
+        }
+      },
+      readableHighWaterMark: {
+        __proto__: null,
+        enumerable: false,
+        get: function() {
+          return this._readableState.highWaterMark;
+        }
+      },
+      readableBuffer: {
+        __proto__: null,
+        enumerable: false,
+        get: function() {
+          return this._readableState && this._readableState.buffer;
+        }
+      },
+      readableFlowing: {
+        __proto__: null,
+        enumerable: false,
+        get: function() {
+          return this._readableState.flowing;
+        },
+        set: function(state) {
+          if (this._readableState) {
+            this._readableState.flowing = state;
+          }
+        }
+      },
+      readableLength: {
+        __proto__: null,
+        enumerable: false,
+        get() {
+          return this._readableState.length;
+        }
+      },
+      readableObjectMode: {
+        __proto__: null,
+        enumerable: false,
+        get() {
+          return this._readableState ? this._readableState.objectMode : false;
+        }
+      },
+      readableEncoding: {
+        __proto__: null,
+        enumerable: false,
+        get() {
+          return this._readableState ? this._readableState.encoding : null;
+        }
+      },
+      errored: {
+        __proto__: null,
+        enumerable: false,
+        get() {
+          return this._readableState ? this._readableState.errored : null;
+        }
+      },
+      closed: {
+        __proto__: null,
+        get() {
+          return this._readableState ? this._readableState.closed : false;
+        }
+      },
+      destroyed: {
+        __proto__: null,
+        enumerable: false,
+        get() {
+          return this._readableState ? this._readableState.destroyed : false;
+        },
+        set(value) {
+          if (!this._readableState) {
+            return;
+          }
+          this._readableState.destroyed = value;
+        }
+      },
+      readableEnded: {
+        __proto__: null,
+        enumerable: false,
+        get() {
+          return this._readableState ? this._readableState.endEmitted : false;
+        }
+      }
+    });
+    ObjectDefineProperties(ReadableState.prototype, {
+      // Legacy getter for `pipesCount`.
+      pipesCount: {
+        __proto__: null,
+        get() {
+          return this.pipes.length;
+        }
+      },
+      // Legacy property for `paused`.
+      paused: {
+        __proto__: null,
+        get() {
+          return this[kPaused] !== false;
+        },
+        set(value) {
+          this[kPaused] = !!value;
+        }
+      }
+    });
+    Readable._fromList = fromList;
+    function fromList(n, state) {
+      if (state.length === 0) return null;
+      let ret;
+      if (state.objectMode) ret = state.buffer.shift();
+      else if (!n || n >= state.length) {
+        if (state.decoder) ret = state.buffer.join("");
+        else if (state.buffer.length === 1) ret = state.buffer.first();
+        else ret = state.buffer.concat(state.length);
+        state.buffer.clear();
+      } else {
+        ret = state.buffer.consume(n, state.decoder);
+      }
+      return ret;
+    }
+    function endReadable(stream) {
+      const state = stream._readableState;
+      debug("endReadable", state.endEmitted);
+      if (!state.endEmitted) {
+        state.ended = true;
+        process2.nextTick(endReadableNT, state, stream);
+      }
+    }
+    function endReadableNT(state, stream) {
+      debug("endReadableNT", state.endEmitted, state.length);
+      if (!state.errored && !state.closeEmitted && !state.endEmitted && state.length === 0) {
+        state.endEmitted = true;
+        stream.emit("end");
+        if (stream.writable && stream.allowHalfOpen === false) {
+          process2.nextTick(endWritableNT, stream);
+        } else if (state.autoDestroy) {
+          const wState = stream._writableState;
+          const autoDestroy = !wState || wState.autoDestroy && // We don't expect the writable to ever 'finish'
+          // if writable is explicitly set to false.
+          (wState.finished || wState.writable === false);
+          if (autoDestroy) {
+            stream.destroy();
+          }
+        }
+      }
+    }
+    function endWritableNT(stream) {
+      const writable = stream.writable && !stream.writableEnded && !stream.destroyed;
+      if (writable) {
+        stream.end();
+      }
+    }
+    Readable.from = function(iterable, opts) {
+      return from(Readable, iterable, opts);
+    };
+    var webStreamsAdapters;
+    function lazyWebStreams() {
+      if (webStreamsAdapters === void 0) webStreamsAdapters = {};
+      return webStreamsAdapters;
+    }
+    Readable.fromWeb = function(readableStream, options) {
+      return lazyWebStreams().newStreamReadableFromReadableStream(readableStream, options);
+    };
+    Readable.toWeb = function(streamReadable, options) {
+      return lazyWebStreams().newReadableStreamFromStreamReadable(streamReadable, options);
+    };
+    Readable.wrap = function(src, options) {
+      var _ref, _src$readableObjectMo;
+      return new Readable({
+        objectMode: (_ref = (_src$readableObjectMo = src.readableObjectMode) !== null && _src$readableObjectMo !== void 0 ? _src$readableObjectMo : src.objectMode) !== null && _ref !== void 0 ? _ref : true,
+        ...options,
+        destroy(err, callback) {
+          destroyImpl.destroyer(src, err);
+          callback(err);
+        }
+      }).wrap(src);
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/writable.js
+var require_writable = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/writable.js"(exports2, module2) {
+    "use strict";
+    var process2 = require_process();
+    var {
+      ArrayPrototypeSlice,
+      Error: Error2,
+      FunctionPrototypeSymbolHasInstance,
+      ObjectDefineProperty,
+      ObjectDefineProperties,
+      ObjectSetPrototypeOf,
+      StringPrototypeToLowerCase,
+      Symbol: Symbol2,
+      SymbolHasInstance
+    } = require_primordials();
+    module2.exports = Writable;
+    Writable.WritableState = WritableState;
+    var { EventEmitter: EE } = require("events");
+    var Stream2 = require_legacy().Stream;
+    var { Buffer: Buffer3 } = require("buffer");
+    var destroyImpl = require_destroy();
+    var { addAbortSignal } = require_add_abort_signal();
+    var { getHighWaterMark, getDefaultHighWaterMark } = require_state();
+    var {
+      ERR_INVALID_ARG_TYPE,
+      ERR_METHOD_NOT_IMPLEMENTED,
+      ERR_MULTIPLE_CALLBACK,
+      ERR_STREAM_CANNOT_PIPE,
+      ERR_STREAM_DESTROYED,
+      ERR_STREAM_ALREADY_FINISHED,
+      ERR_STREAM_NULL_VALUES,
+      ERR_STREAM_WRITE_AFTER_END,
+      ERR_UNKNOWN_ENCODING
+    } = require_errors().codes;
+    var { errorOrDestroy } = destroyImpl;
+    ObjectSetPrototypeOf(Writable.prototype, Stream2.prototype);
+    ObjectSetPrototypeOf(Writable, Stream2);
+    function nop() {
+    }
+    var kOnFinished = Symbol2("kOnFinished");
+    function WritableState(options, stream, isDuplex) {
+      if (typeof isDuplex !== "boolean") isDuplex = stream instanceof require_duplex();
+      this.objectMode = !!(options && options.objectMode);
+      if (isDuplex) this.objectMode = this.objectMode || !!(options && options.writableObjectMode);
+      this.highWaterMark = options ? getHighWaterMark(this, options, "writableHighWaterMark", isDuplex) : getDefaultHighWaterMark(false);
+      this.finalCalled = false;
+      this.needDrain = false;
+      this.ending = false;
+      this.ended = false;
+      this.finished = false;
+      this.destroyed = false;
+      const noDecode = !!(options && options.decodeStrings === false);
+      this.decodeStrings = !noDecode;
+      this.defaultEncoding = options && options.defaultEncoding || "utf8";
+      this.length = 0;
+      this.writing = false;
+      this.corked = 0;
+      this.sync = true;
+      this.bufferProcessing = false;
+      this.onwrite = onwrite.bind(void 0, stream);
+      this.writecb = null;
+      this.writelen = 0;
+      this.afterWriteTickInfo = null;
+      resetBuffer(this);
+      this.pendingcb = 0;
+      this.constructed = true;
+      this.prefinished = false;
+      this.errorEmitted = false;
+      this.emitClose = !options || options.emitClose !== false;
+      this.autoDestroy = !options || options.autoDestroy !== false;
+      this.errored = null;
+      this.closed = false;
+      this.closeEmitted = false;
+      this[kOnFinished] = [];
+    }
+    function resetBuffer(state) {
+      state.buffered = [];
+      state.bufferedIndex = 0;
+      state.allBuffers = true;
+      state.allNoop = true;
+    }
+    WritableState.prototype.getBuffer = function getBuffer() {
+      return ArrayPrototypeSlice(this.buffered, this.bufferedIndex);
+    };
+    ObjectDefineProperty(WritableState.prototype, "bufferedRequestCount", {
+      __proto__: null,
+      get() {
+        return this.buffered.length - this.bufferedIndex;
+      }
+    });
+    function Writable(options) {
+      const isDuplex = this instanceof require_duplex();
+      if (!isDuplex && !FunctionPrototypeSymbolHasInstance(Writable, this)) return new Writable(options);
+      this._writableState = new WritableState(options, this, isDuplex);
+      if (options) {
+        if (typeof options.write === "function") this._write = options.write;
+        if (typeof options.writev === "function") this._writev = options.writev;
+        if (typeof options.destroy === "function") this._destroy = options.destroy;
+        if (typeof options.final === "function") this._final = options.final;
+        if (typeof options.construct === "function") this._construct = options.construct;
+        if (options.signal) addAbortSignal(options.signal, this);
+      }
+      Stream2.call(this, options);
+      destroyImpl.construct(this, () => {
+        const state = this._writableState;
+        if (!state.writing) {
+          clearBuffer(this, state);
+        }
+        finishMaybe(this, state);
+      });
+    }
+    ObjectDefineProperty(Writable, SymbolHasInstance, {
+      __proto__: null,
+      value: function(object) {
+        if (FunctionPrototypeSymbolHasInstance(this, object)) return true;
+        if (this !== Writable) return false;
+        return object && object._writableState instanceof WritableState;
+      }
+    });
+    Writable.prototype.pipe = function() {
+      errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE());
+    };
+    function _write(stream, chunk, encoding, cb) {
+      const state = stream._writableState;
+      if (typeof encoding === "function") {
+        cb = encoding;
+        encoding = state.defaultEncoding;
+      } else {
+        if (!encoding) encoding = state.defaultEncoding;
+        else if (encoding !== "buffer" && !Buffer3.isEncoding(encoding)) throw new ERR_UNKNOWN_ENCODING(encoding);
+        if (typeof cb !== "function") cb = nop;
+      }
+      if (chunk === null) {
+        throw new ERR_STREAM_NULL_VALUES();
+      } else if (!state.objectMode) {
+        if (typeof chunk === "string") {
+          if (state.decodeStrings !== false) {
+            chunk = Buffer3.from(chunk, encoding);
+            encoding = "buffer";
+          }
+        } else if (chunk instanceof Buffer3) {
+          encoding = "buffer";
+        } else if (Stream2._isUint8Array(chunk)) {
+          chunk = Stream2._uint8ArrayToBuffer(chunk);
+          encoding = "buffer";
+        } else {
+          throw new ERR_INVALID_ARG_TYPE("chunk", ["string", "Buffer", "Uint8Array"], chunk);
+        }
+      }
+      let err;
+      if (state.ending) {
+        err = new ERR_STREAM_WRITE_AFTER_END();
+      } else if (state.destroyed) {
+        err = new ERR_STREAM_DESTROYED("write");
+      }
+      if (err) {
+        process2.nextTick(cb, err);
+        errorOrDestroy(stream, err, true);
+        return err;
+      }
+      state.pendingcb++;
+      return writeOrBuffer(stream, state, chunk, encoding, cb);
+    }
+    Writable.prototype.write = function(chunk, encoding, cb) {
+      return _write(this, chunk, encoding, cb) === true;
+    };
+    Writable.prototype.cork = function() {
+      this._writableState.corked++;
+    };
+    Writable.prototype.uncork = function() {
+      const state = this._writableState;
+      if (state.corked) {
+        state.corked--;
+        if (!state.writing) clearBuffer(this, state);
+      }
+    };
+    Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
+      if (typeof encoding === "string") encoding = StringPrototypeToLowerCase(encoding);
+      if (!Buffer3.isEncoding(encoding)) throw new ERR_UNKNOWN_ENCODING(encoding);
+      this._writableState.defaultEncoding = encoding;
+      return this;
+    };
+    function writeOrBuffer(stream, state, chunk, encoding, callback) {
+      const len = state.objectMode ? 1 : chunk.length;
+      state.length += len;
+      const ret = state.length < state.highWaterMark;
+      if (!ret) state.needDrain = true;
+      if (state.writing || state.corked || state.errored || !state.constructed) {
+        state.buffered.push({
+          chunk,
+          encoding,
+          callback
+        });
+        if (state.allBuffers && encoding !== "buffer") {
+          state.allBuffers = false;
+        }
+        if (state.allNoop && callback !== nop) {
+          state.allNoop = false;
+        }
+      } else {
+        state.writelen = len;
+        state.writecb = callback;
+        state.writing = true;
+        state.sync = true;
+        stream._write(chunk, encoding, state.onwrite);
+        state.sync = false;
+      }
+      return ret && !state.errored && !state.destroyed;
+    }
+    function doWrite(stream, state, writev, len, chunk, encoding, cb) {
+      state.writelen = len;
+      state.writecb = cb;
+      state.writing = true;
+      state.sync = true;
+      if (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED("write"));
+      else if (writev) stream._writev(chunk, state.onwrite);
+      else stream._write(chunk, encoding, state.onwrite);
+      state.sync = false;
+    }
+    function onwriteError(stream, state, er, cb) {
+      --state.pendingcb;
+      cb(er);
+      errorBuffer(state);
+      errorOrDestroy(stream, er);
+    }
+    function onwrite(stream, er) {
+      const state = stream._writableState;
+      const sync = state.sync;
+      const cb = state.writecb;
+      if (typeof cb !== "function") {
+        errorOrDestroy(stream, new ERR_MULTIPLE_CALLBACK());
+        return;
+      }
+      state.writing = false;
+      state.writecb = null;
+      state.length -= state.writelen;
+      state.writelen = 0;
+      if (er) {
+        er.stack;
+        if (!state.errored) {
+          state.errored = er;
+        }
+        if (stream._readableState && !stream._readableState.errored) {
+          stream._readableState.errored = er;
+        }
+        if (sync) {
+          process2.nextTick(onwriteError, stream, state, er, cb);
+        } else {
+          onwriteError(stream, state, er, cb);
+        }
+      } else {
+        if (state.buffered.length > state.bufferedIndex) {
+          clearBuffer(stream, state);
+        }
+        if (sync) {
+          if (state.afterWriteTickInfo !== null && state.afterWriteTickInfo.cb === cb) {
+            state.afterWriteTickInfo.count++;
+          } else {
+            state.afterWriteTickInfo = {
+              count: 1,
+              cb,
+              stream,
+              state
+            };
+            process2.nextTick(afterWriteTick, state.afterWriteTickInfo);
+          }
+        } else {
+          afterWrite(stream, state, 1, cb);
+        }
+      }
+    }
+    function afterWriteTick({ stream, state, count, cb }) {
+      state.afterWriteTickInfo = null;
+      return afterWrite(stream, state, count, cb);
+    }
+    function afterWrite(stream, state, count, cb) {
+      const needDrain = !state.ending && !stream.destroyed && state.length === 0 && state.needDrain;
+      if (needDrain) {
+        state.needDrain = false;
+        stream.emit("drain");
+      }
+      while (count-- > 0) {
+        state.pendingcb--;
+        cb();
+      }
+      if (state.destroyed) {
+        errorBuffer(state);
+      }
+      finishMaybe(stream, state);
+    }
+    function errorBuffer(state) {
+      if (state.writing) {
+        return;
+      }
+      for (let n = state.bufferedIndex; n < state.buffered.length; ++n) {
+        var _state$errored;
+        const { chunk, callback } = state.buffered[n];
+        const len = state.objectMode ? 1 : chunk.length;
+        state.length -= len;
+        callback(
+          (_state$errored = state.errored) !== null && _state$errored !== void 0 ? _state$errored : new ERR_STREAM_DESTROYED("write")
+        );
+      }
+      const onfinishCallbacks = state[kOnFinished].splice(0);
+      for (let i = 0; i < onfinishCallbacks.length; i++) {
+        var _state$errored2;
+        onfinishCallbacks[i](
+          (_state$errored2 = state.errored) !== null && _state$errored2 !== void 0 ? _state$errored2 : new ERR_STREAM_DESTROYED("end")
+        );
+      }
+      resetBuffer(state);
+    }
+    function clearBuffer(stream, state) {
+      if (state.corked || state.bufferProcessing || state.destroyed || !state.constructed) {
+        return;
+      }
+      const { buffered, bufferedIndex, objectMode } = state;
+      const bufferedLength = buffered.length - bufferedIndex;
+      if (!bufferedLength) {
+        return;
+      }
+      let i = bufferedIndex;
+      state.bufferProcessing = true;
+      if (bufferedLength > 1 && stream._writev) {
+        state.pendingcb -= bufferedLength - 1;
+        const callback = state.allNoop ? nop : (err) => {
+          for (let n = i; n < buffered.length; ++n) {
+            buffered[n].callback(err);
+          }
+        };
+        const chunks = state.allNoop && i === 0 ? buffered : ArrayPrototypeSlice(buffered, i);
+        chunks.allBuffers = state.allBuffers;
+        doWrite(stream, state, true, state.length, chunks, "", callback);
+        resetBuffer(state);
+      } else {
+        do {
+          const { chunk, encoding, callback } = buffered[i];
+          buffered[i++] = null;
+          const len = objectMode ? 1 : chunk.length;
+          doWrite(stream, state, false, len, chunk, encoding, callback);
+        } while (i < buffered.length && !state.writing);
+        if (i === buffered.length) {
+          resetBuffer(state);
+        } else if (i > 256) {
+          buffered.splice(0, i);
+          state.bufferedIndex = 0;
+        } else {
+          state.bufferedIndex = i;
+        }
+      }
+      state.bufferProcessing = false;
+    }
+    Writable.prototype._write = function(chunk, encoding, cb) {
+      if (this._writev) {
+        this._writev(
+          [
+            {
+              chunk,
+              encoding
+            }
+          ],
+          cb
+        );
+      } else {
+        throw new ERR_METHOD_NOT_IMPLEMENTED("_write()");
+      }
+    };
+    Writable.prototype._writev = null;
+    Writable.prototype.end = function(chunk, encoding, cb) {
+      const state = this._writableState;
+      if (typeof chunk === "function") {
+        cb = chunk;
+        chunk = null;
+        encoding = null;
+      } else if (typeof encoding === "function") {
+        cb = encoding;
+        encoding = null;
+      }
+      let err;
+      if (chunk !== null && chunk !== void 0) {
+        const ret = _write(this, chunk, encoding);
+        if (ret instanceof Error2) {
+          err = ret;
+        }
+      }
+      if (state.corked) {
+        state.corked = 1;
+        this.uncork();
+      }
+      if (err) {
+      } else if (!state.errored && !state.ending) {
+        state.ending = true;
+        finishMaybe(this, state, true);
+        state.ended = true;
+      } else if (state.finished) {
+        err = new ERR_STREAM_ALREADY_FINISHED("end");
+      } else if (state.destroyed) {
+        err = new ERR_STREAM_DESTROYED("end");
+      }
+      if (typeof cb === "function") {
+        if (err || state.finished) {
+          process2.nextTick(cb, err);
+        } else {
+          state[kOnFinished].push(cb);
+        }
+      }
+      return this;
+    };
+    function needFinish(state) {
+      return state.ending && !state.destroyed && state.constructed && state.length === 0 && !state.errored && state.buffered.length === 0 && !state.finished && !state.writing && !state.errorEmitted && !state.closeEmitted;
+    }
+    function callFinal(stream, state) {
+      let called = false;
+      function onFinish(err) {
+        if (called) {
+          errorOrDestroy(stream, err !== null && err !== void 0 ? err : ERR_MULTIPLE_CALLBACK());
+          return;
+        }
+        called = true;
+        state.pendingcb--;
+        if (err) {
+          const onfinishCallbacks = state[kOnFinished].splice(0);
+          for (let i = 0; i < onfinishCallbacks.length; i++) {
+            onfinishCallbacks[i](err);
+          }
+          errorOrDestroy(stream, err, state.sync);
+        } else if (needFinish(state)) {
+          state.prefinished = true;
+          stream.emit("prefinish");
+          state.pendingcb++;
+          process2.nextTick(finish, stream, state);
+        }
+      }
+      state.sync = true;
+      state.pendingcb++;
+      try {
+        stream._final(onFinish);
+      } catch (err) {
+        onFinish(err);
+      }
+      state.sync = false;
+    }
+    function prefinish(stream, state) {
+      if (!state.prefinished && !state.finalCalled) {
+        if (typeof stream._final === "function" && !state.destroyed) {
+          state.finalCalled = true;
+          callFinal(stream, state);
+        } else {
+          state.prefinished = true;
+          stream.emit("prefinish");
+        }
+      }
+    }
+    function finishMaybe(stream, state, sync) {
+      if (needFinish(state)) {
+        prefinish(stream, state);
+        if (state.pendingcb === 0) {
+          if (sync) {
+            state.pendingcb++;
+            process2.nextTick(
+              (stream2, state2) => {
+                if (needFinish(state2)) {
+                  finish(stream2, state2);
+                } else {
+                  state2.pendingcb--;
+                }
+              },
+              stream,
+              state
+            );
+          } else if (needFinish(state)) {
+            state.pendingcb++;
+            finish(stream, state);
+          }
+        }
+      }
+    }
+    function finish(stream, state) {
+      state.pendingcb--;
+      state.finished = true;
+      const onfinishCallbacks = state[kOnFinished].splice(0);
+      for (let i = 0; i < onfinishCallbacks.length; i++) {
+        onfinishCallbacks[i]();
+      }
+      stream.emit("finish");
+      if (state.autoDestroy) {
+        const rState = stream._readableState;
+        const autoDestroy = !rState || rState.autoDestroy && // We don't expect the readable to ever 'end'
+        // if readable is explicitly set to false.
+        (rState.endEmitted || rState.readable === false);
+        if (autoDestroy) {
+          stream.destroy();
+        }
+      }
+    }
+    ObjectDefineProperties(Writable.prototype, {
+      closed: {
+        __proto__: null,
+        get() {
+          return this._writableState ? this._writableState.closed : false;
+        }
+      },
+      destroyed: {
+        __proto__: null,
+        get() {
+          return this._writableState ? this._writableState.destroyed : false;
+        },
+        set(value) {
+          if (this._writableState) {
+            this._writableState.destroyed = value;
+          }
+        }
+      },
+      writable: {
+        __proto__: null,
+        get() {
+          const w = this._writableState;
+          return !!w && w.writable !== false && !w.destroyed && !w.errored && !w.ending && !w.ended;
+        },
+        set(val) {
+          if (this._writableState) {
+            this._writableState.writable = !!val;
+          }
+        }
+      },
+      writableFinished: {
+        __proto__: null,
+        get() {
+          return this._writableState ? this._writableState.finished : false;
+        }
+      },
+      writableObjectMode: {
+        __proto__: null,
+        get() {
+          return this._writableState ? this._writableState.objectMode : false;
+        }
+      },
+      writableBuffer: {
+        __proto__: null,
+        get() {
+          return this._writableState && this._writableState.getBuffer();
+        }
+      },
+      writableEnded: {
+        __proto__: null,
+        get() {
+          return this._writableState ? this._writableState.ending : false;
+        }
+      },
+      writableNeedDrain: {
+        __proto__: null,
+        get() {
+          const wState = this._writableState;
+          if (!wState) return false;
+          return !wState.destroyed && !wState.ending && wState.needDrain;
+        }
+      },
+      writableHighWaterMark: {
+        __proto__: null,
+        get() {
+          return this._writableState && this._writableState.highWaterMark;
+        }
+      },
+      writableCorked: {
+        __proto__: null,
+        get() {
+          return this._writableState ? this._writableState.corked : 0;
+        }
+      },
+      writableLength: {
+        __proto__: null,
+        get() {
+          return this._writableState && this._writableState.length;
+        }
+      },
+      errored: {
+        __proto__: null,
+        enumerable: false,
+        get() {
+          return this._writableState ? this._writableState.errored : null;
+        }
+      },
+      writableAborted: {
+        __proto__: null,
+        enumerable: false,
+        get: function() {
+          return !!(this._writableState.writable !== false && (this._writableState.destroyed || this._writableState.errored) && !this._writableState.finished);
+        }
+      }
+    });
+    var destroy = destroyImpl.destroy;
+    Writable.prototype.destroy = function(err, cb) {
+      const state = this._writableState;
+      if (!state.destroyed && (state.bufferedIndex < state.buffered.length || state[kOnFinished].length)) {
+        process2.nextTick(errorBuffer, state);
+      }
+      destroy.call(this, err, cb);
+      return this;
+    };
+    Writable.prototype._undestroy = destroyImpl.undestroy;
+    Writable.prototype._destroy = function(err, cb) {
+      cb(err);
+    };
+    Writable.prototype[EE.captureRejectionSymbol] = function(err) {
+      this.destroy(err);
+    };
+    var webStreamsAdapters;
+    function lazyWebStreams() {
+      if (webStreamsAdapters === void 0) webStreamsAdapters = {};
+      return webStreamsAdapters;
+    }
+    Writable.fromWeb = function(writableStream, options) {
+      return lazyWebStreams().newStreamWritableFromWritableStream(writableStream, options);
+    };
+    Writable.toWeb = function(streamWritable) {
+      return lazyWebStreams().newWritableStreamFromStreamWritable(streamWritable);
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/duplexify.js
+var require_duplexify = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/duplexify.js"(exports2, module2) {
+    var process2 = require_process();
+    var bufferModule = require("buffer");
+    var {
+      isReadable,
+      isWritable,
+      isIterable,
+      isNodeStream,
+      isReadableNodeStream,
+      isWritableNodeStream,
+      isDuplexNodeStream,
+      isReadableStream,
+      isWritableStream
+    } = require_utils();
+    var eos = require_end_of_stream();
+    var {
+      AbortError,
+      codes: { ERR_INVALID_ARG_TYPE, ERR_INVALID_RETURN_VALUE }
+    } = require_errors();
+    var { destroyer } = require_destroy();
+    var Duplex = require_duplex();
+    var Readable = require_readable();
+    var Writable = require_writable();
+    var { createDeferredPromise } = require_util();
+    var from = require_from();
+    var Blob = globalThis.Blob || bufferModule.Blob;
+    var isBlob = typeof Blob !== "undefined" ? function isBlob2(b) {
+      return b instanceof Blob;
+    } : function isBlob2(b) {
+      return false;
+    };
+    var AbortController = globalThis.AbortController || require("abort-controller").AbortController;
+    var { FunctionPrototypeCall } = require_primordials();
+    var Duplexify = class extends Duplex {
+      constructor(options) {
+        super(options);
+        if ((options === null || options === void 0 ? void 0 : options.readable) === false) {
+          this._readableState.readable = false;
+          this._readableState.ended = true;
+          this._readableState.endEmitted = true;
+        }
+        if ((options === null || options === void 0 ? void 0 : options.writable) === false) {
+          this._writableState.writable = false;
+          this._writableState.ending = true;
+          this._writableState.ended = true;
+          this._writableState.finished = true;
+        }
+      }
+    };
+    module2.exports = function duplexify(body, name) {
+      if (isDuplexNodeStream(body)) {
+        return body;
+      }
+      if (isReadableNodeStream(body)) {
+        return _duplexify({
+          readable: body
+        });
+      }
+      if (isWritableNodeStream(body)) {
+        return _duplexify({
+          writable: body
+        });
+      }
+      if (isNodeStream(body)) {
+        return _duplexify({
+          writable: false,
+          readable: false
+        });
+      }
+      if (isReadableStream(body)) {
+        return _duplexify({
+          readable: Readable.fromWeb(body)
+        });
+      }
+      if (isWritableStream(body)) {
+        return _duplexify({
+          writable: Writable.fromWeb(body)
+        });
+      }
+      if (typeof body === "function") {
+        const { value, write, final, destroy } = fromAsyncGen(body);
+        if (isIterable(value)) {
+          return from(Duplexify, value, {
+            // TODO (ronag): highWaterMark?
+            objectMode: true,
+            write,
+            final,
+            destroy
+          });
+        }
+        const then2 = value === null || value === void 0 ? void 0 : value.then;
+        if (typeof then2 === "function") {
+          let d;
+          const promise = FunctionPrototypeCall(
+            then2,
+            value,
+            (val) => {
+              if (val != null) {
+                throw new ERR_INVALID_RETURN_VALUE("nully", "body", val);
+              }
+            },
+            (err) => {
+              destroyer(d, err);
+            }
+          );
+          return d = new Duplexify({
+            // TODO (ronag): highWaterMark?
+            objectMode: true,
+            readable: false,
+            write,
+            final(cb) {
+              final(async () => {
+                try {
+                  await promise;
+                  process2.nextTick(cb, null);
+                } catch (err) {
+                  process2.nextTick(cb, err);
+                }
+              });
+            },
+            destroy
+          });
+        }
+        throw new ERR_INVALID_RETURN_VALUE("Iterable, AsyncIterable or AsyncFunction", name, value);
+      }
+      if (isBlob(body)) {
+        return duplexify(body.arrayBuffer());
+      }
+      if (isIterable(body)) {
+        return from(Duplexify, body, {
+          // TODO (ronag): highWaterMark?
+          objectMode: true,
+          writable: false
+        });
+      }
+      if (isReadableStream(body === null || body === void 0 ? void 0 : body.readable) && isWritableStream(body === null || body === void 0 ? void 0 : body.writable)) {
+        return Duplexify.fromWeb(body);
+      }
+      if (typeof (body === null || body === void 0 ? void 0 : body.writable) === "object" || typeof (body === null || body === void 0 ? void 0 : body.readable) === "object") {
+        const readable = body !== null && body !== void 0 && body.readable ? isReadableNodeStream(body === null || body === void 0 ? void 0 : body.readable) ? body === null || body === void 0 ? void 0 : body.readable : duplexify(body.readable) : void 0;
+        const writable = body !== null && body !== void 0 && body.writable ? isWritableNodeStream(body === null || body === void 0 ? void 0 : body.writable) ? body === null || body === void 0 ? void 0 : body.writable : duplexify(body.writable) : void 0;
+        return _duplexify({
+          readable,
+          writable
+        });
+      }
+      const then = body === null || body === void 0 ? void 0 : body.then;
+      if (typeof then === "function") {
+        let d;
+        FunctionPrototypeCall(
+          then,
+          body,
+          (val) => {
+            if (val != null) {
+              d.push(val);
+            }
+            d.push(null);
+          },
+          (err) => {
+            destroyer(d, err);
+          }
+        );
+        return d = new Duplexify({
+          objectMode: true,
+          writable: false,
+          read() {
+          }
+        });
+      }
+      throw new ERR_INVALID_ARG_TYPE(
+        name,
+        [
+          "Blob",
+          "ReadableStream",
+          "WritableStream",
+          "Stream",
+          "Iterable",
+          "AsyncIterable",
+          "Function",
+          "{ readable, writable } pair",
+          "Promise"
+        ],
+        body
+      );
+    };
+    function fromAsyncGen(fn) {
+      let { promise, resolve } = createDeferredPromise();
+      const ac = new AbortController();
+      const signal = ac.signal;
+      const value = fn(
+        (async function* () {
+          while (true) {
+            const _promise = promise;
+            promise = null;
+            const { chunk, done, cb } = await _promise;
+            process2.nextTick(cb);
+            if (done) return;
+            if (signal.aborted)
+              throw new AbortError(void 0, {
+                cause: signal.reason
+              });
+            ({ promise, resolve } = createDeferredPromise());
+            yield chunk;
+          }
+        })(),
+        {
+          signal
+        }
+      );
+      return {
+        value,
+        write(chunk, encoding, cb) {
+          const _resolve = resolve;
+          resolve = null;
+          _resolve({
+            chunk,
+            done: false,
+            cb
+          });
+        },
+        final(cb) {
+          const _resolve = resolve;
+          resolve = null;
+          _resolve({
+            done: true,
+            cb
+          });
+        },
+        destroy(err, cb) {
+          ac.abort();
+          cb(err);
+        }
+      };
+    }
+    function _duplexify(pair) {
+      const r = pair.readable && typeof pair.readable.read !== "function" ? Readable.wrap(pair.readable) : pair.readable;
+      const w = pair.writable;
+      let readable = !!isReadable(r);
+      let writable = !!isWritable(w);
+      let ondrain;
+      let onfinish;
+      let onreadable;
+      let onclose;
+      let d;
+      function onfinished(err) {
+        const cb = onclose;
+        onclose = null;
+        if (cb) {
+          cb(err);
+        } else if (err) {
+          d.destroy(err);
+        }
+      }
+      d = new Duplexify({
+        // TODO (ronag): highWaterMark?
+        readableObjectMode: !!(r !== null && r !== void 0 && r.readableObjectMode),
+        writableObjectMode: !!(w !== null && w !== void 0 && w.writableObjectMode),
+        readable,
+        writable
+      });
+      if (writable) {
+        eos(w, (err) => {
+          writable = false;
+          if (err) {
+            destroyer(r, err);
+          }
+          onfinished(err);
+        });
+        d._write = function(chunk, encoding, callback) {
+          if (w.write(chunk, encoding)) {
+            callback();
+          } else {
+            ondrain = callback;
+          }
+        };
+        d._final = function(callback) {
+          w.end();
+          onfinish = callback;
+        };
+        w.on("drain", function() {
+          if (ondrain) {
+            const cb = ondrain;
+            ondrain = null;
+            cb();
+          }
+        });
+        w.on("finish", function() {
+          if (onfinish) {
+            const cb = onfinish;
+            onfinish = null;
+            cb();
+          }
+        });
+      }
+      if (readable) {
+        eos(r, (err) => {
+          readable = false;
+          if (err) {
+            destroyer(r, err);
+          }
+          onfinished(err);
+        });
+        r.on("readable", function() {
+          if (onreadable) {
+            const cb = onreadable;
+            onreadable = null;
+            cb();
+          }
+        });
+        r.on("end", function() {
+          d.push(null);
+        });
+        d._read = function() {
+          while (true) {
+            const buf = r.read();
+            if (buf === null) {
+              onreadable = d._read;
+              return;
+            }
+            if (!d.push(buf)) {
+              return;
+            }
+          }
+        };
+      }
+      d._destroy = function(err, callback) {
+        if (!err && onclose !== null) {
+          err = new AbortError();
+        }
+        onreadable = null;
+        ondrain = null;
+        onfinish = null;
+        if (onclose === null) {
+          callback(err);
+        } else {
+          onclose = callback;
+          destroyer(w, err);
+          destroyer(r, err);
+        }
+      };
+      return d;
+    }
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/duplex.js
+var require_duplex = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/duplex.js"(exports2, module2) {
+    "use strict";
+    var {
+      ObjectDefineProperties,
+      ObjectGetOwnPropertyDescriptor,
+      ObjectKeys,
+      ObjectSetPrototypeOf
+    } = require_primordials();
+    module2.exports = Duplex;
+    var Readable = require_readable();
+    var Writable = require_writable();
+    ObjectSetPrototypeOf(Duplex.prototype, Readable.prototype);
+    ObjectSetPrototypeOf(Duplex, Readable);
+    {
+      const keys = ObjectKeys(Writable.prototype);
+      for (let i = 0; i < keys.length; i++) {
+        const method = keys[i];
+        if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
+      }
+    }
+    function Duplex(options) {
+      if (!(this instanceof Duplex)) return new Duplex(options);
+      Readable.call(this, options);
+      Writable.call(this, options);
+      if (options) {
+        this.allowHalfOpen = options.allowHalfOpen !== false;
+        if (options.readable === false) {
+          this._readableState.readable = false;
+          this._readableState.ended = true;
+          this._readableState.endEmitted = true;
+        }
+        if (options.writable === false) {
+          this._writableState.writable = false;
+          this._writableState.ending = true;
+          this._writableState.ended = true;
+          this._writableState.finished = true;
+        }
+      } else {
+        this.allowHalfOpen = true;
+      }
+    }
+    ObjectDefineProperties(Duplex.prototype, {
+      writable: {
+        __proto__: null,
+        ...ObjectGetOwnPropertyDescriptor(Writable.prototype, "writable")
+      },
+      writableHighWaterMark: {
+        __proto__: null,
+        ...ObjectGetOwnPropertyDescriptor(Writable.prototype, "writableHighWaterMark")
+      },
+      writableObjectMode: {
+        __proto__: null,
+        ...ObjectGetOwnPropertyDescriptor(Writable.prototype, "writableObjectMode")
+      },
+      writableBuffer: {
+        __proto__: null,
+        ...ObjectGetOwnPropertyDescriptor(Writable.prototype, "writableBuffer")
+      },
+      writableLength: {
+        __proto__: null,
+        ...ObjectGetOwnPropertyDescriptor(Writable.prototype, "writableLength")
+      },
+      writableFinished: {
+        __proto__: null,
+        ...ObjectGetOwnPropertyDescriptor(Writable.prototype, "writableFinished")
+      },
+      writableCorked: {
+        __proto__: null,
+        ...ObjectGetOwnPropertyDescriptor(Writable.prototype, "writableCorked")
+      },
+      writableEnded: {
+        __proto__: null,
+        ...ObjectGetOwnPropertyDescriptor(Writable.prototype, "writableEnded")
+      },
+      writableNeedDrain: {
+        __proto__: null,
+        ...ObjectGetOwnPropertyDescriptor(Writable.prototype, "writableNeedDrain")
+      },
+      destroyed: {
+        __proto__: null,
+        get() {
+          if (this._readableState === void 0 || this._writableState === void 0) {
+            return false;
+          }
+          return this._readableState.destroyed && this._writableState.destroyed;
+        },
+        set(value) {
+          if (this._readableState && this._writableState) {
+            this._readableState.destroyed = value;
+            this._writableState.destroyed = value;
+          }
+        }
+      }
+    });
+    var webStreamsAdapters;
+    function lazyWebStreams() {
+      if (webStreamsAdapters === void 0) webStreamsAdapters = {};
+      return webStreamsAdapters;
+    }
+    Duplex.fromWeb = function(pair, options) {
+      return lazyWebStreams().newStreamDuplexFromReadableWritablePair(pair, options);
+    };
+    Duplex.toWeb = function(duplex) {
+      return lazyWebStreams().newReadableWritablePairFromDuplex(duplex);
+    };
+    var duplexify;
+    Duplex.from = function(body) {
+      if (!duplexify) {
+        duplexify = require_duplexify();
+      }
+      return duplexify(body, "body");
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/transform.js
+var require_transform = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/transform.js"(exports2, module2) {
+    "use strict";
+    var { ObjectSetPrototypeOf, Symbol: Symbol2 } = require_primordials();
+    module2.exports = Transform;
+    var { ERR_METHOD_NOT_IMPLEMENTED } = require_errors().codes;
+    var Duplex = require_duplex();
+    var { getHighWaterMark } = require_state();
+    ObjectSetPrototypeOf(Transform.prototype, Duplex.prototype);
+    ObjectSetPrototypeOf(Transform, Duplex);
+    var kCallback = Symbol2("kCallback");
+    function Transform(options) {
+      if (!(this instanceof Transform)) return new Transform(options);
+      const readableHighWaterMark = options ? getHighWaterMark(this, options, "readableHighWaterMark", true) : null;
+      if (readableHighWaterMark === 0) {
+        options = {
+          ...options,
+          highWaterMark: null,
+          readableHighWaterMark,
+          // TODO (ronag): 0 is not optimal since we have
+          // a "bug" where we check needDrain before calling _write and not after.
+          // Refs: https://github.com/nodejs/node/pull/32887
+          // Refs: https://github.com/nodejs/node/pull/35941
+          writableHighWaterMark: options.writableHighWaterMark || 0
+        };
+      }
+      Duplex.call(this, options);
+      this._readableState.sync = false;
+      this[kCallback] = null;
+      if (options) {
+        if (typeof options.transform === "function") this._transform = options.transform;
+        if (typeof options.flush === "function") this._flush = options.flush;
+      }
+      this.on("prefinish", prefinish);
+    }
+    function final(cb) {
+      if (typeof this._flush === "function" && !this.destroyed) {
+        this._flush((er, data) => {
+          if (er) {
+            if (cb) {
+              cb(er);
+            } else {
+              this.destroy(er);
+            }
+            return;
+          }
+          if (data != null) {
+            this.push(data);
+          }
+          this.push(null);
+          if (cb) {
+            cb();
+          }
+        });
+      } else {
+        this.push(null);
+        if (cb) {
+          cb();
+        }
+      }
+    }
+    function prefinish() {
+      if (this._final !== final) {
+        final.call(this);
+      }
+    }
+    Transform.prototype._final = final;
+    Transform.prototype._transform = function(chunk, encoding, callback) {
+      throw new ERR_METHOD_NOT_IMPLEMENTED("_transform()");
+    };
+    Transform.prototype._write = function(chunk, encoding, callback) {
+      const rState = this._readableState;
+      const wState = this._writableState;
+      const length = rState.length;
+      this._transform(chunk, encoding, (err, val) => {
+        if (err) {
+          callback(err);
+          return;
+        }
+        if (val != null) {
+          this.push(val);
+        }
+        if (wState.ended || // Backwards compat.
+        length === rState.length || // Backwards compat.
+        rState.length < rState.highWaterMark) {
+          callback();
+        } else {
+          this[kCallback] = callback;
+        }
+      });
+    };
+    Transform.prototype._read = function() {
+      if (this[kCallback]) {
+        const callback = this[kCallback];
+        this[kCallback] = null;
+        callback();
+      }
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/passthrough.js
+var require_passthrough = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/passthrough.js"(exports2, module2) {
+    "use strict";
+    var { ObjectSetPrototypeOf } = require_primordials();
+    module2.exports = PassThrough;
+    var Transform = require_transform();
+    ObjectSetPrototypeOf(PassThrough.prototype, Transform.prototype);
+    ObjectSetPrototypeOf(PassThrough, Transform);
+    function PassThrough(options) {
+      if (!(this instanceof PassThrough)) return new PassThrough(options);
+      Transform.call(this, options);
+    }
+    PassThrough.prototype._transform = function(chunk, encoding, cb) {
+      cb(null, chunk);
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/pipeline.js
+var require_pipeline = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/pipeline.js"(exports2, module2) {
+    var process2 = require_process();
+    var { ArrayIsArray, Promise: Promise2, SymbolAsyncIterator, SymbolDispose } = require_primordials();
+    var eos = require_end_of_stream();
+    var { once } = require_util();
+    var destroyImpl = require_destroy();
+    var Duplex = require_duplex();
+    var {
+      aggregateTwoErrors,
+      codes: {
+        ERR_INVALID_ARG_TYPE,
+        ERR_INVALID_RETURN_VALUE,
+        ERR_MISSING_ARGS,
+        ERR_STREAM_DESTROYED,
+        ERR_STREAM_PREMATURE_CLOSE
+      },
+      AbortError
+    } = require_errors();
+    var { validateFunction, validateAbortSignal } = require_validators();
+    var {
+      isIterable,
+      isReadable,
+      isReadableNodeStream,
+      isNodeStream,
+      isTransformStream,
+      isWebStream,
+      isReadableStream,
+      isReadableFinished
+    } = require_utils();
+    var AbortController = globalThis.AbortController || require("abort-controller").AbortController;
+    var PassThrough;
+    var Readable;
+    var addAbortListener;
+    function destroyer(stream, reading, writing) {
+      let finished = false;
+      stream.on("close", () => {
+        finished = true;
+      });
+      const cleanup = eos(
+        stream,
+        {
+          readable: reading,
+          writable: writing
+        },
+        (err) => {
+          finished = !err;
+        }
+      );
+      return {
+        destroy: (err) => {
+          if (finished) return;
+          finished = true;
+          destroyImpl.destroyer(stream, err || new ERR_STREAM_DESTROYED("pipe"));
+        },
+        cleanup
+      };
+    }
+    function popCallback(streams) {
+      validateFunction(streams[streams.length - 1], "streams[stream.length - 1]");
+      return streams.pop();
+    }
+    function makeAsyncIterable(val) {
+      if (isIterable(val)) {
+        return val;
+      } else if (isReadableNodeStream(val)) {
+        return fromReadable(val);
+      }
+      throw new ERR_INVALID_ARG_TYPE("val", ["Readable", "Iterable", "AsyncIterable"], val);
+    }
+    async function* fromReadable(val) {
+      if (!Readable) {
+        Readable = require_readable();
+      }
+      yield* Readable.prototype[SymbolAsyncIterator].call(val);
+    }
+    async function pumpToNode(iterable, writable, finish, { end }) {
+      let error;
+      let onresolve = null;
+      const resume = (err) => {
+        if (err) {
+          error = err;
+        }
+        if (onresolve) {
+          const callback = onresolve;
+          onresolve = null;
+          callback();
+        }
+      };
+      const wait = () => new Promise2((resolve, reject) => {
+        if (error) {
+          reject(error);
+        } else {
+          onresolve = () => {
+            if (error) {
+              reject(error);
+            } else {
+              resolve();
+            }
+          };
+        }
+      });
+      writable.on("drain", resume);
+      const cleanup = eos(
+        writable,
+        {
+          readable: false
+        },
+        resume
+      );
+      try {
+        if (writable.writableNeedDrain) {
+          await wait();
+        }
+        for await (const chunk of iterable) {
+          if (!writable.write(chunk)) {
+            await wait();
+          }
+        }
+        if (end) {
+          writable.end();
+          await wait();
+        }
+        finish();
+      } catch (err) {
+        finish(error !== err ? aggregateTwoErrors(error, err) : err);
+      } finally {
+        cleanup();
+        writable.off("drain", resume);
+      }
+    }
+    async function pumpToWeb(readable, writable, finish, { end }) {
+      if (isTransformStream(writable)) {
+        writable = writable.writable;
+      }
+      const writer = writable.getWriter();
+      try {
+        for await (const chunk of readable) {
+          await writer.ready;
+          writer.write(chunk).catch(() => {
+          });
+        }
+        await writer.ready;
+        if (end) {
+          await writer.close();
+        }
+        finish();
+      } catch (err) {
+        try {
+          await writer.abort(err);
+          finish(err);
+        } catch (err2) {
+          finish(err2);
+        }
+      }
+    }
+    function pipeline(...streams) {
+      return pipelineImpl(streams, once(popCallback(streams)));
+    }
+    function pipelineImpl(streams, callback, opts) {
+      if (streams.length === 1 && ArrayIsArray(streams[0])) {
+        streams = streams[0];
+      }
+      if (streams.length < 2) {
+        throw new ERR_MISSING_ARGS("streams");
+      }
+      const ac = new AbortController();
+      const signal = ac.signal;
+      const outerSignal = opts === null || opts === void 0 ? void 0 : opts.signal;
+      const lastStreamCleanup = [];
+      validateAbortSignal(outerSignal, "options.signal");
+      function abort() {
+        finishImpl(new AbortError());
+      }
+      addAbortListener = addAbortListener || require_util().addAbortListener;
+      let disposable;
+      if (outerSignal) {
+        disposable = addAbortListener(outerSignal, abort);
+      }
+      let error;
+      let value;
+      const destroys = [];
+      let finishCount = 0;
+      function finish(err) {
+        finishImpl(err, --finishCount === 0);
+      }
+      function finishImpl(err, final) {
+        var _disposable;
+        if (err && (!error || error.code === "ERR_STREAM_PREMATURE_CLOSE")) {
+          error = err;
+        }
+        if (!error && !final) {
+          return;
+        }
+        while (destroys.length) {
+          destroys.shift()(error);
+        }
+        ;
+        (_disposable = disposable) === null || _disposable === void 0 ? void 0 : _disposable[SymbolDispose]();
+        ac.abort();
+        if (final) {
+          if (!error) {
+            lastStreamCleanup.forEach((fn) => fn());
+          }
+          process2.nextTick(callback, error, value);
+        }
+      }
+      let ret;
+      for (let i = 0; i < streams.length; i++) {
+        const stream = streams[i];
+        const reading = i < streams.length - 1;
+        const writing = i > 0;
+        const end = reading || (opts === null || opts === void 0 ? void 0 : opts.end) !== false;
+        const isLastStream = i === streams.length - 1;
+        if (isNodeStream(stream)) {
+          let onError2 = function(err) {
+            if (err && err.name !== "AbortError" && err.code !== "ERR_STREAM_PREMATURE_CLOSE") {
+              finish(err);
+            }
+          };
+          var onError = onError2;
+          if (end) {
+            const { destroy, cleanup } = destroyer(stream, reading, writing);
+            destroys.push(destroy);
+            if (isReadable(stream) && isLastStream) {
+              lastStreamCleanup.push(cleanup);
+            }
+          }
+          stream.on("error", onError2);
+          if (isReadable(stream) && isLastStream) {
+            lastStreamCleanup.push(() => {
+              stream.removeListener("error", onError2);
+            });
+          }
+        }
+        if (i === 0) {
+          if (typeof stream === "function") {
+            ret = stream({
+              signal
+            });
+            if (!isIterable(ret)) {
+              throw new ERR_INVALID_RETURN_VALUE("Iterable, AsyncIterable or Stream", "source", ret);
+            }
+          } else if (isIterable(stream) || isReadableNodeStream(stream) || isTransformStream(stream)) {
+            ret = stream;
+          } else {
+            ret = Duplex.from(stream);
+          }
+        } else if (typeof stream === "function") {
+          if (isTransformStream(ret)) {
+            var _ret;
+            ret = makeAsyncIterable((_ret = ret) === null || _ret === void 0 ? void 0 : _ret.readable);
+          } else {
+            ret = makeAsyncIterable(ret);
+          }
+          ret = stream(ret, {
+            signal
+          });
+          if (reading) {
+            if (!isIterable(ret, true)) {
+              throw new ERR_INVALID_RETURN_VALUE("AsyncIterable", `transform[${i - 1}]`, ret);
+            }
+          } else {
+            var _ret2;
+            if (!PassThrough) {
+              PassThrough = require_passthrough();
+            }
+            const pt = new PassThrough({
+              objectMode: true
+            });
+            const then = (_ret2 = ret) === null || _ret2 === void 0 ? void 0 : _ret2.then;
+            if (typeof then === "function") {
+              finishCount++;
+              then.call(
+                ret,
+                (val) => {
+                  value = val;
+                  if (val != null) {
+                    pt.write(val);
+                  }
+                  if (end) {
+                    pt.end();
+                  }
+                  process2.nextTick(finish);
+                },
+                (err) => {
+                  pt.destroy(err);
+                  process2.nextTick(finish, err);
+                }
+              );
+            } else if (isIterable(ret, true)) {
+              finishCount++;
+              pumpToNode(ret, pt, finish, {
+                end
+              });
+            } else if (isReadableStream(ret) || isTransformStream(ret)) {
+              const toRead = ret.readable || ret;
+              finishCount++;
+              pumpToNode(toRead, pt, finish, {
+                end
+              });
+            } else {
+              throw new ERR_INVALID_RETURN_VALUE("AsyncIterable or Promise", "destination", ret);
+            }
+            ret = pt;
+            const { destroy, cleanup } = destroyer(ret, false, true);
+            destroys.push(destroy);
+            if (isLastStream) {
+              lastStreamCleanup.push(cleanup);
+            }
+          }
+        } else if (isNodeStream(stream)) {
+          if (isReadableNodeStream(ret)) {
+            finishCount += 2;
+            const cleanup = pipe(ret, stream, finish, {
+              end
+            });
+            if (isReadable(stream) && isLastStream) {
+              lastStreamCleanup.push(cleanup);
+            }
+          } else if (isTransformStream(ret) || isReadableStream(ret)) {
+            const toRead = ret.readable || ret;
+            finishCount++;
+            pumpToNode(toRead, stream, finish, {
+              end
+            });
+          } else if (isIterable(ret)) {
+            finishCount++;
+            pumpToNode(ret, stream, finish, {
+              end
+            });
+          } else {
+            throw new ERR_INVALID_ARG_TYPE(
+              "val",
+              ["Readable", "Iterable", "AsyncIterable", "ReadableStream", "TransformStream"],
+              ret
+            );
+          }
+          ret = stream;
+        } else if (isWebStream(stream)) {
+          if (isReadableNodeStream(ret)) {
+            finishCount++;
+            pumpToWeb(makeAsyncIterable(ret), stream, finish, {
+              end
+            });
+          } else if (isReadableStream(ret) || isIterable(ret)) {
+            finishCount++;
+            pumpToWeb(ret, stream, finish, {
+              end
+            });
+          } else if (isTransformStream(ret)) {
+            finishCount++;
+            pumpToWeb(ret.readable, stream, finish, {
+              end
+            });
+          } else {
+            throw new ERR_INVALID_ARG_TYPE(
+              "val",
+              ["Readable", "Iterable", "AsyncIterable", "ReadableStream", "TransformStream"],
+              ret
+            );
+          }
+          ret = stream;
+        } else {
+          ret = Duplex.from(stream);
+        }
+      }
+      if (signal !== null && signal !== void 0 && signal.aborted || outerSignal !== null && outerSignal !== void 0 && outerSignal.aborted) {
+        process2.nextTick(abort);
+      }
+      return ret;
+    }
+    function pipe(src, dst, finish, { end }) {
+      let ended = false;
+      dst.on("close", () => {
+        if (!ended) {
+          finish(new ERR_STREAM_PREMATURE_CLOSE());
+        }
+      });
+      src.pipe(dst, {
+        end: false
+      });
+      if (end) {
+        let endFn2 = function() {
+          ended = true;
+          dst.end();
+        };
+        var endFn = endFn2;
+        if (isReadableFinished(src)) {
+          process2.nextTick(endFn2);
+        } else {
+          src.once("end", endFn2);
+        }
+      } else {
+        finish();
+      }
+      eos(
+        src,
+        {
+          readable: true,
+          writable: false
+        },
+        (err) => {
+          const rState = src._readableState;
+          if (err && err.code === "ERR_STREAM_PREMATURE_CLOSE" && rState && rState.ended && !rState.errored && !rState.errorEmitted) {
+            src.once("end", finish).once("error", finish);
+          } else {
+            finish(err);
+          }
+        }
+      );
+      return eos(
+        dst,
+        {
+          readable: false,
+          writable: true
+        },
+        finish
+      );
+    }
+    module2.exports = {
+      pipelineImpl,
+      pipeline
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/compose.js
+var require_compose = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/compose.js"(exports2, module2) {
+    "use strict";
+    var { pipeline } = require_pipeline();
+    var Duplex = require_duplex();
+    var { destroyer } = require_destroy();
+    var {
+      isNodeStream,
+      isReadable,
+      isWritable,
+      isWebStream,
+      isTransformStream,
+      isWritableStream,
+      isReadableStream
+    } = require_utils();
+    var {
+      AbortError,
+      codes: { ERR_INVALID_ARG_VALUE, ERR_MISSING_ARGS }
+    } = require_errors();
+    var eos = require_end_of_stream();
+    module2.exports = function compose(...streams) {
+      if (streams.length === 0) {
+        throw new ERR_MISSING_ARGS("streams");
+      }
+      if (streams.length === 1) {
+        return Duplex.from(streams[0]);
+      }
+      const orgStreams = [...streams];
+      if (typeof streams[0] === "function") {
+        streams[0] = Duplex.from(streams[0]);
+      }
+      if (typeof streams[streams.length - 1] === "function") {
+        const idx = streams.length - 1;
+        streams[idx] = Duplex.from(streams[idx]);
+      }
+      for (let n = 0; n < streams.length; ++n) {
+        if (!isNodeStream(streams[n]) && !isWebStream(streams[n])) {
+          continue;
+        }
+        if (n < streams.length - 1 && !(isReadable(streams[n]) || isReadableStream(streams[n]) || isTransformStream(streams[n]))) {
+          throw new ERR_INVALID_ARG_VALUE(`streams[${n}]`, orgStreams[n], "must be readable");
+        }
+        if (n > 0 && !(isWritable(streams[n]) || isWritableStream(streams[n]) || isTransformStream(streams[n]))) {
+          throw new ERR_INVALID_ARG_VALUE(`streams[${n}]`, orgStreams[n], "must be writable");
+        }
+      }
+      let ondrain;
+      let onfinish;
+      let onreadable;
+      let onclose;
+      let d;
+      function onfinished(err) {
+        const cb = onclose;
+        onclose = null;
+        if (cb) {
+          cb(err);
+        } else if (err) {
+          d.destroy(err);
+        } else if (!readable && !writable) {
+          d.destroy();
+        }
+      }
+      const head = streams[0];
+      const tail = pipeline(streams, onfinished);
+      const writable = !!(isWritable(head) || isWritableStream(head) || isTransformStream(head));
+      const readable = !!(isReadable(tail) || isReadableStream(tail) || isTransformStream(tail));
+      d = new Duplex({
+        // TODO (ronag): highWaterMark?
+        writableObjectMode: !!(head !== null && head !== void 0 && head.writableObjectMode),
+        readableObjectMode: !!(tail !== null && tail !== void 0 && tail.readableObjectMode),
+        writable,
+        readable
+      });
+      if (writable) {
+        if (isNodeStream(head)) {
+          d._write = function(chunk, encoding, callback) {
+            if (head.write(chunk, encoding)) {
+              callback();
+            } else {
+              ondrain = callback;
+            }
+          };
+          d._final = function(callback) {
+            head.end();
+            onfinish = callback;
+          };
+          head.on("drain", function() {
+            if (ondrain) {
+              const cb = ondrain;
+              ondrain = null;
+              cb();
+            }
+          });
+        } else if (isWebStream(head)) {
+          const writable2 = isTransformStream(head) ? head.writable : head;
+          const writer = writable2.getWriter();
+          d._write = async function(chunk, encoding, callback) {
+            try {
+              await writer.ready;
+              writer.write(chunk).catch(() => {
+              });
+              callback();
+            } catch (err) {
+              callback(err);
+            }
+          };
+          d._final = async function(callback) {
+            try {
+              await writer.ready;
+              writer.close().catch(() => {
+              });
+              onfinish = callback;
+            } catch (err) {
+              callback(err);
+            }
+          };
+        }
+        const toRead = isTransformStream(tail) ? tail.readable : tail;
+        eos(toRead, () => {
+          if (onfinish) {
+            const cb = onfinish;
+            onfinish = null;
+            cb();
+          }
+        });
+      }
+      if (readable) {
+        if (isNodeStream(tail)) {
+          tail.on("readable", function() {
+            if (onreadable) {
+              const cb = onreadable;
+              onreadable = null;
+              cb();
+            }
+          });
+          tail.on("end", function() {
+            d.push(null);
+          });
+          d._read = function() {
+            while (true) {
+              const buf = tail.read();
+              if (buf === null) {
+                onreadable = d._read;
+                return;
+              }
+              if (!d.push(buf)) {
+                return;
+              }
+            }
+          };
+        } else if (isWebStream(tail)) {
+          const readable2 = isTransformStream(tail) ? tail.readable : tail;
+          const reader = readable2.getReader();
+          d._read = async function() {
+            while (true) {
+              try {
+                const { value, done } = await reader.read();
+                if (!d.push(value)) {
+                  return;
+                }
+                if (done) {
+                  d.push(null);
+                  return;
+                }
+              } catch {
+                return;
+              }
+            }
+          };
+        }
+      }
+      d._destroy = function(err, callback) {
+        if (!err && onclose !== null) {
+          err = new AbortError();
+        }
+        onreadable = null;
+        ondrain = null;
+        onfinish = null;
+        if (onclose === null) {
+          callback(err);
+        } else {
+          onclose = callback;
+          if (isNodeStream(tail)) {
+            destroyer(tail, err);
+          }
+        }
+      };
+      return d;
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/internal/streams/operators.js
+var require_operators = __commonJS({
+  "node_modules/readable-stream/lib/internal/streams/operators.js"(exports2, module2) {
+    "use strict";
+    var AbortController = globalThis.AbortController || require("abort-controller").AbortController;
+    var {
+      codes: { ERR_INVALID_ARG_VALUE, ERR_INVALID_ARG_TYPE, ERR_MISSING_ARGS, ERR_OUT_OF_RANGE },
+      AbortError
+    } = require_errors();
+    var { validateAbortSignal, validateInteger, validateObject } = require_validators();
+    var kWeakHandler = require_primordials().Symbol("kWeak");
+    var kResistStopPropagation = require_primordials().Symbol("kResistStopPropagation");
+    var { finished } = require_end_of_stream();
+    var staticCompose = require_compose();
+    var { addAbortSignalNoValidate } = require_add_abort_signal();
+    var { isWritable, isNodeStream } = require_utils();
+    var { deprecate } = require_util();
+    var {
+      ArrayPrototypePush,
+      Boolean: Boolean2,
+      MathFloor,
+      Number: Number2,
+      NumberIsNaN,
+      Promise: Promise2,
+      PromiseReject,
+      PromiseResolve,
+      PromisePrototypeThen,
+      Symbol: Symbol2
+    } = require_primordials();
+    var kEmpty = Symbol2("kEmpty");
+    var kEof = Symbol2("kEof");
+    function compose(stream, options) {
+      if (options != null) {
+        validateObject(options, "options");
+      }
+      if ((options === null || options === void 0 ? void 0 : options.signal) != null) {
+        validateAbortSignal(options.signal, "options.signal");
+      }
+      if (isNodeStream(stream) && !isWritable(stream)) {
+        throw new ERR_INVALID_ARG_VALUE("stream", stream, "must be writable");
+      }
+      const composedStream = staticCompose(this, stream);
+      if (options !== null && options !== void 0 && options.signal) {
+        addAbortSignalNoValidate(options.signal, composedStream);
+      }
+      return composedStream;
+    }
+    function map(fn, options) {
+      if (typeof fn !== "function") {
+        throw new ERR_INVALID_ARG_TYPE("fn", ["Function", "AsyncFunction"], fn);
+      }
+      if (options != null) {
+        validateObject(options, "options");
+      }
+      if ((options === null || options === void 0 ? void 0 : options.signal) != null) {
+        validateAbortSignal(options.signal, "options.signal");
+      }
+      let concurrency = 1;
+      if ((options === null || options === void 0 ? void 0 : options.concurrency) != null) {
+        concurrency = MathFloor(options.concurrency);
+      }
+      let highWaterMark = concurrency - 1;
+      if ((options === null || options === void 0 ? void 0 : options.highWaterMark) != null) {
+        highWaterMark = MathFloor(options.highWaterMark);
+      }
+      validateInteger(concurrency, "options.concurrency", 1);
+      validateInteger(highWaterMark, "options.highWaterMark", 0);
+      highWaterMark += concurrency;
+      return async function* map2() {
+        const signal = require_util().AbortSignalAny(
+          [options === null || options === void 0 ? void 0 : options.signal].filter(Boolean2)
+        );
+        const stream = this;
+        const queue = [];
+        const signalOpt = {
+          signal
+        };
+        let next;
+        let resume;
+        let done = false;
+        let cnt = 0;
+        function onCatch() {
+          done = true;
+          afterItemProcessed();
+        }
+        function afterItemProcessed() {
+          cnt -= 1;
+          maybeResume();
+        }
+        function maybeResume() {
+          if (resume && !done && cnt < concurrency && queue.length < highWaterMark) {
+            resume();
+            resume = null;
+          }
+        }
+        async function pump() {
+          try {
+            for await (let val of stream) {
+              if (done) {
+                return;
+              }
+              if (signal.aborted) {
+                throw new AbortError();
+              }
+              try {
+                val = fn(val, signalOpt);
+                if (val === kEmpty) {
+                  continue;
+                }
+                val = PromiseResolve(val);
+              } catch (err) {
+                val = PromiseReject(err);
+              }
+              cnt += 1;
+              PromisePrototypeThen(val, afterItemProcessed, onCatch);
+              queue.push(val);
+              if (next) {
+                next();
+                next = null;
+              }
+              if (!done && (queue.length >= highWaterMark || cnt >= concurrency)) {
+                await new Promise2((resolve) => {
+                  resume = resolve;
+                });
+              }
+            }
+            queue.push(kEof);
+          } catch (err) {
+            const val = PromiseReject(err);
+            PromisePrototypeThen(val, afterItemProcessed, onCatch);
+            queue.push(val);
+          } finally {
+            done = true;
+            if (next) {
+              next();
+              next = null;
+            }
+          }
+        }
+        pump();
+        try {
+          while (true) {
+            while (queue.length > 0) {
+              const val = await queue[0];
+              if (val === kEof) {
+                return;
+              }
+              if (signal.aborted) {
+                throw new AbortError();
+              }
+              if (val !== kEmpty) {
+                yield val;
+              }
+              queue.shift();
+              maybeResume();
+            }
+            await new Promise2((resolve) => {
+              next = resolve;
+            });
+          }
+        } finally {
+          done = true;
+          if (resume) {
+            resume();
+            resume = null;
+          }
+        }
+      }.call(this);
+    }
+    function asIndexedPairs(options = void 0) {
+      if (options != null) {
+        validateObject(options, "options");
+      }
+      if ((options === null || options === void 0 ? void 0 : options.signal) != null) {
+        validateAbortSignal(options.signal, "options.signal");
+      }
+      return async function* asIndexedPairs2() {
+        let index = 0;
+        for await (const val of this) {
+          var _options$signal;
+          if (options !== null && options !== void 0 && (_options$signal = options.signal) !== null && _options$signal !== void 0 && _options$signal.aborted) {
+            throw new AbortError({
+              cause: options.signal.reason
+            });
+          }
+          yield [index++, val];
+        }
+      }.call(this);
+    }
+    async function some(fn, options = void 0) {
+      for await (const unused of filter.call(this, fn, options)) {
+        return true;
+      }
+      return false;
+    }
+    async function every(fn, options = void 0) {
+      if (typeof fn !== "function") {
+        throw new ERR_INVALID_ARG_TYPE("fn", ["Function", "AsyncFunction"], fn);
+      }
+      return !await some.call(
+        this,
+        async (...args) => {
+          return !await fn(...args);
+        },
+        options
+      );
+    }
+    async function find(fn, options) {
+      for await (const result of filter.call(this, fn, options)) {
+        return result;
+      }
+      return void 0;
+    }
+    async function forEach(fn, options) {
+      if (typeof fn !== "function") {
+        throw new ERR_INVALID_ARG_TYPE("fn", ["Function", "AsyncFunction"], fn);
+      }
+      async function forEachFn(value, options2) {
+        await fn(value, options2);
+        return kEmpty;
+      }
+      for await (const unused of map.call(this, forEachFn, options)) ;
+    }
+    function filter(fn, options) {
+      if (typeof fn !== "function") {
+        throw new ERR_INVALID_ARG_TYPE("fn", ["Function", "AsyncFunction"], fn);
+      }
+      async function filterFn(value, options2) {
+        if (await fn(value, options2)) {
+          return value;
+        }
+        return kEmpty;
+      }
+      return map.call(this, filterFn, options);
+    }
+    var ReduceAwareErrMissingArgs = class extends ERR_MISSING_ARGS {
+      constructor() {
+        super("reduce");
+        this.message = "Reduce of an empty stream requires an initial value";
+      }
+    };
+    async function reduce(reducer, initialValue, options) {
+      var _options$signal2;
+      if (typeof reducer !== "function") {
+        throw new ERR_INVALID_ARG_TYPE("reducer", ["Function", "AsyncFunction"], reducer);
+      }
+      if (options != null) {
+        validateObject(options, "options");
+      }
+      if ((options === null || options === void 0 ? void 0 : options.signal) != null) {
+        validateAbortSignal(options.signal, "options.signal");
+      }
+      let hasInitialValue = arguments.length > 1;
+      if (options !== null && options !== void 0 && (_options$signal2 = options.signal) !== null && _options$signal2 !== void 0 && _options$signal2.aborted) {
+        const err = new AbortError(void 0, {
+          cause: options.signal.reason
+        });
+        this.once("error", () => {
+        });
+        await finished(this.destroy(err));
+        throw err;
+      }
+      const ac = new AbortController();
+      const signal = ac.signal;
+      if (options !== null && options !== void 0 && options.signal) {
+        const opts = {
+          once: true,
+          [kWeakHandler]: this,
+          [kResistStopPropagation]: true
+        };
+        options.signal.addEventListener("abort", () => ac.abort(), opts);
+      }
+      let gotAnyItemFromStream = false;
+      try {
+        for await (const value of this) {
+          var _options$signal3;
+          gotAnyItemFromStream = true;
+          if (options !== null && options !== void 0 && (_options$signal3 = options.signal) !== null && _options$signal3 !== void 0 && _options$signal3.aborted) {
+            throw new AbortError();
+          }
+          if (!hasInitialValue) {
+            initialValue = value;
+            hasInitialValue = true;
+          } else {
+            initialValue = await reducer(initialValue, value, {
+              signal
+            });
+          }
+        }
+        if (!gotAnyItemFromStream && !hasInitialValue) {
+          throw new ReduceAwareErrMissingArgs();
+        }
+      } finally {
+        ac.abort();
+      }
+      return initialValue;
+    }
+    async function toArray(options) {
+      if (options != null) {
+        validateObject(options, "options");
+      }
+      if ((options === null || options === void 0 ? void 0 : options.signal) != null) {
+        validateAbortSignal(options.signal, "options.signal");
+      }
+      const result = [];
+      for await (const val of this) {
+        var _options$signal4;
+        if (options !== null && options !== void 0 && (_options$signal4 = options.signal) !== null && _options$signal4 !== void 0 && _options$signal4.aborted) {
+          throw new AbortError(void 0, {
+            cause: options.signal.reason
+          });
+        }
+        ArrayPrototypePush(result, val);
+      }
+      return result;
+    }
+    function flatMap(fn, options) {
+      const values = map.call(this, fn, options);
+      return async function* flatMap2() {
+        for await (const val of values) {
+          yield* val;
+        }
+      }.call(this);
+    }
+    function toIntegerOrInfinity(number) {
+      number = Number2(number);
+      if (NumberIsNaN(number)) {
+        return 0;
+      }
+      if (number < 0) {
+        throw new ERR_OUT_OF_RANGE("number", ">= 0", number);
+      }
+      return number;
+    }
+    function drop(number, options = void 0) {
+      if (options != null) {
+        validateObject(options, "options");
+      }
+      if ((options === null || options === void 0 ? void 0 : options.signal) != null) {
+        validateAbortSignal(options.signal, "options.signal");
+      }
+      number = toIntegerOrInfinity(number);
+      return async function* drop2() {
+        var _options$signal5;
+        if (options !== null && options !== void 0 && (_options$signal5 = options.signal) !== null && _options$signal5 !== void 0 && _options$signal5.aborted) {
+          throw new AbortError();
+        }
+        for await (const val of this) {
+          var _options$signal6;
+          if (options !== null && options !== void 0 && (_options$signal6 = options.signal) !== null && _options$signal6 !== void 0 && _options$signal6.aborted) {
+            throw new AbortError();
+          }
+          if (number-- <= 0) {
+            yield val;
+          }
+        }
+      }.call(this);
+    }
+    function take(number, options = void 0) {
+      if (options != null) {
+        validateObject(options, "options");
+      }
+      if ((options === null || options === void 0 ? void 0 : options.signal) != null) {
+        validateAbortSignal(options.signal, "options.signal");
+      }
+      number = toIntegerOrInfinity(number);
+      return async function* take2() {
+        var _options$signal7;
+        if (options !== null && options !== void 0 && (_options$signal7 = options.signal) !== null && _options$signal7 !== void 0 && _options$signal7.aborted) {
+          throw new AbortError();
+        }
+        for await (const val of this) {
+          var _options$signal8;
+          if (options !== null && options !== void 0 && (_options$signal8 = options.signal) !== null && _options$signal8 !== void 0 && _options$signal8.aborted) {
+            throw new AbortError();
+          }
+          if (number-- > 0) {
+            yield val;
+          }
+          if (number <= 0) {
+            return;
+          }
+        }
+      }.call(this);
+    }
+    module2.exports.streamReturningOperators = {
+      asIndexedPairs: deprecate(asIndexedPairs, "readable.asIndexedPairs will be removed in a future version."),
+      drop,
+      filter,
+      flatMap,
+      map,
+      take,
+      compose
+    };
+    module2.exports.promiseReturningOperators = {
+      every,
+      forEach,
+      reduce,
+      toArray,
+      some,
+      find
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/stream/promises.js
+var require_promises = __commonJS({
+  "node_modules/readable-stream/lib/stream/promises.js"(exports2, module2) {
+    "use strict";
+    var { ArrayPrototypePop, Promise: Promise2 } = require_primordials();
+    var { isIterable, isNodeStream, isWebStream } = require_utils();
+    var { pipelineImpl: pl } = require_pipeline();
+    var { finished } = require_end_of_stream();
+    require_stream();
+    function pipeline(...streams) {
+      return new Promise2((resolve, reject) => {
+        let signal;
+        let end;
+        const lastArg = streams[streams.length - 1];
+        if (lastArg && typeof lastArg === "object" && !isNodeStream(lastArg) && !isIterable(lastArg) && !isWebStream(lastArg)) {
+          const options = ArrayPrototypePop(streams);
+          signal = options.signal;
+          end = options.end;
+        }
+        pl(
+          streams,
+          (err, value) => {
+            if (err) {
+              reject(err);
+            } else {
+              resolve(value);
+            }
+          },
+          {
+            signal,
+            end
+          }
+        );
+      });
+    }
+    module2.exports = {
+      finished,
+      pipeline
+    };
+  }
+});
+
+// node_modules/readable-stream/lib/stream.js
+var require_stream = __commonJS({
+  "node_modules/readable-stream/lib/stream.js"(exports2, module2) {
+    "use strict";
+    var { Buffer: Buffer3 } = require("buffer");
+    var { ObjectDefineProperty, ObjectKeys, ReflectApply } = require_primordials();
+    var {
+      promisify: { custom: customPromisify }
+    } = require_util();
+    var { streamReturningOperators, promiseReturningOperators } = require_operators();
+    var {
+      codes: { ERR_ILLEGAL_CONSTRUCTOR }
+    } = require_errors();
+    var compose = require_compose();
+    var { setDefaultHighWaterMark, getDefaultHighWaterMark } = require_state();
+    var { pipeline } = require_pipeline();
+    var { destroyer } = require_destroy();
+    var eos = require_end_of_stream();
+    var promises = require_promises();
+    var utils = require_utils();
+    var Stream2 = module2.exports = require_legacy().Stream;
+    Stream2.isDestroyed = utils.isDestroyed;
+    Stream2.isDisturbed = utils.isDisturbed;
+    Stream2.isErrored = utils.isErrored;
+    Stream2.isReadable = utils.isReadable;
+    Stream2.isWritable = utils.isWritable;
+    Stream2.Readable = require_readable();
+    for (const key of ObjectKeys(streamReturningOperators)) {
+      let fn = function(...args) {
+        if (new.target) {
+          throw ERR_ILLEGAL_CONSTRUCTOR();
+        }
+        return Stream2.Readable.from(ReflectApply(op, this, args));
+      };
+      const op = streamReturningOperators[key];
+      ObjectDefineProperty(fn, "name", {
+        __proto__: null,
+        value: op.name
+      });
+      ObjectDefineProperty(fn, "length", {
+        __proto__: null,
+        value: op.length
+      });
+      ObjectDefineProperty(Stream2.Readable.prototype, key, {
+        __proto__: null,
+        value: fn,
+        enumerable: false,
+        configurable: true,
+        writable: true
+      });
+    }
+    for (const key of ObjectKeys(promiseReturningOperators)) {
+      let fn = function(...args) {
+        if (new.target) {
+          throw ERR_ILLEGAL_CONSTRUCTOR();
+        }
+        return ReflectApply(op, this, args);
+      };
+      const op = promiseReturningOperators[key];
+      ObjectDefineProperty(fn, "name", {
+        __proto__: null,
+        value: op.name
+      });
+      ObjectDefineProperty(fn, "length", {
+        __proto__: null,
+        value: op.length
+      });
+      ObjectDefineProperty(Stream2.Readable.prototype, key, {
+        __proto__: null,
+        value: fn,
+        enumerable: false,
+        configurable: true,
+        writable: true
+      });
+    }
+    Stream2.Writable = require_writable();
+    Stream2.Duplex = require_duplex();
+    Stream2.Transform = require_transform();
+    Stream2.PassThrough = require_passthrough();
+    Stream2.pipeline = pipeline;
+    var { addAbortSignal } = require_add_abort_signal();
+    Stream2.addAbortSignal = addAbortSignal;
+    Stream2.finished = eos;
+    Stream2.destroy = destroyer;
+    Stream2.compose = compose;
+    Stream2.setDefaultHighWaterMark = setDefaultHighWaterMark;
+    Stream2.getDefaultHighWaterMark = getDefaultHighWaterMark;
+    ObjectDefineProperty(Stream2, "promises", {
+      __proto__: null,
+      configurable: true,
+      enumerable: true,
+      get() {
+        return promises;
+      }
+    });
+    ObjectDefineProperty(pipeline, customPromisify, {
+      __proto__: null,
+      enumerable: true,
+      get() {
+        return promises.pipeline;
+      }
+    });
+    ObjectDefineProperty(eos, customPromisify, {
+      __proto__: null,
+      enumerable: true,
+      get() {
+        return promises.finished;
+      }
+    });
+    Stream2.Stream = Stream2;
+    Stream2._isUint8Array = function isUint8Array(value) {
+      return value instanceof Uint8Array;
+    };
+    Stream2._uint8ArrayToBuffer = function _uint8ArrayToBuffer(chunk) {
+      return Buffer3.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
+    };
+  }
+});
+
+// stream-entry.cjs
+var Stream = require_stream();
+var process = require("process");
+var { Buffer: Buffer2 } = require("buffer");
+Stream.setDefaultHighWaterMark(false, process.platform === "win32" ? 16384 : 65536);
+function invalidStream(name) {
+  return new TypeError(`The "${name}" argument must be a stream.`);
+}
+Stream.Readable.fromWeb = function(web, options = {}) {
+  if (!web || typeof web.getReader !== "function") throw invalidStream("readableStream");
+  const reader = web.getReader();
+  let pending = false;
+  let ended = false;
+  let released = false;
+  const release = () => {
+    released = true;
+  };
+  const readable = new Stream.Readable({
+    ...options,
+    read() {
+      if (pending || ended) return;
+      pending = true;
+      reader.read().then(({ value, done }) => {
+        pending = false;
+        if (done) {
+          ended = true;
+          release();
+          this.push(null);
+        } else this.push(value);
+      }, (error) => {
+        pending = false;
+        this.destroy(error);
+      });
+    },
+    destroy(error, callback) {
+      if (ended || released) {
+        callback(error);
+        return;
+      }
+      ended = true;
+      Promise.resolve(reader.cancel(error)).then(() => {
+        release();
+        callback(error);
+      }, (reason) => {
+        release();
+        callback(reason || error);
+      });
+    }
+  });
+  return readable;
+};
+Stream.Readable.toWeb = function(readable, options = {}) {
+  if (!readable || typeof readable.on !== "function" || typeof readable.pause !== "function") throw invalidStream("streamReadable");
+  let controller;
+  let ended = false;
+  function cleanup() {
+    readable.removeListener("data", data);
+    readable.removeListener("end", end);
+    readable.removeListener("error", error);
+    readable.removeListener("close", close);
+  }
+  function data(chunk) {
+    if (ended) return;
+    controller.enqueue(Buffer2.isBuffer(chunk) ? new Uint8Array(chunk) : chunk);
+    if (controller.desiredSize <= 0) readable.pause();
+  }
+  function end() {
+    if (ended) return;
+    ended = true;
+    cleanup();
+    controller.close();
+  }
+  function error(reason) {
+    if (ended) return;
+    ended = true;
+    cleanup();
+    controller.error(reason);
+  }
+  function close() {
+    if (ended) return;
+    if (readable.readableEnded) end();
+    else {
+      const reason = new Error("Premature close");
+      reason.code = "ERR_STREAM_PREMATURE_CLOSE";
+      error(reason);
+    }
+  }
+  return new ReadableStream({
+    start(value) {
+      controller = value;
+      readable.on("data", data);
+      readable.on("end", end);
+      readable.on("error", error);
+      readable.on("close", close);
+      readable.pause();
+      if (readable.readableEnded) end();
+      else if (readable.destroyed) close();
+    },
+    pull() {
+      if (!ended) readable.resume();
+    },
+    cancel(reason) {
+      ended = true;
+      cleanup();
+      readable.once("error", () => {
+      });
+      readable.destroy(reason);
+    }
+  }, { highWaterMark: readable.readableHighWaterMark, ...options.strategy });
+};
+Stream.Writable.fromWeb = function(web, options = {}) {
+  if (!web || typeof web.getWriter !== "function") throw invalidStream("writableStream");
+  const writer = web.getWriter();
+  let ended = false;
+  let released = false;
+  const release = () => {
+    released = true;
+  };
+  return new Stream.Writable({
+    ...options,
+    write(chunk, encoding, callback) {
+      Promise.resolve(writer.write(chunk)).then(() => callback(), callback);
+    },
+    final(callback) {
+      Promise.resolve(writer.close()).then(() => {
+        ended = true;
+        release();
+        callback();
+      }, callback);
+    },
+    destroy(error, callback) {
+      if (ended || released) {
+        callback(error);
+        return;
+      }
+      ended = true;
+      Promise.resolve(writer.abort(error)).then(() => {
+        release();
+        callback(error);
+      }, (reason) => {
+        release();
+        callback(reason || error);
+      });
+    }
+  });
+};
+Stream.Writable.toWeb = function(writable) {
+  if (!writable || typeof writable.write !== "function" || typeof writable.on !== "function") throw invalidStream("streamWritable");
+  let controller;
+  let rejectPending;
+  let ended = false;
+  function error(reason) {
+    if (!ended) controller.error(reason);
+    rejectPending?.(reason);
+    rejectPending = void 0;
+  }
+  function cleanup() {
+    writable.removeListener("error", error);
+  }
+  return new WritableStream({
+    start(value) {
+      controller = value;
+      writable.on("error", error);
+      if (writable.errored) error(writable.errored);
+    },
+    write(chunk) {
+      return new Promise((resolve, reject) => {
+        rejectPending = reject;
+        writable.write(chunk, (reason) => {
+          rejectPending = void 0;
+          reason ? reject(reason) : resolve();
+        });
+      });
+    },
+    close() {
+      return new Promise((resolve, reject) => {
+        rejectPending = reject;
+        writable.end((reason) => {
+          ended = true;
+          rejectPending = void 0;
+          cleanup();
+          reason ? reject(reason) : resolve();
+        });
+      });
+    },
+    abort(reason) {
+      ended = true;
+      cleanup();
+      writable.once("error", () => {
+      });
+      writable.destroy(reason);
+    }
+  }, { highWaterMark: writable.writableHighWaterMark });
+};
+Stream.Duplex.fromWeb = function(pair, options = {}) {
+  if (!pair || !pair.readable || !pair.writable) throw invalidStream("pair");
+  return Stream.Duplex.from({ readable: Stream.Readable.fromWeb(pair.readable, options), writable: Stream.Writable.fromWeb(pair.writable, options) });
+};
+Stream.Duplex.toWeb = function(duplex) {
+  return { readable: Stream.Readable.toWeb(duplex), writable: Stream.Writable.toWeb(duplex) };
+};
+module.exports = Stream;
diff --git a/src/Node/Lib/string_decoder.cjs b/src/Node/Lib/string_decoder.cjs
new file mode 100644
index 00000000..38cb96fa
--- /dev/null
+++ b/src/Node/Lib/string_decoder.cjs
@@ -0,0 +1,310 @@
+// Generated by scripts/node-primitives/build.mjs. See primitives-LICENSES.txt.
+"use strict";
+var __getOwnPropNames = Object.getOwnPropertyNames;
+var __commonJS = (cb, mod) => function __require() {
+  try {
+    return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
+  } catch (e) {
+    throw mod = 0, e;
+  }
+};
+
+// node_modules/safe-buffer/index.js
+var require_safe_buffer = __commonJS({
+  "node_modules/safe-buffer/index.js"(exports2, module2) {
+    /*! safe-buffer. MIT License. Feross Aboukhadijeh  */
+    var buffer = require("buffer");
+    var Buffer2 = buffer.Buffer;
+    function copyProps(src, dst) {
+      for (var key in src) {
+        dst[key] = src[key];
+      }
+    }
+    if (Buffer2.from && Buffer2.alloc && Buffer2.allocUnsafe && Buffer2.allocUnsafeSlow) {
+      module2.exports = buffer;
+    } else {
+      copyProps(buffer, exports2);
+      exports2.Buffer = SafeBuffer;
+    }
+    function SafeBuffer(arg, encodingOrOffset, length) {
+      return Buffer2(arg, encodingOrOffset, length);
+    }
+    SafeBuffer.prototype = Object.create(Buffer2.prototype);
+    copyProps(Buffer2, SafeBuffer);
+    SafeBuffer.from = function(arg, encodingOrOffset, length) {
+      if (typeof arg === "number") {
+        throw new TypeError("Argument must not be a number");
+      }
+      return Buffer2(arg, encodingOrOffset, length);
+    };
+    SafeBuffer.alloc = function(size, fill, encoding) {
+      if (typeof size !== "number") {
+        throw new TypeError("Argument must be a number");
+      }
+      var buf = Buffer2(size);
+      if (fill !== void 0) {
+        if (typeof encoding === "string") {
+          buf.fill(fill, encoding);
+        } else {
+          buf.fill(fill);
+        }
+      } else {
+        buf.fill(0);
+      }
+      return buf;
+    };
+    SafeBuffer.allocUnsafe = function(size) {
+      if (typeof size !== "number") {
+        throw new TypeError("Argument must be a number");
+      }
+      return Buffer2(size);
+    };
+    SafeBuffer.allocUnsafeSlow = function(size) {
+      if (typeof size !== "number") {
+        throw new TypeError("Argument must be a number");
+      }
+      return buffer.SlowBuffer(size);
+    };
+  }
+});
+
+// node_modules/string_decoder/lib/string_decoder.js
+var require_string_decoder = __commonJS({
+  "node_modules/string_decoder/lib/string_decoder.js"(exports2) {
+    "use strict";
+    var Buffer2 = require_safe_buffer().Buffer;
+    var isEncoding = Buffer2.isEncoding || function(encoding) {
+      encoding = "" + encoding;
+      switch (encoding && encoding.toLowerCase()) {
+        case "hex":
+        case "utf8":
+        case "utf-8":
+        case "ascii":
+        case "binary":
+        case "base64":
+        case "ucs2":
+        case "ucs-2":
+        case "utf16le":
+        case "utf-16le":
+        case "raw":
+          return true;
+        default:
+          return false;
+      }
+    };
+    function _normalizeEncoding(enc) {
+      if (!enc) return "utf8";
+      var retried;
+      while (true) {
+        switch (enc) {
+          case "utf8":
+          case "utf-8":
+            return "utf8";
+          case "ucs2":
+          case "ucs-2":
+          case "utf16le":
+          case "utf-16le":
+            return "utf16le";
+          case "latin1":
+          case "binary":
+            return "latin1";
+          case "base64":
+          case "ascii":
+          case "hex":
+            return enc;
+          default:
+            if (retried) return;
+            enc = ("" + enc).toLowerCase();
+            retried = true;
+        }
+      }
+    }
+    function normalizeEncoding(enc) {
+      var nenc = _normalizeEncoding(enc);
+      if (typeof nenc !== "string" && (Buffer2.isEncoding === isEncoding || !isEncoding(enc))) throw new Error("Unknown encoding: " + enc);
+      return nenc || enc;
+    }
+    exports2.StringDecoder = StringDecoder;
+    function StringDecoder(encoding) {
+      this.encoding = normalizeEncoding(encoding);
+      var nb;
+      switch (this.encoding) {
+        case "utf16le":
+          this.text = utf16Text;
+          this.end = utf16End;
+          nb = 4;
+          break;
+        case "utf8":
+          this.fillLast = utf8FillLast;
+          nb = 4;
+          break;
+        case "base64":
+          this.text = base64Text;
+          this.end = base64End;
+          nb = 3;
+          break;
+        default:
+          this.write = simpleWrite;
+          this.end = simpleEnd;
+          return;
+      }
+      this.lastNeed = 0;
+      this.lastTotal = 0;
+      this.lastChar = Buffer2.allocUnsafe(nb);
+    }
+    StringDecoder.prototype.write = function(buf) {
+      if (buf.length === 0) return "";
+      var r;
+      var i;
+      if (this.lastNeed) {
+        r = this.fillLast(buf);
+        if (r === void 0) return "";
+        i = this.lastNeed;
+        this.lastNeed = 0;
+      } else {
+        i = 0;
+      }
+      if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);
+      return r || "";
+    };
+    StringDecoder.prototype.end = utf8End;
+    StringDecoder.prototype.text = utf8Text;
+    StringDecoder.prototype.fillLast = function(buf) {
+      if (this.lastNeed <= buf.length) {
+        buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);
+        return this.lastChar.toString(this.encoding, 0, this.lastTotal);
+      }
+      buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);
+      this.lastNeed -= buf.length;
+    };
+    function utf8CheckByte(byte) {
+      if (byte <= 127) return 0;
+      else if (byte >> 5 === 6) return 2;
+      else if (byte >> 4 === 14) return 3;
+      else if (byte >> 3 === 30) return 4;
+      return byte >> 6 === 2 ? -1 : -2;
+    }
+    function utf8CheckIncomplete(self, buf, i) {
+      var j = buf.length - 1;
+      if (j < i) return 0;
+      var nb = utf8CheckByte(buf[j]);
+      if (nb >= 0) {
+        if (nb > 0) self.lastNeed = nb - 1;
+        return nb;
+      }
+      if (--j < i || nb === -2) return 0;
+      nb = utf8CheckByte(buf[j]);
+      if (nb >= 0) {
+        if (nb > 0) self.lastNeed = nb - 2;
+        return nb;
+      }
+      if (--j < i || nb === -2) return 0;
+      nb = utf8CheckByte(buf[j]);
+      if (nb >= 0) {
+        if (nb > 0) {
+          if (nb === 2) nb = 0;
+          else self.lastNeed = nb - 3;
+        }
+        return nb;
+      }
+      return 0;
+    }
+    function utf8CheckExtraBytes(self, buf, p) {
+      if ((buf[0] & 192) !== 128) {
+        self.lastNeed = 0;
+        return "\uFFFD";
+      }
+      if (self.lastNeed > 1 && buf.length > 1) {
+        if ((buf[1] & 192) !== 128) {
+          self.lastNeed = 1;
+          return "\uFFFD";
+        }
+        if (self.lastNeed > 2 && buf.length > 2) {
+          if ((buf[2] & 192) !== 128) {
+            self.lastNeed = 2;
+            return "\uFFFD";
+          }
+        }
+      }
+    }
+    function utf8FillLast(buf) {
+      var p = this.lastTotal - this.lastNeed;
+      var r = utf8CheckExtraBytes(this, buf, p);
+      if (r !== void 0) return r;
+      if (this.lastNeed <= buf.length) {
+        buf.copy(this.lastChar, p, 0, this.lastNeed);
+        return this.lastChar.toString(this.encoding, 0, this.lastTotal);
+      }
+      buf.copy(this.lastChar, p, 0, buf.length);
+      this.lastNeed -= buf.length;
+    }
+    function utf8Text(buf, i) {
+      var total = utf8CheckIncomplete(this, buf, i);
+      if (!this.lastNeed) return buf.toString("utf8", i);
+      this.lastTotal = total;
+      var end = buf.length - (total - this.lastNeed);
+      buf.copy(this.lastChar, 0, end);
+      return buf.toString("utf8", i, end);
+    }
+    function utf8End(buf) {
+      var r = buf && buf.length ? this.write(buf) : "";
+      if (this.lastNeed) return r + "\uFFFD";
+      return r;
+    }
+    function utf16Text(buf, i) {
+      if ((buf.length - i) % 2 === 0) {
+        var r = buf.toString("utf16le", i);
+        if (r) {
+          var c = r.charCodeAt(r.length - 1);
+          if (c >= 55296 && c <= 56319) {
+            this.lastNeed = 2;
+            this.lastTotal = 4;
+            this.lastChar[0] = buf[buf.length - 2];
+            this.lastChar[1] = buf[buf.length - 1];
+            return r.slice(0, -1);
+          }
+        }
+        return r;
+      }
+      this.lastNeed = 1;
+      this.lastTotal = 2;
+      this.lastChar[0] = buf[buf.length - 1];
+      return buf.toString("utf16le", i, buf.length - 1);
+    }
+    function utf16End(buf) {
+      var r = buf && buf.length ? this.write(buf) : "";
+      if (this.lastNeed) {
+        var end = this.lastTotal - this.lastNeed;
+        return r + this.lastChar.toString("utf16le", 0, end);
+      }
+      return r;
+    }
+    function base64Text(buf, i) {
+      var n = (buf.length - i) % 3;
+      if (n === 0) return buf.toString("base64", i);
+      this.lastNeed = 3 - n;
+      this.lastTotal = 3;
+      if (n === 1) {
+        this.lastChar[0] = buf[buf.length - 1];
+      } else {
+        this.lastChar[0] = buf[buf.length - 2];
+        this.lastChar[1] = buf[buf.length - 1];
+      }
+      return buf.toString("base64", i, buf.length - n);
+    }
+    function base64End(buf) {
+      var r = buf && buf.length ? this.write(buf) : "";
+      if (this.lastNeed) return r + this.lastChar.toString("base64", 0, 3 - this.lastNeed);
+      return r;
+    }
+    function simpleWrite(buf) {
+      return buf.toString(this.encoding);
+    }
+    function simpleEnd(buf) {
+      return buf && buf.length ? this.write(buf) : "";
+    }
+  }
+});
+
+// string_decoder-entry.cjs
+module.exports = require_string_decoder();
diff --git a/src/Node/Lib/timers-promises.cjs b/src/Node/Lib/timers-promises.cjs
new file mode 100644
index 00000000..d5eb3429
--- /dev/null
+++ b/src/Node/Lib/timers-promises.cjs
@@ -0,0 +1,52 @@
+'use strict';
+
+const timers = require('timers');
+function abortError(signal) { return Object.assign(new Error('The operation was aborted', { cause: signal && signal.reason }), { name: 'AbortError', code: 'ABORT_ERR' }); }
+function optionsValue(options) {
+  if (options === undefined) return {};
+  if (options === null || typeof options !== 'object') throw Object.assign(new TypeError('options must be an object'), { code: 'ERR_INVALID_ARG_TYPE' });
+  if (options.ref !== undefined && typeof options.ref !== 'boolean') throw Object.assign(new TypeError('options.ref must be a boolean'), { code: 'ERR_INVALID_ARG_TYPE' });
+  if (options.signal !== undefined && !(options.signal instanceof AbortSignal)) throw Object.assign(new TypeError('options.signal must be an AbortSignal'), { code: 'ERR_INVALID_ARG_TYPE' });
+  return options;
+}
+function wait(kind, delay, value, options) {
+  return new Promise((resolve, reject) => {
+    options = optionsValue(options);
+    const signal = options.signal;
+    if (signal && signal.aborted) { reject(abortError(signal)); return; }
+    let timer;
+    const cleanup = () => { if (signal) signal.removeEventListener('abort', aborted); };
+    const aborted = () => { kind === 'immediate' ? timers.clearImmediate(timer) : timers.clearTimeout(timer); cleanup(); reject(abortError(signal)); };
+    const done = () => { cleanup(); resolve(value); };
+    timer = kind === 'immediate' ? timers.setImmediate(done) : timers.setTimeout(done, delay);
+    if (options.ref === false) timer.unref();
+    if (signal) signal.addEventListener('abort', aborted, { once: true });
+  });
+}
+async function* interval(delay, value, options) {
+  options = optionsValue(options);
+  const signal = options.signal;
+  if (signal && signal.aborted) throw abortError(signal);
+  let available = 0, wake, aborted = false;
+  const timer = timers.setInterval(() => { available++; if (wake) { const callback = wake; wake = null; callback(); } }, delay);
+  if (options.ref === false) timer.unref();
+  const onAbort = () => { aborted = true; if (wake) { const callback = wake; wake = null; callback(); } };
+  if (signal) signal.addEventListener('abort', onAbort, { once: true });
+  try {
+    while (true) {
+      if (available === 0 && !aborted) await new Promise(resolve => { wake = resolve; });
+      if (aborted) throw abortError(signal);
+      available--;
+      yield value;
+    }
+  } finally {
+    timers.clearInterval(timer);
+    if (signal) signal.removeEventListener('abort', onAbort);
+  }
+}
+module.exports = {
+  setTimeout: (delay, value, options) => wait('timeout', delay, value, options),
+  setImmediate: (value, options) => wait('immediate', 0, value, options),
+  setInterval: interval,
+  scheduler: { wait: (delay, options) => wait('timeout', delay, undefined, options), yield: () => wait('immediate') },
+};
diff --git a/src/Node/Lib/timers.cjs b/src/Node/Lib/timers.cjs
new file mode 100644
index 00000000..db930866
--- /dev/null
+++ b/src/Node/Lib/timers.cjs
@@ -0,0 +1,74 @@
+'use strict';
+
+const host = __phasisNodeHost;
+const handles = new Map();
+let sequence = 0;
+function check(callback) {
+  if (typeof callback !== 'function') throw Object.assign(new TypeError('The callback argument must be a function'), { code: 'ERR_INVALID_ARG_TYPE' });
+}
+function delayValue(value) {
+  value = Number(value);
+  return value >= 1 && value <= 2147483647 ? Math.trunc(value) : 1;
+}
+class Timeout {
+  constructor(callback, delay, args, repeating = false) {
+    this._id = ++sequence;
+    this._callback = callback;
+    this._delay = delayValue(delay);
+    this._args = args;
+    this._repeating = repeating;
+    this._referenced = true;
+    this._nativeId = null;
+    this._destroyed = false;
+    this._generation = 0;
+    this._schedule();
+  }
+  _schedule() {
+    const generation = ++this._generation;
+    this._destroyed = false;
+    handles.set(this._id, this);
+    this._nativeId = host.timer(this._repeating ? 'interval' : 'timeout', () => {
+      if (!this._repeating) { this._nativeId = null; handles.delete(this._id); this._destroyed = true; }
+      this._callback.apply(this, this._args);
+    }, this._delay);
+    host.timer('ref', this._nativeId, this._referenced);
+  }
+  ref() { this._referenced = true; if (this._nativeId !== null) host.timer('ref', this._nativeId, true); return this; }
+  unref() { this._referenced = false; if (this._nativeId !== null) host.timer('ref', this._nativeId, false); return this; }
+  hasRef() { return this._referenced; }
+  refresh() { if (this._nativeId !== null) host.timer('clear', this._nativeId); this._schedule(); return this; }
+  close() { if (this._nativeId !== null) host.timer('clear', this._nativeId); this._nativeId = null; this._destroyed = true; handles.delete(this._id); return this; }
+  [Symbol.toPrimitive]() { return this._id; }
+  [Symbol.dispose]() { this.close(); }
+}
+class Immediate {
+  constructor(callback, args) {
+    this._id = ++sequence;
+    this._referenced = true;
+    this._destroyed = false;
+    handles.set(this._id, this);
+    this._nativeId = host.timer('immediate', () => {
+      this._nativeId = null;
+      this._destroyed = true;
+      handles.delete(this._id);
+      callback.apply(this, args);
+    });
+  }
+  ref() { this._referenced = true; if (this._nativeId !== null) host.timer('ref', this._nativeId, true); return this; }
+  unref() { this._referenced = false; if (this._nativeId !== null) host.timer('ref', this._nativeId, false); return this; }
+  hasRef() { return this._referenced; }
+  [Symbol.dispose]() { clearImmediate(this); }
+}
+function clearTimeout(handle) {
+  if (typeof handle === 'number' || typeof handle === 'string') handle = handles.get(Number(handle));
+  if (handle instanceof Timeout) handle.close();
+}
+function clearImmediate(handle) {
+  if (!(handle instanceof Immediate)) return;
+  if (handle._nativeId !== null) host.timer('clear', handle._nativeId);
+  handle._nativeId = null; handle._destroyed = true; handles.delete(handle._id);
+}
+function setTimeout(callback, delay, ...args) { check(callback); return new Timeout(callback, delay, args); }
+function setInterval(callback, delay, ...args) { check(callback); return new Timeout(callback, delay, args, true); }
+function setImmediate(callback, ...args) { check(callback); return new Immediate(callback, args); }
+module.exports = { setTimeout, clearTimeout, setInterval, clearInterval: clearTimeout, setImmediate, clearImmediate };
diff --git a/src/Node/Lib/tls.cjs b/src/Node/Lib/tls.cjs
new file mode 100644
index 00000000..5683b60a
--- /dev/null
+++ b/src/Node/Lib/tls.cjs
@@ -0,0 +1,171 @@
+'use strict';
+
+const net = require('net');
+const { Buffer } = require('buffer');
+const host = __phasisNodeHost.net;
+
+function call(operation, ...args) {
+  const result = host.call(operation, ...args);
+  if (result.error) throw Object.assign(new Error(result.error.message), result.error);
+  return result.value;
+}
+function pem(value) {
+  return Array.isArray(value) ? value.map(pem).join('\n') : Buffer.isBuffer(value) ? value.toString() : value;
+}
+function configuration(options = {}) {
+  const result = { ...(options.secureContext ? options.secureContext.context : {}), ...options };
+  for (const name of ['ca', 'cert', 'key']) if (result[name] !== undefined) result[name] = pem(result[name]);
+  if (result.key && typeof result.key === 'object') {
+    result.passphrase = result.key.passphrase === undefined ? result.passphrase : result.key.passphrase;
+    result.key = pem(result.key.pem);
+  }
+  if (Buffer.isBuffer(result.ALPNProtocols)) {
+    const protocols = [];
+    for (let offset = 0; offset < result.ALPNProtocols.length;) {
+      const length = result.ALPNProtocols[offset++];
+      if (offset + length > result.ALPNProtocols.length) throw new TypeError('Invalid ALPN protocol list.');
+      protocols.push(result.ALPNProtocols.toString('ascii', offset, offset + length));
+      offset += length;
+    }
+    result.ALPNProtocols = protocols;
+  }
+  if (result.checkServerIdentity !== undefined && typeof result.checkServerIdentity !== 'function') throw new TypeError('checkServerIdentity must be a function.');
+  result.customIdentityCheck = typeof result.checkServerIdentity === 'function';
+  return result;
+}
+class SecureContext {
+  constructor(options = {}) { this.context = configuration(options); }
+}
+function createSecureContext(options) { return new SecureContext(options); }
+
+function dnsMatch(hostname, pattern) {
+  hostname = hostname.toLowerCase().replace(/\.$/, '');
+  pattern = pattern.toLowerCase().replace(/\.$/, '');
+  if (!pattern.includes('*')) return hostname === pattern;
+  const hostParts = hostname.split('.'), parts = pattern.split('.');
+  return parts.length >= 3 && parts.length === hostParts.length && parts[0] === '*' &&
+    !hostParts[0].startsWith('xn--') && hostParts.slice(1).join('.') === parts.slice(1).join('.');
+}
+function ip(value) {
+  return value.includes(':') ? new URL('http://[' + value.replace(/^\[|\]$/g, '') + ']').hostname : value;
+}
+function checkServerIdentity(hostname, cert) {
+  hostname = String(hostname);
+  const names = String(cert.subjectaltname || '').split(/,\s*/);
+  const ips = names.filter(name => name.startsWith('IP Address:')).map(name => name.slice(11));
+  const dns = names.filter(name => name.startsWith('DNS:')).map(name => name.slice(4));
+  let matched;
+  if (net.isIP(hostname)) matched = ips.some(address => ip(address) === ip(hostname));
+  else if (dns.length) matched = dns.some(name => dnsMatch(hostname, name));
+  else {
+    const common = cert.subject && cert.subject.CN;
+    matched = (Array.isArray(common) ? common : [common]).some(name => typeof name === 'string' && dnsMatch(hostname, name));
+  }
+  if (matched) return;
+  const reason = `Host: ${hostname}. is not in the cert's altnames: ${cert.subjectaltname || cert.subject && cert.subject.CN || ''}`;
+  return Object.assign(new Error('Hostname/IP does not match certificate\'s altnames: ' + reason), {
+    code: 'ERR_TLS_CERT_ALTNAME_INVALID', reason, host: hostname, cert,
+  });
+}
+
+class TLSSocket extends net.Socket {
+  constructor(socket, options = {}) {
+    if (socket && !(socket instanceof net.Socket)) { options = socket; socket = undefined; }
+    const config = configuration(options);
+    if (socket && socket._handle !== null) config.handle = socket._handle;
+    super(config);
+    if (socket && socket._handle !== null) socket._handle = null;
+    this.encrypted = true;
+    this.authorized = false;
+    this.authorizationError = null;
+    this._tlsOptions = config;
+    this._secureEstablished = false;
+    this._secureConnecting = true;
+    this._tlsStarted = false;
+    this._tlsInfo = null;
+    this.servername = config.servername || false;
+    this.alpnProtocol = false;
+    if (this._handle !== null) this._startTls();
+  }
+  _startTls() {
+    if (this._tlsStarted || this._handle === null) return;
+    this._tlsStarted = true;
+    try { call('startTls', this._handle, this._tlsOptions); }
+    catch (error) { process.nextTick(() => this.destroy(error)); }
+  }
+  _native(event, value) {
+    if (event === 'connect') this._startTls();
+    if (event !== 'secure') return super._native(event, value);
+    this._tlsInfo = value;
+    this.alpnProtocol = value.alpnProtocol;
+    this.authorized = value.authorized;
+    this.authorizationError = value.authorizationError;
+    if (!this._tlsOptions.isServer) {
+      const check = this._tlsOptions.checkServerIdentity || checkServerIdentity;
+      const error = check(this._tlsOptions.servername || this._tlsOptions.host || 'localhost', this.getPeerCertificate());
+      if (error) {
+        this.authorized = false;
+        this.authorizationError = error.code;
+        if (this._tlsOptions.rejectUnauthorized !== false) { this.destroy(error); return; }
+      }
+    }
+    this._secureConnecting = false;
+    this._secureEstablished = true;
+    this.emit('secure');
+    if (!this._tlsOptions.isServer) this.emit('secureConnect');
+  }
+  _write(chunk, encoding, done) {
+    if (!this._secureEstablished) { this.once('secure', () => super._write(chunk, encoding, done)); return; }
+    super._write(chunk, encoding, done);
+  }
+  _final(done) {
+    if (!this._secureEstablished) { this.once('secure', () => super._final(done)); return; }
+    super._final(done);
+  }
+  getPeerCertificate(detailed = false) {
+    if (!this._tlsInfo) return {};
+    const cert = { ...this._tlsInfo.certificate };
+    if (cert.rawBase64) { cert.raw = Buffer.from(cert.rawBase64, 'base64'); delete cert.rawBase64; }
+    if (detailed && cert.issuer && cert.subject && JSON.stringify(cert.issuer) === JSON.stringify(cert.subject)) cert.issuerCertificate = cert;
+    return cert;
+  }
+  getProtocol() { return this._tlsInfo ? this._tlsInfo.protocol : null; }
+  getCipher() { return this._tlsInfo ? { ...this._tlsInfo.cipher } : undefined; }
+}
+
+class Server extends net.Server {
+  constructor(options = {}, listener) {
+    if (typeof options === 'function') { listener = options; options = {}; }
+    super(options);
+    this._tlsOptions = configuration({ ...options, isServer: true });
+    if (listener) this.on('secureConnection', listener);
+  }
+  _createSocket(handle) {
+    const socket = new TLSSocket(undefined, { ...this._tlsOptions, handle });
+    socket.once('secure', () => this.emit('secureConnection', socket));
+    socket.on('error', error => { if (!socket._secureEstablished) this.emit('tlsClientError', error, socket); });
+    return socket;
+  }
+  setSecureContext(options) { this._tlsOptions = configuration({ ...options, isServer: true }); }
+}
+function connect(...args) {
+  let options;
+  if (args[0] !== null && typeof args[0] === 'object') options = { ...args[0] };
+  else {
+    options = { port: args[0] };
+    let index = 1;
+    if (typeof args[index] === 'string') options.host = args[index++];
+    if (args[index] !== null && typeof args[index] === 'object') Object.assign(options, args[index]);
+  }
+  options.host = options.host || options.hostname || 'localhost';
+  const callback = typeof args[args.length - 1] === 'function' ? args[args.length - 1] : undefined;
+  const socket = new TLSSocket(options.socket, options);
+  if (callback) socket.once('secureConnect', callback);
+  if (socket._handle === null) socket.connect(options);
+  return socket;
+}
+module.exports = {
+  TLSSocket, Server, SecureContext, connect, createConnection: connect, createSecureContext, checkServerIdentity,
+  createServer: (options, listener) => new Server(options, listener),
+  DEFAULT_MIN_VERSION: 'TLSv1.2', DEFAULT_MAX_VERSION: 'TLSv1.3',
+};
diff --git a/src/Node/Lib/tty.cjs b/src/Node/Lib/tty.cjs
new file mode 100644
index 00000000..a0225d46
--- /dev/null
+++ b/src/Node/Lib/tty.cjs
@@ -0,0 +1,11 @@
+'use strict';
+const streams = require('./stdio.cjs');
+class WriteStream extends streams.WriteStream {
+  clearLine(direction, callback) { return this.write('\x1b[' + (direction < 0 ? '1' : direction > 0 ? '0' : '2') + 'K', callback); }
+  clearScreenDown(callback) { return this.write('\x1b[0J', callback); }
+  cursorTo(x, y, callback) { if (typeof y === 'function') { callback = y; y = undefined; } return this.write(y === undefined ? `\x1b[${x + 1}G` : `\x1b[${y + 1};${x + 1}H`, callback); }
+  moveCursor(dx, dy, callback) { let output = ''; if (dx) output += `\x1b[${Math.abs(dx)}${dx < 0 ? 'D' : 'C'}`; if (dy) output += `\x1b[${Math.abs(dy)}${dy < 0 ? 'A' : 'B'}`; return this.write(output, callback); }
+  getColorDepth(env = process.env) { if (env.FORCE_COLOR === '0' || env.NO_COLOR !== undefined || env.NODE_DISABLE_COLORS) return 1; if (env.FORCE_COLOR === '3' || /truecolor|24bit/.test(env.COLORTERM || '')) return 24; if (env.FORCE_COLOR === '2' || /256color/.test(env.TERM || '')) return 8; return this.isTTY || env.FORCE_COLOR ? 4 : 1; }
+  hasColors(count = 16, env) { if (typeof count === 'object') { env = count; count = 16; } return count <= 2 ** this.getColorDepth(env); }
+}
+module.exports = { isatty: fd => typeof fd === 'number' && Number.isInteger(fd) && __phasisNodeHost.isatty(fd), WriteStream, ReadStream: streams.ReadStream };
diff --git a/src/Node/Lib/url.cjs b/src/Node/Lib/url.cjs
new file mode 100644
index 00000000..5f948303
--- /dev/null
+++ b/src/Node/Lib/url.cjs
@@ -0,0 +1,1045 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+'use strict';
+
+const {
+  ArrayPrototypeJoin,
+  Boolean,
+  Int8Array,
+  ObjectAssign,
+  ObjectKeys,
+  StringPrototypeAt,
+  StringPrototypeCharCodeAt,
+  StringPrototypeIndexOf,
+  StringPrototypeReplaceAll,
+  StringPrototypeSlice,
+  decodeURIComponent,
+} = require('./portable/primordials.cjs');
+
+const { URLPattern } = globalThis;
+const { toASCII } = { toASCII: require('./portable/whatwg-url.cjs').domainToASCII };
+const { encodeStr, hexTable } = require('./portable/internal-querystring.cjs');
+const querystring = require('querystring');
+
+const {
+  ERR_INVALID_ARG_TYPE,
+  ERR_INVALID_URL,
+  ERR_INVALID_ARG_VALUE,
+} = require('./portable/errors.cjs').codes;
+const {
+  validateString,
+  validateObject,
+} = require('./portable/validators.cjs');
+
+// This ensures setURLConstructor() is called before the native
+// URL::ToObject() method is used.
+const { spliceOne } = require('./portable/helpers.cjs');
+const { isInsideNodeModules } = require('./portable/helpers.cjs');
+
+// WHATWG URL implementation provided by internal/url
+const {
+  URL,
+  URLSearchParams,
+  domainToASCII,
+  domainToUnicode,
+  fileURLToPath,
+  fileURLToPathBuffer,
+  pathToFileURL: _pathToFileURL,
+  urlToHttpOptions,
+  unsafeProtocol,
+  hostlessProtocol,
+  slashedProtocol,
+} = require('./portable/whatwg-url.cjs');
+
+const bindingUrl = require('./portable/whatwg-url.cjs');
+
+// Original url.parse() API
+
+function Url() {
+  this.protocol = null;
+  this.slashes = null;
+  this.auth = null;
+  this.host = null;
+  this.port = null;
+  this.hostname = null;
+  this.hash = null;
+  this.search = null;
+  this.query = null;
+  this.pathname = null;
+  this.path = null;
+  this.href = null;
+}
+
+// Reference: RFC 3986, RFC 1808, RFC 2396
+
+// define these here so at least they only have to be
+// compiled once on the first module load.
+const protocolPattern = /^[a-z0-9.+-]+:/i;
+const portPattern = /:[0-9]*$/;
+const hostPattern = /^\/\/[^@/]+@[^@/]+/;
+
+// Special case for a simple path URL
+const simplePathPattern = /^(\/\/?(?!\/)[^?\s]*)(\?[^\s]*)?$/;
+
+const hostnameMaxLen = 255;
+const {
+  CHAR_SPACE,
+  CHAR_TAB,
+  CHAR_CARRIAGE_RETURN,
+  CHAR_LINE_FEED,
+  CHAR_NO_BREAK_SPACE,
+  CHAR_ZERO_WIDTH_NOBREAK_SPACE,
+  CHAR_HASH,
+  CHAR_FORWARD_SLASH,
+  CHAR_LEFT_SQUARE_BRACKET,
+  CHAR_RIGHT_SQUARE_BRACKET,
+  CHAR_LEFT_ANGLE_BRACKET,
+  CHAR_RIGHT_ANGLE_BRACKET,
+  CHAR_LEFT_CURLY_BRACKET,
+  CHAR_RIGHT_CURLY_BRACKET,
+  CHAR_QUESTION_MARK,
+  CHAR_DOUBLE_QUOTE,
+  CHAR_SINGLE_QUOTE,
+  CHAR_PERCENT,
+  CHAR_SEMICOLON,
+  CHAR_BACKWARD_SLASH,
+  CHAR_CIRCUMFLEX_ACCENT,
+  CHAR_GRAVE_ACCENT,
+  CHAR_VERTICAL_LINE,
+  CHAR_AT,
+  CHAR_COLON,
+} = require('./portable/constants.cjs');
+
+let urlParseWarned = false;
+
+function urlParse(url, parseQueryString, slashesDenoteHost) {
+  if (!urlParseWarned && !isInsideNodeModules(4)) {
+    urlParseWarned = true;
+    process.emitWarning(
+      '`url.parse()` behavior is not standardized and prone to ' +
+      'errors that have security implications. Use the WHATWG URL API ' +
+      'instead. CVEs are not issued for `url.parse()` vulnerabilities.',
+      'DeprecationWarning',
+      'DEP0169',
+    );
+  }
+
+  if (url instanceof Url) return url;
+
+  const urlObject = new Url();
+  urlObject.parse(url, parseQueryString, slashesDenoteHost);
+  return urlObject;
+}
+
+function isIpv6Hostname(hostname) {
+  return (
+    StringPrototypeCharCodeAt(hostname, 0) === CHAR_LEFT_SQUARE_BRACKET &&
+    StringPrototypeCharCodeAt(hostname, hostname.length - 1) ===
+    CHAR_RIGHT_SQUARE_BRACKET
+  );
+}
+
+// This prevents some common spoofing bugs due to our use of IDNA toASCII. For
+// compatibility, the set of characters we use here is the *intersection* of
+// "forbidden host code point" in the WHATWG URL Standard [1] and the
+// characters in the host parsing loop in Url.prototype.parse, with the
+// following additions:
+//
+// - ':' since this could cause a "protocol spoofing" bug
+// - '@' since this could cause parts of the hostname to be confused with auth
+// - '[' and ']' since this could cause a non-IPv6 hostname to be interpreted
+//   as IPv6 by isIpv6Hostname above
+//
+// [1]: https://url.spec.whatwg.org/#forbidden-host-code-point
+const forbiddenHostChars = /[\0\t\n\r #%/:<>?@[\\\]^|]/;
+// For IPv6, permit '[', ']', and ':'.
+const forbiddenHostCharsIpv6 = /[\0\t\n\r #%/<>?@\\^|]/;
+
+Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
+  validateString(url, 'url');
+
+  // Copy chrome, IE, opera backslash-handling behavior.
+  // Back slashes before the query string get converted to forward slashes
+  // See: https://code.google.com/p/chromium/issues/detail?id=25916
+  let hasHash = false;
+  let hasAt = false;
+  let start = -1;
+  let end = -1;
+  let rest = '';
+  let lastPos = 0;
+  for (let i = 0, inWs = false, split = false; i < url.length; ++i) {
+    const code = url.charCodeAt(i);
+
+    // Find first and last non-whitespace characters for trimming
+    const isWs = code < 33 ||
+                 code === CHAR_NO_BREAK_SPACE ||
+                 code === CHAR_ZERO_WIDTH_NOBREAK_SPACE;
+    if (start === -1) {
+      if (isWs)
+        continue;
+      lastPos = start = i;
+    } else if (inWs) {
+      if (!isWs) {
+        end = -1;
+        inWs = false;
+      }
+    } else if (isWs) {
+      end = i;
+      inWs = true;
+    }
+
+    // Only convert backslashes while we haven't seen a split character
+    if (!split) {
+      switch (code) {
+        case CHAR_AT:
+          hasAt = true;
+          break;
+        case CHAR_HASH:
+          hasHash = true;
+        // Fall through
+        case CHAR_QUESTION_MARK:
+          split = true;
+          break;
+        case CHAR_BACKWARD_SLASH:
+          if (i - lastPos > 0)
+            rest += url.slice(lastPos, i);
+          rest += '/';
+          lastPos = i + 1;
+          break;
+      }
+    } else if (!hasHash && code === CHAR_HASH) {
+      hasHash = true;
+    }
+  }
+
+  // Check if string was non-empty (including strings with only whitespace)
+  if (start !== -1) {
+    if (lastPos === start) {
+      // We didn't convert any backslashes
+
+      if (end === -1) {
+        if (start === 0)
+          rest = url;
+        else
+          rest = url.slice(start);
+      } else {
+        rest = url.slice(start, end);
+      }
+    } else if (end === -1 && lastPos < url.length) {
+      // We converted some backslashes and have only part of the entire string
+      rest += url.slice(lastPos);
+    } else if (end !== -1 && lastPos < end) {
+      // We converted some backslashes and have only part of the entire string
+      rest += url.slice(lastPos, end);
+    }
+  }
+
+  if (!slashesDenoteHost && !hasHash && !hasAt) {
+    // Try fast path regexp
+    const simplePath = simplePathPattern.exec(rest);
+    if (simplePath) {
+      this.path = rest;
+      this.href = rest;
+      this.pathname = simplePath[1];
+      if (simplePath[2]) {
+        this.search = simplePath[2];
+        if (parseQueryString) {
+          this.query = querystring.parse(this.search.slice(1));
+        } else {
+          this.query = this.search.slice(1);
+        }
+      } else if (parseQueryString) {
+        this.search = null;
+        this.query = { __proto__: null };
+      }
+      return this;
+    }
+  }
+
+  let proto = protocolPattern.exec(rest);
+  let lowerProto;
+  if (proto) {
+    proto = proto[0];
+    lowerProto = proto.toLowerCase();
+    this.protocol = lowerProto;
+    rest = rest.slice(proto.length);
+  }
+
+  // Figure out if it's got a host
+  // user@server is *always* interpreted as a hostname, and url
+  // resolution will treat //foo/bar as host=foo,path=bar because that's
+  // how the browser resolves relative URLs.
+  let slashes;
+  if (slashesDenoteHost || proto || hostPattern.test(rest)) {
+    slashes = rest.charCodeAt(0) === CHAR_FORWARD_SLASH &&
+              rest.charCodeAt(1) === CHAR_FORWARD_SLASH;
+    if (slashes && !(proto && hostlessProtocol.has(lowerProto))) {
+      rest = rest.slice(2);
+      this.slashes = true;
+    }
+  }
+
+  if (!hostlessProtocol.has(lowerProto) &&
+      (slashes || (proto && !slashedProtocol.has(proto)))) {
+
+    // there's a hostname.
+    // the first instance of /, ?, ;, or # ends the host.
+    //
+    // If there is an @ in the hostname, then non-host chars *are* allowed
+    // to the left of the last @ sign, unless some host-ending character
+    // comes *before* the @-sign.
+    // URLs are obnoxious.
+    //
+    // ex:
+    // http://a@b@c/ => user:a@b host:c
+    // http://a@b?@c => user:a host:b path:/?@c
+
+    let hostEnd = -1;
+    let atSign = -1;
+    let nonHost = -1;
+    for (let i = 0; i < rest.length; ++i) {
+      switch (rest.charCodeAt(i)) {
+        case CHAR_TAB:
+        case CHAR_LINE_FEED:
+        case CHAR_CARRIAGE_RETURN:
+          // WHATWG URL removes tabs, newlines, and carriage returns. Let's do that too.
+          rest = rest.slice(0, i) + rest.slice(i + 1);
+          i -= 1;
+          break;
+        case CHAR_SPACE:
+        case CHAR_DOUBLE_QUOTE:
+        case CHAR_PERCENT:
+        case CHAR_SINGLE_QUOTE:
+        case CHAR_SEMICOLON:
+        case CHAR_LEFT_ANGLE_BRACKET:
+        case CHAR_RIGHT_ANGLE_BRACKET:
+        case CHAR_BACKWARD_SLASH:
+        case CHAR_CIRCUMFLEX_ACCENT:
+        case CHAR_GRAVE_ACCENT:
+        case CHAR_LEFT_CURLY_BRACKET:
+        case CHAR_VERTICAL_LINE:
+        case CHAR_RIGHT_CURLY_BRACKET:
+          // Characters that are never ever allowed in a hostname from RFC 2396
+          if (nonHost === -1)
+            nonHost = i;
+          break;
+        case CHAR_HASH:
+        case CHAR_FORWARD_SLASH:
+        case CHAR_QUESTION_MARK:
+          // Find the first instance of any host-ending characters
+          if (nonHost === -1)
+            nonHost = i;
+          hostEnd = i;
+          break;
+        case CHAR_AT:
+          // At this point, either we have an explicit point where the
+          // auth portion cannot go past, or the last @ char is the decider.
+          atSign = i;
+          nonHost = -1;
+          break;
+      }
+      if (hostEnd !== -1)
+        break;
+    }
+    start = 0;
+    if (atSign !== -1) {
+      this.auth = decodeURIComponent(rest.slice(0, atSign));
+      start = atSign + 1;
+    }
+    if (nonHost === -1) {
+      this.host = rest.slice(start);
+      rest = '';
+    } else {
+      this.host = rest.slice(start, nonHost);
+      rest = rest.slice(nonHost);
+    }
+
+    // pull out port.
+    this.parseHost();
+
+    // We've indicated that there is a hostname,
+    // so even if it's empty, it has to be present.
+    if (typeof this.hostname !== 'string')
+      this.hostname = '';
+
+    const hostname = this.hostname;
+
+    // If hostname begins with [ and ends with ]
+    // assume that it's an IPv6 address.
+    const ipv6Hostname = isIpv6Hostname(hostname);
+
+    // validate a little.
+    if (!ipv6Hostname) {
+      rest = getHostname(this, rest, hostname, url);
+    }
+
+    if (this.hostname.length > hostnameMaxLen) {
+      this.hostname = '';
+    } else {
+      // Hostnames are always lower case.
+      this.hostname = this.hostname.toLowerCase();
+    }
+
+    if (this.hostname !== '') {
+      if (ipv6Hostname) {
+        if (forbiddenHostCharsIpv6.test(this.hostname)) {
+          throw new ERR_INVALID_URL(url);
+        }
+      } else {
+        // IDNA Support: Returns a punycoded representation of "domain".
+        // It only converts parts of the domain name that
+        // have non-ASCII characters, i.e. it doesn't matter if
+        // you call it with a domain that already is ASCII-only.
+        this.hostname = toASCII(this.hostname);
+
+        // Prevent two potential routes of hostname spoofing.
+        // 1. If this.hostname is empty, it must have become empty due to toASCII
+        //    since we checked this.hostname above.
+        // 2. If any of forbiddenHostChars appears in this.hostname, it must have
+        //    also gotten in due to toASCII. This is since getHostname would have
+        //    filtered them out otherwise.
+        // Rather than trying to correct this by moving the non-host part into
+        // the pathname as we've done in getHostname, throw an exception to
+        // convey the severity of this issue.
+        if (this.hostname === '' || forbiddenHostChars.test(this.hostname)) {
+          throw new ERR_INVALID_URL(url);
+        }
+      }
+    }
+
+    const p = this.port ? ':' + this.port : '';
+    const h = this.hostname || '';
+    this.host = h + p;
+
+    // strip [ and ] from the hostname
+    // the host field still retains them, though
+    if (ipv6Hostname) {
+      this.hostname = this.hostname.slice(1, -1);
+      if (rest[0] !== '/') {
+        rest = '/' + rest;
+      }
+    }
+  }
+
+  // Now rest is set to the post-host stuff.
+  // Chop off any delim chars.
+  if (!unsafeProtocol.has(lowerProto)) {
+    // First, make 100% sure that any "autoEscape" chars get
+    // escaped, even if encodeURIComponent doesn't think they
+    // need to be.
+    rest = autoEscapeStr(rest);
+  }
+
+  let questionIdx = -1;
+  let hashIdx = -1;
+  for (let i = 0; i < rest.length; ++i) {
+    const code = rest.charCodeAt(i);
+    if (code === CHAR_HASH) {
+      this.hash = rest.slice(i);
+      hashIdx = i;
+      break;
+    } else if (code === CHAR_QUESTION_MARK && questionIdx === -1) {
+      questionIdx = i;
+    }
+  }
+
+  if (questionIdx !== -1) {
+    if (hashIdx === -1) {
+      this.search = rest.slice(questionIdx);
+      this.query = rest.slice(questionIdx + 1);
+    } else {
+      this.search = rest.slice(questionIdx, hashIdx);
+      this.query = rest.slice(questionIdx + 1, hashIdx);
+    }
+    if (parseQueryString) {
+      this.query = querystring.parse(this.query);
+    }
+  } else if (parseQueryString) {
+    // No query string, but parseQueryString still requested
+    this.search = null;
+    this.query = { __proto__: null };
+  }
+
+  const useQuestionIdx =
+    questionIdx !== -1 && (hashIdx === -1 || questionIdx < hashIdx);
+  const firstIdx = useQuestionIdx ? questionIdx : hashIdx;
+  if (firstIdx === -1) {
+    if (rest.length > 0)
+      this.pathname = rest;
+  } else if (firstIdx > 0) {
+    this.pathname = rest.slice(0, firstIdx);
+  }
+  if (slashedProtocol.has(lowerProto) &&
+      this.hostname && !this.pathname) {
+    this.pathname = '/';
+  }
+
+  // To support http.request
+  if (this.pathname || this.search) {
+    const p = this.pathname || '';
+    const s = this.search || '';
+    this.path = p + s;
+  }
+
+  // Finally, reconstruct the href based on what has been validated.
+  this.href = this.format();
+  return this;
+};
+
+function getHostname(self, rest, hostname, url) {
+  for (let i = 0; i < hostname.length; ++i) {
+    const code = hostname.charCodeAt(i);
+    const isValid = (code !== CHAR_FORWARD_SLASH &&
+                     code !== CHAR_BACKWARD_SLASH &&
+                     code !== CHAR_HASH &&
+                     code !== CHAR_QUESTION_MARK &&
+                     code !== CHAR_COLON);
+
+    if (!isValid) {
+      // If leftover starts with :, then it represents an invalid port.
+      if (code === CHAR_COLON) {
+        throw new ERR_INVALID_ARG_VALUE('url', 'Invalid port in url', url);
+      }
+      self.hostname = hostname.slice(0, i);
+      return `/${hostname.slice(i)}${rest}`;
+    }
+  }
+  return rest;
+}
+
+// Escaped characters. Use empty strings to fill up unused entries.
+// Using Array is faster than Object/Map
+const escapedCodes = [
+  /* 0 - 9 */ '', '', '', '', '', '', '', '', '', '%09',
+  /* 10 - 19 */ '%0A', '', '', '%0D', '', '', '', '', '', '',
+  /* 20 - 29 */ '', '', '', '', '', '', '', '', '', '',
+  /* 30 - 39 */ '', '', '%20', '', '%22', '', '', '', '', '%27',
+  /* 40 - 49 */ '', '', '', '', '', '', '', '', '', '',
+  /* 50 - 59 */ '', '', '', '', '', '', '', '', '', '',
+  /* 60 - 69 */ '%3C', '', '%3E', '', '', '', '', '', '', '',
+  /* 70 - 79 */ '', '', '', '', '', '', '', '', '', '',
+  /* 80 - 89 */ '', '', '', '', '', '', '', '', '', '',
+  /* 90 - 99 */ '', '', '%5C', '', '%5E', '', '%60', '', '', '',
+  /* 100 - 109 */ '', '', '', '', '', '', '', '', '', '',
+  /* 110 - 119 */ '', '', '', '', '', '', '', '', '', '',
+  /* 120 - 125 */ '', '', '', '%7B', '%7C', '%7D',
+];
+
+// Automatically escape all delimiters and unwise characters from RFC 2396.
+// Also escape single quotes in case of an XSS attack.
+// Return the escaped string.
+function autoEscapeStr(rest) {
+  let escaped = '';
+  let lastEscapedPos = 0;
+  for (let i = 0; i < rest.length; ++i) {
+    // `escaped` contains substring up to the last escaped character.
+    const escapedChar = escapedCodes[rest.charCodeAt(i)];
+    if (escapedChar) {
+      // Concat if there are ordinary characters in the middle.
+      if (i > lastEscapedPos)
+        escaped += rest.slice(lastEscapedPos, i);
+      escaped += escapedChar;
+      lastEscapedPos = i + 1;
+    }
+  }
+  if (lastEscapedPos === 0)  // Nothing has been escaped.
+    return rest;
+
+  // There are ordinary characters at the end.
+  if (lastEscapedPos < rest.length)
+    escaped += rest.slice(lastEscapedPos);
+
+  return escaped;
+}
+
+// Format a parsed object into a url string
+function urlFormat(urlObject, options) {
+  // Ensure it's an object, and not a string url.
+  // If it's an object, this is a no-op.
+  // this way, you can call urlParse() on strings
+  // to clean up potentially wonky urls.
+  if (typeof urlObject === 'string') {
+    urlObject = urlParse(urlObject);
+  } else if (typeof urlObject !== 'object' || urlObject === null) {
+    throw new ERR_INVALID_ARG_TYPE('urlObject',
+                                   ['Object', 'string'], urlObject);
+  } else if (urlObject instanceof URL) {
+    let fragment = true;
+    let unicode = false;
+    let search = true;
+    let auth = true;
+
+    if (options) {
+      validateObject(options, 'options');
+
+      if (options.fragment != null) {
+        fragment = Boolean(options.fragment);
+      }
+
+      if (options.unicode != null) {
+        unicode = Boolean(options.unicode);
+      }
+
+      if (options.search != null) {
+        search = Boolean(options.search);
+      }
+
+      if (options.auth != null) {
+        auth = Boolean(options.auth);
+      }
+    }
+
+    return bindingUrl.format(urlObject.href, fragment, unicode, search, auth);
+  }
+
+  return Url.prototype.format.call(urlObject);
+}
+
+// These characters do not need escaping:
+// ! - . _ ~
+// ' ( ) * :
+// digits
+// alpha (uppercase)
+// alpha (lowercase)
+const noEscapeAuth = new Int8Array([
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 - 0x0F
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10 - 0x1F
+  0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, // 0x20 - 0x2F
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 0x30 - 0x3F
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 - 0x4F
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 0x50 - 0x5F
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 0x6F
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 0x70 - 0x7F
+]);
+
+Url.prototype.format = function format() {
+  let auth = this.auth || '';
+  if (auth) {
+    auth = encodeStr(auth, noEscapeAuth, hexTable);
+    auth += '@';
+  }
+
+  let protocol = this.protocol || '';
+  if (protocol && StringPrototypeCharCodeAt(protocol, protocol.length - 1) !== 58 /* : */) {
+    protocol += ':';
+  }
+
+  let pathname = this.pathname || '';
+  let hash = this.hash || '';
+  let host = '';
+  let query = '';
+
+  if (this.host) {
+    host = auth + this.host;
+  } else if (this.hostname) {
+    host = auth + (
+      StringPrototypeIndexOf(this.hostname, ':') !== -1 && !isIpv6Hostname(this.hostname) ?
+        '[' + this.hostname + ']' :
+        this.hostname
+    );
+    if (this.port) {
+      host += ':' + this.port;
+    }
+  }
+
+  if (this.query !== null && typeof this.query === 'object') {
+    query = querystring.stringify(this.query);
+  }
+  let search = this.search || (query && ('?' + query)) || '';
+
+  if (StringPrototypeIndexOf(pathname, '#') !== -1 || StringPrototypeIndexOf(pathname, '?') !== -1) {
+    let newPathname = '';
+    let lastPos = 0;
+    const len = pathname.length;
+    for (let i = 0; i < len; i++) {
+      const code = StringPrototypeCharCodeAt(pathname, i);
+      if (code === CHAR_HASH || code === CHAR_QUESTION_MARK) {
+        if (i > lastPos) {
+          newPathname += StringPrototypeSlice(pathname, lastPos, i);
+        }
+        newPathname += (code === CHAR_HASH ? '%23' : '%3F');
+        lastPos = i + 1;
+      }
+    }
+    if (lastPos < len) {
+      newPathname += StringPrototypeSlice(pathname, lastPos);
+    }
+    pathname = newPathname;
+  }
+
+  // Only the slashedProtocols get the //.  Not mailto:, xmpp:, etc.
+  // unless they had them to begin with.
+  if (this.slashes || slashedProtocol.has(protocol)) {
+    if (this.slashes || host) {
+      if (pathname && StringPrototypeCharCodeAt(pathname, 0) !== CHAR_FORWARD_SLASH)
+        pathname = '/' + pathname;
+      host = '//' + host;
+    } else if (protocol.length >= 4 &&
+               StringPrototypeCharCodeAt(protocol, 0) === 102/* f */ &&
+               StringPrototypeCharCodeAt(protocol, 1) === 105/* i */ &&
+               StringPrototypeCharCodeAt(protocol, 2) === 108/* l */ &&
+               StringPrototypeCharCodeAt(protocol, 3) === 101/* e */) {
+      host = '//';
+    }
+  }
+
+  // Escape '#' in search.
+  if (StringPrototypeIndexOf(search, '#') !== -1) {
+    search = StringPrototypeReplaceAll(search, '#', '%23');
+  }
+
+  if (hash && StringPrototypeCharCodeAt(hash, 0) !== CHAR_HASH) {
+    hash = '#' + hash;
+  }
+  if (search && StringPrototypeCharCodeAt(search, 0) !== CHAR_QUESTION_MARK) {
+    search = '?' + search;
+  }
+
+  return protocol + host + pathname + search + hash;
+};
+
+function urlResolve(source, relative) {
+  return urlParse(source, false, true).resolve(relative);
+}
+
+Url.prototype.resolve = function resolve(relative) {
+  return this.resolveObject(urlParse(relative, false, true)).format();
+};
+
+function urlResolveObject(source, relative) {
+  if (!source) return relative;
+  return urlParse(source, false, true).resolveObject(relative);
+}
+
+Url.prototype.resolveObject = function resolveObject(relative) {
+  if (typeof relative === 'string') {
+    const rel = new Url();
+    rel.parse(relative, false, true);
+    relative = rel;
+  }
+
+  const result = new Url();
+  ObjectAssign(result, this);
+
+  // Hash is always overridden, no matter what.
+  // even href="" will remove it.
+  result.hash = relative.hash;
+
+  // If the relative url is empty, then there's nothing left to do here.
+  if (relative.href === '') {
+    result.href = result.format();
+    return result;
+  }
+
+  // Hrefs like //foo/bar always cut to the protocol.
+  if (relative.slashes && !relative.protocol) {
+    // Take everything except the protocol from relative
+    const relativeWithoutProtocol = ObjectKeys(relative).reduce((acc, key) => {
+      if (key !== 'protocol') {
+        acc[key] = relative[key];
+      }
+      return acc;
+    }, {});
+    ObjectAssign(result, relativeWithoutProtocol);
+
+    // urlParse appends trailing / to urls like http://www.example.com
+    if (slashedProtocol.has(result.protocol) &&
+        result.hostname && !result.pathname) {
+      result.path = result.pathname = '/';
+    }
+
+    result.href = result.format();
+    return result;
+  }
+
+  if (relative.protocol && relative.protocol !== result.protocol) {
+    // If it's a known url protocol, then changing
+    // the protocol does weird things
+    // first, if it's not file:, then we MUST have a host,
+    // and if there was a path
+    // to begin with, then we MUST have a path.
+    // if it is file:, then the host is dropped,
+    // because that's known to be hostless.
+    // anything else is assumed to be absolute.
+    if (!slashedProtocol.has(relative.protocol)) {
+      ObjectAssign(result, relative);
+      result.href = result.format();
+      return result;
+    }
+
+    result.protocol = relative.protocol;
+    if (!relative.host &&
+        !/^file:?$/.test(relative.protocol) &&
+        !hostlessProtocol.has(relative.protocol)) {
+      const relPath = (relative.pathname || '').split('/');
+      while (relPath.length && !(relative.host = relPath.shift()));
+      relative.host ||= '';
+      relative.hostname ||= '';
+      if (relPath[0] !== '') relPath.unshift('');
+      if (relPath.length < 2) relPath.unshift('');
+      result.pathname = relPath.join('/');
+    } else {
+      result.pathname = relative.pathname;
+    }
+    result.search = relative.search;
+    result.query = relative.query;
+    result.host = relative.host || '';
+    result.auth = relative.auth;
+    result.hostname = relative.hostname || relative.host;
+    result.port = relative.port;
+    // To support http.request
+    if (result.pathname || result.search) {
+      const p = result.pathname || '';
+      const s = result.search || '';
+      result.path = p + s;
+    }
+    result.slashes ||= relative.slashes;
+    result.href = result.format();
+    return result;
+  }
+
+  const isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/');
+  const isRelAbs = (
+    relative.host || (relative.pathname && relative.pathname.charAt(0) === '/')
+  );
+  let mustEndAbs = (isRelAbs || isSourceAbs ||
+                    (result.host && relative.pathname));
+  const removeAllDots = mustEndAbs;
+  let srcPath = (result.pathname && result.pathname.split('/')) || [];
+  const relPath = (relative.pathname && relative.pathname.split('/')) || [];
+  const noLeadingSlashes = result.protocol &&
+      !slashedProtocol.has(result.protocol);
+
+  // If the url is a non-slashed url, then relative
+  // links like ../.. should be able
+  // to crawl up to the hostname, as well.  This is strange.
+  // result.protocol has already been set by now.
+  // Later on, put the first path part into the host field.
+  if (noLeadingSlashes) {
+    result.hostname = '';
+    result.port = null;
+    if (result.host) {
+      if (srcPath[0] === '') srcPath[0] = result.host;
+      else srcPath.unshift(result.host);
+    }
+    result.host = '';
+    if (relative.protocol) {
+      relative.hostname = null;
+      relative.port = null;
+      result.auth = null;
+      if (relative.host) {
+        if (relPath[0] === '') relPath[0] = relative.host;
+        else relPath.unshift(relative.host);
+      }
+      relative.host = null;
+    }
+    mustEndAbs &&= (relPath[0] === '' || srcPath[0] === '');
+  }
+
+  if (isRelAbs) {
+    // it's absolute.
+    if (relative.host || relative.host === '') {
+      if (result.host !== relative.host) result.auth = null;
+      result.host = relative.host;
+      result.port = relative.port;
+    }
+    if (relative.hostname || relative.hostname === '') {
+      if (result.hostname !== relative.hostname) result.auth = null;
+      result.hostname = relative.hostname;
+    }
+    result.search = relative.search;
+    result.query = relative.query;
+    srcPath = relPath;
+    // Fall through to the dot-handling below.
+  } else if (relPath.length) {
+    // it's relative
+    // throw away the existing file, and take the new path instead.
+    srcPath ||= [];
+    srcPath.pop();
+    srcPath = srcPath.concat(relPath);
+    result.search = relative.search;
+    result.query = relative.query;
+  } else if (relative.search !== null && relative.search !== undefined) {
+    // Just pull out the search.
+    // like href='?foo'.
+    // Put this after the other two cases because it simplifies the booleans
+    if (noLeadingSlashes) {
+      result.hostname = result.host = srcPath.shift();
+      // Occasionally the auth can get stuck only in host.
+      // This especially happens in cases like
+      // url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+      const authInHost =
+        result.host && result.host.indexOf('@') > 0 && result.host.split('@');
+      if (authInHost) {
+        result.auth = authInHost.shift();
+        result.host = result.hostname = authInHost.shift();
+      }
+    }
+    result.search = relative.search;
+    result.query = relative.query;
+    // To support http.request
+    if (result.pathname !== null || result.search !== null) {
+      result.path = (result.pathname ? result.pathname : '') +
+                    (result.search ? result.search : '');
+    }
+    result.href = result.format();
+    return result;
+  }
+
+  if (!srcPath.length) {
+    // No path at all. All other things were already handled above.
+    result.pathname = null;
+    // To support http.request
+    if (result.search) {
+      result.path = '/' + result.search;
+    } else {
+      result.path = null;
+    }
+    result.href = result.format();
+    return result;
+  }
+
+  // If a url ENDs in . or .., then it must get a trailing slash.
+  // however, if it ends in anything else non-slashy,
+  // then it must NOT get a trailing slash.
+  let last = srcPath[srcPath.length - 1];
+  const hasTrailingSlash = (
+    ((result.host || relative.host || srcPath.length > 1) &&
+    (last === '.' || last === '..')) || last === '');
+
+  // Strip single dots, resolve double dots to parent dir
+  // if the path tries to go above the root, `up` ends up > 0
+  let up = 0;
+  for (let i = srcPath.length - 1; i >= 0; i--) {
+    last = srcPath[i];
+    if (last === '.') {
+      spliceOne(srcPath, i);
+    } else if (last === '..') {
+      spliceOne(srcPath, i);
+      up++;
+    } else if (up) {
+      spliceOne(srcPath, i);
+      up--;
+    }
+  }
+
+  // If the path is allowed to go above the root, restore leading ..s
+  if (!mustEndAbs && !removeAllDots) {
+    while (up--) {
+      srcPath.unshift('..');
+    }
+  }
+
+  if (mustEndAbs && srcPath[0] !== '' &&
+      (!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
+    srcPath.unshift('');
+  }
+
+  if (hasTrailingSlash && StringPrototypeAt(ArrayPrototypeJoin(srcPath, '/'), -1) !== '/') {
+    srcPath.push('');
+  }
+
+  const isAbsolute = srcPath[0] === '' ||
+      (srcPath[0] && srcPath[0].charAt(0) === '/');
+
+  // put the host back
+  if (noLeadingSlashes) {
+    result.hostname =
+      result.host = isAbsolute ? '' : srcPath.length ? srcPath.shift() : '';
+    // Occasionally the auth can get stuck only in host.
+    // This especially happens in cases like
+    // url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+    const authInHost = result.host && result.host.indexOf('@') > 0 ?
+      result.host.split('@') : false;
+    if (authInHost) {
+      result.auth = authInHost.shift();
+      result.host = result.hostname = authInHost.shift();
+    }
+  }
+
+  mustEndAbs ||= (result.host && srcPath.length);
+
+  if (mustEndAbs && !isAbsolute) {
+    srcPath.unshift('');
+  }
+
+  if (!srcPath.length) {
+    result.pathname = null;
+    result.path = null;
+  } else {
+    result.pathname = srcPath.join('/');
+  }
+
+  // To support request.http
+  if (result.pathname !== null || result.search !== null) {
+    result.path = (result.pathname ? result.pathname : '') +
+                  (result.search ? result.search : '');
+  }
+  result.auth = relative.auth || result.auth;
+  result.slashes ||= relative.slashes;
+  result.href = result.format();
+  return result;
+};
+
+Url.prototype.parseHost = function parseHost() {
+  let host = this.host;
+  let port = portPattern.exec(host);
+  if (port) {
+    port = port[0];
+    if (port !== ':') {
+      this.port = port.slice(1);
+    }
+    host = host.slice(0, host.length - port.length);
+  }
+  if (host) this.hostname = host;
+};
+
+// When used internally, we are not obligated to associate TypeError with
+// this function, so non-strings can be rejected by underlying implementation.
+// Public API has to validate input and throw appropriate error.
+function pathToFileURL(path, options) {
+  validateString(path, 'path');
+
+  return _pathToFileURL(path, options);
+}
+
+module.exports = {
+  // Original API
+  Url,
+  parse: urlParse,
+  resolve: urlResolve,
+  resolveObject: urlResolveObject,
+  format: urlFormat,
+
+  // WHATWG API
+  URL,
+  URLPattern,
+  URLSearchParams,
+  domainToASCII,
+  domainToUnicode,
+
+  // Utilities
+  pathToFileURL,
+  fileURLToPath,
+  fileURLToPathBuffer,
+  urlToHttpOptions,
+};
diff --git a/src/Node/Lib/util.cjs b/src/Node/Lib/util.cjs
new file mode 100644
index 00000000..5243d0b8
--- /dev/null
+++ b/src/Node/Lib/util.cjs
@@ -0,0 +1,44 @@
+'use strict';
+
+const util = require('./portable/util-base.cjs');
+const custom = Symbol.for('nodejs.util.promisify.custom');
+const basePromisify = util.promisify;
+
+util.promisify = function promisify(original) {
+  if (typeof original !== 'function') {
+    const error = new TypeError('The "original" argument must be of type function. Received ' + typeof original);
+    error.code = 'ERR_INVALID_ARG_TYPE';
+    throw error;
+  }
+  if (original[custom] !== undefined) {
+    if (typeof original[custom] !== 'function') throw new TypeError('The "util.promisify.custom" property must be of type function.');
+    return original[custom];
+  }
+  const result = basePromisify(original);
+  Object.defineProperty(result, custom, { value: result, configurable: true });
+  return result;
+};
+Object.defineProperty(util.promisify, 'custom', { value: custom });
+util.TextEncoder = globalThis.TextEncoder;
+util.TextDecoder = globalThis.TextDecoder;
+util.inspect.custom = Symbol.for('nodejs.util.inspect.custom');
+util.format = function format(...args) { return require('./portable/format.cjs').format(util.inspect, undefined, args); };
+util.formatWithOptions = function formatWithOptions(options, ...args) {
+  if (options === null || typeof options !== 'object') {
+    const error = new TypeError('The "inspectOptions" argument must be of type object.');
+    error.code = 'ERR_INVALID_ARG_TYPE';
+    throw error;
+  }
+  return require('./portable/format.cjs').format(util.inspect, options, args);
+};
+util.stripVTControlCharacters = function stripVTControlCharacters(value) {
+  if (typeof value !== 'string') throw new TypeError('The "str" argument must be of type string.');
+  return value.replace(/[\u001b\u009b][[\]()#;?]*(?:(?:(?:[a-zA-Z\d]*(?:;[-a-zA-Z\d\/#&.:=?%@~_]+)*)?\u0007)|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))/g, '');
+};
+util.isDeepStrictEqual = function isDeepStrictEqual(a, b) {
+  try { require('./assert.cjs').deepStrictEqual(a, b); return true; } catch (error) {
+    if (error && error.code === 'ERR_ASSERTION') return false;
+    throw error;
+  }
+};
+module.exports = util;
diff --git a/src/Node/Lib/vm.cjs b/src/Node/Lib/vm.cjs
new file mode 100644
index 00000000..2b0424f6
--- /dev/null
+++ b/src/Node/Lib/vm.cjs
@@ -0,0 +1,63 @@
+'use strict';
+
+const { Buffer } = require('buffer');
+const host = __phasisNodeHost.vm;
+const vm = module.exports;
+function error(code, message, Constructor = TypeError) { return Object.assign(new Constructor(message), { code }); }
+function object(value, name) {
+  if (typeof value !== 'object' || value === null) throw error('ERR_INVALID_ARG_TYPE', `The "${name}" argument must be of type object`);
+  return value;
+}
+function options(value) {
+  if (value === undefined) return {};
+  if (typeof value === 'string') return { filename: value };
+  object(value, 'options');
+  for (const name of ['lineOffset', 'columnOffset']) if (value[name] !== undefined && !Number.isInteger(value[name])) throw error('ERR_OUT_OF_RANGE', `The value of "options.${name}" is out of range`, RangeError);
+  if (value.timeout !== undefined && (!Number.isInteger(value.timeout) || value.timeout <= 0 || value.timeout > 0xffffffff)) throw error('ERR_OUT_OF_RANGE', 'The value of "options.timeout" is out of range', RangeError);
+  return value;
+}
+function run(script, context, value) {
+  const config = options(value);
+  const result = host.run(script, context, config);
+  if (result.timeout) throw error('ERR_SCRIPT_EXECUTION_TIMEOUT', `Script execution timed out after ${config.timeout}ms`, Error);
+  return result.value;
+}
+vm.isContext = value => host.isContext(value);
+vm.createContext = (context = {}, value) => {
+  object(context, 'object');
+  const config = options(value);
+  if (config.codeGeneration?.strings === false || config.codeGeneration?.wasm === false) {
+    throw error('ERR_FEATURE_UNAVAILABLE_ON_PLATFORM', 'Per-context code-generation controls are not yet available in Phasis', Error);
+  }
+  return host.createContext(context, config);
+};
+class Script {
+  constructor(code, value) {
+    const config = options(value);
+    this._source = String(code); this._options = config;
+    this._script = host.compile(this._source, config);
+    if (config.cachedData !== undefined) this.cachedDataRejected = true;
+    if (config.produceCachedData) this.cachedDataProduced = false;
+  }
+  runInContext(context, value) {
+    if (!vm.isContext(context)) throw error('ERR_INVALID_ARG_TYPE', 'The "contextifiedObject" argument must be a vm.Context');
+    return run(this._script, context, value);
+  }
+  runInNewContext(context = {}, value) { return this.runInContext(vm.createContext(context, value), value); }
+  runInThisContext(value) { return run(this._script, undefined, value); }
+  createCachedData() { throw error('ERR_FEATURE_UNAVAILABLE_ON_PLATFORM', 'V8 cached-data serialization is unavailable in Phasis', Error); }
+  get sourceMapURL() { return /\/\/[#@]\s*sourceMappingURL=(\S+)/.exec(this._source)?.[1]; }
+}
+vm.Script = Script;
+vm.createScript = (code, value) => new Script(code, value);
+vm.runInContext = (code, context, value) => new Script(code, value).runInContext(context, value);
+vm.runInNewContext = (code, context, value) => new Script(code, value).runInNewContext(context, value);
+vm.runInThisContext = (code, value) => new Script(code, value).runInThisContext(value);
+vm.compileFunction = (code, params = [], value = {}) => {
+  if (typeof code !== 'string') throw error('ERR_INVALID_ARG_TYPE', 'The "code" argument must be of type string');
+  if (!Array.isArray(params) || params.some(name => typeof name !== 'string')) throw error('ERR_INVALID_ARG_TYPE', 'The "params" argument must be an array of strings');
+  const config = options(value);
+  if (config.contextExtensions?.length) throw error('ERR_FEATURE_UNAVAILABLE_ON_PLATFORM', 'compileFunction context extensions are not yet available in Phasis', Error);
+  const source = `(function (${params.join(',')}) {\n${code}\n})`;
+  return config.parsingContext ? vm.runInContext(source, config.parsingContext, config) : vm.runInThisContext(source, config);
+};
diff --git a/src/Node/Lib/zlib.cjs b/src/Node/Lib/zlib.cjs
new file mode 100644
index 00000000..5c38d315
--- /dev/null
+++ b/src/Node/Lib/zlib.cjs
@@ -0,0 +1,250 @@
+'use strict';
+
+const { Transform } = require('stream');
+const { Buffer } = require('buffer');
+const host = __phasisNodeHost.zlib;
+const zlib = module.exports;
+const constants = zlib.constants = Object.freeze({
+  Z_NO_FLUSH: 0, Z_PARTIAL_FLUSH: 1, Z_SYNC_FLUSH: 2, Z_FULL_FLUSH: 3, Z_FINISH: 4, Z_BLOCK: 5,
+  Z_OK: 0, Z_STREAM_END: 1, Z_NEED_DICT: 2, Z_ERRNO: -1, Z_STREAM_ERROR: -2,
+  Z_DATA_ERROR: -3, Z_MEM_ERROR: -4, Z_BUF_ERROR: -5, Z_VERSION_ERROR: -6,
+  Z_NO_COMPRESSION: 0, Z_BEST_SPEED: 1, Z_BEST_COMPRESSION: 9, Z_DEFAULT_COMPRESSION: -1,
+  Z_FILTERED: 1, Z_HUFFMAN_ONLY: 2, Z_RLE: 3, Z_FIXED: 4, Z_DEFAULT_STRATEGY: 0,
+  DEFLATE: 1, INFLATE: 2, GZIP: 3, GUNZIP: 4, DEFLATERAW: 5, INFLATERAW: 6, UNZIP: 7,
+  BROTLI_DECODE: 8, BROTLI_ENCODE: 9,
+  Z_MIN_WINDOWBITS: 8, Z_MAX_WINDOWBITS: 15, Z_DEFAULT_WINDOWBITS: 15,
+  Z_MIN_CHUNK: 64, Z_MAX_CHUNK: Infinity, Z_DEFAULT_CHUNK: 16384,
+  Z_MIN_MEMLEVEL: 1, Z_MAX_MEMLEVEL: 9, Z_DEFAULT_MEMLEVEL: 8,
+  Z_MIN_LEVEL: -1, Z_MAX_LEVEL: 9, Z_DEFAULT_LEVEL: -1,
+  BROTLI_OPERATION_PROCESS: 0, BROTLI_OPERATION_FLUSH: 1, BROTLI_OPERATION_FINISH: 2, BROTLI_OPERATION_EMIT_METADATA: 3,
+  BROTLI_PARAM_MODE: 0, BROTLI_MODE_GENERIC: 0, BROTLI_MODE_TEXT: 1, BROTLI_MODE_FONT: 2, BROTLI_DEFAULT_MODE: 0,
+  BROTLI_PARAM_QUALITY: 1, BROTLI_MIN_QUALITY: 0, BROTLI_MAX_QUALITY: 11, BROTLI_DEFAULT_QUALITY: 11,
+  BROTLI_PARAM_LGWIN: 2, BROTLI_MIN_WINDOW_BITS: 10, BROTLI_MAX_WINDOW_BITS: 24, BROTLI_DEFAULT_WINDOW: 22,
+  BROTLI_PARAM_LGBLOCK: 3, BROTLI_MIN_INPUT_BLOCK_BITS: 16, BROTLI_MAX_INPUT_BLOCK_BITS: 24,
+  BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING: 4, BROTLI_PARAM_SIZE_HINT: 5,
+  BROTLI_PARAM_LARGE_WINDOW: 6, BROTLI_PARAM_NPOSTFIX: 7, BROTLI_PARAM_NDIRECT: 8,
+  BROTLI_DECODER_RESULT_ERROR: 0, BROTLI_DECODER_RESULT_SUCCESS: 1,
+  BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: 2, BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: 3,
+  BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION: 0, BROTLI_DECODER_PARAM_LARGE_WINDOW: 1,
+});
+for (const [name, value] of Object.entries(constants)) if (name.startsWith('Z_')) zlib[name] = value;
+zlib.codes = {};
+for (const name of ['Z_OK', 'Z_STREAM_END', 'Z_NEED_DICT', 'Z_ERRNO', 'Z_STREAM_ERROR', 'Z_DATA_ERROR', 'Z_MEM_ERROR', 'Z_BUF_ERROR', 'Z_VERSION_ERROR']) {
+  zlib.codes[name] = constants[name]; zlib.codes[constants[name]] = name;
+}
+Object.freeze(zlib.codes);
+
+function failure(code, message, Class = Error) { return Object.assign(new Class(message), { code }); }
+function bytes(value) {
+  if (typeof value === 'string') return Buffer.from(value);
+  if (value instanceof ArrayBuffer) return new Uint8Array(value);
+  if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
+  throw failure('ERR_INVALID_ARG_TYPE', 'The "buffer" argument must be of type string or an instance of Buffer, TypedArray, DataView, or ArrayBuffer', TypeError);
+}
+function config(value) {
+  if (value == null) return {};
+  if (typeof value !== 'object') throw failure('ERR_INVALID_ARG_TYPE', 'The "options" argument must be of type object', TypeError);
+  const result = { ...value };
+  for (const [name, min, max] of [['level', -1, 9], ['windowBits', 8, 15], ['memLevel', 1, 9], ['strategy', 0, 4], ['chunkSize', 64, Infinity], ['flush', 0, 5], ['finishFlush', 0, 5], ['maxOutputLength', 1, Number.MAX_SAFE_INTEGER]]) {
+    const entry = result[name];
+    if (entry !== undefined && (typeof entry !== 'number' || !Number.isInteger(entry) || entry < min || entry > max)) {
+      throw failure('ERR_OUT_OF_RANGE', `The value of "options.${name}" is out of range. It must be >= ${min} and <= ${max}. Received ${entry}`, RangeError);
+    }
+  }
+  if (result.dictionary !== undefined) result.dictionary = bytes(result.dictionary);
+  return result;
+}
+function call(operation, ...args) {
+  const result = host.call(operation, ...args);
+  if (result.error) {
+    const { message, ...properties } = result.error;
+    throw Object.assign(new Error(message), properties);
+  }
+  return result.value;
+}
+function buffer(value) { return Buffer.from(value.buffer, value.byteOffset, value.byteLength); }
+function outputLimit(length, options) {
+  if (length > (options.maxOutputLength ?? Infinity)) throw failure('ERR_BUFFER_TOO_LARGE', `Cannot create a Buffer larger than ${options.maxOutputLength} bytes`, RangeError);
+}
+
+class ZlibBase extends Transform {
+  constructor(mode, options) {
+    options = config(options);
+    super(options);
+    this._mode = mode; this._options = options;
+    this._codec = call('create', mode, options);
+    this._handle = this._codec;
+    this.bytesWritten = 0; this._outputLength = 0;
+    this._flushFlag = options.flush ?? constants.Z_NO_FLUSH;
+    this._finishFlushFlag = options.finishFlush ?? constants.Z_FINISH;
+  }
+  _transform(chunk, encoding, done) {
+    try {
+      const result = call('process', this._codec, bytes(chunk), this._flushFlag);
+      this.bytesWritten = result.consumed;
+      this._outputLength += result.bytes.length;
+      outputLimit(this._outputLength, this._options);
+      if (result.bytes.length) this.push(buffer(result.bytes));
+      done();
+    } catch (error) { done(error); }
+  }
+  _flush(done) {
+    try {
+      const result = call('process', this._codec, Buffer.alloc(0), this._finishFlushFlag);
+      this.bytesWritten = result.consumed;
+      this._outputLength += result.bytes.length;
+      outputLimit(this._outputLength, this._options);
+      if (result.bytes.length) this.push(buffer(result.bytes));
+      done();
+    } catch (error) { done(error); }
+  }
+  _destroy(error, done) {
+    if (this._handle !== null) call('close', this._codec);
+    this._handle = null;
+    done(error);
+  }
+  close(cb) { if (cb) this.once('close', cb); this.destroy(); }
+  reset() { call('reset', this._codec); this.bytesWritten = 0; this._outputLength = 0; }
+  flush(kind, cb) {
+    if (typeof kind === 'function') { cb = kind; kind = constants.Z_FULL_FLUSH; }
+    kind ??= constants.Z_FULL_FLUSH;
+    if (this.writableFinished) { if (cb) process.nextTick(cb); return; }
+    this.write(Buffer.alloc(0), () => {
+      try {
+        const result = call('process', this._codec, Buffer.alloc(0), kind);
+        if (result.bytes.length) this.push(buffer(result.bytes));
+        if (cb) cb();
+      } catch (error) { if (cb) cb(error); else this.destroy(error); }
+    });
+  }
+  params(level, strategy, cb) {
+    if (level === (this._options.level ?? -1) && strategy === (this._options.strategy ?? 0)) { process.nextTick(cb); return; }
+    const error = failure('ERR_FEATURE_UNAVAILABLE_ON_PLATFORM', 'PHP zlib does not expose deflateParams');
+    if (cb) process.nextTick(cb, error); else throw error;
+  }
+  _processChunk(chunk, flush, cb) {
+    if (cb) { this._flushFlag = flush; this.write(chunk, cb); return; }
+    try {
+      const result = call('process', this._codec, bytes(chunk), flush);
+      this.bytesWritten = result.consumed;
+      outputLimit(result.bytes.length, this._options);
+      return buffer(result.bytes);
+    } finally { this.close(); }
+  }
+}
+zlib.ZlibBase = ZlibBase;
+for (const name of ['Deflate', 'Inflate', 'Gzip', 'Gunzip', 'DeflateRaw', 'InflateRaw', 'Unzip']) {
+  const Constructor = class extends ZlibBase { constructor(options) { super(name, options); } };
+  Object.defineProperty(Constructor, 'name', { value: name });
+  zlib[name] = Constructor;
+  zlib['create' + name] = options => new Constructor(options);
+  const operation = name[0].toLowerCase() + name.slice(1);
+  zlib[operation + 'Sync'] = (input, value) => {
+    const options = config(value);
+    const data = bytes(input);
+    const stream = new Constructor(options);
+    const result = stream._processChunk(data, options.finishFlush ?? constants.Z_FINISH);
+    return options.info ? { buffer: result, engine: stream } : result;
+  };
+  zlib[operation] = (input, value, cb) => {
+    if (typeof value === 'function') { cb = value; value = undefined; }
+    if (typeof cb !== 'function') throw failure('ERR_INVALID_ARG_TYPE', 'The "callback" argument must be of type function', TypeError);
+    const data = bytes(input); const options = config(value);
+    process.nextTick(() => {
+      let result;
+      try { result = zlib[operation + 'Sync'](data, options); }
+      catch (error) { cb(error); return; }
+      cb(null, result);
+    });
+  };
+}
+
+zlib.crc32 = (input, value = 0) => {
+  const data = bytes(input);
+  let crc = (value ^ 0xffffffff) >>> 0;
+  for (const byte of data) {
+    crc ^= byte;
+    for (let bit = 0; bit < 8; bit++) crc = crc >>> 1 ^ (crc & 1 ? 0xedb88320 : 0);
+  }
+  return (crc ^ 0xffffffff) >>> 0;
+};
+
+function brotliOptions(value) {
+  const options = config(value);
+  const params = options.params ?? {};
+  for (const [name, min, max] of [[constants.BROTLI_PARAM_MODE, 0, 2], [constants.BROTLI_PARAM_QUALITY, 0, 11], [constants.BROTLI_PARAM_LGWIN, 10, 24]]) {
+    if (params[name] !== undefined && (!Number.isInteger(params[name]) || params[name] < min || params[name] > max)) {
+      throw failure('ERR_BROTLI_INVALID_PARAM', `Invalid Brotli parameter: ${name}`, RangeError);
+    }
+  }
+  return options;
+}
+function brotli(input, options, decompress) {
+  try {
+    const result = decompress
+      ? require('./brotli-decoder.cjs')(bytes(input))
+      : require('./brotli-encoder.cjs')(bytes(input), {
+        quality: options.params?.[constants.BROTLI_PARAM_QUALITY],
+        lgwin: options.params?.[constants.BROTLI_PARAM_LGWIN],
+        mode: options.params?.[constants.BROTLI_PARAM_MODE],
+      });
+    outputLimit(result.length, options);
+    return buffer(result);
+  } catch (error) {
+    if (error.code) throw error;
+    if (/unexpected end/i.test(error.message)) throw Object.assign(failure('Z_BUF_ERROR', 'unexpected end of file'), { errno: -5 });
+    throw Object.assign(failure('ERR_BROTLI_COMPRESSION_FAILED', error.message || 'Brotli codec failed'), { errno: -1 });
+  }
+}
+class BrotliBase extends Transform {
+  constructor(decompress, value) {
+    const options = brotliOptions(value);
+    super(options);
+    this._options = options; this._decompress = decompress;
+    this._chunks = []; this.bytesWritten = 0; this._handle = {};
+  }
+  _transform(chunk, encoding, done) {
+    const data = Buffer.from(bytes(chunk));
+    this._chunks.push(data); this.bytesWritten += data.length; done();
+  }
+  _flush(done) {
+    try {
+      const data = Buffer.concat(this._chunks); this._chunks = [];
+      this.push(brotli(data, this._options, this._decompress)); done();
+    } catch (error) { done(error); }
+  }
+  _destroy(error, done) { this._chunks = []; this._handle = null; done(error); }
+  close(cb) { if (cb) this.once('close', cb); this.destroy(); }
+  reset() { this._chunks = []; this.bytesWritten = 0; }
+  flush(kind, cb) {
+    if (typeof kind === 'function') { cb = kind; kind = constants.BROTLI_OPERATION_FLUSH; }
+    if (kind === constants.BROTLI_OPERATION_FINISH) { this.end(cb); return; }
+    const error = failure('ERR_FEATURE_UNAVAILABLE_ON_PLATFORM', 'The bundled Brotli codec requires complete frames and cannot flush a partial frame');
+    if (cb) process.nextTick(cb, error); else throw error;
+  }
+}
+for (const [name, decompress] of [['BrotliCompress', false], ['BrotliDecompress', true]]) {
+  const Constructor = class extends BrotliBase { constructor(options) { super(decompress, options); } };
+  Object.defineProperty(Constructor, 'name', { value: name });
+  zlib[name] = Constructor;
+  zlib['create' + name] = options => new Constructor(options);
+  const operation = name[0].toLowerCase() + name.slice(1);
+  zlib[operation + 'Sync'] = (input, value) => {
+    const options = brotliOptions(value);
+    const result = brotli(input, options, decompress);
+    if (!options.info) return result;
+    const engine = new Constructor(options); engine.bytesWritten = bytes(input).length; engine.close();
+    return { buffer: result, engine };
+  };
+  zlib[operation] = (input, value, cb) => {
+    if (typeof value === 'function') { cb = value; value = undefined; }
+    if (typeof cb !== 'function') throw failure('ERR_INVALID_ARG_TYPE', 'The "callback" argument must be of type function', TypeError);
+    const data = bytes(input); const options = brotliOptions(value);
+    process.nextTick(() => {
+      let result;
+      try { result = zlib[operation + 'Sync'](data, options); }
+      catch (error) { cb(error); return; }
+      cb(null, result);
+    });
+  };
+}
diff --git a/src/Node/NodeCommand.php b/src/Node/NodeCommand.php
new file mode 100644
index 00000000..fb06fb09
--- /dev/null
+++ b/src/Node/NodeCommand.php
@@ -0,0 +1,82 @@
+ $arguments Arguments following the entry file.
+     */
+    public static function runFile(string $file, array $arguments = []): int
+    {
+        $path = realpath($file);
+        if ($path === false || !is_file($path)) {
+            fwrite(STDERR, "Cannot read file: {$file}\n");
+            return 1;
+        }
+        return self::execute($path, null, [PHP_BINARY, $path, ...$arguments]);
+    }
+
+    /**
+     * Evaluate a Node-compatible global script with live stdout/stderr.
+     * @param list $arguments Arguments following the source option.
+     */
+    public static function runSource(string $source, array $arguments = []): int
+    {
+        return self::execute(null, $source, [PHP_BINARY, ...$arguments]);
+    }
+
+    /** @param list $argv */
+    private static function execute(?string $file, ?string $source, array $argv): int
+    {
+        $engine = new Engine();
+        register_shutdown_function(static fn () => $engine->close());
+        try {
+            $engine->enableNode(new NodeOptions(argv: $argv));
+            $process = $engine->getGlobalEnv()->get('process');
+            if (!$process instanceof JsObject) {
+                throw new \RuntimeException('Node process global was not installed.');
+            }
+            $process->set('exit', JsFunction::fromCallable('exit', static function (JsValue $this_, array $args) use ($process): JsValue {
+                exit(self::exitCode($args[0] ?? $process->get('exitCode')));
+            }));
+            $engine->eval(<<<'JS'
+(() => {
+  const format = require('node:util').format;
+  for (const name of ['log', 'info', 'debug', 'warn', 'error']) {
+    console[name] = (...args) => {
+      const stream = name === 'warn' || name === 'error' ? process.stderr : process.stdout;
+      stream.write(format(...args) + '\n');
+    };
+  }
+})();
+JS);
+            if ($file === null) {
+                $engine->eval($source ?? '');
+            } else {
+                $engine->execFile($file);
+            }
+            return self::exitCode($process->get('exitCode'));
+        } catch (\Throwable $error) {
+            fwrite(STDERR, $error->getMessage() . "\n");
+            return 1;
+        } finally {
+            $engine->close();
+        }
+    }
+
+    private static function exitCode(JsValue $value): int
+    {
+        return $value instanceof JsUndefined ? 0 : (int) $value->toNumber();
+    }
+}
diff --git a/src/Node/NodeOptions.php b/src/Node/NodeOptions.php
new file mode 100644
index 00000000..d6ce07f2
--- /dev/null
+++ b/src/Node/NodeOptions.php
@@ -0,0 +1,21 @@
+ $env Environment variables; null inherits the PHP environment.
+     * @param list $argv Program arguments, including the executable and script when supplied.
+     */
+    public function __construct(
+        public ?string $cwd = null,
+        public ?array $env = null,
+        public array $argv = [],
+    ) {
+    }
+}
diff --git a/src/Node/NodeRuntime.php b/src/Node/NodeRuntime.php
new file mode 100644
index 00000000..fda1c6cd
--- /dev/null
+++ b/src/Node/NodeRuntime.php
@@ -0,0 +1,304 @@
+ */
+    private const LIBRARIES = [
+        'buffer' => 'buffer.cjs',
+        'events' => 'events.cjs',
+        'stream' => 'stream.cjs',
+        'stream/promises' => 'stream-promises.cjs',
+        'stream/consumers' => 'stream-consumers.cjs',
+        'stream/web' => 'stream-web.cjs',
+        'string_decoder' => 'string_decoder.cjs',
+        'path' => 'path.cjs',
+        'url' => 'url.cjs',
+        'querystring' => 'querystring.cjs',
+        'util' => 'util.cjs',
+        'assert' => 'assert.cjs',
+        'process' => 'process.cjs',
+        'async_hooks' => 'async_hooks.cjs',
+        'fs' => 'fs.cjs',
+        'net' => 'net.cjs',
+        'http' => 'http.cjs',
+        'http2' => 'http2.cjs',
+        '_http_common' => 'http-common.cjs',
+        'https' => 'https.cjs',
+        'tls' => 'tls.cjs',
+        'tty' => 'tty.cjs',
+        'vm' => 'vm.cjs',
+        'child_process' => 'child_process.cjs',
+        'crypto' => 'crypto.cjs',
+        'zlib' => 'zlib.cjs',
+        'module' => 'module.cjs',
+        'timers' => 'timers.cjs',
+        'timers/promises' => 'timers-promises.cjs',
+    ];
+
+    private string $workingDirectory;
+
+    private JsObject $process;
+
+    /** @var list<\Closure(): void> */
+    private array $nextTicks = [];
+
+    /** @var array */
+    private array $moduleValues = [];
+
+    /** @var list<\Closure(): void> */
+    private array $closeHooks = [];
+
+    /** @var ?\Closure(): bool */
+    private ?\Closure $turnHook = null;
+
+    private bool $closed = false;
+
+    public function __construct(private readonly Engine $engine, private readonly NodeOptions $configuration)
+    {
+        $cwd = realpath($configuration->cwd ?? (getcwd() ?: '.'));
+        if ($cwd === false || !is_dir($cwd)) {
+            throw new \InvalidArgumentException('Node working directory must exist.');
+        }
+        $this->workingDirectory = $cwd;
+        $this->process = new JsObject();
+    }
+
+    /** Configuration retained across Engine::reset(). */
+    public function options(): NodeOptions
+    {
+        return $this->configuration;
+    }
+
+    /** Current directory for this realm, without changing PHP's process directory. */
+    public function cwd(): string
+    {
+        return $this->workingDirectory;
+    }
+
+    /** Set the realm's working directory. */
+    public function chdir(string $directory): void
+    {
+        $path = realpath($this->absolutePath($directory));
+        if ($path === false || !is_dir($path)) {
+            throw new TypeError("ENOENT: no such directory, chdir '{$directory}'");
+        }
+        $this->workingDirectory = $path;
+    }
+
+    /** Resolve a host path against this realm's current directory. */
+    public function absolutePath(string $path): string
+    {
+        return str_starts_with($path, '/') ? $path : $this->workingDirectory . '/' . $path;
+    }
+
+    /** Register built-ins and install the Node global environment. */
+    public function install(): void
+    {
+        $this->engine->getEventLoop()->setRealTime(true);
+        $loader = $this->engine->getInterpreter()->getModuleLoader();
+        foreach (self::LIBRARIES as $name => $file) {
+            $loader->registerCommonJsBuiltinModule(
+                $name,
+                fn (): JsValue => $this->loadLibrary($name, $file),
+                ['node:' . $name],
+            );
+        }
+        $loader->registerCommonJsBuiltinModule('os', fn (): JsValue => OsModule::create($this->engine), ['node:os']);
+        foreach (
+            ['path/posix' => ['path', 'posix'], 'path/win32' => ['path', 'win32'],
+            'util/types' => ['util', 'types'], 'assert/strict' => ['assert', 'strict'],
+            'fs/promises' => ['fs', 'promises']] as $name => [$parent, $property]
+        ) {
+            $loader->registerCommonJsBuiltinModule($name, function () use ($parent, $property): JsValue {
+                $module = $this->module($parent);
+                return $module instanceof JsObject ? $module->get($property) : JsUndefined::instance();
+            }, ['node:' . $name]);
+        }
+
+        $env = $this->engine->getGlobalEnv();
+        $env->defineVar('global', $env->get('globalThis'));
+        $env->defineVar('process', $this->process);
+        $this->initializeProcess();
+        $this->engine->setGlobalJsValue('__phasisNodeHost', HostBindings::create($this->engine, $this));
+        ErrorStack::install($this->engine);
+        $env->defineVar('require', $loader->createRequire($this->workingDirectory . '/.phasis-eval.cjs'));
+        $this->turnHook = fn (): bool => $this->drainNextTicks();
+        JsPromise::setTurnBoundaryHook($this->turnHook);
+        $this->module('process');
+        $buffer = $this->module('buffer');
+        if ($buffer instanceof JsObject) {
+            $env->defineVar('Buffer', $buffer->get('Buffer'));
+        }
+        // Realize the web timer family first so its remaining lazy entries
+        // cannot later overwrite the Node handle-returning functions.
+        $env->get('queueMicrotask');
+        $timers = $this->module('timers');
+        if ($timers instanceof JsObject) {
+            foreach (['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'setImmediate', 'clearImmediate'] as $name) {
+                $env->defineVar($name, $timers->get($name));
+            }
+        }
+        $channels = $this->loadLibrary('#broadcast-channel', 'broadcast_channel.cjs');
+        if ($channels instanceof JsObject) {
+            $env->defineVar('BroadcastChannel', $channels->get('BroadcastChannel'));
+            $closeChannels = $channels->get('closeAll');
+            if ($closeChannels instanceof JsFunction) {
+                $this->onClose(function () use ($closeChannels): void {
+                    $this->engine->getInterpreter()->callFunction($closeChannels, JsUndefined::instance(), []);
+                });
+            }
+        }
+    }
+
+    /** The shared CommonJS value, also exposed as the corresponding ESM default. */
+    public function module(string $name): JsValue
+    {
+        return $this->engine->getInterpreter()->getModuleLoader()->requireModule($name, __FILE__);
+    }
+
+    /** Run the asynchronous Fetch transport on this realm's HTTP sockets. */
+    public function fetch(
+        JsObject $request,
+        JsValue $bytes,
+        JsFunction $cookieGet,
+        JsFunction $cookieSet,
+        JsFunction $finalize,
+        JsFunction $responseConstructor,
+    ): JsPromise {
+        $transport = $this->loadLibrary('#fetch', 'fetch.cjs');
+        if (!$transport instanceof JsFunction) {
+            throw new \LogicException('Invalid Node fetch transport');
+        }
+        $result = $this->engine->getInterpreter()->callFunction(
+            $transport,
+            JsUndefined::instance(),
+            [$request, $bytes, $cookieGet, $cookieSet, $finalize, $responseConstructor],
+        );
+        if (!$result instanceof JsPromise) {
+            throw new \LogicException('Node fetch transport must return a Promise');
+        }
+        return $result;
+    }
+
+    /**
+     * Known native module names, used by module.isBuiltin and process helpers.
+     * @return list
+     */
+    public function builtinNames(): array
+    {
+        return [...array_keys(self::LIBRARIES), 'os', 'path/posix', 'path/win32', 'util/types', 'assert/strict', 'fs/promises'];
+    }
+
+    /**
+     * Queue a nextTick callback with the active async context.
+     * @param list $arguments
+     */
+    public function nextTick(JsFunction $callback, array $arguments = []): void
+    {
+        $context = AsyncContextStorage::active()->snapshot();
+        $this->nextTicks[] = function () use ($callback, $arguments, $context): void {
+            $storage = AsyncContextStorage::active();
+            $previous = $storage->snapshot();
+            $storage->restore($context);
+            try {
+                $this->engine->getInterpreter()->callFunction($callback, JsUndefined::instance(), $arguments);
+            } finally {
+                $storage->restore($previous);
+            }
+        };
+    }
+
+    /** Run the entire nextTick batch before Promise jobs resume. */
+    public function drainNextTicks(): bool
+    {
+        $progressed = $this->nextTicks !== [];
+        while ($this->nextTicks !== []) {
+            $callback = array_shift($this->nextTicks);
+            $callback();
+        }
+        return $progressed;
+    }
+
+    /** Release runtime resources when the owning engine is reset or closed. */
+    public function close(): void
+    {
+        if ($this->closed) {
+            return;
+        }
+        $this->closed = true;
+        $this->nextTicks = [];
+        if (JsPromise::getTurnBoundaryHook() === $this->turnHook) {
+            JsPromise::setTurnBoundaryHook(null);
+        }
+        $this->engine->getEventLoop()->clearAll();
+        $failure = null;
+        foreach (array_reverse($this->closeHooks) as $close) {
+            try {
+                $close();
+            } catch (\Throwable $error) {
+                $failure ??= $error;
+            }
+        }
+        $this->closeHooks = [];
+        if ($failure !== null) {
+            throw $failure;
+        }
+    }
+
+    /** Register cleanup for a host resource group owned by this runtime. */
+    public function onClose(\Closure $close): void
+    {
+        $this->closeHooks[] = $close;
+    }
+
+    private function loadLibrary(string $name, string $file): JsValue
+    {
+        if (!isset($this->moduleValues[$name])) {
+            $path = __DIR__ . '/Lib/' . $file;
+            if (!is_file($path)) {
+                throw new TypeError("Node module '{$name}' is not installed: {$path}");
+            }
+            $this->moduleValues[$name] = $this->engine->getInterpreter()->getModuleLoader()->requireModule($path, __FILE__);
+        }
+        return $this->moduleValues[$name];
+    }
+
+    private function initializeProcess(): void
+    {
+        $environment = $this->configuration->env ?? (getenv() ?: []);
+        $environment['NODE_ENV'] ??= $this->engine->getInterpreter()->getModuleLoader()->moduleOptions()->nodeEnv;
+        $env = new JsObject();
+        foreach ($environment as $key => $value) {
+            $env->set((string) $key, new JsString($value));
+        }
+        $this->process->set('env', $env);
+        $this->process->set('argv', PhpToJs::convert($this->configuration->argv));
+        $this->process->set('argv0', new JsString($this->configuration->argv[0] ?? 'phasis'));
+        $this->process->set('execPath', new JsString(PHP_BINARY));
+        $this->process->set('version', new JsString('v26.12.0'));
+        $this->process->set('release', PhpToJs::convert(['name' => 'node']));
+        $this->process->set('versions', PhpToJs::convert(['node' => '26.12.0', 'phasis' => '0.8.0', 'php' => PHP_VERSION]));
+        $this->process->set('platform', new JsString(match (PHP_OS_FAMILY) {
+            'Darwin' => 'darwin', 'Windows' => 'win32', default => strtolower(PHP_OS_FAMILY),
+        }));
+        $this->process->set('arch', new JsString(match (php_uname('m')) {
+            'arm64', 'aarch64' => 'arm64', 'x86_64', 'amd64' => 'x64', default => php_uname('m'),
+        }));
+    }
+}
diff --git a/src/Node/OsModule.php b/src/Node/OsModule.php
new file mode 100644
index 00000000..6c575d98
--- /dev/null
+++ b/src/Node/OsModule.php
@@ -0,0 +1,191 @@
+set('EOL', new JsString(PHP_EOL));
+        $module->set('devNull', new JsString(PHP_OS_FAMILY === 'Windows' ? '\\\\.\\nul' : '/dev/null'));
+        $module->set('constants', PhpToJs::convert(self::constants()));
+        $functions = [
+            'arch' => static fn (): string => self::processProperty($engine, 'arch'),
+            'platform' => static fn (): string => self::processProperty($engine, 'platform'),
+            'machine' => static fn (): string => php_uname('m'),
+            'type' => static fn (): string => php_uname('s'),
+            'release' => static fn (): string => php_uname('r'),
+            'version' => static fn (): string => php_uname('v'),
+            'hostname' => static fn (): string => gethostname() ?: php_uname('n'),
+            'endianness' => static fn (): string => ord(pack('S', 1)[0]) === 1 ? 'LE' : 'BE',
+            'homedir' => static fn (): string => self::homeDirectory($engine),
+            'tmpdir' => static fn (): string => self::temporaryDirectory($engine),
+            'loadavg' => static fn (): array => function_exists('sys_getloadavg') ? sys_getloadavg() : [0.0, 0.0, 0.0],
+            'freemem' => static fn (): int => self::memory('MemFree'),
+            'totalmem' => static fn (): int => self::memory('MemTotal'),
+            'uptime' => static fn (): float => self::uptime(),
+        ];
+        foreach ($functions as $name => $function) {
+            $module->set($name, JsFunction::fromCallable(
+                $name,
+                static fn (JsValue $this_, array $args): JsValue => PhpToJs::convert($function()),
+                0,
+            ));
+        }
+        $module->set('userInfo', JsFunction::fromCallable('userInfo', static function (JsValue $this_, array $args) use ($engine): JsValue {
+            $options = $args[0] ?? JsUndefined::instance();
+            if (!$options instanceof JsUndefined && !$options instanceof JsObject) {
+                throw new TypeError('The "options" argument must be of type object.');
+            }
+            $encoding = $options instanceof JsObject ? $options->get('encoding') : JsUndefined::instance();
+            $encoding = $encoding instanceof JsUndefined ? 'utf8' : $encoding->toJsString();
+            $result = PhpToJs::convert(self::userInfo($engine));
+            if (!$result instanceof JsObject || $encoding === 'utf8' || $encoding === 'utf-8') {
+                return $result;
+            }
+            $buffer = $engine->getGlobalEnv()->get('Buffer');
+            $from = $buffer instanceof JsObject ? $buffer->get('from') : JsUndefined::instance();
+            if (!$from instanceof JsFunction) {
+                throw new TypeError('Buffer is unavailable in this realm.');
+            }
+            foreach (['username', 'homedir', 'shell'] as $property) {
+                $value = $result->get($property);
+                if (!$value instanceof JsString) {
+                    continue;
+                }
+                $encoded = $engine->getInterpreter()->callFunction($from, $buffer, [$value]);
+                if ($encoding !== 'buffer' && $encoded instanceof JsObject) {
+                    $toString = $encoded->get('toString');
+                    if ($toString instanceof JsFunction) {
+                        $encoded = $engine->getInterpreter()->callFunction($toString, $encoded, [new JsString($encoding)]);
+                    }
+                }
+                $result->set($property, $encoded);
+            }
+            return $result;
+        }));
+        return $module;
+    }
+
+    /** @return array{signals: array, errno: array} */
+    private static function constants(): array
+    {
+        $signals = [];
+        $errno = [];
+        foreach (get_defined_constants() as $name => $value) {
+            if (!is_int($value)) {
+                continue;
+            }
+            if (preg_match('/^SIG[A-Z0-9]+$/', $name) === 1) {
+                $signals[$name] = $value;
+            } elseif (str_starts_with($name, 'SOCKET_E')) {
+                $errno[substr($name, 7)] = $value;
+            }
+        }
+        return ['signals' => $signals, 'errno' => $errno];
+    }
+
+    private static function processProperty(Engine $engine, string $name): string
+    {
+        $process = $engine->getGlobalEnv()->get('process');
+        return $process instanceof JsObject ? $process->get($name)->toJsString() : '';
+    }
+
+    private static function environment(Engine $engine, string $name): ?string
+    {
+        $process = $engine->getGlobalEnv()->get('process');
+        $environment = $process instanceof JsObject ? $process->get('env') : JsUndefined::instance();
+        $value = $environment instanceof JsObject ? $environment->get($name) : JsUndefined::instance();
+        return $value instanceof JsUndefined ? null : $value->toJsString();
+    }
+
+    private static function homeDirectory(Engine $engine): string
+    {
+        $environment = self::environment($engine, PHP_OS_FAMILY === 'Windows' ? 'USERPROFILE' : 'HOME');
+        if ($environment !== null && $environment !== '') {
+            return $environment;
+        }
+        if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) {
+            $user = posix_getpwuid(posix_geteuid());
+            if (is_array($user)) {
+                return (string) $user['dir'];
+            }
+        }
+        throw new TypeError('Could not determine the home directory on this PHP host.');
+    }
+
+    private static function temporaryDirectory(Engine $engine): string
+    {
+        $keys = PHP_OS_FAMILY === 'Windows' ? ['TEMP', 'TMP'] : ['TMPDIR', 'TMP', 'TEMP'];
+        foreach ($keys as $key) {
+            $value = self::environment($engine, $key);
+            if ($value !== null && $value !== '') {
+                return strlen($value) > 1 ? rtrim($value, '/\\') : $value;
+            }
+        }
+        return PHP_OS_FAMILY === 'Windows' ? sys_get_temp_dir() : '/tmp';
+    }
+
+    /** @return array{uid: int, gid: int, username: string, homedir: string, shell: ?string} */
+    private static function userInfo(Engine $engine): array
+    {
+        if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) {
+            $user = posix_getpwuid(posix_geteuid());
+            if (is_array($user)) {
+                return [
+                    'uid' => (int) $user['uid'],
+                    'gid' => (int) $user['gid'],
+                    'username' => (string) $user['name'],
+                    'homedir' => (string) $user['dir'],
+                    'shell' => (string) $user['shell'],
+                ];
+            }
+        }
+        if (PHP_OS_FAMILY === 'Windows') {
+            return [
+                'uid' => -1,
+                'gid' => -1,
+                'username' => self::environment($engine, 'USERNAME') ?? get_current_user(),
+                'homedir' => self::homeDirectory($engine),
+                'shell' => null,
+            ];
+        }
+        throw new TypeError('Could not determine the current user on this PHP host.');
+    }
+
+    private static function memory(string $field, ?string $fallback = null): int
+    {
+        $data = is_readable('/proc/meminfo') ? file_get_contents('/proc/meminfo') : false;
+        if ($data !== false) {
+            foreach ([$field, $fallback] as $key) {
+                if ($key !== null && preg_match('/^' . $key . ':\s+(\d+)\s+kB$/m', $data, $match) === 1) {
+                    return (int) $match[1] * 1024;
+                }
+            }
+        }
+        throw new TypeError('Host memory information is unavailable without an operating-system PHP binding.');
+    }
+
+    private static function uptime(): float
+    {
+        $data = is_readable('/proc/uptime') ? file_get_contents('/proc/uptime') : false;
+        if ($data !== false && preg_match('/^([0-9.]+)/', $data, $match) === 1) {
+            return floor((float) $match[1]);
+        }
+        throw new TypeError('Host uptime is unavailable without an operating-system PHP binding.');
+    }
+}
diff --git a/src/Node/PathBindings.php b/src/Node/PathBindings.php
new file mode 100644
index 00000000..a994d6ab
--- /dev/null
+++ b/src/Node/PathBindings.php
@@ -0,0 +1,57 @@
+set('normalizeString', JsFunction::fromCallable(
+            'normalizeString',
+            static function (JsValue $this_, array $args): JsValue {
+                $path = $args[0] ?? JsUndefined::instance();
+                $separator = $args[2] ?? JsUndefined::instance();
+                if (!$path instanceof JsString || !$separator instanceof JsString) {
+                    throw new TypeError('Path normalization requires string arguments.');
+                }
+                if ($separator->value !== '/' && $separator->value !== '\\') {
+                    throw new TypeError('Invalid path separator.');
+                }
+                $allowAboveRoot = ($args[1] ?? JsUndefined::instance())->toBoolean();
+                // Separators and dot segments are ASCII. Splitting their bytes
+                // preserves every other UTF-16 value, including lone surrogates.
+                $input = $separator->value === '\\' ? str_replace('\\', '/', $path->value) : $path->value;
+                $segments = [];
+                foreach (explode('/', $input) as $segment) {
+                    if ($segment === '' || $segment === '.') {
+                        continue;
+                    }
+                    if ($segment === '..') {
+                        if ($segments !== [] && $segments[count($segments) - 1] !== '..') {
+                            array_pop($segments);
+                        } elseif ($allowAboveRoot) {
+                            $segments[] = '..';
+                        }
+                    } else {
+                        $segments[] = $segment;
+                    }
+                }
+                return new JsString(implode($separator->value, $segments));
+            },
+            3,
+        ));
+        return $host;
+    }
+}
diff --git a/src/Node/SocketState.php b/src/Node/SocketState.php
new file mode 100644
index 00000000..dc98ea4b
--- /dev/null
+++ b/src/Node/SocketState.php
@@ -0,0 +1,43 @@
+ */
+    public array $tlsFiles = [];
+    /** @var list */
+    public array $tlsAuthorities = [];
+
+    /**
+     * @param resource $stream
+     * @param array{0: array, 1: array} $context
+     */
+    public function __construct(
+        public readonly int $id,
+        public mixed $stream,
+        public readonly bool $server,
+        public ?JsFunction $callback,
+        public readonly array $context,
+    ) {
+    }
+}
diff --git a/src/Node/VmBindings.php b/src/Node/VmBindings.php
new file mode 100644
index 00000000..35ab4782
--- /dev/null
+++ b/src/Node/VmBindings.php
@@ -0,0 +1,172 @@
+> */
+    private \WeakMap $contexts;
+    private readonly string $contextSlot;
+    private static int $contextSequence = 0;
+
+    private function __construct(private readonly Engine $owner)
+    {
+        $this->contexts = new \WeakMap();
+        $this->contextSlot = '[[NodeVmContext:' . ++self::$contextSequence . ']]';
+    }
+
+    /** Install vm host functions without evaluating scripts or starting external runtimes. */
+    public static function create(Engine $engine, NodeRuntime $runtime): JsObject
+    {
+        $bindings = new self($engine);
+        $runtime->onClose(static function () use ($bindings): void {
+            foreach ($bindings->contexts as $sandbox => $reference) {
+                $sandbox->setInternalProperty($bindings->contextSlot, null);
+            }
+            $bindings->contexts = new \WeakMap();
+        });
+        $host = new JsObject();
+        self::method($host, 'createContext', static function (array $args) use ($bindings): JsValue {
+            return $bindings->context(self::object($args[0]), self::object($args[1]));
+        });
+        self::method($host, 'isContext', static fn (array $args): JsValue => new JsBoolean(
+            ($args[0] ?? null) instanceof JsObject && isset($bindings->contexts[$args[0]]),
+        ));
+        self::method($host, 'compile', static fn (array $args): JsValue => $bindings->compile($args[0]->toJsString(), self::object($args[1])));
+        self::method($host, 'run', static fn (array $args): JsValue => $bindings->run(
+            self::object($args[0]),
+            $args[1] instanceof JsObject ? $args[1] : null,
+            self::object($args[2]),
+        ));
+        return $host;
+    }
+
+    private function context(JsObject $sandbox, JsObject $options): JsObject
+    {
+        if (isset($this->contexts[$sandbox])) {
+            return $sandbox;
+        }
+        $state = VmRealmState::capture();
+        try {
+            // Materialize intrinsics before linking the sandbox so lazy installation cannot leak globals into it.
+            $engine = new Engine(eager: true);
+            $engine->getInterpreter()->inheritLimits($this->owner->getInterpreter());
+            $env = $engine->getGlobalEnv();
+            $intrinsics = self::object($env->get('globalThis'));
+            $global = new VmGlobalObject($sandbox, $intrinsics);
+            $env->defineVar('this', $global);
+            $env->defineVar('globalThis', $global);
+            $intrinsics->set('globalThis', $global);
+            $intrinsics->set('self', $global);
+            $env->linkGlobalObject($global);
+            $context = new VmContext($engine, $global, $options, JsPromise::captureIntrinsicState());
+            // PHP WeakMap values are strong references, not ephemerons. The
+            // sandbox owns its realm so the registry cannot retain its key.
+            $sandbox->setInternalProperty($this->contextSlot, $context);
+            $this->contexts[$sandbox] = \WeakReference::create($context);
+        } finally {
+            $state->restore();
+        }
+        return $sandbox;
+    }
+
+    private function compile(string $source, JsObject $options): JsObject
+    {
+        $lineOffset = $options->get('lineOffset');
+        $columnOffset = $options->get('columnOffset');
+        $source = str_repeat("\n", $lineOffset instanceof JsUndefined ? 0 : max(0, (int) $lineOffset->toNumber()))
+            . str_repeat(' ', $columnOffset instanceof JsUndefined ? 0 : max(0, (int) $columnOffset->toNumber())) . $source;
+        $parser = new Parser($source);
+        $script = new JsObject();
+        $script->setInternalProperty('[[VmProgram]]', $parser->parse());
+        $filename = $options->get('filename');
+        $script->setInternalProperty('[[VmFilename]]', $filename instanceof JsUndefined ? 'evalmachine.' : $filename->toJsString());
+        return $script;
+    }
+
+    private function run(JsObject $script, ?JsObject $sandbox, JsObject $options): JsValue
+    {
+        $program = $script->getInternalProperty('[[VmProgram]]');
+        if (!$program instanceof Program) {
+            throw new TypeError('Invalid compiled vm.Script.');
+        }
+        if ($sandbox !== null && !isset($this->contexts[$sandbox])) {
+            throw new TypeError('The contextifiedObject argument must be a vm.Context.');
+        }
+        $entry = $sandbox === null ? null : $this->contexts[$sandbox]->get();
+        $engine = $entry->engine ?? $this->owner;
+        $interpreter = $engine->getInterpreter();
+        $caller = Engine::getCurrentInterpreter() ?? $this->owner->getInterpreter();
+        $state = VmRealmState::capture();
+        $strict = $interpreter->isStrictMode();
+        $evalContext = $interpreter->isEvalContext();
+        $timeout = $options->get('timeout');
+        if ($engine !== $this->owner) {
+            $interpreter->inheritLimits($caller);
+        }
+        $hostBudget = $interpreter->executionBudgetState();
+        $timed = !$timeout instanceof JsUndefined;
+        if ($timed) {
+            $interpreter->tightenExecutionBudget($timeout->toNumber() / 1000);
+        }
+        VmRealmState::activate($engine);
+        if ($entry !== null) {
+            JsPromise::restoreIntrinsicState($entry->promiseIntrinsics);
+        }
+        Engine::pushSourceURL((string) $script->getInternalProperty('[[VmFilename]]'));
+        try {
+            $interpreter->setStrictMode(false);
+            $interpreter->setEvalContext(false);
+            $result = $interpreter->execute($program);
+            $value = new JsObject();
+            $value->set('value', $result);
+            return $value;
+        } catch (BudgetExceeded $error) {
+            if (!$timed || $hostBudget !== null && hrtime(true) >= $hostBudget->deadline) {
+                throw $error;
+            }
+            $failure = new JsObject();
+            $failure->set('timeout', new JsBoolean(true));
+            return $failure;
+        } finally {
+            Engine::popSourceURL();
+            $interpreter->setStrictMode($strict);
+            $interpreter->setEvalContext($evalContext);
+            $interpreter->restoreExecutionBudgetState($hostBudget);
+            if ($engine !== $this->owner) {
+                $interpreter->inheritLimits($caller);
+            }
+            $state->restore();
+        }
+    }
+
+    private static function object(JsValue $value): JsObject
+    {
+        if (!$value instanceof JsObject) {
+            throw new TypeError('Expected an object.');
+        }
+        return $value;
+    }
+
+    /** @param \Closure(list): JsValue $callback */
+    private static function method(JsObject $target, string $name, \Closure $callback): void
+    {
+        $target->set($name, JsFunction::fromCallable($name, static fn (JsValue $this_, array $args): JsValue => $callback($args)));
+    }
+}
diff --git a/src/Node/VmContext.php b/src/Node/VmContext.php
new file mode 100644
index 00000000..92f7e65f
--- /dev/null
+++ b/src/Node/VmContext.php
@@ -0,0 +1,22 @@
+getPrototype());
+    }
+
+    public function get(string $name): JsValue
+    {
+        return $this->getWithValueReceiver($name, $this);
+    }
+
+    public function getWithValueReceiver(string $name, JsValue $receiver): JsValue
+    {
+        if ($this->sandbox->has($name)) {
+            return $this->sandbox->getWithValueReceiver($name, $receiver);
+        }
+        return $this->intrinsics->getWithValueReceiver($name, $receiver);
+    }
+
+    public function has(string $name): bool
+    {
+        return $this->sandbox->has($name) || $this->intrinsics->has($name);
+    }
+
+    public function hasOwnProperty(string $name): bool
+    {
+        return $this->sandbox->hasOwnProperty($name) || $this->intrinsics->hasOwnProperty($name);
+    }
+
+    public function internalSet(string $name, JsValue $value, JsObject $receiver): bool
+    {
+        if (!$this->sandbox->has($name)) {
+            $descriptor = $this->intrinsics->getOwnPropertyDescriptor($name);
+            if ($descriptor !== null && $descriptor->writable === false && !$descriptor->isAccessorDescriptor()) {
+                return false;
+            }
+        }
+        return $this->sandbox->internalSet($name, $value, $receiver === $this ? $this->sandbox : $receiver);
+    }
+
+    public function defineOwnProperty(string $name, PropertyDescriptor $descriptor): bool
+    {
+        return $this->sandbox->defineOwnProperty($name, $descriptor);
+    }
+
+    public function getOwnPropertyDescriptor(string $name): ?PropertyDescriptor
+    {
+        return $this->sandbox->getOwnPropertyDescriptor($name) ?? $this->intrinsics->getOwnPropertyDescriptor($name);
+    }
+
+    public function getOwnPropertyDescriptorRaw(string $name): ?PropertyDescriptor
+    {
+        return $this->getOwnPropertyDescriptor($name);
+    }
+
+    public function delete(string $name, bool $strict = false): bool
+    {
+        if ($this->sandbox->hasOwnProperty($name)) {
+            return $this->sandbox->delete($name, $strict);
+        }
+        return $this->intrinsics->delete($name, $strict);
+    }
+
+    /** @return list */
+    public function getOwnPropertyNames(): array
+    {
+        return array_values(array_unique(array_merge($this->sandbox->getOwnPropertyNames(), $this->intrinsics->getOwnPropertyNames())));
+    }
+
+    /** @return list */
+    public function ownKeys(): array
+    {
+        return $this->getOwnPropertyNames();
+    }
+
+    /** @return list */
+    public function getOwnEnumerableKeys(): array
+    {
+        return array_values(array_filter(
+            $this->getOwnPropertyNames(),
+            fn (string $name): bool => $this->getOwnPropertyDescriptor($name)?->enumerable === true,
+        ));
+    }
+
+    /** @return list */
+    public function ordinaryOwnPropertyKeys(): array
+    {
+        $keys = array_map(static fn (string $name): JsValue => new JsString($name), $this->getOwnPropertyNames());
+        foreach ($this->getOwnSymbolsWithDescriptors() as [$symbol]) {
+            $keys[] = $symbol;
+        }
+        return $keys;
+    }
+
+    public function getBySymbol(JsSymbol $symbol): JsValue
+    {
+        return $this->getBySymbolWithReceiver($symbol, $this);
+    }
+
+    public function getBySymbolWithReceiver(JsSymbol $symbol, JsValue $receiver): JsValue
+    {
+        return $this->sandbox->hasBySymbol($symbol)
+            ? $this->sandbox->getBySymbolWithReceiver($symbol, $receiver)
+            : $this->intrinsics->getBySymbolWithReceiver($symbol, $receiver);
+    }
+
+    public function hasBySymbol(JsSymbol $symbol): bool
+    {
+        return $this->sandbox->hasBySymbol($symbol) || $this->intrinsics->hasBySymbol($symbol);
+    }
+
+    public function internalSetBySymbol(JsSymbol $symbol, JsValue $value, JsObject $receiver): bool
+    {
+        return $this->sandbox->internalSetBySymbol($symbol, $value, $receiver === $this ? $this->sandbox : $receiver);
+    }
+
+    public function definePropertyBySymbol(JsSymbol $symbol, PropertyDescriptor $descriptor): bool
+    {
+        return $this->sandbox->definePropertyBySymbol($symbol, $descriptor);
+    }
+
+    public function getPropertyDescriptorBySymbol(JsSymbol $symbol): ?PropertyDescriptor
+    {
+        return $this->sandbox->getPropertyDescriptorBySymbol($symbol) ?? $this->intrinsics->getPropertyDescriptorBySymbol($symbol);
+    }
+
+    public function deleteBySymbol(JsSymbol $symbol): bool
+    {
+        return $this->sandbox->hasBySymbol($symbol)
+            ? $this->sandbox->deleteBySymbol($symbol) : $this->intrinsics->deleteBySymbol($symbol);
+    }
+
+    /** @return list */
+    public function getOwnSymbolsWithDescriptors(): array
+    {
+        $entries = [];
+        $symbols = array_merge($this->intrinsics->getOwnSymbolsWithDescriptors(), $this->sandbox->getOwnSymbolsWithDescriptors());
+        foreach ($symbols as [$symbol, $descriptor]) {
+            $entries[$symbol->getId()] = [$symbol, $descriptor];
+        }
+        return array_values($entries);
+    }
+}
diff --git a/src/Node/VmRealmState.php b/src/Node/VmRealmState.php
new file mode 100644
index 00000000..e5fbdf25
--- /dev/null
+++ b/src/Node/VmRealmState.php
@@ -0,0 +1,101 @@
+, 1: array} */
+    private array $context;
+
+    private ?Interpreter $interpreter;
+
+    private ?Interpreter $functionInterpreter;
+
+    private ?\Closure $functionCallback;
+
+    private ?\Closure $postDrain;
+
+    private ?\Closure $turnBoundary;
+
+    /** @var array{?JsObject, ?JsValue} */
+    private array $promiseIntrinsics;
+
+    private function __construct()
+    {
+        $this->interpreter = Engine::getCurrentInterpreter();
+        $this->functionInterpreter = JsFunction::getInterpreterInstance();
+        $this->functionCallback = JsFunction::getInterpreterCallback();
+        $this->postDrain = JsPromise::getPostDrainHook();
+        $this->turnBoundary = JsPromise::getTurnBoundaryHook();
+        $this->promiseIntrinsics = JsPromise::captureIntrinsicState();
+        $this->context = AsyncContextStorage::active()->snapshot();
+    }
+
+    /** Capture the active caller without clearing queued work. */
+    public static function capture(): self
+    {
+        return new self();
+    }
+
+    /** Select realm-owned intrinsic defaults for native value constructors. */
+    public static function activate(Engine $engine): void
+    {
+        $interpreter = $engine->getInterpreter();
+        Engine::setCurrentInterpreter($interpreter);
+        JsFunction::setInterpreterInstance($interpreter);
+        JsFunction::setInterpreterCallback($interpreter->callFunction(...));
+        $env = $engine->getGlobalEnv();
+        $setters = [
+            'Object' => JsObject::setGlobalPrototype(...), 'Array' => JsArray::setGlobalPrototype(...),
+            'String' => JsString::setStringPrototype(...), 'Number' => JsNumber::setNumberPrototype(...),
+            'Boolean' => JsBoolean::setBooleanPrototype(...), 'Symbol' => JsSymbol::setSymbolPrototype(...),
+            'BigInt' => JsBigInt::setPrototype(...), 'ArrayBuffer' => JsArrayBuffer::setDefaultPrototype(...),
+            'Promise' => JsPromise::setPromisePrototype(...),
+        ];
+        foreach ($setters as $name => $setter) {
+            $constructor = $env->get($name);
+            $prototype = $constructor instanceof JsObject ? $constructor->get('prototype') : null;
+            if ($prototype instanceof JsObject) {
+                $setter($prototype);
+            }
+        }
+    }
+
+    /** Restore the outer event loop, async context, interpreter, and intrinsic defaults. */
+    public function restore(): void
+    {
+        $realm = $this->interpreter?->getRealm();
+        if ($realm !== null) {
+            self::activate($realm);
+        }
+        Engine::setCurrentInterpreter($this->interpreter);
+        if ($this->functionInterpreter !== null) {
+            JsFunction::setInterpreterInstance($this->functionInterpreter);
+        }
+        if ($this->functionCallback !== null) {
+            JsFunction::setInterpreterCallback($this->functionCallback);
+        }
+        JsPromise::setPostDrainHook($this->postDrain);
+        JsPromise::setTurnBoundaryHook($this->turnBoundary);
+        JsPromise::restoreIntrinsicState($this->promiseIntrinsics);
+        AsyncContextStorage::active()->restore($this->context);
+    }
+}
diff --git a/src/Node/ZlibBindings.php b/src/Node/ZlibBindings.php
new file mode 100644
index 00000000..eb488d94
--- /dev/null
+++ b/src/Node/ZlibBindings.php
@@ -0,0 +1,195 @@
+, context: \InflateContext|\DeflateContext|null, pending: string, consumed: int, ended: bool}> */
+    private array $contexts = [];
+
+    private int $nextId = 1;
+
+    private function __construct(private readonly Engine $engine)
+    {
+    }
+
+    /** Create the host codec bridge and register cleanup for live contexts. */
+    public static function create(Engine $engine, NodeRuntime $runtime): JsObject
+    {
+        $bindings = new self($engine);
+        $runtime->onClose(static function () use ($bindings): void {
+            $bindings->contexts = [];
+        });
+        $host = new JsObject();
+        $host->set('call', JsFunction::fromCallable('call', static function (JsValue $this_, array $args) use ($bindings): JsValue {
+            $operation = array_shift($args)?->toJsString() ?? '';
+            $result = new JsObject();
+            try {
+                $result->set('value', $bindings->dispatch($operation, $args));
+            } catch (\RuntimeException $error) {
+                $result->set('error', PhpToJs::convert([
+                    'message' => $error->getMessage(),
+                    'errno' => $error->getCode(),
+                    'code' => match ($error->getCode()) {
+                        2 => 'Z_NEED_DICT', -2 => 'Z_STREAM_ERROR', -4 => 'Z_MEM_ERROR',
+                        -5 => 'Z_BUF_ERROR', default => 'Z_DATA_ERROR',
+                    },
+                ]));
+            }
+            return $result;
+        }));
+        return $host;
+    }
+
+    /** @param list $args */
+    private function dispatch(string $operation, array $args): JsValue
+    {
+        if ($operation === 'create') {
+            $mode = $args[0]->toJsString();
+            $config = $args[1];
+            $options = [];
+            if ($config instanceof JsObject) {
+                foreach (['level', 'windowBits' => 'window', 'memLevel' => 'memory', 'strategy'] as $key => $name) {
+                    $value = $config->get(is_string($key) ? $key : $name);
+                    if (!$value instanceof JsUndefined) {
+                        $options[$name] = (int) $value->toNumber();
+                    }
+                }
+                $dictionary = $config->get('dictionary');
+                if ($dictionary instanceof JsTypedArray) {
+                    $options['dictionary'] = self::readBytes($dictionary);
+                }
+            }
+            $id = $this->nextId++;
+            $this->contexts[$id] = [
+                'mode' => $mode, 'options' => $options, 'context' => $this->initialize($mode, $options),
+                'pending' => '', 'consumed' => 0, 'ended' => false,
+            ];
+            return JsNumber::of($id);
+        }
+        $id = (int) $args[0]->toNumber();
+        if ($operation === 'close') {
+            unset($this->contexts[$id]);
+            return JsUndefined::instance();
+        }
+        if (!isset($this->contexts[$id])) {
+            throw new \RuntimeException('zlib binding closed', -2);
+        }
+        $entry = &$this->contexts[$id];
+        if ($operation === 'reset') {
+            $entry['context'] = $this->initialize($entry['mode'], $entry['options']);
+            $entry['pending'] = '';
+            $entry['consumed'] = 0;
+            $entry['ended'] = false;
+            return JsUndefined::instance();
+        }
+        if ($operation !== 'process' || !$args[1] instanceof JsTypedArray) {
+            throw new \RuntimeException('Invalid zlib operation', -2);
+        }
+        $bytes = $entry['pending'] . self::readBytes($args[1]);
+        $entry['pending'] = '';
+        $flush = (int) $args[2]->toNumber();
+        if ($entry['context'] === null) {
+            if (strlen($bytes) < 2 && $flush !== ZLIB_FINISH) {
+                $entry['pending'] = $bytes;
+                return $this->output('', $entry['consumed']);
+            }
+            $entry['mode'] = str_starts_with($bytes, "\x1f\x8b") ? 'Gunzip' : 'Inflate';
+            $entry['context'] = $this->initialize($entry['mode'], $entry['options']);
+        }
+        $context = $entry['context'];
+        if ($context instanceof \DeflateContext) {
+            $output = @deflate_add($context, $bytes, $flush);
+            if ($output === false) {
+                throw new \RuntimeException('stream error', -2);
+            }
+            $entry['consumed'] += strlen($bytes);
+            return $this->output($output, $entry['consumed']);
+        }
+        if (!$context instanceof \InflateContext) {
+            throw new \RuntimeException('stream error', -2);
+        }
+        $output = '';
+        do {
+            if ($entry['ended']) {
+                if ($entry['mode'] !== 'Gunzip' || $bytes === '' || $bytes[0] === "\0") {
+                    break;
+                }
+                $context = $entry['context'] = $this->initialize('Gunzip', $entry['options']);
+                if (!$context instanceof \InflateContext) {
+                    throw new \RuntimeException('stream error', -2);
+                }
+                $entry['ended'] = false;
+            }
+            $before = inflate_get_read_len($context);
+            $chunk = @inflate_add($context, $bytes, $flush);
+            $read = inflate_get_read_len($context) - $before;
+            $status = inflate_get_status($context);
+            if ($chunk === false || $status < 0 && $status !== ZLIB_BUF_ERROR) {
+                $message = $status === ZLIB_NEED_DICT ? 'Missing dictionary' : 'incorrect header check';
+                throw new \RuntimeException($message, $status === ZLIB_NEED_DICT ? 2 : -3);
+            }
+            $output .= $chunk;
+            $entry['consumed'] += $read;
+            $entry['ended'] = $status === ZLIB_STREAM_END;
+            $bytes = substr($bytes, $read);
+        } while ($entry['ended'] && $entry['mode'] === 'Gunzip' && $bytes !== '');
+        if ($flush === ZLIB_FINISH && !$entry['ended']) {
+            throw new \RuntimeException('unexpected end of file', -5);
+        }
+        return $this->output($output, $entry['consumed']);
+    }
+
+    /** @param array $options */
+    private function initialize(string $mode, array $options): \InflateContext|\DeflateContext|null
+    {
+        if ($mode === 'Unzip') {
+            return null;
+        }
+        $encoding = match ($mode) {
+            'Gzip', 'Gunzip' => ZLIB_ENCODING_GZIP,
+            'DeflateRaw', 'InflateRaw' => ZLIB_ENCODING_RAW,
+            default => ZLIB_ENCODING_DEFLATE,
+        };
+        $compress = in_array($mode, ['Deflate', 'DeflateRaw', 'Gzip'], true);
+        try {
+            $context = $compress ? @deflate_init($encoding, $options) : @inflate_init($encoding, $options);
+        } catch (\ValueError $error) {
+            throw new \RuntimeException($error->getMessage(), -2, $error);
+        }
+        if ($context === false) {
+            throw new \RuntimeException('Failed to initialize zlib context', -2);
+        }
+        return $context;
+    }
+
+    private static function readBytes(JsTypedArray $view): string
+    {
+        $view->validateNotDetached();
+        return $view->getBuffer()->readBytes($view->getByteOffset(), $view->getLength() * $view->getBytesPerElement());
+    }
+
+    private function output(string $bytes, int $consumed): JsObject
+    {
+        $constructor = $this->engine->getGlobalEnv()->get('Uint8Array');
+        $prototype = $constructor instanceof JsObject ? $constructor->get('prototype') : null;
+        $view = JsTypedArray::fromLength('Uint8Array', strlen($bytes), $prototype instanceof JsObject ? $prototype : null);
+        $view->getBuffer()->setData($bytes);
+        $result = new JsObject();
+        $result->set('bytes', $view);
+        $result->set('consumed', JsNumber::of($consumed));
+        return $result;
+    }
+}
diff --git a/src/Node/child-runtime.php b/src/Node/child-runtime.php
new file mode 100644
index 00000000..fd7598fe
--- /dev/null
+++ b/src/Node/child-runtime.php
@@ -0,0 +1,24 @@
+ */
     private array $lines = [];
+    /** @var list */
+    private array $functions = [];
     private int $depth = 0;
 
     public function __construct(
@@ -45,19 +47,21 @@ public function __construct(
     }
 
     /** Push a new frame onto the call stack. Throws if the stack depth limit is exceeded. */
-    public function push(string $name, int $line): void
+    public function push(string $name, int $line, ?\Phasis\Value\JsFunction $function = null): void
     {
         if ($this->depth >= $this->maxDepth) {
             throw new InternalError('Maximum call stack size exceeded');
         }
         $this->names[$this->depth] = $name;
         $this->lines[$this->depth] = $line;
+        $this->functions[$this->depth] = $function;
         $this->depth++;
     }
 
     public function pop(): void
     {
         $this->depth--;
+        unset($this->functions[$this->depth]);
     }
 
     public function depth(): int
@@ -70,7 +74,7 @@ public function getFrames(): array
     {
         $result = [];
         for ($i = 0; $i < $this->depth; $i++) {
-            $result[] = new CallFrame($this->names[$i], $this->lines[$i]);
+            $result[] = new CallFrame($this->names[$i], $this->lines[$i], $this->functions[$i]);
         }
         return $result;
     }
diff --git a/src/Runtime/Environment.php b/src/Runtime/Environment.php
index fccd0c45..8f3e29c4 100644
--- a/src/Runtime/Environment.php
+++ b/src/Runtime/Environment.php
@@ -27,6 +27,9 @@ class Environment
     /** @var array */
     private array $bindings = [];
 
+    /** @var array Host intrinsics retained independently of mutable global bindings. */
+    private array $intrinsics = [];
+
     /** @var array Track which bindings are const. */
     private array $constants = [];
 
@@ -128,6 +131,24 @@ public function getLinkedObject(): ?\Phasis\Value\JsObject
         return $this->linkedObject;
     }
 
+    /** Read an installed intrinsic during lazy realization without reentering its global accessor. */
+    public function getInstalledBinding(string $name): ?JsValue
+    {
+        return $this->bindings[$name] ?? null;
+    }
+
+    /** Internal: retain a realm intrinsic when its built-in module is installed. */
+    public function setIntrinsic(string $name, JsValue $value): void
+    {
+        $this->intrinsics[$name] = $value;
+    }
+
+    /** Internal: read a realm intrinsic without invoking a replacement global. */
+    public function getIntrinsic(string $name): ?JsValue
+    {
+        return $this->intrinsics[$name] ?? null;
+    }
+
     /** Whether this scope or any parent is a `with` (Object Environment) scope. */
     public function isUnderWithScope(): bool
     {
@@ -144,10 +165,20 @@ public function isUnderWithScope(): bool
     /** Check whether a binding exists in this scope only (not parents). */
     public function hasOwnBinding(string $name): bool
     {
+        if ($this->isGlobalObjectBinding($name)) {
+            return $this->linkedObject->has($name);
+        }
         return array_key_exists($name, $this->bindings)
             || array_key_exists($name, $this->importBindings);
     }
 
+    private function isGlobalObjectBinding(string $name): bool
+    {
+        return $this->linkedObject !== null && $this->parent === null
+            && $name !== 'this' && !self::isInternalPrototypeName($name)
+            && !isset($this->constants[$name]) && !isset($this->lexical[$name]);
+    }
+
     /**
      * Pre-computed at construction: whether this env or any ancestor has
      * a `with`-object attached. Each child inherits the parent's flag;
@@ -423,6 +454,9 @@ public function getAtDepth(string $name, int $depth): ?JsValue
         if ($cur === null) {
             return null;
         }
+        if ($cur->isGlobalObjectBinding($name)) {
+            return null;
+        }
         if (
             isset($cur->bindings[$name])
             && !isset($cur->tdz[$name])
@@ -461,11 +495,7 @@ public function findBindingDepth(string $name): ?array
                 // Linked-object globals are dynamic via globalThis writes;
                 // do not memoise their depth.
                 if (
-                    $cur->linkedObject !== null
-                    && $cur->parent === null
-                    && !isset($cur->constants[$name])
-                    && !isset($cur->lexical[$name])
-                    && $cur->linkedObject->hasOwnProperty($name)
+                    $cur->isGlobalObjectBinding($name)
                 ) {
                     return null;
                 }
@@ -565,12 +595,11 @@ public function get(
             // bindings whose linked property exists (e.g. mutated via
             // `this.x = ...`).
             if (
-                $this->linkedObject !== null
-                && $this->parent === null
-                && !isset($this->constants[$name])
-                && !isset($this->lexical[$name])
-                && $this->linkedObject->hasOwnProperty($name)
+                $this->isGlobalObjectBinding($name)
             ) {
+                if (!$this->linkedObject->has($name)) {
+                    throw new ReferenceError("{$name} is not defined");
+                }
                 return $this->linkedObject->get($name);
             }
 
@@ -703,6 +732,17 @@ public function set(string $name, JsValue $value, bool $strict = true): void
                 throw new TypeError('Assignment to constant variable');
             }
 
+            if ($this->isGlobalObjectBinding($name)) {
+                if ($strict && !$this->linkedObject->has($name)) {
+                    throw new ReferenceError("{$name} is not defined");
+                }
+                $this->linkedObject->set($name, $value, $strict);
+                if ($this->linkedObject->hasOwnProperty($name)) {
+                    $this->bindings[$name] = $value;
+                }
+                return;
+            }
+
             // Check global object writability before updating the binding.
             // Per spec, non-writable global properties (NaN, Infinity, undefined)
             // silently fail in sloppy mode and throw TypeError in strict mode.
@@ -772,6 +812,9 @@ public function set(string $name, JsValue $value, bool $strict = true): void
     /** Check whether a binding exists anywhere in the scope chain. */
     public function has(string $name): bool
     {
+        if ($this->isGlobalObjectBinding($name)) {
+            return $this->linkedObject->has($name);
+        }
         // "with" object environment record: delegate to the binding object using [[Has]].
         if ($this->withObject !== null) {
             if ($this->withObject->has($name) && !$this->isUnscopable($name)) {
@@ -826,6 +869,14 @@ public function deleteBinding(string $name): bool
         }
 
         if (array_key_exists($name, $this->bindings)) {
+            if ($this->isGlobalObjectBinding($name)) {
+                if (!$this->linkedObject->delete($name)) {
+                    return false;
+                }
+                unset($this->bindings[$name], $this->deletable[$name]);
+                self::$globalBindingsVersion++;
+                return true;
+            }
             if (isset($this->deletable[$name])) {
                 unset($this->bindings[$name], $this->deletable[$name]);
                 // Mirror the delete to the linked global object, if any, so
diff --git a/src/Runtime/EventLoop.php b/src/Runtime/EventLoop.php
index c085c902..4d9f9532 100644
--- a/src/Runtime/EventLoop.php
+++ b/src/Runtime/EventLoop.php
@@ -45,6 +45,9 @@ final class EventLoop
     /** @var array */
     private array $tasks = [];
 
+    /** @var array */
+    private array $immediates = [];
+
     private int $nextId = 1;
 
     /**
@@ -58,6 +61,80 @@ final class EventLoop
     /** Whether timers fire; while off, setTimeout and setInterval still return ids but never run. */
     private bool $timersEnabled = true;
 
+    /** @var ?\Closure(int): bool */
+    private ?\Closure $ioPoll = null;
+
+    /** @var ?\Closure(): bool */
+    private ?\Closure $ioReferences = null;
+
+    /** @var array */
+    private array $ioDrivers = [];
+
+    private bool $realTime = false;
+
+    /** Install the realm's nonblocking I/O driver. The timeout is in milliseconds. */
+    public function setIoDriver(?\Closure $poll, ?\Closure $hasReferences): void
+    {
+        if ($poll === null || $hasReferences === null) {
+            $this->removeIoDriver('default');
+        } else {
+            $this->addIoDriver('default', $poll, $hasReferences);
+        }
+    }
+
+    /**
+     * Register a host resource source alongside sockets and other drivers.
+     * @param \Closure(int): bool $poll
+     * @param \Closure(): bool $hasReferences
+     */
+    public function addIoDriver(string $name, \Closure $poll, \Closure $hasReferences): void
+    {
+        $this->ioDrivers[$name] = [$poll, $hasReferences];
+        $this->ioReferences = function (): bool {
+            foreach ($this->ioDrivers as [, $hasReferences]) {
+                if ($hasReferences()) {
+                    return true;
+                }
+            }
+            return false;
+        };
+        $this->ioPoll = function (int $timeout): bool {
+            $progress = false;
+            foreach ($this->ioDrivers as [$poll]) {
+                $progress = $poll(0) || $progress;
+            }
+            if (!$progress && $timeout > 0) {
+                $first = array_key_first($this->ioDrivers);
+                if ($first !== null) {
+                    $progress = ($this->ioDrivers[$first][0])($timeout);
+                    foreach ($this->ioDrivers as $key => [$poll]) {
+                        if ($key !== $first) {
+                            $progress = $poll(0) || $progress;
+                        }
+                    }
+                }
+            }
+            return $progress;
+        };
+    }
+
+    /** Unregister a driver once its owning host resource group closes. */
+    public function removeIoDriver(string $name): void
+    {
+        unset($this->ioDrivers[$name]);
+        if ($this->ioDrivers === []) {
+            $this->ioPoll = null;
+            $this->ioReferences = null;
+        }
+    }
+
+    /** Node timers follow elapsed host time; the default ECMAScript runner uses virtual time. */
+    public function setRealTime(bool $enabled): void
+    {
+        $this->realTime = $enabled;
+        $this->nowMs = self::wallTimeMs();
+    }
+
     public function setTimersEnabled(bool $enabled): void
     {
         $this->timersEnabled = $enabled;
@@ -67,7 +144,9 @@ public function __construct(private readonly Engine $engine)
     {
         $this->nowMs = self::wallTimeMs();
         JsPromise::setPostDrainHook(function (): bool {
-            return $this->fireDueTasks();
+            // Node macrotasks run in runUntilEmpty's I/O phases. Draining
+            // newly due timers here can starve ready sockets indefinitely.
+            return !$this->realTime && $this->fireDueTasks();
         });
     }
 
@@ -75,6 +154,8 @@ public function __construct(private readonly Engine $engine)
     public function detach(): void
     {
         JsPromise::setPostDrainHook(null);
+        $this->ioDrivers = [];
+        $this->ioPoll = $this->ioReferences = null;
     }
 
     /**
@@ -129,23 +210,75 @@ public function setInterval(JsFunction $cb, float $intervalMs, array $callbackAr
         return $id;
     }
 
+    /** Schedule a Node check-phase callback, after the next I/O poll. */
+    public function setImmediate(JsFunction $callback): int
+    {
+        $id = $this->nextId++;
+        $this->immediates[$id] = new EventLoopTask($id, 0, $callback, false, 0, AsyncContextStorage::active()->snapshot());
+        return $id;
+    }
+
+    /** Control whether a timer keeps the Node event loop alive. */
+    public function reference(int $id, bool $referenced): void
+    {
+        $task = $this->tasks[$id] ?? $this->immediates[$id] ?? null;
+        if ($task !== null) {
+            $task->referenced = $referenced;
+        }
+    }
+
+    private function fireImmediate(): bool
+    {
+        $key = array_key_first($this->immediates);
+        if ($key === null) {
+            return false;
+        }
+        $task = $this->immediates[$key];
+        unset($this->immediates[$key]);
+        $this->invoke($task);
+        return true;
+    }
+
+    private function hasTimerReferences(): bool
+    {
+        foreach ([$this->tasks, $this->immediates] as $queue) {
+            foreach ($queue as $task) {
+                if ($task->referenced && !$task->cancelled) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * Cancel a scheduled task. Returns true if the task was pending,
      * false if the id was unknown or the task already cancelled.
      */
     public function clear(int $id): bool
     {
-        $task = $this->tasks[$id] ?? null;
+        $task = $this->tasks[$id] ?? $this->immediates[$id] ?? null;
         if ($task === null || $task->cancelled) {
             return false;
         }
         $task->cancelled = true;
-        unset($this->tasks[$id]);
+        unset($this->tasks[$id], $this->immediates[$id]);
         return true;
     }
 
+    /** Cancel all tasks when the owning realm closes or resets. */
+    public function clearAll(): void
+    {
+        foreach ([$this->tasks, $this->immediates] as $queue) {
+            foreach ($queue as $task) {
+                $task->cancelled = true;
+            }
+        }
+        $this->tasks = $this->immediates = [];
+    }
+
     /**
-     * Fire every task whose deadline is at or before the current
+     * Fire one task whose deadline is at or before the current
      * virtual clock. Returns true if at least one task fired (signal
      * to the microtask drain loop that more work may now be pending).
      */
@@ -157,34 +290,24 @@ public function fireDueTasks(): bool
         if ($this->tasks === []) {
             return false;
         }
+        if ($this->realTime && !$this->hasTimerReferences() && !($this->ioReferences !== null && ($this->ioReferences)())) {
+            return false;
+        }
         $this->advanceClock();
-        $fired = false;
-        // Iterate while due tasks remain. The task stays IN $tasks
-        // while its callback runs so that clearTimeout / clearInterval
-        // invoked from inside the callback can find and cancel it.
-        // Post-callback we either remove (one-shot or cancelled) or
-        // re-arm the deadline (repeating + still live).
-        while (true) {
-            $task = $this->peekEarliestDue();
-            if ($task === null) {
-                break;
-            }
-            $fired = true;
-            $this->invoke($task);
-            if ($task->cancelled || !$task->repeating) {
-                // Cancelled by clearInterval inside the callback, or
-                // never repeating in the first place. Remove if still
-                // present — clear() may have unset it already.
-                unset($this->tasks[$task->id]);
-            } else {
-                // Still live; re-arm. Use the current virtual clock
-                // (which advanceClock may have advanced past the old
-                // deadline) so a slow callback doesn't generate
-                // multiple back-to-back fires for one missed period.
-                $task->deadlineMs = $this->nowMs + $task->intervalMs;
-            }
+        $task = $this->peekEarliestDue();
+        if ($task === null) {
+            return false;
+        }
+        // A microtask checkpoint is required between callbacks, including
+        // timers scheduled by another timer. Otherwise polling loops can
+        // starve the Promise continuation that would terminate them.
+        $this->invoke($task);
+        if ($task->cancelled || !$task->repeating) {
+            unset($this->tasks[$task->id]);
+        } else {
+            $task->deadlineMs = $this->nowMs + $task->intervalMs;
         }
-        return $fired;
+        return true;
     }
 
     /**
@@ -197,11 +320,26 @@ public function fireDueTasks(): bool
      */
     public function runUntilEmpty(int $maxIters = 100_000): void
     {
-        for ($i = 0; $i < $maxIters; $i++) {
+        for ($i = 0; $this->realTime || $i < $maxIters; $i++) {
             JsPromise::drainMicrotasks();
-            if ($this->tasks === [] || !$this->timersEnabled) {
+            $hasIo = $this->ioReferences !== null && ($this->ioReferences)();
+            $hasTimers = $this->timersEnabled && ($this->realTime ? $this->hasTimerReferences() : $this->tasks !== []);
+            if (!$hasIo && !$hasTimers) {
                 return;
             }
+            if ($this->realTime || $hasIo) {
+                $this->engine->getInterpreter()->checkBudget();
+                $delay = $hasTimers ? max(0, (int) ceil($this->nextDelayMs() ?? 50)) : 50;
+                $delay = min(50, $delay);
+                if ($this->immediates !== []) {
+                    $delay = 0;
+                }
+                $this->pollReadyIo($delay);
+                $this->fireImmediate();
+                JsPromise::drainMicrotasks();
+                $this->fireDueTasks();
+                continue;
+            }
             // Microtasks emptied + no due timer + queue not empty
             // means every pending task is in the future. Jump the
             // virtual clock so they become due, then loop. The
@@ -231,19 +369,47 @@ public function runUntilEmpty(int $maxIters = 100_000): void
     public function tick(): bool
     {
         JsPromise::drainMicrotasks();
-        return $this->fireDueTasks();
+        $progress = $this->pollReadyIo(0);
+        $progress = $this->fireImmediate() || $progress;
+        JsPromise::drainMicrotasks();
+        return $this->fireDueTasks() || $progress;
+    }
+
+    private function pollReadyIo(int $timeout): bool
+    {
+        if ($this->ioPoll === null) {
+            if ($timeout > 0) {
+                usleep($timeout * 1000);
+            }
+            JsPromise::drainMicrotasks();
+            return false;
+        }
+        $progress = false;
+        // I/O callbacks and their Promise continuations can make more host
+        // work ready. Drain a bounded batch before the check/timer phases,
+        // without waiting again or starving timers under sustained traffic.
+        for ($round = 0; $round < 8; $round++) {
+            $ready = ($this->ioPoll)($round === 0 ? $timeout : 0);
+            $progress = $ready || $progress;
+            JsPromise::drainMicrotasks();
+            if (!$ready || $this->ioPoll === null) {
+                break;
+            }
+            $this->engine->getInterpreter()->checkBudget();
+        }
+        return $progress;
     }
 
     /** Number of pending tasks (excluding cancelled). */
     public function pendingTaskCount(): int
     {
-        return count($this->tasks);
+        return count($this->tasks) + count($this->immediates);
     }
 
     /** True when no tasks are pending. */
     public function isEmpty(): bool
     {
-        return $this->tasks === [];
+        return $this->tasks === [] && $this->immediates === [];
     }
 
     /**
@@ -316,6 +482,9 @@ private function invoke(EventLoopTask $task): void
                 $task->callbackArgs,
             );
         } catch (\Throwable $e) {
+            if ($this->engine->getNodeRuntime() !== null) {
+                throw $e;
+            }
             // Per HTML spec, uncaught errors from a timer callback go
             // to the "report an error" algorithm — which in a host
             // context fires the global error event. Phasis has no
diff --git a/src/Runtime/EventLoopTask.php b/src/Runtime/EventLoopTask.php
index ef9a4389..3be49891 100644
--- a/src/Runtime/EventLoopTask.php
+++ b/src/Runtime/EventLoopTask.php
@@ -24,6 +24,7 @@
 final class EventLoopTask
 {
     public bool $cancelled = false;
+    public bool $referenced = true;
 
     /**
      * @param array{0: array, 1: array} $contextSnapshot
diff --git a/src/Runtime/Interpreter.php b/src/Runtime/Interpreter.php
index 32c1ef37..26a30835 100644
--- a/src/Runtime/Interpreter.php
+++ b/src/Runtime/Interpreter.php
@@ -217,7 +217,7 @@ public function setupInlineVmCall(
         \Phasis\Value\JsValue $thisValue,
         array $args,
     ): array {
-        $this->callStack->push($fn->name, 0);
+        $this->callStack->push($fn->name, 0, $fn);
         $this->callerStack[] = $fn;
 
         if ($fn->setCallerPropCache === null) {
@@ -552,6 +552,27 @@ public function hasExecutionBudget(): bool
         return $this->budget !== null;
     }
 
+    /** Temporarily tighten a child execution deadline without extending its inherited host budget. */
+    public function tightenExecutionBudget(float $seconds): void
+    {
+        $deadline = hrtime(true) + (int) ($seconds * 1_000_000_000);
+        if ($this->budget === null || $deadline < $this->budget->deadline) {
+            $this->budget = new ExecutionBudget($deadline);
+        }
+    }
+
+    /** Capture a host deadline when a nested evaluation adds its own shorter timeout. */
+    public function executionBudgetState(): ?ExecutionBudget
+    {
+        return $this->budget;
+    }
+
+    /** Restore the exact shared host deadline after a nested evaluation. */
+    public function restoreExecutionBudgetState(?ExecutionBudget $budget): void
+    {
+        $this->budget = $budget;
+    }
+
     /**
      * Where the last statement the tree-walker started begins. After an
      * error escapes an evaluation that ran on the tree-walker, as every
diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php
index a39e93ec..dcd11c84 100644
--- a/src/Runtime/Parts/ExpressionEvaluation.php
+++ b/src/Runtime/Parts/ExpressionEvaluation.php
@@ -103,6 +103,9 @@
  */
 trait ExpressionEvaluation
 {
+    /** @var ?\WeakMap */
+    private ?\WeakMap $argumentsUsage = null;
+
     // -------------------------------------------------------------------------
     // Expression evaluation
     // -------------------------------------------------------------------------
@@ -118,9 +121,6 @@ public function evaluate(Node $node, Environment $env): JsValue
         // node types. Literals never produce the sentinel.
         if ($node instanceof Identifier) {
             $name = $node->name;
-            if ($name === 'undefined') {
-                return JsUndefined::instance();
-            }
             // Identifier scope-depth cache: if we have already
             // resolved this Identifier in a structurally identical
             // env chain, jump directly to the owning env. Safe only
@@ -875,62 +875,10 @@ private function evalDelete(Node $argument, Environment $env): JsValue
             if ($obj instanceof JsOptionalUndefined) {
                 return new JsBoolean(true);
             }
-            if ($obj instanceof JsNull || $obj instanceof JsUndefined) {
-                throw new TypeError(
-                    'Cannot read properties of ' . ($obj instanceof JsNull ? 'null' : 'undefined') . ' (deleting)',
-                );
-            }
-            if ($obj instanceof JsObject) {
-                $rawKey = null;
-                if ($argument->computed) {
-                    // ToPropertyKey on the computed key so a Symbol returned
-                    // by a custom toString stays a Symbol key.
-                    $rawKey = TypeConversion::toPropertyKey($this->evaluate($argument->property, $env));
-                    if ($rawKey instanceof JsSymbol) {
-                        // Delete symbol-keyed property.
-                        $deleted = $obj->deleteBySymbol($rawKey);
-                        if (!$deleted && $this->strictMode) {
-                            throw new TypeError(
-                                "Cannot delete property '" . $rawKey->toString() . "' of #"
-                            );
-                        }
-                        return new JsBoolean($deleted);
-                    }
-                    $key = $rawKey instanceof JsString ? $rawKey->value : TypeConversion::toString($rawKey);
-                } else {
-                    $key = $argument->property instanceof Identifier ? $argument->property->name : '';
-                }
-                return new JsBoolean($obj->delete($key, $this->strictMode));
-            }
-            // Deleting a property on a primitive base: per spec [[Delete]] on
-            // an Object Reference Record uses ToObject(GetBase) then attempts
-            // delete. For string-indexed properties (non-configurable), this
-            // returns false in sloppy mode and throws TypeError in strict.
-            if ($obj instanceof JsString) {
-                $rawKey = null;
-                if ($argument->computed) {
-                    $rawKey = TypeConversion::toPropertyKey($this->evaluate($argument->property, $env));
-                    $key = $rawKey instanceof JsString ? $rawKey->value : TypeConversion::toString($rawKey);
-                } else {
-                    $key = $argument->property instanceof Identifier ? $argument->property->name : '';
-                }
-                // String indices and length are non-configurable on the
-                // exotic String object — deletion fails.
-                $u16 = JsString::utf8ToUtf16LE($obj->value);
-                $u16Len = (int) (strlen($u16) / 2);
-                if ($key === 'length' || (ctype_digit($key) && (int) $key < $u16Len)) {
-                    if ($this->strictMode) {
-                        throw new TypeError("Cannot delete property '{$key}' of '{$obj->value}'");
-                    }
-                    return new JsBoolean(false);
-                }
-                // Other properties (those on String.prototype etc.) cannot
-                // be deleted via the exotic — also non-configurable on the
-                // wrapper, so always true (no own slot to remove).
-                return new JsBoolean(true);
-            }
-            // Other primitives: no own properties, delete is a no-op.
-            return new JsBoolean(true);
+            $key = $argument->computed
+                ? $this->evaluate($argument->property, $env)
+                : new JsString($argument->property instanceof Identifier ? $argument->property->name : '');
+            return new JsBoolean(AbstractOperations::deletePropertyReference($obj, $key, $this->strictMode));
         }
 
         // Delete on an identifier reference.
@@ -4010,6 +3958,7 @@ private function callFunctionInner(
         // standard executeFunction path so spec semantics are preserved.
         if (
             $fn->phpCompiled !== null
+            && $this->budget === null
             && !$fn->isClassConstructor()
             && !$fn->isDerivedConstructor()
             && $fn->getHomeObject() === null
@@ -4122,7 +4071,7 @@ private function executeFunction(
         JsValue $thisValue,
         array $args,
     ): JsValue|TailCallThunk {
-        $this->callStack->push($fn->getName(), 0);
+        $this->callStack->push($fn->getName(), 0, $fn);
         $this->callerStack[] = $fn;
         $fnBody = $fn->getBody();
         // Only ordinary constructable functions (e.g. 'function f(){}') track
@@ -4183,6 +4132,7 @@ private function executeFunction(
         // the lexical-this scan.
         if (
             $fn->compiled !== null
+            && $this->budget === null
             && $fn->compiled->canSkipEnvAlloc
             && !$fn->isClassConstructor()
             && !$fn->isDerivedConstructor()
@@ -4350,7 +4300,7 @@ private function executeFunction(
                 // compiler never emits LOAD_NEW_TARGET (no MetaProperty
                 // support yet, so any new.target use bails). Frame
                 // params come from $args directly via paramSlots.
-                $vmCanSkipEnvBindings = $fn->compiled !== null;
+                $vmCanSkipEnvBindings = $fn->compiled !== null && !$fn->compiled->parametersFromEnvironment && $this->budget === null;
                 if (!$vmCanSkipEnvBindings || $fn->compiled->needsThis) {
                     $fnEnv->defineVar('this', $thisValue);
                 }
@@ -4430,7 +4380,7 @@ private function executeFunction(
             // directly via tryRunOnVm; their nested closures are
             // forbidden from observing outer locals via the env
             // (capture-detection bails). Skip the env bindings then.
-            if ($fn->compiled === null) {
+            if ($fn->compiled === null || $fn->compiled->parametersFromEnvironment || $fn->compiled->needsArgsBinding || $this->budget !== null) {
                 $this->bindParameters($params, $args, $fnEnv, $hasDefaultParams);
             }
 
@@ -4499,25 +4449,31 @@ private function executeFunction(
             // the parameter list do not see body-scoped var declarations.
             if ($hasDefaultParams && $body instanceof BlockStatement) {
                 $bodyEnv = $fnEnv->createChild();
-                // Copy parameter bindings to the body environment as vars.
+                $this->forceHoistVarNames($body->body, $bodyEnv);
+                // Only var-redeclared parameters get a separate body binding.
+                // Other assignments must remain visible to parameter closures.
                 foreach ($params as $p) {
                     $this->copyParamBindings($p, $fnEnv, $bodyEnv);
                 }
                 // arguments in body env should still be available, but only
                 // when we actually built the arguments object on entry.
-                if (!$fn->isArrow() && $argsObj !== null) {
+                if (!$fn->isArrow() && $argsObj !== null && $bodyEnv->hasOwnBinding('arguments')) {
                     $bodyEnv->defineVar('arguments', $argsObj);
                 }
                 // Force-hoist var names into bodyEnv so they shadow parent bindings.
                 // This is necessary because the body environment is separate from
                 // the parameter environment, and var declarations must create
                 // bindings in the body scope, not update parent scope bindings.
-                $this->forceHoistVarNames($body->body, $bodyEnv);
                 $this->hoistDeclarations($body->body, $bodyEnv);
                 $this->currentParamNames = $savedParamNames;
                 $this->hoistEvalLexicalDeclarations($body->body, $bodyEnv);
                 $savedTailPos = $this->inTailPosition;
                 $this->inTailPosition = $this->strictMode;
+                $vmReturn = $this->tryRunOnVm($fn, $bodyEnv, $thisValue, $args);
+                if ($vmReturn !== null) {
+                    $this->inTailPosition = $savedTailPos;
+                    return $this->derivedConstructorReturn($fn, $fnEnv, $vmReturn);
+                }
                 $completion = $this->executeDisposableBody($body->body, $bodyEnv);
                 $this->inTailPosition = $savedTailPos;
                 $completion = $this->applyDisposals($bodyEnv, $completion);
@@ -4640,7 +4596,7 @@ public function executeVmFunctionDirect(
         // each one method dispatch per call. The hot-path field reads
         // collapse to plain property fetches now that JsFunction
         // exposes these as public.
-        $this->callStack->push($fn->name, 0);
+        $this->callStack->push($fn->name, 0, $fn);
         $this->callerStack[] = $fn;
 
         if ($fn->setCallerPropCache === null) {
@@ -4910,62 +4866,70 @@ private function driveAsyncFiber(
         ?JsValue $throwValue = null,
         ?string $modulePath = null,
     ): void {
-        // Swap currentModulePath to the async function's defining
-        // module for the duration of the resume so that import() and
-        // import.meta inside the body see the right referrer.
-        $previousModulePath = $this->currentModulePath;
-        if ($modulePath !== null) {
-            $this->currentModulePath = $modulePath;
-        }
+        $storage = \Phasis\Runtime\AsyncContextStorage::active();
+        $previousContext = $storage->snapshot();
         try {
-            if ($start) {
-                $suspended = $fiber->start();
-            } elseif ($resumeAsThrow) {
-                $suspended = $fiber->throw(
-                    new \Phasis\Exceptions\JsThrowable($throwValue ?? JsUndefined::instance()),
-                );
-            } else {
-                $suspended = $fiber->resume($resumeValue);
+            // Swap currentModulePath to the async function's defining
+            // module for the duration of the resume so that import() and
+            // import.meta inside the body see the right referrer.
+            $previousModulePath = $this->currentModulePath;
+            if ($modulePath !== null) {
+                $this->currentModulePath = $modulePath;
             }
-        } catch (\Phasis\Exceptions\JsThrowable $e) {
-            $this->currentModulePath = $previousModulePath;
-            $promise->reject($e->jsValue);
-            return;
-        } catch (\Phasis\Exceptions\RuntimeError $e) {
-            $this->currentModulePath = $previousModulePath;
-            $promise->reject($this->phpExceptionToJsValue($e));
-            return;
-        } catch (\Throwable $e) {
+            try {
+                if ($start) {
+                    $suspended = $fiber->start();
+                } elseif ($resumeAsThrow) {
+                    $suspended = $fiber->throw(
+                        new \Phasis\Exceptions\JsThrowable($throwValue ?? JsUndefined::instance()),
+                    );
+                } else {
+                    $suspended = $fiber->resume($resumeValue);
+                }
+            } catch (\Phasis\Exceptions\JsThrowable $e) {
+                $this->currentModulePath = $previousModulePath;
+                $promise->reject($e->jsValue);
+                return;
+            } catch (\Phasis\Exceptions\RuntimeError $e) {
+                $this->currentModulePath = $previousModulePath;
+                $promise->reject($this->phpExceptionToJsValue($e));
+                return;
+            } catch (\Throwable $e) {
+                $this->currentModulePath = $previousModulePath;
+                $promise->reject($this->phpExceptionToJsValue($e));
+                return;
+            }
+            // Restore on the normal-completion path too. If the fiber
+            // suspended again we've already taken its module path off
+            // the saved trail, and the next resume will reinstate it.
             $this->currentModulePath = $previousModulePath;
-            $promise->reject($this->phpExceptionToJsValue($e));
-            return;
-        }
-        // Restore on the normal-completion path too. If the fiber
-        // suspended again we've already taken its module path off
-        // the saved trail, and the next resume will reinstate it.
-        $this->currentModulePath = $previousModulePath;
 
-        if ($fiber->isTerminated()) {
-            $returnValue = $fiber->getReturn();
-            if (!$returnValue instanceof JsValue) {
-                $returnValue = JsUndefined::instance();
+            if ($fiber->isTerminated()) {
+                $returnValue = $fiber->getReturn();
+                if (!$returnValue instanceof JsValue) {
+                    $returnValue = JsUndefined::instance();
+                }
+                $promise->resolve($returnValue);
+                return;
             }
-            $promise->resolve($returnValue);
-            return;
-        }
 
-        if ($suspended instanceof \Phasis\Value\AwaitSuspension) {
-            // Per spec Await(value): synchronously do PromiseResolve and
-            // PerformPromiseThen, then suspend. The .then path itself queues
-            // the resumption as a microtask, so we attach handlers
-            // synchronously here. Wrapping in scheduleCallback would add
-            // an extra tick that breaks await/microtask interleaving.
-            $this->settleAwaitedAndResume($fiber, $promise, $suspended->value, $modulePath);
-            return;
-        }
+            if ($suspended instanceof \Phasis\Value\AwaitSuspension) {
+                // Per spec Await(value): synchronously do PromiseResolve and
+                // PerformPromiseThen, then suspend. The .then path itself queues
+                // the resumption as a microtask, so we attach handlers
+                // synchronously here. Wrapping in scheduleCallback would add
+                // an extra tick that breaks await/microtask interleaving.
+                $this->settleAwaitedAndResume($fiber, $promise, $suspended->value, $modulePath);
+                return;
+            }
 
-        // Unknown suspension shape: treat as resolved with undefined.
-        $promise->resolve(JsUndefined::instance());
+            // Unknown suspension shape: treat as resolved with undefined.
+            $promise->resolve(JsUndefined::instance());
+        } finally {
+            // A suspended Fiber can still be inside AsyncLocalStorage.run.
+            // Capture its continuation first, then restore the caller's map.
+            $storage->restore($previousContext);
+        }
     }
 
     /**
@@ -5342,7 +5306,7 @@ public function executeGeneratorBody(
         array $args,
         ?Environment $prebuiltEnv = null,
     ): JsValue {
-        $this->callStack->push($fn->getName(), 0);
+        $this->callStack->push($fn->getName(), 0, $fn);
 
         try {
             // Use pre-built environment if provided (parameters already bound).
@@ -5371,11 +5335,13 @@ public function executeGeneratorBody(
 
             if ($hasDefaultParams && $body instanceof BlockStatement) {
                 $bodyEnv = $fnEnv->createChild();
+                $this->forceHoistVarNames($body->body, $bodyEnv);
                 foreach ($params as $p) {
                     $this->copyParamBindings($p, $fnEnv, $bodyEnv);
                 }
-                $bodyEnv->defineVar('arguments', $fnEnv->get('arguments'));
-                $this->forceHoistVarNames($body->body, $bodyEnv);
+                if ($bodyEnv->hasOwnBinding('arguments')) {
+                    $bodyEnv->defineVar('arguments', $fnEnv->get('arguments'));
+                }
                 $this->hoistDeclarations($body->body, $bodyEnv);
                 $this->hoistEvalLexicalDeclarations($body->body, $bodyEnv);
                 $completion = $this->executeDisposableBody($body->body, $bodyEnv);
@@ -6269,7 +6235,10 @@ private function tryRunOnVm(
         // into those slots without going through env->defineVar.
         $argCount = count($args);
         for ($i = 0; $i < $paramCount; $i++) {
-            $frame->locals[$paramSlots[$i]] = $i < $argCount ? $args[$i] : $undef;
+            $slot = $paramSlots[$i];
+            $frame->locals[$slot] = $cf->parametersFromEnvironment
+                ? $fnEnv->get($cf->localNames[$slot])
+                : ($i < $argCount ? $args[$i] : $undef);
         }
         if ($this->vm === null) {
             $this->vm = new \Phasis\Bytecode\VM($this);
@@ -6477,6 +6446,15 @@ private function bodyUsesArguments(mixed $body, array $params = []): bool
     }
 
     private function nodeReferencesArguments(Node $node): bool
+    {
+        $cache = $this->argumentsUsage ??= new \WeakMap();
+        if (isset($cache[$node])) {
+            return $cache[$node];
+        }
+        return $cache[$node] = $this->scanNodeReferencesArguments($node);
+    }
+
+    private function scanNodeReferencesArguments(Node $node): bool
     {
         if ($node instanceof Identifier) {
             // Direct eval can introspect arguments, so any `eval` reference
@@ -6664,7 +6642,9 @@ private function nodeReferencesArgumentsIdentifier(Node $node): bool
     private function copyParamBindings(Node $param, Environment $source, Environment $target): void
     {
         if ($param instanceof Identifier) {
-            $target->defineVar($param->name, $source->get($param->name));
+            if ($target->hasOwnBinding($param->name)) {
+                $target->defineVar($param->name, $source->get($param->name));
+            }
         } elseif ($param instanceof AssignmentPattern) {
             $this->copyParamBindings($param->left, $source, $target);
         } elseif ($param instanceof ArrayPattern) {
@@ -7174,6 +7154,19 @@ private function createStringIteratorFactory(JsString $str): JsFunction
         return JsFunction::fromCallable('[Symbol.iterator]', $iteratorFactory);
     }
 
+    /** Consume a compiled array spread with the interpreter's iterator protocol. */
+    public function vmArraySpread(JsArray $array, JsValue $iterable): void
+    {
+        $items = [];
+        $this->spreadInto($iterable, $items);
+        foreach ($items as $item) {
+            $array->defineOwnProperty(
+                (string) $array->getLength(),
+                PropertyDescriptor::data($item, true, true, true),
+            );
+        }
+    }
+
     private function evalArrayExpression(ArrayExpression $node, Environment $env): JsValue
     {
         $arr = new JsArray();
diff --git a/src/Runtime/Parts/Helpers/RegExpHelpers.php b/src/Runtime/Parts/Helpers/RegExpHelpers.php
index 76aba148..d7b2ff0a 100644
--- a/src/Runtime/Parts/Helpers/RegExpHelpers.php
+++ b/src/Runtime/Parts/Helpers/RegExpHelpers.php
@@ -212,17 +212,13 @@ private function createRegExpObject(string $pattern, string $flags): JsObject
             throw $e;
         }
 
-        $regexpProto = null;
-        if ($this->globalEnv->has('RegExp')) {
-            $ctor = $this->globalEnv->get('RegExp');
-            if ($ctor instanceof JsFunction) {
-                $proto = $ctor->get('prototype');
-                if ($proto instanceof JsObject) {
-                    $regexpProto = $proto;
-                }
-            }
+        $regexpProto = $this->globalEnv->getIntrinsic('RegExpPrototype');
+        if (!$regexpProto instanceof JsObject && $this->globalEnv->has('RegExp')) {
+            // Force lazy installation before reading the private intrinsic.
+            $this->globalEnv->get('RegExp');
+            $regexpProto = $this->globalEnv->getIntrinsic('RegExpPrototype');
         }
-        $obj = new JsObject($regexpProto);
+        $obj = new JsObject($regexpProto instanceof JsObject ? $regexpProto : null);
 
         // Per spec §22.2.5.3 get RegExp.prototype.flags, flags are returned in canonical order:
         // d, g, i, m, s, u, v, y (alphabetical subset of valid flag characters).
diff --git a/src/Runtime/Parts/StatementExecution.php b/src/Runtime/Parts/StatementExecution.php
index dc234e83..114c4c6f 100644
--- a/src/Runtime/Parts/StatementExecution.php
+++ b/src/Runtime/Parts/StatementExecution.php
@@ -2575,8 +2575,15 @@ private function execReturnStatement(ReturnStatement $node, Environment $env): C
         // TailCallThunk instead of evaluating the call immediately. The
         // helper returns either a TailCallThunk or a JsValue (when the
         // tail branch could be evaluated directly with its side-effecting
-        // prefix); we wrap accordingly.
-        if ($this->strictMode && $node->argument !== null && $this->inTailPosition) {
+        // prefix); we wrap accordingly. Async and generator bodies have no
+        // proper tail positions: their return values still need their own
+        // promise or iterator completion processing.
+        if (
+            $this->strictMode
+            && $node->argument !== null
+            && $this->inTailPosition
+            && !in_array($env->getEnclosingFunctionKind(), ['async', 'generator', 'async-generator'], true)
+        ) {
             $result = $this->evalTailPositionExpr($node->argument, $env);
             if ($result !== null) {
                 return Completion::return($result);
diff --git a/src/Spec/AbstractOperations.php b/src/Spec/AbstractOperations.php
index 1c6bea57..caa6e90d 100644
--- a/src/Spec/AbstractOperations.php
+++ b/src/Spec/AbstractOperations.php
@@ -497,6 +497,35 @@ public static function typeofOperator(JsValue $value): JsString
         return new JsString($value->typeof());
     }
 
+    /**
+     * Delete an evaluated property reference, preserving strict failures and key coercion.
+     *
+     * The key expression has already run; nullish bases fail before ToPropertyKey.
+     */
+    public static function deletePropertyReference(JsValue $object, JsValue $key, bool $strict): bool
+    {
+        if ($object instanceof JsNull || $object instanceof JsUndefined) {
+            throw new TypeError('Cannot delete a property of ' . $object->toJsString());
+        }
+        $key = TypeConversion::toPropertyKey($key);
+        $deleted = true;
+        if ($object instanceof JsObject) {
+            $deleted = $key instanceof JsSymbol
+                ? $object->deleteBySymbol($key)
+                : $object->delete($key->toJsString(), $strict);
+        } elseif ($object instanceof JsString && $key instanceof JsString) {
+            $name = $key->value;
+            $index = (int) $name;
+            $deleted = $name !== 'length' && !(ctype_digit($name) && (string) $index === $name
+                && $index < $object->length());
+        }
+        if (!$deleted && $strict) {
+            $name = $key instanceof JsSymbol ? $key->toString() : $key->toJsString();
+            throw new TypeError("Cannot delete property '{$name}'");
+        }
+        return $deleted;
+    }
+
     /**
      * 13.10.2 InstanceofOperator(V, target).
      *
diff --git a/src/Value/JsGenerator.php b/src/Value/JsGenerator.php
index 3c9b7209..5e384cf4 100644
--- a/src/Value/JsGenerator.php
+++ b/src/Value/JsGenerator.php
@@ -4,6 +4,7 @@
 
 namespace Phasis\Value;
 
+use Phasis\Engine;
 use Phasis\Exceptions\JsThrowable;
 use Phasis\Exceptions\RuntimeError;
 use Phasis\Object\PropertyDescriptor;
@@ -67,31 +68,9 @@ public function __construct(
         // Per spec §27.5.1 via OrdinaryCreateFromConstructor:
         // The [[Prototype]] is generatorFn.prototype if it's an Object,
         // otherwise falls back to the intrinsic %GeneratorPrototype%.
-        $instanceProto = null;
-        $fnProto = $generatorFn->get('prototype');
-        if ($fnProto instanceof JsObject) {
-            $instanceProto = $fnProto;
-        } else {
-            $instanceProto = self::$generatorPrototype;
-        }
+        $instanceProto = self::instancePrototype($generatorFn);
         parent::__construct($instanceProto);
 
-        // Ensure the prototype chain is properly wired to Object.prototype.
-        // %IteratorPrototype% may have been created before Object.prototype was
-        // set as the global prototype. Walk up and fix any broken link.
-        if ($instanceProto !== null) {
-            $tail = $instanceProto;
-            while ($tail->getPrototype() !== null) {
-                $tail = $tail->getPrototype();
-            }
-            // If the tail is not Object.prototype itself (Object.prototype has
-            // null [[Prototype]]), wire it up so toString, etc. are reachable.
-            $globalProto = JsObject::getGlobalPrototype();
-            if ($globalProto !== null && $tail !== $globalProto) {
-                $tail->setPrototype($globalProto);
-            }
-        }
-
         $fn = $generatorFn;
         $thisVal = $thisValue;
         $fnArgs = $args;
@@ -133,28 +112,22 @@ private static function createWithoutFiber(JsFunction $generatorFn, JsValue $thi
         $g = (new \ReflectionClass(self::class))->newInstanceWithoutConstructor();
         // Wire up the prototype chain manually, mirroring
         // __construct's setup.
-        $instanceProto = null;
-        $fnProto = $generatorFn->get('prototype');
-        if ($fnProto instanceof JsObject) {
-            $instanceProto = $fnProto;
-        } else {
-            $instanceProto = self::$generatorPrototype;
-        }
+        $instanceProto = self::instancePrototype($generatorFn);
         $g->properties = new \Phasis\Object\PropertyMap();
         $g->setPrototype($instanceProto);
-        if ($instanceProto !== null) {
-            $tail = $instanceProto;
-            while ($tail->getPrototype() !== null) {
-                $tail = $tail->getPrototype();
-            }
-            $globalProto = JsObject::getGlobalPrototype();
-            if ($globalProto !== null && $tail !== $globalProto) {
-                $tail->setPrototype($globalProto);
-            }
-        }
         return $g;
     }
 
+    private static function instancePrototype(JsFunction $function): ?JsObject
+    {
+        $prototype = $function->get('prototype');
+        if ($prototype instanceof JsObject) {
+            return $prototype;
+        }
+        $intrinsic = $function->realm?->getGlobalEnv()->get('__GeneratorPrototype__');
+        return $intrinsic instanceof JsObject ? $intrinsic : self::$generatorPrototype;
+    }
+
     /**
      * Resume the generator, optionally passing a value as the result of
      * the yield expression that last paused execution.
@@ -506,9 +479,10 @@ private function isFiberDone(): bool
      */
     private function makeResult(JsValue $value, bool $done): JsObject
     {
-        $result = new JsObject();
-        $result->set('value', $value);
-        $result->set('done', new JsBoolean($done));
+        $prototype = Engine::getCurrentRealm()?->getGlobalEnv()->get('__ObjectPrototype__');
+        $result = new JsObject($prototype instanceof JsObject ? $prototype : null);
+        $result->defineOwnProperty('value', PropertyDescriptor::data($value, true, true, true));
+        $result->defineOwnProperty('done', PropertyDescriptor::data(new JsBoolean($done), true, true, true));
         return $result;
     }
 
diff --git a/src/Value/JsPromise.php b/src/Value/JsPromise.php
index c71ded8c..c5de5cec 100644
--- a/src/Value/JsPromise.php
+++ b/src/Value/JsPromise.php
@@ -5,14 +5,13 @@
 namespace Phasis\Value;
 
 use Phasis\Object\PropertyDescriptor;
+use Phasis\Runtime\AsyncContextStorage;
 
 /**
  * Represents a JavaScript Promise.
  *
- * Since PHP is single-threaded, this is a synchronous implementation.
- * The executor runs immediately, and then/catch/finally handlers run
- * synchronously when called. This passes basic Promise tests while
- * maintaining correct value propagation semantics.
+ * Executors run immediately. Promise reactions run in the microtask queue
+ * and retain the async context where they were registered.
  */
 class JsPromise extends JsObject
 {
@@ -25,11 +24,12 @@ class JsPromise extends JsObject
 
     /**
      * Pending handlers queued while this promise is unresolved.
-     * Each entry is [onFulfilled|null, onRejected|null, childPromise|null].
+     * Each entry holds fulfillment/rejection handlers, an optional child promise,
+     * and the async context captured when the reaction was registered.
      * The child promise is null for subscription-only handlers attached
      * via Promise resolution (see resolveValue's thenable adoption path).
      *
-     * @var list
+     * @var list, array}}>
      */
     private array $pendingHandlers = [];
 
@@ -60,6 +60,9 @@ class JsPromise extends JsObject
      */
     private static ?\Closure $postDrainHook = null;
 
+    /** @var ?\Closure(): bool Host jobs run at turn boundaries before Promise jobs. */
+    private static ?\Closure $turnBoundaryHook = null;
+
     /**
      * Schedule a callback to run in the microtask queue.
      * Used to defer promise handler execution so that handlers fire in
@@ -73,13 +76,13 @@ class JsPromise extends JsObject
      * AsyncContext proposal).
      *
      * @param \Closure(): void $cb
+     * @param array{array, array}|null $context
      */
-    public static function scheduleCallback(\Closure $cb): void
+    public static function scheduleCallback(\Closure $cb, ?array $context = null): void
     {
-        $storage = \Phasis\Runtime\AsyncContextStorage::active();
-        $captured = $storage->snapshot();
+        $captured = $context ?? AsyncContextStorage::active()->snapshot();
         self::$microtaskQueue[] = static function () use ($cb, $captured): void {
-            $storage = \Phasis\Runtime\AsyncContextStorage::active();
+            $storage = AsyncContextStorage::active();
             $previous = $storage->snapshot();
             $storage->restore($captured);
             try {
@@ -101,6 +104,24 @@ public static function setPostDrainHook(?\Closure $hook): void
         self::$postDrainHook = $hook;
     }
 
+    /** Install host jobs, such as Node nextTick, outside a Promise job batch. */
+    public static function setTurnBoundaryHook(?\Closure $hook): void
+    {
+        self::$turnBoundaryHook = $hook;
+    }
+
+    /** Preserve the event-loop driver while constructing or entering a child realm. */
+    public static function getPostDrainHook(): ?\Closure
+    {
+        return self::$postDrainHook;
+    }
+
+    /** Preserve Node host jobs while constructing or entering a child realm. */
+    public static function getTurnBoundaryHook(): ?\Closure
+    {
+        return self::$turnBoundaryHook;
+    }
+
     /**
      * Drain the microtask queue, running all scheduled callbacks.
      * Callbacks added during draining are also processed. When a
@@ -115,10 +136,17 @@ public static function drainMicrotasks(): void
         self::$drainingMicrotasks = true;
         try {
             do {
+                if (self::$turnBoundaryHook !== null) {
+                    (self::$turnBoundaryHook)();
+                }
                 while (self::$microtaskQueue !== []) {
                     $cb = array_shift(self::$microtaskQueue);
                     $cb();
                 }
+                if (self::$turnBoundaryHook !== null && (self::$turnBoundaryHook)()) {
+                    $progressed = true;
+                    continue;
+                }
                 $hook = self::$postDrainHook;
                 if ($hook === null) {
                     break;
@@ -138,6 +166,7 @@ public static function clearMicrotasks(): void
         self::$microtaskQueue = [];
         self::$drainingMicrotasks = false;
         self::$postDrainHook = null;
+        self::$turnBoundaryHook = null;
     }
 
     /** Promise.prototype: the shared prototype for all JsPromise instances. */
@@ -159,6 +188,18 @@ public static function setPromisePrototype(JsObject $proto): void
         self::$intrinsicThen = $descriptor?->value;
     }
 
+    /** @return array{?JsObject, ?JsValue} The realm's native Promise defaults, including the original then method. */
+    public static function captureIntrinsicState(): array
+    {
+        return [self::$promisePrototype, self::$intrinsicThen];
+    }
+
+    /** @param array{?JsObject, ?JsValue} $state */
+    public static function restoreIntrinsicState(array $state): void
+    {
+        [self::$promisePrototype, self::$intrinsicThen] = $state;
+    }
+
     public function __construct(?JsObject $prototype = null)
     {
         parent::__construct($prototype ?? self::$promisePrototype);
@@ -225,7 +266,6 @@ public function resolve(JsValue $value): void
             } else {
                 // Still pending: subscribe to it so we settle when it does.
                 $outer = $this;
-                $value->pendingHandlers[] = [null, null, null];
                 // Use a direct subscription via the inner promise's pending handler list.
                 $resolved = false;
                 $resolveFn = JsFunction::fromCallable('resolve', function (JsValue $this_, array $args) use ($outer, &$resolved): JsValue {
@@ -245,8 +285,7 @@ public function resolve(JsValue $value): void
                     return JsUndefined::instance();
                 }, 1);
                 // Register directly on the inner promise's handler list.
-                array_pop($value->pendingHandlers); // remove the placeholder we added above
-                $value->pendingHandlers[] = [$resolveFn, $rejectFn, null];
+                $value->pendingHandlers[] = [$resolveFn, $rejectFn, null, AsyncContextStorage::active()->snapshot()];
             }
             return;
         }
@@ -337,7 +376,7 @@ private function drainPendingHandlers(): void
         $handlers = $this->pendingHandlers;
         $this->pendingHandlers = [];
         $self = $this;
-        foreach ($handlers as [$onFulfilled, $onRejected, $child]) {
+        foreach ($handlers as [$onFulfilled, $onRejected, $child, $context]) {
             if ($child === null) {
                 // Subscription-only handler (no child promise). Still runs as
                 // a microtask so handler order matches spec PromiseReactions.
@@ -350,7 +389,7 @@ private function drainPendingHandlers(): void
                         } catch (\Throwable) {
                             // Ignore errors in subscription handlers.
                         }
-                    });
+                    }, $context);
                 }
                 continue;
             }
@@ -358,7 +397,7 @@ private function drainPendingHandlers(): void
             // interleave with siblings per spec PromiseReactions enqueue order.
             self::scheduleCallback(static function () use ($self, $onFulfilled, $onRejected, $child): void {
                 $self->runHandler($onFulfilled, $onRejected, $child);
-            });
+            }, $context);
         }
     }
 
@@ -417,7 +456,7 @@ public function addFulfillHandler(\Closure $cb): void
                 $cb($args[0] ?? JsUndefined::instance());
                 return JsUndefined::instance();
             }, 1);
-            $this->pendingHandlers[] = [$fn, null, null];
+            $this->pendingHandlers[] = [$fn, null, null, AsyncContextStorage::active()->snapshot()];
         }
     }
 
@@ -438,7 +477,7 @@ public function addRejectHandler(\Closure $cb): void
                 $cb($args[0] ?? JsUndefined::instance());
                 return JsUndefined::instance();
             }, 1);
-            $this->pendingHandlers[] = [null, $fn, null];
+            $this->pendingHandlers[] = [null, $fn, null, AsyncContextStorage::active()->snapshot()];
         }
     }
 
@@ -480,7 +519,7 @@ public function then(array $args): self
 
         if ($this->state === self::STATE_PENDING) {
             // Queue the handler to run when this promise settles.
-            $this->pendingHandlers[] = [$fulfillFn, $rejectFn, $child];
+            $this->pendingHandlers[] = [$fulfillFn, $rejectFn, $child, AsyncContextStorage::active()->snapshot()];
             return $child;
         }
 
diff --git a/src/Value/JsString.php b/src/Value/JsString.php
index 82129ace..6cab1701 100644
--- a/src/Value/JsString.php
+++ b/src/Value/JsString.php
@@ -8,6 +8,9 @@ class JsString implements JsValue
 {
     private static ?JsObject $stringPrototype = null;
 
+    private ?string $utf16 = null;
+    private ?int $codeUnitLength = null;
+
     public static function setStringPrototype(JsObject $proto): void
     {
         self::$stringPrototype = $proto;
@@ -66,8 +69,15 @@ public function display(): string
     /** JavaScript String.length (UTF-16 code unit count). */
     public function length(): int
     {
-        $u16 = self::utf8ToUtf16LE($this->value);
-        return (int) (strlen($u16) / 2);
+        return $this->codeUnitLength ??= mb_check_encoding($this->value, 'ASCII')
+            ? strlen($this->value)
+            : (int) (strlen($this->utf16LE()) / 2);
+    }
+
+    /** UTF-16 code units cached for this immutable string value. */
+    public function utf16LE(): string
+    {
+        return $this->utf16 ??= self::utf8ToUtf16LE($this->value);
     }
 
     /**
@@ -95,6 +105,9 @@ public static function utf16CodeUnitToUtf8(int $codeUnit): string
      */
     public static function utf8ToUtf16LE(string $str): string
     {
+        if (mb_check_encoding($str, 'UTF-8')) {
+            return mb_convert_encoding($str, 'UTF-16LE', 'UTF-8');
+        }
         $len = strlen($str);
         $result = '';
         $i = 0;
diff --git a/tests/Frameworks/.gitignore b/tests/Frameworks/.gitignore
new file mode 100644
index 00000000..e3f4dd5e
--- /dev/null
+++ b/tests/Frameworks/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+express/upstream/
+hono/upstream/
+!package-lock.json
diff --git a/tests/Frameworks/express/manifest.json b/tests/Frameworks/express/manifest.json
new file mode 100644
index 00000000..0e51299e
--- /dev/null
+++ b/tests/Frameworks/express/manifest.json
@@ -0,0 +1,5666 @@
+{
+  "version": 2,
+  "tests": 1261,
+  "files": [
+    {
+      "path": "test/Route.js",
+      "sha256": "4607c2b70f5b897c1cb85f8a2bc1067944c4b36828bc73d140732851acc9782e",
+      "tests": 13,
+      "cases": [
+        {
+          "id": "test/Route.js:1",
+          "title": "Route should work without handlers"
+        },
+        {
+          "id": "test/Route.js:2",
+          "title": "Route should not stack overflow with a large sync stack"
+        },
+        {
+          "id": "test/Route.js:3",
+          "title": "Route .all should add handler"
+        },
+        {
+          "id": "test/Route.js:4",
+          "title": "Route .all should handle VERBS"
+        },
+        {
+          "id": "test/Route.js:5",
+          "title": "Route .all should stack"
+        },
+        {
+          "id": "test/Route.js:6",
+          "title": "Route .VERB should support .get"
+        },
+        {
+          "id": "test/Route.js:7",
+          "title": "Route .VERB should limit to just .VERB"
+        },
+        {
+          "id": "test/Route.js:8",
+          "title": "Route .VERB should allow fallthrough"
+        },
+        {
+          "id": "test/Route.js:9",
+          "title": "Route errors should handle errors via arity 4 functions"
+        },
+        {
+          "id": "test/Route.js:10",
+          "title": "Route errors should handle throw"
+        },
+        {
+          "id": "test/Route.js:11",
+          "title": "Route errors should handle throwing inside error handlers"
+        },
+        {
+          "id": "test/Route.js:12",
+          "title": "Route errors should handle throw in .all"
+        },
+        {
+          "id": "test/Route.js:13",
+          "title": "Route errors should handle single error handler"
+        }
+      ]
+    },
+    {
+      "path": "test/Router.js",
+      "sha256": "721ffc840d1c4aad931d859a661c98f07eb56389f1c3a1902cb06fae4d4c0c32",
+      "tests": 39,
+      "cases": [
+        {
+          "id": "test/Router.js:1",
+          "title": "Router should return a function with router methods"
+        },
+        {
+          "id": "test/Router.js:2",
+          "title": "Router should support .use of other routers"
+        },
+        {
+          "id": "test/Router.js:3",
+          "title": "Router should support dynamic routes"
+        },
+        {
+          "id": "test/Router.js:4",
+          "title": "Router should handle blank URL"
+        },
+        {
+          "id": "test/Router.js:5",
+          "title": "Router should handle missing URL"
+        },
+        {
+          "id": "test/Router.js:6",
+          "title": "Router handle missing method"
+        },
+        {
+          "id": "test/Router.js:7",
+          "title": "Router should not stack overflow with many registered routes"
+        },
+        {
+          "id": "test/Router.js:8",
+          "title": "Router should not stack overflow with a large sync route stack"
+        },
+        {
+          "id": "test/Router.js:9",
+          "title": "Router should not stack overflow with a large sync middleware stack"
+        },
+        {
+          "id": "test/Router.js:10",
+          "title": "Router .handle should dispatch"
+        },
+        {
+          "id": "test/Router.js:11",
+          "title": "Router .multiple callbacks should throw if a callback is null"
+        },
+        {
+          "id": "test/Router.js:12",
+          "title": "Router .multiple callbacks should throw if a callback is undefined"
+        },
+        {
+          "id": "test/Router.js:13",
+          "title": "Router .multiple callbacks should throw if a callback is not a function"
+        },
+        {
+          "id": "test/Router.js:14",
+          "title": "Router .multiple callbacks should not throw if all callbacks are functions"
+        },
+        {
+          "id": "test/Router.js:15",
+          "title": "Router error should skip non error middleware"
+        },
+        {
+          "id": "test/Router.js:16",
+          "title": "Router error should handle throwing inside routes with params"
+        },
+        {
+          "id": "test/Router.js:17",
+          "title": "Router error should handle throwing in handler after async param"
+        },
+        {
+          "id": "test/Router.js:18",
+          "title": "Router error should handle throwing inside error handlers"
+        },
+        {
+          "id": "test/Router.js:19",
+          "title": "Router FQDN should not obscure FQDNs"
+        },
+        {
+          "id": "test/Router.js:20",
+          "title": "Router FQDN should ignore FQDN in search"
+        },
+        {
+          "id": "test/Router.js:21",
+          "title": "Router FQDN should ignore FQDN in path"
+        },
+        {
+          "id": "test/Router.js:22",
+          "title": "Router FQDN should adjust FQDN req.url"
+        },
+        {
+          "id": "test/Router.js:23",
+          "title": "Router FQDN should adjust FQDN req.url with multiple handlers"
+        },
+        {
+          "id": "test/Router.js:24",
+          "title": "Router FQDN should adjust FQDN req.url with multiple routed handlers"
+        },
+        {
+          "id": "test/Router.js:25",
+          "title": "Router .all should support using .all to capture all http verbs"
+        },
+        {
+          "id": "test/Router.js:26",
+          "title": "Router .use should require middleware"
+        },
+        {
+          "id": "test/Router.js:27",
+          "title": "Router .use should reject string as middleware"
+        },
+        {
+          "id": "test/Router.js:28",
+          "title": "Router .use should reject number as middleware"
+        },
+        {
+          "id": "test/Router.js:29",
+          "title": "Router .use should reject null as middleware"
+        },
+        {
+          "id": "test/Router.js:30",
+          "title": "Router .use should reject Date as middleware"
+        },
+        {
+          "id": "test/Router.js:31",
+          "title": "Router .use should be called for any URL"
+        },
+        {
+          "id": "test/Router.js:32",
+          "title": "Router .use should accept array of middleware"
+        },
+        {
+          "id": "test/Router.js:33",
+          "title": "Router .param should require function"
+        },
+        {
+          "id": "test/Router.js:34",
+          "title": "Router .param should reject non-function"
+        },
+        {
+          "id": "test/Router.js:35",
+          "title": "Router .param should call param function when routing VERBS"
+        },
+        {
+          "id": "test/Router.js:36",
+          "title": "Router .param should call param function when routing middleware"
+        },
+        {
+          "id": "test/Router.js:37",
+          "title": "Router .param should only call once per request"
+        },
+        {
+          "id": "test/Router.js:38",
+          "title": "Router .param should call when values differ"
+        },
+        {
+          "id": "test/Router.js:39",
+          "title": "Router parallel requests should not mix requests"
+        }
+      ]
+    },
+    {
+      "path": "test/app.all.js",
+      "sha256": "ae892a75df019ae2eda9cbd79dde06b6fc5a408e8aeaed4384f61311452e7262",
+      "tests": 2,
+      "cases": [
+        {
+          "id": "test/app.all.js:1",
+          "title": "app.all() should add a router per method"
+        },
+        {
+          "id": "test/app.all.js:2",
+          "title": "app.all() should run the callback for a method just once"
+        }
+      ]
+    },
+    {
+      "path": "test/app.engine.js",
+      "sha256": "30d1606056440d76ffef7b74ee7ccfca94adbf85ae456ee58bcd66ad9e4fd3c9",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/app.engine.js:1",
+          "title": "app .engine(ext, fn) should map a template engine"
+        },
+        {
+          "id": "test/app.engine.js:2",
+          "title": "app .engine(ext, fn) should throw when the callback is missing"
+        },
+        {
+          "id": "test/app.engine.js:3",
+          "title": "app .engine(ext, fn) should work without leading \".\""
+        },
+        {
+          "id": "test/app.engine.js:4",
+          "title": "app .engine(ext, fn) should work \"view engine\" setting"
+        },
+        {
+          "id": "test/app.engine.js:5",
+          "title": "app .engine(ext, fn) should work \"view engine\" with leading \".\""
+        }
+      ]
+    },
+    {
+      "path": "test/app.head.js",
+      "sha256": "1826481948a30b17ebefa94d235711230e2548f9f22a6064065dbbe953f7a656",
+      "tests": 3,
+      "cases": [
+        {
+          "id": "test/app.head.js:1",
+          "title": "HEAD should default to GET"
+        },
+        {
+          "id": "test/app.head.js:2",
+          "title": "HEAD should output the same headers as GET requests"
+        },
+        {
+          "id": "test/app.head.js:3",
+          "title": "app.head() should override"
+        }
+      ]
+    },
+    {
+      "path": "test/app.js",
+      "sha256": "826034bcb123e71507dc0070cc7d6223c6944eb72c0f76fce47d931a577e96dc",
+      "tests": 9,
+      "cases": [
+        {
+          "id": "test/app.js:1",
+          "title": "app should inherit from event emitter"
+        },
+        {
+          "id": "test/app.js:2",
+          "title": "app should be callable"
+        },
+        {
+          "id": "test/app.js:3",
+          "title": "app should 404 without routes"
+        },
+        {
+          "id": "test/app.js:4",
+          "title": "app.parent should return the parent when mounted"
+        },
+        {
+          "id": "test/app.js:5",
+          "title": "app.mountpath should return the mounted path"
+        },
+        {
+          "id": "test/app.js:6",
+          "title": "app.path() should return the canonical"
+        },
+        {
+          "id": "test/app.js:7",
+          "title": "in development should disable \"view cache\""
+        },
+        {
+          "id": "test/app.js:8",
+          "title": "in production should enable \"view cache\""
+        },
+        {
+          "id": "test/app.js:9",
+          "title": "without NODE_ENV should default to development"
+        }
+      ]
+    },
+    {
+      "path": "test/app.listen.js",
+      "sha256": "cf6de481a11d1ec873c4d6d08182720021e9f7848353edd471d9a44cfd6449cb",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/app.listen.js:1",
+          "title": "app.listen() should wrap with an HTTP server"
+        },
+        {
+          "id": "test/app.listen.js:2",
+          "title": "app.listen() should callback on HTTP server errors"
+        },
+        {
+          "id": "test/app.listen.js:3",
+          "title": "app.listen() accepts port + hostname + backlog + callback"
+        },
+        {
+          "id": "test/app.listen.js:4",
+          "title": "app.listen() accepts just a callback (no args)"
+        },
+        {
+          "id": "test/app.listen.js:5",
+          "title": "app.listen() server.address() gives a { address, port, family } object"
+        }
+      ]
+    },
+    {
+      "path": "test/app.locals.js",
+      "sha256": "740de98086b2f9b8d72c5d3c20711c5dd2ff4b421065a779b299a9e4d22dab15",
+      "tests": 2,
+      "cases": [
+        {
+          "id": "test/app.locals.js:1",
+          "title": "app .locals should default object with null prototype"
+        },
+        {
+          "id": "test/app.locals.js:2",
+          "title": "app .locals .settings should contain app settings "
+        }
+      ]
+    },
+    {
+      "path": "test/app.options.js",
+      "sha256": "d4af092f1014bec6d66bc2da3cc29bf65648610c489f717c434bd4fc2ad58057",
+      "tests": 7,
+      "cases": [
+        {
+          "id": "test/app.options.js:1",
+          "title": "OPTIONS should default to the routes defined"
+        },
+        {
+          "id": "test/app.options.js:2",
+          "title": "OPTIONS should only include each method once"
+        },
+        {
+          "id": "test/app.options.js:3",
+          "title": "OPTIONS should not be affected by app.all"
+        },
+        {
+          "id": "test/app.options.js:4",
+          "title": "OPTIONS should not respond if the path is not defined"
+        },
+        {
+          "id": "test/app.options.js:5",
+          "title": "OPTIONS should forward requests down the middleware chain"
+        },
+        {
+          "id": "test/app.options.js:6",
+          "title": "OPTIONS when error occurs in response handler should pass error to callback"
+        },
+        {
+          "id": "test/app.options.js:7",
+          "title": "app.options() should override the default behavior"
+        }
+      ]
+    },
+    {
+      "path": "test/app.param.js",
+      "sha256": "5d214dfa424f0e87766fb58655f188fb24536afccf3f4a426c6bab7eb8a9d60e",
+      "tests": 13,
+      "cases": [
+        {
+          "id": "test/app.param.js:1",
+          "title": "app .param(names, fn) should map the array"
+        },
+        {
+          "id": "test/app.param.js:2",
+          "title": "app .param(name, fn) should map logic for a single param"
+        },
+        {
+          "id": "test/app.param.js:3",
+          "title": "app .param(name, fn) should only call once per request"
+        },
+        {
+          "id": "test/app.param.js:4",
+          "title": "app .param(name, fn) should call when values differ"
+        },
+        {
+          "id": "test/app.param.js:5",
+          "title": "app .param(name, fn) should support altering req.params across routes"
+        },
+        {
+          "id": "test/app.param.js:6",
+          "title": "app .param(name, fn) should not invoke without route handler"
+        },
+        {
+          "id": "test/app.param.js:7",
+          "title": "app .param(name, fn) should work with encoded values"
+        },
+        {
+          "id": "test/app.param.js:8",
+          "title": "app .param(name, fn) should catch thrown error"
+        },
+        {
+          "id": "test/app.param.js:9",
+          "title": "app .param(name, fn) should catch thrown secondary error"
+        },
+        {
+          "id": "test/app.param.js:10",
+          "title": "app .param(name, fn) should defer to next route"
+        },
+        {
+          "id": "test/app.param.js:11",
+          "title": "app .param(name, fn) should defer all the param routes"
+        },
+        {
+          "id": "test/app.param.js:12",
+          "title": "app .param(name, fn) should not call when values differ on error"
+        },
+        {
+          "id": "test/app.param.js:13",
+          "title": "app .param(name, fn) should call when values differ when using \"next\""
+        }
+      ]
+    },
+    {
+      "path": "test/app.render.js",
+      "sha256": "65cedddf807447609b5f8cbc381c03ca814e70d6d76c870dd8ec46d1c8d5a66c",
+      "tests": 21,
+      "cases": [
+        {
+          "id": "test/app.render.js:1",
+          "title": "app .render(name, fn) should support absolute paths"
+        },
+        {
+          "id": "test/app.render.js:2",
+          "title": "app .render(name, fn) should support absolute paths with \"view engine\""
+        },
+        {
+          "id": "test/app.render.js:3",
+          "title": "app .render(name, fn) should expose app.locals"
+        },
+        {
+          "id": "test/app.render.js:4",
+          "title": "app .render(name, fn) should support index."
+        },
+        {
+          "id": "test/app.render.js:5",
+          "title": "app .render(name, fn) should handle render error throws"
+        },
+        {
+          "id": "test/app.render.js:6",
+          "title": "app .render(name, fn) when the file does not exist should provide a helpful error"
+        },
+        {
+          "id": "test/app.render.js:7",
+          "title": "app .render(name, fn) when an error occurs should invoke the callback"
+        },
+        {
+          "id": "test/app.render.js:8",
+          "title": "app .render(name, fn) when an extension is given should render the template"
+        },
+        {
+          "id": "test/app.render.js:9",
+          "title": "app .render(name, fn) when \"view engine\" is given should render the template"
+        },
+        {
+          "id": "test/app.render.js:10",
+          "title": "app .render(name, fn) when \"views\" is given should lookup the file in the path"
+        },
+        {
+          "id": "test/app.render.js:11",
+          "title": "app .render(name, fn) when \"views\" is given when array of paths should lookup the file in the path"
+        },
+        {
+          "id": "test/app.render.js:12",
+          "title": "app .render(name, fn) when \"views\" is given when array of paths should lookup in later paths until found"
+        },
+        {
+          "id": "test/app.render.js:13",
+          "title": "app .render(name, fn) when \"views\" is given when array of paths should error if file does not exist"
+        },
+        {
+          "id": "test/app.render.js:14",
+          "title": "app .render(name, fn) when a \"view\" constructor is given should create an instance of it"
+        },
+        {
+          "id": "test/app.render.js:15",
+          "title": "app .render(name, fn) caching should always lookup view without cache"
+        },
+        {
+          "id": "test/app.render.js:16",
+          "title": "app .render(name, fn) caching should cache with \"view cache\" setting"
+        },
+        {
+          "id": "test/app.render.js:17",
+          "title": "app .render(name, options, fn) should render the template"
+        },
+        {
+          "id": "test/app.render.js:18",
+          "title": "app .render(name, options, fn) should expose app.locals"
+        },
+        {
+          "id": "test/app.render.js:19",
+          "title": "app .render(name, options, fn) should give precedence to app.render() locals"
+        },
+        {
+          "id": "test/app.render.js:20",
+          "title": "app .render(name, options, fn) should accept null or undefined options"
+        },
+        {
+          "id": "test/app.render.js:21",
+          "title": "app .render(name, options, fn) caching should cache with cache option"
+        }
+      ]
+    },
+    {
+      "path": "test/app.request.js",
+      "sha256": "b7cdf42087d8f693c2c3a73741df9bc41cfbce555e30fcd1d2d19832a4d0f649",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/app.request.js:1",
+          "title": "app .request should extend the request prototype"
+        },
+        {
+          "id": "test/app.request.js:2",
+          "title": "app .request should only extend for the referenced app"
+        },
+        {
+          "id": "test/app.request.js:3",
+          "title": "app .request should inherit to sub apps"
+        },
+        {
+          "id": "test/app.request.js:4",
+          "title": "app .request should allow sub app to override"
+        },
+        {
+          "id": "test/app.request.js:5",
+          "title": "app .request should not pollute parent app"
+        }
+      ]
+    },
+    {
+      "path": "test/app.response.js",
+      "sha256": "fa825e21a28538d00ae9877198e7644090447fa3660b842aa43b4a32e16f6869",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/app.response.js:1",
+          "title": "app .response should extend the response prototype"
+        },
+        {
+          "id": "test/app.response.js:2",
+          "title": "app .response should only extend for the referenced app"
+        },
+        {
+          "id": "test/app.response.js:3",
+          "title": "app .response should inherit to sub apps"
+        },
+        {
+          "id": "test/app.response.js:4",
+          "title": "app .response should allow sub app to override"
+        },
+        {
+          "id": "test/app.response.js:5",
+          "title": "app .response should not pollute parent app"
+        }
+      ]
+    },
+    {
+      "path": "test/app.route.js",
+      "sha256": "18ddd7005789c9455a09a88c2339223c41fbcbe75d5a6168b61f61bb38814be6",
+      "tests": 10,
+      "cases": [
+        {
+          "id": "test/app.route.js:1",
+          "title": "app.route should return a new route"
+        },
+        {
+          "id": "test/app.route.js:2",
+          "title": "app.route should all .VERB after .all"
+        },
+        {
+          "id": "test/app.route.js:3",
+          "title": "app.route should support dynamic routes"
+        },
+        {
+          "id": "test/app.route.js:4",
+          "title": "app.route should not error on empty routes"
+        },
+        {
+          "id": "test/app.route.js:5",
+          "title": "app.route promise support should pass rejected promise value"
+        },
+        {
+          "id": "test/app.route.js:6",
+          "title": "app.route promise support should pass rejected promise without value"
+        },
+        {
+          "id": "test/app.route.js:7",
+          "title": "app.route promise support should ignore resolved promise"
+        },
+        {
+          "id": "test/app.route.js:8",
+          "title": "app.route promise support error handling should pass rejected promise value"
+        },
+        {
+          "id": "test/app.route.js:9",
+          "title": "app.route promise support error handling should pass rejected promise without value"
+        },
+        {
+          "id": "test/app.route.js:10",
+          "title": "app.route promise support error handling should ignore resolved promise"
+        }
+      ]
+    },
+    {
+      "path": "test/app.router.js",
+      "sha256": "875a5aac701d34cbdabaad0501e1e5a661161b24b2312d49875100dea1143a3b",
+      "tests": 132,
+      "cases": [
+        {
+          "id": "test/app.router.js:1",
+          "title": "app.router should restore req.params after leaving router"
+        },
+        {
+          "id": "test/app.router.js:2",
+          "title": "app.router should be .use()able"
+        },
+        {
+          "id": "test/app.router.js:3",
+          "title": "app.router should allow literal \".\""
+        },
+        {
+          "id": "test/app.router.js:4",
+          "title": "app.router should allow rewriting of the url"
+        },
+        {
+          "id": "test/app.router.js:5",
+          "title": "app.router should run in order added"
+        },
+        {
+          "id": "test/app.router.js:6",
+          "title": "app.router should be chainable"
+        },
+        {
+          "id": "test/app.router.js:7",
+          "title": "app.router should not use disposed router/middleware"
+        },
+        {
+          "id": "test/app.router.js:8",
+          "title": "app.router methods should include ACL"
+        },
+        {
+          "id": "test/app.router.js:9",
+          "title": "app.router methods should reject numbers for app.acl"
+        },
+        {
+          "id": "test/app.router.js:10",
+          "title": "app.router methods should include BIND"
+        },
+        {
+          "id": "test/app.router.js:11",
+          "title": "app.router methods should reject numbers for app.bind"
+        },
+        {
+          "id": "test/app.router.js:12",
+          "title": "app.router methods should include CHECKOUT"
+        },
+        {
+          "id": "test/app.router.js:13",
+          "title": "app.router methods should reject numbers for app.checkout"
+        },
+        {
+          "id": "test/app.router.js:14",
+          "title": "app.router methods should include COPY"
+        },
+        {
+          "id": "test/app.router.js:15",
+          "title": "app.router methods should reject numbers for app.copy"
+        },
+        {
+          "id": "test/app.router.js:16",
+          "title": "app.router methods should include DELETE"
+        },
+        {
+          "id": "test/app.router.js:17",
+          "title": "app.router methods should reject numbers for app.delete"
+        },
+        {
+          "id": "test/app.router.js:18",
+          "title": "app.router methods should include GET"
+        },
+        {
+          "id": "test/app.router.js:19",
+          "title": "app.router methods should reject numbers for app.get"
+        },
+        {
+          "id": "test/app.router.js:20",
+          "title": "app.router methods should include HEAD"
+        },
+        {
+          "id": "test/app.router.js:21",
+          "title": "app.router methods should reject numbers for app.head"
+        },
+        {
+          "id": "test/app.router.js:22",
+          "title": "app.router methods should include LINK"
+        },
+        {
+          "id": "test/app.router.js:23",
+          "title": "app.router methods should reject numbers for app.link"
+        },
+        {
+          "id": "test/app.router.js:24",
+          "title": "app.router methods should include LOCK"
+        },
+        {
+          "id": "test/app.router.js:25",
+          "title": "app.router methods should reject numbers for app.lock"
+        },
+        {
+          "id": "test/app.router.js:26",
+          "title": "app.router methods should include M-SEARCH"
+        },
+        {
+          "id": "test/app.router.js:27",
+          "title": "app.router methods should reject numbers for app.m-search"
+        },
+        {
+          "id": "test/app.router.js:28",
+          "title": "app.router methods should include MERGE"
+        },
+        {
+          "id": "test/app.router.js:29",
+          "title": "app.router methods should reject numbers for app.merge"
+        },
+        {
+          "id": "test/app.router.js:30",
+          "title": "app.router methods should include MKACTIVITY"
+        },
+        {
+          "id": "test/app.router.js:31",
+          "title": "app.router methods should reject numbers for app.mkactivity"
+        },
+        {
+          "id": "test/app.router.js:32",
+          "title": "app.router methods should include MKCALENDAR"
+        },
+        {
+          "id": "test/app.router.js:33",
+          "title": "app.router methods should reject numbers for app.mkcalendar"
+        },
+        {
+          "id": "test/app.router.js:34",
+          "title": "app.router methods should include MKCOL"
+        },
+        {
+          "id": "test/app.router.js:35",
+          "title": "app.router methods should reject numbers for app.mkcol"
+        },
+        {
+          "id": "test/app.router.js:36",
+          "title": "app.router methods should include MOVE"
+        },
+        {
+          "id": "test/app.router.js:37",
+          "title": "app.router methods should reject numbers for app.move"
+        },
+        {
+          "id": "test/app.router.js:38",
+          "title": "app.router methods should include NOTIFY"
+        },
+        {
+          "id": "test/app.router.js:39",
+          "title": "app.router methods should reject numbers for app.notify"
+        },
+        {
+          "id": "test/app.router.js:40",
+          "title": "app.router methods should include OPTIONS"
+        },
+        {
+          "id": "test/app.router.js:41",
+          "title": "app.router methods should reject numbers for app.options"
+        },
+        {
+          "id": "test/app.router.js:42",
+          "title": "app.router methods should include PATCH"
+        },
+        {
+          "id": "test/app.router.js:43",
+          "title": "app.router methods should reject numbers for app.patch"
+        },
+        {
+          "id": "test/app.router.js:44",
+          "title": "app.router methods should include POST"
+        },
+        {
+          "id": "test/app.router.js:45",
+          "title": "app.router methods should reject numbers for app.post"
+        },
+        {
+          "id": "test/app.router.js:46",
+          "title": "app.router methods should include PROPFIND"
+        },
+        {
+          "id": "test/app.router.js:47",
+          "title": "app.router methods should reject numbers for app.propfind"
+        },
+        {
+          "id": "test/app.router.js:48",
+          "title": "app.router methods should include PROPPATCH"
+        },
+        {
+          "id": "test/app.router.js:49",
+          "title": "app.router methods should reject numbers for app.proppatch"
+        },
+        {
+          "id": "test/app.router.js:50",
+          "title": "app.router methods should include PURGE"
+        },
+        {
+          "id": "test/app.router.js:51",
+          "title": "app.router methods should reject numbers for app.purge"
+        },
+        {
+          "id": "test/app.router.js:52",
+          "title": "app.router methods should include PUT"
+        },
+        {
+          "id": "test/app.router.js:53",
+          "title": "app.router methods should reject numbers for app.put"
+        },
+        {
+          "id": "test/app.router.js:54",
+          "title": "app.router methods should include QUERY"
+        },
+        {
+          "id": "test/app.router.js:55",
+          "title": "app.router methods should reject numbers for app.query"
+        },
+        {
+          "id": "test/app.router.js:56",
+          "title": "app.router methods should include REBIND"
+        },
+        {
+          "id": "test/app.router.js:57",
+          "title": "app.router methods should reject numbers for app.rebind"
+        },
+        {
+          "id": "test/app.router.js:58",
+          "title": "app.router methods should include REPORT"
+        },
+        {
+          "id": "test/app.router.js:59",
+          "title": "app.router methods should reject numbers for app.report"
+        },
+        {
+          "id": "test/app.router.js:60",
+          "title": "app.router methods should include SEARCH"
+        },
+        {
+          "id": "test/app.router.js:61",
+          "title": "app.router methods should reject numbers for app.search"
+        },
+        {
+          "id": "test/app.router.js:62",
+          "title": "app.router methods should include SOURCE"
+        },
+        {
+          "id": "test/app.router.js:63",
+          "title": "app.router methods should reject numbers for app.source"
+        },
+        {
+          "id": "test/app.router.js:64",
+          "title": "app.router methods should include SUBSCRIBE"
+        },
+        {
+          "id": "test/app.router.js:65",
+          "title": "app.router methods should reject numbers for app.subscribe"
+        },
+        {
+          "id": "test/app.router.js:66",
+          "title": "app.router methods should include TRACE"
+        },
+        {
+          "id": "test/app.router.js:67",
+          "title": "app.router methods should reject numbers for app.trace"
+        },
+        {
+          "id": "test/app.router.js:68",
+          "title": "app.router methods should include UNBIND"
+        },
+        {
+          "id": "test/app.router.js:69",
+          "title": "app.router methods should reject numbers for app.unbind"
+        },
+        {
+          "id": "test/app.router.js:70",
+          "title": "app.router methods should include UNLINK"
+        },
+        {
+          "id": "test/app.router.js:71",
+          "title": "app.router methods should reject numbers for app.unlink"
+        },
+        {
+          "id": "test/app.router.js:72",
+          "title": "app.router methods should include UNLOCK"
+        },
+        {
+          "id": "test/app.router.js:73",
+          "title": "app.router methods should reject numbers for app.unlock"
+        },
+        {
+          "id": "test/app.router.js:74",
+          "title": "app.router methods should include UNSUBSCRIBE"
+        },
+        {
+          "id": "test/app.router.js:75",
+          "title": "app.router methods should reject numbers for app.unsubscribe"
+        },
+        {
+          "id": "test/app.router.js:76",
+          "title": "app.router methods should re-route when method is altered"
+        },
+        {
+          "id": "test/app.router.js:77",
+          "title": "app.router decode params should decode correct params"
+        },
+        {
+          "id": "test/app.router.js:78",
+          "title": "app.router decode params should not accept params in malformed paths"
+        },
+        {
+          "id": "test/app.router.js:79",
+          "title": "app.router decode params should not decode spaces"
+        },
+        {
+          "id": "test/app.router.js:80",
+          "title": "app.router decode params should work with unicode"
+        },
+        {
+          "id": "test/app.router.js:81",
+          "title": "app.router when given a regexp should match the pathname only"
+        },
+        {
+          "id": "test/app.router.js:82",
+          "title": "app.router when given a regexp should populate req.params with the captures"
+        },
+        {
+          "id": "test/app.router.js:83",
+          "title": "app.router when given a regexp should populate req.params with named captures"
+        },
+        {
+          "id": "test/app.router.js:84",
+          "title": "app.router when given a regexp should ensure regexp matches path prefix"
+        },
+        {
+          "id": "test/app.router.js:85",
+          "title": "app.router case sensitivity should be disabled by default"
+        },
+        {
+          "id": "test/app.router.js:86",
+          "title": "app.router case sensitivity when \"case sensitive routing\" is enabled should match identical casing"
+        },
+        {
+          "id": "test/app.router.js:87",
+          "title": "app.router case sensitivity when \"case sensitive routing\" is enabled should not match otherwise"
+        },
+        {
+          "id": "test/app.router.js:88",
+          "title": "app.router params should overwrite existing req.params by default"
+        },
+        {
+          "id": "test/app.router.js:89",
+          "title": "app.router params should allow merging existing req.params"
+        },
+        {
+          "id": "test/app.router.js:90",
+          "title": "app.router params should use params from router"
+        },
+        {
+          "id": "test/app.router.js:91",
+          "title": "app.router params should merge numeric indices req.params"
+        },
+        {
+          "id": "test/app.router.js:92",
+          "title": "app.router params should merge numeric indices req.params when more in parent"
+        },
+        {
+          "id": "test/app.router.js:93",
+          "title": "app.router params should merge numeric indices req.params when parent has same number"
+        },
+        {
+          "id": "test/app.router.js:94",
+          "title": "app.router params should ignore invalid incoming req.params"
+        },
+        {
+          "id": "test/app.router.js:95",
+          "title": "app.router params should restore req.params"
+        },
+        {
+          "id": "test/app.router.js:96",
+          "title": "app.router trailing slashes should be optional by default"
+        },
+        {
+          "id": "test/app.router.js:97",
+          "title": "app.router trailing slashes when \"strict routing\" is enabled should match trailing slashes"
+        },
+        {
+          "id": "test/app.router.js:98",
+          "title": "app.router trailing slashes when \"strict routing\" is enabled should pass-through middleware"
+        },
+        {
+          "id": "test/app.router.js:99",
+          "title": "app.router trailing slashes when \"strict routing\" is enabled should pass-through mounted middleware"
+        },
+        {
+          "id": "test/app.router.js:100",
+          "title": "app.router trailing slashes when \"strict routing\" is enabled should match no slashes"
+        },
+        {
+          "id": "test/app.router.js:101",
+          "title": "app.router trailing slashes when \"strict routing\" is enabled should match middleware when omitting the trailing slash"
+        },
+        {
+          "id": "test/app.router.js:102",
+          "title": "app.router trailing slashes when \"strict routing\" is enabled should match middleware"
+        },
+        {
+          "id": "test/app.router.js:103",
+          "title": "app.router trailing slashes when \"strict routing\" is enabled should match middleware when adding the trailing slash"
+        },
+        {
+          "id": "test/app.router.js:104",
+          "title": "app.router trailing slashes when \"strict routing\" is enabled should fail when omitting the trailing slash"
+        },
+        {
+          "id": "test/app.router.js:105",
+          "title": "app.router trailing slashes when \"strict routing\" is enabled should fail when adding the trailing slash"
+        },
+        {
+          "id": "test/app.router.js:106",
+          "title": "app.router :name should denote a capture group"
+        },
+        {
+          "id": "test/app.router.js:107",
+          "title": "app.router :name should match a single segment only"
+        },
+        {
+          "id": "test/app.router.js:108",
+          "title": "app.router :name should allow several capture groups"
+        },
+        {
+          "id": "test/app.router.js:109",
+          "title": "app.router :name should work following a partial capture group"
+        },
+        {
+          "id": "test/app.router.js:110",
+          "title": "app.router :name should work inside literal parenthesis"
+        },
+        {
+          "id": "test/app.router.js:111",
+          "title": "app.router :name should work in array of paths"
+        },
+        {
+          "id": "test/app.router.js:112",
+          "title": "app.router :name? should denote an optional capture group"
+        },
+        {
+          "id": "test/app.router.js:113",
+          "title": "app.router :name? should populate the capture group"
+        },
+        {
+          "id": "test/app.router.js:114",
+          "title": "app.router :name* should match one segment"
+        },
+        {
+          "id": "test/app.router.js:115",
+          "title": "app.router :name* should match many segments"
+        },
+        {
+          "id": "test/app.router.js:116",
+          "title": "app.router :name* should match zero segments"
+        },
+        {
+          "id": "test/app.router.js:117",
+          "title": "app.router :name+ should match one segment"
+        },
+        {
+          "id": "test/app.router.js:118",
+          "title": "app.router :name+ should match many segments"
+        },
+        {
+          "id": "test/app.router.js:119",
+          "title": "app.router :name+ should not match zero segments"
+        },
+        {
+          "id": "test/app.router.js:120",
+          "title": "app.router .:name should denote a format"
+        },
+        {
+          "id": "test/app.router.js:121",
+          "title": "app.router .:name? should denote an optional format"
+        },
+        {
+          "id": "test/app.router.js:122",
+          "title": "app.router when next() is called should continue lookup"
+        },
+        {
+          "id": "test/app.router.js:123",
+          "title": "app.router when next(\"route\") is called should jump to next route"
+        },
+        {
+          "id": "test/app.router.js:124",
+          "title": "app.router when next(\"router\") is called should jump out of router"
+        },
+        {
+          "id": "test/app.router.js:125",
+          "title": "app.router when next(err) is called should break out of app.router"
+        },
+        {
+          "id": "test/app.router.js:126",
+          "title": "app.router when next(err) is called should call handler in same route, if exists"
+        },
+        {
+          "id": "test/app.router.js:127",
+          "title": "app.router promise support should pass rejected promise value"
+        },
+        {
+          "id": "test/app.router.js:128",
+          "title": "app.router promise support should pass rejected promise without value"
+        },
+        {
+          "id": "test/app.router.js:129",
+          "title": "app.router promise support should ignore resolved promise"
+        },
+        {
+          "id": "test/app.router.js:130",
+          "title": "app.router promise support error handling should pass rejected promise value"
+        },
+        {
+          "id": "test/app.router.js:131",
+          "title": "app.router promise support error handling should pass rejected promise without value"
+        },
+        {
+          "id": "test/app.router.js:132",
+          "title": "app.router promise support error handling should ignore resolved promise"
+        }
+      ]
+    },
+    {
+      "path": "test/app.routes.error.js",
+      "sha256": "69379b4852515e5ab9f010390eb2eaa1d18250c1ac1ffb8c1ecc6fbabab2190a",
+      "tests": 2,
+      "cases": [
+        {
+          "id": "test/app.routes.error.js:1",
+          "title": "app .VERB() should not get invoked without error handler on error"
+        },
+        {
+          "id": "test/app.routes.error.js:2",
+          "title": "app .VERB() should only call an error handling routing callback when an error is propagated"
+        }
+      ]
+    },
+    {
+      "path": "test/app.use.js",
+      "sha256": "5bd9a8b9464ddd5b3c0fd49b21a822ca8afa5d89263e482d53adb36282305ef0",
+      "tests": 27,
+      "cases": [
+        {
+          "id": "test/app.use.js:1",
+          "title": "app should emit \"mount\" when mounted"
+        },
+        {
+          "id": "test/app.use.js:2",
+          "title": "app .use(app) should mount the app"
+        },
+        {
+          "id": "test/app.use.js:3",
+          "title": "app .use(app) should support mount-points"
+        },
+        {
+          "id": "test/app.use.js:4",
+          "title": "app .use(app) should set the child's .parent"
+        },
+        {
+          "id": "test/app.use.js:5",
+          "title": "app .use(app) should support dynamic routes"
+        },
+        {
+          "id": "test/app.use.js:6",
+          "title": "app .use(app) should support mounted app anywhere"
+        },
+        {
+          "id": "test/app.use.js:7",
+          "title": "app .use(middleware) should accept multiple arguments"
+        },
+        {
+          "id": "test/app.use.js:8",
+          "title": "app .use(middleware) should invoke middleware for all requests"
+        },
+        {
+          "id": "test/app.use.js:9",
+          "title": "app .use(middleware) should accept array of middleware"
+        },
+        {
+          "id": "test/app.use.js:10",
+          "title": "app .use(middleware) should accept multiple arrays of middleware"
+        },
+        {
+          "id": "test/app.use.js:11",
+          "title": "app .use(middleware) should accept nested arrays of middleware"
+        },
+        {
+          "id": "test/app.use.js:12",
+          "title": "app .use(path, middleware) should require middleware"
+        },
+        {
+          "id": "test/app.use.js:13",
+          "title": "app .use(path, middleware) should reject string as middleware"
+        },
+        {
+          "id": "test/app.use.js:14",
+          "title": "app .use(path, middleware) should reject number as middleware"
+        },
+        {
+          "id": "test/app.use.js:15",
+          "title": "app .use(path, middleware) should reject null as middleware"
+        },
+        {
+          "id": "test/app.use.js:16",
+          "title": "app .use(path, middleware) should reject Date as middleware"
+        },
+        {
+          "id": "test/app.use.js:17",
+          "title": "app .use(path, middleware) should strip path from req.url"
+        },
+        {
+          "id": "test/app.use.js:18",
+          "title": "app .use(path, middleware) should accept multiple arguments"
+        },
+        {
+          "id": "test/app.use.js:19",
+          "title": "app .use(path, middleware) should invoke middleware for all requests starting with path"
+        },
+        {
+          "id": "test/app.use.js:20",
+          "title": "app .use(path, middleware) should work if path has trailing slash"
+        },
+        {
+          "id": "test/app.use.js:21",
+          "title": "app .use(path, middleware) should accept array of middleware"
+        },
+        {
+          "id": "test/app.use.js:22",
+          "title": "app .use(path, middleware) should accept multiple arrays of middleware"
+        },
+        {
+          "id": "test/app.use.js:23",
+          "title": "app .use(path, middleware) should accept nested arrays of middleware"
+        },
+        {
+          "id": "test/app.use.js:24",
+          "title": "app .use(path, middleware) should support array of paths"
+        },
+        {
+          "id": "test/app.use.js:25",
+          "title": "app .use(path, middleware) should support array of paths with middleware array"
+        },
+        {
+          "id": "test/app.use.js:26",
+          "title": "app .use(path, middleware) should support regexp path"
+        },
+        {
+          "id": "test/app.use.js:27",
+          "title": "app .use(path, middleware) should support empty string path"
+        }
+      ]
+    },
+    {
+      "path": "test/config.js",
+      "sha256": "4208ea05427049016181ef7a0e2ad6a3388cbe53bcb60281c625ee42e1d1aa8c",
+      "tests": 26,
+      "cases": [
+        {
+          "id": "test/config.js:1",
+          "title": "config .set() should set a value"
+        },
+        {
+          "id": "test/config.js:2",
+          "title": "config .set() should set prototype values"
+        },
+        {
+          "id": "test/config.js:3",
+          "title": "config .set() should return the app"
+        },
+        {
+          "id": "test/config.js:4",
+          "title": "config .set() should return the app when undefined"
+        },
+        {
+          "id": "test/config.js:5",
+          "title": "config .set() should return set value"
+        },
+        {
+          "id": "test/config.js:6",
+          "title": "config .set() should return undefined for prototype values"
+        },
+        {
+          "id": "test/config.js:7",
+          "title": "config .set() \"etag\" should throw on bad value"
+        },
+        {
+          "id": "test/config.js:8",
+          "title": "config .set() \"etag\" should set \"etag fn\""
+        },
+        {
+          "id": "test/config.js:9",
+          "title": "config .set() \"trust proxy\" should set \"trust proxy fn\""
+        },
+        {
+          "id": "test/config.js:10",
+          "title": "config .get() should return undefined when unset"
+        },
+        {
+          "id": "test/config.js:11",
+          "title": "config .get() should return undefined for prototype values"
+        },
+        {
+          "id": "test/config.js:12",
+          "title": "config .get() should otherwise return the value"
+        },
+        {
+          "id": "test/config.js:13",
+          "title": "config .get() when mounted should default to the parent app"
+        },
+        {
+          "id": "test/config.js:14",
+          "title": "config .get() when mounted should given precedence to the child"
+        },
+        {
+          "id": "test/config.js:15",
+          "title": "config .get() when mounted should inherit \"trust proxy\" setting"
+        },
+        {
+          "id": "test/config.js:16",
+          "title": "config .get() when mounted should prefer child \"trust proxy\" setting"
+        },
+        {
+          "id": "test/config.js:17",
+          "title": "config .enable() should set the value to true"
+        },
+        {
+          "id": "test/config.js:18",
+          "title": "config .enable() should set prototype values"
+        },
+        {
+          "id": "test/config.js:19",
+          "title": "config .disable() should set the value to false"
+        },
+        {
+          "id": "test/config.js:20",
+          "title": "config .disable() should set prototype values"
+        },
+        {
+          "id": "test/config.js:21",
+          "title": "config .enabled() should default to false"
+        },
+        {
+          "id": "test/config.js:22",
+          "title": "config .enabled() should return true when set"
+        },
+        {
+          "id": "test/config.js:23",
+          "title": "config .enabled() should default to false for prototype values"
+        },
+        {
+          "id": "test/config.js:24",
+          "title": "config .disabled() should default to true"
+        },
+        {
+          "id": "test/config.js:25",
+          "title": "config .disabled() should return false when set"
+        },
+        {
+          "id": "test/config.js:26",
+          "title": "config .disabled() should default to true for prototype values"
+        }
+      ]
+    },
+    {
+      "path": "test/exports.js",
+      "sha256": "4d8389207f6b4693dc5792f79f61f719a70389fe1900c04c83ff31ef06b07001",
+      "tests": 12,
+      "cases": [
+        {
+          "id": "test/exports.js:1",
+          "title": "exports should expose Router"
+        },
+        {
+          "id": "test/exports.js:2",
+          "title": "exports should expose json middleware"
+        },
+        {
+          "id": "test/exports.js:3",
+          "title": "exports should expose raw middleware"
+        },
+        {
+          "id": "test/exports.js:4",
+          "title": "exports should expose static middleware"
+        },
+        {
+          "id": "test/exports.js:5",
+          "title": "exports should expose text middleware"
+        },
+        {
+          "id": "test/exports.js:6",
+          "title": "exports should expose urlencoded middleware"
+        },
+        {
+          "id": "test/exports.js:7",
+          "title": "exports should expose the application prototype"
+        },
+        {
+          "id": "test/exports.js:8",
+          "title": "exports should expose the request prototype"
+        },
+        {
+          "id": "test/exports.js:9",
+          "title": "exports should expose the response prototype"
+        },
+        {
+          "id": "test/exports.js:10",
+          "title": "exports should permit modifying the .application prototype"
+        },
+        {
+          "id": "test/exports.js:11",
+          "title": "exports should permit modifying the .request prototype"
+        },
+        {
+          "id": "test/exports.js:12",
+          "title": "exports should permit modifying the .response prototype"
+        }
+      ]
+    },
+    {
+      "path": "test/express.json.js",
+      "sha256": "143f7bd2d26d94725227629f0f32723471da6bd9f299c44b0191400a0c990820",
+      "tests": 60,
+      "cases": [
+        {
+          "id": "test/express.json.js:1",
+          "title": "express.json() should parse JSON"
+        },
+        {
+          "id": "test/express.json.js:2",
+          "title": "express.json() should handle Content-Length: 0"
+        },
+        {
+          "id": "test/express.json.js:3",
+          "title": "express.json() should handle empty message-body"
+        },
+        {
+          "id": "test/express.json.js:4",
+          "title": "express.json() should handle no message-body"
+        },
+        {
+          "id": "test/express.json.js:5",
+          "title": "express.json() should 400 when only whitespace"
+        },
+        {
+          "id": "test/express.json.js:6",
+          "title": "express.json() should 400 when invalid content-length"
+        },
+        {
+          "id": "test/express.json.js:7",
+          "title": "express.json() should handle duplicated middleware"
+        },
+        {
+          "id": "test/express.json.js:8",
+          "title": "express.json() when JSON is invalid should 400 for bad token"
+        },
+        {
+          "id": "test/express.json.js:9",
+          "title": "express.json() when JSON is invalid should 400 for incomplete"
+        },
+        {
+          "id": "test/express.json.js:10",
+          "title": "express.json() when JSON is invalid should include original body on error object"
+        },
+        {
+          "id": "test/express.json.js:11",
+          "title": "express.json() with limit option should 413 when over limit with Content-Length"
+        },
+        {
+          "id": "test/express.json.js:12",
+          "title": "express.json() with limit option should 413 when over limit with chunked encoding"
+        },
+        {
+          "id": "test/express.json.js:13",
+          "title": "express.json() with limit option should 413 when inflated body over limit"
+        },
+        {
+          "id": "test/express.json.js:14",
+          "title": "express.json() with limit option should accept number of bytes"
+        },
+        {
+          "id": "test/express.json.js:15",
+          "title": "express.json() with limit option should not change when options altered"
+        },
+        {
+          "id": "test/express.json.js:16",
+          "title": "express.json() with limit option should not hang response"
+        },
+        {
+          "id": "test/express.json.js:17",
+          "title": "express.json() with limit option should not error when inflating"
+        },
+        {
+          "id": "test/express.json.js:18",
+          "title": "express.json() with inflate option when false should not accept content-encoding"
+        },
+        {
+          "id": "test/express.json.js:19",
+          "title": "express.json() with inflate option when true should accept content-encoding"
+        },
+        {
+          "id": "test/express.json.js:20",
+          "title": "express.json() with strict option when undefined should 400 on primitives"
+        },
+        {
+          "id": "test/express.json.js:21",
+          "title": "express.json() with strict option when false should parse primitives"
+        },
+        {
+          "id": "test/express.json.js:22",
+          "title": "express.json() with strict option when true should not parse primitives"
+        },
+        {
+          "id": "test/express.json.js:23",
+          "title": "express.json() with strict option when true should not parse primitives with leading whitespaces"
+        },
+        {
+          "id": "test/express.json.js:24",
+          "title": "express.json() with strict option when true should allow leading whitespaces in JSON"
+        },
+        {
+          "id": "test/express.json.js:25",
+          "title": "express.json() with strict option when true should include correct message in stack trace"
+        },
+        {
+          "id": "test/express.json.js:26",
+          "title": "express.json() with type option when \"application/vnd.api+json\" should parse JSON for custom type"
+        },
+        {
+          "id": "test/express.json.js:27",
+          "title": "express.json() with type option when \"application/vnd.api+json\" should ignore standard type"
+        },
+        {
+          "id": "test/express.json.js:28",
+          "title": "express.json() with type option when [\"application/json\", \"application/vnd.api+json\"] should parse JSON for \"application/json\""
+        },
+        {
+          "id": "test/express.json.js:29",
+          "title": "express.json() with type option when [\"application/json\", \"application/vnd.api+json\"] should parse JSON for \"application/vnd.api+json\""
+        },
+        {
+          "id": "test/express.json.js:30",
+          "title": "express.json() with type option when [\"application/json\", \"application/vnd.api+json\"] should ignore \"application/x-json\""
+        },
+        {
+          "id": "test/express.json.js:31",
+          "title": "express.json() with type option when a function should parse when truthy value returned"
+        },
+        {
+          "id": "test/express.json.js:32",
+          "title": "express.json() with type option when a function should work without content-type"
+        },
+        {
+          "id": "test/express.json.js:33",
+          "title": "express.json() with type option when a function should not invoke without a body"
+        },
+        {
+          "id": "test/express.json.js:34",
+          "title": "express.json() with verify option should assert value if function"
+        },
+        {
+          "id": "test/express.json.js:35",
+          "title": "express.json() with verify option should error from verify"
+        },
+        {
+          "id": "test/express.json.js:36",
+          "title": "express.json() with verify option should allow custom codes"
+        },
+        {
+          "id": "test/express.json.js:37",
+          "title": "express.json() with verify option should allow custom type"
+        },
+        {
+          "id": "test/express.json.js:38",
+          "title": "express.json() with verify option should include original body on error object"
+        },
+        {
+          "id": "test/express.json.js:39",
+          "title": "express.json() with verify option should allow pass-through"
+        },
+        {
+          "id": "test/express.json.js:40",
+          "title": "express.json() with verify option should work with different charsets"
+        },
+        {
+          "id": "test/express.json.js:41",
+          "title": "express.json() with verify option should 415 on unknown charset prior to verify"
+        },
+        {
+          "id": "test/express.json.js:42",
+          "title": "express.json() async local storage should persist store"
+        },
+        {
+          "id": "test/express.json.js:43",
+          "title": "express.json() async local storage should persist store when unmatched content-type"
+        },
+        {
+          "id": "test/express.json.js:44",
+          "title": "express.json() async local storage should persist store when inflated"
+        },
+        {
+          "id": "test/express.json.js:45",
+          "title": "express.json() async local storage should persist store when inflate error"
+        },
+        {
+          "id": "test/express.json.js:46",
+          "title": "express.json() async local storage should persist store when parse error"
+        },
+        {
+          "id": "test/express.json.js:47",
+          "title": "express.json() async local storage should persist store when limit exceeded"
+        },
+        {
+          "id": "test/express.json.js:48",
+          "title": "express.json() charset should parse utf-8"
+        },
+        {
+          "id": "test/express.json.js:49",
+          "title": "express.json() charset should parse utf-16"
+        },
+        {
+          "id": "test/express.json.js:50",
+          "title": "express.json() charset should parse when content-length != char length"
+        },
+        {
+          "id": "test/express.json.js:51",
+          "title": "express.json() charset should default to utf-8"
+        },
+        {
+          "id": "test/express.json.js:52",
+          "title": "express.json() charset should fail on unknown charset"
+        },
+        {
+          "id": "test/express.json.js:53",
+          "title": "express.json() encoding should parse without encoding"
+        },
+        {
+          "id": "test/express.json.js:54",
+          "title": "express.json() encoding should support identity encoding"
+        },
+        {
+          "id": "test/express.json.js:55",
+          "title": "express.json() encoding should support gzip encoding"
+        },
+        {
+          "id": "test/express.json.js:56",
+          "title": "express.json() encoding should support deflate encoding"
+        },
+        {
+          "id": "test/express.json.js:57",
+          "title": "express.json() encoding should be case-insensitive"
+        },
+        {
+          "id": "test/express.json.js:58",
+          "title": "express.json() encoding should 415 on unknown encoding"
+        },
+        {
+          "id": "test/express.json.js:59",
+          "title": "express.json() encoding should 400 on malformed encoding"
+        },
+        {
+          "id": "test/express.json.js:60",
+          "title": "express.json() encoding should 413 when inflated value exceeds limit"
+        }
+      ]
+    },
+    {
+      "path": "test/express.raw.js",
+      "sha256": "453ae81d1de129ae902fbb91dbd9492897bee37e183eb93e8b2059c6d17d279b",
+      "tests": 38,
+      "cases": [
+        {
+          "id": "test/express.raw.js:1",
+          "title": "express.raw() should parse application/octet-stream"
+        },
+        {
+          "id": "test/express.raw.js:2",
+          "title": "express.raw() should 400 when invalid content-length"
+        },
+        {
+          "id": "test/express.raw.js:3",
+          "title": "express.raw() should handle Content-Length: 0"
+        },
+        {
+          "id": "test/express.raw.js:4",
+          "title": "express.raw() should handle empty message-body"
+        },
+        {
+          "id": "test/express.raw.js:5",
+          "title": "express.raw() should handle duplicated middleware"
+        },
+        {
+          "id": "test/express.raw.js:6",
+          "title": "express.raw() with limit option should 413 when over limit with Content-Length"
+        },
+        {
+          "id": "test/express.raw.js:7",
+          "title": "express.raw() with limit option should 413 when over limit with chunked encoding"
+        },
+        {
+          "id": "test/express.raw.js:8",
+          "title": "express.raw() with limit option should 413 when inflated body over limit"
+        },
+        {
+          "id": "test/express.raw.js:9",
+          "title": "express.raw() with limit option should accept number of bytes"
+        },
+        {
+          "id": "test/express.raw.js:10",
+          "title": "express.raw() with limit option should not change when options altered"
+        },
+        {
+          "id": "test/express.raw.js:11",
+          "title": "express.raw() with limit option should not hang response"
+        },
+        {
+          "id": "test/express.raw.js:12",
+          "title": "express.raw() with limit option should not error when inflating"
+        },
+        {
+          "id": "test/express.raw.js:13",
+          "title": "express.raw() with inflate option when false should not accept content-encoding"
+        },
+        {
+          "id": "test/express.raw.js:14",
+          "title": "express.raw() with inflate option when true should accept content-encoding"
+        },
+        {
+          "id": "test/express.raw.js:15",
+          "title": "express.raw() with type option when \"application/vnd+octets\" should parse for custom type"
+        },
+        {
+          "id": "test/express.raw.js:16",
+          "title": "express.raw() with type option when \"application/vnd+octets\" should ignore standard type"
+        },
+        {
+          "id": "test/express.raw.js:17",
+          "title": "express.raw() with type option when [\"application/octet-stream\", \"application/vnd+octets\"] should parse \"application/octet-stream\""
+        },
+        {
+          "id": "test/express.raw.js:18",
+          "title": "express.raw() with type option when [\"application/octet-stream\", \"application/vnd+octets\"] should parse \"application/vnd+octets\""
+        },
+        {
+          "id": "test/express.raw.js:19",
+          "title": "express.raw() with type option when [\"application/octet-stream\", \"application/vnd+octets\"] should ignore \"application/x-foo\""
+        },
+        {
+          "id": "test/express.raw.js:20",
+          "title": "express.raw() with type option when a function should parse when truthy value returned"
+        },
+        {
+          "id": "test/express.raw.js:21",
+          "title": "express.raw() with type option when a function should work without content-type"
+        },
+        {
+          "id": "test/express.raw.js:22",
+          "title": "express.raw() with type option when a function should not invoke without a body"
+        },
+        {
+          "id": "test/express.raw.js:23",
+          "title": "express.raw() with verify option should assert value is function"
+        },
+        {
+          "id": "test/express.raw.js:24",
+          "title": "express.raw() with verify option should error from verify"
+        },
+        {
+          "id": "test/express.raw.js:25",
+          "title": "express.raw() with verify option should allow custom codes"
+        },
+        {
+          "id": "test/express.raw.js:26",
+          "title": "express.raw() with verify option should allow pass-through"
+        },
+        {
+          "id": "test/express.raw.js:27",
+          "title": "express.raw() async local storage should persist store"
+        },
+        {
+          "id": "test/express.raw.js:28",
+          "title": "express.raw() async local storage should persist store when unmatched content-type"
+        },
+        {
+          "id": "test/express.raw.js:29",
+          "title": "express.raw() async local storage should persist store when inflated"
+        },
+        {
+          "id": "test/express.raw.js:30",
+          "title": "express.raw() async local storage should persist store when inflate error"
+        },
+        {
+          "id": "test/express.raw.js:31",
+          "title": "express.raw() async local storage should persist store when limit exceeded"
+        },
+        {
+          "id": "test/express.raw.js:32",
+          "title": "express.raw() charset should ignore charset"
+        },
+        {
+          "id": "test/express.raw.js:33",
+          "title": "express.raw() encoding should parse without encoding"
+        },
+        {
+          "id": "test/express.raw.js:34",
+          "title": "express.raw() encoding should support identity encoding"
+        },
+        {
+          "id": "test/express.raw.js:35",
+          "title": "express.raw() encoding should support gzip encoding"
+        },
+        {
+          "id": "test/express.raw.js:36",
+          "title": "express.raw() encoding should support deflate encoding"
+        },
+        {
+          "id": "test/express.raw.js:37",
+          "title": "express.raw() encoding should be case-insensitive"
+        },
+        {
+          "id": "test/express.raw.js:38",
+          "title": "express.raw() encoding should 415 on unknown encoding"
+        }
+      ]
+    },
+    {
+      "path": "test/express.static.js",
+      "sha256": "edbd3ac4ffd15ac2b57a9e7a0e107e68a493563de4a4c25ecb48663e85a2c5b1",
+      "tests": 90,
+      "cases": [
+        {
+          "id": "test/express.static.js:1",
+          "title": "express.static() basic operations should require root path"
+        },
+        {
+          "id": "test/express.static.js:2",
+          "title": "express.static() basic operations should require root path to be string"
+        },
+        {
+          "id": "test/express.static.js:3",
+          "title": "express.static() basic operations should serve static files"
+        },
+        {
+          "id": "test/express.static.js:4",
+          "title": "express.static() basic operations should support nesting"
+        },
+        {
+          "id": "test/express.static.js:5",
+          "title": "express.static() basic operations should set Content-Type"
+        },
+        {
+          "id": "test/express.static.js:6",
+          "title": "express.static() basic operations should set Last-Modified"
+        },
+        {
+          "id": "test/express.static.js:7",
+          "title": "express.static() basic operations should default max-age=0"
+        },
+        {
+          "id": "test/express.static.js:8",
+          "title": "express.static() basic operations should support urlencoded pathnames"
+        },
+        {
+          "id": "test/express.static.js:9",
+          "title": "express.static() basic operations should not choke on auth-looking URL"
+        },
+        {
+          "id": "test/express.static.js:10",
+          "title": "express.static() basic operations should support index.html"
+        },
+        {
+          "id": "test/express.static.js:11",
+          "title": "express.static() basic operations should support ../"
+        },
+        {
+          "id": "test/express.static.js:12",
+          "title": "express.static() basic operations should support HEAD"
+        },
+        {
+          "id": "test/express.static.js:13",
+          "title": "express.static() basic operations should skip POST requests"
+        },
+        {
+          "id": "test/express.static.js:14",
+          "title": "express.static() basic operations should support conditional requests"
+        },
+        {
+          "id": "test/express.static.js:15",
+          "title": "express.static() basic operations should support precondition checks"
+        },
+        {
+          "id": "test/express.static.js:16",
+          "title": "express.static() basic operations should serve zero-length files"
+        },
+        {
+          "id": "test/express.static.js:17",
+          "title": "express.static() basic operations should ignore hidden files"
+        },
+        {
+          "id": "test/express.static.js:18",
+          "title": "express.static() current dir should be served with \".\""
+        },
+        {
+          "id": "test/express.static.js:19",
+          "title": "express.static() acceptRanges when false should not include Accept-Ranges"
+        },
+        {
+          "id": "test/express.static.js:20",
+          "title": "express.static() acceptRanges when false should ignore Rage request header"
+        },
+        {
+          "id": "test/express.static.js:21",
+          "title": "express.static() acceptRanges when true should include Accept-Ranges"
+        },
+        {
+          "id": "test/express.static.js:22",
+          "title": "express.static() acceptRanges when true should obey Rage request header"
+        },
+        {
+          "id": "test/express.static.js:23",
+          "title": "express.static() cacheControl when false should not include Cache-Control"
+        },
+        {
+          "id": "test/express.static.js:24",
+          "title": "express.static() cacheControl when false should ignore maxAge"
+        },
+        {
+          "id": "test/express.static.js:25",
+          "title": "express.static() cacheControl when true should include Cache-Control"
+        },
+        {
+          "id": "test/express.static.js:26",
+          "title": "express.static() extensions should be not be enabled by default"
+        },
+        {
+          "id": "test/express.static.js:27",
+          "title": "express.static() extensions should be configurable"
+        },
+        {
+          "id": "test/express.static.js:28",
+          "title": "express.static() extensions should support disabling extensions"
+        },
+        {
+          "id": "test/express.static.js:29",
+          "title": "express.static() extensions should support fallbacks"
+        },
+        {
+          "id": "test/express.static.js:30",
+          "title": "express.static() extensions should 404 if nothing found"
+        },
+        {
+          "id": "test/express.static.js:31",
+          "title": "express.static() fallthrough should default to true"
+        },
+        {
+          "id": "test/express.static.js:32",
+          "title": "express.static() fallthrough when true should fall-through when OPTIONS request"
+        },
+        {
+          "id": "test/express.static.js:33",
+          "title": "express.static() fallthrough when true should fall-through when URL malformed"
+        },
+        {
+          "id": "test/express.static.js:34",
+          "title": "express.static() fallthrough when true should fall-through when traversing past root"
+        },
+        {
+          "id": "test/express.static.js:35",
+          "title": "express.static() fallthrough when true should fall-through when URL too long"
+        },
+        {
+          "id": "test/express.static.js:36",
+          "title": "express.static() fallthrough when true with redirect: true should fall-through when directory"
+        },
+        {
+          "id": "test/express.static.js:37",
+          "title": "express.static() fallthrough when true with redirect: true should redirect when directory without slash"
+        },
+        {
+          "id": "test/express.static.js:38",
+          "title": "express.static() fallthrough when true with redirect: false should fall-through when directory"
+        },
+        {
+          "id": "test/express.static.js:39",
+          "title": "express.static() fallthrough when true with redirect: false should fall-through when directory without slash"
+        },
+        {
+          "id": "test/express.static.js:40",
+          "title": "express.static() fallthrough when false should 405 when OPTIONS request"
+        },
+        {
+          "id": "test/express.static.js:41",
+          "title": "express.static() fallthrough when false should 400 when URL malformed"
+        },
+        {
+          "id": "test/express.static.js:42",
+          "title": "express.static() fallthrough when false should 403 when traversing past root"
+        },
+        {
+          "id": "test/express.static.js:43",
+          "title": "express.static() fallthrough when false should 404 when URL too long"
+        },
+        {
+          "id": "test/express.static.js:44",
+          "title": "express.static() fallthrough when false with redirect: true should 404 when directory"
+        },
+        {
+          "id": "test/express.static.js:45",
+          "title": "express.static() fallthrough when false with redirect: true should redirect when directory without slash"
+        },
+        {
+          "id": "test/express.static.js:46",
+          "title": "express.static() fallthrough when false with redirect: false should 404 when directory"
+        },
+        {
+          "id": "test/express.static.js:47",
+          "title": "express.static() fallthrough when false with redirect: false should 404 when directory without slash"
+        },
+        {
+          "id": "test/express.static.js:48",
+          "title": "express.static() hidden files should be served when dotfiles: \"allow\" is given"
+        },
+        {
+          "id": "test/express.static.js:49",
+          "title": "express.static() immutable should default to false"
+        },
+        {
+          "id": "test/express.static.js:50",
+          "title": "express.static() immutable should set immutable directive in Cache-Control"
+        },
+        {
+          "id": "test/express.static.js:51",
+          "title": "express.static() lastModified when false should not include Last-Modified"
+        },
+        {
+          "id": "test/express.static.js:52",
+          "title": "express.static() lastModified when true should include Last-Modified"
+        },
+        {
+          "id": "test/express.static.js:53",
+          "title": "express.static() maxAge should accept string"
+        },
+        {
+          "id": "test/express.static.js:54",
+          "title": "express.static() maxAge should be reasonable when infinite"
+        },
+        {
+          "id": "test/express.static.js:55",
+          "title": "express.static() redirect should redirect directories"
+        },
+        {
+          "id": "test/express.static.js:56",
+          "title": "express.static() redirect should include HTML link"
+        },
+        {
+          "id": "test/express.static.js:57",
+          "title": "express.static() redirect should redirect directories with query string"
+        },
+        {
+          "id": "test/express.static.js:58",
+          "title": "express.static() redirect should not redirect to protocol-relative locations"
+        },
+        {
+          "id": "test/express.static.js:59",
+          "title": "express.static() redirect should ensure redirect URL is properly encoded"
+        },
+        {
+          "id": "test/express.static.js:60",
+          "title": "express.static() redirect should respond with default Content-Security-Policy"
+        },
+        {
+          "id": "test/express.static.js:61",
+          "title": "express.static() redirect should not redirect incorrectly"
+        },
+        {
+          "id": "test/express.static.js:62",
+          "title": "express.static() redirect when false should disable redirect"
+        },
+        {
+          "id": "test/express.static.js:63",
+          "title": "express.static() setHeaders should reject non-functions"
+        },
+        {
+          "id": "test/express.static.js:64",
+          "title": "express.static() setHeaders should get called when sending file"
+        },
+        {
+          "id": "test/express.static.js:65",
+          "title": "express.static() setHeaders should not get called on 404"
+        },
+        {
+          "id": "test/express.static.js:66",
+          "title": "express.static() setHeaders should not get called on redirect"
+        },
+        {
+          "id": "test/express.static.js:67",
+          "title": "express.static() when traversing past root should catch urlencoded ../"
+        },
+        {
+          "id": "test/express.static.js:68",
+          "title": "express.static() when traversing past root should not allow root path disclosure"
+        },
+        {
+          "id": "test/express.static.js:69",
+          "title": "express.static() when request has \"Range\" header should support byte ranges"
+        },
+        {
+          "id": "test/express.static.js:70",
+          "title": "express.static() when request has \"Range\" header should be inclusive"
+        },
+        {
+          "id": "test/express.static.js:71",
+          "title": "express.static() when request has \"Range\" header should set Content-Range"
+        },
+        {
+          "id": "test/express.static.js:72",
+          "title": "express.static() when request has \"Range\" header should support -n"
+        },
+        {
+          "id": "test/express.static.js:73",
+          "title": "express.static() when request has \"Range\" header should support n-"
+        },
+        {
+          "id": "test/express.static.js:74",
+          "title": "express.static() when request has \"Range\" header should respond with 206 \"Partial Content\""
+        },
+        {
+          "id": "test/express.static.js:75",
+          "title": "express.static() when request has \"Range\" header should set Content-Length to the # of octets transferred"
+        },
+        {
+          "id": "test/express.static.js:76",
+          "title": "express.static() when request has \"Range\" header when last-byte-pos of the range is greater than current length is taken to be equal to one less than the current length"
+        },
+        {
+          "id": "test/express.static.js:77",
+          "title": "express.static() when request has \"Range\" header when last-byte-pos of the range is greater than current length should adapt the Content-Length accordingly"
+        },
+        {
+          "id": "test/express.static.js:78",
+          "title": "express.static() when request has \"Range\" header when the first- byte-pos of the range is greater than the current length should respond with 416"
+        },
+        {
+          "id": "test/express.static.js:79",
+          "title": "express.static() when request has \"Range\" header when the first- byte-pos of the range is greater than the current length should include a Content-Range header of complete length"
+        },
+        {
+          "id": "test/express.static.js:80",
+          "title": "express.static() when request has \"Range\" header when syntactically invalid should respond with 200 and the entire contents"
+        },
+        {
+          "id": "test/express.static.js:81",
+          "title": "express.static() when index at mount point should redirect correctly"
+        },
+        {
+          "id": "test/express.static.js:82",
+          "title": "express.static() when mounted should redirect relative to the originalUrl"
+        },
+        {
+          "id": "test/express.static.js:83",
+          "title": "express.static() when mounted should not choke on auth-looking URL"
+        },
+        {
+          "id": "test/express.static.js:84",
+          "title": "express.static() when mounted \"root\" as a file should load the file when on trailing slash"
+        },
+        {
+          "id": "test/express.static.js:85",
+          "title": "express.static() when mounted \"root\" as a file should 404 when trailing slash"
+        },
+        {
+          "id": "test/express.static.js:86",
+          "title": "express.static() when responding non-2xx or 304 should not alter the status"
+        },
+        {
+          "id": "test/express.static.js:87",
+          "title": "express.static() when index file serving disabled should next() on directory"
+        },
+        {
+          "id": "test/express.static.js:88",
+          "title": "express.static() when index file serving disabled should redirect to trailing slash"
+        },
+        {
+          "id": "test/express.static.js:89",
+          "title": "express.static() when index file serving disabled should next() on mount point"
+        },
+        {
+          "id": "test/express.static.js:90",
+          "title": "express.static() when index file serving disabled should redirect to trailing slash mount point"
+        }
+      ]
+    },
+    {
+      "path": "test/express.text.js",
+      "sha256": "2e9244502a31ae1ce18d0c16e4ee79980b25c9e8006e280351e1bfd5ecf079ce",
+      "tests": 45,
+      "cases": [
+        {
+          "id": "test/express.text.js:1",
+          "title": "express.text() should parse text/plain"
+        },
+        {
+          "id": "test/express.text.js:2",
+          "title": "express.text() should 400 when invalid content-length"
+        },
+        {
+          "id": "test/express.text.js:3",
+          "title": "express.text() should handle Content-Length: 0"
+        },
+        {
+          "id": "test/express.text.js:4",
+          "title": "express.text() should handle empty message-body"
+        },
+        {
+          "id": "test/express.text.js:5",
+          "title": "express.text() should handle duplicated middleware"
+        },
+        {
+          "id": "test/express.text.js:6",
+          "title": "express.text() with defaultCharset option should change default charset"
+        },
+        {
+          "id": "test/express.text.js:7",
+          "title": "express.text() with defaultCharset option should honor content-type charset"
+        },
+        {
+          "id": "test/express.text.js:8",
+          "title": "express.text() with limit option should 413 when over limit with Content-Length"
+        },
+        {
+          "id": "test/express.text.js:9",
+          "title": "express.text() with limit option should 413 when over limit with chunked encoding"
+        },
+        {
+          "id": "test/express.text.js:10",
+          "title": "express.text() with limit option should 413 when inflated body over limit"
+        },
+        {
+          "id": "test/express.text.js:11",
+          "title": "express.text() with limit option should accept number of bytes"
+        },
+        {
+          "id": "test/express.text.js:12",
+          "title": "express.text() with limit option should not change when options altered"
+        },
+        {
+          "id": "test/express.text.js:13",
+          "title": "express.text() with limit option should not hang response"
+        },
+        {
+          "id": "test/express.text.js:14",
+          "title": "express.text() with limit option should not error when inflating"
+        },
+        {
+          "id": "test/express.text.js:15",
+          "title": "express.text() with inflate option when false should not accept content-encoding"
+        },
+        {
+          "id": "test/express.text.js:16",
+          "title": "express.text() with inflate option when true should accept content-encoding"
+        },
+        {
+          "id": "test/express.text.js:17",
+          "title": "express.text() with type option when \"text/html\" should parse for custom type"
+        },
+        {
+          "id": "test/express.text.js:18",
+          "title": "express.text() with type option when \"text/html\" should ignore standard type"
+        },
+        {
+          "id": "test/express.text.js:19",
+          "title": "express.text() with type option when [\"text/html\", \"text/plain\"] should parse \"text/html\""
+        },
+        {
+          "id": "test/express.text.js:20",
+          "title": "express.text() with type option when [\"text/html\", \"text/plain\"] should parse \"text/plain\""
+        },
+        {
+          "id": "test/express.text.js:21",
+          "title": "express.text() with type option when [\"text/html\", \"text/plain\"] should ignore \"text/xml\""
+        },
+        {
+          "id": "test/express.text.js:22",
+          "title": "express.text() with type option when a function should parse when truthy value returned"
+        },
+        {
+          "id": "test/express.text.js:23",
+          "title": "express.text() with type option when a function should work without content-type"
+        },
+        {
+          "id": "test/express.text.js:24",
+          "title": "express.text() with type option when a function should not invoke without a body"
+        },
+        {
+          "id": "test/express.text.js:25",
+          "title": "express.text() with verify option should assert value is function"
+        },
+        {
+          "id": "test/express.text.js:26",
+          "title": "express.text() with verify option should error from verify"
+        },
+        {
+          "id": "test/express.text.js:27",
+          "title": "express.text() with verify option should allow custom codes"
+        },
+        {
+          "id": "test/express.text.js:28",
+          "title": "express.text() with verify option should allow pass-through"
+        },
+        {
+          "id": "test/express.text.js:29",
+          "title": "express.text() with verify option should 415 on unknown charset prior to verify"
+        },
+        {
+          "id": "test/express.text.js:30",
+          "title": "express.text() async local storage should persist store"
+        },
+        {
+          "id": "test/express.text.js:31",
+          "title": "express.text() async local storage should persist store when unmatched content-type"
+        },
+        {
+          "id": "test/express.text.js:32",
+          "title": "express.text() async local storage should persist store when inflated"
+        },
+        {
+          "id": "test/express.text.js:33",
+          "title": "express.text() async local storage should persist store when inflate error"
+        },
+        {
+          "id": "test/express.text.js:34",
+          "title": "express.text() async local storage should persist store when limit exceeded"
+        },
+        {
+          "id": "test/express.text.js:35",
+          "title": "express.text() charset should parse utf-8"
+        },
+        {
+          "id": "test/express.text.js:36",
+          "title": "express.text() charset should parse codepage charsets"
+        },
+        {
+          "id": "test/express.text.js:37",
+          "title": "express.text() charset should parse when content-length != char length"
+        },
+        {
+          "id": "test/express.text.js:38",
+          "title": "express.text() charset should default to utf-8"
+        },
+        {
+          "id": "test/express.text.js:39",
+          "title": "express.text() charset should 415 on unknown charset"
+        },
+        {
+          "id": "test/express.text.js:40",
+          "title": "express.text() encoding should parse without encoding"
+        },
+        {
+          "id": "test/express.text.js:41",
+          "title": "express.text() encoding should support identity encoding"
+        },
+        {
+          "id": "test/express.text.js:42",
+          "title": "express.text() encoding should support gzip encoding"
+        },
+        {
+          "id": "test/express.text.js:43",
+          "title": "express.text() encoding should support deflate encoding"
+        },
+        {
+          "id": "test/express.text.js:44",
+          "title": "express.text() encoding should be case-insensitive"
+        },
+        {
+          "id": "test/express.text.js:45",
+          "title": "express.text() encoding should 415 on unknown encoding"
+        }
+      ]
+    },
+    {
+      "path": "test/express.urlencoded.js",
+      "sha256": "dd635b20f32b600c73094695e6176cd75c59e3f8e51362a5e9245228740ed47e",
+      "tests": 68,
+      "cases": [
+        {
+          "id": "test/express.urlencoded.js:1",
+          "title": "express.urlencoded() should parse x-www-form-urlencoded"
+        },
+        {
+          "id": "test/express.urlencoded.js:2",
+          "title": "express.urlencoded() should 400 when invalid content-length"
+        },
+        {
+          "id": "test/express.urlencoded.js:3",
+          "title": "express.urlencoded() should handle Content-Length: 0"
+        },
+        {
+          "id": "test/express.urlencoded.js:4",
+          "title": "express.urlencoded() should handle empty message-body"
+        },
+        {
+          "id": "test/express.urlencoded.js:5",
+          "title": "express.urlencoded() should handle duplicated middleware"
+        },
+        {
+          "id": "test/express.urlencoded.js:6",
+          "title": "express.urlencoded() should not parse extended syntax"
+        },
+        {
+          "id": "test/express.urlencoded.js:7",
+          "title": "express.urlencoded() with extended option when false should not parse extended syntax"
+        },
+        {
+          "id": "test/express.urlencoded.js:8",
+          "title": "express.urlencoded() with extended option when false should parse multiple key instances"
+        },
+        {
+          "id": "test/express.urlencoded.js:9",
+          "title": "express.urlencoded() with extended option when true should parse multiple key instances"
+        },
+        {
+          "id": "test/express.urlencoded.js:10",
+          "title": "express.urlencoded() with extended option when true should parse extended syntax"
+        },
+        {
+          "id": "test/express.urlencoded.js:11",
+          "title": "express.urlencoded() with extended option when true should parse parameters with dots"
+        },
+        {
+          "id": "test/express.urlencoded.js:12",
+          "title": "express.urlencoded() with extended option when true should parse fully-encoded extended syntax"
+        },
+        {
+          "id": "test/express.urlencoded.js:13",
+          "title": "express.urlencoded() with extended option when true should parse array index notation"
+        },
+        {
+          "id": "test/express.urlencoded.js:14",
+          "title": "express.urlencoded() with extended option when true should parse array index notation with large array"
+        },
+        {
+          "id": "test/express.urlencoded.js:15",
+          "title": "express.urlencoded() with extended option when true should parse array of objects syntax"
+        },
+        {
+          "id": "test/express.urlencoded.js:16",
+          "title": "express.urlencoded() with extended option when true should parse deep object"
+        },
+        {
+          "id": "test/express.urlencoded.js:17",
+          "title": "express.urlencoded() with inflate option when false should not accept content-encoding"
+        },
+        {
+          "id": "test/express.urlencoded.js:18",
+          "title": "express.urlencoded() with inflate option when true should accept content-encoding"
+        },
+        {
+          "id": "test/express.urlencoded.js:19",
+          "title": "express.urlencoded() with limit option should 413 when over limit with Content-Length"
+        },
+        {
+          "id": "test/express.urlencoded.js:20",
+          "title": "express.urlencoded() with limit option should 413 when over limit with chunked encoding"
+        },
+        {
+          "id": "test/express.urlencoded.js:21",
+          "title": "express.urlencoded() with limit option should 413 when inflated body over limit"
+        },
+        {
+          "id": "test/express.urlencoded.js:22",
+          "title": "express.urlencoded() with limit option should accept number of bytes"
+        },
+        {
+          "id": "test/express.urlencoded.js:23",
+          "title": "express.urlencoded() with limit option should not change when options altered"
+        },
+        {
+          "id": "test/express.urlencoded.js:24",
+          "title": "express.urlencoded() with limit option should not hang response"
+        },
+        {
+          "id": "test/express.urlencoded.js:25",
+          "title": "express.urlencoded() with limit option should not error when inflating"
+        },
+        {
+          "id": "test/express.urlencoded.js:26",
+          "title": "express.urlencoded() with parameterLimit option with extended: false should reject 0"
+        },
+        {
+          "id": "test/express.urlencoded.js:27",
+          "title": "express.urlencoded() with parameterLimit option with extended: false should reject string"
+        },
+        {
+          "id": "test/express.urlencoded.js:28",
+          "title": "express.urlencoded() with parameterLimit option with extended: false should 413 if over limit"
+        },
+        {
+          "id": "test/express.urlencoded.js:29",
+          "title": "express.urlencoded() with parameterLimit option with extended: false should work when at the limit"
+        },
+        {
+          "id": "test/express.urlencoded.js:30",
+          "title": "express.urlencoded() with parameterLimit option with extended: false should work if number is floating point"
+        },
+        {
+          "id": "test/express.urlencoded.js:31",
+          "title": "express.urlencoded() with parameterLimit option with extended: false should work with large limit"
+        },
+        {
+          "id": "test/express.urlencoded.js:32",
+          "title": "express.urlencoded() with parameterLimit option with extended: false should work with Infinity limit"
+        },
+        {
+          "id": "test/express.urlencoded.js:33",
+          "title": "express.urlencoded() with parameterLimit option with extended: true should reject 0"
+        },
+        {
+          "id": "test/express.urlencoded.js:34",
+          "title": "express.urlencoded() with parameterLimit option with extended: true should reject string"
+        },
+        {
+          "id": "test/express.urlencoded.js:35",
+          "title": "express.urlencoded() with parameterLimit option with extended: true should 413 if over limit"
+        },
+        {
+          "id": "test/express.urlencoded.js:36",
+          "title": "express.urlencoded() with parameterLimit option with extended: true should work when at the limit"
+        },
+        {
+          "id": "test/express.urlencoded.js:37",
+          "title": "express.urlencoded() with parameterLimit option with extended: true should work if number is floating point"
+        },
+        {
+          "id": "test/express.urlencoded.js:38",
+          "title": "express.urlencoded() with parameterLimit option with extended: true should work with large limit"
+        },
+        {
+          "id": "test/express.urlencoded.js:39",
+          "title": "express.urlencoded() with parameterLimit option with extended: true should work with Infinity limit"
+        },
+        {
+          "id": "test/express.urlencoded.js:40",
+          "title": "express.urlencoded() with type option when \"application/vnd.x-www-form-urlencoded\" should parse for custom type"
+        },
+        {
+          "id": "test/express.urlencoded.js:41",
+          "title": "express.urlencoded() with type option when \"application/vnd.x-www-form-urlencoded\" should ignore standard type"
+        },
+        {
+          "id": "test/express.urlencoded.js:42",
+          "title": "express.urlencoded() with type option when [\"urlencoded\", \"application/x-pairs\"] should parse \"application/x-www-form-urlencoded\""
+        },
+        {
+          "id": "test/express.urlencoded.js:43",
+          "title": "express.urlencoded() with type option when [\"urlencoded\", \"application/x-pairs\"] should parse \"application/x-pairs\""
+        },
+        {
+          "id": "test/express.urlencoded.js:44",
+          "title": "express.urlencoded() with type option when [\"urlencoded\", \"application/x-pairs\"] should ignore application/x-foo"
+        },
+        {
+          "id": "test/express.urlencoded.js:45",
+          "title": "express.urlencoded() with type option when a function should parse when truthy value returned"
+        },
+        {
+          "id": "test/express.urlencoded.js:46",
+          "title": "express.urlencoded() with type option when a function should work without content-type"
+        },
+        {
+          "id": "test/express.urlencoded.js:47",
+          "title": "express.urlencoded() with type option when a function should not invoke without a body"
+        },
+        {
+          "id": "test/express.urlencoded.js:48",
+          "title": "express.urlencoded() with verify option should assert value if function"
+        },
+        {
+          "id": "test/express.urlencoded.js:49",
+          "title": "express.urlencoded() with verify option should error from verify"
+        },
+        {
+          "id": "test/express.urlencoded.js:50",
+          "title": "express.urlencoded() with verify option should allow custom codes"
+        },
+        {
+          "id": "test/express.urlencoded.js:51",
+          "title": "express.urlencoded() with verify option should allow custom type"
+        },
+        {
+          "id": "test/express.urlencoded.js:52",
+          "title": "express.urlencoded() with verify option should allow pass-through"
+        },
+        {
+          "id": "test/express.urlencoded.js:53",
+          "title": "express.urlencoded() with verify option should 415 on unknown charset prior to verify"
+        },
+        {
+          "id": "test/express.urlencoded.js:54",
+          "title": "express.urlencoded() async local storage should persist store"
+        },
+        {
+          "id": "test/express.urlencoded.js:55",
+          "title": "express.urlencoded() async local storage should persist store when unmatched content-type"
+        },
+        {
+          "id": "test/express.urlencoded.js:56",
+          "title": "express.urlencoded() async local storage should persist store when inflated"
+        },
+        {
+          "id": "test/express.urlencoded.js:57",
+          "title": "express.urlencoded() async local storage should persist store when inflate error"
+        },
+        {
+          "id": "test/express.urlencoded.js:58",
+          "title": "express.urlencoded() async local storage should persist store when limit exceeded"
+        },
+        {
+          "id": "test/express.urlencoded.js:59",
+          "title": "express.urlencoded() charset should parse utf-8"
+        },
+        {
+          "id": "test/express.urlencoded.js:60",
+          "title": "express.urlencoded() charset should parse when content-length != char length"
+        },
+        {
+          "id": "test/express.urlencoded.js:61",
+          "title": "express.urlencoded() charset should default to utf-8"
+        },
+        {
+          "id": "test/express.urlencoded.js:62",
+          "title": "express.urlencoded() charset should fail on unknown charset"
+        },
+        {
+          "id": "test/express.urlencoded.js:63",
+          "title": "express.urlencoded() encoding should parse without encoding"
+        },
+        {
+          "id": "test/express.urlencoded.js:64",
+          "title": "express.urlencoded() encoding should support identity encoding"
+        },
+        {
+          "id": "test/express.urlencoded.js:65",
+          "title": "express.urlencoded() encoding should support gzip encoding"
+        },
+        {
+          "id": "test/express.urlencoded.js:66",
+          "title": "express.urlencoded() encoding should support deflate encoding"
+        },
+        {
+          "id": "test/express.urlencoded.js:67",
+          "title": "express.urlencoded() encoding should be case-insensitive"
+        },
+        {
+          "id": "test/express.urlencoded.js:68",
+          "title": "express.urlencoded() encoding should 415 on unknown encoding"
+        }
+      ]
+    },
+    {
+      "path": "test/middleware.basic.js",
+      "sha256": "eb08ba656fa64c5a428879b6487dce31f7e4c993529a1b660a208d4f80ca13cc",
+      "tests": 1,
+      "cases": [
+        {
+          "id": "test/middleware.basic.js:1",
+          "title": "middleware .next() should behave like connect"
+        }
+      ]
+    },
+    {
+      "path": "test/regression.js",
+      "sha256": "030464330427a72e495502b7d28e4192f8c364348ccccb4c3ea82f5dc4e64383",
+      "tests": 1,
+      "cases": [
+        {
+          "id": "test/regression.js:1",
+          "title": "throw after .end() should fail gracefully"
+        }
+      ]
+    },
+    {
+      "path": "test/req.accepts.js",
+      "sha256": "80bd6f4700f6a28a837bc42f7284b9830c178591d472fd589297cb26c863f5e5",
+      "tests": 9,
+      "cases": [
+        {
+          "id": "test/req.accepts.js:1",
+          "title": "req should accept an argument list of type names"
+        },
+        {
+          "id": "test/req.accepts.js:2",
+          "title": "req .accepts(type) should return true when Accept is not present"
+        },
+        {
+          "id": "test/req.accepts.js:3",
+          "title": "req .accepts(type) should return true when present"
+        },
+        {
+          "id": "test/req.accepts.js:4",
+          "title": "req .accepts(type) should return false otherwise"
+        },
+        {
+          "id": "test/req.accepts.js:5",
+          "title": "req .accepts(types) should return the first when Accept is not present"
+        },
+        {
+          "id": "test/req.accepts.js:6",
+          "title": "req .accepts(types) should return the first acceptable type"
+        },
+        {
+          "id": "test/req.accepts.js:7",
+          "title": "req .accepts(types) should return false when no match is made"
+        },
+        {
+          "id": "test/req.accepts.js:8",
+          "title": "req .accepts(types) should take quality into account"
+        },
+        {
+          "id": "test/req.accepts.js:9",
+          "title": "req .accepts(types) should return the first acceptable type with canonical mime types"
+        }
+      ]
+    },
+    {
+      "path": "test/req.acceptsCharsets.js",
+      "sha256": "a071399dc5b72428634b8088aac4a3cf1b5744ef828c1201222dbb5a4f236c09",
+      "tests": 4,
+      "cases": [
+        {
+          "id": "test/req.acceptsCharsets.js:1",
+          "title": "req .acceptsCharsets(type) when Accept-Charset is not present should return true"
+        },
+        {
+          "id": "test/req.acceptsCharsets.js:2",
+          "title": "req .acceptsCharsets(type) when Accept-Charset is present should return true"
+        },
+        {
+          "id": "test/req.acceptsCharsets.js:3",
+          "title": "req .acceptsCharsets(type) when Accept-Charset is present should return false otherwise"
+        },
+        {
+          "id": "test/req.acceptsCharsets.js:4",
+          "title": "req .acceptsCharsets(type) when Accept-Charset is present should return the best matching charset from multiple inputs"
+        }
+      ]
+    },
+    {
+      "path": "test/req.acceptsEncodings.js",
+      "sha256": "bd2c58a5435926db2bdb39640c3e967e7953e752b1baddc3e33be84de547fa8a",
+      "tests": 2,
+      "cases": [
+        {
+          "id": "test/req.acceptsEncodings.js:1",
+          "title": "req .acceptsEncodings should return encoding if accepted"
+        },
+        {
+          "id": "test/req.acceptsEncodings.js:2",
+          "title": "req .acceptsEncodings should be false if encoding not accepted"
+        }
+      ]
+    },
+    {
+      "path": "test/req.acceptsLanguages.js",
+      "sha256": "93a795aa224ac42f700fd0479be32399d097903dcdc482b9e30f70ddd607d44f",
+      "tests": 3,
+      "cases": [
+        {
+          "id": "test/req.acceptsLanguages.js:1",
+          "title": "req .acceptsLanguages should return language if accepted"
+        },
+        {
+          "id": "test/req.acceptsLanguages.js:2",
+          "title": "req .acceptsLanguages should be false if language not accepted"
+        },
+        {
+          "id": "test/req.acceptsLanguages.js:3",
+          "title": "req .acceptsLanguages when Accept-Language is not present should always return language"
+        }
+      ]
+    },
+    {
+      "path": "test/req.baseUrl.js",
+      "sha256": "e20c9aa41f9e1cad5676ab4df70412be4847a20b9473947eba3e09849bd66810",
+      "tests": 4,
+      "cases": [
+        {
+          "id": "test/req.baseUrl.js:1",
+          "title": "req .baseUrl should be empty for top-level route"
+        },
+        {
+          "id": "test/req.baseUrl.js:2",
+          "title": "req .baseUrl should contain lower path"
+        },
+        {
+          "id": "test/req.baseUrl.js:3",
+          "title": "req .baseUrl should contain full lower path"
+        },
+        {
+          "id": "test/req.baseUrl.js:4",
+          "title": "req .baseUrl should travel through routers correctly"
+        }
+      ]
+    },
+    {
+      "path": "test/req.fresh.js",
+      "sha256": "1ccf13c5b51568bd08b884e60c945abd1b72ca8e2af4b5e0218c00460f5c997e",
+      "tests": 6,
+      "cases": [
+        {
+          "id": "test/req.fresh.js:1",
+          "title": "req .fresh should return true when the resource is not modified"
+        },
+        {
+          "id": "test/req.fresh.js:2",
+          "title": "req .fresh should return false when the resource is modified"
+        },
+        {
+          "id": "test/req.fresh.js:3",
+          "title": "req .fresh should return false without response headers"
+        },
+        {
+          "id": "test/req.fresh.js:4",
+          "title": "req .fresh should return true for a QUERY request with a body when the resource is not modified"
+        },
+        {
+          "id": "test/req.fresh.js:5",
+          "title": "req .fresh should return false for a QUERY request with a body when the resource is modified"
+        },
+        {
+          "id": "test/req.fresh.js:6",
+          "title": "req .fresh should ignore \"If-Modified-Since\" when \"If-None-Match\" is present"
+        }
+      ]
+    },
+    {
+      "path": "test/req.get.js",
+      "sha256": "49e423b6803afffbf996f619c4213f98099b201c0c2ec75feb1ba8acf604deb7",
+      "tests": 4,
+      "cases": [
+        {
+          "id": "test/req.get.js:1",
+          "title": "req .get(field) should return the header field value"
+        },
+        {
+          "id": "test/req.get.js:2",
+          "title": "req .get(field) should special-case Referer"
+        },
+        {
+          "id": "test/req.get.js:3",
+          "title": "req .get(field) should throw missing header name"
+        },
+        {
+          "id": "test/req.get.js:4",
+          "title": "req .get(field) should throw for non-string header name"
+        }
+      ]
+    },
+    {
+      "path": "test/req.host.js",
+      "sha256": "350982925a8a874537d14dd6d628888d01a59643a2993300c6fd0eb458987501",
+      "tests": 10,
+      "cases": [
+        {
+          "id": "test/req.host.js:1",
+          "title": "req .host should return the Host when present"
+        },
+        {
+          "id": "test/req.host.js:2",
+          "title": "req .host should strip port number"
+        },
+        {
+          "id": "test/req.host.js:3",
+          "title": "req .host should return undefined otherwise"
+        },
+        {
+          "id": "test/req.host.js:4",
+          "title": "req .host should work with IPv6 Host"
+        },
+        {
+          "id": "test/req.host.js:5",
+          "title": "req .host should work with IPv6 Host and port"
+        },
+        {
+          "id": "test/req.host.js:6",
+          "title": "req .host when \"trust proxy\" is enabled should respect X-Forwarded-Host"
+        },
+        {
+          "id": "test/req.host.js:7",
+          "title": "req .host when \"trust proxy\" is enabled should ignore X-Forwarded-Host if socket addr not trusted"
+        },
+        {
+          "id": "test/req.host.js:8",
+          "title": "req .host when \"trust proxy\" is enabled should default to Host"
+        },
+        {
+          "id": "test/req.host.js:9",
+          "title": "req .host when \"trust proxy\" is enabled when trusting hop count should respect X-Forwarded-Host"
+        },
+        {
+          "id": "test/req.host.js:10",
+          "title": "req .host when \"trust proxy\" is disabled should ignore X-Forwarded-Host"
+        }
+      ]
+    },
+    {
+      "path": "test/req.hostname.js",
+      "sha256": "882dcbca78105b0de0abf8b329319dbee798897c99e301dced6516d54411e873",
+      "tests": 12,
+      "cases": [
+        {
+          "id": "test/req.hostname.js:1",
+          "title": "req .hostname should return the Host when present"
+        },
+        {
+          "id": "test/req.hostname.js:2",
+          "title": "req .hostname should strip port number"
+        },
+        {
+          "id": "test/req.hostname.js:3",
+          "title": "req .hostname should return undefined otherwise"
+        },
+        {
+          "id": "test/req.hostname.js:4",
+          "title": "req .hostname should work with IPv6 Host"
+        },
+        {
+          "id": "test/req.hostname.js:5",
+          "title": "req .hostname should work with IPv6 Host and port"
+        },
+        {
+          "id": "test/req.hostname.js:6",
+          "title": "req .hostname when \"trust proxy\" is enabled should respect X-Forwarded-Host"
+        },
+        {
+          "id": "test/req.hostname.js:7",
+          "title": "req .hostname when \"trust proxy\" is enabled should ignore X-Forwarded-Host if socket addr not trusted"
+        },
+        {
+          "id": "test/req.hostname.js:8",
+          "title": "req .hostname when \"trust proxy\" is enabled should default to Host"
+        },
+        {
+          "id": "test/req.hostname.js:9",
+          "title": "req .hostname when \"trust proxy\" is enabled when multiple X-Forwarded-Host should use the first value"
+        },
+        {
+          "id": "test/req.hostname.js:10",
+          "title": "req .hostname when \"trust proxy\" is enabled when multiple X-Forwarded-Host should remove OWS around comma"
+        },
+        {
+          "id": "test/req.hostname.js:11",
+          "title": "req .hostname when \"trust proxy\" is enabled when multiple X-Forwarded-Host should strip port number"
+        },
+        {
+          "id": "test/req.hostname.js:12",
+          "title": "req .hostname when \"trust proxy\" is disabled should ignore X-Forwarded-Host"
+        }
+      ]
+    },
+    {
+      "path": "test/req.ip.js",
+      "sha256": "053fbbd6ee2aa3b5b81b3af8b9375797825b952a91d78d29ebb688119d372bbe",
+      "tests": 6,
+      "cases": [
+        {
+          "id": "test/req.ip.js:1",
+          "title": "req .ip when X-Forwarded-For is present when \"trust proxy\" is enabled should return the client addr"
+        },
+        {
+          "id": "test/req.ip.js:2",
+          "title": "req .ip when X-Forwarded-For is present when \"trust proxy\" is enabled should return the addr after trusted proxy based on count"
+        },
+        {
+          "id": "test/req.ip.js:3",
+          "title": "req .ip when X-Forwarded-For is present when \"trust proxy\" is enabled should return the addr after trusted proxy based on list"
+        },
+        {
+          "id": "test/req.ip.js:4",
+          "title": "req .ip when X-Forwarded-For is present when \"trust proxy\" is enabled should return the addr after trusted proxy, from sub app"
+        },
+        {
+          "id": "test/req.ip.js:5",
+          "title": "req .ip when X-Forwarded-For is present when \"trust proxy\" is disabled should return the remote address"
+        },
+        {
+          "id": "test/req.ip.js:6",
+          "title": "req .ip when X-Forwarded-For is not present should return the remote address"
+        }
+      ]
+    },
+    {
+      "path": "test/req.ips.js",
+      "sha256": "f14aaa30756b15f3ce8604e3b0dec162c4b008c4bf9eb538b35f13878dfec3d4",
+      "tests": 4,
+      "cases": [
+        {
+          "id": "test/req.ips.js:1",
+          "title": "req .ips when X-Forwarded-For is present when \"trust proxy\" is enabled should return an array of the specified addresses"
+        },
+        {
+          "id": "test/req.ips.js:2",
+          "title": "req .ips when X-Forwarded-For is present when \"trust proxy\" is enabled should stop at first untrusted"
+        },
+        {
+          "id": "test/req.ips.js:3",
+          "title": "req .ips when X-Forwarded-For is present when \"trust proxy\" is disabled should return an empty array"
+        },
+        {
+          "id": "test/req.ips.js:4",
+          "title": "req .ips when X-Forwarded-For is not present should return []"
+        }
+      ]
+    },
+    {
+      "path": "test/req.is.js",
+      "sha256": "c348305f45be8c307c1bbc1d49044e53336535ad6c151fc028e668a48d80b1d7",
+      "tests": 11,
+      "cases": [
+        {
+          "id": "test/req.is.js:1",
+          "title": "req.is() when given a mime type should return the type when matching"
+        },
+        {
+          "id": "test/req.is.js:2",
+          "title": "req.is() when given a mime type should return false when not matching"
+        },
+        {
+          "id": "test/req.is.js:3",
+          "title": "req.is() when given a mime type should ignore charset"
+        },
+        {
+          "id": "test/req.is.js:4",
+          "title": "req.is() when content-type is not present should return false"
+        },
+        {
+          "id": "test/req.is.js:5",
+          "title": "req.is() when given an extension should lookup the mime type"
+        },
+        {
+          "id": "test/req.is.js:6",
+          "title": "req.is() when given */subtype should return the full type when matching"
+        },
+        {
+          "id": "test/req.is.js:7",
+          "title": "req.is() when given */subtype should return false when not matching"
+        },
+        {
+          "id": "test/req.is.js:8",
+          "title": "req.is() when given */subtype should ignore charset"
+        },
+        {
+          "id": "test/req.is.js:9",
+          "title": "req.is() when given type/* should return the full type when matching"
+        },
+        {
+          "id": "test/req.is.js:10",
+          "title": "req.is() when given type/* should return false when not matching"
+        },
+        {
+          "id": "test/req.is.js:11",
+          "title": "req.is() when given type/* should ignore charset"
+        }
+      ]
+    },
+    {
+      "path": "test/req.path.js",
+      "sha256": "a5086d758464bff1c620e8042ea8cf961d81d1522193b70db3045a9cda78a706",
+      "tests": 1,
+      "cases": [
+        {
+          "id": "test/req.path.js:1",
+          "title": "req .path should return the parsed pathname"
+        }
+      ]
+    },
+    {
+      "path": "test/req.protocol.js",
+      "sha256": "95ade060958d64c6981c1a138f33628040293acaee094d93728fe84eaa9a8a3d",
+      "tests": 7,
+      "cases": [
+        {
+          "id": "test/req.protocol.js:1",
+          "title": "req .protocol should return the protocol string"
+        },
+        {
+          "id": "test/req.protocol.js:2",
+          "title": "req .protocol when \"trust proxy\" is enabled should respect X-Forwarded-Proto"
+        },
+        {
+          "id": "test/req.protocol.js:3",
+          "title": "req .protocol when \"trust proxy\" is enabled should default to the socket addr if X-Forwarded-Proto not present"
+        },
+        {
+          "id": "test/req.protocol.js:4",
+          "title": "req .protocol when \"trust proxy\" is enabled should ignore X-Forwarded-Proto if socket addr not trusted"
+        },
+        {
+          "id": "test/req.protocol.js:5",
+          "title": "req .protocol when \"trust proxy\" is enabled should default to http"
+        },
+        {
+          "id": "test/req.protocol.js:6",
+          "title": "req .protocol when \"trust proxy\" is enabled when trusting hop count should respect X-Forwarded-Proto"
+        },
+        {
+          "id": "test/req.protocol.js:7",
+          "title": "req .protocol when \"trust proxy\" is disabled should ignore X-Forwarded-Proto"
+        }
+      ]
+    },
+    {
+      "path": "test/req.query.js",
+      "sha256": "6d9feadd594e81f5ea9d9091152f50f6845a2bd4b9f6296baf188713f5deb40d",
+      "tests": 9,
+      "cases": [
+        {
+          "id": "test/req.query.js:1",
+          "title": "req .query should default to {}"
+        },
+        {
+          "id": "test/req.query.js:2",
+          "title": "req .query should default to parse simple keys"
+        },
+        {
+          "id": "test/req.query.js:3",
+          "title": "req .query when \"query parser\" is extended should parse complex keys"
+        },
+        {
+          "id": "test/req.query.js:4",
+          "title": "req .query when \"query parser\" is extended should parse parameters with dots"
+        },
+        {
+          "id": "test/req.query.js:5",
+          "title": "req .query when \"query parser\" is simple should not parse complex keys"
+        },
+        {
+          "id": "test/req.query.js:6",
+          "title": "req .query when \"query parser\" is a function should parse using function"
+        },
+        {
+          "id": "test/req.query.js:7",
+          "title": "req .query when \"query parser\" disabled should not parse query"
+        },
+        {
+          "id": "test/req.query.js:8",
+          "title": "req .query when \"query parser\" enabled should not parse complex keys"
+        },
+        {
+          "id": "test/req.query.js:9",
+          "title": "req .query when \"query parser\" an unknown value should throw"
+        }
+      ]
+    },
+    {
+      "path": "test/req.range.js",
+      "sha256": "263ed06eebe97323c116cde572c68a749a6183cc4c493cfeb0a32af4919e837d",
+      "tests": 7,
+      "cases": [
+        {
+          "id": "test/req.range.js:1",
+          "title": "req .range(size) should return parsed ranges"
+        },
+        {
+          "id": "test/req.range.js:2",
+          "title": "req .range(size) should cap to the given size"
+        },
+        {
+          "id": "test/req.range.js:3",
+          "title": "req .range(size) should cap to the given size when open-ended"
+        },
+        {
+          "id": "test/req.range.js:4",
+          "title": "req .range(size) should have a .type"
+        },
+        {
+          "id": "test/req.range.js:5",
+          "title": "req .range(size) should accept any type"
+        },
+        {
+          "id": "test/req.range.js:6",
+          "title": "req .range(size) should return undefined if no range"
+        },
+        {
+          "id": "test/req.range.js:7",
+          "title": "req .range(size, options) with \"combine: true\" option should return combined ranges"
+        }
+      ]
+    },
+    {
+      "path": "test/req.route.js",
+      "sha256": "ffdc76eb77441c81d5815000269de19e3dcb83565fb378b756b2d9fad62f1bd3",
+      "tests": 1,
+      "cases": [
+        {
+          "id": "test/req.route.js:1",
+          "title": "req .route should be the executed Route"
+        }
+      ]
+    },
+    {
+      "path": "test/req.secure.js",
+      "sha256": "ab1b40856ef99e44d022243a50a9ee71a8ccc926abfa05a64358cd09055e2b39",
+      "tests": 6,
+      "cases": [
+        {
+          "id": "test/req.secure.js:1",
+          "title": "req .secure when X-Forwarded-Proto is missing should return false when http"
+        },
+        {
+          "id": "test/req.secure.js:2",
+          "title": "req .secure when X-Forwarded-Proto is present should return false when http"
+        },
+        {
+          "id": "test/req.secure.js:3",
+          "title": "req .secure when X-Forwarded-Proto is present should return true when \"trust proxy\" is enabled"
+        },
+        {
+          "id": "test/req.secure.js:4",
+          "title": "req .secure when X-Forwarded-Proto is present should return false when initial proxy is http"
+        },
+        {
+          "id": "test/req.secure.js:5",
+          "title": "req .secure when X-Forwarded-Proto is present should return true when initial proxy is https"
+        },
+        {
+          "id": "test/req.secure.js:6",
+          "title": "req .secure when X-Forwarded-Proto is present when \"trust proxy\" trusting hop count should respect X-Forwarded-Proto"
+        }
+      ]
+    },
+    {
+      "path": "test/req.signedCookies.js",
+      "sha256": "f4cf63e15d459f7c418221564be4c5630785c0029b3fafd39349f731c4b62faa",
+      "tests": 1,
+      "cases": [
+        {
+          "id": "test/req.signedCookies.js:1",
+          "title": "req .signedCookies should return a signed JSON cookie"
+        }
+      ]
+    },
+    {
+      "path": "test/req.stale.js",
+      "sha256": "a7e5835111913aa59bd17244e2afb6756764e4102aea77097980ebadc1123eee",
+      "tests": 3,
+      "cases": [
+        {
+          "id": "test/req.stale.js:1",
+          "title": "req .stale should return false when the resource is not modified"
+        },
+        {
+          "id": "test/req.stale.js:2",
+          "title": "req .stale should return true when the resource is modified"
+        },
+        {
+          "id": "test/req.stale.js:3",
+          "title": "req .stale should return true without response headers"
+        }
+      ]
+    },
+    {
+      "path": "test/req.subdomains.js",
+      "sha256": "b06fc91e7a90eb5ed5a0f68273ae28fc9094d49da29ae5f8fce9efa1b1f8b822",
+      "tests": 11,
+      "cases": [
+        {
+          "id": "test/req.subdomains.js:1",
+          "title": "req .subdomains when present should return an array"
+        },
+        {
+          "id": "test/req.subdomains.js:2",
+          "title": "req .subdomains when present should work with IPv4 address"
+        },
+        {
+          "id": "test/req.subdomains.js:3",
+          "title": "req .subdomains when present should work with IPv6 address"
+        },
+        {
+          "id": "test/req.subdomains.js:4",
+          "title": "req .subdomains otherwise should return an empty array"
+        },
+        {
+          "id": "test/req.subdomains.js:5",
+          "title": "req .subdomains with no host should return an empty array"
+        },
+        {
+          "id": "test/req.subdomains.js:6",
+          "title": "req .subdomains with trusted X-Forwarded-Host should return an array"
+        },
+        {
+          "id": "test/req.subdomains.js:7",
+          "title": "req .subdomains when subdomain offset is set when subdomain offset is zero should return an array with the whole domain"
+        },
+        {
+          "id": "test/req.subdomains.js:8",
+          "title": "req .subdomains when subdomain offset is set when subdomain offset is zero should return an array with the whole IPv4"
+        },
+        {
+          "id": "test/req.subdomains.js:9",
+          "title": "req .subdomains when subdomain offset is set when subdomain offset is zero should return an array with the whole IPv6"
+        },
+        {
+          "id": "test/req.subdomains.js:10",
+          "title": "req .subdomains when subdomain offset is set when present should return an array"
+        },
+        {
+          "id": "test/req.subdomains.js:11",
+          "title": "req .subdomains when subdomain offset is set otherwise should return an empty array"
+        }
+      ]
+    },
+    {
+      "path": "test/req.xhr.js",
+      "sha256": "c63968e22ea15512686a4a81acf5529f4e62fdeed3896bcd2d6456371f8b1f2b",
+      "tests": 4,
+      "cases": [
+        {
+          "id": "test/req.xhr.js:1",
+          "title": "req .xhr should return true when X-Requested-With is xmlhttprequest"
+        },
+        {
+          "id": "test/req.xhr.js:2",
+          "title": "req .xhr should case-insensitive"
+        },
+        {
+          "id": "test/req.xhr.js:3",
+          "title": "req .xhr should return false otherwise"
+        },
+        {
+          "id": "test/req.xhr.js:4",
+          "title": "req .xhr should return false when not present"
+        }
+      ]
+    },
+    {
+      "path": "test/res.append.js",
+      "sha256": "35f0e842b50fef2ed332de2bc48e74bc16c17f8eeafbe6505c3977b36f5516fe",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/res.append.js:1",
+          "title": "res .append(field, val) should append multiple headers"
+        },
+        {
+          "id": "test/res.append.js:2",
+          "title": "res .append(field, val) should accept array of values"
+        },
+        {
+          "id": "test/res.append.js:3",
+          "title": "res .append(field, val) should get reset by res.set(field, val)"
+        },
+        {
+          "id": "test/res.append.js:4",
+          "title": "res .append(field, val) should work with res.set(field, val) first"
+        },
+        {
+          "id": "test/res.append.js:5",
+          "title": "res .append(field, val) should work together with res.cookie"
+        }
+      ]
+    },
+    {
+      "path": "test/res.attachment.js",
+      "sha256": "a4de6e96ca9b3cb951b589ea02abfcfa4d9c065e71ca000e36c51d2e5304f968",
+      "tests": 8,
+      "cases": [
+        {
+          "id": "test/res.attachment.js:1",
+          "title": "res .attachment() should Content-Disposition to attachment"
+        },
+        {
+          "id": "test/res.attachment.js:2",
+          "title": "res .attachment(filename) should add the filename param"
+        },
+        {
+          "id": "test/res.attachment.js:3",
+          "title": "res .attachment(filename) should quote file names that are not a valid token"
+        },
+        {
+          "id": "test/res.attachment.js:4",
+          "title": "res .attachment(filename) should handle an empty file name"
+        },
+        {
+          "id": "test/res.attachment.js:5",
+          "title": "res .attachment(filename) should set the Content-Type"
+        },
+        {
+          "id": "test/res.attachment.js:6",
+          "title": "res .attachment(utf8filename) should add the filename and filename* params"
+        },
+        {
+          "id": "test/res.attachment.js:7",
+          "title": "res .attachment(utf8filename) should encode latin1 file names with an ASCII fallback and filename* param"
+        },
+        {
+          "id": "test/res.attachment.js:8",
+          "title": "res .attachment(utf8filename) should set the Content-Type"
+        }
+      ]
+    },
+    {
+      "path": "test/res.clearCookie.js",
+      "sha256": "83d883aebfb0e17d1d9fb864c1a52599d1070b2d45af7f9b591acad3ca614882",
+      "tests": 4,
+      "cases": [
+        {
+          "id": "test/res.clearCookie.js:1",
+          "title": "res .clearCookie(name) should set a cookie passed expiry"
+        },
+        {
+          "id": "test/res.clearCookie.js:2",
+          "title": "res .clearCookie(name, options) should set the given params"
+        },
+        {
+          "id": "test/res.clearCookie.js:3",
+          "title": "res .clearCookie(name, options) should ignore maxAge"
+        },
+        {
+          "id": "test/res.clearCookie.js:4",
+          "title": "res .clearCookie(name, options) should ignore user supplied expires param"
+        }
+      ]
+    },
+    {
+      "path": "test/res.cookie.js",
+      "sha256": "97604da5a7e511d981121189bce161d4112557da9d7c26cbf33155330c7ca137",
+      "tests": 19,
+      "cases": [
+        {
+          "id": "test/res.cookie.js:1",
+          "title": "res .cookie(name, object) should generate a JSON cookie"
+        },
+        {
+          "id": "test/res.cookie.js:2",
+          "title": "res .cookie(name, string) should set a cookie"
+        },
+        {
+          "id": "test/res.cookie.js:3",
+          "title": "res .cookie(name, string) should allow multiple calls"
+        },
+        {
+          "id": "test/res.cookie.js:4",
+          "title": "res .cookie(name, string, options) should set params"
+        },
+        {
+          "id": "test/res.cookie.js:5",
+          "title": "res .cookie(name, string, options) expires should throw on invalid date"
+        },
+        {
+          "id": "test/res.cookie.js:6",
+          "title": "res .cookie(name, string, options) partitioned should set partitioned"
+        },
+        {
+          "id": "test/res.cookie.js:7",
+          "title": "res .cookie(name, string, options) maxAge should set relative expires"
+        },
+        {
+          "id": "test/res.cookie.js:8",
+          "title": "res .cookie(name, string, options) maxAge should set max-age"
+        },
+        {
+          "id": "test/res.cookie.js:9",
+          "title": "res .cookie(name, string, options) maxAge should not mutate the options object"
+        },
+        {
+          "id": "test/res.cookie.js:10",
+          "title": "res .cookie(name, string, options) maxAge should not throw on null"
+        },
+        {
+          "id": "test/res.cookie.js:11",
+          "title": "res .cookie(name, string, options) maxAge should not throw on undefined"
+        },
+        {
+          "id": "test/res.cookie.js:12",
+          "title": "res .cookie(name, string, options) maxAge should throw an error with invalid maxAge"
+        },
+        {
+          "id": "test/res.cookie.js:13",
+          "title": "res .cookie(name, string, options) priority should set low priority"
+        },
+        {
+          "id": "test/res.cookie.js:14",
+          "title": "res .cookie(name, string, options) priority should set medium priority"
+        },
+        {
+          "id": "test/res.cookie.js:15",
+          "title": "res .cookie(name, string, options) priority should set high priority"
+        },
+        {
+          "id": "test/res.cookie.js:16",
+          "title": "res .cookie(name, string, options) priority should throw with invalid priority"
+        },
+        {
+          "id": "test/res.cookie.js:17",
+          "title": "res .cookie(name, string, options) signed should generate a signed JSON cookie"
+        },
+        {
+          "id": "test/res.cookie.js:18",
+          "title": "res .cookie(name, string, options) signed without secret should throw an error"
+        },
+        {
+          "id": "test/res.cookie.js:19",
+          "title": "res .cookie(name, string, options) .signedCookie(name, string) should set a signed cookie"
+        }
+      ]
+    },
+    {
+      "path": "test/res.download.js",
+      "sha256": "274bbf9ce6cc03f2f6480ca05d7c80707081837b238d53d1a9ca2c0c96038a8a",
+      "tests": 25,
+      "cases": [
+        {
+          "id": "test/res.download.js:1",
+          "title": "res .download(path) should transfer as an attachment"
+        },
+        {
+          "id": "test/res.download.js:2",
+          "title": "res .download(path) should accept range requests"
+        },
+        {
+          "id": "test/res.download.js:3",
+          "title": "res .download(path) should respond with requested byte range"
+        },
+        {
+          "id": "test/res.download.js:4",
+          "title": "res .download(path, filename) should provide an alternate filename"
+        },
+        {
+          "id": "test/res.download.js:5",
+          "title": "res .download(path, fn) should invoke the callback"
+        },
+        {
+          "id": "test/res.download.js:6",
+          "title": "res .download(path, fn) async local storage should persist store"
+        },
+        {
+          "id": "test/res.download.js:7",
+          "title": "res .download(path, fn) async local storage should persist store on error"
+        },
+        {
+          "id": "test/res.download.js:8",
+          "title": "res .download(path, options) should allow options to res.sendFile()"
+        },
+        {
+          "id": "test/res.download.js:9",
+          "title": "res .download(path, options) with \"headers\" option should set headers on response"
+        },
+        {
+          "id": "test/res.download.js:10",
+          "title": "res .download(path, options) with \"headers\" option should use last header when duplicated"
+        },
+        {
+          "id": "test/res.download.js:11",
+          "title": "res .download(path, options) with \"headers\" option should override Content-Type"
+        },
+        {
+          "id": "test/res.download.js:12",
+          "title": "res .download(path, options) with \"headers\" option should not set headers on 404"
+        },
+        {
+          "id": "test/res.download.js:13",
+          "title": "res .download(path, options) with \"headers\" option when headers contains Content-Disposition should be ignored"
+        },
+        {
+          "id": "test/res.download.js:14",
+          "title": "res .download(path, options) with \"headers\" option when headers contains Content-Disposition should be ignored case-insensitively"
+        },
+        {
+          "id": "test/res.download.js:15",
+          "title": "res .download(path, options) with \"root\" option should allow relative path"
+        },
+        {
+          "id": "test/res.download.js:16",
+          "title": "res .download(path, options) with \"root\" option should allow up within root"
+        },
+        {
+          "id": "test/res.download.js:17",
+          "title": "res .download(path, options) with \"root\" option should reject up outside root"
+        },
+        {
+          "id": "test/res.download.js:18",
+          "title": "res .download(path, options) with \"root\" option should reject reading outside root"
+        },
+        {
+          "id": "test/res.download.js:19",
+          "title": "res .download(path, filename, fn) should invoke the callback"
+        },
+        {
+          "id": "test/res.download.js:20",
+          "title": "res .download(path, filename, options, fn) should invoke the callback"
+        },
+        {
+          "id": "test/res.download.js:21",
+          "title": "res .download(path, filename, options, fn) should allow options to res.sendFile()"
+        },
+        {
+          "id": "test/res.download.js:22",
+          "title": "res .download(path, filename, options, fn) when options.headers contains Content-Disposition should be ignored"
+        },
+        {
+          "id": "test/res.download.js:23",
+          "title": "res .download(path, filename, options, fn) when options.headers contains Content-Disposition should be ignored case-insensitively"
+        },
+        {
+          "id": "test/res.download.js:24",
+          "title": "res on failure should invoke the callback"
+        },
+        {
+          "id": "test/res.download.js:25",
+          "title": "res on failure should remove Content-Disposition"
+        }
+      ]
+    },
+    {
+      "path": "test/res.format.js",
+      "sha256": "bfc02443c7ebc62e716dfc9e121613e27507d63382db8ce3ea430b9019c37c8d",
+      "tests": 38,
+      "cases": [
+        {
+          "id": "test/res.format.js:1",
+          "title": "res .format(obj) with canonicalized mime types should utilize qvalues in negotiation"
+        },
+        {
+          "id": "test/res.format.js:2",
+          "title": "res .format(obj) with canonicalized mime types should allow wildcard type/subtypes"
+        },
+        {
+          "id": "test/res.format.js:3",
+          "title": "res .format(obj) with canonicalized mime types should default the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:4",
+          "title": "res .format(obj) with canonicalized mime types should set the correct charset for the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:5",
+          "title": "res .format(obj) with canonicalized mime types should Vary: Accept"
+        },
+        {
+          "id": "test/res.format.js:6",
+          "title": "res .format(obj) with canonicalized mime types when Accept is not present should invoke the first callback"
+        },
+        {
+          "id": "test/res.format.js:7",
+          "title": "res .format(obj) with canonicalized mime types when no match is made should respond with 406 not acceptable"
+        },
+        {
+          "id": "test/res.format.js:8",
+          "title": "res .format(obj) with extnames should utilize qvalues in negotiation"
+        },
+        {
+          "id": "test/res.format.js:9",
+          "title": "res .format(obj) with extnames should allow wildcard type/subtypes"
+        },
+        {
+          "id": "test/res.format.js:10",
+          "title": "res .format(obj) with extnames should default the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:11",
+          "title": "res .format(obj) with extnames should set the correct charset for the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:12",
+          "title": "res .format(obj) with extnames should Vary: Accept"
+        },
+        {
+          "id": "test/res.format.js:13",
+          "title": "res .format(obj) with extnames when Accept is not present should invoke the first callback"
+        },
+        {
+          "id": "test/res.format.js:14",
+          "title": "res .format(obj) with extnames when no match is made should respond with 406 not acceptable"
+        },
+        {
+          "id": "test/res.format.js:15",
+          "title": "res .format(obj) with parameters should utilize qvalues in negotiation"
+        },
+        {
+          "id": "test/res.format.js:16",
+          "title": "res .format(obj) with parameters should allow wildcard type/subtypes"
+        },
+        {
+          "id": "test/res.format.js:17",
+          "title": "res .format(obj) with parameters should default the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:18",
+          "title": "res .format(obj) with parameters should set the correct charset for the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:19",
+          "title": "res .format(obj) with parameters should Vary: Accept"
+        },
+        {
+          "id": "test/res.format.js:20",
+          "title": "res .format(obj) with parameters when Accept is not present should invoke the first callback"
+        },
+        {
+          "id": "test/res.format.js:21",
+          "title": "res .format(obj) with parameters when no match is made should respond with 406 not acceptable"
+        },
+        {
+          "id": "test/res.format.js:22",
+          "title": "res .format(obj) given .default should be invoked instead of auto-responding"
+        },
+        {
+          "id": "test/res.format.js:23",
+          "title": "res .format(obj) given .default should work when only .default is provided"
+        },
+        {
+          "id": "test/res.format.js:24",
+          "title": "res .format(obj) given .default should be able to invoke other formatter"
+        },
+        {
+          "id": "test/res.format.js:25",
+          "title": "res .format(obj) in router should utilize qvalues in negotiation"
+        },
+        {
+          "id": "test/res.format.js:26",
+          "title": "res .format(obj) in router should allow wildcard type/subtypes"
+        },
+        {
+          "id": "test/res.format.js:27",
+          "title": "res .format(obj) in router should default the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:28",
+          "title": "res .format(obj) in router should set the correct charset for the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:29",
+          "title": "res .format(obj) in router should Vary: Accept"
+        },
+        {
+          "id": "test/res.format.js:30",
+          "title": "res .format(obj) in router when Accept is not present should invoke the first callback"
+        },
+        {
+          "id": "test/res.format.js:31",
+          "title": "res .format(obj) in router when no match is made should respond with 406 not acceptable"
+        },
+        {
+          "id": "test/res.format.js:32",
+          "title": "res .format(obj) in router should utilize qvalues in negotiation"
+        },
+        {
+          "id": "test/res.format.js:33",
+          "title": "res .format(obj) in router should allow wildcard type/subtypes"
+        },
+        {
+          "id": "test/res.format.js:34",
+          "title": "res .format(obj) in router should default the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:35",
+          "title": "res .format(obj) in router should set the correct charset for the Content-Type"
+        },
+        {
+          "id": "test/res.format.js:36",
+          "title": "res .format(obj) in router should Vary: Accept"
+        },
+        {
+          "id": "test/res.format.js:37",
+          "title": "res .format(obj) in router when Accept is not present should invoke the first callback"
+        },
+        {
+          "id": "test/res.format.js:38",
+          "title": "res .format(obj) in router when no match is made should respond with 406 not acceptable"
+        }
+      ]
+    },
+    {
+      "path": "test/res.get.js",
+      "sha256": "8acb82fb8337faae72acc8349f7e53ad8c8ec28b5ad50ee8348ef43e837a5b40",
+      "tests": 1,
+      "cases": [
+        {
+          "id": "test/res.get.js:1",
+          "title": "res .get(field) should get the response header field"
+        }
+      ]
+    },
+    {
+      "path": "test/res.json.js",
+      "sha256": "08186aceebdb74af9f6fabe495c8c8b9334fbc6e5d53bf52145e4f86850eb046",
+      "tests": 13,
+      "cases": [
+        {
+          "id": "test/res.json.js:1",
+          "title": "res .json(object) should not support jsonp callbacks"
+        },
+        {
+          "id": "test/res.json.js:2",
+          "title": "res .json(object) should not override previous Content-Types"
+        },
+        {
+          "id": "test/res.json.js:3",
+          "title": "res .json(object) when given primitives should respond with json for null"
+        },
+        {
+          "id": "test/res.json.js:4",
+          "title": "res .json(object) when given primitives should respond with json for Number"
+        },
+        {
+          "id": "test/res.json.js:5",
+          "title": "res .json(object) when given primitives should respond with json for String"
+        },
+        {
+          "id": "test/res.json.js:6",
+          "title": "res .json(object) when given an array should respond with json"
+        },
+        {
+          "id": "test/res.json.js:7",
+          "title": "res .json(object) when given an object should respond with json"
+        },
+        {
+          "id": "test/res.json.js:8",
+          "title": "res .json(object) \"json escape\" setting should be undefined by default"
+        },
+        {
+          "id": "test/res.json.js:9",
+          "title": "res .json(object) \"json escape\" setting should unicode escape HTML-sniffing characters"
+        },
+        {
+          "id": "test/res.json.js:10",
+          "title": "res .json(object) \"json escape\" setting should not break undefined escape"
+        },
+        {
+          "id": "test/res.json.js:11",
+          "title": "res .json(object) \"json replacer\" setting should be passed to JSON.stringify()"
+        },
+        {
+          "id": "test/res.json.js:12",
+          "title": "res .json(object) \"json spaces\" setting should be undefined by default"
+        },
+        {
+          "id": "test/res.json.js:13",
+          "title": "res .json(object) \"json spaces\" setting should be passed to JSON.stringify()"
+        }
+      ]
+    },
+    {
+      "path": "test/res.jsonp.js",
+      "sha256": "b0762ac61a0946e269f47a668e7bda4da6c1cb404278394b44bf07caac08cdf8",
+      "tests": 23,
+      "cases": [
+        {
+          "id": "test/res.jsonp.js:1",
+          "title": "res .jsonp(object) should respond with jsonp"
+        },
+        {
+          "id": "test/res.jsonp.js:2",
+          "title": "res .jsonp(object) should use first callback parameter with jsonp"
+        },
+        {
+          "id": "test/res.jsonp.js:3",
+          "title": "res .jsonp(object) should ignore object callback parameter with jsonp"
+        },
+        {
+          "id": "test/res.jsonp.js:4",
+          "title": "res .jsonp(object) should allow renaming callback"
+        },
+        {
+          "id": "test/res.jsonp.js:5",
+          "title": "res .jsonp(object) should allow []"
+        },
+        {
+          "id": "test/res.jsonp.js:6",
+          "title": "res .jsonp(object) should disallow arbitrary js"
+        },
+        {
+          "id": "test/res.jsonp.js:7",
+          "title": "res .jsonp(object) should escape utf whitespace"
+        },
+        {
+          "id": "test/res.jsonp.js:8",
+          "title": "res .jsonp(object) should not escape utf whitespace for json fallback"
+        },
+        {
+          "id": "test/res.jsonp.js:9",
+          "title": "res .jsonp(object) should include security header and prologue"
+        },
+        {
+          "id": "test/res.jsonp.js:10",
+          "title": "res .jsonp(object) should not override previous Content-Types with no callback"
+        },
+        {
+          "id": "test/res.jsonp.js:11",
+          "title": "res .jsonp(object) should override previous Content-Types with callback"
+        },
+        {
+          "id": "test/res.jsonp.js:12",
+          "title": "res .jsonp(object) when given undefined should invoke callback with no arguments"
+        },
+        {
+          "id": "test/res.jsonp.js:13",
+          "title": "res .jsonp(object) when given null should invoke callback with null"
+        },
+        {
+          "id": "test/res.jsonp.js:14",
+          "title": "res .jsonp(object) when given a string should invoke callback with a string"
+        },
+        {
+          "id": "test/res.jsonp.js:15",
+          "title": "res .jsonp(object) when given a number should invoke callback with a number"
+        },
+        {
+          "id": "test/res.jsonp.js:16",
+          "title": "res .jsonp(object) when given an array should invoke callback with an array"
+        },
+        {
+          "id": "test/res.jsonp.js:17",
+          "title": "res .jsonp(object) when given an object should invoke callback with an object"
+        },
+        {
+          "id": "test/res.jsonp.js:18",
+          "title": "res .jsonp(object) \"json escape\" setting should be undefined by default"
+        },
+        {
+          "id": "test/res.jsonp.js:19",
+          "title": "res .jsonp(object) \"json escape\" setting should unicode escape HTML-sniffing characters"
+        },
+        {
+          "id": "test/res.jsonp.js:20",
+          "title": "res .jsonp(object) \"json escape\" setting should not break undefined escape"
+        },
+        {
+          "id": "test/res.jsonp.js:21",
+          "title": "res .jsonp(object) \"json replacer\" setting should be passed to JSON.stringify()"
+        },
+        {
+          "id": "test/res.jsonp.js:22",
+          "title": "res .jsonp(object) \"json spaces\" setting should be undefined by default"
+        },
+        {
+          "id": "test/res.jsonp.js:23",
+          "title": "res .jsonp(object) \"json spaces\" setting should be passed to JSON.stringify()"
+        }
+      ]
+    },
+    {
+      "path": "test/res.links.js",
+      "sha256": "77bb1d8c74e0efa72114157f3a5deec7cce7500398e49f94bf442f30e96248bf",
+      "tests": 3,
+      "cases": [
+        {
+          "id": "test/res.links.js:1",
+          "title": "res .links(obj) should set Link header field"
+        },
+        {
+          "id": "test/res.links.js:2",
+          "title": "res .links(obj) should set Link header field for multiple calls"
+        },
+        {
+          "id": "test/res.links.js:3",
+          "title": "res .links(obj) should set multiple links for single rel"
+        }
+      ]
+    },
+    {
+      "path": "test/res.locals.js",
+      "sha256": "1b7ef31efd3da01df660fe852faabfe2ce126afe8ea8d43989347d0247ea1bf9",
+      "tests": 2,
+      "cases": [
+        {
+          "id": "test/res.locals.js:1",
+          "title": "res should work when mounted"
+        },
+        {
+          "id": "test/res.locals.js:2",
+          "title": "res .locals should be empty by default"
+        }
+      ]
+    },
+    {
+      "path": "test/res.location.js",
+      "sha256": "5d46e67f931862cf2372c210d8b3efb8ecaa31b328738115eb3ed3060a86f1ef",
+      "tests": 21,
+      "cases": [
+        {
+          "id": "test/res.location.js:1",
+          "title": "res .location(url) should set the header"
+        },
+        {
+          "id": "test/res.location.js:2",
+          "title": "res .location(url) should preserve trailing slashes when not present"
+        },
+        {
+          "id": "test/res.location.js:3",
+          "title": "res .location(url) should encode \"url\""
+        },
+        {
+          "id": "test/res.location.js:4",
+          "title": "res .location(url) should encode data uri"
+        },
+        {
+          "id": "test/res.location.js:5",
+          "title": "res .location(url) should consistently handle non-string input: boolean"
+        },
+        {
+          "id": "test/res.location.js:6",
+          "title": "res .location(url) should consistently handle non-string inputs: object"
+        },
+        {
+          "id": "test/res.location.js:7",
+          "title": "res .location(url) should consistently handle non-string inputs: array"
+        },
+        {
+          "id": "test/res.location.js:8",
+          "title": "res .location(url) should consistently handle empty string input"
+        },
+        {
+          "id": "test/res.location.js:9",
+          "title": "res .location(url) should accept an instance of URL"
+        },
+        {
+          "id": "test/res.location.js:10",
+          "title": "res location header encoding should not touch already-encoded sequences in \"url\""
+        },
+        {
+          "id": "test/res.location.js:11",
+          "title": "res location header encoding should consistently handle relative urls"
+        },
+        {
+          "id": "test/res.location.js:12",
+          "title": "res location header encoding should not encode urls in such a way that they can bypass redirect allow lists"
+        },
+        {
+          "id": "test/res.location.js:13",
+          "title": "res location header encoding should not be case sensitive"
+        },
+        {
+          "id": "test/res.location.js:14",
+          "title": "res location header encoding should work with https"
+        },
+        {
+          "id": "test/res.location.js:15",
+          "title": "res location header encoding should correctly encode schemaless paths"
+        },
+        {
+          "id": "test/res.location.js:16",
+          "title": "res location header encoding should keep backslashes in the path"
+        },
+        {
+          "id": "test/res.location.js:17",
+          "title": "res location header encoding should escape header splitting for old node versions"
+        },
+        {
+          "id": "test/res.location.js:18",
+          "title": "res location header encoding should encode unicode correctly"
+        },
+        {
+          "id": "test/res.location.js:19",
+          "title": "res location header encoding should encode unicode correctly even with a bad host"
+        },
+        {
+          "id": "test/res.location.js:20",
+          "title": "res location header encoding should work correctly despite using deprecated url.parse"
+        },
+        {
+          "id": "test/res.location.js:21",
+          "title": "res location header encoding should encode file uri path"
+        }
+      ]
+    },
+    {
+      "path": "test/res.redirect.js",
+      "sha256": "451fae6e8674bbb463de046afd8fafa3c7a766fea840abd8b1af63a1f31b8f04",
+      "tests": 13,
+      "cases": [
+        {
+          "id": "test/res.redirect.js:1",
+          "title": "res .redirect(url) should default to a 302 redirect"
+        },
+        {
+          "id": "test/res.redirect.js:2",
+          "title": "res .redirect(url) should encode \"url\""
+        },
+        {
+          "id": "test/res.redirect.js:3",
+          "title": "res .redirect(url) should not touch already-encoded sequences in \"url\""
+        },
+        {
+          "id": "test/res.redirect.js:4",
+          "title": "res .redirect(status, url) should set the response status"
+        },
+        {
+          "id": "test/res.redirect.js:5",
+          "title": "res when the request method is HEAD should ignore the body"
+        },
+        {
+          "id": "test/res.redirect.js:6",
+          "title": "res when accepting html should respond with html"
+        },
+        {
+          "id": "test/res.redirect.js:7",
+          "title": "res when accepting html should escape the url"
+        },
+        {
+          "id": "test/res.redirect.js:8",
+          "title": "res when accepting html should not render evil javascript links in anchor href (prevent XSS)"
+        },
+        {
+          "id": "test/res.redirect.js:9",
+          "title": "res when accepting html should include the redirect type"
+        },
+        {
+          "id": "test/res.redirect.js:10",
+          "title": "res when accepting text should respond with text"
+        },
+        {
+          "id": "test/res.redirect.js:11",
+          "title": "res when accepting text should encode the url"
+        },
+        {
+          "id": "test/res.redirect.js:12",
+          "title": "res when accepting text should include the redirect type"
+        },
+        {
+          "id": "test/res.redirect.js:13",
+          "title": "res when accepting neither text or html should respond with an empty body"
+        }
+      ]
+    },
+    {
+      "path": "test/res.render.js",
+      "sha256": "9db3993c09c0319caed25a548b800feeddd05b2f8242e82b166ebd194c6421fe",
+      "tests": 21,
+      "cases": [
+        {
+          "id": "test/res.render.js:1",
+          "title": "res .render(name) should support absolute paths"
+        },
+        {
+          "id": "test/res.render.js:2",
+          "title": "res .render(name) should support absolute paths with \"view engine\""
+        },
+        {
+          "id": "test/res.render.js:3",
+          "title": "res .render(name) should error without \"view engine\" set and file extension to a non-engine module"
+        },
+        {
+          "id": "test/res.render.js:4",
+          "title": "res .render(name) should error without \"view engine\" set and no file extension"
+        },
+        {
+          "id": "test/res.render.js:5",
+          "title": "res .render(name) should expose app.locals"
+        },
+        {
+          "id": "test/res.render.js:6",
+          "title": "res .render(name) should expose app.locals with `name` property"
+        },
+        {
+          "id": "test/res.render.js:7",
+          "title": "res .render(name) should support index."
+        },
+        {
+          "id": "test/res.render.js:8",
+          "title": "res .render(name) when an error occurs should next(err)"
+        },
+        {
+          "id": "test/res.render.js:9",
+          "title": "res .render(name) when \"view engine\" is given should render the template"
+        },
+        {
+          "id": "test/res.render.js:10",
+          "title": "res .render(name) when \"views\" is given should lookup the file in the path"
+        },
+        {
+          "id": "test/res.render.js:11",
+          "title": "res .render(name) when \"views\" is given when array of paths should lookup the file in the path"
+        },
+        {
+          "id": "test/res.render.js:12",
+          "title": "res .render(name) when \"views\" is given when array of paths should lookup in later paths until found"
+        },
+        {
+          "id": "test/res.render.js:13",
+          "title": "res .render(name, option) should render the template"
+        },
+        {
+          "id": "test/res.render.js:14",
+          "title": "res .render(name, option) should expose app.locals"
+        },
+        {
+          "id": "test/res.render.js:15",
+          "title": "res .render(name, option) should expose res.locals"
+        },
+        {
+          "id": "test/res.render.js:16",
+          "title": "res .render(name, option) should give precedence to res.locals over app.locals"
+        },
+        {
+          "id": "test/res.render.js:17",
+          "title": "res .render(name, option) should give precedence to res.render() locals over res.locals"
+        },
+        {
+          "id": "test/res.render.js:18",
+          "title": "res .render(name, option) should give precedence to res.render() locals over app.locals"
+        },
+        {
+          "id": "test/res.render.js:19",
+          "title": "res .render(name, options, fn) should pass the resulting string"
+        },
+        {
+          "id": "test/res.render.js:20",
+          "title": "res .render(name, fn) should pass the resulting string"
+        },
+        {
+          "id": "test/res.render.js:21",
+          "title": "res .render(name, fn) when an error occurs should pass it to the callback"
+        }
+      ]
+    },
+    {
+      "path": "test/res.send.js",
+      "sha256": "0e3a96ef40d49e5956ec81eea79125a3a2651d909eb2dde0e9d288408ba9bb30",
+      "tests": 76,
+      "cases": [
+        {
+          "id": "test/res.send.js:1",
+          "title": "res should always check regardless of length"
+        },
+        {
+          "id": "test/res.send.js:2",
+          "title": "res should respond with 304 Not Modified when fresh"
+        },
+        {
+          "id": "test/res.send.js:3",
+          "title": "res should not perform freshness check unless 2xx or 304"
+        },
+        {
+          "id": "test/res.send.js:4",
+          "title": "res should not support jsonp callbacks"
+        },
+        {
+          "id": "test/res.send.js:5",
+          "title": "res should be chainable"
+        },
+        {
+          "id": "test/res.send.js:6",
+          "title": "res .send() should set body to \"\""
+        },
+        {
+          "id": "test/res.send.js:7",
+          "title": "res .send(null) should set body to \"\""
+        },
+        {
+          "id": "test/res.send.js:8",
+          "title": "res .send(undefined) should set body to \"\""
+        },
+        {
+          "id": "test/res.send.js:9",
+          "title": "res .send(Number) should send as application/json"
+        },
+        {
+          "id": "test/res.send.js:10",
+          "title": "res .send(String) should send as html"
+        },
+        {
+          "id": "test/res.send.js:11",
+          "title": "res .send(String) should set ETag"
+        },
+        {
+          "id": "test/res.send.js:12",
+          "title": "res .send(String) should not override Content-Type"
+        },
+        {
+          "id": "test/res.send.js:13",
+          "title": "res .send(String) should override charset in Content-Type"
+        },
+        {
+          "id": "test/res.send.js:14",
+          "title": "res .send(String) should preserve existing parameters when adding charset"
+        },
+        {
+          "id": "test/res.send.js:15",
+          "title": "res .send(String) should not throw on a Content-Type that fails to parse"
+        },
+        {
+          "id": "test/res.send.js:16",
+          "title": "res .send(String) should keep charset in Content-Type for Buffers"
+        },
+        {
+          "id": "test/res.send.js:17",
+          "title": "res .send(Buffer) should send as octet-stream"
+        },
+        {
+          "id": "test/res.send.js:18",
+          "title": "res .send(Buffer) should set ETag"
+        },
+        {
+          "id": "test/res.send.js:19",
+          "title": "res .send(Buffer) should not override Content-Type"
+        },
+        {
+          "id": "test/res.send.js:20",
+          "title": "res .send(Buffer) should accept Uint8Array"
+        },
+        {
+          "id": "test/res.send.js:21",
+          "title": "res .send(Buffer) should not override ETag"
+        },
+        {
+          "id": "test/res.send.js:22",
+          "title": "res .send(Object) should send as application/json"
+        },
+        {
+          "id": "test/res.send.js:23",
+          "title": "res when the request method is HEAD should ignore the body"
+        },
+        {
+          "id": "test/res.send.js:24",
+          "title": "res when .statusCode is 204 should strip Content-* fields, Transfer-Encoding field, and body"
+        },
+        {
+          "id": "test/res.send.js:25",
+          "title": "res when .statusCode is 205 should strip Transfer-Encoding field and body, set Content-Length"
+        },
+        {
+          "id": "test/res.send.js:26",
+          "title": "res when .statusCode is 304 should strip Content-* fields, Transfer-Encoding field, and body"
+        },
+        {
+          "id": "test/res.send.js:27",
+          "title": "res \"etag\" setting when enabled should send ETag"
+        },
+        {
+          "id": "test/res.send.js:28",
+          "title": "res \"etag\" setting when enabled should send ETag in response to ACL request"
+        },
+        {
+          "id": "test/res.send.js:29",
+          "title": "res \"etag\" setting when enabled should send ETag in response to BIND request"
+        },
+        {
+          "id": "test/res.send.js:30",
+          "title": "res \"etag\" setting when enabled should send ETag in response to CHECKOUT request"
+        },
+        {
+          "id": "test/res.send.js:31",
+          "title": "res \"etag\" setting when enabled should send ETag in response to COPY request"
+        },
+        {
+          "id": "test/res.send.js:32",
+          "title": "res \"etag\" setting when enabled should send ETag in response to DELETE request"
+        },
+        {
+          "id": "test/res.send.js:33",
+          "title": "res \"etag\" setting when enabled should send ETag in response to GET request"
+        },
+        {
+          "id": "test/res.send.js:34",
+          "title": "res \"etag\" setting when enabled should send ETag in response to HEAD request"
+        },
+        {
+          "id": "test/res.send.js:35",
+          "title": "res \"etag\" setting when enabled should send ETag in response to LINK request"
+        },
+        {
+          "id": "test/res.send.js:36",
+          "title": "res \"etag\" setting when enabled should send ETag in response to LOCK request"
+        },
+        {
+          "id": "test/res.send.js:37",
+          "title": "res \"etag\" setting when enabled should send ETag in response to M-SEARCH request"
+        },
+        {
+          "id": "test/res.send.js:38",
+          "title": "res \"etag\" setting when enabled should send ETag in response to MERGE request"
+        },
+        {
+          "id": "test/res.send.js:39",
+          "title": "res \"etag\" setting when enabled should send ETag in response to MKACTIVITY request"
+        },
+        {
+          "id": "test/res.send.js:40",
+          "title": "res \"etag\" setting when enabled should send ETag in response to MKCALENDAR request"
+        },
+        {
+          "id": "test/res.send.js:41",
+          "title": "res \"etag\" setting when enabled should send ETag in response to MKCOL request"
+        },
+        {
+          "id": "test/res.send.js:42",
+          "title": "res \"etag\" setting when enabled should send ETag in response to MOVE request"
+        },
+        {
+          "id": "test/res.send.js:43",
+          "title": "res \"etag\" setting when enabled should send ETag in response to NOTIFY request"
+        },
+        {
+          "id": "test/res.send.js:44",
+          "title": "res \"etag\" setting when enabled should send ETag in response to OPTIONS request"
+        },
+        {
+          "id": "test/res.send.js:45",
+          "title": "res \"etag\" setting when enabled should send ETag in response to PATCH request"
+        },
+        {
+          "id": "test/res.send.js:46",
+          "title": "res \"etag\" setting when enabled should send ETag in response to POST request"
+        },
+        {
+          "id": "test/res.send.js:47",
+          "title": "res \"etag\" setting when enabled should send ETag in response to PROPFIND request"
+        },
+        {
+          "id": "test/res.send.js:48",
+          "title": "res \"etag\" setting when enabled should send ETag in response to PROPPATCH request"
+        },
+        {
+          "id": "test/res.send.js:49",
+          "title": "res \"etag\" setting when enabled should send ETag in response to PURGE request"
+        },
+        {
+          "id": "test/res.send.js:50",
+          "title": "res \"etag\" setting when enabled should send ETag in response to PUT request"
+        },
+        {
+          "id": "test/res.send.js:51",
+          "title": "res \"etag\" setting when enabled should send ETag in response to QUERY request"
+        },
+        {
+          "id": "test/res.send.js:52",
+          "title": "res \"etag\" setting when enabled should send ETag in response to REBIND request"
+        },
+        {
+          "id": "test/res.send.js:53",
+          "title": "res \"etag\" setting when enabled should send ETag in response to REPORT request"
+        },
+        {
+          "id": "test/res.send.js:54",
+          "title": "res \"etag\" setting when enabled should send ETag in response to SEARCH request"
+        },
+        {
+          "id": "test/res.send.js:55",
+          "title": "res \"etag\" setting when enabled should send ETag in response to SOURCE request"
+        },
+        {
+          "id": "test/res.send.js:56",
+          "title": "res \"etag\" setting when enabled should send ETag in response to SUBSCRIBE request"
+        },
+        {
+          "id": "test/res.send.js:57",
+          "title": "res \"etag\" setting when enabled should send ETag in response to TRACE request"
+        },
+        {
+          "id": "test/res.send.js:58",
+          "title": "res \"etag\" setting when enabled should send ETag in response to UNBIND request"
+        },
+        {
+          "id": "test/res.send.js:59",
+          "title": "res \"etag\" setting when enabled should send ETag in response to UNLINK request"
+        },
+        {
+          "id": "test/res.send.js:60",
+          "title": "res \"etag\" setting when enabled should send ETag in response to UNLOCK request"
+        },
+        {
+          "id": "test/res.send.js:61",
+          "title": "res \"etag\" setting when enabled should send ETag in response to UNSUBSCRIBE request"
+        },
+        {
+          "id": "test/res.send.js:62",
+          "title": "res \"etag\" setting when enabled should send ETag for empty string response"
+        },
+        {
+          "id": "test/res.send.js:63",
+          "title": "res \"etag\" setting when enabled should send ETag for long response"
+        },
+        {
+          "id": "test/res.send.js:64",
+          "title": "res \"etag\" setting when enabled should not override ETag when manually set"
+        },
+        {
+          "id": "test/res.send.js:65",
+          "title": "res \"etag\" setting when enabled should not send ETag for res.send()"
+        },
+        {
+          "id": "test/res.send.js:66",
+          "title": "res \"etag\" setting when disabled should send no ETag"
+        },
+        {
+          "id": "test/res.send.js:67",
+          "title": "res \"etag\" setting when disabled should send ETag when manually set"
+        },
+        {
+          "id": "test/res.send.js:68",
+          "title": "res \"etag\" setting when \"strong\" should send strong ETag"
+        },
+        {
+          "id": "test/res.send.js:69",
+          "title": "res \"etag\" setting when \"weak\" should send weak ETag"
+        },
+        {
+          "id": "test/res.send.js:70",
+          "title": "res \"etag\" setting when a function should send custom ETag"
+        },
+        {
+          "id": "test/res.send.js:71",
+          "title": "res \"etag\" setting when a function should not send falsy ETag"
+        },
+        {
+          "id": "test/res.send.js:72",
+          "title": "res when Transfer-Encoding header is present should not add Content-Length header if Transfer-Encoding header is equal to chunked"
+        },
+        {
+          "id": "test/res.send.js:73",
+          "title": "res when Transfer-Encoding header is present should not add Content-Length header if Transfer-Encoding header is equal to compress"
+        },
+        {
+          "id": "test/res.send.js:74",
+          "title": "res when Transfer-Encoding header is present should not add Content-Length header if Transfer-Encoding header is equal to deflate"
+        },
+        {
+          "id": "test/res.send.js:75",
+          "title": "res when Transfer-Encoding header is present should not add Content-Length header if Transfer-Encoding header is equal to gzip"
+        },
+        {
+          "id": "test/res.send.js:76",
+          "title": "res when Transfer-Encoding header is present should still generate an ETag"
+        }
+      ]
+    },
+    {
+      "path": "test/res.sendFile.js",
+      "sha256": "1ce86ede00a1e19a3c11a835ef9f87669d495ada5060922d96cc96e4120ec4f7",
+      "tests": 55,
+      "cases": [
+        {
+          "id": "test/res.sendFile.js:1",
+          "title": "res .sendFile(path) should error missing path"
+        },
+        {
+          "id": "test/res.sendFile.js:2",
+          "title": "res .sendFile(path) should error for non-string path"
+        },
+        {
+          "id": "test/res.sendFile.js:3",
+          "title": "res .sendFile(path) should error for non-absolute path"
+        },
+        {
+          "id": "test/res.sendFile.js:4",
+          "title": "res .sendFile(path) should transfer a file"
+        },
+        {
+          "id": "test/res.sendFile.js:5",
+          "title": "res .sendFile(path) should transfer a file with special characters in string"
+        },
+        {
+          "id": "test/res.sendFile.js:6",
+          "title": "res .sendFile(path) should include ETag"
+        },
+        {
+          "id": "test/res.sendFile.js:7",
+          "title": "res .sendFile(path) should 304 when ETag matches"
+        },
+        {
+          "id": "test/res.sendFile.js:8",
+          "title": "res .sendFile(path) should disable the ETag function if requested"
+        },
+        {
+          "id": "test/res.sendFile.js:9",
+          "title": "res .sendFile(path) should 404 for directory"
+        },
+        {
+          "id": "test/res.sendFile.js:10",
+          "title": "res .sendFile(path) should 404 when not found"
+        },
+        {
+          "id": "test/res.sendFile.js:11",
+          "title": "res .sendFile(path) should send cache-control by default"
+        },
+        {
+          "id": "test/res.sendFile.js:12",
+          "title": "res .sendFile(path) should not serve dotfiles by default"
+        },
+        {
+          "id": "test/res.sendFile.js:13",
+          "title": "res .sendFile(path) should not override manual content-types"
+        },
+        {
+          "id": "test/res.sendFile.js:14",
+          "title": "res .sendFile(path) should not error if the client aborts"
+        },
+        {
+          "id": "test/res.sendFile.js:15",
+          "title": "res .sendFile(path, fn) should invoke the callback when complete"
+        },
+        {
+          "id": "test/res.sendFile.js:16",
+          "title": "res .sendFile(path, fn) should invoke the callback when client aborts"
+        },
+        {
+          "id": "test/res.sendFile.js:17",
+          "title": "res .sendFile(path, fn) should invoke the callback when client already aborted"
+        },
+        {
+          "id": "test/res.sendFile.js:18",
+          "title": "res .sendFile(path, fn) should invoke the callback without error when HEAD"
+        },
+        {
+          "id": "test/res.sendFile.js:19",
+          "title": "res .sendFile(path, fn) should invoke the callback without error when 304"
+        },
+        {
+          "id": "test/res.sendFile.js:20",
+          "title": "res .sendFile(path, fn) should invoke the callback on 404"
+        },
+        {
+          "id": "test/res.sendFile.js:21",
+          "title": "res .sendFile(path, fn) async local storage should persist store"
+        },
+        {
+          "id": "test/res.sendFile.js:22",
+          "title": "res .sendFile(path, fn) async local storage should persist store on error"
+        },
+        {
+          "id": "test/res.sendFile.js:23",
+          "title": "res .sendFile(path, options) should pass options to send module"
+        },
+        {
+          "id": "test/res.sendFile.js:24",
+          "title": "res .sendFile(path, options) with \"acceptRanges\" option when true should advertise byte range accepted"
+        },
+        {
+          "id": "test/res.sendFile.js:25",
+          "title": "res .sendFile(path, options) with \"acceptRanges\" option when true should respond to range request"
+        },
+        {
+          "id": "test/res.sendFile.js:26",
+          "title": "res .sendFile(path, options) with \"acceptRanges\" option when false should not advertise accept-ranges"
+        },
+        {
+          "id": "test/res.sendFile.js:27",
+          "title": "res .sendFile(path, options) with \"acceptRanges\" option when false should not honor range requests"
+        },
+        {
+          "id": "test/res.sendFile.js:28",
+          "title": "res .sendFile(path, options) with \"cacheControl\" option when true should send cache-control header"
+        },
+        {
+          "id": "test/res.sendFile.js:29",
+          "title": "res .sendFile(path, options) with \"cacheControl\" option when false should not send cache-control header"
+        },
+        {
+          "id": "test/res.sendFile.js:30",
+          "title": "res .sendFile(path, options) with \"dotfiles\" option when \"allow\" should allow dotfiles"
+        },
+        {
+          "id": "test/res.sendFile.js:31",
+          "title": "res .sendFile(path, options) with \"dotfiles\" option when \"deny\" should deny dotfiles"
+        },
+        {
+          "id": "test/res.sendFile.js:32",
+          "title": "res .sendFile(path, options) with \"dotfiles\" option when \"ignore\" should ignore dotfiles"
+        },
+        {
+          "id": "test/res.sendFile.js:33",
+          "title": "res .sendFile(path, options) with \"headers\" option should set headers on response"
+        },
+        {
+          "id": "test/res.sendFile.js:34",
+          "title": "res .sendFile(path, options) with \"headers\" option should use last header when duplicated"
+        },
+        {
+          "id": "test/res.sendFile.js:35",
+          "title": "res .sendFile(path, options) with \"headers\" option should override Content-Type"
+        },
+        {
+          "id": "test/res.sendFile.js:36",
+          "title": "res .sendFile(path, options) with \"headers\" option should not set headers on 404"
+        },
+        {
+          "id": "test/res.sendFile.js:37",
+          "title": "res .sendFile(path, options) with \"immutable\" option when true should send cache-control header with immutable"
+        },
+        {
+          "id": "test/res.sendFile.js:38",
+          "title": "res .sendFile(path, options) with \"immutable\" option when false should not send cache-control header with immutable"
+        },
+        {
+          "id": "test/res.sendFile.js:39",
+          "title": "res .sendFile(path, options) with \"lastModified\" option when true should send last-modified header"
+        },
+        {
+          "id": "test/res.sendFile.js:40",
+          "title": "res .sendFile(path, options) with \"lastModified\" option when true should conditionally respond with if-modified-since"
+        },
+        {
+          "id": "test/res.sendFile.js:41",
+          "title": "res .sendFile(path, options) with \"lastModified\" option when false should not have last-modified header"
+        },
+        {
+          "id": "test/res.sendFile.js:42",
+          "title": "res .sendFile(path, options) with \"lastModified\" option when false should not honor if-modified-since"
+        },
+        {
+          "id": "test/res.sendFile.js:43",
+          "title": "res .sendFile(path, options) with \"maxAge\" option should set cache-control max-age to milliseconds"
+        },
+        {
+          "id": "test/res.sendFile.js:44",
+          "title": "res .sendFile(path, options) with \"maxAge\" option should cap cache-control max-age to 1 year"
+        },
+        {
+          "id": "test/res.sendFile.js:45",
+          "title": "res .sendFile(path, options) with \"maxAge\" option should min cache-control max-age to 0"
+        },
+        {
+          "id": "test/res.sendFile.js:46",
+          "title": "res .sendFile(path, options) with \"maxAge\" option should floor cache-control max-age"
+        },
+        {
+          "id": "test/res.sendFile.js:47",
+          "title": "res .sendFile(path, options) with \"maxAge\" option when cacheControl: false should not send cache-control"
+        },
+        {
+          "id": "test/res.sendFile.js:48",
+          "title": "res .sendFile(path, options) with \"maxAge\" option when string should accept plain number as milliseconds"
+        },
+        {
+          "id": "test/res.sendFile.js:49",
+          "title": "res .sendFile(path, options) with \"maxAge\" option when string should accept suffix \"s\" for seconds"
+        },
+        {
+          "id": "test/res.sendFile.js:50",
+          "title": "res .sendFile(path, options) with \"maxAge\" option when string should accept suffix \"m\" for minutes"
+        },
+        {
+          "id": "test/res.sendFile.js:51",
+          "title": "res .sendFile(path, options) with \"maxAge\" option when string should accept suffix \"d\" for days"
+        },
+        {
+          "id": "test/res.sendFile.js:52",
+          "title": "res .sendFile(path, options) with \"root\" option should allow relative path"
+        },
+        {
+          "id": "test/res.sendFile.js:53",
+          "title": "res .sendFile(path, options) with \"root\" option should allow up within root"
+        },
+        {
+          "id": "test/res.sendFile.js:54",
+          "title": "res .sendFile(path, options) with \"root\" option should reject up outside root"
+        },
+        {
+          "id": "test/res.sendFile.js:55",
+          "title": "res .sendFile(path, options) with \"root\" option should reject reading outside root"
+        }
+      ]
+    },
+    {
+      "path": "test/res.sendStatus.js",
+      "sha256": "94f1c9739f66160f27e3616c61532b251c038a64cf6658a851c0bc072201561d",
+      "tests": 3,
+      "cases": [
+        {
+          "id": "test/res.sendStatus.js:1",
+          "title": "res .sendStatus(statusCode) should send the status code and message as body"
+        },
+        {
+          "id": "test/res.sendStatus.js:2",
+          "title": "res .sendStatus(statusCode) should work with unknown code"
+        },
+        {
+          "id": "test/res.sendStatus.js:3",
+          "title": "res .sendStatus(statusCode) should raise error for invalid status code"
+        }
+      ]
+    },
+    {
+      "path": "test/res.set.js",
+      "sha256": "18e7ba428f65f200307e904c1bd34009632f6c0c8a51a88a51127950b78a1c6d",
+      "tests": 8,
+      "cases": [
+        {
+          "id": "test/res.set.js:1",
+          "title": "res .set(field, value) should set the response header field"
+        },
+        {
+          "id": "test/res.set.js:2",
+          "title": "res .set(field, value) should coerce to a string"
+        },
+        {
+          "id": "test/res.set.js:3",
+          "title": "res .set(field, values) should set multiple response header fields"
+        },
+        {
+          "id": "test/res.set.js:4",
+          "title": "res .set(field, values) should coerce to an array of strings"
+        },
+        {
+          "id": "test/res.set.js:5",
+          "title": "res .set(field, values) should not set a charset of one is already set"
+        },
+        {
+          "id": "test/res.set.js:6",
+          "title": "res .set(field, values) should throw when Content-Type is an array"
+        },
+        {
+          "id": "test/res.set.js:7",
+          "title": "res .set(object) should set multiple fields"
+        },
+        {
+          "id": "test/res.set.js:8",
+          "title": "res .set(object) should coerce to a string"
+        }
+      ]
+    },
+    {
+      "path": "test/res.status.js",
+      "sha256": "2fe6137bcb25077ff88436c9286fc5d42d1a94951fdcd50e62919b2f13785c8f",
+      "tests": 16,
+      "cases": [
+        {
+          "id": "test/res.status.js:1",
+          "title": "res .status(code) should set the status code when valid"
+        },
+        {
+          "id": "test/res.status.js:2",
+          "title": "res .status(code) accept valid ranges should set the response status code to 101"
+        },
+        {
+          "id": "test/res.status.js:3",
+          "title": "res .status(code) accept valid ranges should set the response status code to 201"
+        },
+        {
+          "id": "test/res.status.js:4",
+          "title": "res .status(code) accept valid ranges should set the response status code to 302"
+        },
+        {
+          "id": "test/res.status.js:5",
+          "title": "res .status(code) accept valid ranges should set the response status code to 403"
+        },
+        {
+          "id": "test/res.status.js:6",
+          "title": "res .status(code) accept valid ranges should set the response status code to 501"
+        },
+        {
+          "id": "test/res.status.js:7",
+          "title": "res .status(code) accept valid ranges should set the response status code to 700"
+        },
+        {
+          "id": "test/res.status.js:8",
+          "title": "res .status(code) accept valid ranges should set the response status code to 800"
+        },
+        {
+          "id": "test/res.status.js:9",
+          "title": "res .status(code) accept valid ranges should set the response status code to 900"
+        },
+        {
+          "id": "test/res.status.js:10",
+          "title": "res .status(code) invalid status codes should raise error for status code below 100"
+        },
+        {
+          "id": "test/res.status.js:11",
+          "title": "res .status(code) invalid status codes should raise error for status code above 999"
+        },
+        {
+          "id": "test/res.status.js:12",
+          "title": "res .status(code) invalid status codes should raise error for non-integer status codes"
+        },
+        {
+          "id": "test/res.status.js:13",
+          "title": "res .status(code) invalid status codes should raise error for undefined status code"
+        },
+        {
+          "id": "test/res.status.js:14",
+          "title": "res .status(code) invalid status codes should raise error for null status code"
+        },
+        {
+          "id": "test/res.status.js:15",
+          "title": "res .status(code) invalid status codes should raise error for string status code"
+        },
+        {
+          "id": "test/res.status.js:16",
+          "title": "res .status(code) invalid status codes should raise error for NaN status code"
+        }
+      ]
+    },
+    {
+      "path": "test/res.type.js",
+      "sha256": "6ec2b2c15d4b8e2a3d500026c8a5f584a276e3e0ae4d2641a81df3e78789b3fc",
+      "tests": 8,
+      "cases": [
+        {
+          "id": "test/res.type.js:1",
+          "title": "res .type(str) should set the Content-Type based on a filename"
+        },
+        {
+          "id": "test/res.type.js:2",
+          "title": "res .type(str) should default to application/octet-stream"
+        },
+        {
+          "id": "test/res.type.js:3",
+          "title": "res .type(str) should set the Content-Type with type/subtype"
+        },
+        {
+          "id": "test/res.type.js:4",
+          "title": "res .type(str) edge cases should handle empty string gracefully"
+        },
+        {
+          "id": "test/res.type.js:5",
+          "title": "res .type(str) edge cases should handle file extension with dots"
+        },
+        {
+          "id": "test/res.type.js:6",
+          "title": "res .type(str) edge cases should handle multiple file extensions"
+        },
+        {
+          "id": "test/res.type.js:7",
+          "title": "res .type(str) edge cases should handle uppercase extensions"
+        },
+        {
+          "id": "test/res.type.js:8",
+          "title": "res .type(str) edge cases should handle extension with special characters"
+        }
+      ]
+    },
+    {
+      "path": "test/res.vary.js",
+      "sha256": "fa77db01d6b6d48f1a10f7e044f7ef263499d18e4f564c6ed687b79b2c284a44",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/res.vary.js:1",
+          "title": "res.vary() with no arguments should throw error"
+        },
+        {
+          "id": "test/res.vary.js:2",
+          "title": "res.vary() with an empty array should not set Vary"
+        },
+        {
+          "id": "test/res.vary.js:3",
+          "title": "res.vary() with an array should set the values"
+        },
+        {
+          "id": "test/res.vary.js:4",
+          "title": "res.vary() with a string should set the value"
+        },
+        {
+          "id": "test/res.vary.js:5",
+          "title": "res.vary() when the value is present should not add it again"
+        }
+      ]
+    },
+    {
+      "path": "test/utils.js",
+      "sha256": "022f171575ba38ed5f595ec8080da0bb4578130d280942a0d4aea019a172711e",
+      "tests": 20,
+      "cases": [
+        {
+          "id": "test/utils.js:1",
+          "title": "utils.etag(body, encoding) should support strings"
+        },
+        {
+          "id": "test/utils.js:2",
+          "title": "utils.etag(body, encoding) should support utf8 strings"
+        },
+        {
+          "id": "test/utils.js:3",
+          "title": "utils.etag(body, encoding) should support buffer"
+        },
+        {
+          "id": "test/utils.js:4",
+          "title": "utils.etag(body, encoding) should support empty string"
+        },
+        {
+          "id": "test/utils.js:5",
+          "title": "utils.normalizeType acceptParams method should handle a type with a malformed parameter and break the loop in acceptParams"
+        },
+        {
+          "id": "test/utils.js:6",
+          "title": "utils.normalizeType acceptParams method should default to application/octet-stream when mime lookup fails"
+        },
+        {
+          "id": "test/utils.js:7",
+          "title": "utils.setCharset(type, charset) should do anything without type"
+        },
+        {
+          "id": "test/utils.js:8",
+          "title": "utils.setCharset(type, charset) should return type if not given charset"
+        },
+        {
+          "id": "test/utils.js:9",
+          "title": "utils.setCharset(type, charset) should keep charset if not given charset"
+        },
+        {
+          "id": "test/utils.js:10",
+          "title": "utils.setCharset(type, charset) should set charset"
+        },
+        {
+          "id": "test/utils.js:11",
+          "title": "utils.setCharset(type, charset) should override charset"
+        },
+        {
+          "id": "test/utils.js:12",
+          "title": "utils.wetag(body, encoding) should support strings"
+        },
+        {
+          "id": "test/utils.js:13",
+          "title": "utils.wetag(body, encoding) should support utf8 strings"
+        },
+        {
+          "id": "test/utils.js:14",
+          "title": "utils.wetag(body, encoding) should support buffer"
+        },
+        {
+          "id": "test/utils.js:15",
+          "title": "utils.wetag(body, encoding) should support empty string"
+        },
+        {
+          "id": "test/utils.js:16",
+          "title": "utils.compileETag() should return generateETag for true"
+        },
+        {
+          "id": "test/utils.js:17",
+          "title": "utils.compileETag() should return undefined for false"
+        },
+        {
+          "id": "test/utils.js:18",
+          "title": "utils.compileETag() should return generateETag for string values \"strong\" and \"weak\""
+        },
+        {
+          "id": "test/utils.js:19",
+          "title": "utils.compileETag() should throw for unknown string values"
+        },
+        {
+          "id": "test/utils.js:20",
+          "title": "utils.compileETag() should throw for unsupported types like arrays and objects"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/auth.js",
+      "sha256": "788ee64833f7bf18c7c8d6236e2423f5f2f94d62ea750c7c456ece6fea92ed29",
+      "tests": 10,
+      "cases": [
+        {
+          "id": "test/acceptance/auth.js:1",
+          "title": "auth GET / should redirect to /login"
+        },
+        {
+          "id": "test/acceptance/auth.js:2",
+          "title": "auth GET /login should render login form"
+        },
+        {
+          "id": "test/acceptance/auth.js:3",
+          "title": "auth GET /login should display login error for bad user"
+        },
+        {
+          "id": "test/acceptance/auth.js:4",
+          "title": "auth GET /login should display login error for bad password"
+        },
+        {
+          "id": "test/acceptance/auth.js:5",
+          "title": "auth GET /logout should redirect to /"
+        },
+        {
+          "id": "test/acceptance/auth.js:6",
+          "title": "auth GET /restricted should redirect to /login without cookie"
+        },
+        {
+          "id": "test/acceptance/auth.js:7",
+          "title": "auth GET /restricted should succeed with proper cookie"
+        },
+        {
+          "id": "test/acceptance/auth.js:8",
+          "title": "auth POST /login should fail without proper username"
+        },
+        {
+          "id": "test/acceptance/auth.js:9",
+          "title": "auth POST /login should fail without proper password"
+        },
+        {
+          "id": "test/acceptance/auth.js:10",
+          "title": "auth POST /login should succeed with proper credentials"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/content-negotiation.js",
+      "sha256": "aeb415791ce1c7675401f3d41433900145620a191b6ad4e107a0b41f798c1446",
+      "tests": 6,
+      "cases": [
+        {
+          "id": "test/acceptance/content-negotiation.js:1",
+          "title": "content-negotiation GET / should default to text/html"
+        },
+        {
+          "id": "test/acceptance/content-negotiation.js:2",
+          "title": "content-negotiation GET / should accept to text/plain"
+        },
+        {
+          "id": "test/acceptance/content-negotiation.js:3",
+          "title": "content-negotiation GET / should accept to application/json"
+        },
+        {
+          "id": "test/acceptance/content-negotiation.js:4",
+          "title": "content-negotiation GET /users should default to text/html"
+        },
+        {
+          "id": "test/acceptance/content-negotiation.js:5",
+          "title": "content-negotiation GET /users should accept to text/plain"
+        },
+        {
+          "id": "test/acceptance/content-negotiation.js:6",
+          "title": "content-negotiation GET /users should accept to application/json"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/cookie-sessions.js",
+      "sha256": "65f79320983cb4dff1efcd03d9546cdf36635dde7a4b361eaa9501b7b95cd00c",
+      "tests": 3,
+      "cases": [
+        {
+          "id": "test/acceptance/cookie-sessions.js:1",
+          "title": "cookie-sessions GET / should display no views"
+        },
+        {
+          "id": "test/acceptance/cookie-sessions.js:2",
+          "title": "cookie-sessions GET / should set a session cookie"
+        },
+        {
+          "id": "test/acceptance/cookie-sessions.js:3",
+          "title": "cookie-sessions GET / should display 1 view on revisit"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/cookies.js",
+      "sha256": "02525d8572520090b040f5d00edfc224638430147af94a67894909b6d5ab5e47",
+      "tests": 6,
+      "cases": [
+        {
+          "id": "test/acceptance/cookies.js:1",
+          "title": "cookies GET / should have a form"
+        },
+        {
+          "id": "test/acceptance/cookies.js:2",
+          "title": "cookies GET / should respond with no cookies"
+        },
+        {
+          "id": "test/acceptance/cookies.js:3",
+          "title": "cookies GET / should respond to cookie"
+        },
+        {
+          "id": "test/acceptance/cookies.js:4",
+          "title": "cookies GET /forget should clear cookie"
+        },
+        {
+          "id": "test/acceptance/cookies.js:5",
+          "title": "cookies POST / should set a cookie"
+        },
+        {
+          "id": "test/acceptance/cookies.js:6",
+          "title": "cookies POST / should no set cookie w/o reminder"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/downloads.js",
+      "sha256": "404320d52882b3b35268c6217cf04711803782930b4d14641006a043207d65ee",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/acceptance/downloads.js:1",
+          "title": "downloads GET / should have a link to amazing.txt"
+        },
+        {
+          "id": "test/acceptance/downloads.js:2",
+          "title": "downloads GET /files/notes/groceries.txt should have a download header"
+        },
+        {
+          "id": "test/acceptance/downloads.js:3",
+          "title": "downloads GET /files/amazing.txt should have a download header"
+        },
+        {
+          "id": "test/acceptance/downloads.js:4",
+          "title": "downloads GET /files/missing.txt should respond with 404"
+        },
+        {
+          "id": "test/acceptance/downloads.js:5",
+          "title": "downloads GET /files/../index.js should respond with 403"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/ejs.js",
+      "sha256": "3babd4b539171c71a72afae2318c42b66d949e6599c712901963c732b6b1b803",
+      "tests": 1,
+      "cases": [
+        {
+          "id": "test/acceptance/ejs.js:1",
+          "title": "ejs GET / should respond with html"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/error-pages.js",
+      "sha256": "5f3fc7b689e76253d75a9f0d0a29dcbaa64151b2e157a54cb1bcb6bb2bc18855",
+      "tests": 10,
+      "cases": [
+        {
+          "id": "test/acceptance/error-pages.js:1",
+          "title": "error-pages GET / should respond with page list"
+        },
+        {
+          "id": "test/acceptance/error-pages.js:2",
+          "title": "error-pages Accept: text/html GET /403 should respond with 403"
+        },
+        {
+          "id": "test/acceptance/error-pages.js:3",
+          "title": "error-pages Accept: text/html GET /404 should respond with 404"
+        },
+        {
+          "id": "test/acceptance/error-pages.js:4",
+          "title": "error-pages Accept: text/html GET /500 should respond with 500"
+        },
+        {
+          "id": "test/acceptance/error-pages.js:5",
+          "title": "error-pages Accept: application/json GET /403 should respond with 403"
+        },
+        {
+          "id": "test/acceptance/error-pages.js:6",
+          "title": "error-pages Accept: application/json GET /404 should respond with 404"
+        },
+        {
+          "id": "test/acceptance/error-pages.js:7",
+          "title": "error-pages Accept: application/json GET /500 should respond with 500"
+        },
+        {
+          "id": "test/acceptance/error-pages.js:8",
+          "title": "error-pages Accept: text/plain GET /403 should respond with 403"
+        },
+        {
+          "id": "test/acceptance/error-pages.js:9",
+          "title": "error-pages Accept: text/plain GET /404 should respond with 404"
+        },
+        {
+          "id": "test/acceptance/error-pages.js:10",
+          "title": "error-pages Accept: text/plain GET /500 should respond with 500"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/error.js",
+      "sha256": "0409fe9e66ed52c7386a17d286c8d939cf0679c934e85811d277ec5c815b99da",
+      "tests": 3,
+      "cases": [
+        {
+          "id": "test/acceptance/error.js:1",
+          "title": "error GET / should respond with 500"
+        },
+        {
+          "id": "test/acceptance/error.js:2",
+          "title": "error GET /next should respond with 500"
+        },
+        {
+          "id": "test/acceptance/error.js:3",
+          "title": "error GET /missing should respond with 404"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/hello-world.js",
+      "sha256": "1047572c2e458969e9ff1dba0f9671b1a32a53de3633c79f9ea83c9669e5fc92",
+      "tests": 2,
+      "cases": [
+        {
+          "id": "test/acceptance/hello-world.js:1",
+          "title": "hello-world GET / should respond with hello world"
+        },
+        {
+          "id": "test/acceptance/hello-world.js:2",
+          "title": "hello-world GET /missing should respond with 404"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/markdown.js",
+      "sha256": "1cfe5b3a6715a9f9113c5b080bb5e761cea442eff4a6878e743bb9cb18a07bfa",
+      "tests": 2,
+      "cases": [
+        {
+          "id": "test/acceptance/markdown.js:1",
+          "title": "markdown GET / should respond with html"
+        },
+        {
+          "id": "test/acceptance/markdown.js:2",
+          "title": "markdown GET /fail should respond with an error"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/multi-router.js",
+      "sha256": "62ebf8ac4e00790b6d2db04baa85be064eeb31d6da6b63ba4669f6d558bd70e6",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/acceptance/multi-router.js:1",
+          "title": "multi-router GET / should respond with root handler"
+        },
+        {
+          "id": "test/acceptance/multi-router.js:2",
+          "title": "multi-router GET /api/v1/ should respond with APIv1 root handler"
+        },
+        {
+          "id": "test/acceptance/multi-router.js:3",
+          "title": "multi-router GET /api/v1/users should respond with users from APIv1"
+        },
+        {
+          "id": "test/acceptance/multi-router.js:4",
+          "title": "multi-router GET /api/v2/ should respond with APIv2 root handler"
+        },
+        {
+          "id": "test/acceptance/multi-router.js:5",
+          "title": "multi-router GET /api/v2/users should respond with users from APIv2"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/mvc.js",
+      "sha256": "fa95870634e2059676930875d1cf306693397d0f3ba08863a870d9f1035732b8",
+      "tests": 12,
+      "cases": [
+        {
+          "id": "test/acceptance/mvc.js:1",
+          "title": "mvc GET / should redirect to /users"
+        },
+        {
+          "id": "test/acceptance/mvc.js:2",
+          "title": "mvc GET /pet/0 should get pet"
+        },
+        {
+          "id": "test/acceptance/mvc.js:3",
+          "title": "mvc GET /pet/0/edit should get pet edit page"
+        },
+        {
+          "id": "test/acceptance/mvc.js:4",
+          "title": "mvc PUT /pet/2 should update the pet"
+        },
+        {
+          "id": "test/acceptance/mvc.js:5",
+          "title": "mvc GET /users should display a list of users"
+        },
+        {
+          "id": "test/acceptance/mvc.js:6",
+          "title": "mvc GET /user/:id when present should display the user"
+        },
+        {
+          "id": "test/acceptance/mvc.js:7",
+          "title": "mvc GET /user/:id when present should display the users pets"
+        },
+        {
+          "id": "test/acceptance/mvc.js:8",
+          "title": "mvc GET /user/:id when not present should 404"
+        },
+        {
+          "id": "test/acceptance/mvc.js:9",
+          "title": "mvc GET /user/:id/edit should display the edit form"
+        },
+        {
+          "id": "test/acceptance/mvc.js:10",
+          "title": "mvc PUT /user/:id should 500 on error"
+        },
+        {
+          "id": "test/acceptance/mvc.js:11",
+          "title": "mvc PUT /user/:id should update the user"
+        },
+        {
+          "id": "test/acceptance/mvc.js:12",
+          "title": "mvc POST /user/:id/pet should create a pet for user"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/params.js",
+      "sha256": "f3e14ec179c345496dbef4c0251e0430ebd694333c714c078156c4cd19fc00c5",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/acceptance/params.js:1",
+          "title": "params GET / should respond with instructions"
+        },
+        {
+          "id": "test/acceptance/params.js:2",
+          "title": "params GET /user/0 should respond with a user"
+        },
+        {
+          "id": "test/acceptance/params.js:3",
+          "title": "params GET /user/9 should fail to find user"
+        },
+        {
+          "id": "test/acceptance/params.js:4",
+          "title": "params GET /users/0-2 should respond with three users"
+        },
+        {
+          "id": "test/acceptance/params.js:5",
+          "title": "params GET /users/foo-bar should fail integer parsing"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/resource.js",
+      "sha256": "5139e45dad146bd6e1753f8802484b4fc3faa73e37bff189c6277e308b8f42ca",
+      "tests": 8,
+      "cases": [
+        {
+          "id": "test/acceptance/resource.js:1",
+          "title": "resource GET / should respond with instructions"
+        },
+        {
+          "id": "test/acceptance/resource.js:2",
+          "title": "resource GET /users should respond with all users"
+        },
+        {
+          "id": "test/acceptance/resource.js:3",
+          "title": "resource GET /users/1 should respond with user 1"
+        },
+        {
+          "id": "test/acceptance/resource.js:4",
+          "title": "resource GET /users/9 should respond with error"
+        },
+        {
+          "id": "test/acceptance/resource.js:5",
+          "title": "resource GET /users/1..3 should respond with users 1 through 3"
+        },
+        {
+          "id": "test/acceptance/resource.js:6",
+          "title": "resource DELETE /users/1 should delete user 1"
+        },
+        {
+          "id": "test/acceptance/resource.js:7",
+          "title": "resource DELETE /users/9 should fail"
+        },
+        {
+          "id": "test/acceptance/resource.js:8",
+          "title": "resource GET /users/1..3.json should respond with users 2 and 3 as json"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/route-map.js",
+      "sha256": "00b0da9b7dc07f25c7a596475d402027c87f346bf21eb0d24220d953d67269a9",
+      "tests": 5,
+      "cases": [
+        {
+          "id": "test/acceptance/route-map.js:1",
+          "title": "route-map GET /users should respond with users"
+        },
+        {
+          "id": "test/acceptance/route-map.js:2",
+          "title": "route-map DELETE /users should delete users"
+        },
+        {
+          "id": "test/acceptance/route-map.js:3",
+          "title": "route-map GET /users/:id should get a user"
+        },
+        {
+          "id": "test/acceptance/route-map.js:4",
+          "title": "route-map GET /users/:id/pets should get a users pets"
+        },
+        {
+          "id": "test/acceptance/route-map.js:5",
+          "title": "route-map GET /users/:id/pets/:pid should get a users pet"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/route-separation.js",
+      "sha256": "4bf8efc813b76faebc5c48ddeffe85ed2c50db155092854ead18f9d2ac1be695",
+      "tests": 10,
+      "cases": [
+        {
+          "id": "test/acceptance/route-separation.js:1",
+          "title": "route-separation GET / should respond with index"
+        },
+        {
+          "id": "test/acceptance/route-separation.js:2",
+          "title": "route-separation GET /users should list users"
+        },
+        {
+          "id": "test/acceptance/route-separation.js:3",
+          "title": "route-separation GET /user/:id should get a user"
+        },
+        {
+          "id": "test/acceptance/route-separation.js:4",
+          "title": "route-separation GET /user/:id should 404 on missing user"
+        },
+        {
+          "id": "test/acceptance/route-separation.js:5",
+          "title": "route-separation GET /user/:id/view should get a user"
+        },
+        {
+          "id": "test/acceptance/route-separation.js:6",
+          "title": "route-separation GET /user/:id/view should 404 on missing user"
+        },
+        {
+          "id": "test/acceptance/route-separation.js:7",
+          "title": "route-separation GET /user/:id/edit should get a user to edit"
+        },
+        {
+          "id": "test/acceptance/route-separation.js:8",
+          "title": "route-separation PUT /user/:id/edit should edit a user"
+        },
+        {
+          "id": "test/acceptance/route-separation.js:9",
+          "title": "route-separation POST /user/:id/edit?_method=PUT should edit a user"
+        },
+        {
+          "id": "test/acceptance/route-separation.js:10",
+          "title": "route-separation GET /posts should get a list of posts"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/vhost.js",
+      "sha256": "e8c39760376299c631755e18f39fee13b3522ad935f2f2ea51c1e34e36b31a12",
+      "tests": 4,
+      "cases": [
+        {
+          "id": "test/acceptance/vhost.js:1",
+          "title": "vhost example.com GET / should say hello"
+        },
+        {
+          "id": "test/acceptance/vhost.js:2",
+          "title": "vhost example.com GET /foo should say foo"
+        },
+        {
+          "id": "test/acceptance/vhost.js:3",
+          "title": "vhost foo.example.com GET / should redirect to /foo"
+        },
+        {
+          "id": "test/acceptance/vhost.js:4",
+          "title": "vhost bar.example.com GET / should redirect to /bar"
+        }
+      ]
+    },
+    {
+      "path": "test/acceptance/web-service.js",
+      "sha256": "43e75989e5cd70dc60fbdf1f7761004c8cb7c7d63f32a061f04a83aa04149fee",
+      "tests": 11,
+      "cases": [
+        {
+          "id": "test/acceptance/web-service.js:1",
+          "title": "web-service GET /api/users without an api key should respond with 400 bad request"
+        },
+        {
+          "id": "test/acceptance/web-service.js:2",
+          "title": "web-service GET /api/users with an invalid api key should respond with 401 unauthorized"
+        },
+        {
+          "id": "test/acceptance/web-service.js:3",
+          "title": "web-service GET /api/users with a valid api key should respond users json"
+        },
+        {
+          "id": "test/acceptance/web-service.js:4",
+          "title": "web-service GET /api/repos without an api key should respond with 400 bad request"
+        },
+        {
+          "id": "test/acceptance/web-service.js:5",
+          "title": "web-service GET /api/repos with an invalid api key should respond with 401 unauthorized"
+        },
+        {
+          "id": "test/acceptance/web-service.js:6",
+          "title": "web-service GET /api/repos with a valid api key should respond repos json"
+        },
+        {
+          "id": "test/acceptance/web-service.js:7",
+          "title": "web-service GET /api/user/:name/repos without an api key should respond with 400 bad request"
+        },
+        {
+          "id": "test/acceptance/web-service.js:8",
+          "title": "web-service GET /api/user/:name/repos with an invalid api key should respond with 401 unauthorized"
+        },
+        {
+          "id": "test/acceptance/web-service.js:9",
+          "title": "web-service GET /api/user/:name/repos with a valid api key should respond user repos json"
+        },
+        {
+          "id": "test/acceptance/web-service.js:10",
+          "title": "web-service GET /api/user/:name/repos with a valid api key should 404 with unknown user"
+        },
+        {
+          "id": "test/acceptance/web-service.js:11",
+          "title": "web-service when requesting an invalid route should respond with 404 json"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/Frameworks/express/run-node.cjs b/tests/Frameworks/express/run-node.cjs
new file mode 100644
index 00000000..3e861583
--- /dev/null
+++ b/tests/Frameworks/express/run-node.cjs
@@ -0,0 +1,33 @@
+'use strict';
+
+const fs = require('node:fs');
+const path = require('node:path');
+const crypto = require('node:crypto');
+const root = path.join(__dirname, 'upstream');
+const args = process.argv.slice(2);
+const selectedFile = args.find((arg) => arg.startsWith('--file='))?.slice(7);
+const selectedGrep = args.find((arg) => arg.startsWith('--grep='))?.slice(7);
+const output = args.find((arg) => arg.startsWith('--output='))?.slice(9);
+const pinned = JSON.parse(fs.readFileSync(path.join(__dirname, 'manifest.json'), 'utf8'));
+const manifest = pinned.files.filter(file => !selectedFile || file.path === selectedFile);
+if (!manifest.length) throw new Error('The requested file is not part of the pinned Express suite.');
+const files = manifest.map(file => {
+  const name = path.join(root, file.path);
+  if (crypto.createHash('sha256').update(fs.readFileSync(name)).digest('hex') !== file.sha256) throw new Error('Upstream test checksum changed: ' + file.path);
+  return name;
+});
+const metadata = JSON.parse(fs.readFileSync(path.join(__dirname, 'upstream.json'), 'utf8'));
+process.chdir(root);
+globalThis.__expressFinished = function finished(serialized) {
+  const result = { runtime: 'node', node: process.version, source: metadata, filtered: !!(selectedFile || selectedGrep), manifest, ...JSON.parse(serialized) };
+  const contents = JSON.stringify(result, null, 2) + '\n';
+  if (output) fs.writeFileSync(output, contents);
+  else console.log(contents);
+  process.exitCode = result.fail || result.pending || result.loadErrors.length || result.asynchronousErrors.length ? 1 : 0;
+};
+require('./runner.cjs')(files, {
+  grep: selectedGrep,
+  expectedTests: manifest.reduce((sum, file) => sum + file.tests, 0),
+  expectedCases: manifest.flatMap(file => file.cases),
+  fileNames: Object.fromEntries(manifest.map(file => [path.join(root, file.path), file.path])),
+});
diff --git a/tests/Frameworks/express/run-phasis.php b/tests/Frameworks/express/run-phasis.php
new file mode 100644
index 00000000..fd926545
--- /dev/null
+++ b/tests/Frameworks/express/run-phasis.php
@@ -0,0 +1,108 @@
+enableNode(new NodeOptions(cwd: $root, argv: ['phasis', __FILE__]));
+$engine->setLimit('maxLoopIterations', 1_000_000);
+if (isset($options['budget'])) {
+    $engine->setExecutionBudget((float) $options['budget']);
+}
+$result = null;
+$currentTest = null;
+$checkpoint = function () use (&$result, &$currentTest, $options): void {
+    if (!isset($options['output'])) {
+        return;
+    }
+    $partial = ($result ?? []) + ['currentTest' => $currentTest];
+    file_put_contents((string) $options['output'] . '.partial.json', json_encode(
+        $partial,
+        JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE | JSON_THROW_ON_ERROR,
+    ) . "\n");
+};
+$engine->setGlobal('__expressCurrent', function (string $title, string $file) use (&$currentTest, $checkpoint): void {
+    $currentTest = ['title' => $title, 'file' => $file];
+    $checkpoint();
+});
+$engine->setGlobal('__expressFinished', function (string $serialized) use (&$result, $engine, $checkpoint): void {
+    $result = json_decode($serialized, true, 512, JSON_THROW_ON_ERROR);
+    $checkpoint();
+    $engine->getNodeRuntime()?->close();
+});
+$engine->setGlobal('__expressProgress', function (string $serialized) use (&$result, $checkpoint): void {
+    $result = json_decode($serialized, true, 512, JSON_THROW_ON_ERROR);
+    $checkpoint();
+});
+$engine->setGlobal('__expressFiles', $files);
+$engine->setGlobal('__expressRunner', __DIR__ . '/runner.cjs');
+$engine->setGlobal('__expressOptions', [
+    'grep' => $options['grep'] ?? null,
+    'expectedTests' => array_sum(array_column($manifest, 'tests')),
+    'expectedCases' => array_merge(...array_column($manifest, 'cases')),
+    'fileNames' => array_combine($files, array_column($manifest, 'path')),
+]);
+try {
+    $engine->eval('require(__expressRunner)(__expressFiles, __expressOptions);');
+} catch (Throwable $error) {
+    $result ??= [
+        'complete' => false,
+        'pass' => 0,
+        'fail' => 0,
+        'pending' => 0,
+        'tests' => [],
+        'loadErrors' => [],
+        'asynchronousErrors' => [],
+    ];
+    $result['complete'] = false;
+    $result['loadErrors'][] = ['error' => ['name' => $error::class, 'message' => $error->getMessage()]];
+    $result['interruptedTest'] = $currentTest;
+}
+if ($result === null) {
+    $result = json_decode((string) $engine->eval('JSON.stringify(globalThis.__expressReport || {})'), true, 512, JSON_THROW_ON_ERROR);
+    $result['complete'] = false;
+    $result['completionError'] = 'The upstream runner did not signal completion.';
+}
+$engine->getNodeRuntime()?->close();
+$result = [
+    'runtime' => 'phasis',
+    'php' => PHP_VERSION,
+    'source' => $metadata,
+    'filtered' => isset($options['file']) || isset($options['grep']),
+    'manifest' => $manifest,
+] + $result;
+$serialized = json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE | JSON_THROW_ON_ERROR) . "\n";
+if (isset($options['output'])) {
+    file_put_contents((string) $options['output'], $serialized);
+} else {
+    echo $serialized;
+}
+exit(($result['complete'] ?? false) && ($result['fail'] ?? 0) === 0 && ($result['pending'] ?? 0) === 0
+    && ($result['loadErrors'] ?? []) === [] && ($result['asynchronousErrors'] ?? []) === [] ? 0 : 1);
diff --git a/tests/Frameworks/express/run.py b/tests/Frameworks/express/run.py
new file mode 100644
index 00000000..6ebb8b75
--- /dev/null
+++ b/tests/Frameworks/express/run.py
@@ -0,0 +1,218 @@
+#!/usr/bin/env python3
+"""Run the complete pinned Express suite with bounded, isolated worker groups."""
+
+import argparse
+import concurrent.futures
+import datetime
+import hashlib
+import json
+import os
+from pathlib import Path
+import signal
+import subprocess
+import sys
+import threading
+import time
+
+
+HERE = Path(__file__).resolve().parent
+REPOSITORY = HERE.parents[2]
+
+
+def tree_hash(directory):
+    digest = hashlib.sha256()
+    for path in sorted(directory.rglob("*")):
+        if path.is_file():
+            digest.update(path.relative_to(directory).as_posix().encode() + b"\0")
+            digest.update(hashlib.sha256(path.read_bytes()).digest())
+    return digest.hexdigest()
+
+
+def source_identity():
+    harness = hashlib.sha256()
+    for name in ("run.py", "runner.cjs", "run-node.cjs", "run-phasis.php", "setup.py", "upstream.json"):
+        harness.update(name.encode() + b"\0" + (HERE / name).read_bytes())
+    return {
+        "runtimeSha256": tree_hash(REPOSITORY / "src"),
+        "upstreamSha256": tree_hash(HERE / "upstream"),
+        "manifestSha256": hashlib.sha256((HERE / "manifest.json").read_bytes()).hexdigest(),
+        "packageLockSha256": hashlib.sha256((HERE.parent / "package-lock.json").read_bytes()).hexdigest(),
+        "harnessSha256": harness.hexdigest(),
+    }
+
+
+def terminate_group(process):
+    # A worker may exit while its descendants retain sockets or pipe handles.
+    # Every worker owns a fresh process group, so cleanup includes descendants.
+    try:
+        os.killpg(process.pid, signal.SIGTERM)
+    except ProcessLookupError:
+        pass
+    if process.poll() is None:
+        try:
+            process.wait(timeout=2)
+        except subprocess.TimeoutExpired:
+            pass
+    try:
+        os.killpg(process.pid, signal.SIGKILL)
+    except ProcessLookupError:
+        pass
+    process.wait()
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("--runtime", choices=("node", "phasis", "both"), default="both")
+    parser.add_argument("--jobs", type=int, choices=(1, 2), default=1)
+    parser.add_argument("--timeout", type=float, default=120)
+    parser.add_argument("--output", type=Path, required=True)
+    args = parser.parse_args()
+    if args.timeout <= 0:
+        parser.error("--timeout must be positive")
+    args.output = args.output.resolve()
+    if args.output.exists():
+        parser.error("--output must name a new directory")
+    args.output.mkdir(parents=True)
+    manifest = json.loads((HERE / "manifest.json").read_text())
+    source = json.loads((HERE / "upstream.json").read_text())
+    identity_before = source_identity()
+    runtimes = ["node", "phasis"] if args.runtime == "both" else [args.runtime]
+    tasks = [(runtime, entry) for runtime in runtimes for entry in manifest["files"]]
+    stopped = threading.Event()
+    lock = threading.Lock()
+    active = {}
+
+    def interrupt(signum, frame):
+        stopped.set()
+        raise KeyboardInterrupt
+
+    previous_handlers = {name: signal.signal(name, interrupt) for name in (signal.SIGINT, signal.SIGTERM)}
+
+    def execute(task):
+        runtime, entry = task
+        if stopped.is_set():
+            return None
+        stem = entry["path"].replace("/", "__").removesuffix(".js")
+        output = args.output / (stem + "-" + runtime + ".json")
+        log = output.with_suffix(".log")
+        command = (["node", str(HERE / "run-node.cjs")] if runtime == "node" else
+                   ["php", "-d", "memory_limit=1G", str(HERE / "run-phasis.php")])
+        command += ["--file=" + entry["path"], "--output=" + str(output)]
+        timed_out = False
+        start = time.monotonic()
+        with log.open("w") as handle:
+            with lock:
+                if stopped.is_set():
+                    return None
+                process = subprocess.Popen(command, cwd=REPOSITORY,
+                                           env=dict(os.environ, XDEBUG_MODE="off"),
+                                           stdout=handle, stderr=subprocess.STDOUT,
+                                           start_new_session=True)
+                active[process.pid] = process
+            try:
+                try:
+                    exit_code = process.wait(timeout=args.timeout)
+                except subprocess.TimeoutExpired:
+                    timed_out = True
+                    exit_code = None
+            finally:
+                terminate_group(process)
+                with lock:
+                    active.pop(process.pid, None)
+        partial = Path(str(output) + ".partial.json")
+        report_file = output if output.exists() else partial
+        try:
+            report = json.loads(report_file.read_text()) if report_file.exists() else {}
+        except json.JSONDecodeError:
+            report = {"complete": False, "completionError": "The worker was interrupted while writing its report."}
+        expected = entry["cases"]
+        actual = report.get("caseManifest", [])
+        outcomes = {test.get("id"): test for test in report.get("tests", [])}
+        missing = [case["id"] for case in expected if case["id"] not in outcomes]
+        case_identity_matches = actual == expected
+        result = {
+            "runtime": runtime, "file": entry["path"], "expectedTests": entry["tests"],
+            "exitCode": exit_code, "timedOut": timed_out, "log": log.name,
+            "elapsedSeconds": time.monotonic() - start,
+            "caseIdentityMatches": case_identity_matches, "unaccountedCases": missing,
+            "report": report,
+        }
+        print(json.dumps({key: value for key, value in result.items() if key not in ("report", "unaccountedCases")}
+                         | {"complete": report.get("complete", False), "pass": report.get("pass", 0),
+                            "fail": report.get("fail", 0)}), flush=True)
+        return result
+
+    results = []
+    completed = set()
+    pool = concurrent.futures.ThreadPoolExecutor(max_workers=args.jobs)
+    futures = [pool.submit(execute, task) for task in tasks]
+    try:
+        for future in concurrent.futures.as_completed(futures):
+            result = future.result()
+            completed.add(future)
+            if result is not None:
+                results.append(result)
+                (args.output / "progress.json").write_text(json.dumps(results, indent=2) + "\n")
+    except KeyboardInterrupt:
+        stopped.set()
+    finally:
+        if stopped.is_set():
+            for future in futures:
+                future.cancel()
+            with lock:
+                processes = list(active.values())
+            for process in processes:
+                terminate_group(process)
+        pool.shutdown(wait=True, cancel_futures=True)
+        for future in futures:
+            if future not in completed and not future.cancelled():
+                result = future.result()
+                if result is not None:
+                    results.append(result)
+        for name, handler in previous_handlers.items():
+            signal.signal(name, handler)
+    identity_after = source_identity()
+    stable_source = identity_before == identity_after
+    summary = {
+        "generatedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(),
+        "source": source, "manifest": manifest, "filtered": False,
+        "identityBefore": identity_before, "identityAfter": identity_after,
+        "stableSource": stable_source, "interrupted": stopped.is_set(),
+        "execution": {"isolation": "file", "workers": args.jobs, "timeoutSeconds": args.timeout},
+        "runtimes": {}, "files": results,
+    }
+    successful = stable_source and not stopped.is_set()
+    for runtime in runtimes:
+        selected = {result["file"]: result for result in results if result["runtime"] == runtime}
+        incomplete = [entry["path"] for entry in manifest["files"]
+                      if entry["path"] not in selected or
+                      not selected[entry["path"]]["report"].get("complete") or
+                      selected[entry["path"]]["timedOut"]]
+        unaccounted = [case["id"] for entry in manifest["files"] for case in entry["cases"]
+                       if entry["path"] not in selected or case["id"] in selected[entry["path"]]["unaccountedCases"]]
+        values = {
+            "complete": not incomplete,
+            "expectedTests": manifest["tests"],
+            "discovered": sum(result["report"].get("discovered", 0) for result in selected.values()),
+            "incompleteFiles": incomplete,
+            "unaccountedTests": len(unaccounted), "unaccountedCases": unaccounted,
+            "caseIdentityMatches": all(result["caseIdentityMatches"] for result in selected.values()),
+        }
+        for name in ("pass", "fail", "pending"):
+            values[name] = sum(result["report"].get(name, 0) for result in selected.values())
+        for name in ("loadErrors", "asynchronousErrors"):
+            values[name] = sum(len(result["report"].get(name, [])) for result in selected.values())
+        values["success"] = (stable_source and values["complete"] and values["caseIdentityMatches"]
+                             and not unaccounted and values["pass"] == values["expectedTests"]
+                             and values["fail"] == values["pending"] == values["loadErrors"] == values["asynchronousErrors"] == 0
+                             and all(result["exitCode"] == 0 for result in selected.values()))
+        successful = successful and values["success"]
+        summary["runtimes"][runtime] = values
+    (args.output / "summary.json").write_text(json.dumps(summary, indent=2) + "\n")
+    print(json.dumps({runtime: {key: value for key, value in values.items() if key != "unaccountedCases"}
+                      for runtime, values in summary["runtimes"].items()}, indent=2))
+    return 0 if successful else 1
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/tests/Frameworks/express/runner.cjs b/tests/Frameworks/express/runner.cjs
new file mode 100644
index 00000000..a090dff0
--- /dev/null
+++ b/tests/Frameworks/express/runner.cjs
@@ -0,0 +1,97 @@
+'use strict';
+
+require('mocha/mocha.js');
+const Mocha = globalThis.Mocha;
+
+function serializeError(error) {
+  return {
+    name: error && error.name || 'Error',
+    message: error && error.message || String(error),
+    stack: error && error.stack || '',
+    code: error && error.code,
+  };
+}
+
+module.exports = function runExpressTests(files, options = {}) {
+  const output = { complete: false, discovered: 0, pass: 0, fail: 0, pending: 0, tests: [], loadErrors: [], asynchronousErrors: [] };
+  const caseIds = new WeakMap();
+  let responses = [];
+  const ClientRequest = require('http').ClientRequest;
+  const originalEmit = ClientRequest.prototype.emit;
+  ClientRequest.prototype.emit = function (event, ...args) {
+    if (event === 'response') {
+      const response = args[0], socket = response.socket;
+      responses.push({ url: this.path, host: this.host, status: response.statusCode, headers: response.headers,
+        localAddress: socket.localAddress, localPort: socket.localPort,
+        remoteAddress: socket.remoteAddress, remotePort: socket.remotePort });
+    }
+    return originalEmit.call(this, event, ...args);
+  };
+  function checkpoint() {
+    if (typeof globalThis.__expressProgress === 'function') globalThis.__expressProgress(JSON.stringify(output));
+  }
+  globalThis.__expressReport = output;
+  const mocha = new Mocha({ ui: 'bdd', timeout: options.timeout || 2000, checkLeaks: true, reporter: function Reporter(runner) {
+    runner.on('test', test => {
+      responses = [];
+      if (typeof globalThis.__expressCurrent === 'function') globalThis.__expressCurrent(test.fullTitle(), test.file);
+    });
+    runner.on('pass', (test) => {
+      output.pass++;
+      output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'pass' });
+      if (output.tests.length % 100 === 0) checkpoint();
+    });
+    runner.on('fail', (test, error) => {
+      output.fail++;
+      output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'fail', error: serializeError(error), responses });
+      checkpoint();
+    });
+    runner.on('pending', (test) => {
+      output.pending++;
+      output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'pending' });
+    });
+  } });
+  const onUncaught = (error) => {
+    output.asynchronousErrors.push(serializeError(error));
+    if (typeof globalThis.onerror === 'function') globalThis.onerror(error.message, '', 0, 0, error);
+  };
+  process.on('uncaughtException', onUncaught);
+  process.on('unhandledRejection', onUncaught);
+
+  require('./upstream/test/support/env.js');
+  for (const file of files) {
+    try {
+      mocha.suite.emit('pre-require', globalThis, file, mocha);
+      const value = require(file);
+      mocha.suite.emit('require', value, file, mocha);
+      mocha.suite.emit('post-require', globalThis, file, mocha);
+    } catch (error) {
+      output.loadErrors.push({ file, error: serializeError(error) });
+    }
+  }
+  output.discovered = mocha.suite.total();
+  const fileCounts = Object.create(null);
+  output.caseManifest = [];
+  mocha.suite.eachTest(test => {
+    const file = options.fileNames[test.file];
+    const id = file + ':' + (fileCounts[file] = (fileCounts[file] || 0) + 1);
+    caseIds.set(test, id);
+    output.caseManifest.push({ id, title: test.fullTitle() });
+  });
+  if (JSON.stringify(output.caseManifest) !== JSON.stringify(options.expectedCases)) {
+    output.loadErrors.push({ error: { name: 'CaseIdentityMismatch', message: 'The discovered upstream case identities differ from the pinned manifest.' } });
+  }
+  if (options.expectedTests !== undefined && output.discovered !== options.expectedTests) {
+    output.loadErrors.push({ error: { name: 'DiscoveryMismatch', message: `Expected ${options.expectedTests} upstream tests, discovered ${output.discovered}.` } });
+  }
+  checkpoint();
+  if (options.grep) mocha.grep(new RegExp(options.grep));
+  mocha.run(() => {
+    ClientRequest.prototype.emit = originalEmit;
+    process.removeListener('uncaughtException', onUncaught);
+    process.removeListener('unhandledRejection', onUncaught);
+    output.complete = true;
+    if (typeof globalThis.__expressFinished === 'function') globalThis.__expressFinished(JSON.stringify(output));
+  });
+  return output;
+};
diff --git a/tests/Frameworks/express/setup.py b/tests/Frameworks/express/setup.py
new file mode 100644
index 00000000..3eb35df0
--- /dev/null
+++ b/tests/Frameworks/express/setup.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+"""Fetch the exact Express source archive used by the compatibility suite."""
+
+import hashlib
+import io
+import json
+from pathlib import Path
+import shutil
+import tarfile
+import tempfile
+import urllib.request
+
+BASE = Path(__file__).resolve().parent
+
+
+def main():
+    metadata = json.loads((BASE / 'upstream.json').read_text())
+    archive = urllib.request.urlopen(metadata['archive'], timeout=60).read()
+    actual = hashlib.sha256(archive).hexdigest()
+    if actual != metadata['sha256']:
+        raise RuntimeError(f'Express archive checksum mismatch: {actual}')
+    staging = Path(tempfile.mkdtemp(prefix='.express-upstream-', dir=BASE))
+    try:
+        with tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as package:
+            for member in package.getmembers():
+                parts = Path(member.name).parts
+                if len(parts) == 1:
+                    continue
+                member.name = str(Path(*parts[1:]))
+                package.extract(member, staging, filter='data')
+        package_json = json.loads((staging / 'package.json').read_text())
+        if package_json['version'] != metadata['version']:
+            raise RuntimeError('Express source version does not match the manifest')
+        target = BASE / 'upstream'
+        if target.exists():
+            shutil.rmtree(target)
+        staging.rename(target)
+    finally:
+        if staging.exists():
+            shutil.rmtree(staging)
+    print(f'Prepared Express {metadata["version"]} at {metadata["revision"]}')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/Frameworks/express/test_runner.py b/tests/Frameworks/express/test_runner.py
new file mode 100644
index 00000000..0ded569c
--- /dev/null
+++ b/tests/Frameworks/express/test_runner.py
@@ -0,0 +1,44 @@
+"""Regression checks for owned worker-process cleanup."""
+
+import os
+from pathlib import Path
+import selectors
+import subprocess
+import sys
+import unittest
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+from run import terminate_group
+
+
+class WorkerCleanupTest(unittest.TestCase):
+    def test_termination_reaps_worker_and_stops_its_child(self):
+        program = """
+import signal, subprocess, sys, time
+child = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(600)'])
+def stop(signum, frame):
+    child.wait(timeout=1)
+    sys.exit(0)
+signal.signal(signal.SIGTERM, stop)
+print(child.pid, flush=True)
+time.sleep(600)
+"""
+        worker = subprocess.Popen([sys.executable, "-c", program], stdout=subprocess.PIPE,
+                                  stderr=subprocess.PIPE, text=True, start_new_session=True)
+        try:
+            with selectors.DefaultSelector() as selector:
+                selector.register(worker.stdout, selectors.EVENT_READ)
+                self.assertTrue(selector.select(timeout=5), "Worker did not publish its child PID")
+                child_pid = int(worker.stdout.readline())
+            terminate_group(worker)
+            self.assertIsNotNone(worker.returncode)
+            with self.assertRaises(ProcessLookupError):
+                os.kill(child_pid, 0)
+        finally:
+            terminate_group(worker)
+            worker.stdout.close()
+            worker.stderr.close()
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/tests/Frameworks/express/upstream.json b/tests/Frameworks/express/upstream.json
new file mode 100644
index 00000000..b6a208dc
--- /dev/null
+++ b/tests/Frameworks/express/upstream.json
@@ -0,0 +1,7 @@
+{
+  "package": "express",
+  "version": "5.3.0",
+  "revision": "cf6722bf89a86905281d9160b6482e08166b5ef0",
+  "archive": "https://codeload.github.com/expressjs/express/tar.gz/cf6722bf89a86905281d9160b6482e08166b5ef0",
+  "sha256": "9a5bd805f9045c1e724044e2d523ddbd1ce145fa4bec30cdbbb4067597ff18e6"
+}
diff --git a/tests/Frameworks/hono/.gitignore b/tests/Frameworks/hono/.gitignore
new file mode 100644
index 00000000..b82c67ae
--- /dev/null
+++ b/tests/Frameworks/hono/.gitignore
@@ -0,0 +1,3 @@
+.generated/
+results/
+__pycache__/
diff --git a/tests/Frameworks/hono/README.md b/tests/Frameworks/hono/README.md
new file mode 100644
index 00000000..1b5f7e90
--- /dev/null
+++ b/tests/Frameworks/hono/README.md
@@ -0,0 +1,117 @@
+# Hono upstream compatibility
+
+The ignored source tree in `upstream/hono-4.13.13` is the unchanged Hono v4.13.13
+archive at commit `08a023cbfde55b434fb0fb30fae35d42e4bf20aa`. The repository,
+commit archive URL, SHA-256 checksum, tag and revision are recorded in
+`upstream.json`. Setup verifies the downloaded archive and rejects edited
+existing source files.
+`python3 tests/Frameworks/hono/inventory.py` lists every original project,
+including Bun, Deno, Fastly and workerd suites, with source hashes.
+
+Install the exact shared development dependencies with `npm ci --prefix
+tests/Frameworks`, then run from the Phasis repository root:
+
+```bash
+python3 -B tests/Frameworks/hono/setup.py
+python3 tests/Frameworks/hono/run.py
+python3 tests/Frameworks/hono/run.py --project jsx-runtime-default
+python3 tests/Frameworks/hono/run.py --project jsx-runtime-dom
+python3 tests/Frameworks/hono/run.py --project node
+python3 tests/Frameworks/hono/run-toolchain.py
+python3 -B tests/Frameworks/hono/selftest.py
+```
+
+Pass upstream relative filenames to narrow a run, for example:
+
+```bash
+python3 tests/Frameworks/hono/run.py src/context.test.ts src/request.test.ts
+```
+
+`--runtime node` and `--runtime phasis` select a single runtime. The default
+runs both and compares every discovered case's identity and outcome. Each
+file runs in a separate process, sequentially, with a 1,800 second outer wall
+limit (`--timeout` overrides it). This lets large files finish hundreds of
+cases while retaining the original per-test and per-hook deadlines.
+The PHP worker uses `XDEBUG_MODE=off`, a 1 GiB memory limit and a one million
+iteration limit so the unchanged 100,000-entry parser and large-body stress
+cases fit. A timeout kills the process group, including compiler children.
+The worker closes host resources after the suite completes, as Vitest does
+when terminating its worker. This also cleans up servers that upstream
+runtime tests intentionally leave open.
+
+`build.mjs` uses esbuild only during test preparation. It transpiles the
+original source and assertions to a strict CommonJS module graph, preserving
+original `import.meta` and filename metadata as well as module
+boundaries for module reset and spies. It makes transpiler-generated export
+accessors configurable and preserves namespace identity to match Vitest's
+mockable module host. It does not replace package implementation code or
+rewrite assertions. Phasis executes all generated JavaScript in PHP.
+
+`harness.mjs` uses the real pinned Vitest assertion and spy implementations,
+Chai and Sinon fake timers. Its collector implements suites, parameterized
+cases, asynchronous registration, hooks and explicit upstream skips.
+Unsupported harness operations throw and are reported separately. Upstream
+skip declarations remain skips, never passes. The test environment clears
+`NO_COLOR` for both engines, matching the color tests' unstubbed assumption.
+The Node runtime project sets `NAME=Node`, as its upstream configuration does.
+Test and hook deadlines preserve Vitest 5's defaults of 5,000 ms and 10,000 ms,
+explicit numeric/options values, suite inheritance and disabled deadlines.
+Captured real timers and monotonic time keep deadlines effective under fake
+timers and synchronous or microtask starvation. Failed suite setup is recorded
+as a suite failure with blocked cases, separately from upstream skip declarations.
+The self-test compares intentional async, synchronous, microtask, mock-timer
+and hook deadline failures against the actual pinned Vitest runner.
+
+Every invocation writes an immutable run directory under `results/runs/`.
+Its manifest records the upstream revision, project, complete project
+inventory, selected files, source SHA-256 values, runtime outcomes, elapsed
+time per file, and runtime, harness and dependency hashes at the start and
+end, plus case comparison failures. A run whose source or dependencies changed is exploratory evidence
+and cannot establish a result for a single revision. Per-file logs and case reports belong to that same run.
+`results/manifest.json` and the top-level per-file reports are convenience
+copies; reports from different runs must not be combined into a completeness
+claim. Empty discovery, collection errors, process failures and harness
+limitations fail the command.
+
+The separate toolchain runner prepares compile-time fixtures from the exactly
+pinned published Hono package and runs the five unchanged declaration checks
+with the pinned native TypeScript compiler. It links the ignored
+`dist` build output to that package; it does not change upstream sources.
+Its immutable manifest and native Vitest report remain separate from runtime
+results. To prepare the declaration fixtures for a direct native Vitest run:
+
+```bash
+node tests/Frameworks/hono/prepare-toolchain.mjs
+```
+
+An independent native Vitest baseline runs the original source:
+
+```bash
+node tests/Frameworks/node_modules/vitest/vitest.mjs run \
+  --config tests/Frameworks/hono/vitest.config.mjs \
+  --reporter=json --outputFile=/tmp/hono-native.json
+```
+
+Set `PHASIS_HONO_PROJECT` to one of the project names above to select that
+project in native Vitest. Compare an independent native report against a
+single immutable runner manifest with:
+
+```bash
+python3 tests/Frameworks/hono/compare-native.py /tmp/hono-native.json \
+  tests/Frameworks/hono/results/runs/RUN/manifest.json --runtime node
+```
+
+This compares names, multiplicities and outcomes for every selected file.
+Missing reports and native collection failures are explicit failures.
+
+The upstream main project contains 122 source test files and two build test
+files. The latter spawn the TypeScript compiler against published declaration
+artifacts; the runtime runner selects the 122 source files, while both build
+files remain visible in the original main inventory and run through the
+separate toolchain command. They are not runtime passes.
+The two additional JSX projects each rerun nine DOM/hooks files with their
+respective JSX import source. The Node runtime project tests the actual
+`@hono/node-server` package over HTTP. Upstream also has Fastly, workerd, Bun
+and Deno runtime-specific suites; these require their respective hosts and
+are not represented by the Node project. Passing the main project alone is
+not a claim that all upstream projects or all host environments pass.
diff --git a/tests/Frameworks/hono/build-selftest.mjs b/tests/Frameworks/hono/build-selftest.mjs
new file mode 100644
index 00000000..1d181267
--- /dev/null
+++ b/tests/Frameworks/hono/build-selftest.mjs
@@ -0,0 +1,14 @@
+import { build } from 'esbuild';
+import { mkdir, writeFile } from 'node:fs/promises';
+import { resolve, dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
+const directory = dirname(fileURLToPath(import.meta.url));
+const output = resolve(directory, '.generated/selftest');
+await mkdir(output, { recursive: true });
+await build({
+  entryPoints: [resolve(directory, 'fixtures/timeouts-entry.mjs')],
+  outfile: resolve(output, 'timeouts.cjs'), bundle: true, platform: 'node',
+  format: 'cjs', target: 'es2022', banner: { js: '"use strict";' }, logLevel: 'warning',
+});
+await writeFile(resolve(output, 'timeouts.mjs'),
+  "import {createRequire} from 'node:module';\nconst require = createRequire(import.meta.url);\nrequire('./timeouts.cjs');\n");
diff --git a/tests/Frameworks/hono/build.mjs b/tests/Frameworks/hono/build.mjs
new file mode 100644
index 00000000..c376881f
--- /dev/null
+++ b/tests/Frameworks/hono/build.mjs
@@ -0,0 +1,100 @@
+import { build } from 'esbuild';
+import { resolve, dirname, relative } from 'node:path';
+import { fileURLToPath, pathToFileURL } from 'node:url';
+import { mkdir, readFile, writeFile, readdir, stat, rename } from 'node:fs/promises';
+import { builtinModules } from 'node:module';
+async function writeGenerated(path, contents) {
+  const temporary = `${path}.${process.pid}.tmp`;
+  await writeFile(temporary, contents);
+  await rename(temporary, path);
+}
+const directory = dirname(fileURLToPath(import.meta.url));
+const metadata = JSON.parse(await readFile(resolve(directory, 'upstream.json'), 'utf8'));
+const upstream = resolve(directory, metadata.directory);
+const project = process.env.PHASIS_HONO_PROJECT || 'main';
+const output = resolve(directory, '.generated', ...(project === 'main' ? [] : [project]));
+const modules = resolve(output, 'modules');
+await mkdir(modules, { recursive: true });
+const stamp = `${metadata.commit}:cjs-graph-1:${(await stat(fileURLToPath(import.meta.url))).mtimeMs}`;
+let previous;
+try { previous = await readFile(resolve(output, 'stamp'), 'utf8'); } catch {}
+if (previous !== stamp) {
+  const files = [];
+  const assets = [];
+  async function visit(path) {
+    for (const entry of await readdir(path, { withFileTypes: true })) {
+      const file = resolve(path, entry.name);
+      if (entry.isDirectory()) await visit(file);
+      else if (/\.(?:tsx?|js)$/.test(file) && !file.endsWith('.d.ts')) files.push(file);
+      else assets.push(file);
+    }
+  }
+  for (const area of ['src', 'scripts', 'build', 'runtime-tests']) {
+    try { await visit(resolve(upstream, area)); } catch (error) { if (error.code !== 'ENOENT') throw error; }
+  }
+  const result = await build({
+    entryPoints: files, outbase: upstream, outdir: modules, bundle: false,
+    format: 'cjs', platform: 'node', target: 'es2022', write: false,
+    jsx: 'automatic', jsxImportSource: resolve(modules, project === 'jsx-runtime-dom' ? 'src/jsx/dom' : 'src/jsx'),
+    supported: { 'dynamic-import': false },
+    define: {
+      'import.meta.url': '__honoSourceUrl', 'import.meta.dirname': '__honoSourceDirectory',
+      'import.meta.filename': '__honoSourceFile', '__filename': '__honoSourceFile', '__dirname': '__honoSourceDirectory',
+    },
+    logLevel: 'warning',
+  });
+  const originalFiles = new Map(files.map(file => [resolve(modules, relative(upstream, file).replace(/\.tsx?$/, '.js')), file]));
+  for (const file of result.outputFiles) {
+    const original = originalFiles.get(file.path);
+    if (!original) throw new Error('Unknown transpiled source: ' + file.path);
+    const sourceMetadata = `var __honoSourceUrl = ${JSON.stringify(pathToFileURL(original).href)}, __honoSourceFile = ${JSON.stringify(original)}, __honoSourceDirectory = ${JSON.stringify(dirname(original))};\n`;
+    await mkdir(dirname(file.path), { recursive: true });
+    // Vitest exposes mutable import namespaces so spies can replace exports.
+    // CJS imports retain property reads, preserving live spy observations.
+    const contents = file.text
+      .replace('get: all[name], enumerable: true', 'get: all[name], enumerable: true, configurable: true')
+      .replace('get: () => from[key], enumerable:', 'get: () => from[key], configurable: true, enumerable:')
+      .replace('__toESM = (mod, isNodeMode, target) => (target =', '__toESM = (mod, isNodeMode, target) => mod?.__esModule ? mod : (target =');
+    await writeGenerated(file.path, '"use strict";\n' + sourceMetadata + contents);
+  }
+  for (const file of assets) {
+    const target = resolve(modules, relative(upstream, file));
+    await mkdir(dirname(target), { recursive: true });
+    await writeGenerated(target, await readFile(file));
+  }
+  await writeGenerated(resolve(modules, 'package.json'), JSON.stringify({ type: 'commonjs' }));
+  const vitest = resolve(modules, 'node_modules/vitest');
+  await mkdir(vitest, { recursive: true });
+  await writeGenerated(resolve(vitest, 'package.json'), JSON.stringify({ name: 'vitest', main: 'index.cjs' }));
+  await writeGenerated(resolve(vitest, 'index.cjs'), `module.exports = require(${JSON.stringify(resolve(output, 'harness.cjs'))});\n`);
+  await writeGenerated(resolve(output, 'stamp'), stamp);
+}
+const harnessBuild = await build({
+  entryPoints: [resolve(directory, 'harness.mjs')], outfile: resolve(output, 'harness.cjs'),
+  bundle: true, format: 'cjs', platform: 'node', target: 'es2022', write: false,
+  external: ['node:*', ...builtinModules], logLevel: 'warning',
+});
+for (const file of harnessBuild.outputFiles) await writeGenerated(file.path, '"use strict";\n' + file.text);
+for (const name of process.argv.slice(2)) {
+  const file = resolve(modules, name.replace(/\.tsx?$/, '.js'));
+  await stat(file);
+  const target = resolve(output, name.replace(/[\\/]/g, '__').replace(/\.(?:tsx?|js)$/, '.mjs'));
+  const entry = `import {createRequire} from 'node:module';
+const require = createRequire(import.meta.url);
+const harness = require(${JSON.stringify(resolve(output, 'harness.cjs'))});
+globalThis.__honoCase ||= value => process.stdout.write('__PHASIS_HONO_CASE__' + value + '\\n');
+globalThis.__honoResetModules = () => {
+  for (const key of Object.keys(require.cache)) {
+    if (key.startsWith(${JSON.stringify(modules + '/')})) delete require.cache[key];
+  }
+};
+require(${JSON.stringify(file)});
+harness.run().then(report => {
+  globalThis.__honoReport = report;
+  if (globalThis.__honoComplete) globalThis.__honoComplete();
+  else process.stdout.write('__PHASIS_HONO_REPORT__' + JSON.stringify(report) + '\\n', () => process.exit(0));
+});
+`;
+  await writeGenerated(target, entry);
+  console.log(target);
+}
diff --git a/tests/Frameworks/hono/compare-native.py b/tests/Frameworks/hono/compare-native.py
new file mode 100644
index 00000000..5b95b390
--- /dev/null
+++ b/tests/Frameworks/hono/compare-native.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+"""Compare every case with an independent, original-source Vitest JSON report."""
+import argparse
+from collections import Counter
+import json
+from pathlib import Path
+
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument('native', type=Path)
+parser.add_argument('manifest', type=Path)
+parser.add_argument('--runtime', choices=['node', 'phasis'], default='node')
+args = parser.parse_args()
+reference = json.loads(args.native.read_text())
+manifest = json.loads(args.manifest.read_text())
+marker = Path(manifest['upstream']['directory']).name + '/'
+files = {row['name'].split(marker, 1)[-1]: row for row in reference['testResults']}
+comparison = []
+statuses = {'pass': 'passed', 'upstream-skip': 'skipped', 'suite-blocked': 'skipped', 'fail': 'failed', 'harness-blocked': 'harness-blocked'}
+for name in manifest['selected']:
+    row = {'file': name, 'status': 'match'}
+    comparison.append(row)
+    native = files.get(name)
+    if native is None:
+        row['status'] = 'native-file-missing'
+        continue
+    if not native['assertionResults']:
+        row['status'] = 'native-collection-blocked'
+        row['message'] = native.get('message', '')
+        continue
+    report_file = args.manifest.parent / (name.replace('/', '__').rsplit('.', 1)[0] + '-' + args.runtime + '.json')
+    if not report_file.is_file():
+        row['status'] = 'runtime-report-missing'
+        continue
+    report = json.loads(report_file.read_text())
+    expected = Counter((' > '.join(case['ancestorTitles'] + [case['title']]), case['status'])
+                       for case in native['assertionResults'])
+    actual = Counter((case['name'], statuses[case['status']]) for case in report['results'])
+    row['nativeCases'] = sum(expected.values())
+    row['runtimeCases'] = sum(actual.values())
+    if expected != actual:
+        row['status'] = 'case-results-differ'
+        row['missing'] = list((expected - actual).elements())
+        row['unexpected'] = list((actual - expected).elements())
+result = {'run': manifest['id'], 'runtime': args.runtime, 'files': comparison,
+          'counts': dict(Counter(row['status'] for row in comparison))}
+output = args.manifest.parent / ('native-comparison-' + args.runtime + '.json')
+output.write_text(json.dumps(result, indent=2))
+print(json.dumps({'report': str(output), 'counts': result['counts']}))
+raise SystemExit(int(any(row['status'] != 'match' for row in comparison)))
diff --git a/tests/Frameworks/hono/deadline.mjs b/tests/Frameworks/hono/deadline.mjs
new file mode 100644
index 00000000..68cbb568
--- /dev/null
+++ b/tests/Frameworks/hono/deadline.mjs
@@ -0,0 +1,50 @@
+const realSetTimeout = globalThis.setTimeout;
+const realClearTimeout = globalThis.clearTimeout;
+export const monotonicNow = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
+
+export const defaultTestTimeout = 5_000;
+export const defaultHookTimeout = 10_000;
+
+// Vitest 5 checks elapsed time even when synchronous work or microtasks starve timers.
+export function withDeadline(action, timeout, isHook = false, abort) {
+  if (timeout <= 0 || timeout === Infinity) return action();
+  return new Promise((resolve, reject) => {
+    const end = monotonicNow() + timeout;
+    let settled = false;
+    const timer = realSetTimeout(expired, timeout);
+    function expired() {
+      if (settled) return;
+      settled = true;
+      realClearTimeout(timer);
+      const kind = isHook ? 'Hook' : 'Test';
+      const error = new Error(`${kind} timed out in ${timeout}ms.\nIf this is a long-running ${kind.toLowerCase()}, pass a timeout value as the last argument or configure it globally with "${isHook ? 'hookTimeout' : 'testTimeout'}".`);
+      try {
+        abort?.(error);
+      } catch (cause) {
+        error.cause = cause;
+      } finally {
+        reject(error);
+      }
+    }
+    function complete(value) {
+      if (settled) return;
+      if (monotonicNow() >= end) return expired();
+      settled = true;
+      realClearTimeout(timer);
+      resolve(value);
+    }
+    function failed(error) {
+      if (settled) return;
+      settled = true;
+      realClearTimeout(timer);
+      reject(error);
+    }
+    try {
+      const result = action();
+      if (typeof result === 'object' && result !== null && typeof result.then === 'function') result.then(complete, failed);
+      else complete(result);
+    } catch (error) {
+      failed(error);
+    }
+  });
+}
diff --git a/tests/Frameworks/hono/fixtures/timeouts-entry.mjs b/tests/Frameworks/hono/fixtures/timeouts-entry.mjs
new file mode 100644
index 00000000..56db0ca9
--- /dev/null
+++ b/tests/Frameworks/hono/fixtures/timeouts-entry.mjs
@@ -0,0 +1,7 @@
+import { run } from '../harness.mjs';
+import './timeouts.test.mjs';
+run().then(report => {
+  globalThis.__honoReport = report;
+  if (globalThis.__honoComplete) globalThis.__honoComplete();
+  else process.stdout.write('__PHASIS_HONO_REPORT__' + JSON.stringify(report) + '\n', () => process.exit(0));
+});
diff --git a/tests/Frameworks/hono/fixtures/timeouts.test.mjs b/tests/Frameworks/hono/fixtures/timeouts.test.mjs
new file mode 100644
index 00000000..ec918229
--- /dev/null
+++ b/tests/Frameworks/hono/fixtures/timeouts.test.mjs
@@ -0,0 +1,47 @@
+import { setTimeout as nativeTimeout } from 'node:timers';
+import { withDeadline } from '../deadline.mjs';
+const realNow = performance.now.bind(performance);
+const delay = duration => new Promise(resolve => nativeTimeout(resolve, duration));
+const pending = () => new Promise(() => {});
+const busy = duration => {
+  const end = realNow() + duration;
+  while (realNow() < end) {}
+};
+
+afterEach(() => vi.useRealTimers());
+test('ordinary completion', () => expect(1).toBe(1));
+test('async deadline', pending, 30);
+test('synchronous deadline', () => busy(70), 30);
+test('microtask deadline', () => Promise.resolve().then(() => busy(70)), 30);
+test('options deadline', { timeout: 30 }, pending);
+test('disabled deadline', () => delay(40), 0);
+test('infinite deadline', { timeout: Infinity }, () => delay(40));
+test('abort failures remain visible without losing completion', async () => {
+  await expect(withDeadline(pending, 30, false, () => { throw new Error('abort failed'); }))
+    .rejects.toMatchObject({ message: expect.stringContaining('Test timed out in 30ms.'),
+      cause: { message: 'abort failed' } });
+});
+test('fake timers preserve real deadline', { timeout: 30 }, () => {
+  vi.useFakeTimers();
+  return pending();
+});
+test('late synchronous errors remain original errors', () => {
+  busy(70);
+  throw new Error('original synchronous error');
+}, 30);
+describe('inherited deadline', { timeout: 30 }, () => {
+  test('inherits suite limit', pending);
+});
+test.each([1])('parameterized deadline %s', { timeout: 30 }, pending);
+describe('beforeEach limit', () => {
+  beforeEach(pending, 30);
+  test('reports hook timeout', () => expect.unreachable());
+});
+describe('beforeAll limit', () => {
+  beforeAll(pending, 30);
+  test('reports setup timeout', () => expect.unreachable());
+});
+describe('cleanup limit', () => {
+  beforeEach(() => pending, 30);
+  test('reports cleanup timeout', () => expect(1).toBe(1));
+});
diff --git a/tests/Frameworks/hono/harness.mjs b/tests/Frameworks/hono/harness.mjs
new file mode 100644
index 00000000..1613fa9e
--- /dev/null
+++ b/tests/Frameworks/hono/harness.mjs
@@ -0,0 +1,298 @@
+import { AsyncLocalStorage } from 'node:async_hooks';
+import * as chai from 'chai';
+import {
+  ASYMMETRIC_MATCHERS_OBJECT, GLOBAL_EXPECT, JestAsymmetricMatchers,
+  JestChaiExpect, JestExtend, ChaiStyleAssertions, customMatchers, getState, setState,
+} from '@vitest/expect';
+import { fn, spyOn, clearAllMocks, resetAllMocks, restoreAllMocks } from '@vitest/spy';
+import { expectTypeOf } from 'expect-type';
+import fakeTimers from '@sinonjs/fake-timers';
+import { format } from '@vitest/pretty-format';
+import { defaultTestTimeout, defaultHookTimeout, withDeadline, monotonicNow } from './deadline.mjs';
+
+chai.use(JestExtend);
+chai.use(JestChaiExpect);
+chai.use(JestAsymmetricMatchers);
+chai.use(ChaiStyleAssertions);
+let activeTest;
+export const expect = Object.assign((value, message) => {
+  const state = getState(expect);
+  setState({ assertionCalls: state.assertionCalls + 1 }, expect);
+  const assertion = chai.expect(value, message);
+  return activeTest ? assertion.withTest(activeTest) : assertion;
+}, chai.expect, globalThis[ASYMMETRIC_MATCHERS_OBJECT]);
+globalThis[GLOBAL_EXPECT] = expect;
+setState({ assertionCalls: 0, currentTestName: '', isExpectingAssertions: false, expectedAssertionsNumber: null }, expect);
+expect.getState = () => getState(expect);
+expect.setState = state => setState(state, expect);
+expect.extend = matchers => chai.expect.extend(expect, matchers);
+expect.extend(customMatchers);
+expect.assertions = count => setState({ expectedAssertionsNumber: count }, expect);
+expect.hasAssertions = () => setState({ isExpectingAssertions: true }, expect);
+expect.unreachable = message => { throw new Error(message || 'Expected code to be unreachable'); };
+expect.soft = (value, message) => expect(value, message).withContext({ soft: true });
+expect.extend({
+  toMatchInlineSnapshot(received, expected) {
+    if (typeof expected !== 'string') unsupported('property snapshots and snapshot updates');
+    const actual = format(received, { escapeRegex: true, printFunctionName: false });
+    return { pass: actual === expected, message: () => `Snapshot mismatch\nExpected: ${expected}\nReceived: ${actual}` };
+  },
+  toThrowErrorMatchingInlineSnapshot(received, expected) {
+    if (this.promise !== 'rejects') {
+      if (typeof received !== 'function') throw new TypeError('Expected a function for error snapshot');
+      try { received(); } catch (error) { return this.equals(format(error, { escapeRegex: true, printFunctionName: false }), expected)
+        ? { pass: true, message: () => 'Expected the function not to throw the snapshot error' }
+        : { pass: false, message: () => `Error snapshot mismatch: ${format(error)} !== ${expected}` }; }
+      return { pass: false, message: () => 'Expected the function to throw' };
+    }
+    const actual = format(received, { escapeRegex: true, printFunctionName: false });
+    return { pass: actual === expected, message: () => `Error snapshot mismatch: ${actual} !== ${expected}` };
+  },
+});
+export { expectTypeOf };
+
+const root = { name: '', children: [], beforeAll: [], afterAll: [], beforeEach: [], afterEach: [], parent: null, options: {} };
+const collectionContext = new AsyncLocalStorage();
+const pendingCollections = [];
+const suiteErrors = [];
+const currentSuite = () => collectionContext.getStore() || root;
+let nextId = 0;
+class HarnessUnsupportedError extends Error {}
+class SkippedTest extends Error {}
+const unsupported = name => { throw new HarnessUnsupportedError('Harness support required: ' + name); };
+function caseName(template, args, index) {
+  let position = 0;
+  return template.replace(/%[%sdifjo#]|\$[\w.]+/g, token => {
+    if (token === '%%') return '%';
+    if (token === '%#') return String(index);
+    if (token[0] === '$') {
+      if ((args[0] === null || typeof args[0] !== 'object') && !/^\d+$/.test(token.slice(1))) return token;
+      let value = args[0];
+      for (const key of token.slice(1).split('.')) value = value?.[key];
+      return String(value);
+    }
+    const value = args[position++];
+    return token === '%j' || token === '%o' ? JSON.stringify(value) : String(value);
+  });
+}
+function eachTable(table, ...values) {
+  if (!Array.isArray(table) || !Object.hasOwn(table, 'raw')) return table;
+  const headings = table[0].trim().split('|').map(value => value.trim());
+  const rows = [];
+  for (let i = 0; i < values.length; i += headings.length) {
+    const row = {};
+    for (let j = 0; j < headings.length; j++) row[headings[j]] = values[i + j];
+    rows.push(row);
+  }
+  return rows;
+}
+function registration(kind, skipped = false) {
+  const register = (name, optionsOrAction, timeoutOrAction) => {
+    const { options, action } = parseArguments(optionsOrAction, timeoutOrAction);
+    const suite = currentSuite();
+    const entry = { name: String(name), id: nextId++, skipped: skipped || suite.skipped, parent: suite, suite: suite.parent ? suite : undefined,
+      options: { ...suite.options, ...options } };
+    if (kind === 'suite') {
+      Object.assign(entry, { children: [], beforeAll: [], afterAll: [], beforeEach: [], afterEach: [] });
+      suite.children.push(entry);
+      const collecting = collectionContext.run(entry, action);
+      if (collecting && typeof collecting.then === 'function') pendingCollections.push(collecting);
+    } else {
+      entry.action = action;
+      suite.children.push(entry);
+    }
+  };
+  register.each = (table, ...values) => (name, optionsOrAction, timeoutOrAction) => {
+    const { options, action } = parseArguments(optionsOrAction, timeoutOrAction);
+    eachTable(table, ...values).forEach((row, index) => {
+      const args = Array.isArray(row) ? row : [row];
+      register(caseName(name, args, index), options, () => action(...args));
+    });
+  };
+  register.skipIf = condition => registration(kind, skipped || Boolean(condition));
+  register.runIf = condition => registration(kind, skipped || !condition);
+  Object.defineProperty(register, 'skip', { get: () => registration(kind, true) });
+  Object.defineProperty(register, 'only', { get: () => unsupported('exclusive test selection') });
+  register.todo = name => registration(kind, true)(name, () => {});
+  return register;
+}
+function parseArguments(optionsOrAction, timeoutOrAction) {
+  if (timeoutOrAction !== null && typeof timeoutOrAction === 'object') {
+    throw new TypeError('Pass test options as the second argument, as required by Vitest 5.');
+  }
+  if (typeof optionsOrAction === 'function' && typeof timeoutOrAction === 'function') {
+    throw new TypeError('Cannot use two functions as test arguments.');
+  }
+  return {
+    action: typeof optionsOrAction === 'function' ? optionsOrAction : timeoutOrAction,
+    options: typeof timeoutOrAction === 'number' ? { timeout: timeoutOrAction }
+      : optionsOrAction !== null && typeof optionsOrAction === 'object' ? optionsOrAction : {},
+  };
+}
+export const describe = registration('suite');
+export const test = registration('test');
+export const it = test;
+const hook = kind => (action, timeout = defaultHookTimeout) => currentSuite()[kind].push({ action, timeout: timeout ?? defaultHookTimeout });
+export const beforeAll = hook('beforeAll');
+export const afterAll = hook('afterAll');
+export const beforeEach = hook('beforeEach');
+export const afterEach = hook('afterEach');
+const savedGlobals = new Map();
+const savedEnv = new Map();
+let fakeClock;
+export const vi = {
+  fn, spyOn, clearAllMocks, resetAllMocks, restoreAllMocks,
+  stubGlobal(name, value) {
+    if (!savedGlobals.has(name)) savedGlobals.set(name, Object.getOwnPropertyDescriptor(globalThis, name));
+    Object.defineProperty(globalThis, name, { configurable: true, writable: true, enumerable: true, value });
+    return vi;
+  },
+  unstubAllGlobals() {
+    for (const [name, descriptor] of savedGlobals) {
+      if (descriptor) Object.defineProperty(globalThis, name, descriptor);
+      else delete globalThis[name];
+    }
+    savedGlobals.clear();
+    return vi;
+  },
+  stubEnv(name, value) {
+    if (typeof process === 'undefined') unsupported('process.env');
+    if (!savedEnv.has(name)) savedEnv.set(name, Object.getOwnPropertyDescriptor(process.env, name));
+    if (value === undefined) delete process.env[name]; else process.env[name] = String(value);
+    return vi;
+  },
+  unstubAllEnvs() {
+    for (const [name, descriptor] of savedEnv) {
+      if (descriptor) Object.defineProperty(process.env, name, descriptor);
+      else delete process.env[name];
+    }
+    savedEnv.clear();
+    return vi;
+  },
+  useFakeTimers(options = {}) {
+    fakeClock ||= fakeTimers.withGlobal(globalThis).install({
+      ...options,
+      toFake: options.toFake || Object.keys(fakeTimers.timers).filter(name => name !== 'nextTick' && name !== 'queueMicrotask'),
+    });
+    return vi;
+  },
+  setSystemTime(value) { if (!fakeClock) vi.useFakeTimers(); fakeClock.setSystemTime(value); return vi; },
+  useRealTimers() { fakeClock?.uninstall(); fakeClock = undefined; return vi; },
+  resetModules() {
+    if (typeof globalThis.__honoResetModules !== 'function') unsupported('module-cache reset');
+    globalThis.__honoResetModules();
+    return vi;
+  },
+};
+Object.assign(globalThis, { describe, test, it, beforeAll, afterAll, beforeEach, afterEach, expect, expectTypeOf, vi });
+function fullName(entry) {
+  const names = [];
+  for (let current = entry; current?.parent; current = current.parent) names.unshift(current.name);
+  return names.join(' > ');
+}
+function failure(error, depth = 0) {
+  return { name: error?.name || 'Error', message: String(error?.message ?? error), stack: String(error?.stack || ''),
+    ...(error?.cause !== undefined && depth < 3 ? { cause: failure(error.cause, depth + 1) } : {}) };
+}
+async function invoke(hook, context) {
+  const cleanup = await withDeadline(() => hook.action(context), hook.timeout, true, error => context.abort?.(error));
+  return typeof cleanup === 'function' ? { action: () => cleanup(), timeout: hook.timeout } : undefined;
+}
+async function runCase(entry, ancestors, results, inheritedError) {
+  const started = monotonicNow();
+  const record = { id: entry.id, name: fullName(entry), status: 'pass', assertions: 0 };
+  globalThis.__honoCase?.(JSON.stringify({ id: record.id, name: record.name }));
+  if (entry.skipped) {
+    record.status = 'upstream-skip';
+    results.push(record);
+    return;
+  }
+  if (inheritedError) {
+    record.status = 'suite-blocked';
+    record.error = failure(inheritedError);
+    results.push(record);
+    return;
+  }
+  const task = { name: entry.name, suite: entry.parent, promises: [], onFinished: [], result: { state: 'run', errors: [] } };
+  const controller = new AbortController();
+  const context = { expect, task, signal: controller.signal, abort: error => controller.abort(error),
+    skip: reason => { throw new SkippedTest(String(reason || 'Skipped by upstream test')); } };
+  activeTest = task;
+  setState({ assertionCalls: 0, currentTestName: record.name, isExpectingAssertions: false, expectedAssertionsNumber: null }, expect);
+  const cleanups = [];
+  let problem = inheritedError;
+  try {
+    if (problem) throw problem;
+    for (const ancestor of ancestors) {
+      for (const hook of ancestor.beforeEach) {
+        const cleanup = await invoke(hook, context);
+        if (cleanup) cleanups.push(cleanup);
+      }
+    }
+    if (typeof entry.action !== 'function') throw new Error('Test has no callback');
+    await withDeadline(async () => {
+      await entry.action(context);
+      await Promise.all(task.promises);
+    }, entry.options.timeout ?? defaultTestTimeout, false, context.abort);
+    for (const complete of task.onFinished) await withDeadline(complete, defaultHookTimeout, true, context.abort);
+    if (task.result.errors.length) throw new Error(task.result.errors.map(error => error.message).join('\n'));
+    const state = getState(expect);
+    if (state.isExpectingAssertions && state.assertionCalls === 0) throw new Error('Expected at least one assertion');
+    if (state.expectedAssertionsNumber !== null && state.expectedAssertionsNumber !== state.assertionCalls) {
+      throw new Error(`Expected ${state.expectedAssertionsNumber} assertions, got ${state.assertionCalls}`);
+    }
+  } catch (error) { problem = error; }
+  for (const ancestor of [...ancestors].reverse()) {
+    for (const hook of [...ancestor.afterEach].reverse()) {
+      try { await invoke(hook, context); } catch (error) { problem ||= error; }
+    }
+  }
+  for (const cleanup of cleanups.reverse()) {
+    try { await invoke(cleanup, context); } catch (error) { problem ||= error; }
+  }
+  record.assertions = getState(expect).assertionCalls;
+  record.durationMs = monotonicNow() - started;
+  if (problem) {
+    record.status = problem instanceof SkippedTest ? 'upstream-skip' : problem instanceof HarnessUnsupportedError ? 'harness-blocked' : 'fail';
+    record.error = failure(problem);
+  }
+  results.push(record);
+  globalThis.__honoResult?.(JSON.stringify(record));
+  activeTest = undefined;
+}
+async function runSuite(current, ancestors, results, inheritedError) {
+  const lineage = [...ancestors, current];
+  const cleanups = [];
+  let problem = inheritedError;
+  if (!current.skipped && !problem) {
+    try {
+      for (const hook of current.beforeAll) {
+        const cleanup = await invoke(hook, {});
+        if (cleanup) cleanups.push(cleanup);
+      }
+    } catch (error) {
+      problem = error;
+      suiteErrors.push({ name: fullName(current) + ' > beforeAll', error: failure(error) });
+    }
+  }
+  for (const child of current.children) {
+    if (child.children) await runSuite(child, lineage, results, problem);
+    else await runCase(child, lineage, results, problem);
+  }
+  if (!current.skipped) {
+    for (const hook of [...current.afterAll].reverse()) {
+      try { await invoke(hook, {}); } catch (error) { suiteErrors.push({ name: fullName(current) + ' > afterAll', error: failure(error) }); }
+    }
+    for (const cleanup of cleanups.reverse()) {
+      try { await invoke(cleanup, {}); } catch (error) { suiteErrors.push({ name: fullName(current) + ' > beforeAll cleanup', error: failure(error) }); }
+    }
+  }
+}
+export async function run() {
+  while (pendingCollections.length) await Promise.all(pendingCollections.splice(0));
+  const results = [];
+  await runSuite(root, [], results);
+  const counts = { pass: 0, fail: 0, 'upstream-skip': 0, 'harness-blocked': 0, 'suite-blocked': 0 };
+  for (const result of results) counts[result.status]++;
+  return { counts, results, suiteErrors };
+}
diff --git a/tests/Frameworks/hono/inventory.py b/tests/Frameworks/hono/inventory.py
new file mode 100644
index 00000000..4a2db61f
--- /dev/null
+++ b/tests/Frameworks/hono/inventory.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+"""Inventory all original Hono test projects, including host-specific suites."""
+import hashlib
+import json
+from pathlib import Path
+
+DIRECTORY = Path(__file__).resolve().parent
+METADATA = json.loads((DIRECTORY / 'upstream.json').read_text())
+UPSTREAM = DIRECTORY / METADATA['directory']
+
+
+def test_files(area):
+    return sorted(str(path.relative_to(UPSTREAM)) for path in (UPSTREAM / area).rglob('*')
+                  if path.is_file() and ('.test.' in path.name or '.spec.' in path.name)
+                  and path.suffix in ['.ts', '.tsx', '.js'] and 'sandbox' not in path.parts)
+
+
+def inventory():
+    source = test_files('src')
+    runtime = [name for name in source if '.case.test.' not in name] + test_files('scripts')
+    toolchain = test_files('build')
+    dom = test_files('src/jsx/dom') + ['src/jsx/hooks/dom.test.tsx']
+    projects = {
+        'main': {'host': 'Node and web APIs, plus native TypeScript build checks',
+                 'files': sorted(runtime + toolchain), 'runtimeFiles': sorted(runtime),
+                 'toolchainFiles': sorted(toolchain)},
+        'jsx-runtime-default': {'host': 'Node with jsdom', 'files': sorted(dom)},
+        'jsx-runtime-dom': {'host': 'Node with jsdom', 'files': sorted(dom)},
+    }
+    for host in ['node', 'fastly', 'workerd', 'bun', 'deno', 'deno-jsx']:
+        projects[host] = {'host': host, 'files': test_files('runtime-tests/' + host)}
+    files = sorted(set(name for project in projects.values() for name in project['files']))
+    return {'upstream': METADATA, 'projects': projects,
+            'fixtures': [name for name in source if '.case.test.' in name],
+            'sha256': {name: hashlib.sha256((UPSTREAM / name).read_bytes()).hexdigest() for name in files}}
+
+
+if __name__ == '__main__':
+    print(json.dumps(inventory(), indent=2))
diff --git a/tests/Frameworks/hono/prepare-toolchain.mjs b/tests/Frameworks/hono/prepare-toolchain.mjs
new file mode 100644
index 00000000..d85819ac
--- /dev/null
+++ b/tests/Frameworks/hono/prepare-toolchain.mjs
@@ -0,0 +1,19 @@
+import { readFile, realpath, symlink } from 'node:fs/promises';
+import { dirname, relative, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const directory = dirname(fileURLToPath(import.meta.url));
+const metadata = JSON.parse(await readFile(resolve(directory, 'upstream.json'), 'utf8'));
+const upstream = resolve(directory, metadata.directory);
+const published = resolve(directory, '../node_modules/hono');
+const packageMetadata = JSON.parse(await readFile(resolve(published, 'package.json'), 'utf8'));
+if (packageMetadata.version !== metadata.version) throw new Error('Published Hono fixture version differs from upstream source');
+const distribution = await realpath(resolve(published, 'dist'));
+const target = resolve(upstream, 'dist');
+try {
+  if (await realpath(target) !== distribution) throw new Error('Existing upstream dist is not the pinned published package');
+} catch (error) {
+  if (error.code !== 'ENOENT') throw error;
+  await symlink(relative(upstream, distribution), target, 'dir');
+}
+console.log(`Declaration fixtures use published Hono ${metadata.version}: ${distribution}`);
diff --git a/tests/Frameworks/hono/run-php.php b/tests/Frameworks/hono/run-php.php
new file mode 100644
index 00000000..27dc663c
--- /dev/null
+++ b/tests/Frameworks/hono/run-php.php
@@ -0,0 +1,63 @@
+getMessage() . PHP_EOL);
+    foreach (array_slice($error->getTrace(), 0, 12) as $frame) {
+        fwrite(STDERR, ($frame['file'] ?? '[native]') . ':' . ($frame['line'] ?? 0) . PHP_EOL);
+    }
+    exit(1);
+});
+$errorReserve = str_repeat(' ', 32768);
+register_shutdown_function(static function () use (&$errorReserve): void {
+    $errorReserve = null;
+    $error = error_get_last();
+    if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
+        fwrite(STDERR, 'PHP fatal: ' . $error['message'] . ' at ' . $error['file'] . ':' . $error['line'] . PHP_EOL);
+    }
+});
+set_error_handler(static function (int $severity, string $message, string $file, int $line): bool {
+    if ((error_reporting() & $severity) === 0) {
+        return false;
+    }
+    throw new ErrorException($message, 0, $severity, $file, $line);
+});
+
+$engine = new Phasis\Engine(node: true);
+$engine->setLimit('maxLoopIterations', 1_000_000);
+$engine->setGlobalJsValue('__honoCase', Phasis\Value\JsFunction::fromCallable(
+    '',
+    static function (Phasis\Value\JsValue $this_, array $args): Phasis\Value\JsValue {
+        $record = json_decode(($args[0] ?? Phasis\Value\JsUndefined::instance())->toJsString(), true, flags: JSON_THROW_ON_ERROR);
+        $record['heapBytes'] = memory_get_usage(true);
+        $record['monotonicSeconds'] = hrtime(true) / 1_000_000_000;
+        fwrite(STDOUT, '__PHASIS_HONO_CASE__' . json_encode($record, JSON_THROW_ON_ERROR) . PHP_EOL);
+        return Phasis\Value\JsUndefined::instance();
+    },
+));
+$engine->setGlobalJsValue('__honoComplete', Phasis\Value\JsFunction::fromCallable(
+    '',
+    static function () use ($engine): Phasis\Value\JsValue {
+        $engine->getNodeRuntime()?->close();
+        return Phasis\Value\JsUndefined::instance();
+    },
+));
+$engine->setGlobalJsValue('__honoResult', Phasis\Value\JsFunction::fromCallable(
+    '',
+    static function (Phasis\Value\JsValue $this_, array $args): Phasis\Value\JsValue {
+        fwrite(STDOUT, '__PHASIS_HONO_RESULT__' . ($args[0] ?? Phasis\Value\JsUndefined::instance())->toJsString() . PHP_EOL);
+        return Phasis\Value\JsUndefined::instance();
+    },
+));
+$engine->execFile($argv[1]);
+$report = $engine->eval('globalThis.__honoReport');
+if ($report === null) {
+    fwrite(STDERR, $engine->getConsoleOutput() . "\nThe Hono upstream runner did not finish.\n");
+    exit(2);
+}
+echo '__PHASIS_HONO_REPORT__', json_encode($report, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_SUBSTITUTE), PHP_EOL;
diff --git a/tests/Frameworks/hono/run-toolchain.py b/tests/Frameworks/hono/run-toolchain.py
new file mode 100644
index 00000000..f73bebc1
--- /dev/null
+++ b/tests/Frameworks/hono/run-toolchain.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+"""Validate unchanged Hono declaration fixtures with the pinned native TypeScript compiler."""
+import argparse
+from datetime import datetime, timezone
+import hashlib
+import json
+from uuid import uuid4
+
+from run import DIRECTORY, REPOSITORY, execute, upstream_inventory
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('--timeout', type=float, default=180)
+    args = parser.parse_args()
+    run_id = datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ-') + uuid4().hex[:8]
+    archive = DIRECTORY / 'results' / 'runs' / run_id
+    archive.mkdir(parents=True)
+    inventory = upstream_inventory()
+    dependencies = json.loads((DIRECTORY.parent / 'package.json').read_text())['devDependencies']
+    manifest = {'id': run_id, 'project': 'toolchain', 'host': 'native TypeScript compiler',
+                'upstreamProjects': inventory,
+                'selected': inventory['projects']['main']['toolchainFiles'],
+                'dependencies': {name: dependencies[name] for name in ['hono', 'typescript', 'vitest']},
+                'lockSha256': hashlib.sha256((DIRECTORY.parent / 'package-lock.json').read_bytes()).hexdigest()}
+    status, output = execute(['node', str(DIRECTORY / 'prepare-toolchain.mjs')], args.timeout, 'toolchain')
+    (archive / 'prepare.log').write_text(output)
+    if status:
+        manifest['status'] = 'preparation-blocked'
+    else:
+        report_file = archive / 'native.json'
+        status, output = execute([
+            'node', str(DIRECTORY.parent / 'node_modules/vitest/vitest.mjs'), 'run',
+            '--config', str(DIRECTORY / 'vitest.config.mjs'), '--reporter=json',
+            '--outputFile=' + str(report_file),
+        ], args.timeout, 'toolchain')
+        (archive / 'native.log').write_text(output)
+        if report_file.exists():
+            report = json.loads(report_file.read_text())
+            manifest['counts'] = {key: report[key] for key in
+                                  ['numTotalTests', 'numPassedTests', 'numFailedTests', 'numPendingTests']}
+            manifest['status'] = 'pass' if status == 0 and report['success'] and report['numTotalTests'] else 'fail'
+        else:
+            manifest['status'] = 'process-blocked'
+    manifest['exitCode'] = status
+    (archive / 'manifest.json').write_text(json.dumps(manifest, indent=2))
+    print(manifest['status'], manifest.get('counts', {}))
+    print('Run manifest:', archive / 'manifest.json')
+    return int(manifest['status'] != 'pass')
+
+
+if __name__ == '__main__':
+    raise SystemExit(main())
diff --git a/tests/Frameworks/hono/run.py b/tests/Frameworks/hono/run.py
new file mode 100644
index 00000000..c16554df
--- /dev/null
+++ b/tests/Frameworks/hono/run.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python3
+"""Run unchanged transpiled Hono tests in bounded Node/Phasis subprocesses."""
+import argparse
+import json
+import hashlib
+from datetime import datetime, timezone
+from uuid import uuid4
+from inventory import inventory as upstream_inventory
+import os
+import signal
+from pathlib import Path
+import subprocess
+import sys
+import tempfile
+import time
+
+
+def stop_on_signal(signum, frame):
+    raise SystemExit(128 + signum)
+
+
+signal.signal(signal.SIGTERM, stop_on_signal)
+
+DIRECTORY = Path(__file__).resolve().parent
+REPOSITORY = DIRECTORY.parents[2]
+UPSTREAM_METADATA = json.loads((DIRECTORY / 'upstream.json').read_text())
+UPSTREAM = DIRECTORY / UPSTREAM_METADATA['directory']
+PREFIX = '__PHASIS_HONO_REPORT__'
+
+
+def terminate_group(process):
+    # Successful workers can leave descendants with open listeners or pipes.
+    # Each worker has a dedicated process group, so include its descendants.
+    try:
+        os.killpg(process.pid, signal.SIGTERM)
+    except ProcessLookupError:
+        pass
+    if process.poll() is None:
+        try:
+            process.wait(timeout=2)
+        except subprocess.TimeoutExpired:
+            pass
+    try:
+        os.killpg(process.pid, signal.SIGKILL)
+    except ProcessLookupError:
+        pass
+    process.wait()
+
+
+def execute(command, timeout, project="main", log_file=None):
+    try:
+        environment = dict(os.environ, XDEBUG_MODE='off', PHASIS_HONO_PROJECT=project)
+        if project == 'node':
+            environment['NAME'] = 'Node'
+        environment.pop('NO_COLOR', None)
+        with (log_file.open('w+') if log_file else tempfile.TemporaryFile(mode='w+')) as log:
+            process = subprocess.Popen(command, cwd=REPOSITORY, env=environment,
+                                       stdout=log, stderr=subprocess.STDOUT,
+                                       text=True, start_new_session=True)
+            timed_out = False
+            try:
+                try:
+                    status = process.wait(timeout=timeout)
+                except subprocess.TimeoutExpired:
+                    timed_out = True
+                    status = 124
+            finally:
+                terminate_group(process)
+            log.seek(0)
+            return status, log.read() + ('\nPROCESS TIMEOUT\n' if timed_out else '')
+    except OSError as error:
+        return 127, str(error) + '\n'
+
+
+def source_hash(directory):
+    digest = hashlib.sha256()
+    for path in sorted(directory.rglob('*')):
+        if path.is_file() and path.suffix in ['.php', '.cjs', '.mjs']:
+            digest.update(str(path.relative_to(directory)).encode() + b'\0')
+            digest.update(path.read_bytes())
+    return digest.hexdigest()
+
+
+def harness_hash():
+    digest = hashlib.sha256()
+    for name in ['build.mjs', 'harness.mjs', 'deadline.mjs', 'run.py', 'run-php.php', 'inventory.py', 'upstream.json']:
+        digest.update(name.encode() + b'\0' + (DIRECTORY / name).read_bytes())
+    return digest.hexdigest()
+
+
+def dependency_hash():
+    return hashlib.sha256((DIRECTORY.parent / 'package-lock.json').read_bytes()).hexdigest()
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('files', nargs='*')
+    parser.add_argument('--timeout', type=float, default=1800)
+    parser.add_argument('--project', choices=['main', 'jsx-runtime-default', 'jsx-runtime-dom', 'node'], default='main')
+    parser.add_argument('--runtime', choices=['node', 'phasis', 'both'], default='both')
+    parser.add_argument('--no-build', action='store_true')
+    args = parser.parse_args()
+    all_projects = upstream_inventory()
+    project = all_projects['projects'][args.project]
+    inventory = project.get('runtimeFiles', project['files'])
+    files = args.files or inventory
+    if len(files) != len(set(files)):
+        parser.error('Each upstream file may appear only once in a run')
+    for name in files:
+        if name in all_projects['projects']['main']['toolchainFiles']:
+            parser.error(name + ' is a native TypeScript check; use run-toolchain.py')
+        if name not in inventory:
+            parser.error(name + ' is not in the selected upstream project')
+    run_id = datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ-') + uuid4().hex[:8]
+    results = DIRECTORY / 'results'
+    archive = results / 'runs' / run_id
+    archive.mkdir(parents=True)
+    manifest = []
+    metadata = {'id': run_id, 'upstream': UPSTREAM_METADATA, 'project': args.project,
+                'inventory': inventory, 'upstreamProjects': all_projects,
+                'selected': files, 'runtimes': args.runtime,
+                'timeoutSeconds': args.timeout, 'runtimeSourceAtStart': source_hash(REPOSITORY / 'src'),
+                'harnessSourceAtStart': harness_hash(), 'dependenciesAtStart': dependency_hash(),
+                'complete': False, 'files': manifest}
+
+    def save(name, contents):
+        (archive / name).write_text(contents)
+        (results / name).write_text(contents)
+
+    def save_manifest():
+        save('manifest.json', json.dumps(metadata, indent=2))
+    save_manifest()
+    for name in files:
+        identifier = name.replace('/', '__').rsplit('.', 1)[0]
+        row = {'file': name, 'sha256': hashlib.sha256((UPSTREAM / name).read_bytes()).hexdigest(), 'runtimes': {}}
+        case_reports = {}
+        manifest.append(row)
+        save_manifest()
+        if not args.no_build:
+            status, output = execute(['node', str(DIRECTORY / 'build.mjs'), name], args.timeout, args.project)
+            save(identifier + '-build.log', output)
+            if status:
+                row['build'] = {'status': 'build-blocked', 'exitCode': status}
+                print(name, 'BUILD BLOCKED', flush=True)
+                save_manifest()
+                continue
+        for runtime in (['node', 'phasis'] if args.runtime == 'both' else [args.runtime]):
+            row['runtimes'][runtime] = {'status': 'running'}
+            save_manifest()
+            generated = DIRECTORY / '.generated'
+            if args.project != 'main':
+                generated /= args.project
+            script = str(generated / (identifier + '.mjs'))
+            command = ['node', script] if runtime == 'node' else ['php', '-d', 'memory_limit=1G', str(DIRECTORY / 'run-php.php'), script]
+            started = time.monotonic()
+            status, output = execute(command, args.timeout, args.project,
+                                     archive / (identifier + '-' + runtime + '.log'))
+            row.setdefault('elapsedSeconds', {})[runtime] = round(time.monotonic() - started, 3)
+            save(identifier + '-' + runtime + '.log', output)
+            reports = [line[len(PREFIX):] for line in output.splitlines() if line.startswith(PREFIX)]
+            if status or len(reports) != 1:
+                row['runtimes'][runtime] = {'status': 'process-blocked', 'exitCode': status}
+            else:
+                report = json.loads(reports[0])
+                if not report['results']:
+                    row['runtimes'][runtime] = {'status': 'empty-discovery', 'exitCode': status}
+                else:
+                    save(identifier + '-' + runtime + '.json', json.dumps(report, indent=2))
+                    case_reports[runtime] = [(case['id'], case['name'], case['status']) for case in report['results']]
+                    row['runtimes'][runtime] = report['counts']
+                    if report.get('suiteErrors'):
+                        row['runtimes'][runtime]['suite-failures'] = len(report['suiteErrors'])
+            print(name, runtime, row['runtimes'][runtime], flush=True)
+        if len(case_reports) == 2 and case_reports['node'] != case_reports['phasis']:
+            row['comparison'] = 'case-results-differ'
+        save_manifest()
+    metadata['runtimeSourceAtEnd'] = source_hash(REPOSITORY / 'src')
+    metadata['runtimeChangedDuringRun'] = metadata['runtimeSourceAtStart'] != metadata['runtimeSourceAtEnd']
+    metadata['harnessSourceAtEnd'] = harness_hash()
+    metadata['harnessChangedDuringRun'] = metadata['harnessSourceAtStart'] != metadata['harnessSourceAtEnd']
+    metadata['dependenciesAtEnd'] = dependency_hash()
+    metadata['dependenciesChangedDuringRun'] = metadata['dependenciesAtStart'] != metadata['dependenciesAtEnd']
+    metadata['complete'] = True
+    save_manifest()
+    print('Run manifest:', archive / 'manifest.json', flush=True)
+    changed = any(metadata[key] for key in ['runtimeChangedDuringRun', 'harnessChangedDuringRun', 'dependenciesChangedDuringRun'])
+    return int(changed or any(row.get('build') or row.get('comparison') or any(report.get('status') or report.get('fail') or report.get('harness-blocked') or report.get('suite-blocked') or report.get('suite-failures')
+                for report in row['runtimes'].values()) for row in manifest))
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/tests/Frameworks/hono/selftest.config.mjs b/tests/Frameworks/hono/selftest.config.mjs
new file mode 100644
index 00000000..cc11a5bb
--- /dev/null
+++ b/tests/Frameworks/hono/selftest.config.mjs
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vitest/config';
+import { dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
+export default defineConfig({
+  root: dirname(fileURLToPath(import.meta.url)),
+  test: { globals: true, maxWorkers: 1, include: ['fixtures/timeouts.test.mjs'], coverage: { enabled: false } },
+});
diff --git a/tests/Frameworks/hono/selftest.py b/tests/Frameworks/hono/selftest.py
new file mode 100644
index 00000000..2dbaa203
--- /dev/null
+++ b/tests/Frameworks/hono/selftest.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+"""Differentially verify harness deadlines against the actual pinned Vitest runner."""
+from datetime import datetime, timezone
+import json
+from uuid import uuid4
+
+from run import DIRECTORY, PREFIX, REPOSITORY, execute, harness_hash, source_hash
+
+
+def main():
+    run_id = datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ-') + uuid4().hex[:8] + '-selftest'
+    archive = DIRECTORY / 'results/runs' / run_id
+    archive.mkdir(parents=True)
+    status, output = execute(['node', str(DIRECTORY / 'build-selftest.mjs')], 60)
+    (archive / 'build.log').write_text(output)
+    if status:
+        raise RuntimeError('Harness self-test build failed')
+    script = DIRECTORY / '.generated/selftest/timeouts.mjs'
+    commands = {
+        'native': ['node', str(DIRECTORY.parent / 'node_modules/vitest/vitest.mjs'), 'run',
+                   '--config', str(DIRECTORY / 'selftest.config.mjs'), '--reporter=json',
+                   '--outputFile=' + str(archive / 'native.json')],
+        'node': ['node', str(script)],
+        'phasis': ['php', '-d', 'memory_limit=1G', str(DIRECTORY / 'run-php.php'), str(script)],
+    }
+    manifest = {'id': run_id, 'kind': 'harness-deadline-selftest', 'results': {},
+                'runtimeSource': source_hash(REPOSITORY / 'src'), 'harnessSource': harness_hash()}
+    for runtime, command in commands.items():
+        status, output = execute(command, 60, log_file=archive / (runtime + '.log'))
+        if runtime == 'native':
+            if status != 1:
+                raise RuntimeError('Native Vitest must report the intentional deadline failures')
+        else:
+            reports = [line[len(PREFIX):] for line in output.splitlines() if line.startswith(PREFIX)]
+            if status != 0 or len(reports) != 1:
+                raise RuntimeError(runtime + ' did not finish the deadline fixtures')
+            (archive / (runtime + '.json')).write_text(reports[0])
+    native = json.loads((archive / 'native.json').read_text())
+    cases = {(' > '.join(case['ancestorTitles'] + [case['title']])): case
+             for file in native['testResults'] for case in file['assertionResults']}
+    if len(cases) != 15 or native['numPassedTests'] != 4 or native['numFailedTests'] != 10:
+        raise RuntimeError('Native deadline fixture inventory changed unexpectedly')
+    for runtime in ['node', 'phasis']:
+        report = json.loads((archive / (runtime + '.json')).read_text())
+        failures = []
+        if len(report['results']) != len(cases):
+            failures.append('case inventory differs')
+        statuses = {'pass': 'passed', 'fail': 'failed', 'suite-blocked': 'skipped'}
+        for case in report['results']:
+            reference = cases.get(case['name'])
+            if reference is None or statuses.get(case['status']) != reference['status']:
+                failures.append(case['name'] + ': outcome differs')
+                continue
+            if reference['failureMessages']:
+                expected = reference['failureMessages'][0].splitlines()[0].removeprefix('Error: ')
+                actual = case.get('error', {}).get('message', '').splitlines()[0]
+                if expected != actual:
+                    failures.append(case['name'] + ': error differs')
+        if len(report['suiteErrors']) != 1 or not report['suiteErrors'][0]['error']['message'].startswith('Hook timed out in 30ms.'):
+            failures.append('suite setup failure was not preserved')
+        manifest['results'][runtime] = {'cases': len(report['results']), 'differences': failures}
+    (archive / 'manifest.json').write_text(json.dumps(manifest, indent=2))
+    print(json.dumps(manifest['results']))
+    print('Run manifest:', archive / 'manifest.json')
+    return int(any(result['differences'] for result in manifest['results'].values()))
+
+
+if __name__ == '__main__':
+    raise SystemExit(main())
diff --git a/tests/Frameworks/hono/setup.py b/tests/Frameworks/hono/setup.py
new file mode 100644
index 00000000..7335ed1d
--- /dev/null
+++ b/tests/Frameworks/hono/setup.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+"""Fetch and verify the exact Hono source archive used by the compatibility suite."""
+import hashlib
+import io
+import json
+from pathlib import Path
+import shutil
+import tarfile
+import tempfile
+import urllib.request
+
+DIRECTORY = Path(__file__).resolve().parent
+
+
+def main():
+    metadata = json.loads((DIRECTORY / 'upstream.json').read_text())
+    archive = urllib.request.urlopen(metadata['source'], timeout=60).read()
+    checksum = hashlib.sha256(archive).hexdigest()
+    if checksum != metadata['sha256']:
+        raise RuntimeError('Hono archive checksum mismatch: ' + checksum)
+    target = DIRECTORY / metadata['directory']
+    target.parent.mkdir(parents=True, exist_ok=True)
+    with tempfile.TemporaryDirectory(prefix='.hono-upstream-', dir=target.parent) as temporary:
+        staging = Path(temporary)
+        with tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as package:
+            for member in package.getmembers():
+                parts = Path(member.name).parts
+                if len(parts) == 1:
+                    continue
+                member.name = str(Path(*parts[1:]))
+                package.extract(member, staging, filter='data')
+        package_json = json.loads((staging / 'package.json').read_text())
+        if package_json['version'] != metadata['version']:
+            raise RuntimeError('Hono source version does not match the manifest')
+        if target.exists():
+            # Preserve existing build artifacts, but reject edited upstream files.
+            for source in staging.rglob('*'):
+                destination = target / source.relative_to(staging)
+                if source.is_file() and (not destination.is_file() or source.read_bytes() != destination.read_bytes()):
+                    raise RuntimeError('Existing Hono source differs: ' + str(destination))
+            for area in ['src', 'scripts', 'build', 'runtime-tests']:
+                for source in (target / area).rglob('*'):
+                    if source.is_file() and not (staging / source.relative_to(target)).is_file():
+                        raise RuntimeError('Unexpected file in Hono source: ' + str(source))
+        else:
+            shutil.copytree(staging, target)
+    print(f'Prepared Hono {metadata["version"]} at {metadata["commit"]} ({checksum})')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/Frameworks/hono/test_runner.py b/tests/Frameworks/hono/test_runner.py
new file mode 100644
index 00000000..e06c22ed
--- /dev/null
+++ b/tests/Frameworks/hono/test_runner.py
@@ -0,0 +1,35 @@
+"""Verify that Hono workers cannot leave owned processes behind."""
+import os
+import sys
+import time
+import unittest
+
+from run import execute
+
+
+class WorkerCleanupTest(unittest.TestCase):
+    def test_successful_worker_stops_its_surviving_child(self):
+        program = """
+import subprocess, sys
+child = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(60)'])
+print(child.pid, flush=True)
+"""
+        status, output = execute([sys.executable, '-c', program], 5)
+        self.assertEqual(status, 0)
+        child_pid = int(output.strip())
+        for _ in range(100):
+            try:
+                os.kill(child_pid, 0)
+            except ProcessLookupError:
+                return
+            time.sleep(.01)
+        self.fail('Worker left its child running')
+
+    def test_timed_out_worker_reports_the_original_timeout(self):
+        status, output = execute([sys.executable, '-c', 'import time; time.sleep(60)'], .05)
+        self.assertEqual(status, 124)
+        self.assertIn('PROCESS TIMEOUT', output)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/Frameworks/hono/upstream.json b/tests/Frameworks/hono/upstream.json
new file mode 100644
index 00000000..6c9a149e
--- /dev/null
+++ b/tests/Frameworks/hono/upstream.json
@@ -0,0 +1,10 @@
+{
+  "repository": "https://github.com/honojs/hono",
+  "version": "4.13.13",
+  "tag": "v4.13.13",
+  "commit": "08a023cbfde55b434fb0fb30fae35d42e4bf20aa",
+  "source": "https://codeload.github.com/honojs/hono/tar.gz/08a023cbfde55b434fb0fb30fae35d42e4bf20aa",
+  "directory": "upstream/hono-4.13.13",
+  "upstreamConfiguration": "vitest.config.ts",
+  "sha256": "e5d8bf83f9afe4d89d4a4aa7f99574d0e0b5ce2ddb3e23f3213fae2779d1ebad"
+}
diff --git a/tests/Frameworks/hono/vitest.config.mjs b/tests/Frameworks/hono/vitest.config.mjs
new file mode 100644
index 00000000..1feb8924
--- /dev/null
+++ b/tests/Frameworks/hono/vitest.config.mjs
@@ -0,0 +1,21 @@
+import { defineConfig, configDefaults } from 'vitest/config';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+const root = resolve(dirname(fileURLToPath(import.meta.url)), 'upstream/hono-4.13.13');
+const project = process.env.PHASIS_HONO_PROJECT || 'main';
+const include = project === 'node' ? ['runtime-tests/node/index.test.ts']
+  : project === 'toolchain' ? ['build/**/*.{test,spec}.{ts,tsx,js}']
+  : project.startsWith('jsx-runtime-') ? ['src/jsx/dom/**/*.{test,spec}.{ts,tsx,js}', 'src/jsx/hooks/dom.test.tsx']
+  : ['src/**/*.{test,spec}.{ts,tsx,js}', 'scripts/**/*.{test,spec}.{ts,tsx,js}', 'build/**/*.{test,spec}.{ts,tsx,js}'];
+export default defineConfig({
+  root,
+  oxc: { jsx: { runtime: 'automatic', importSource: resolve(root, project === 'jsx-runtime-dom' ? 'src/jsx/dom' : 'src/jsx') } },
+  test: {
+    globals: true,
+    coverage: { enabled: false },
+    maxWorkers: 1,
+    include,
+    env: project === 'node' ? { NAME: 'Node' } : {},
+    exclude: [...configDefaults.exclude, '**/sandbox/**', '**/*.case.test.*'],
+  },
+});
diff --git a/tests/Frameworks/http2/certificate.php b/tests/Frameworks/http2/certificate.php
new file mode 100644
index 00000000..97286304
--- /dev/null
+++ b/tests/Frameworks/http2/certificate.php
@@ -0,0 +1,20 @@
+ OPENSSL_KEYTYPE_RSA, 'private_key_bits' => 2048]);
+if ($key === false) {
+    throw new RuntimeException('Unable to generate the test certificate key.');
+}
+$request = openssl_csr_new(['commonName' => 'localhost'], $key, ['digest_alg' => 'sha256']);
+if ($request === false) {
+    throw new RuntimeException('Unable to generate the test certificate request.');
+}
+$certificate = openssl_csr_sign($request, null, $key, 1, ['digest_alg' => 'sha256']);
+if ($certificate === false) {
+    throw new RuntimeException('Unable to generate the test certificate.');
+}
+$private = $public = '';
+openssl_pkey_export($key, $private);
+openssl_x509_export($certificate, $public);
+echo json_encode(['key' => $private, 'cert' => $public], JSON_THROW_ON_ERROR);
diff --git a/tests/Frameworks/http2/client.cjs b/tests/Frameworks/http2/client.cjs
new file mode 100644
index 00000000..af2748b1
--- /dev/null
+++ b/tests/Frameworks/http2/client.cjs
@@ -0,0 +1,27 @@
+'use strict';
+const http2 = require('http2');
+const crypto = require('crypto');
+const results = [];
+const secure = !!process.env.PHASIS_HTTP2_TLS_CERT;
+const client = http2.connect((secure ? 'https://' : 'http://') + '127.0.0.1:' + process.argv[2], secure ? {
+  ca: require('fs').readFileSync(process.env.PHASIS_HTTP2_TLS_CERT), servername: 'localhost',
+} : {});
+client.on('connect', () => {
+  for (let i = 0; i < 3; i++) {
+    const request = client.request({ ':method': 'POST', ':path': '/peer/' + i, 'x-compressed': 'shared header value across streams' });
+    const chunks = [], result = { id: i };
+    request.on('response', headers => { result.status = headers[':status']; result.path = headers['x-path']; result.header = headers['x-compressed']; });
+    request.on('trailers', headers => { result.trailer = headers['x-finished']; });
+    request.on('data', chunk => chunks.push(chunk));
+    request.on('end', () => {
+      const data = Buffer.concat(chunks); result.bytes = data.length; result.sha256 = crypto.createHash('sha256').update(data).digest('hex');
+      results.push(result);
+      if (results.length === 3) {
+        const serialized = JSON.stringify({ results: results.sort((a, b) => a.id - b.id) });
+        if (typeof __http2Report === 'function') __http2Report(serialized); else console.log(serialized);
+        client.close();
+      }
+    });
+    request.end(Buffer.alloc(70000 + i, 65 + i));
+  }
+});
diff --git a/tests/Frameworks/http2/interop.mjs b/tests/Frameworks/http2/interop.mjs
new file mode 100644
index 00000000..aa3d2663
--- /dev/null
+++ b/tests/Frameworks/http2/interop.mjs
@@ -0,0 +1,69 @@
+import { spawn, execFileSync } from 'node:child_process';
+import { fileURLToPath } from 'node:url';
+import { dirname, resolve } from 'node:path';
+import { createHash } from 'node:crypto';
+import assert from 'node:assert/strict';
+import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+
+const directory = dirname(fileURLToPath(import.meta.url));
+const running = new Set();
+const materialDirectory = mkdtempSync(resolve(tmpdir(), 'phasis-http2-interop-'));
+const material = JSON.parse(execFileSync('php', [resolve(directory, 'certificate.php')], { env: { ...process.env, XDEBUG_MODE: 'off' }, encoding: 'utf8' }));
+writeFileSync(resolve(materialDirectory, 'key.pem'), material.key, { mode: 0o600 });
+writeFileSync(resolve(materialDirectory, 'cert.pem'), material.cert, { mode: 0o600 });
+function launch(runtime, file, args = [], secure = false) {
+  const command = runtime === 'node' ? ['node', resolve(directory, file), ...args]
+    : ['php', '-d', 'memory_limit=1G', resolve(directory, 'run-php.php'), resolve(directory, file), ...args];
+  const env = { ...process.env, XDEBUG_MODE: 'off' };
+  if (secure) { env.PHASIS_HTTP2_TLS_KEY = resolve(materialDirectory, 'key.pem'); env.PHASIS_HTTP2_TLS_CERT = resolve(materialDirectory, 'cert.pem'); }
+  const child = spawn(command[0], command.slice(1), { env, stdio: ['ignore', 'pipe', 'pipe'] });
+  running.add(child);
+  let output = '', errors = '';
+  const lines = [], waiters = [];
+  child.stdout.on('data', data => {
+    output += data;
+    while (output.includes('\n')) {
+      const end = output.indexOf('\n'), line = output.slice(0, end); output = output.slice(end + 1);
+      let decoded; try { decoded = JSON.parse(line); } catch { errors += line + '\n'; continue; }
+      if (waiters.length) waiters.shift().resolve(decoded); else lines.push(decoded);
+    }
+  });
+  child.stderr.on('data', data => { errors += data; });
+  const completion = new Promise((resolve, reject) => {
+    child.once('error', reject);
+    child.once('exit', code => {
+      running.delete(child);
+      if (code === 0) resolve(); else reject(new Error(`${runtime} ${file} exited ${code}: ${errors}`));
+      for (const waiter of waiters) waiter.reject(new Error(`${runtime} exited before producing a report: ${errors}`));
+    });
+  });
+  completion.catch(() => {});
+  return { completion, next: () => lines.length ? Promise.resolve(lines.shift()) : new Promise((resolve, reject) => waiters.push({ resolve, reject })) };
+}
+const timeout = setTimeout(() => {
+  for (const child of running) child.kill('SIGKILL');
+  process.exitCode = 1;
+}, 60000);
+try {
+  for (const [serverRuntime, clientRuntime, secure] of [['node', 'phasis', false], ['phasis', 'node', false], ['node', 'phasis', true], ['phasis', 'node', true]]) {
+    const server = launch(serverRuntime, 'server.cjs', [], secure);
+    const { ready } = await server.next();
+    const client = launch(clientRuntime, 'client.cjs', [String(ready)], secure);
+    const { results } = await client.next();
+    assert.equal(results.length, 3);
+    for (const result of results) {
+      assert.deepEqual(result, {
+        id: result.id, status: 201, path: '/peer/' + result.id,
+        header: 'shared header value across streams', trailer: 'yes', bytes: 70000 + result.id,
+        sha256: createHash('sha256').update(Buffer.alloc(70000 + result.id, 65 + result.id)).digest('hex'),
+      });
+    }
+    await Promise.all([client.completion, server.completion]);
+    console.log(JSON.stringify({ server: serverRuntime, client: clientRuntime, tls: secure, streams: results.length, passed: true }));
+  }
+} finally {
+  clearTimeout(timeout);
+  for (const child of running) child.kill('SIGKILL');
+  rmSync(materialDirectory, { recursive: true, force: true });
+}
diff --git a/tests/Frameworks/http2/run-php.php b/tests/Frameworks/http2/run-php.php
new file mode 100644
index 00000000..0a3a1c50
--- /dev/null
+++ b/tests/Frameworks/http2/run-php.php
@@ -0,0 +1,23 @@
+enableNode(new NodeOptions(argv: ['phasis', $argv[1], ...array_slice($argv, 2)]));
+$engine->setLimit('maxLoopIterations', 1_000_000);
+$engine->setGlobal('__http2Ready', static function (int $port): void {
+    fwrite(STDOUT, json_encode(['ready' => $port], JSON_THROW_ON_ERROR) . "\n");
+});
+$engine->setGlobal('__http2Report', static function (string $report): void {
+    fwrite(STDOUT, $report . "\n");
+});
+try {
+    $engine->execFile($argv[1]);
+} finally {
+    $engine->getNodeRuntime()?->close();
+}
diff --git a/tests/Frameworks/http2/server.cjs b/tests/Frameworks/http2/server.cjs
new file mode 100644
index 00000000..069c9f31
--- /dev/null
+++ b/tests/Frameworks/http2/server.cjs
@@ -0,0 +1,22 @@
+'use strict';
+const http2 = require('http2');
+const secure = !!process.env.PHASIS_HTTP2_TLS_CERT;
+const server = secure ? http2.createSecureServer({
+  key: require('fs').readFileSync(process.env.PHASIS_HTTP2_TLS_KEY),
+  cert: require('fs').readFileSync(process.env.PHASIS_HTTP2_TLS_CERT),
+}) : http2.createServer();
+let completed = 0;
+server.on('stream', (stream, headers) => {
+  const chunks = [];
+  stream.on('data', chunk => chunks.push(chunk));
+  stream.on('end', () => {
+    stream.respond({ ':status': 201, 'x-path': headers[':path'], 'x-compressed': headers['x-compressed'] }, { waitForTrailers: true });
+    stream.on('wantTrailers', () => stream.sendTrailers({ 'x-finished': 'yes' }));
+    stream.end(Buffer.concat(chunks));
+  });
+  stream.on('close', () => { if (++completed === 3) server.close(); });
+});
+server.listen(0, '127.0.0.1', () => {
+  if (typeof __http2Ready === 'function') __http2Ready(server.address().port);
+  else console.log(JSON.stringify({ ready: server.address().port }));
+});
diff --git a/tests/Frameworks/package-lock.json b/tests/Frameworks/package-lock.json
new file mode 100644
index 00000000..f4509fd9
--- /dev/null
+++ b/tests/Frameworks/package-lock.json
@@ -0,0 +1,5630 @@
+{
+  "name": "phasis-framework-oracles",
+  "version": "0.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "phasis-framework-oracles",
+      "version": "0.0.0",
+      "devDependencies": {
+        "@hono/node-server": "2.0.12",
+        "@sinonjs/fake-timers": "15.4.0",
+        "@vitest/expect": "5.0.1",
+        "@vitest/spy": "5.0.1",
+        "after": "0.8.2",
+        "connect-redis": "8.1.0",
+        "cookie-parser": "1.4.7",
+        "cookie-session": "2.1.1",
+        "ejs": "3.1.10",
+        "esbuild": "0.28.2",
+        "express": "5.3.0",
+        "express-session": "1.19.0",
+        "hbs": "4.3.1",
+        "hono": "4.13.13",
+        "jsdom": "22.1.0",
+        "marked": "15.0.12",
+        "method-override": "3.0.0",
+        "mocha": "11.8.0",
+        "morgan": "1.12.1",
+        "msw": "2.6.0",
+        "pbkdf2-password": "1.2.1",
+        "supertest": "6.3.4",
+        "typescript": "6.0.3",
+        "vhost": "3.0.2",
+        "vitest": "5.0.1",
+        "ws": "8.21.0",
+        "zod": "3.23.8"
+      },
+      "engines": {
+        "node": ">=26"
+      }
+    },
+    "node_modules/@bundled-es-modules/cookie": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz",
+      "integrity": "sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "cookie": "^0.7.2"
+      }
+    },
+    "node_modules/@bundled-es-modules/statuses": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz",
+      "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "statuses": "^2.0.1"
+      }
+    },
+    "node_modules/@bundled-es-modules/tough-cookie": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz",
+      "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@types/tough-cookie": "^4.0.5",
+        "tough-cookie": "^4.1.4"
+      }
+    },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
+      "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
+      "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
+      "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
+      "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
+      "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
+      "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
+      "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
+      "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
+      "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
+      "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
+      "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
+      "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
+      "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
+      "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
+      "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
+      "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
+      "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
+      "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
+      "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
+      "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
+      "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openharmony-arm64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
+      "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
+      "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
+      "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
+      "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
+      "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@hono/node-server": {
+      "version": "2.0.12",
+      "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.0.12.tgz",
+      "integrity": "sha512-eWpQYr67tqJLeaSUl0Q+TquuYfUdTibpOJlUMV2FfUP7+KqCC5TufnwnlXL6mobZBJbGAYRd7ZvEBDCbLInjhg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=20"
+      },
+      "peerDependencies": {
+        "hono": "^4"
+      }
+    },
+    "node_modules/@inquirer/ansi": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
+      "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@inquirer/confirm": {
+      "version": "5.1.21",
+      "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz",
+      "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/type": "^3.0.10"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/core": {
+      "version": "10.3.2",
+      "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz",
+      "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/ansi": "^1.0.2",
+        "@inquirer/figures": "^1.0.15",
+        "@inquirer/type": "^3.0.10",
+        "cli-width": "^4.1.0",
+        "mute-stream": "^2.0.0",
+        "signal-exit": "^4.1.0",
+        "wrap-ansi": "^6.2.0",
+        "yoctocolors-cjs": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/core/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@inquirer/core/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@inquirer/core/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@inquirer/core/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@inquirer/core/node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@inquirer/figures": {
+      "version": "1.0.15",
+      "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz",
+      "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@inquirer/type": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz",
+      "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@isaacs/cliui": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^5.1.2",
+        "string-width-cjs": "npm:string-width@^4.2.0",
+        "strip-ansi": "^7.0.1",
+        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+        "wrap-ansi": "^8.1.0",
+        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz",
+      "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@mswjs/interceptors": {
+      "version": "0.36.10",
+      "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.36.10.tgz",
+      "integrity": "sha512-GXrJgakgJW3DWKueebkvtYgGKkxA7s0u5B0P5syJM5rvQUnrpLPigvci8Hukl7yEM+sU06l+er2Fgvx/gmiRgg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@open-draft/deferred-promise": "^2.2.0",
+        "@open-draft/logger": "^0.3.0",
+        "@open-draft/until": "^2.0.0",
+        "is-node-process": "^1.2.0",
+        "outvariant": "^1.4.3",
+        "strict-event-emitter": "^0.5.1"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@noble/hashes": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
+      "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^14.21.3 || >=16"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@open-draft/deferred-promise": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz",
+      "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@open-draft/logger": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz",
+      "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-node-process": "^1.2.0",
+        "outvariant": "^1.4.0"
+      }
+    },
+    "node_modules/@open-draft/until": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz",
+      "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@oxc-project/types": {
+      "version": "0.155.0",
+      "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz",
+      "integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "url": "https://github.com/sponsors/oxc-project"
+      }
+    },
+    "node_modules/@paralleldrive/cuid2": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz",
+      "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@noble/hashes": "^1.1.5"
+      }
+    },
+    "node_modules/@pkgjs/parseargs": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+      "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@rolldown/binding-android-arm-eabi": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.15.tgz",
+      "integrity": "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-android-arm64": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.15.tgz",
+      "integrity": "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-darwin-arm64": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.15.tgz",
+      "integrity": "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-darwin-x64": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.15.tgz",
+      "integrity": "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-freebsd-x64": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.15.tgz",
+      "integrity": "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.15.tgz",
+      "integrity": "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-arm64-gnu": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.15.tgz",
+      "integrity": "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "libc": [
+        "glibc"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-arm64-musl": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.15.tgz",
+      "integrity": "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "libc": [
+        "musl"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-ppc64-gnu": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.15.tgz",
+      "integrity": "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "libc": [
+        "glibc"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-s390x-gnu": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.15.tgz",
+      "integrity": "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "libc": [
+        "glibc"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-x64-gnu": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.15.tgz",
+      "integrity": "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "libc": [
+        "glibc"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-linux-x64-musl": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.15.tgz",
+      "integrity": "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "libc": [
+        "musl"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-openharmony-arm64": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.15.tgz",
+      "integrity": "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-win32-arm64-msvc": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.15.tgz",
+      "integrity": "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/binding-win32-x64-msvc": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.15.tgz",
+      "integrity": "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      }
+    },
+    "node_modules/@rolldown/pluginutils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
+      "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@sinonjs/commons": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
+      "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "type-detect": "4.0.8"
+      }
+    },
+    "node_modules/@sinonjs/fake-timers": {
+      "version": "15.4.0",
+      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz",
+      "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@sinonjs/commons": "^3.0.1"
+      }
+    },
+    "node_modules/@standard-schema/spec": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+      "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@tootallnate/once": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz",
+      "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@types/chai": {
+      "version": "5.2.3",
+      "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
+      "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/deep-eql": "*",
+        "assertion-error": "^2.0.1"
+      }
+    },
+    "node_modules/@types/cookie": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+      "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/deep-eql": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
+      "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+      "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/statuses": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz",
+      "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/tough-cookie": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
+      "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@vitest/expect": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-5.0.1.tgz",
+      "integrity": "sha512-U4YclNr7ds8kqZdtLcoVCYTaLRmaKeyjRjQHQ2We5iY0ZjegavIeBWJOr2F4pgUFuN0tO0bz/cVa4ERwKhf1Hg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@standard-schema/spec": "^1.1.0",
+        "@types/chai": "^5.2.2",
+        "@vitest/spy": "5.0.1",
+        "@vitest/utils": "5.0.1",
+        "chai": "^6.2.2",
+        "tinyrainbow": "^3.1.1"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/mocker": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.1.tgz",
+      "integrity": "sha512-6K1DoBNAPGvuOcSsGA4D6x+5zEEff/KmOOP3uetT2TrGpVfI+HRHRnJJfKi5ib/g1vx8IYHQD8s0pbJz8WQI7Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/trace-mapping": "0.3.31",
+        "@vitest/spy": "5.0.1",
+        "estree-walker": "^3.0.3",
+        "magic-string": "^1.2.3"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "msw": "^2.4.9",
+        "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "msw": {
+          "optional": true
+        },
+        "vite": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vitest/pretty-format": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-5.0.1.tgz",
+      "integrity": "sha512-6guWwj5d9bguuefTOvJoq387tfpkzSv554YdUEGzjJH2PnnmvzTLQ1UQSuAk5wBFVhf2CUmy/S/palOcb6dmpA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tinyrainbow": "^3.1.1"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/spy": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.1.tgz",
+      "integrity": "sha512-rbto/mF/SGERxEgYOek7Xm6B9b+y+mVoo+f4b2LymYO8zM1b7uB5nHuhVMTP2hxdzgxvGiZYGxGIaMvL5y180Q==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/utils": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-5.0.1.tgz",
+      "integrity": "sha512-E9+yEA+jsfaoxZcUHFzEqUrQcoNh2EwrPT5efIqkUPUwD5Ua2Li9BRWaYeRwvzvdLgTSVrre8oKNeyrfg7KkdQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/pretty-format": "5.0.1",
+        "convert-source-map": "^2.0.0",
+        "tinyrainbow": "^3.1.1"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/abab": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
+      "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
+      "deprecated": "Use your platform's native atob() and btoa() methods instead",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/accepts": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+      "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-types": "^3.0.0",
+        "negotiator": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/after": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
+      "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
+    "node_modules/agent-base/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz",
+      "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true,
+      "license": "Python-2.0"
+    },
+    "node_modules/asap": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+      "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/assertion-error": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+      "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/async": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+      "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/basic-auth": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+      "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "5.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/basic-auth/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/body-parser": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.4.0.tgz",
+      "integrity": "sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bytes": "^3.1.2",
+        "content-type": "^2.1.0",
+        "debug": "^4.4.3",
+        "http-errors": "^2.0.1",
+        "iconv-lite": "^0.7.3",
+        "on-finished": "^2.4.1",
+        "qs": "^6.16.1",
+        "raw-body": "^3.0.2",
+        "type-is": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/body-parser/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
+      "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/browser-stdout": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/call-bind-apply-helpers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/call-bound": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+      "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "get-intrinsic": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/camelcase": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/chai": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz",
+      "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/chalk/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/cli-width": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+      "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/cliui/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cliui/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cliui/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cliui/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cliui/node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/component-emitter": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
+      "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/connect-redis": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-8.1.0.tgz",
+      "integrity": "sha512-Km0EYLDlmExF52UCss5gLGTtrukGC57G6WCC2aqEMft5Vr4xNWuM4tL+T97kWrw+vp40SXFteb6Xk/7MxgpwdA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "express-session": ">=1"
+      }
+    },
+    "node_modules/content-disposition": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz",
+      "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/content-type": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz",
+      "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cookie": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+      "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/cookie-parser": {
+      "version": "1.4.7",
+      "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+      "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cookie": "0.7.2",
+        "cookie-signature": "1.0.6"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/cookie-session": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.1.1.tgz",
+      "integrity": "sha512-ji3kym/XZaFVew1+tIZk5ZLp9Z/fLv9rK1aZmpug0FsgE7Cu3ZDrUdRo7FT9vFjMYfNimrrUHJzywDwT7XEFlg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cookies": "0.9.1",
+        "debug": "3.2.7",
+        "on-headers": "~1.1.0",
+        "safe-buffer": "5.2.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cookiejar": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
+      "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cookies": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.9.1.tgz",
+      "integrity": "sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "depd": "~2.0.0",
+        "keygrip": "~1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/cssstyle": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
+      "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "rrweb-cssom": "^0.6.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/data-urls": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz",
+      "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "abab": "^2.0.6",
+        "whatwg-mimetype": "^3.0.0",
+        "whatwg-url": "^12.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/decamelize": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/decimal.js": {
+      "version": "10.6.0",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
+      "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/dezalgo": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
+      "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "asap": "^2.0.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/diff": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
+      "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/domexception": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
+      "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
+      "deprecated": "Use your platform's native DOMException instead",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "webidl-conversions": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/dunder-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/ejs": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
+      "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "jake": "^10.8.5"
+      },
+      "bin": {
+        "ejs": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/encodeurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+      "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/entities": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+      "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-module-lexer": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz",
+      "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
+      "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+      "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/esbuild": {
+      "version": "0.28.2",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
+      "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.28.2",
+        "@esbuild/android-arm": "0.28.2",
+        "@esbuild/android-arm64": "0.28.2",
+        "@esbuild/android-x64": "0.28.2",
+        "@esbuild/darwin-arm64": "0.28.2",
+        "@esbuild/darwin-x64": "0.28.2",
+        "@esbuild/freebsd-arm64": "0.28.2",
+        "@esbuild/freebsd-x64": "0.28.2",
+        "@esbuild/linux-arm": "0.28.2",
+        "@esbuild/linux-arm64": "0.28.2",
+        "@esbuild/linux-ia32": "0.28.2",
+        "@esbuild/linux-loong64": "0.28.2",
+        "@esbuild/linux-mips64el": "0.28.2",
+        "@esbuild/linux-ppc64": "0.28.2",
+        "@esbuild/linux-riscv64": "0.28.2",
+        "@esbuild/linux-s390x": "0.28.2",
+        "@esbuild/linux-x64": "0.28.2",
+        "@esbuild/netbsd-arm64": "0.28.2",
+        "@esbuild/netbsd-x64": "0.28.2",
+        "@esbuild/openbsd-arm64": "0.28.2",
+        "@esbuild/openbsd-x64": "0.28.2",
+        "@esbuild/openharmony-arm64": "0.28.2",
+        "@esbuild/sunos-x64": "0.28.2",
+        "@esbuild/win32-arm64": "0.28.2",
+        "@esbuild/win32-ia32": "0.28.2",
+        "@esbuild/win32-x64": "0.28.2"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/estree-walker": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+      "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0"
+      }
+    },
+    "node_modules/etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/expect-type": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz",
+      "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/express": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/express/-/express-5.3.0.tgz",
+      "integrity": "sha512-qCqy1xSoaugxOD4IVHb1ZWdkvCF2W3aE2okKouWj8VwJ+ztskSiXoBnCSJqfKT+cVPJhuJqe9YLbY425+Zh00g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "accepts": "^2.0.0",
+        "body-parser": "^2.3.0",
+        "content-disposition": "^2.0.1",
+        "content-type": "^2.0.0",
+        "cookie": "^0.7.1",
+        "cookie-signature": "^1.2.1",
+        "debug": "^4.4.0",
+        "depd": "^2.0.0",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "etag": "^1.8.1",
+        "finalhandler": "^2.1.0",
+        "fresh": "^2.0.0",
+        "http-errors": "^2.0.0",
+        "merge-descriptors": "^2.0.0",
+        "mime-types": "^3.0.0",
+        "on-finished": "^2.4.1",
+        "once": "^1.4.0",
+        "parseurl": "^1.3.3",
+        "proxy-addr": "^2.0.8",
+        "qs": "^6.16.0",
+        "range-parser": "^1.2.1",
+        "router": "^2.2.0",
+        "send": "^1.1.0",
+        "serve-static": "^2.2.0",
+        "statuses": "^2.0.1",
+        "type-is": "^2.1.0",
+        "vary": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/express-session": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.19.0.tgz",
+      "integrity": "sha512-0csaMkGq+vaiZTmSMMGkfdCOabYv192VbytFypcvI0MANrp+4i/7yEkJ0sbAEhycQjntaKGzYfjfXQyVb7BHMA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cookie": "~0.7.2",
+        "cookie-signature": "~1.0.7",
+        "debug": "~2.6.9",
+        "depd": "~2.0.0",
+        "on-headers": "~1.1.0",
+        "parseurl": "~1.3.3",
+        "safe-buffer": "~5.2.1",
+        "uid-safe": "~2.1.5"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/express-session/node_modules/cookie-signature": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
+      "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/express-session/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/express-session/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/express/node_modules/cookie-signature": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+      "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.6.0"
+      }
+    },
+    "node_modules/express/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/fast-safe-stringify": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+      "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fastfall": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/fastfall/-/fastfall-1.5.1.tgz",
+      "integrity": "sha512-KH6p+Z8AKPXnmA7+Iz2Lh8ARCMr+8WNPVludm1LGkZoD2MjY6LVnRMtTKhkdzI+jr0RzQWXKzKyBJm1zoHEL4Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "reusify": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fdir": {
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+      "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/filelist": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz",
+      "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "minimatch": "^5.0.1"
+      }
+    },
+    "node_modules/finalhandler": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
+      "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.4.0",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "on-finished": "^2.4.1",
+        "parseurl": "^1.3.3",
+        "statuses": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/finalhandler/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/flat": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "bin": {
+        "flat": "cli.js"
+      }
+    },
+    "node_modules/foreachasync": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz",
+      "integrity": "sha512-J+ler7Ta54FwwNcx6wQRDhTIbNeyDcARMkOcguEqnEdtm0jKvN3Li3PDAb2Du3ubJYEWfYL83XMROXdsXAXycw==",
+      "dev": true,
+      "license": "Apache2"
+    },
+    "node_modules/foreground-child": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+      "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "cross-spawn": "^7.0.6",
+        "signal-exit": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
+      "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "es-set-tostringtag": "^2.1.0",
+        "hasown": "^2.0.4",
+        "mime-types": "^2.1.35"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/form-data/node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/form-data/node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/formidable": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.5.tgz",
+      "integrity": "sha512-Oz5Hwvwak/DCaXVVUtPn4oLMLLy1CdclLKO1LFgU7XzDpVMUU5UjlSLpGMocyQNNk8F6IJW9M/YdooSn2MRI+Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@paralleldrive/cuid2": "^2.2.2",
+        "dezalgo": "^1.0.4",
+        "once": "^1.4.0",
+        "qs": "^6.11.0"
+      },
+      "funding": {
+        "url": "https://ko-fi.com/tunnckoCore/commissions"
+      }
+    },
+    "node_modules/forwarded": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/fresh": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+      "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "function-bind": "^1.1.2",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "math-intrinsics": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/glob": {
+      "version": "10.5.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+      "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "foreground-child": "^3.1.0",
+        "jackspeak": "^3.1.2",
+        "minimatch": "^9.0.4",
+        "minipass": "^7.1.2",
+        "package-json-from-dist": "^1.0.0",
+        "path-scurry": "^1.11.1"
+      },
+      "bin": {
+        "glob": "dist/esm/bin.mjs"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob/node_modules/minimatch": {
+      "version": "9.0.9",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+      "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/graphql": {
+      "version": "16.14.2",
+      "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.2.tgz",
+      "integrity": "sha512-Chq1s4CY7jmh8gO2qvLIJyfCDIN+EHLFW/9iShnp1z8FjBQMoodWP1kDC36VAMXXIvAjj4ARa7ntfAV2BrjsbA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
+      }
+    },
+    "node_modules/handlebars": {
+      "version": "4.7.9",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
+      "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "minimist": "^1.2.5",
+        "neo-async": "^2.6.2",
+        "source-map": "^0.6.1",
+        "wordwrap": "^1.0.0"
+      },
+      "bin": {
+        "handlebars": "bin/handlebars"
+      },
+      "engines": {
+        "node": ">=0.4.7"
+      },
+      "optionalDependencies": {
+        "uglify-js": "^3.1.4"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-symbols": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
+      "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/hbs": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/hbs/-/hbs-4.3.1.tgz",
+      "integrity": "sha512-3dnqb6UauidoOLE0Ve2661d6rHeJuVFCycO/2vACtx9NCs4cL2xFPuT3CozQ+5vTxjoOMZ5tRJEYDPkMHXl0Tg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "handlebars": "4.7.9",
+        "walk": "2.3.15"
+      },
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "node_modules/he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "he": "bin/he"
+      }
+    },
+    "node_modules/headers-polyfill": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz",
+      "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/hono": {
+      "version": "4.13.13",
+      "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.13.tgz",
+      "integrity": "sha512-CQ46U0ZkAGmbT/4UxdzzGJpacP2IeKgY4a5/tOI9AABbpOMfK739wfDXmv1usCk+3RkKj1hQy4/fjhiwa2xlrA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=16.9.0"
+      }
+    },
+    "node_modules/html-encoding-sniffer": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
+      "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-encoding": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/http-errors": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+      "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "depd": "~2.0.0",
+        "inherits": "~2.0.4",
+        "setprototypeof": "~1.2.0",
+        "statuses": "~2.0.2",
+        "toidentifier": "~1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/http-proxy-agent": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
+      "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@tootallnate/once": "2",
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/http-proxy-agent/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/https-proxy-agent/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
+      "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-node-process": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
+      "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/is-path-inside": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-potential-custom-element-name": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+      "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/is-promise": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+      "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/jackspeak": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+      "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "@isaacs/cliui": "^8.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      },
+      "optionalDependencies": {
+        "@pkgjs/parseargs": "^0.11.0"
+      }
+    },
+    "node_modules/jake": {
+      "version": "10.9.4",
+      "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz",
+      "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "async": "^3.2.6",
+        "filelist": "^1.0.4",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "jake": "bin/cli.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/js-yaml": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+      "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/puzrin"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/nodeca"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsdom": {
+      "version": "22.1.0",
+      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
+      "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "abab": "^2.0.6",
+        "cssstyle": "^3.0.0",
+        "data-urls": "^4.0.0",
+        "decimal.js": "^10.4.3",
+        "domexception": "^4.0.0",
+        "form-data": "^4.0.0",
+        "html-encoding-sniffer": "^3.0.0",
+        "http-proxy-agent": "^5.0.0",
+        "https-proxy-agent": "^5.0.1",
+        "is-potential-custom-element-name": "^1.0.1",
+        "nwsapi": "^2.2.4",
+        "parse5": "^7.1.2",
+        "rrweb-cssom": "^0.6.0",
+        "saxes": "^6.0.0",
+        "symbol-tree": "^3.2.4",
+        "tough-cookie": "^4.1.2",
+        "w3c-xmlserializer": "^4.0.0",
+        "webidl-conversions": "^7.0.0",
+        "whatwg-encoding": "^2.0.0",
+        "whatwg-mimetype": "^3.0.0",
+        "whatwg-url": "^12.0.1",
+        "ws": "^8.13.0",
+        "xml-name-validator": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "peerDependencies": {
+        "canvas": "^2.5.0"
+      },
+      "peerDependenciesMeta": {
+        "canvas": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/keygrip": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
+      "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tsscmp": "1.0.6"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/lightningcss": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz",
+      "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==",
+      "dev": true,
+      "license": "MPL-2.0",
+      "peer": true,
+      "dependencies": {
+        "detect-libc": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "lightningcss-android-arm64": "1.33.0",
+        "lightningcss-darwin-arm64": "1.33.0",
+        "lightningcss-darwin-x64": "1.33.0",
+        "lightningcss-freebsd-x64": "1.33.0",
+        "lightningcss-linux-arm-gnueabihf": "1.33.0",
+        "lightningcss-linux-arm64-gnu": "1.33.0",
+        "lightningcss-linux-arm64-musl": "1.33.0",
+        "lightningcss-linux-x64-gnu": "1.33.0",
+        "lightningcss-linux-x64-musl": "1.33.0",
+        "lightningcss-win32-arm64-msvc": "1.33.0",
+        "lightningcss-win32-x64-msvc": "1.33.0"
+      }
+    },
+    "node_modules/lightningcss-android-arm64": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz",
+      "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-darwin-arm64": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz",
+      "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-darwin-x64": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz",
+      "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-freebsd-x64": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz",
+      "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm-gnueabihf": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz",
+      "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm64-gnu": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz",
+      "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "libc": [
+        "glibc"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-arm64-musl": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz",
+      "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "libc": [
+        "musl"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-x64-gnu": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz",
+      "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "libc": [
+        "glibc"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-linux-x64-musl": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz",
+      "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "libc": [
+        "musl"
+      ],
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-win32-arm64-msvc": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz",
+      "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/lightningcss-win32-x64-msvc": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz",
+      "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MPL-2.0",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "peer": true,
+      "engines": {
+        "node": ">= 12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/magic-string": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.3.tgz",
+      "integrity": "sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.6.0"
+      }
+    },
+    "node_modules/marked": {
+      "version": "15.0.12",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz",
+      "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "marked": "bin/marked.js"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/math-intrinsics": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/media-typer": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz",
+      "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/merge-descriptors": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+      "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/method-override": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz",
+      "integrity": "sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "3.1.0",
+        "methods": "~1.1.2",
+        "parseurl": "~1.3.2",
+        "vary": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/method-override/node_modules/debug": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/method-override/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
+      "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.54.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+      "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
+      "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "^1.54.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "5.1.9",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
+      "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+      "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/mocha": {
+      "version": "11.8.0",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.8.0.tgz",
+      "integrity": "sha512-VyCeUdGN3A9lmCTTgG4yuvY9ixxaDk+xt2R/7/+1AP6EqNG+G9OKkzBwhVtVYoNX8YsxNSgAl8mOv3IAeOpFbw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "browser-stdout": "^1.3.1",
+        "chokidar": "^4.0.1",
+        "debug": "^4.3.5",
+        "diff": "^7.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "find-up": "^5.0.0",
+        "glob": "^10.4.5",
+        "he": "^1.2.0",
+        "is-path-inside": "^3.0.3",
+        "js-yaml": "^4.1.0",
+        "log-symbols": "^4.1.0",
+        "minimatch": "^9.0.5",
+        "ms": "^2.1.3",
+        "picocolors": "^1.1.1",
+        "serialize-javascript": "^6.0.2",
+        "strip-json-comments": "^3.1.1",
+        "supports-color": "^8.1.1",
+        "workerpool": "^9.2.0",
+        "yargs": "^17.7.2",
+        "yargs-parser": "^21.1.1",
+        "yargs-unparser": "^2.0.0"
+      },
+      "bin": {
+        "_mocha": "bin/_mocha",
+        "mocha": "bin/mocha.js"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/mocha/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/mocha/node_modules/minimatch": {
+      "version": "9.0.9",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+      "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/morgan": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.12.1.tgz",
+      "integrity": "sha512-tljKC0ex20AjO58Ob/eZ53JloycbVswbVNCHx6V6VLGzqt/w8dIynVGL0G8qVjNKwiA7sYSogCrN6QtJ82IV+g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "basic-auth": "~2.0.1",
+        "debug": "2.6.9",
+        "depd": "~2.0.0",
+        "on-finished": "~2.4.1",
+        "on-headers": "~1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/morgan/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/morgan/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/msw": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/msw/-/msw-2.6.0.tgz",
+      "integrity": "sha512-n3tx2w0MZ3H4pxY0ozrQ4sNPzK/dGtlr2cIIyuEsgq2Bhy4wvcW6ZH2w/gXM9+MEUY6HC1fWhqtcXDxVZr5Jxw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "@bundled-es-modules/cookie": "^2.0.0",
+        "@bundled-es-modules/statuses": "^1.0.1",
+        "@bundled-es-modules/tough-cookie": "^0.1.6",
+        "@inquirer/confirm": "^5.0.0",
+        "@mswjs/interceptors": "^0.36.5",
+        "@open-draft/deferred-promise": "^2.2.0",
+        "@open-draft/until": "^2.1.0",
+        "@types/cookie": "^0.6.0",
+        "@types/statuses": "^2.0.4",
+        "chalk": "^4.1.2",
+        "graphql": "^16.8.1",
+        "headers-polyfill": "^4.0.2",
+        "is-node-process": "^1.2.0",
+        "outvariant": "^1.4.3",
+        "path-to-regexp": "^6.3.0",
+        "strict-event-emitter": "^0.5.1",
+        "type-fest": "^4.26.1",
+        "yargs": "^17.7.2"
+      },
+      "bin": {
+        "msw": "cli/index.js"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mswjs"
+      },
+      "peerDependencies": {
+        "typescript": ">= 4.8.x"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/msw/node_modules/path-to-regexp": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
+      "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/mute-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz",
+      "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.20",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz",
+      "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/negotiator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz",
+      "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "content-type": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/neo-async": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+      "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/nwsapi": {
+      "version": "2.2.28",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.28.tgz",
+      "integrity": "sha512-IlVB7OS7qrOsVYlpnFIkETjMwT9jwvmocJmmM+GZU/PAB3uGi9Ezd7vcWhWBUnSc0ya4ppmQITOyP1ez9gg8cg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+      "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/obug": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz",
+      "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==",
+      "dev": true,
+      "funding": [
+        "https://github.com/sponsors/sxzz",
+        "https://opencollective.com/debug"
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.20.0"
+      }
+    },
+    "node_modules/on-finished": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.2.tgz",
+      "integrity": "sha512-ATWUv387i+nLD49EiDoOft5scf32Vsdz3ktrQJG9bi7jRFmaXTssvyvj1EmeKVVgvesbqUtvQQvaS2TpTukAZQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/on-headers": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
+      "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/outvariant": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz",
+      "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/package-json-from-dist": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+      "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0"
+    },
+    "node_modules/parse5": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+      "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "entities": "^6.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-scurry": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+      "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "lru-cache": "^10.2.0",
+        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/path-to-regexp": {
+      "version": "8.4.2",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
+      "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/pbkdf2-password": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/pbkdf2-password/-/pbkdf2-password-1.2.1.tgz",
+      "integrity": "sha512-I6ZiUi82uhYN47lOzi8P7O69e70LRopgS4TIkq0ecDAPHrlxABWOHxLEsTzCuogkxTofFJDj0eEbOALgrrxhKg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fastfall": "^1.2.3"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
+      "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.5.31",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz",
+      "integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "nanoid": "^3.3.20",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.2"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/proxy-addr": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.8.tgz",
+      "integrity": "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "forwarded": "0.2.0",
+        "ipaddr.js": "1.9.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/psl": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
+      "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "punycode": "^2.3.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/lupomontero"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.16.1",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.1.tgz",
+      "integrity": "sha512-5Px6J7rfHBAGUhNQ3es4YzcOdBBw0SDcVtThJml4RdnKw4tKs2epA0kPZ+K8X+WiHktT93RHVcQ/3ym5aTCgtg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "es-define-property": "^1.0.1",
+        "side-channel": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/querystringify": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/random-bytes": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+      "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "node_modules/range-parser": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz",
+      "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/raw-body": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
+      "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bytes": "~3.1.2",
+        "http-errors": "~2.0.1",
+        "iconv-lite": "~0.7.0",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.18.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/reusify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rolldown": {
+      "version": "1.2.15",
+      "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.15.tgz",
+      "integrity": "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@oxc-project/types": "=0.155.0",
+        "@rolldown/pluginutils": "^1.0.0"
+      },
+      "bin": {
+        "rolldown": "bin/cli.mjs"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "optionalDependencies": {
+        "@rolldown/binding-android-arm-eabi": "1.2.15",
+        "@rolldown/binding-android-arm64": "1.2.15",
+        "@rolldown/binding-darwin-arm64": "1.2.15",
+        "@rolldown/binding-darwin-x64": "1.2.15",
+        "@rolldown/binding-freebsd-x64": "1.2.15",
+        "@rolldown/binding-linux-arm-gnueabihf": "1.2.15",
+        "@rolldown/binding-linux-arm64-gnu": "1.2.15",
+        "@rolldown/binding-linux-arm64-musl": "1.2.15",
+        "@rolldown/binding-linux-ppc64-gnu": "1.2.15",
+        "@rolldown/binding-linux-s390x-gnu": "1.2.15",
+        "@rolldown/binding-linux-x64-gnu": "1.2.15",
+        "@rolldown/binding-linux-x64-musl": "1.2.15",
+        "@rolldown/binding-openharmony-arm64": "1.2.15",
+        "@rolldown/binding-win32-arm64-msvc": "1.2.15",
+        "@rolldown/binding-win32-x64-msvc": "1.2.15"
+      }
+    },
+    "node_modules/router": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+      "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.4.0",
+        "depd": "^2.0.0",
+        "is-promise": "^4.0.0",
+        "parseurl": "^1.3.3",
+        "path-to-regexp": "^8.0.0"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/router/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/rrweb-cssom": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
+      "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/saxes": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+      "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "xmlchars": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=v12.22.7"
+      }
+    },
+    "node_modules/semver": {
+      "version": "7.8.5",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+      "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/send": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
+      "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.4.3",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "etag": "^1.8.1",
+        "fresh": "^2.0.0",
+        "http-errors": "^2.0.1",
+        "mime-types": "^3.0.2",
+        "ms": "^2.1.3",
+        "on-finished": "^2.4.1",
+        "range-parser": "^1.2.1",
+        "statuses": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/send/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/serialize-javascript": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+      "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "randombytes": "^2.1.0"
+      }
+    },
+    "node_modules/serve-static": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
+      "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "parseurl": "^1.3.3",
+        "send": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz",
+      "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.4",
+        "side-channel-list": "^1.0.1",
+        "side-channel-map": "^1.0.1",
+        "side-channel-weakmap": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-list": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
+      "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+      "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-weakmap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+      "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3",
+        "side-channel-map": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/siginfo": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+      "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
+      "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/stackback": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+      "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/statuses": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+      "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/std-env": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.3.0.tgz",
+      "integrity": "sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/strict-event-emitter": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz",
+      "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/string-width-cjs": {
+      "name": "string-width",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/string-width-cjs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+      "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^6.2.2"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/strip-ansi-cjs": {
+      "name": "strip-ansi",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/superagent": {
+      "version": "8.1.2",
+      "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz",
+      "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==",
+      "deprecated": "Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "component-emitter": "^1.3.0",
+        "cookiejar": "^2.1.4",
+        "debug": "^4.3.4",
+        "fast-safe-stringify": "^2.1.1",
+        "form-data": "^4.0.0",
+        "formidable": "^2.1.2",
+        "methods": "^1.1.2",
+        "mime": "2.6.0",
+        "qs": "^6.11.0",
+        "semver": "^7.3.8"
+      },
+      "engines": {
+        "node": ">=6.4.0 <13 || >=14"
+      }
+    },
+    "node_modules/superagent/node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/supertest": {
+      "version": "6.3.4",
+      "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz",
+      "integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==",
+      "deprecated": "Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "methods": "^1.1.2",
+        "superagent": "^8.1.2"
+      },
+      "engines": {
+        "node": ">=6.4.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/symbol-tree": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+      "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tinybench": {
+      "version": "6.1.4",
+      "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.1.4.tgz",
+      "integrity": "sha512-9APumHG7r4yOk4X4WlkmE71aZcv1gvin1czO3OQ1U9iJcFA5Ja/ygyb0vPOVHTthFozUYs8CLoLUlM8grb2lTQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/tinyexec": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz",
+      "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tinyglobby": {
+      "version": "0.2.17",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+      "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/tinyrainbow": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.2.0.tgz",
+      "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/tough-cookie": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
+      "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "psl": "^1.1.33",
+        "punycode": "^2.1.1",
+        "universalify": "^0.2.0",
+        "url-parse": "^1.5.3"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/tr46": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
+      "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "punycode": "^2.3.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/tsscmp": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
+      "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.6.x"
+      }
+    },
+    "node_modules/type-detect": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/type-fest": {
+      "version": "4.41.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+      "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+      "dev": true,
+      "license": "(MIT OR CC0-1.0)",
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/type-is": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz",
+      "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "content-type": "^2.0.0",
+        "media-typer": "^1.1.0",
+        "mime-types": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
+      "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/uglify-js": {
+      "version": "3.19.3",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
+      "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "optional": true,
+      "bin": {
+        "uglifyjs": "bin/uglifyjs"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/uid-safe": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
+      "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "random-bytes": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+      "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/url-parse": {
+      "version": "1.5.10",
+      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+      "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "querystringify": "^2.1.1",
+        "requires-port": "^1.0.0"
+      }
+    },
+    "node_modules/vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/vhost": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/vhost/-/vhost-3.0.2.tgz",
+      "integrity": "sha512-S3pJdWrpFWrKMboRU4dLYgMrTgoPALsmYwOvyebK2M6X95b9kQrjZy5rwl3uzzpfpENe/XrNYu/2U+e7/bmT5g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/vite": {
+      "version": "8.3.5",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.5.tgz",
+      "integrity": "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "lightningcss": "^1.33.0",
+        "picomatch": "^4.0.7",
+        "postcss": "^8.5.30",
+        "rolldown": "~1.2.14",
+        "tinyglobby": "^0.2.17"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^20.19.0 || >=22.12.0",
+        "@vitejs/devtools": "^0.7.1 || ^0.8.0",
+        "esbuild": "^0.27.0 || ^0.28.0",
+        "jiti": ">=1.21.0",
+        "less": "^4.0.0",
+        "sass": "^1.70.0",
+        "sass-embedded": "^1.70.0",
+        "stylus": ">=0.54.8",
+        "sugarss": "^5.0.0",
+        "terser": "^5.16.0",
+        "tsx": "^4.8.1",
+        "yaml": "^2.4.2"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "@vitejs/devtools": {
+          "optional": true
+        },
+        "esbuild": {
+          "optional": true
+        },
+        "jiti": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vitest": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.1.tgz",
+      "integrity": "sha512-iA95lQbKEkvrtTkdAgnWbXfbipWiiWe/hDl2P5tMi6WFwD76G0NxXAGp/M9EOcYupeGJRr6wppMc7CoA41TQjg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/chai": "^5.2.2",
+        "@vitest/mocker": "5.0.1",
+        "chai": "^6.2.2",
+        "es-module-lexer": "^2.3.2",
+        "expect-type": "^1.4.0",
+        "magic-string": "^1.2.3",
+        "obug": "^2.1.4",
+        "picomatch": "^4.0.7",
+        "std-env": "^4.2.0",
+        "tinybench": "6.1.4",
+        "tinyexec": "1.3.0",
+        "tinyglobby": "^0.2.17",
+        "why-is-node-running": "^2.3.0"
+      },
+      "bin": {
+        "vitest": "vitest.mjs"
+      },
+      "engines": {
+        "node": "^22.12.0 || ^24.0.0 || >=26.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "@edge-runtime/vm": "*",
+        "@opentelemetry/api": "^1.9.0",
+        "@types/node": "^22.0.0 || >=24.0.0",
+        "@vitest/browser-playwright": "5.0.1",
+        "@vitest/browser-preview": "5.0.1",
+        "@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0",
+        "@vitest/coverage-istanbul": "5.0.1",
+        "@vitest/coverage-v8": "5.0.1",
+        "@vitest/ui": "5.0.1",
+        "happy-dom": "*",
+        "jsdom": "*",
+        "vite": "^6.4.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@edge-runtime/vm": {
+          "optional": true
+        },
+        "@opentelemetry/api": {
+          "optional": true
+        },
+        "@types/node": {
+          "optional": true
+        },
+        "@vitest/browser-playwright": {
+          "optional": true
+        },
+        "@vitest/browser-preview": {
+          "optional": true
+        },
+        "@vitest/browser-webdriverio": {
+          "optional": true
+        },
+        "@vitest/coverage-istanbul": {
+          "optional": true
+        },
+        "@vitest/coverage-v8": {
+          "optional": true
+        },
+        "@vitest/ui": {
+          "optional": true
+        },
+        "happy-dom": {
+          "optional": true
+        },
+        "jsdom": {
+          "optional": true
+        },
+        "vite": {
+          "optional": false
+        }
+      }
+    },
+    "node_modules/w3c-xmlserializer": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
+      "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "xml-name-validator": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/walk": {
+      "version": "2.3.15",
+      "resolved": "https://registry.npmjs.org/walk/-/walk-2.3.15.tgz",
+      "integrity": "sha512-4eRTBZljBfIISK1Vnt69Gvr2w/wc3U6Vtrw7qiN5iqYJPH7LElcYh/iU4XWhdCy2dZqv1ToMyYlybDylfG/5Vg==",
+      "dev": true,
+      "license": "(MIT OR Apache-2.0)",
+      "dependencies": {
+        "foreachasync": "^3.0.0"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+      "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/whatwg-encoding": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
+      "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
+      "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "iconv-lite": "0.6.3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/whatwg-encoding/node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/whatwg-mimetype": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
+      "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/whatwg-url": {
+      "version": "12.0.1",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
+      "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "^4.1.1",
+        "webidl-conversions": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/why-is-node-running": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+      "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "siginfo": "^2.0.0",
+        "stackback": "0.0.2"
+      },
+      "bin": {
+        "why-is-node-running": "cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/workerpool": {
+      "version": "9.3.4",
+      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz",
+      "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==",
+      "dev": true,
+      "license": "Apache-2.0"
+    },
+    "node_modules/wrap-ansi": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.1.0",
+        "string-width": "^5.0.1",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs": {
+      "name": "wrap-ansi",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+      "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/ws": {
+      "version": "8.21.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
+      "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/xml-name-validator": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
+      "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/xmlchars": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+      "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs": {
+      "version": "17.7.3",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz",
+      "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-unparser": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+      "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "camelcase": "^6.0.0",
+        "decamelize": "^4.0.0",
+        "flat": "^5.0.2",
+        "is-plain-obj": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/yargs/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/yoctocolors-cjs": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz",
+      "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/zod": {
+      "version": "3.23.8",
+      "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
+      "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/colinhacks"
+      }
+    }
+  }
+}
diff --git a/tests/Frameworks/package.json b/tests/Frameworks/package.json
new file mode 100644
index 00000000..20db4355
--- /dev/null
+++ b/tests/Frameworks/package.json
@@ -0,0 +1,41 @@
+{
+  "name": "phasis-framework-oracles",
+  "private": true,
+  "version": "0.0.0",
+  "description": "Pinned real-framework packages and upstream test dependencies for Phasis compatibility validation.",
+  "engines": {
+    "node": ">=26"
+  },
+  "scripts": {
+    "test:express:node": "node express/run-node.cjs"
+  },
+  "devDependencies": {
+    "@hono/node-server": "2.0.12",
+    "@sinonjs/fake-timers": "15.4.0",
+    "@vitest/expect": "5.0.1",
+    "@vitest/spy": "5.0.1",
+    "after": "0.8.2",
+    "connect-redis": "8.1.0",
+    "cookie-parser": "1.4.7",
+    "cookie-session": "2.1.1",
+    "ejs": "3.1.10",
+    "esbuild": "0.28.2",
+    "express": "5.3.0",
+    "express-session": "1.19.0",
+    "hbs": "4.3.1",
+    "hono": "4.13.13",
+    "jsdom": "22.1.0",
+    "marked": "15.0.12",
+    "method-override": "3.0.0",
+    "mocha": "11.8.0",
+    "morgan": "1.12.1",
+    "msw": "2.6.0",
+    "pbkdf2-password": "1.2.1",
+    "supertest": "6.3.4",
+    "typescript": "6.0.3",
+    "vhost": "3.0.2",
+    "vitest": "5.0.1",
+    "ws": "8.21.0",
+    "zod": "3.23.8"
+  }
+}
diff --git a/tests/Unit/BuiltIn/AsyncContextTest.php b/tests/Unit/BuiltIn/AsyncContextTest.php
index 45cfa035..2b9be3a1 100644
--- a/tests/Unit/BuiltIn/AsyncContextTest.php
+++ b/tests/Unit/BuiltIn/AsyncContextTest.php
@@ -76,6 +76,28 @@ public function testContextPropagatesAcrossPromiseThen(): void
         $this->assertSame('A', $engine->eval('globalThis.__seen'));
     }
 
+    public function testPendingPromiseReactionsRetainRegistrationContext(): void
+    {
+        $engine = new Engine();
+        $engine->eval(<<<'JS'
+const context = new AsyncContext.Variable({ defaultValue: 'outside' });
+const seen = [];
+let resolve, reject;
+const fulfilled = new Promise(done => { resolve = done; });
+const rejected = new Promise((_, fail) => { reject = fail; });
+context.run('first', () => fulfilled.then(() => seen.push('then:' + context.get())));
+context.run('second', () => rejected.catch(() => seen.push('catch:' + context.get())));
+context.run('await', async () => { await fulfilled; seen.push('await:' + context.get()); });
+fulfilled.then(() => seen.push('outside:' + context.get()));
+context.run('settlement', () => { resolve(); reject(); });
+JS);
+        self::assertSame(
+            ['then:first', 'await:await', 'outside:outside', 'catch:second'],
+            $engine->eval('seen'),
+        );
+        self::assertSame('outside', $engine->eval('context.get()'));
+    }
+
     public function testContextPropagatesAcrossQueueMicrotask(): void
     {
         $engine = new Engine();
diff --git a/tests/Unit/BuiltIn/Ed25519CryptoTest.php b/tests/Unit/BuiltIn/Ed25519CryptoTest.php
new file mode 100644
index 00000000..0444d3f7
--- /dev/null
+++ b/tests/Unit/BuiltIn/Ed25519CryptoTest.php
@@ -0,0 +1,77 @@
+eval(<<<'JS'
+var keyShape;
+crypto.subtle.importKey('raw', new Uint8Array([1, 2]), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']).then(key => {
+  keyShape = [key instanceof CryptoKey, Object.getPrototypeOf(key) === CryptoKey.prototype, Object.prototype.toString.call(key)];
+});
+var illegal;
+try { new CryptoKey(); } catch (error) { illegal = error instanceof TypeError; }
+JS);
+        self::assertSame('[true,true,"[object CryptoKey]"]', $engine->eval('JSON.stringify(keyShape)'));
+        self::assertTrue($engine->eval('illegal'));
+    }
+
+    public function testEd25519MatchesRfc8032AndRoundTripsEveryKeyFormat(): void
+    {
+        $engine = new Engine();
+        $engine->eval(<<<'JS'
+var edResult, edFailure;
+const fromHex = text => Uint8Array.from(text.match(/../g), byte => parseInt(byte, 16));
+const hex = value => Array.from(new Uint8Array(value), byte => byte.toString(16).padStart(2, '0')).join('');
+(async () => {
+  const seed = '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60';
+  const publicHex = 'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a';
+  const key = await crypto.subtle.importKey('pkcs8', fromHex('302e020100300506032b657004220420' + seed), 'Ed25519', true, ['sign']);
+  const publicKey = await crypto.subtle.importKey('raw', fromHex(publicHex), 'Ed25519', true, ['verify']);
+  const signature = await crypto.subtle.sign('Ed25519', key, new Uint8Array());
+  const jwk = await crypto.subtle.exportKey('jwk', key);
+  const importedJwk = await crypto.subtle.importKey('jwk', jwk, 'Ed25519', true, ['sign']);
+  const spki = await crypto.subtle.exportKey('spki', publicKey);
+  const importedSpki = await crypto.subtle.importKey('spki', spki, 'Ed25519', true, ['verify']);
+  const pair = await crypto.subtle.generateKey('Ed25519', false, ['sign', 'verify']);
+  const generatedSignature = await crypto.subtle.sign('Ed25519', pair.privateKey, fromHex('1234'));
+  edResult = {
+    signature: hex(signature),
+    public: hex(await crypto.subtle.exportKey('raw', importedSpki)),
+    seed: hex(await crypto.subtle.exportKey('pkcs8', importedJwk)).slice(-64),
+    verify: await crypto.subtle.verify('Ed25519', publicKey, signature, new Uint8Array()),
+    tamper: await crypto.subtle.verify('Ed25519', publicKey, signature, new Uint8Array([1])),
+    short: await crypto.subtle.verify('Ed25519', publicKey, new Uint8Array([1]), new Uint8Array()),
+    generated: await crypto.subtle.verify('Ed25519', pair.publicKey, generatedSignature, fromHex('1234')),
+    properties: [key.type, key.algorithm.name, key instanceof CryptoKey, pair.publicKey.extractable, pair.privateKey.extractable],
+  };
+})().catch(error => { edFailure = error.name + ': ' + error.message; });
+JS);
+        if (!extension_loaded('sodium')) {
+            self::assertSame('NotSupportedError: Ed25519 requires the PHP sodium extension.', $engine->eval('edFailure'));
+            return;
+        }
+        self::assertSame('undefined', $engine->eval('typeof edFailure'));
+        $actual = json_decode((string) $engine->eval('JSON.stringify(edResult)'), true, 512, JSON_THROW_ON_ERROR);
+        self::assertSame(
+            'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555'
+            . 'fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b',
+            $actual['signature'],
+        );
+        self::assertSame('d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a', $actual['public']);
+        self::assertSame('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60', $actual['seed']);
+        self::assertTrue($actual['verify']);
+        self::assertFalse($actual['tamper']);
+        self::assertFalse($actual['short']);
+        self::assertTrue($actual['generated']);
+        self::assertSame(['private', 'Ed25519', true, true, false], $actual['properties']);
+    }
+}
diff --git a/tests/Unit/BuiltIn/FunctionProxyCallTest.php b/tests/Unit/BuiltIn/FunctionProxyCallTest.php
new file mode 100644
index 00000000..1ef1cd86
--- /dev/null
+++ b/tests/Unit/BuiltIn/FunctionProxyCallTest.php
@@ -0,0 +1,47 @@
+eval(<<<'JS'
+const receiver = { name: 'receiver' };
+const callable = new Proxy(function () {}, {
+    apply(target, value, args) { return value.name + ':' + args.join(','); }
+});
+[
+    callable.call(receiver, 'call'),
+    callable.apply(receiver, ['dense']),
+    callable.apply(receiver, { 0: 'sparse', length: 1 }),
+    callable.apply(receiver, []),
+    callable.apply(receiver, null),
+];
+JS),
+        );
+    }
+
+    public function testRevokedCallableProxyThrowsAfterApplyReadsItsArguments(): void
+    {
+        $engine = new Engine();
+        self::assertSame(['length', 'TypeError', 'TypeError'], $engine->eval(<<<'JS'
+const {proxy, revoke} = Proxy.revocable(function () {}, {});
+const log = [];
+revoke();
+try {
+    Function.prototype.apply.call(proxy, null, {get length() { log.push('length'); return 0; }});
+} catch (error) { log.push(error.name); }
+try { Function.prototype.call.call(proxy, null); } catch (error) { log.push(error.name); }
+log;
+JS));
+    }
+}
diff --git a/tests/Unit/BuiltIn/JsonPropertyNamesTest.php b/tests/Unit/BuiltIn/JsonPropertyNamesTest.php
new file mode 100644
index 00000000..96b63820
--- /dev/null
+++ b/tests/Unit/BuiltIn/JsonPropertyNamesTest.php
@@ -0,0 +1,49 @@
+eval(<<<'JS'
+const separatorData = { ['\u2028/\u2029']: '\u2028 \u2029 woot' };
+const separatorCompact = JSON.stringify(separatorData);
+const separatorCached = JSON.stringify(separatorData);
+const separatorReplacer = JSON.stringify(separatorData, (key, value) => value);
+const surrogateKey = JSON.stringify({ ['\ud800']: 1 }, (key, value) => value);
+JS);
+        $expected = '{"' . "\u{2028}/\u{2029}" . '":"' . "\u{2028} \u{2029} woot" . '"}';
+        self::assertSame($expected, $engine->eval('separatorCompact'));
+        self::assertSame($expected, $engine->eval('separatorCached'));
+        self::assertSame($expected, $engine->eval('separatorReplacer'));
+        self::assertSame('{"\\ud800":1}', $engine->eval('surrogateKey'));
+    }
+
+    public function testStringifyPreservesUserPropertyPrefixesAndIntegerOrder(): void
+    {
+        $engine = new Engine();
+        $engine->eval(<<<'JS'
+const data = JSON.parse('{"__proto__":"data","__private":1,"[prefix]":2,"[":3,"10":"ten","2":"two"}');
+const compact = JSON.stringify(data);
+const viaReplacer = JSON.stringify(data, (key, value) => value);
+data.__private = 4;
+const changed = JSON.stringify(data);
+JS);
+        self::assertSame(
+            '{"2":"two","10":"ten","__proto__":"data","__private":1,"[prefix]":2,"[":3}',
+            $engine->eval('compact'),
+        );
+        self::assertSame($engine->eval('compact'), $engine->eval('viaReplacer'));
+        self::assertSame(
+            '{"2":"two","10":"ten","__proto__":"data","__private":4,"[prefix]":2,"[":3}',
+            $engine->eval('changed'),
+        );
+    }
+}
diff --git a/tests/Unit/BuiltIn/LiveFetchBodyTest.php b/tests/Unit/BuiltIn/LiveFetchBodyTest.php
new file mode 100644
index 00000000..9779ccb1
--- /dev/null
+++ b/tests/Unit/BuiltIn/LiveFetchBodyTest.php
@@ -0,0 +1,89 @@
+eval(<<<'JS'
+var result;
+const transform = new TransformStream();
+const response = new Response(transform.readable);
+const writer = transform.writable.getWriter();
+const identity = response.body === transform.readable;
+const text = response.text();
+(async () => {
+    await writer.write(new TextEncoder().encode('hello'));
+    await Promise.resolve();
+    await writer.write(new TextEncoder().encode(' world'));
+    await writer.close();
+})();
+text.then(value => { result = [identity, value, response.bodyUsed, response.body.locked]; });
+JS);
+        self::assertSame([true, 'hello world', true, true], $engine->eval('result'));
+    }
+
+    public function testResponseClonesTeeFutureChunksWithIndependentByteArrays(): void
+    {
+        $engine = new Engine();
+        $engine->eval(<<<'JS'
+var result;
+let controller;
+const chunk = new Uint8Array([65]);
+const response = new Response(new ReadableStream({start(value) {controller = value;}}));
+const clone = response.clone();
+Promise.all([response.body.getReader().read(), clone.body.getReader().read()]).then(([a, b]) => {
+    a.value[0] = 66;
+    result = [a.value === chunk, b.value === chunk, a.value[0], b.value[0]];
+});
+queueMicrotask(() => {controller.enqueue(chunk); controller.close();});
+JS);
+        self::assertSame([true, false, 66, 65], $engine->eval('result'));
+    }
+
+    public function testStreamFailuresRejectConsumersWithTheOriginalReason(): void
+    {
+        $engine = new Engine();
+        $engine->eval(<<<'JS'
+var result;
+const reason = new Error('producer failed');
+const errorResponse = new Response(new ReadableStream({start(controller) {
+    queueMicrotask(() => controller.error(reason));
+}}));
+const invalidResponse = new Response(new ReadableStream({start(controller) {
+    controller.enqueue('not bytes'); controller.close();
+}}));
+Promise.all([
+    errorResponse.text().catch(error => error === reason),
+    invalidResponse.arrayBuffer().catch(error => error.name),
+]).then(value => { result = value; });
+JS);
+        self::assertSame([true, 'TypeError'], $engine->eval('result'));
+    }
+
+    public function testRequestConstructionTransfersALiveBodyAndCloneKeepsBothBranches(): void
+    {
+        $engine = new Engine();
+        $engine->eval(<<<'JS'
+var result;
+let controller;
+const source = new Request('https://example.com', {
+    method: 'POST', body: new ReadableStream({start(value) {controller = value;}}), duplex: 'half'
+});
+const request = new Request(source);
+const clone = request.clone();
+Promise.all([request.text(), clone.text()]).then(values => {
+    result = [source.bodyUsed, source.body.locked, ...values];
+});
+queueMicrotask(() => {controller.enqueue(new TextEncoder().encode('payload')); controller.close();});
+JS);
+        self::assertSame([true, true, 'payload', 'payload'], $engine->eval('result'));
+    }
+}
diff --git a/tests/Unit/BuiltIn/MessageEventTest.php b/tests/Unit/BuiltIn/MessageEventTest.php
new file mode 100644
index 00000000..f74d3e87
--- /dev/null
+++ b/tests/Unit/BuiltIn/MessageEventTest.php
@@ -0,0 +1,41 @@
+eval(<<<'JS'
+const data = {name: 'x'};
+const event = new MessageEvent('message', {data, origin: 'origin', lastEventId: 123});
+const target = new EventTarget();
+let observed;
+target.addEventListener('message', value => {observed = value;});
+target.dispatchEvent(event);
+[
+    event instanceof Event, event instanceof MessageEvent, event.data.name,
+    event.origin, event.lastEventId, event.source, Object.isFrozen(event.ports), observed === event
+];
+JS));
+    }
+
+    public function testDefaultsAndIncompatibleReceiverChecks(): void
+    {
+        $engine = new Engine();
+        self::assertSame([null, '', '', 0, false, 'TypeError', 'TypeError'], $engine->eval(<<<'JS'
+const event = new MessageEvent('message');
+const values = [event.data, event.origin, event.lastEventId, event.ports.length, event.isTrusted];
+try { Object.getOwnPropertyDescriptor(MessageEvent.prototype, 'data').get.call(new Event('x')); }
+catch (error) { values.push(error.name); }
+try { new MessageEvent('message', {source: {}}); } catch (error) { values.push(error.name); }
+values;
+JS));
+    }
+}
diff --git a/tests/Unit/BuiltIn/ReadableStreamSchedulingTest.php b/tests/Unit/BuiltIn/ReadableStreamSchedulingTest.php
new file mode 100644
index 00000000..2e10d0a3
--- /dev/null
+++ b/tests/Unit/BuiltIn/ReadableStreamSchedulingTest.php
@@ -0,0 +1,86 @@
+eval(<<<'JS'
+const observations = [];
+(async () => {
+    for (const type of ['default', 'bytes']) {
+        const log = [];
+        let count = 0;
+        const scratch = new Uint8Array(4);
+        const stream = new ReadableStream({
+            ...type === 'bytes' ? { type: 'bytes' } : {},
+            pull(controller) {
+                const value = ++count;
+                log.push('pull:' + value);
+                const data = type === 'bytes' ? new Uint8Array(4) : scratch;
+                data.fill(value);
+                controller.enqueue(data);
+                if (count === 2) controller.close();
+            },
+        });
+        log.push('constructed');
+        const reader = stream.getReader();
+        const reading = (async () => {
+            while (true) {
+                const { done, value } = await reader.read();
+                if (done) {
+                    log.push('done');
+                    break;
+                }
+                log.push('read:' + value[0]);
+            }
+        })();
+        queueMicrotask(() => log.push('checkpoint'));
+        await reading;
+        observations.push(log);
+    }
+})();
+JS);
+        $expected = ['constructed', 'pull:1', 'checkpoint', 'read:1', 'pull:2', 'read:2', 'done'];
+        self::assertSame([$expected, $expected], $engine->eval('observations'));
+    }
+
+    public function testStartSettlesInOneMicrotaskForBothPromiseStates(): void
+    {
+        $engine = new Engine();
+        $engine->eval(<<<'JS'
+const startObservations = [];
+(async () => {
+    for (const pending of [false, true]) {
+        const log = [];
+        const stream = new ReadableStream({
+            start() {
+                log.push('start');
+                return pending ? Promise.resolve().then(() => log.push('start resolved')) : undefined;
+            },
+            pull(controller) {
+                log.push('pull');
+                controller.close();
+            },
+        });
+        log.push('constructed');
+        queueMicrotask(() => log.push('checkpoint'));
+        await stream.getReader().read();
+        log.push('read');
+        startObservations.push(log);
+    }
+})();
+JS);
+        self::assertSame([
+            ['start', 'constructed', 'pull', 'checkpoint', 'read'],
+            ['start', 'constructed', 'start resolved', 'checkpoint', 'pull', 'read'],
+        ], $engine->eval('startObservations'));
+    }
+}
diff --git a/tests/Unit/BuiltIn/RequestTest.php b/tests/Unit/BuiltIn/RequestTest.php
index 6183b5da..36216c52 100644
--- a/tests/Unit/BuiltIn/RequestTest.php
+++ b/tests/Unit/BuiltIn/RequestTest.php
@@ -36,6 +36,21 @@ public function testInvalidUrlThrows(): void
         $this->assertSame('TypeError', $result);
     }
 
+    public function testReferrerIsParsedAndSerializedAsAUrl(): void
+    {
+        $engine = new Engine();
+        self::assertSame(
+            ['https://example.com/', 'about:client', '', 'TypeError', 'TypeError'],
+            $engine->eval(<<<'JS'
+const values = ['HTTPS://EXAMPLE.COM:443', 'about:client', '', 'not a url', 'no-referrer'];
+values.map(referrer => {
+    try { return new Request('https://target.test/', {referrer}).clone().referrer; }
+    catch (error) { return error.name; }
+});
+JS),
+        );
+    }
+
     public function testConstructorFromAnotherRequestCopiesHeaders(): void
     {
         $engine = new Engine();
@@ -347,7 +362,7 @@ public function testInitOptions(): void
   credentials: "include",
   cache: "no-store",
   redirect: "manual",
-  referrer: "no-referrer",
+  referrer: "",
   referrerPolicy: "no-referrer",
   integrity: "sha256-abc",
   keepalive: true,
@@ -356,7 +371,7 @@ public function testInitOptions(): void
 [req.mode, req.credentials, req.cache, req.redirect, req.referrer, req.referrerPolicy, req.integrity, req.keepalive, req.priority];
 JS);
         $this->assertSame(
-            ['cors', 'include', 'no-store', 'manual', 'no-referrer', 'no-referrer', 'sha256-abc', true, 'high'],
+            ['cors', 'include', 'no-store', 'manual', '', 'no-referrer', 'sha256-abc', true, 'high'],
             $result,
         );
     }
diff --git a/tests/Unit/BuiltIn/StringCodeUnitTest.php b/tests/Unit/BuiltIn/StringCodeUnitTest.php
new file mode 100644
index 00000000..4fa9c1af
--- /dev/null
+++ b/tests/Unit/BuiltIn/StringCodeUnitTest.php
@@ -0,0 +1,83 @@
+eval(<<<'JS'
+function units(value) {
+    const result = [];
+    for (let i = 0; i < value.length; i++) result.push(value.charCodeAt(i));
+    return result;
+}
+function split(value, separator) { return value.split(separator).map(units); }
+for (let i = 0; i < 10; i++) split('warm/up', '/');
+[
+    '😀'.split('').map(value => value.charCodeAt(0)),
+    '\udfff'.split('').map(value => value.charCodeAt(0)),
+    '😀'.split('', 1).map(value => value.charCodeAt(0)),
+    split('😀', '\ud83d'),
+    split('😀', '\ude00'),
+    split('\ud83d' + '\ude00', '😀'),
+    split('\ud800\u6100\u0062', '\u6261'),
+];
+JS));
+    }
+
+    public function testNativeUtf8ConversionKeepsUtf16LengthsAndNullBytes(): void
+    {
+        $engine = new Engine();
+        self::assertSame([
+            [3, 65, 0, 122],
+            [2, 0x00E4, 0x20AC],
+            [2, 0xD83D, 0xDE00],
+            [3, 0x6587, 0xD83D, 0xDE00],
+        ], $engine->eval(<<<'JS'
+['A\0z', 'ä€', '😀', '文😀'].map(value => {
+    const units = [value.length];
+    for (let i = 0; i < value.length; i++) units.push(value.charCodeAt(i));
+    return units;
+});
+JS));
+    }
+
+    public function testCachedCodeUnitsPreserveSurrogatesAndCoercionOrder(): void
+    {
+        $engine = new Engine();
+        $engine->eval(<<<'JS'
+const value = 'a\ud83d\ude00\ud800z';
+const observations = [];
+for (let i = 0; i < 3; i++) {
+  observations.push([value.length, value.charCodeAt(1), value.charCodeAt(2), value.charCodeAt(3),
+    value.slice(1, 3), value.substring(1, 3), value.at(-1), value.codePointAt(1)]);
+}
+const order = [];
+const receiver = {toString() { order.push('receiver'); return 'xyz'; }};
+const index = {valueOf() { order.push('index'); return 1; }};
+const coerced = String.prototype.charCodeAt.call(receiver, index);
+const bounds = [value.charCodeAt(NaN), Number.isNaN(value.charCodeAt(Infinity)), Number.isNaN(value.charCodeAt(-Infinity)),
+  value.charAt(NaN), value.charAt(Infinity), value.charAt(-Infinity)];
+JS);
+        $expected = [5, 0xD83D, 0xDE00, 0xD800, '😀', '😀', 'z', 0x1F600];
+        self::assertSame([$expected, $expected, $expected], $engine->eval('observations'));
+        self::assertSame(['receiver', 'index'], $engine->eval('order'));
+        self::assertSame(121, $engine->eval('coerced'));
+        self::assertSame([97, true, true, 'a', '', ''], $engine->eval('bounds'));
+    }
+}
diff --git a/tests/Unit/BuiltIn/StructuredCloneTest.php b/tests/Unit/BuiltIn/StructuredCloneTest.php
index 135c88e8..0ae5861b 100644
--- a/tests/Unit/BuiltIn/StructuredCloneTest.php
+++ b/tests/Unit/BuiltIn/StructuredCloneTest.php
@@ -13,14 +13,6 @@
  * Covers the HTML §2.7 StructuredClone algorithm:
  *   https://html.spec.whatwg.org/multipage/structured-data.html#structured-cloning
  *
- * NOTE on DataCloneError: this worktree does not yet wire up
- * DOMException as a global (Subagent A is implementing that
- * concurrently). The implementation under test probes for the
- * DOMException constructor at runtime and falls back to a JS
- * Error-shaped object with `name === 'DataCloneError'`. The tests
- * below assert on `e.name === 'DataCloneError'` so they remain
- * green both before and after DOMException lands; the reviewer
- * can later add `e instanceof DOMException` once it exists.
  */
 class StructuredCloneTest extends TestCase
 {
diff --git a/tests/Unit/BuiltIn/TextDecoderTest.php b/tests/Unit/BuiltIn/TextDecoderTest.php
index ebbb08c0..ce9b1975 100644
--- a/tests/Unit/BuiltIn/TextDecoderTest.php
+++ b/tests/Unit/BuiltIn/TextDecoderTest.php
@@ -9,6 +9,18 @@
 
 class TextDecoderTest extends TestCase
 {
+    public function testMalformedUtf8ConsumesTheValidPrefixAndReprocessesTheBadByte(): void
+    {
+        $engine = new Engine();
+        self::assertSame("\u{FFFD}%A", $engine->eval('new TextDecoder().decode(new Uint8Array([0xe0, 0xa4, 0x25, 0x41]))'));
+        self::assertSame("\u{FFFD}A", $engine->eval('new TextDecoder().decode(new Uint8Array([0xf0, 0x90, 0x41]))'));
+        self::assertSame("\u{FFFD}\u{FFFD}", $engine->eval('new TextDecoder().decode(new Uint8Array([0xe0, 0x80]))'));
+        self::assertSame("\u{FFFD}A", $engine->eval(<<<'JS'
+const prefixDecoder = new TextDecoder();
+prefixDecoder.decode(new Uint8Array([0xf0, 0x90]), { stream: true }) + prefixDecoder.decode(new Uint8Array([0x41]));
+JS));
+    }
+
     public function testDefaultsToUtf8(): void
     {
         $engine = new Engine();
diff --git a/tests/Unit/Bytecode/ArraySpreadTest.php b/tests/Unit/Bytecode/ArraySpreadTest.php
new file mode 100644
index 00000000..3e1606e6
--- /dev/null
+++ b/tests/Unit/Bytecode/ArraySpreadTest.php
@@ -0,0 +1,49 @@
+eval(<<<'JS'
+const events = [];
+const iterable = { [Symbol.iterator]() {
+    let index = 0;
+    return { next() { events.push('next'); return index++ ? {done: true} : {value: 9, done: false}; } };
+} };
+function array(source) { return [0, , ...'a😀', ...source, , 4]; }
+const first = array(iterable), second = array(iterable);
+[first, second, Object.hasOwn(first, 1), Object.hasOwn(first, 4), Object.hasOwn(first, 5), events.join(',')];
+JS));
+        $function = $engine->getGlobalEnv()->get('array');
+        self::assertInstanceOf(JsFunction::class, $function);
+        self::assertNotNull($function->compiled);
+    }
+
+    public function testArrayLiteralBypassesInheritedIndexSettersAndHonorsCustomIterators(): void
+    {
+        $engine = new Engine();
+        self::assertSame([['custom', 2], ['custom', 2], 0], $engine->eval(<<<'JS'
+const source = [1];
+source[Symbol.iterator] = function* () { yield 'custom'; };
+let setters = 0;
+Object.defineProperty(Array.prototype, '0', {set() { setters++; }, configurable: true});
+function array(input) { return [...input, 2]; }
+const first = array(source), second = array(source);
+delete Array.prototype[0];
+[first, second, setters];
+JS));
+        $function = $engine->getGlobalEnv()->get('array');
+        self::assertInstanceOf(JsFunction::class, $function);
+        self::assertNotNull($function->compiled);
+    }
+}
diff --git a/tests/Unit/Bytecode/CapturedBindingTest.php b/tests/Unit/Bytecode/CapturedBindingTest.php
new file mode 100644
index 00000000..d8cd964c
--- /dev/null
+++ b/tests/Unit/Bytecode/CapturedBindingTest.php
@@ -0,0 +1,140 @@
+eval(<<<'JS'
+function make(start) {
+    let current = start;
+    const offset = 3;
+    var calls = 0;
+    function read() { return current + offset; }
+    function add(value) { current += value; }
+    function record() { calls++; return calls + current; }
+    add(2);
+    current++;
+    return [read, add, record];
+}
+const first = make(7);
+const second = make(20);
+const result = [first[0]()];
+first[1](5);
+result.push(first[0](), second[2](), second[0]());
+first[1](5);
+result.push(first[0]());
+second[1](5);
+result.push(second[0]());
+result;
+JS));
+        $this->assertCompiled($engine, 'make');
+    }
+
+    public function testCapturedLexicalsKeepTheirDeadZonesAndImmutability(): void
+    {
+        $engine = new Engine();
+        self::assertSame([['ReferenceError', 4, null, 'TypeError'], ['ReferenceError', 4, null, 'TypeError']], $engine->eval(<<<'JS'
+function lexical() {
+    function read() { return value; }
+    function write() { constant = 9; }
+    function uninitialized() { return empty; }
+    var before;
+    try { read(); } catch (error) { before = error.name; }
+    let value = 4;
+    let empty;
+    const constant = 7;
+    var assignment;
+    try { write(); } catch (other) { assignment = other.name; }
+    return [before, read(), uninitialized(), assignment];
+}
+[lexical(), lexical()];
+JS));
+        $this->assertCompiled($engine, 'lexical');
+    }
+
+    public function testNestedArrowParametersAndDefaultBodyScopesRemainIndependent(): void
+    {
+        $engine = new Engine();
+        self::assertSame([4, 8, 3, 6, 10, 11], $engine->eval(<<<'JS'
+const arrow = (value) => () => value;
+function defaults(value = 2) {
+    function read() { return value; }
+    value++;
+    return read;
+}
+function redeclared(value = 8) {
+    var value;
+    function read() { return value; }
+    value += 2;
+    return read;
+}
+const first = arrow(4);
+const second = arrow(8);
+[first(), second(), defaults()(), defaults(5)(), redeclared()(), redeclared(9)()];
+JS));
+        $this->assertCompiled($engine, 'arrow');
+        $this->assertCompiled($engine, 'defaults');
+        $this->assertCompiled($engine, 'redeclared');
+    }
+
+    public function testPerIterationAndCatchCapturesKeepInterpreterScopes(): void
+    {
+        $engine = new Engine();
+        self::assertSame([[0, 1, 2], [0, 1, 2]], $engine->eval(<<<'JS'
+function iterations() {
+    var result = [];
+    for (let i = 0; i < 3; i++) result.push(() => i);
+    return result;
+}
+function catches() {
+    var result = [];
+    for (var i = 0; i < 3; i++) {
+        try { throw i; } catch (error) { result.push(() => error); }
+    }
+    return result;
+}
+[iterations().map(fn => fn()), catches().map(fn => fn())];
+JS));
+        foreach (['iterations', 'catches'] as $name) {
+            $function = $engine->getGlobalEnv()->get($name);
+            self::assertInstanceOf(JsFunction::class, $function);
+            self::assertNull($function->compiled);
+        }
+    }
+
+    public function testCapturedLoopCounterReadsMutationsMadeByCallbacks(): void
+    {
+        $engine = new Engine();
+        self::assertSame([2, 2], $engine->eval(<<<'JS'
+function loop() {
+    var counter = 0;
+    var limit = 8;
+    function advance() { counter += 2; limit = 5; }
+    var visits = 0;
+    for (counter = 0; counter < limit; counter++) {
+        advance();
+        visits++;
+    }
+    return visits;
+}
+[loop(), loop()];
+JS));
+        $this->assertCompiled($engine, 'loop');
+    }
+
+    private function assertCompiled(Engine $engine, string $name): void
+    {
+        $function = $engine->getGlobalEnv()->get($name);
+        self::assertInstanceOf(JsFunction::class, $function);
+        self::assertNotNull($function->compiled, "{$name} must exercise captured bytecode bindings.");
+    }
+}
diff --git a/tests/Unit/Bytecode/CompilationFailuresTest.php b/tests/Unit/Bytecode/CompilationFailuresTest.php
new file mode 100644
index 00000000..de125585
--- /dev/null
+++ b/tests/Unit/Bytecode/CompilationFailuresTest.php
@@ -0,0 +1,94 @@
+eval(<<<'JS'
+function helper(value) { return value + 1; }
+function template(value) { try { return helper(value); } catch (error) { return 0; } }
+JS);
+        $template = $engine->getGlobalEnv()->get('template');
+        self::assertInstanceOf(JsFunction::class, $template);
+        $strict = new JsFunction('strict', $template->getParams(), $template->getBody(), $template->getClosure(), strict: true);
+        self::assertNull(JsToPhp::compile($strict));
+        try {
+            (new Compiler())->compile($strict);
+            self::fail('Strict tail calls require the interpreter trampoline.');
+        } catch (CompilerBailout $error) {
+            self::assertStringContainsString('tail', $error->getMessage());
+        }
+        $sloppy = new JsFunction('sloppy', $template->getParams(), $template->getBody(), $template->getClosure());
+        self::assertInstanceOf(CompiledFunction::class, (new Compiler())->compile($sloppy));
+        $engine->setGlobalJsValue('strict', $strict);
+        $engine->setGlobalJsValue('sloppy', $sloppy);
+        self::assertSame('3:5', $engine->eval('[strict(2), sloppy(4)].join(":")'));
+    }
+
+    public function testMethodBailoutDoesNotDisableOrdinaryNumericCompilation(): void
+    {
+        $engine = new Engine();
+        $engine->eval('function numeric(value) { return value + 1; }');
+        $template = $engine->getGlobalEnv()->get('numeric');
+        self::assertInstanceOf(JsFunction::class, $template);
+        $method = new JsFunction('method', $template->getParams(), $template->getBody(), $template->getClosure());
+        $method->setHomeObject(new \Phasis\Value\JsObject());
+        self::assertNull(JsToPhp::compile($method));
+        $ordinary = new JsFunction('ordinary', $template->getParams(), $template->getBody(), $template->getClosure());
+        self::assertInstanceOf(\Closure::class, JsToPhp::compile($ordinary));
+        $engine->setGlobalJsValue('ordinary', $ordinary);
+        self::assertSame(8, $engine->eval('ordinary(7)'));
+    }
+
+    public function testRepeatedUnsupportedClosuresKeepTheirOwnCapturedState(): void
+    {
+        $engine = new Engine();
+        self::assertSame('2:11:3:12', $engine->eval(<<<'JS'
+function create(initial) {
+  return function step(options = {}) {
+    const { amount = 1 } = options;
+    return initial += amount;
+  };
+}
+const first = create(1), second = create(10);
+[first(), second(), first(), second()].join(':');
+JS));
+    }
+
+    public function testCompilationFailureDoesNotRetainDiscardedSyntaxOrClosureEnvironment(): void
+    {
+        $engine = new Engine();
+        $program = (new Parser('function rejected(value) { eval(""); return helper(value); }'))->parse();
+        $declaration = $program->body[0];
+        self::assertInstanceOf(\Phasis\Ast\Declaration\FunctionDeclaration::class, $declaration);
+        $body = $declaration->body;
+        $function = new JsFunction('rejected', $declaration->params, $body, $engine->getGlobalEnv()->createChild(), strict: true);
+        $bodyReference = \WeakReference::create($body);
+        $closureReference = \WeakReference::create($function->getClosure());
+        self::assertNull(JsToPhp::compile($function));
+        try {
+            (new Compiler())->compile($function);
+            self::fail('Dynamic scope must remain a structural compilation bailout.');
+        } catch (CompilerBailout $error) {
+            self::assertSame('uses eval', $error->getMessage());
+        }
+        unset($error, $function, $body, $declaration, $program);
+        gc_collect_cycles();
+        self::assertNull($bodyReference->get());
+        self::assertNull($closureReference->get());
+    }
+}
diff --git a/tests/Unit/Bytecode/CompilationTemplatesTest.php b/tests/Unit/Bytecode/CompilationTemplatesTest.php
new file mode 100644
index 00000000..a77ead60
--- /dev/null
+++ b/tests/Unit/Bytecode/CompilationTemplatesTest.php
@@ -0,0 +1,54 @@
+eval(<<<'JS'
+function make(value) { return function read() { return value.amount; }; }
+const first = make({amount: 1}), second = make({amount: 9});
+first(); second();
+JS);
+        $first = $engine->getGlobalEnv()->get('first');
+        $second = $engine->getGlobalEnv()->get('second');
+        self::assertInstanceOf(JsFunction::class, $first);
+        self::assertInstanceOf(JsFunction::class, $second);
+        self::assertNotNull($first->compiled);
+        self::assertNotNull($second->compiled);
+        self::assertNotSame($first->compiled, $second->compiled);
+        self::assertSame($first->compiled->code, $second->compiled->code);
+        $first->compiled->loadNameIc[9876] = [JsNumber::of(30), 0];
+        self::assertArrayNotHasKey(9876, $second->compiled->loadNameIc);
+        self::assertSame([1, 9, 1, 9], $engine->eval('[first(), second(), first(), second()]'));
+    }
+
+    public function testTemplateDoesNotKeepDiscardedSyntaxOrEnvironmentsAlive(): void
+    {
+        $engine = new Engine();
+        $program = (new Parser('function factory(value) { function read() { return value; } return read; }'))->parse();
+        $declaration = $program->body[0];
+        self::assertInstanceOf(\Phasis\Ast\Declaration\FunctionDeclaration::class, $declaration);
+        $body = $declaration->body;
+        $function = new JsFunction('factory', $declaration->params, $body, $engine->getGlobalEnv()->createChild());
+        $bodyReference = \WeakReference::create($body);
+        $closureReference = \WeakReference::create($function->getClosure());
+        $compiled = (new Compiler())->compile($function);
+        self::assertNotEmpty($compiled->nestedFns);
+        unset($compiled, $function, $body, $declaration, $program);
+        gc_collect_cycles();
+        self::assertNull($bodyReference->get());
+        self::assertNull($closureReference->get());
+    }
+}
diff --git a/tests/Unit/Bytecode/DefaultBindingTest.php b/tests/Unit/Bytecode/DefaultBindingTest.php
new file mode 100644
index 00000000..1f94854b
--- /dev/null
+++ b/tests/Unit/Bytecode/DefaultBindingTest.php
@@ -0,0 +1,71 @@
+eval(<<<'JS'
+let defaults = 0;
+function nextDefault() { defaults++; return defaults; }
+function options(value = {}) {
+  const { a = nextDefault(), b = a + 2 } = value;
+  return [a, b, defaults];
+}
+[options(), options({a: null}), options({a: 4}), options({a: undefined})];
+JS));
+        $function = $engine->getGlobalEnv()->get('options');
+        self::assertInstanceOf(JsFunction::class, $function);
+        self::assertNotNull($function->compiled, 'This regression must exercise the bytecode path.');
+    }
+
+    public function testParameterClosuresObserveAssignmentButNotBodyVarRedeclaration(): void
+    {
+        $engine = new Engine();
+        self::assertSame([2, 1, 2, 1, 3], $engine->eval(<<<'JS'
+function shared(a = 1, read = () => a) { a = 2; return read(); }
+function shadowed(a = 1, read = () => a) { var a = 2; return read(); }
+function* generator(a = 1, read = () => a) { a = 2; yield read(); }
+function* shadowedGenerator(a = 1, read = () => a) { var a = 2; yield read(); }
+function argumentBinding(read = () => arguments) { arguments = 3; return read(); }
+[shared(), shadowed(), generator().next().value, shadowedGenerator().next().value, argumentBinding()];
+JS));
+    }
+
+    public function testWarmDefaultsKeepThisArgumentsAndNewTargetBindings(): void
+    {
+        $engine = new Engine();
+        self::assertSame([4, 5, 8, 9, true, true], $engine->eval(<<<'JS'
+function receiver(value = this.value) { return value; }
+function argument(value = arguments[1]) { return value; }
+function constructor(value = new.target) { return { value }; }
+[receiver.call({value: 4}), receiver.call({value: 5}), argument(undefined, 8), argument(undefined, 9),
+ new constructor().value === constructor, new constructor().value === constructor];
+JS));
+    }
+
+    public function testDefaultTemporalDeadZonesAndAnonymousNamesRemainObservable(): void
+    {
+        $engine = new Engine();
+        self::assertSame(['ReferenceError', 'ReferenceError', 'ReferenceError', 'named', 'named'], $engine->eval(<<<'JS'
+function parameter(x = x) { return x; }
+function selfReference() { const {x = x} = {}; return x; }
+function forwardReference() { const {x = y, y = 1} = {}; return x; }
+function inferred() { const {named = function () {}} = {}; return named.name; }
+const results = [];
+for (const fn of [parameter, selfReference, forwardReference]) {
+  try { fn(); } catch (error) { results.push(error.name); }
+}
+results.push(inferred(), inferred());
+results;
+JS));
+    }
+}
diff --git a/tests/Unit/Bytecode/ObjectLiteralPrototypeTest.php b/tests/Unit/Bytecode/ObjectLiteralPrototypeTest.php
new file mode 100644
index 00000000..c76e39a8
--- /dev/null
+++ b/tests/Unit/Bytecode/ObjectLiteralPrototypeTest.php
@@ -0,0 +1,31 @@
+eval((string) file_get_contents(__DIR__ . '/fixtures/object-literal-prototype.js'));
+        self::assertJsonStringEqualsJsonFile(
+            __DIR__ . '/fixtures/object-literal-prototype.json',
+            $engine->eval('JSON.stringify(objectLiteralPrototypeResult)'),
+        );
+        $names = [
+            'prototypeLiteral', 'quotedPrototypeLiteral', 'computedLiteral', 'shorthandLiteral',
+            'mixedLiteral', 'anonymousPrototypeLiteral', 'orderedLiteral',
+        ];
+        foreach ($names as $name) {
+            $function = $engine->getGlobalEnv()->get($name);
+            self::assertInstanceOf(JsFunction::class, $function);
+            self::assertNotNull($function->compiled, $name . ' must exercise the bytecode path.');
+        }
+    }
+}
diff --git a/tests/Unit/Bytecode/RegExpLiteralTest.php b/tests/Unit/Bytecode/RegExpLiteralTest.php
new file mode 100644
index 00000000..0a707fa6
--- /dev/null
+++ b/tests/Unit/Bytecode/RegExpLiteralTest.php
@@ -0,0 +1,42 @@
+eval(<<<'JS'
+const prototype = RegExp.prototype;
+let globalReads = 0;
+function literal() { return /a\/b/g; }
+const first = literal();
+first.lastIndex = 1;
+const second = literal();
+Object.defineProperty(globalThis, 'RegExp', { configurable: true, get() { globalReads++; throw new Error('global'); } });
+const third = literal();
+[first !== second, first.lastIndex, second.lastIndex, Object.getPrototypeOf(third) === prototype,
+ third.source, third.flags, third.test('a/b'), globalReads];
+JS));
+        $function = $engine->getGlobalEnv()->get('literal');
+        self::assertInstanceOf(JsFunction::class, $function);
+        self::assertNotNull($function->compiled);
+    }
+
+    public function testLiteralObjectsStayInTheirOwnRealm(): void
+    {
+        $first = new Engine();
+        $second = new Engine();
+        $first->eval('function literal() { return /x/; } literal();');
+        $second->eval('RegExp.prototype.realm = 2;');
+        self::assertSame([true, true], $first->eval('[Object.getPrototypeOf(literal()) === RegExp.prototype, literal().realm === undefined]'));
+        self::assertSame(2, $second->eval('(/x/).realm'));
+    }
+}
diff --git a/tests/Unit/Bytecode/TailCallTest.php b/tests/Unit/Bytecode/TailCallTest.php
new file mode 100644
index 00000000..3aaadba5
--- /dev/null
+++ b/tests/Unit/Bytecode/TailCallTest.php
@@ -0,0 +1,70 @@
+eval(<<<'JS'
+'use strict';
+function tail(count, total) {
+  if (count === 0) return total;
+  return tail(count - 1, total + 1);
+}
+function wrapper() { let result = tail(10000, 0); result += tail(10000, 0); return result; }
+wrapper();
+JS));
+        $function = $engine->getGlobalEnv()->get('tail');
+        self::assertInstanceOf(JsFunction::class, $function);
+        self::assertNotNull($function->compiled);
+        self::assertFalse($function->compiled->canSkipEnvAlloc);
+    }
+
+    public function testTailMethodsPreserveReceiverAndLookupBeforeArguments(): void
+    {
+        $engine = new Engine();
+        self::assertSame(['get', 'argument', 'get', 'argument', 7, 7, 'caught'], $engine->eval(<<<'JS'
+'use strict';
+const order = [];
+const object = { value: 4, get method() { order.push('get'); return function (x) { return this.value + x; }; } };
+function argument() { order.push('argument'); return 3; }
+function call() { return object.method(argument()); }
+function fail() { throw new Error('caught'); }
+function protectedCall() { try { return fail(); } catch (error) { return error.message; } }
+order.push(call(), call(), protectedCall());
+order;
+JS));
+    }
+
+    public function testConditionalLogicalAndSequenceTailPositionsKeepTheirEvaluationOrder(): void
+    {
+        $engine = new Engine();
+        self::assertSame([10000, false, true, 0, 10000, 2, 'leftright'], $engine->eval(<<<'JS'
+'use strict';
+let visits = 0;
+let order = '';
+function conditional(n, sum) { return n === 0 ? sum : conditional(n - 1, sum + 1); }
+function andTail(n) { return n > 0 && andTail(n - 1); }
+function orTail(n) { return n === 0 || orTail(n - 1); }
+function nullishTail(n) { return (n === 0 ? 0 : null) ?? nullishTail(n - 1); }
+function sequenceTail(n) { return n === 0 ? visits : (visits = visits + 1, sequenceTail(n - 1)); }
+function left() { order += 'left'; return 0; }
+function right() { order += 'right'; return 2; }
+const arrow = () => left() || right();
+[conditional(10000, 0), andTail(10000), orTail(10000), nullishTail(10000), sequenceTail(10000), arrow(), order];
+JS));
+        foreach (['conditional', 'andTail', 'orTail', 'nullishTail', 'sequenceTail', 'arrow'] as $name) {
+            $function = $engine->getGlobalEnv()->get($name);
+            self::assertInstanceOf(JsFunction::class, $function);
+            self::assertNotNull($function->compiled, $name . ' must use bytecode.');
+        }
+    }
+}
diff --git a/tests/Unit/Bytecode/UnaryReferenceTest.php b/tests/Unit/Bytecode/UnaryReferenceTest.php
new file mode 100644
index 00000000..b048814f
--- /dev/null
+++ b/tests/Unit/Bytecode/UnaryReferenceTest.php
@@ -0,0 +1,45 @@
+setExecutionBudget(10);
+        $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/unary-references.js'));
+        self::assertJsonStringEqualsJsonFile(
+            __DIR__ . '/fixtures/unary-references.json',
+            $engine->eval('JSON.stringify(unaryReferenceResult)'),
+        );
+        $function = $engine->getGlobalEnv()->get('deleteOrdered');
+        self::assertInstanceOf(JsFunction::class, $function);
+        self::assertNull($function->compiled, 'The budgeted engine must exercise the interpreter path.');
+    }
+
+    public function testCompiledTypeofAndDeleteMatchNodeReferenceSemantics(): void
+    {
+        $engine = new Engine();
+        $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/unary-references.js'));
+        self::assertJsonStringEqualsJsonFile(
+            __DIR__ . '/fixtures/unary-references.json',
+            $engine->eval('JSON.stringify(unaryReferenceResult)'),
+        );
+        $names = [
+            'typeOfValue', 'unknownType', 'lexicalType', 'shadowedUndefined', 'deleteMember', 'deleteComputed',
+            'deleteStrict', 'deleteGlobal', 'deleteLocal', 'deleteSideEffect', 'deleteOrdered',
+        ];
+        foreach ($names as $name) {
+            $function = $engine->getGlobalEnv()->get($name);
+            self::assertInstanceOf(JsFunction::class, $function);
+            self::assertNotNull($function->compiled, $name . ' must exercise the bytecode path.');
+        }
+    }
+}
diff --git a/tests/Unit/Bytecode/fixtures/object-literal-prototype.js b/tests/Unit/Bytecode/fixtures/object-literal-prototype.js
new file mode 100644
index 00000000..d12a1176
--- /dev/null
+++ b/tests/Unit/Bytecode/fixtures/object-literal-prototype.js
@@ -0,0 +1,80 @@
+function prototypeLiteral(value) {
+  return { before: 1, __proto__: value, after: 2 };
+}
+function quotedPrototypeLiteral(value) {
+  return { '__proto__': value };
+}
+function computedLiteral(key, value) {
+  return { [key]: value };
+}
+function shorthandLiteral(__proto__) {
+  return { __proto__ };
+}
+function mixedLiteral(value) {
+  return { ['__proto__']: 3, __proto__: value, after: 4 };
+}
+function anonymousPrototypeLiteral() {
+  return { __proto__: function () {} };
+}
+var literalTrace = [];
+function markLiteral(label, value) {
+  literalTrace.push(label);
+  return value;
+}
+function orderedLiteral(key, value) {
+  return {
+    before: markLiteral('before', 1),
+    [key]: markLiteral('value', 2),
+    __proto__: markLiteral('prototype', value),
+    after: markLiteral('after', 3)
+  };
+}
+var literalPrototype = { inherited: 5 };
+var literalSymbol = Symbol('key');
+var setterCalls = 0;
+var originalPrototypeDescriptor = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__');
+Object.defineProperty(Object.prototype, '__proto__', { configurable: true, set() { setterCalls++; } });
+Object.defineProperty(Object.prototype, 'before', { configurable: true, set() { setterCalls++; } });
+Object.defineProperty(Object.prototype, literalSymbol, { configurable: true, set() { setterCalls++; } });
+var literalResults = [];
+try {
+  for (var round = 0; round < 2; round++) {
+    for (var value of [literalPrototype, null, 0, 'text', true, undefined, literalSymbol, 1n]) {
+      var object = prototypeLiteral(value);
+      var expected = value === null || typeof value === 'object' ? value : Object.prototype;
+      literalResults.push([
+        Object.getPrototypeOf(object) === expected,
+        Object.hasOwn(object, '__proto__'),
+        Object.keys(object), object.before, object.after
+      ]);
+      literalResults.push(Object.getPrototypeOf(quotedPrototypeLiteral(value)) === expected);
+    }
+    var computed = computedLiteral('__proto__', literalPrototype);
+    var shorthand = shorthandLiteral(literalPrototype);
+    var mixed = mixedLiteral(null);
+    var symbolic = computedLiteral(literalSymbol, 7);
+    var anonymous = anonymousPrototypeLiteral();
+    literalResults.push([
+      Object.getPrototypeOf(computed) === Object.prototype, computed.__proto__ === literalPrototype,
+      Object.getPrototypeOf(shorthand) === Object.prototype, shorthand.__proto__ === literalPrototype,
+      Object.getPrototypeOf(mixed) === null, mixed.__proto__, mixed.after,
+      Object.getOwnPropertyDescriptor(symbolic, literalSymbol),
+      Object.getPrototypeOf(anonymous).name,
+      Object.hasOwn(anonymous, '__proto__')
+    ]);
+    literalTrace = [];
+    var key = { [Symbol.toPrimitive](hint) { literalTrace.push('key:' + hint); return '__proto__'; } };
+    var ordered = orderedLiteral(key, literalPrototype);
+    literalResults.push([literalTrace.slice(), Object.getPrototypeOf(ordered) === literalPrototype, ordered.__proto__, Object.keys(ordered)]);
+    literalTrace = [];
+    var throwingKey = { [Symbol.toPrimitive]() { literalTrace.push('throw'); throw new RangeError('key'); } };
+    try { orderedLiteral(throwingKey, null); }
+    catch (error) { literalResults.push([error.name, literalTrace.slice()]); }
+  }
+  literalResults.push(setterCalls);
+} finally {
+  Object.defineProperty(Object.prototype, '__proto__', originalPrototypeDescriptor);
+  delete Object.prototype.before;
+  delete Object.prototype[literalSymbol];
+}
+globalThis.objectLiteralPrototypeResult = literalResults;
diff --git a/tests/Unit/Bytecode/fixtures/object-literal-prototype.json b/tests/Unit/Bytecode/fixtures/object-literal-prototype.json
new file mode 100644
index 00000000..ee272fb1
--- /dev/null
+++ b/tests/Unit/Bytecode/fixtures/object-literal-prototype.json
@@ -0,0 +1,259 @@
+[
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    true,
+    true,
+    true,
+    true,
+    3,
+    4,
+    {
+      "value": 7,
+      "writable": true,
+      "enumerable": true,
+      "configurable": true
+    },
+    "",
+    false
+  ],
+  [
+    [
+      "before",
+      "key:string",
+      "value",
+      "prototype",
+      "after"
+    ],
+    true,
+    2,
+    [
+      "before",
+      "__proto__",
+      "after"
+    ]
+  ],
+  [
+    "RangeError",
+    [
+      "before",
+      "throw"
+    ]
+  ],
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    false,
+    [
+      "before",
+      "after"
+    ],
+    1,
+    2
+  ],
+  true,
+  [
+    true,
+    true,
+    true,
+    true,
+    true,
+    3,
+    4,
+    {
+      "value": 7,
+      "writable": true,
+      "enumerable": true,
+      "configurable": true
+    },
+    "",
+    false
+  ],
+  [
+    [
+      "before",
+      "key:string",
+      "value",
+      "prototype",
+      "after"
+    ],
+    true,
+    2,
+    [
+      "before",
+      "__proto__",
+      "after"
+    ]
+  ],
+  [
+    "RangeError",
+    [
+      "before",
+      "throw"
+    ]
+  ],
+  0
+]
diff --git a/tests/Unit/Bytecode/fixtures/unary-references.js b/tests/Unit/Bytecode/fixtures/unary-references.js
new file mode 100644
index 00000000..f1c6ae44
--- /dev/null
+++ b/tests/Unit/Bytecode/fixtures/unary-references.js
@@ -0,0 +1,64 @@
+function typeOfValue(value) { return typeof value; }
+function unknownType() { return typeof __unaryMissing__; }
+function lexicalType() { return typeof laterLexical; }
+function shadowedUndefined(undefined) { return typeof undefined; }
+function capturedUndefined(undefined) { return function captured() { return typeof undefined; }; }
+function deleteMember(object) { return delete object.value; }
+function deleteComputed(object, key) { return delete object[key]; }
+function deleteStrict(object, key) { 'use strict'; return delete object[key]; }
+function deleteGlobal() { return delete __unaryGlobal__; }
+function deleteLocal(value) { return delete value; }
+function deleteSideEffect(callback) { return delete callback(); }
+function deleteOrdered(object, callback) { return delete object[callback()]; }
+var unaryResults = [];
+unaryResults.push(unknownType());
+globalThis.__unaryMissing__ = 1;
+unaryResults.push(unknownType());
+delete globalThis.__unaryMissing__;
+unaryResults.push(unknownType());
+try { lexicalType(); } catch (error) { unaryResults.push(error.name); }
+let laterLexical = null;
+unaryResults.push(lexicalType(), shadowedUndefined(5), shadowedUndefined(false), capturedUndefined('x')());
+var revoked = Proxy.revocable(function () {}, {});
+revoked.revoke();
+for (var value of [undefined, null, true, 1, 'x', Symbol(), 1n, {}, [], function () {}, revoked.proxy]) {
+  unaryResults.push(typeOfValue(value));
+}
+var unarySymbol = Symbol('key');
+for (var round = 0; round < 2; round++) {
+  var reads = 0;
+  var object = {};
+  Object.defineProperty(object, 'value', { configurable: true, get() { reads++; return 1; } });
+  unaryResults.push([deleteMember(object), reads, Object.hasOwn(object, 'value')]);
+  var fixed = {};
+  Object.defineProperty(fixed, 'value', { value: 1 });
+  Object.defineProperty(fixed, unarySymbol, { value: 2 });
+  unaryResults.push([deleteMember(fixed), deleteComputed(fixed, unarySymbol), deleteLocal(1)]);
+  for (var key of ['value', unarySymbol]) {
+    try { deleteStrict(fixed, key); } catch (error) { unaryResults.push(error.name); }
+  }
+  for (var key of ['0', '1', '2', '00', '1.0', '-0', 'length', unarySymbol]) {
+    unaryResults.push(deleteComputed('😀', key));
+  }
+  var trace = [];
+  var keyObject = { [Symbol.toPrimitive](hint) { trace.push('coerce:' + hint); return unarySymbol; } };
+  var keyed = { [unarySymbol]: 3 };
+  unaryResults.push([deleteComputed(keyed, keyObject), trace.slice(), Object.hasOwn(keyed, unarySymbol)]);
+  for (var base of [null, undefined, 1, false, Symbol(), 1n]) {
+    trace = [];
+    try {
+      unaryResults.push(deleteOrdered(base, function () { trace.push('expression'); return keyObject; }));
+    } catch (error) { unaryResults.push(error.name); }
+    unaryResults.push(trace.slice());
+  }
+  var effects = 0;
+  unaryResults.push([deleteSideEffect(function () { effects++; }), effects]);
+  globalThis.__unaryGlobal__ = 4;
+  unaryResults.push([deleteGlobal(), typeof __unaryGlobal__, deleteGlobal()]);
+  var target = { x: 1 };
+  trace = [];
+  var proxy = new Proxy(target, { deleteProperty(object, key) { trace.push(key); return false; } });
+  unaryResults.push([deleteComputed(proxy, 'x'), trace.slice()]);
+  try { deleteStrict(proxy, 'x'); } catch (error) { unaryResults.push(error.name); }
+}
+globalThis.unaryReferenceResult = unaryResults;
diff --git a/tests/Unit/Bytecode/fixtures/unary-references.json b/tests/Unit/Bytecode/fixtures/unary-references.json
new file mode 100644
index 00000000..52b623dd
--- /dev/null
+++ b/tests/Unit/Bytecode/fixtures/unary-references.json
@@ -0,0 +1,163 @@
+[
+  "undefined",
+  "number",
+  "undefined",
+  "ReferenceError",
+  "object",
+  "number",
+  "boolean",
+  "string",
+  "undefined",
+  "object",
+  "boolean",
+  "number",
+  "string",
+  "symbol",
+  "bigint",
+  "object",
+  "object",
+  "function",
+  "function",
+  [
+    true,
+    0,
+    false
+  ],
+  [
+    false,
+    false,
+    false
+  ],
+  "TypeError",
+  "TypeError",
+  false,
+  false,
+  true,
+  true,
+  true,
+  true,
+  false,
+  true,
+  [
+    true,
+    [
+      "coerce:string"
+    ],
+    false
+  ],
+  "TypeError",
+  [
+    "expression"
+  ],
+  "TypeError",
+  [
+    "expression"
+  ],
+  true,
+  [
+    "expression",
+    "coerce:string"
+  ],
+  true,
+  [
+    "expression",
+    "coerce:string"
+  ],
+  true,
+  [
+    "expression",
+    "coerce:string"
+  ],
+  true,
+  [
+    "expression",
+    "coerce:string"
+  ],
+  [
+    true,
+    1
+  ],
+  [
+    true,
+    "undefined",
+    true
+  ],
+  [
+    false,
+    [
+      "x"
+    ]
+  ],
+  "TypeError",
+  [
+    true,
+    0,
+    false
+  ],
+  [
+    false,
+    false,
+    false
+  ],
+  "TypeError",
+  "TypeError",
+  false,
+  false,
+  true,
+  true,
+  true,
+  true,
+  false,
+  true,
+  [
+    true,
+    [
+      "coerce:string"
+    ],
+    false
+  ],
+  "TypeError",
+  [
+    "expression"
+  ],
+  "TypeError",
+  [
+    "expression"
+  ],
+  true,
+  [
+    "expression",
+    "coerce:string"
+  ],
+  true,
+  [
+    "expression",
+    "coerce:string"
+  ],
+  true,
+  [
+    "expression",
+    "coerce:string"
+  ],
+  true,
+  [
+    "expression",
+    "coerce:string"
+  ],
+  [
+    true,
+    1
+  ],
+  [
+    true,
+    "undefined",
+    true
+  ],
+  [
+    false,
+    [
+      "x"
+    ]
+  ],
+  "TypeError"
+]
diff --git a/tests/Unit/ExecutionBudgetTest.php b/tests/Unit/ExecutionBudgetTest.php
index 1b055b91..eb996e91 100644
--- a/tests/Unit/ExecutionBudgetTest.php
+++ b/tests/Unit/ExecutionBudgetTest.php
@@ -99,4 +99,36 @@ public function testDisabledTimersNeverFire(): void
 
         self::assertSame('microtask', $engine->eval('log.join()'));
     }
+
+    public function testEnablingABudgetPreservesWarmFunctionBindings(): void
+    {
+        $engine = new Engine();
+        $engine->eval(<<<'JS'
+'use strict';
+function initialize(value) { this.value = value; }
+function Container(value) { initialize.call(this, value); }
+function read(value) { return value.name; }
+function arithmetic(value) { return value + 2; }
+new Container('warm');
+read({ name: 'warm' });
+arithmetic(1);
+JS);
+        $engine->setExecutionBudget(5);
+
+        self::assertSame(
+            ['budgeted', 'bound', 5],
+            $engine->eval('[new Container("budgeted").value, read({name: "bound"}), arithmetic(3)]'),
+        );
+    }
+
+    public function testEnablingABudgetStopsAnAlreadyCompiledNumericLoop(): void
+    {
+        $engine = new Engine();
+        $engine->setLimit('maxLoopIterations', PHP_INT_MAX);
+        $engine->eval('function count(n) { var value = 0; while (value < n) value++; return value; } count(1);');
+        $engine->setExecutionBudget(0.01);
+
+        $this->expectException(BudgetExceeded::class);
+        $engine->eval('count(Infinity);');
+    }
 }
diff --git a/tests/Unit/Module/CommonJsCacheTest.php b/tests/Unit/Module/CommonJsCacheTest.php
new file mode 100644
index 00000000..3e80002f
--- /dev/null
+++ b/tests/Unit/Module/CommonJsCacheTest.php
@@ -0,0 +1,107 @@
+project([
+            'entry.cjs' => <<<'JS'
+const first = require('./child.cjs');
+const second = require('./child.cjs');
+try { require('./bad.cjs'); } catch {}
+globalThis.result = [module.id, module.parent, require.main === module,
+  module.children.length, module.children[0].exports === first,
+  first.parent === module, first.loadedDuringExecution, first.module.loaded,
+  module.require('./child.cjs') === second, module.paths[0] === __dirname + '/node_modules'];
+JS,
+            'child.cjs' => 'module.exports = {parent: module.parent, module, loadedDuringExecution: module.loaded};',
+            'bad.cjs' => 'throw new Error("load failed");',
+        ]);
+        $engine = new Engine(node: true);
+        $engine->execFile($root . '/entry.cjs');
+        self::assertSame(['.', null, true, 1, true, true, false, true, true, true], $engine->eval('result'));
+    }
+
+    public function testDeletingCacheEntriesReexecutesModulesAndSharesCycles(): void
+    {
+        $root = $this->project([
+            'entry.cjs' => <<<'JS'
+const path = require.resolve('./count.cjs');
+const first = require(path);
+const metadata = require.cache[path];
+delete require.cache[path];
+const second = require(path);
+globalThis.result = [first, second, metadata.loaded, metadata.filename === path,
+  Object.getPrototypeOf(require.cache) === null, require('./cycle.cjs').same];
+JS,
+            'count.cjs' => 'globalThis.count = (globalThis.count || 0) + 1; module.exports = count;',
+            'cycle.cjs' => 'exports.same = require.cache[__filename].exports === exports && require(__filename) === exports;',
+        ]);
+        $engine = new Engine(node: true);
+        $engine->execFile($root . '/entry.cjs');
+        self::assertSame([1, 2, true, true, true, true], $engine->eval('result'));
+    }
+
+    public function testRequireDoesNotReadExportGettersAndEsmImportCreatesSnapshotBindings(): void
+    {
+        $root = $this->project([
+            'entry.cjs' => <<<'JS'
+const throwing = require('./throwing.cjs');
+const values = require('./values.cjs');
+globalThis.result = [typeof throwing, globalThis.reads || 0];
+JS,
+            'throwing.cjs' => 'module.exports = {get unsafe() { throw new Error("must not read"); }};',
+            'values.cjs' => <<<'JS'
+Object.defineProperty(exports, '__esModule', {value: true});
+exports.default = 'bundler default';
+const source = {get value() { globalThis.reads = (globalThis.reads || 0) + 1; return 42; }};
+Object.defineProperty(exports, 'value', {enumerable: true, get: function () { return source.value; }});
+JS,
+            'import.mjs' => <<<'JS'
+import value, {value as named} from './values.cjs';
+import * as namespace from './values.cjs';
+globalThis.imported = [typeof value, named, named, globalThis.reads,
+ namespace.default === value, namespace['module.exports'] === value];
+JS,
+        ]);
+        $engine = new Engine(node: true);
+        $engine->execFile($root . '/entry.cjs');
+        self::assertSame(['object', 0], $engine->eval('result'));
+        $engine->execFile($root . '/import.mjs');
+        self::assertSame(['object', 42, 42, 1, true, true], $engine->eval('imported'));
+    }
+
+    public function testCacheOverridesAndFailedModuleRetriesMatchNode(): void
+    {
+        $root = $this->project([
+            'entry.cjs' => <<<'JS'
+const path = require.resolve('./value.json');
+const initial = require(path);
+require.cache[path] = {exports: 'override'};
+const replacement = require(path);
+delete require.cache[path];
+const again = require(path);
+require.cache.events = {exports: 'shadow'};
+const results = [initial.value, replacement, again.value, require('events'), typeof require('node:events')];
+for (let i = 0; i < 2; i++) {
+  try { require('./throws.cjs'); } catch (error) { results.push(error.message); }
+}
+globalThis.result = results;
+JS,
+            'value.json' => '{"value": 42}',
+            'throws.cjs' => 'globalThis.attempt = (globalThis.attempt || 0) + 1; throw new Error(String(attempt));',
+        ]);
+        $engine = new Engine(node: true);
+        $engine->execFile($root . '/entry.cjs');
+        self::assertSame([42, 'override', 42, 'shadow', 'function', '1', '2'], $engine->eval('result'));
+    }
+}
diff --git a/tests/Unit/Module/ResolverTest.php b/tests/Unit/Module/ResolverTest.php
index 574cffb6..b7abd960 100644
--- a/tests/Unit/Module/ResolverTest.php
+++ b/tests/Unit/Module/ResolverTest.php
@@ -35,6 +35,22 @@ public function testProbesExtensionsAndIndexFiles(): void
         $this->assertSame($root . '/src/data.json', $resolver->resolve('./data', $from));
     }
 
+    public function testRelativeDirectoriesUsePackageMainWithoutProbingSiblingJson(): void
+    {
+        $root = $this->project([
+            'package.json' => '{"main":"lib/entry.js"}',
+            'lib/entry.js' => '',
+            'test/case.js' => '',
+            'test.json' => '{}',
+            'nested/package.json' => '{"main":"."}',
+            'nested/index.js' => '',
+        ]);
+        $resolver = new ModuleResolver((new ModuleOptions(projectRoot: $root))->forNode(), static fn (string $s): bool => false);
+        self::assertSame($root . '/lib/entry.js', $resolver->resolve('..', $root . '/test/case.js', 'require'));
+        self::assertSame($root . '/lib/entry.js', $resolver->resolve('../', $root . '/test/case.js', 'require'));
+        self::assertSame($root . '/nested/index.js', $resolver->resolve('./nested/', $root . '/entry.js', 'require'));
+    }
+
     public function testJsconfigAliasWithComments(): void
     {
         $root = $this->project([
@@ -64,6 +80,35 @@ public function testNodeBuiltinsAreRejected(): void
         $this->resolver($root)->resolve('node:fs', $root . '/main.mjs');
     }
 
+    public function testLegacyPackageTrailingSlashResolvesMainWithoutUsingBundlerModuleField(): void
+    {
+        $root = $this->project([
+            'main.cjs' => '',
+            'node_modules/legacy/package.json' => '{"main":"entry.cjs","module":"bundle.mjs"}',
+            'node_modules/legacy/entry.cjs' => '',
+            'node_modules/legacy/bundle.mjs' => '',
+        ]);
+        $resolver = new ModuleResolver(
+            (new ModuleOptions(projectRoot: $root))->forNode(),
+            static fn (string $specifier): bool => false,
+        );
+        self::assertSame($root . '/node_modules/legacy/entry.cjs', $resolver->resolve('legacy/', $root . '/main.cjs', 'require'));
+        self::assertSame($root . '/node_modules/legacy/entry.cjs', $resolver->resolve('legacy', $root . '/main.cjs', 'import'));
+        self::assertSame($root . '/node_modules/legacy/bundle.mjs', $this->resolver($root)->resolve('legacy', $root . '/main.cjs'));
+    }
+
+    public function testTrailingPackageSlashDoesNotBypassExports(): void
+    {
+        $root = $this->project([
+            'main.cjs' => '',
+            'node_modules/closed/package.json' => '{"exports":"./entry.cjs","main":"entry.cjs"}',
+            'node_modules/closed/entry.cjs' => '',
+        ]);
+        $this->expectException(TypeError::class);
+        $this->expectExceptionMessage("Package subpath './' is not defined");
+        $this->resolver($root)->resolve('closed/', $root . '/main.cjs', 'require');
+    }
+
     public function testPackageImportsField(): void
     {
         $root = $this->project([
diff --git a/tests/Unit/Node/AbortRealmTest.php b/tests/Unit/Node/AbortRealmTest.php
new file mode 100644
index 00000000..9651f900
--- /dev/null
+++ b/tests/Unit/Node/AbortRealmTest.php
@@ -0,0 +1,44 @@
+eval(<<<'JS'
+const OriginalEvent = Event;
+const OriginalException = DOMException;
+const early = new AbortController();
+require('node:vm').runInNewContext('globalThis.Event = class Event {}; globalThis.DOMException = class DOMException {};');
+const late = new AbortController();
+const events = [];
+early.signal.addEventListener('abort', event => events.push(event instanceof OriginalEvent));
+late.signal.addEventListener('abort', event => events.push(event instanceof OriginalEvent));
+globalThis.Event = class ReplacementEvent {};
+globalThis.DOMException = class ReplacementException {};
+early.abort();
+late.abort('explicit reason');
+const immediate = AbortSignal.abort();
+const timeout = AbortSignal.timeout(0);
+timeout.addEventListener('abort', event => events.push(event instanceof OriginalEvent));
+const reasons = [early.signal.reason instanceof OriginalException, early.signal.reason.name,
+    late.signal.reason, immediate.reason instanceof OriginalException];
+JS);
+            self::assertSame([true, true, true], $engine->eval('events'));
+            self::assertSame([true, 'AbortError', 'explicit reason', true], $engine->eval('reasons'));
+            self::assertSame([true, 'TimeoutError'], $engine->eval(
+                '[timeout.reason instanceof OriginalException, timeout.reason.name]',
+            ));
+        } finally {
+            $engine->getNodeRuntime()?->close();
+        }
+    }
+}
diff --git a/tests/Unit/Node/BroadcastChannelTest.php b/tests/Unit/Node/BroadcastChannelTest.php
new file mode 100644
index 00000000..dff32557
--- /dev/null
+++ b/tests/Unit/Node/BroadcastChannelTest.php
@@ -0,0 +1,87 @@
+eval(<<<'JS'
+const sender = new BroadcastChannel('example');
+const first = new BroadcastChannel('example');
+const second = new BroadcastChannel('example');
+const other = new BroadcastChannel('other');
+const events = [];
+sender.onmessage = () => events.push('self');
+other.onmessage = () => events.push('other');
+first.addEventListener('message', event => {
+  events.push('first:' + event.data.value + ':' + (event.target === first));
+  event.data.value = 'receiver mutation';
+}, {once: true});
+second.onmessage = function (event) {
+  events.push('second:' + event.data.value + ':' + (this === second));
+};
+const data = {value: 'original'};
+sender.postMessage(data);
+data.value = 'sender mutation';
+events.push('synchronous');
+queueMicrotask(() => events.push('microtask'));
+JS);
+        self::assertSame(
+            ['synchronous', 'microtask', 'first:original:true', 'second:original:true'],
+            $engine->eval('events'),
+        );
+        $engine->eval('for (const channel of [sender, first, second, other]) channel.close();');
+        self::assertSame(0, $engine->getEventLoop()->pendingTaskCount());
+    }
+
+    public function testCloseCancelsDeliveryAndValidationUsesRealDomExceptions(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->eval(<<<'JS'
+const sender = new BroadcastChannel('closed');
+const recipient = new BroadcastChannel('closed');
+let delivered = false;
+recipient.onmessage = () => { delivered = true; };
+sender.postMessage('cancel');
+recipient.close();
+const errors = [];
+try { sender.postMessage(() => {}); } catch (error) { errors.push(error.name, error instanceof DOMException); }
+sender.close();
+try { sender.postMessage('no'); } catch (error) { errors.push(error.name, error instanceof DOMException); }
+const handles = [sender.ref() === sender, sender.unref() === sender];
+JS);
+        self::assertFalse($engine->eval('delivered'));
+        self::assertSame(['DataCloneError', true, 'InvalidStateError', true], $engine->eval('errors'));
+        self::assertSame([true, true], $engine->eval('handles'));
+        self::assertSame(0, $engine->getEventLoop()->pendingTaskCount());
+    }
+
+    public function testReplacingOnmessagePreservesItsListenerPosition(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->eval(<<<'JS'
+const sender = new BroadcastChannel('handlers');
+const recipient = new BroadcastChannel('handlers');
+const order = [];
+recipient.onmessage = () => order.push('old');
+recipient.addEventListener('message', () => order.push('listener'));
+recipient.onmessage = () => order.push('replacement');
+sender.postMessage(1);
+JS);
+        self::assertSame(['replacement', 'listener'], $engine->eval('order'));
+        $engine->eval(<<<'JS'
+recipient.onmessage = null;
+recipient.onmessage = () => order.push('new position');
+sender.postMessage(2);
+JS);
+        self::assertSame(['replacement', 'listener', 'listener', 'new position'], $engine->eval('order'));
+        $engine->eval('sender.close(); recipient.close();');
+    }
+}
diff --git a/tests/Unit/Node/ChildProcessTest.php b/tests/Unit/Node/ChildProcessTest.php
new file mode 100644
index 00000000..303849d0
--- /dev/null
+++ b/tests/Unit/Node/ChildProcessTest.php
@@ -0,0 +1,43 @@
+setExecutionBudget(30);
+        try {
+            $engine->execFile(__DIR__ . '/fixtures/primitives/child-process.mjs');
+            self::assertNull($engine->eval('globalThis.__nodePrimitiveError'), $engine->getConsoleOutput());
+            $result = $engine->eval('globalThis.__nodePrimitiveResult');
+            self::assertIsString($result, 'All child processes must exit and close their pipes.');
+            self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/primitives/child-process.json', $result);
+        } finally {
+            $engine->getNodeRuntime()?->close();
+        }
+    }
+
+    public function testResetKillsAndReapsUnreferencedChildren(): void
+    {
+        $engine = new Engine(node: true);
+        try {
+            $pid = $engine->eval(<<<'JS'
+globalThis.child = require('child_process').spawn('/bin/sleep', ['60'], { stdio: 'ignore' });
+child.unref(); child.pid;
+JS);
+            self::assertIsInt($pid);
+            self::assertTrue(posix_kill($pid, 0));
+            $engine->reset();
+            self::assertFalse(posix_kill($pid, 0), 'Reset must reap the actual native process, not merely forget its handle.');
+        } finally {
+            $engine->getNodeRuntime()?->close();
+        }
+    }
+}
diff --git a/tests/Unit/Node/ErrorStackTest.php b/tests/Unit/Node/ErrorStackTest.php
new file mode 100644
index 00000000..aa70edec
--- /dev/null
+++ b/tests/Unit/Node/ErrorStackTest.php
@@ -0,0 +1,49 @@
+eval(<<<'JS'
+let preparations = 0;
+Error.stackTraceLimit = 1;
+Error.prepareStackTrace = (error, frames) => {
+  preparations++;
+  return { message: error.message, frames };
+};
+function createError() {
+  const error = { message: 'example' };
+  Error.captureStackTrace(error, createError);
+  return error;
+}
+function caller() {
+  const error = createError();
+  const before = preparations;
+  const stack = error.stack;
+  return [before, preparations, stack === error.stack, stack.message, stack.frames.length,
+    stack.frames[0].getFunctionName(), stack.frames[0].getFunction() === caller,
+    Object.keys(error).includes('stack')];
+}
+globalThis.stackResult = caller();
+JS);
+            self::assertSame([0, 1, true, 'example', 1, 'caller', true, false], $engine->eval('stackResult'));
+            self::assertSame('replacement', $engine->eval(<<<'JS'
+const overwritten = {};
+Error.captureStackTrace(overwritten);
+overwritten.stack = 'replacement';
+overwritten.stack;
+JS));
+        } finally {
+            $engine->close();
+        }
+    }
+}
diff --git a/tests/Unit/Node/FetchHeadersTest.php b/tests/Unit/Node/FetchHeadersTest.php
new file mode 100644
index 00000000..77c839c6
--- /dev/null
+++ b/tests/Unit/Node/FetchHeadersTest.php
@@ -0,0 +1,67 @@
+eval(<<<'JS'
+['cors', 'no-cors', 'same-origin'].map(mode => {
+    const request = new Request('https://example.com', {
+        mode, headers: { Cookie: 'a=b', 'Content-Type': 'application/json', 'X-Test': 'yes' }
+    }).clone();
+    return ['cookie', 'content-type', 'x-test'].map(name => request.headers.get(name)).join('|');
+});
+JS));
+    }
+
+    public function testRequestInitHeadersReplaceTheSourceHeaders(): void
+    {
+        $engine = new Engine();
+        self::assertSame(['original', null, 'replacement', 'original', 'TypeError'], $engine->eval(<<<'JS'
+const source = new Request('https://example.com', {headers: {'x-method-override': 'original'}});
+const empty = new Request(source, {headers: new Headers()});
+const changed = new Request(source, {headers: {'x-method-override': 'replacement'}});
+const inherited = new Request(source, {headers: undefined});
+let error;
+try { new Request(source, {headers: null}); } catch (caught) { error = caught.name; }
+[source.headers.get('x-method-override'), empty.headers.get('x-method-override'),
+ changed.headers.get('x-method-override'), inherited.headers.get('x-method-override'), error];
+JS));
+    }
+
+    public function testNodeResponsesKeepCookiesAndImmutableClones(): void
+    {
+        $engine = new Engine(node: true);
+        self::assertSame([['a=b', 'c=d'], 'TypeError'], $engine->eval(<<<'JS'
+const response = new Response(null, {headers: {'set-cookie': 'a=b'}});
+response.headers.append('set-cookie', 'c=d');
+const immutable = Response.error().clone();
+let error;
+try { immutable.headers.set('x-test', 'value'); } catch (caught) { error = caught.name; }
+[response.clone().headers.getSetCookie(), error];
+JS));
+    }
+
+    public function testEnablingNodeDoesNotAlterExistingBrowserHeaders(): void
+    {
+        $engine = new Engine();
+        $engine->eval('globalThis.response = new Response();');
+        $engine->enableNode();
+        self::assertSame([[], [], ['server']], $engine->eval(<<<'JS'
+response.headers.append('set-cookie', 'old');
+const copy = response.clone();
+copy.headers.append('set-cookie', 'clone');
+const server = new Response();
+server.headers.append('set-cookie', 'server');
+[response.headers.getSetCookie(), copy.headers.getSetCookie(), server.headers.getSetCookie()];
+JS));
+    }
+}
diff --git a/tests/Unit/Node/FetchTest.php b/tests/Unit/Node/FetchTest.php
new file mode 100644
index 00000000..3b646727
--- /dev/null
+++ b/tests/Unit/Node/FetchTest.php
@@ -0,0 +1,75 @@
+setExecutionBudget(15);
+        try {
+            $engine->eval(<<<'JS'
+const NativeResponse = Response;
+globalThis.Request = class { constructor() { throw new Error('global Request called'); } };
+globalThis.Response = class { constructor() { throw new Error('global Response called'); } };
+const http = require('node:http');
+const result = [];
+const server = http.createServer((req, res) => res.end('intrinsic'));
+server.listen(0, '127.0.0.1', async () => {
+  try {
+    const response = await fetch('http://127.0.0.1:' + server.address().port);
+    result.push(response instanceof NativeResponse, await response.text());
+  } catch (error) { result.push(error.message); }
+  finally { server.close(); }
+});
+JS);
+            self::assertSame([true, 'intrinsic'], $engine->eval('result'));
+        } finally {
+            $engine->close();
+        }
+    }
+
+    public function testFetchUsesAsyncHttpAndRetainsStreamedRequestAndResponseBytes(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(15);
+        $engine->eval(<<<'JS'
+const http = require('http');
+const result = [];
+const server = http.createServer((req, res) => {
+  if (req.url === '/redirect') { res.writeHead(302, { Location: '/stream' }); res.end(); return; }
+  if (req.method === 'POST') {
+    const chunks = [];
+    req.on('data', chunk => chunks.push(chunk));
+    req.on('end', () => res.end(Buffer.concat(chunks)));
+    return;
+  }
+  res.write('first');
+  setTimeout(() => res.end('last'), 5);
+});
+server.listen(0, '127.0.0.1', async () => {
+  const base = 'http://127.0.0.1:' + server.address().port;
+  try {
+    const response = await fetch(base + '/redirect');
+    result.push(response.redirected, response.url === base + '/stream', await response.text());
+    try { response.headers.set('x-change', 'no'); } catch (error) { result.push(error.name); }
+    const body = new ReadableStream({ start(controller) {
+      controller.enqueue(new Uint8Array([0, 255]));
+      setTimeout(() => { controller.enqueue(new Uint8Array([128, 65])); controller.close(); }, 5);
+    } });
+    const echo = await fetch(base + '/echo', { method: 'POST', body, duplex: 'half' });
+    result.push(Buffer.from(await echo.arrayBuffer()).toString('hex'));
+  } catch (error) { result.push(error.name + ':' + error.message); }
+  finally { server.close(); }
+});
+JS);
+        self::assertSame([true, true, 'firstlast', 'TypeError', '00ff8041'], $engine->eval('result'));
+        $engine->reset();
+    }
+}
diff --git a/tests/Unit/Node/FileSystemTest.php b/tests/Unit/Node/FileSystemTest.php
new file mode 100644
index 00000000..d84797de
--- /dev/null
+++ b/tests/Unit/Node/FileSystemTest.php
@@ -0,0 +1,66 @@
+setGlobal('longPath', sys_get_temp_dir() . str_repeat('/long-component', PHP_MAXPATHLEN));
+        $result = $engine->eval(<<<'JS'
+            JSON.stringify(['statSync', 'lstatSync', 'accessSync'].map(function (method) {
+                try {
+                    require('fs')[method](longPath);
+                    return null;
+                } catch (error) {
+                    return [error.code, error.errno, error.syscall, error.path === longPath];
+                }
+            }));
+            JS);
+        $number = defined('SOCKET_ENAMETOOLONG') ? constant('SOCKET_ENAMETOOLONG') : (PHP_OS_FAMILY === 'Darwin' ? 63 : 36);
+        self::assertSame([
+            ['ENAMETOOLONG', -$number, 'stat', true],
+            ['ENAMETOOLONG', -$number, 'lstat', true],
+            ['ENAMETOOLONG', -$number, 'access', true],
+        ], json_decode($result, true, flags: JSON_THROW_ON_ERROR));
+    }
+
+    public function testFileSystemMatchesNodeOracle(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(30);
+        $engine->execFile(__DIR__ . '/fixtures/primitives/fs.mjs');
+        self::assertNull($engine->eval('globalThis.__nodePrimitiveError'), $engine->getConsoleOutput());
+        $result = $engine->eval('globalThis.__nodePrimitiveResult');
+        self::assertIsString($result, 'All asynchronous filesystem operations must finish.');
+        self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/primitives/fs.json', $result);
+    }
+
+    public function testEngineResetClosesOwnedFileDescriptors(): void
+    {
+        $path = tempnam(sys_get_temp_dir(), 'phasis-fs-cleanup-');
+        self::assertIsString($path);
+        try {
+            $engine = new Engine(node: true);
+            $engine->setGlobal('testPath', $path);
+            $engine->eval('globalThis.testDescriptor = require("fs").openSync(testPath, "w+");');
+            $owned = array_filter(get_resources('stream'), static fn ($stream): bool => (stream_get_meta_data($stream)['uri'] ?? null) === $path);
+            self::assertCount(1, $owned);
+            $descriptor = $engine->eval('testDescriptor');
+            $engine->reset();
+            foreach ($owned as $stream) {
+                self::assertFalse(is_resource($stream));
+            }
+            $engine->setGlobal('testDescriptor', $descriptor);
+            self::assertSame('EBADF', $engine->eval('try { require("fs").closeSync(testDescriptor); } catch (error) { error.code; }'));
+        } finally {
+            unlink($path);
+        }
+    }
+}
diff --git a/tests/Unit/Node/Http2Test.php b/tests/Unit/Node/Http2Test.php
new file mode 100644
index 00000000..487e57ef
--- /dev/null
+++ b/tests/Unit/Node/Http2Test.php
@@ -0,0 +1,25 @@
+setLimit('maxLoopIterations', 1_000_000);
+        try {
+            $engine->execFile(__DIR__ . '/fixtures/http2.cjs');
+            $actual = json_decode((string) $engine->eval('JSON.stringify(http2Result)'), true, 512, JSON_THROW_ON_ERROR);
+            self::assertSame($expected, $actual);
+        } finally {
+            $engine->getNodeRuntime()?->close();
+        }
+    }
+}
diff --git a/tests/Unit/Node/HttpTest.php b/tests/Unit/Node/HttpTest.php
new file mode 100644
index 00000000..cc5972f6
--- /dev/null
+++ b/tests/Unit/Node/HttpTest.php
@@ -0,0 +1,107 @@
+eval(<<<'JS'
+const http = require('http');
+const result = [];
+const server = http.createServer((req, res) => {
+  res.on('close', () => {
+    result.push(res.writableFinished, res.destroyed);
+    server.close();
+  });
+  res.write('streaming');
+});
+server.listen(0, '127.0.0.1', () => {
+  const req = http.get({ host: '127.0.0.1', port: server.address().port }, res => {
+    res.once('data', () => req.destroy());
+    res.on('error', () => {});
+  });
+});
+JS);
+        self::assertSame([false, true], $engine->eval('result'));
+        $engine->reset();
+    }
+
+    public function testHttpStreamingHeadersTrailersAndBinaryBodies(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(15);
+        $engine->eval(<<<'JS'
+const http = require('http');
+const result = [];
+const server = http.createServer((req, res) => {
+  const body = [];
+  req.on('data', chunk => body.push(chunk));
+  req.on('end', () => {
+    result.push([req.method, req.url, req.headers['x-custom'], Buffer.concat(body).toString('hex')]);
+    res.setHeader('Set-Cookie', ['a=1', 'b=2']);
+    res.write(Buffer.from([255, 0]));
+    res.addTrailers({ 'X-Checksum': 'yes' });
+    res.end('done');
+  });
+}).listen(0, '127.0.0.1', () => {
+  const options = { host: '127.0.0.1', port: server.address().port, method: 'POST', path: '/echo?x=1', headers: { 'X-Custom': 'value' } };
+  const req = http.request(options, res => {
+    const chunks = [];
+    res.on('data', chunk => chunks.push(chunk));
+    res.on('end', () => {
+      result.push([res.statusCode, res.headers['set-cookie'], Buffer.concat(chunks).toString('hex'), res.trailers['x-checksum']]);
+      server.close();
+    });
+  });
+  req.write(Buffer.from([128, 255]));
+  req.end('ok');
+});
+JS);
+        self::assertSame([
+            ['POST', '/echo?x=1', 'value', '80ff6f6b'],
+            [200, ['a=1', 'b=2'], 'ff00646f6e65', 'yes'],
+        ], $engine->eval('result'));
+        $engine->reset();
+    }
+
+    public function testKeepAliveReusesRealConnectionAndHeadHasNoBody(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(15);
+        $engine->eval(<<<'JS'
+const http = require('http');
+const result = [];
+let connections = 0;
+const agent = new http.Agent({ keepAlive: true });
+const server = http.createServer((req, res) => res.end('body'));
+server.on('connection', () => connections++);
+server.listen(0, '127.0.0.1', () => {
+  const options = { host: '127.0.0.1', port: server.address().port, agent };
+  http.get(options, res => {
+    res.resume();
+    res.on('end', () => {
+      const req = http.request({ ...options, method: 'HEAD' }, res => {
+        let text = '';
+        res.on('data', chunk => text += chunk);
+        res.on('end', () => {
+          result.push(connections, req.reusedSocket, text, res.headers['content-length']);
+          agent.destroy();
+          server.close();
+        });
+      });
+      req.end();
+    });
+  });
+});
+JS);
+        self::assertSame([1, true, '', '4'], $engine->eval('result'));
+        $engine->reset();
+    }
+}
diff --git a/tests/Unit/Node/NetTest.php b/tests/Unit/Node/NetTest.php
new file mode 100644
index 00000000..8f354881
--- /dev/null
+++ b/tests/Unit/Node/NetTest.php
@@ -0,0 +1,75 @@
+eval(<<<'JS'
+const net = require('net');
+const result = [];
+const server = net.createServer().listen(0, '127.0.0.1', () => {
+  const port = server.address().port;
+  server.close(() => {
+    const client = net.connect(port, '127.0.0.1');
+    client.on('error', error => result.push(error.code, error.errno, error.syscall));
+  });
+});
+JS);
+        self::assertSame(['ECONNREFUSED', -SOCKET_ECONNREFUSED, 'connect'], $engine->eval('result'));
+        $engine->reset();
+    }
+
+    public function testRealTcpStreamingAndCloseLifecycle(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(10);
+        $engine->eval(<<<'JS'
+const net = require('net');
+const result = [];
+const server = net.createServer(socket => {
+  result.push(socket.remoteAddress === '127.0.0.1');
+  socket.on('data', data => socket.write(data));
+  socket.on('end', () => socket.end());
+});
+server.listen(0, '127.0.0.1', () => {
+  const client = net.connect(server.address().port, '127.0.0.1', () => {
+    client.setNoDelay();
+    client.write(Buffer.from([0, 255, 128, 65]));
+  });
+  const chunks = [];
+  client.on('data', data => { chunks.push(data); client.end(); });
+  client.on('end', () => result.push(Buffer.concat(chunks).toString('hex')));
+  client.on('close', () => server.close(() => result.push('closed')));
+});
+JS);
+        self::assertSame([true, '00ff8041', 'closed'], $engine->eval('result'));
+        $engine->reset();
+    }
+
+    public function testListenErrorsAndReferenceLifetime(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(10);
+        $engine->eval(<<<'JS'
+const net = require('net');
+const result = [];
+const first = net.createServer().listen(0, '127.0.0.1', () => {
+  const second = net.createServer();
+  second.on('error', error => { result.push(error.code); first.close(); });
+  second.listen(first.address().port, '127.0.0.1');
+});
+JS);
+        self::assertSame(['EADDRINUSE'], $engine->eval('result'));
+        $engine->eval('globalThis.unreferenced = require("net").createServer().listen(0, "127.0.0.1").unref();');
+        self::assertTrue($engine->eval('unreferenced.listening'));
+        $engine->reset();
+    }
+}
diff --git a/tests/Unit/Node/NodeCommandTest.php b/tests/Unit/Node/NodeCommandTest.php
new file mode 100644
index 00000000..f7457972
--- /dev/null
+++ b/tests/Unit/Node/NodeCommandTest.php
@@ -0,0 +1,81 @@
+project([
+            'value.cjs' => 'module.exports = "loaded";',
+            'entry.cjs' => <<<'JS'
+console.log('%s:%s:%s', require('./value.cjs'), require.main === module, process.argv[2]);
+console.error('stderr');
+setTimeout(() => { console.log('timer'); process.exitCode = 7; }, 1);
+JS,
+        ]);
+        [$code, $stdout, $stderr] = $this->command(['--node', $root . '/entry.cjs', '--node']);
+        self::assertSame(7, $code);
+        self::assertSame("loaded:true:--node\ntimer\n", $stdout);
+        self::assertSame("stderr\n", $stderr);
+    }
+
+    public function testEvaluationSupportsExplicitExitAndDefaultModeRemainsIsolated(): void
+    {
+        [$code, $stdout, $stderr] = $this->command([
+            '--node', '-e', 'console.log(process.argv[1]); process.exit(9); console.log("unreachable");', 'argument',
+        ]);
+        self::assertSame([9, "argument\n", ''], [$code, $stdout, $stderr]);
+        self::assertSame([0, "undefined\n", ''], $this->command(['-e', 'console.log(typeof process)']));
+    }
+
+    /**
+     * @param list $arguments
+     * @return array{int, string, string}
+     */
+    private function command(array $arguments): array
+    {
+        $root = dirname(__DIR__, 3);
+        $process = proc_open(
+            [PHP_BINARY, $root . '/bin/phasis', ...$arguments],
+            [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
+            $pipes,
+            $root,
+            [...getenv(), 'XDEBUG_MODE' => 'off'],
+        );
+        self::assertIsResource($process);
+        fclose($pipes[0]);
+        stream_set_blocking($pipes[1], false);
+        stream_set_blocking($pipes[2], false);
+        $stdout = $stderr = '';
+        $deadline = microtime(true) + 30;
+        try {
+            do {
+                $stdout .= stream_get_contents($pipes[1]);
+                $stderr .= stream_get_contents($pipes[2]);
+                $status = proc_get_status($process);
+                if (!$status['running']) {
+                    $stdout .= stream_get_contents($pipes[1]);
+                    $stderr .= stream_get_contents($pipes[2]);
+                    return [$status['exitcode'], $stdout, $stderr];
+                }
+                usleep(1000);
+            } while (microtime(true) < $deadline);
+            self::fail('CLI subprocess exceeded 30 seconds.');
+        } finally {
+            if (proc_get_status($process)['running']) {
+                proc_terminate($process, 9);
+            }
+            fclose($pipes[1]);
+            fclose($pipes[2]);
+            proc_close($process);
+        }
+    }
+}
diff --git a/tests/Unit/Node/NodeRuntimeTest.php b/tests/Unit/Node/NodeRuntimeTest.php
new file mode 100644
index 00000000..965370d4
--- /dev/null
+++ b/tests/Unit/Node/NodeRuntimeTest.php
@@ -0,0 +1,120 @@
+eval('[typeof process, typeof Buffer, typeof require].join(",")'));
+        $engine->enableNode(new NodeOptions(env: ['NODE_ENV' => 'test']));
+        self::assertSame('test:68656c6c6f', $engine->eval('process.env.NODE_ENV + ":" + Buffer.from("hello").toString("hex")'));
+    }
+
+    public function testBuiltinAliasesShareCommonJsAndModuleIdentity(): void
+    {
+        $engine = new Engine(node: true);
+        self::assertTrue($engine->eval('require("buffer") === require("node:buffer")'));
+        self::assertSame('node:buffer,buffer', $engine->eval('[require.resolve("node:buffer"), require.resolve("buffer")].join(",")'));
+        $engine->evalAsModule(<<<'JS'
+import first, { Buffer } from 'buffer';
+import second, * as ns from 'node:buffer';
+import * as plain from 'buffer';
+globalThis.nodeInterop = first === second && first.Buffer === Buffer && ns === plain;
+JS);
+        self::assertTrue($engine->eval('nodeInterop'));
+        self::assertTrue($engine->eval(<<<'JS'
+process.getBuiltinModule('node:buffer') === require('buffer')
+  && process.getBuiltinModule('unavailable-module') === undefined;
+JS));
+        self::assertSame('ERR_INVALID_ARG_TYPE', $engine->eval(<<<'JS'
+try { process.getBuiltinModule(null); } catch (error) { error.code; }
+JS));
+    }
+
+    public function testNextTicksRunAroundPromiseBatchesWithAsyncContext(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->eval(<<<'JS'
+const { AsyncLocalStorage } = require('node:async_hooks');
+const storage = new AsyncLocalStorage();
+const order = [];
+storage.run('context', () => {
+  Promise.resolve().then(() => {
+    order.push('promise:' + storage.getStore());
+    process.nextTick(() => order.push('nested'));
+  });
+  process.nextTick(() => {
+    order.push('tick:' + storage.getStore());
+    process.nextTick(() => order.push('nested-tick'));
+  });
+  queueMicrotask(() => order.push('micro'));
+});
+JS);
+        self::assertSame('tick:context,nested-tick,promise:context,micro,nested', $engine->eval('order.join(",")'));
+        self::assertSame('undefined', $engine->eval('typeof storage.getStore()'));
+    }
+
+    public function testAsyncLocalStorageRestoresThrowsAndDistinguishesUndefinedFromDefault(): void
+    {
+        $engine = new Engine(node: true);
+        $engine->eval(<<<'JS'
+const { AsyncLocalStorage } = require('async_hooks');
+const storage = new AsyncLocalStorage({ defaultValue: 'default', name: 'request' });
+const result = [];
+result.push(storage.getStore());
+storage.run('outer', () => {
+  result.push(storage.run(undefined, () => typeof storage.getStore()));
+  try { storage.run('inner', () => { throw new Error('stop'); }); } catch {}
+  result.push(storage.getStore());
+});
+result.push(storage.getStore(), storage.name);
+JS);
+        self::assertSame('default,undefined,outer,default,request', $engine->eval('result.join(",")'));
+    }
+
+    public function testWorkingDirectoryAndEnvironmentAreOwnedByTheRealm(): void
+    {
+        $cwd = getcwd();
+        $engine = new Engine();
+        $engine->enableNode(new NodeOptions(cwd: __DIR__, env: ['ONLY_THIS' => 'yes']));
+        self::assertSame(__DIR__, $engine->eval('process.cwd()'));
+        self::assertSame('yes', $engine->eval('process.env.ONLY_THIS'));
+        $engine->eval('process.chdir(".."); process.env.ONLY_THIS = "changed";');
+        self::assertSame(dirname(__DIR__), $engine->eval('process.cwd()'));
+        self::assertSame($cwd, getcwd());
+        $engine->reset();
+        self::assertSame(__DIR__, $engine->eval('process.cwd()'));
+        self::assertSame('yes', $engine->eval('process.env.ONLY_THIS'));
+    }
+
+    public function testCloseReleasesEveryResourceEvenIfOneCleanupFails(): void
+    {
+        $engine = new Engine(node: true);
+        $runtime = $engine->getNodeRuntime();
+        self::assertNotNull($runtime);
+        $closed = [];
+        $runtime->onClose(static function () use (&$closed): void {
+            $closed[] = 'first';
+        });
+        $runtime->onClose(static function () use (&$closed): void {
+            $closed[] = 'second';
+            throw new \RuntimeException('cleanup failure');
+        });
+        try {
+            $engine->close();
+            self::fail('The cleanup exception must reach the host.');
+        } catch (\RuntimeException $error) {
+            self::assertSame('cleanup failure', $error->getMessage());
+        }
+        $engine->close();
+        self::assertSame(['second', 'first'], $closed);
+    }
+}
diff --git a/tests/Unit/Node/PortableModulesTest.php b/tests/Unit/Node/PortableModulesTest.php
new file mode 100644
index 00000000..1af512a1
--- /dev/null
+++ b/tests/Unit/Node/PortableModulesTest.php
@@ -0,0 +1,53 @@
+assertOracle('portable', 'portableResult');
+    }
+
+    public function testCryptographicOperationsMatchPinnedNodeOracle(): void
+    {
+        $this->assertOracle('crypto', 'cryptoResult');
+    }
+
+    public function testPathNormalizationMatchesDeterministicNodeCorpus(): void
+    {
+        $this->assertOracle('path-normalization', 'pathNormalizationResult');
+    }
+
+    public function testOsUsesRealmEnvironmentAndProvidesEncodedUserInfo(): void
+    {
+        $engine = new Engine();
+        $engine->enableNode(new NodeOptions(env: ['HOME' => '/configured/home', 'TMPDIR' => '/configured/tmp/']));
+        self::assertSame('/configured/home:/configured/tmp', $engine->eval('require("os").homedir() + ":" + require("os").tmpdir()'));
+        self::assertTrue($engine->eval(<<<'JS'
+const os = require('os');
+const plain = os.userInfo();
+const encoded = os.userInfo({ encoding: 'buffer' });
+Buffer.isBuffer(encoded.username) && encoded.username.toString() === plain.username &&
+  encoded.homedir.toString() === plain.homedir && encoded.uid === plain.uid;
+JS));
+    }
+
+    private function assertOracle(string $fixture, string $global): void
+    {
+        $expected = json_decode((string) file_get_contents(__DIR__ . '/fixtures/' . $fixture . '.json'), true, 512, JSON_THROW_ON_ERROR);
+        $engine = new Engine(node: true);
+        $engine->execFile(__DIR__ . '/fixtures/' . $fixture . '.cjs');
+        $actual = json_decode((string) $engine->eval('JSON.stringify(' . $global . ')'), true, 512, JSON_THROW_ON_ERROR);
+        if (isset($actual['async'])) {
+            usort($actual['async'], static fn (array $a, array $b): int => $a[0] <=> $b[0]);
+        }
+        self::assertSame($expected, $actual);
+    }
+}
diff --git a/tests/Unit/Node/PrimitivesTest.php b/tests/Unit/Node/PrimitivesTest.php
new file mode 100644
index 00000000..67b2f497
--- /dev/null
+++ b/tests/Unit/Node/PrimitivesTest.php
@@ -0,0 +1,32 @@
+ */
+    public static function modules(): iterable
+    {
+        foreach (['buffer', 'events', 'stream', 'stream-web'] as $name) {
+            yield $name => [$name];
+        }
+    }
+
+    #[DataProvider('modules')]
+    public function testPrimitivesMatchNodeOracle(string $name): void
+    {
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(20);
+        $engine->execFile(__DIR__ . '/fixtures/primitives/' . $name . '.mjs');
+        self::assertNull($engine->eval('globalThis.__nodePrimitiveError'), $engine->getConsoleOutput());
+        $result = $engine->eval('globalThis.__nodePrimitiveResult');
+        self::assertIsString($result, 'The asynchronous probe must finish.');
+        self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/primitives/' . $name . '.json', $result);
+    }
+}
diff --git a/tests/Unit/Node/TimersTest.php b/tests/Unit/Node/TimersTest.php
new file mode 100644
index 00000000..473e3cb5
--- /dev/null
+++ b/tests/Unit/Node/TimersTest.php
@@ -0,0 +1,85 @@
+eval(<<<'JS'
+const results = [];
+let count = 0;
+const timer = setTimeout(function (value) {
+  results.push(this === timer, value, ++count);
+  Promise.resolve().then(() => results.push('micro'));
+  if (count === 1) this.refresh();
+}, 1, 'argument');
+const id = Number(timer);
+results.push(timer.unref() === timer, timer.hasRef(), timer.ref() === timer, timer.hasRef());
+const cancelled = setTimeout(() => results.push('cancelled'), 1000);
+clearTimeout(Number(cancelled));
+JS);
+            self::assertSame(
+                [true, false, true, true, true, 'argument', 1, 'micro', true, 'argument', 2, 'micro'],
+                $engine->eval('results'),
+            );
+            self::assertTrue($engine->eval('id === Number(timer)'));
+            self::assertSame(0, $engine->pendingTaskCount());
+        } finally {
+            $engine->close();
+        }
+    }
+
+    public function testTopLevelAwaitCanResumeFromARealTimer(): void
+    {
+        $engine = new Engine(node: true);
+        try {
+            $engine->evalAsModule(<<<'JS'
+import { setTimeout } from 'node:timers/promises';
+globalThis.completedTimer = await setTimeout(1, 'done');
+JS);
+            self::assertSame('done', $engine->eval('completedTimer'));
+        } finally {
+            $engine->close();
+        }
+    }
+
+    public function testReadyIoCannotStarveTimersAndCloseCancelsUnreferencedWork(): void
+    {
+        $engine = new Engine(node: true);
+        $loop = $engine->getEventLoop();
+        $polls = 0;
+        $timerRan = false;
+        $loop->addIoDriver('busy-test', static function (int $timeout) use (&$polls): bool {
+            $polls++;
+            return true;
+        }, static fn (): bool => true);
+        $loop->setTimeout(JsFunction::fromCallable('stop', static function () use ($loop, &$timerRan): JsUndefined {
+            $timerRan = true;
+            $loop->removeIoDriver('busy-test');
+            return JsUndefined::instance();
+        }), 0);
+        try {
+            $engine->runEventLoop();
+            self::assertTrue($timerRan);
+            self::assertGreaterThan(0, $polls);
+            self::assertLessThan(100, $polls, 'A busy I/O source must yield to due timers.');
+            $engine->eval('setTimeout(() => { throw new Error("unreferenced"); }, 60000).unref()');
+            self::assertSame(1, $engine->pendingTaskCount());
+            $engine->close();
+            $engine->close();
+            self::assertSame(0, $engine->pendingTaskCount());
+        } finally {
+            $engine->close();
+        }
+    }
+}
diff --git a/tests/Unit/Node/TlsTest.php b/tests/Unit/Node/TlsTest.php
new file mode 100644
index 00000000..0160145b
--- /dev/null
+++ b/tests/Unit/Node/TlsTest.php
@@ -0,0 +1,131 @@
+certificate();
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(10);
+        $engine->setGlobal('privateKey', $key);
+        $engine->setGlobal('certificate', $certificate);
+        try {
+            $engine->eval(<<<'JS'
+const https = require('https');
+var received, failure;
+const server = https.createServer({ key: privateKey, cert: certificate }, (request, response) => {
+  response.end(request.method + ':' + request.url + ':' + request.socket.encrypted);
+});
+server.on('tlsClientError', error => { failure = error.message; });
+server.listen(0, '127.0.0.1', () => {
+  const request = https.get({ host: '127.0.0.1', port: server.address().port, path: '/tls',
+    ca: certificate, servername: 'localhost', agent: false }, response => {
+    let body = '';
+    const socket = response.socket;
+    response.setEncoding('utf8');
+    response.on('data', chunk => { body += chunk; });
+    response.on('end', () => {
+      received = [body, socket.encrypted, socket.authorized, socket.getPeerCertificate().subject.CN, socket.getProtocol().startsWith('TLSv1.')];
+      server.close();
+    });
+  });
+  request.on('error', error => { failure = error.message; server.close(); });
+});
+JS);
+            self::assertSame('undefined', $engine->eval('typeof failure'), (string) $engine->eval('failure'));
+            self::assertSame('["GET:/tls:true",true,true,"localhost",true]', $engine->eval('JSON.stringify(received)'));
+        } finally {
+            $engine->getNodeRuntime()?->close();
+        }
+    }
+
+    public function testUntrustedCertificateRejectsTheClientConnection(): void
+    {
+        [$key, $certificate] = $this->certificate();
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(10);
+        $engine->setGlobal('privateKey', $key);
+        $engine->setGlobal('certificate', $certificate);
+        try {
+            $engine->eval(<<<'JS'
+const tls = require('tls');
+var rejected = false, connected = false, rejection;
+const server = tls.createServer({ key: privateKey, cert: certificate }, socket => socket.end('secret'));
+server.on('tlsClientError', () => {});
+server.listen(0, '127.0.0.1', () => {
+  const client = tls.connect({ host: '127.0.0.1', port: server.address().port, servername: 'localhost' });
+  client.on('secureConnect', () => { connected = true; client.destroy(); server.close(); });
+  client.on('error', error => { rejection = error.message; rejected = /certificate/i.test(error.message); server.close(); });
+});
+JS);
+            self::assertTrue($engine->eval('rejected'), (string) $engine->eval('rejection'));
+            self::assertFalse($engine->eval('connected'));
+        } finally {
+            $engine->getNodeRuntime()?->close();
+        }
+    }
+
+    public function testTlsServerVerifiesAnAuthenticatedClient(): void
+    {
+        [$key, $certificate] = $this->certificate();
+        $clientKey = openssl_pkey_new(['private_key_type' => OPENSSL_KEYTYPE_RSA, 'private_key_bits' => 2048]);
+        self::assertNotFalse($clientKey);
+        $clientRequest = openssl_csr_new(['commonName' => 'client'], $clientKey, ['digest_alg' => 'sha256']);
+        self::assertNotFalse($clientRequest);
+        $clientCertificate = openssl_csr_sign($clientRequest, $certificate, $key, 1, ['digest_alg' => 'sha256']);
+        self::assertNotFalse($clientCertificate);
+        $clientKeyPem = $clientCertificatePem = '';
+        self::assertTrue(openssl_pkey_export($clientKey, $clientKeyPem));
+        self::assertTrue(openssl_x509_export($clientCertificate, $clientCertificatePem));
+        $engine = new Engine(node: true);
+        $engine->setExecutionBudget(10);
+        $engine->setGlobal('privateKey', $key);
+        $engine->setGlobal('certificate', $certificate);
+        $engine->setGlobal('clientKey', $clientKeyPem);
+        $engine->setGlobal('clientCertificate', $clientCertificatePem);
+        try {
+            $engine->eval(<<<'JS'
+const tls = require('tls');
+var authenticated, echoed, failure;
+const server = tls.createServer({ key: privateKey, cert: certificate, ca: certificate, requestCert: true }, socket => {
+  authenticated = [socket.authorized, socket.getPeerCertificate().subject.CN];
+  socket.on('data', data => socket.end(data));
+});
+server.on('tlsClientError', error => { failure = error.message; server.close(); });
+server.listen(0, '127.0.0.1', () => {
+  const client = tls.connect({ host: '127.0.0.1', port: server.address().port, servername: 'localhost',
+    key: clientKey, cert: clientCertificate, ca: certificate }, () => client.write('authenticated'));
+  client.on('data', data => { echoed = data.toString(); client.destroy(); server.close(); });
+  client.on('error', error => { failure = error.message; server.close(); });
+});
+JS);
+            self::assertSame('undefined', $engine->eval('typeof failure'), (string) $engine->eval('failure'));
+            self::assertSame('[true,"client"]', $engine->eval('JSON.stringify(authenticated)'));
+            self::assertSame('authenticated', $engine->eval('echoed'));
+        } finally {
+            $engine->getNodeRuntime()?->close();
+        }
+    }
+
+    /** @return array{string, string} */
+    private function certificate(): array
+    {
+        $privateKey = openssl_pkey_new(['private_key_type' => OPENSSL_KEYTYPE_RSA, 'private_key_bits' => 2048]);
+        self::assertNotFalse($privateKey);
+        $request = openssl_csr_new(['commonName' => 'localhost'], $privateKey, ['digest_alg' => 'sha256']);
+        self::assertNotFalse($request);
+        $certificate = openssl_csr_sign($request, null, $privateKey, 1, ['digest_alg' => 'sha256']);
+        self::assertNotFalse($certificate);
+        $keyPem = $certificatePem = '';
+        self::assertTrue(openssl_pkey_export($privateKey, $keyPem));
+        self::assertTrue(openssl_x509_export($certificate, $certificatePem));
+        return [$keyPem, $certificatePem];
+    }
+}
diff --git a/tests/Unit/Node/VmTest.php b/tests/Unit/Node/VmTest.php
new file mode 100644
index 00000000..16c8f87d
--- /dev/null
+++ b/tests/Unit/Node/VmTest.php
@@ -0,0 +1,50 @@
+setExecutionBudget(30);
+        $engine->execFile(__DIR__ . '/fixtures/primitives/vm.mjs');
+        self::assertNull($engine->eval('globalThis.__nodePrimitiveError'), $engine->getConsoleOutput());
+        $result = $engine->eval('globalThis.__nodePrimitiveResult');
+        self::assertIsString($result, 'Outer microtasks, nextTicks and timers must keep running.');
+        self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/primitives/vm.json', $result);
+    }
+
+    public function testContextTimeoutDoesNotPoisonParentOrLaterRuns(): void
+    {
+        $engine = new Engine(node: true);
+        self::assertSame('ERR_SCRIPT_EXECUTION_TIMEOUT:7:9', $engine->eval(<<<'JS'
+const vm = require('vm');
+let code;
+try { vm.runInThisContext('while (true) {}', { timeout: 1 }); } catch (error) { code = error.code; }
+[code, vm.runInThisContext('3 + 4'), vm.runInNewContext('4 + 5')].join(':');
+JS));
+    }
+
+    public function testUnreferencedContextCanBeCollectedWhileItsParentRuntimeRemainsAlive(): void
+    {
+        $engine = new Engine(node: true);
+        $sandbox = new \Phasis\Value\JsObject();
+        $reference = \WeakReference::create($sandbox);
+        $engine->setGlobalJsValue('temporarySandbox', $sandbox);
+        $engine->eval("require('vm').createContext(temporarySandbox);");
+        $engine->setGlobalJsValue('temporarySandbox', \Phasis\Value\JsUndefined::instance());
+        unset($sandbox);
+        // Native intrinsic defaults may retain the most recently installed
+        // realm. Older unreachable sandboxes must not accumulate in the registry.
+        $engine->eval("for (let index = 0; index < 3; index++) require('vm').createContext({});");
+        gc_collect_cycles();
+        self::assertNull($reference->get());
+        self::assertSame(3, $engine->eval("require('vm').runInNewContext('1 + 2')"));
+    }
+}
diff --git a/tests/Unit/Node/ZlibTest.php b/tests/Unit/Node/ZlibTest.php
new file mode 100644
index 00000000..211c5ed6
--- /dev/null
+++ b/tests/Unit/Node/ZlibTest.php
@@ -0,0 +1,31 @@
+execFile(__DIR__ . '/fixtures/primitives/zlib.mjs');
+        self::assertNull($engine->eval('globalThis.__nodePrimitiveError'), $engine->getConsoleOutput());
+        $result = $engine->eval('globalThis.__nodePrimitiveResult');
+        self::assertIsString($result, 'Every codec stream must finish.');
+        self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/primitives/zlib.json', $result);
+    }
+
+    public function testGzipOutputIsReadableByNativePhpZlib(): void
+    {
+        $engine = new Engine(node: true);
+        $hex = $engine->eval('require("zlib").gzipSync(Buffer.from([0, 127, 128, 255])).toString("hex")');
+        self::assertIsString($hex);
+        $data = hex2bin($hex);
+        self::assertIsString($data);
+        self::assertSame("\0\x7f\x80\xff", gzdecode($data));
+    }
+}
diff --git a/tests/Unit/Node/fixtures/crypto.cjs b/tests/Unit/Node/fixtures/crypto.cjs
new file mode 100644
index 00000000..b3ed5b97
--- /dev/null
+++ b/tests/Unit/Node/fixtures/crypto.cjs
@@ -0,0 +1,40 @@
+'use strict';
+
+const crypto = require('node:crypto');
+const { Readable } = require('node:stream');
+const out = {};
+out.hashes = [crypto.createHash('sha1').update('abc').digest('base64'),
+  crypto.createHash('sha256').update(Buffer.from([0, 255, 128])).digest('hex'),
+  crypto.createHash('sha512').update(new DataView(Uint8Array.from([1, 2, 3]).buffer, 1)).digest('hex'),
+  crypto.hash('sha256', 'abc'), crypto.hash('sha1', 'abc', 'buffer').toString('hex')];
+const hash = crypto.createHash('sha256').update('first');
+out.copy = [hash.copy().update('copy').digest('hex'), hash.update('original').digest('hex')];
+out.hmac = [crypto.createHmac('sha256', 'key').update('message').digest('hex'),
+  crypto.createHmac('sha256', '').update('').digest('base64')];
+const hmac = crypto.createHmac('sha1', 'a'); hmac.digest();
+out.hmac.push(hmac.digest('hex'));
+out.pbkdf2 = crypto.pbkdf2Sync('password', 'salt', 3, 32, 'sha256').toString('hex');
+out.hkdf = [Buffer.from(crypto.hkdfSync('sha256', '', '', '', 8)).toString('hex'),
+  Buffer.from(crypto.hkdfSync('sha256', 'key', 'salt', 'info', 42)).toString('hex')];
+out.equal = [crypto.timingSafeEqual(Buffer.from([1, 2]), Uint8Array.from([1, 2])),
+  crypto.timingSafeEqual(Buffer.from([1, 2]), Uint8Array.from([1, 3]))];
+out.random = [Buffer.isBuffer(crypto.randomBytes(16)), crypto.randomBytes(0).length,
+  /^[\da-f]{8}-[\da-f]{4}-4[\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}$/.test(crypto.randomUUID()),
+  crypto.randomInt(4, 5)];
+const target = new Uint16Array([1234, 0, 4321]);
+out.random.push(crypto.randomFillSync(target, 1, 1) === target, target[0], target[2]);
+out.identity = [crypto.webcrypto === globalThis.crypto, crypto.subtle === globalThis.crypto.subtle];
+out.errors = [];
+for (const fn of [() => hash.update('x'), () => hash.digest(),
+  () => crypto.randomBytes(-1), () => crypto.randomInt(2, 2),
+  () => crypto.timingSafeEqual(Buffer.alloc(1), Buffer.alloc(2)),
+  () => crypto.randomFillSync(new Uint16Array(2), 2, 1)]) {
+  try { fn(); out.errors.push('unexpected pass'); } catch (error) { out.errors.push([error.name, error.code]); }
+}
+out.async = [];
+crypto.randomBytes(0, (error, value) => out.async.push(['random', error, value.length]));
+crypto.pbkdf2('p', 's', 1, 8, 'sha256', (error, value) => out.async.push(['pbkdf2', error, value.toString('hex')]));
+const stream = crypto.createHash('sha256');
+stream.on('data', value => { out.stream = value.toString('hex'); });
+Readable.from(['a', 'b', 'c']).pipe(stream);
+globalThis.cryptoResult = out;
diff --git a/tests/Unit/Node/fixtures/crypto.json b/tests/Unit/Node/fixtures/crypto.json
new file mode 100644
index 00000000..c053feeb
--- /dev/null
+++ b/tests/Unit/Node/fixtures/crypto.json
@@ -0,0 +1,79 @@
+{
+  "hashes": [
+    "qZk+NkcGgWq6PiVxeFDCbJzQ2J0=",
+    "f742b965f156c10374bc23aea96e3a8aff8facd6fc079defeaa30219ad86f211",
+    "905458d59155883bb6a62bd52c7bd3b8e67e9326fff5de0e3c374b78d012170c5da3b0ab125b9969b6b6ac09ad4baeb39bb42fa7c6373250c7c8cce5a92e8ec0",
+    "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
+    "a9993e364706816aba3e25717850c26c9cd0d89d"
+  ],
+  "copy": [
+    "d00b165959fc320ec37d8253e6c56e17d5a0a61adcf32e6c9ed808a9aa378d76",
+    "c88f21611d1ea6b8d24106d291755e119a43c7e1c52eee79d3514d7df3903f20"
+  ],
+  "hmac": [
+    "6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a",
+    "thNnmggU2ex3L5XXeMNfxf8Wl8STcVZTxscSFEKSxa0=",
+    ""
+  ],
+  "pbkdf2": "ad35240ac683febfaf3cd49d845473fbbbaa2437f5f82d5a415ae00ac76c6bfc",
+  "hkdf": [
+    "eb70f01dede9afaf",
+    "9ca0d662557439e3b83365f2da4626d35da195c6d9d1779f09838cf9e408966ece99106e2585ace6f083"
+  ],
+  "equal": [
+    true,
+    false
+  ],
+  "random": [
+    true,
+    0,
+    true,
+    4,
+    true,
+    1234,
+    4321
+  ],
+  "identity": [
+    true,
+    true
+  ],
+  "errors": [
+    [
+      "Error",
+      "ERR_CRYPTO_HASH_FINALIZED"
+    ],
+    [
+      "Error",
+      "ERR_CRYPTO_HASH_FINALIZED"
+    ],
+    [
+      "RangeError",
+      "ERR_OUT_OF_RANGE"
+    ],
+    [
+      "RangeError",
+      "ERR_OUT_OF_RANGE"
+    ],
+    [
+      "RangeError",
+      "ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH"
+    ],
+    [
+      "RangeError",
+      "ERR_OUT_OF_RANGE"
+    ]
+  ],
+  "async": [
+    [
+      "pbkdf2",
+      null,
+      "372cc9815244c4a2"
+    ],
+    [
+      "random",
+      null,
+      0
+    ]
+  ],
+  "stream": "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
+}
diff --git a/tests/Unit/Node/fixtures/http2.cjs b/tests/Unit/Node/fixtures/http2.cjs
new file mode 100644
index 00000000..2bad8f6b
--- /dev/null
+++ b/tests/Unit/Node/fixtures/http2.cjs
@@ -0,0 +1,43 @@
+'use strict';
+
+const http2 = require('http2');
+const crypto = require('crypto');
+const result = { responses: [], ping: false, errors: [] };
+globalThis.http2Result = result;
+const server = http2.createServer();
+server.on('sessionError', error => result.errors.push(error.message));
+server.on('stream', (stream, headers) => {
+  const chunks = [];
+  stream.on('error', error => result.errors.push(error.message));
+  stream.on('data', chunk => chunks.push(chunk));
+  stream.on('end', () => {
+    stream.respond({ ':status': 201, 'x-echo': headers['x-repeat'], 'set-cookie': ['a=1', 'b=2'] }, { waitForTrailers: true });
+    stream.on('wantTrailers', () => stream.sendTrailers({ 'x-complete': 'yes' }));
+    stream.end(Buffer.concat(chunks));
+  });
+});
+server.listen(0, '127.0.0.1', () => {
+  const client = http2.connect('http://127.0.0.1:' + server.address().port);
+  client.on('error', error => { result.errors.push(error.message); client.destroy(); server.close(); });
+  client.on('connect', () => {
+    client.ping(Buffer.from('abcdefgh'), (error, duration, payload) => {
+      if (error) result.errors.push(error.message);
+      else result.ping = payload.toString() === 'abcdefgh' && duration >= 0;
+    });
+    for (let i = 0; i < 3; i++) {
+      const request = client.request({ ':method': 'POST', ':path': '/body/' + i, 'x-repeat': 'header compression across requests' });
+      const chunks = [], response = { id: i };
+      request.on('error', error => result.errors.push(error.message));
+      request.on('response', headers => { response.status = headers[':status']; response.echo = headers['x-echo']; response.cookies = headers['set-cookie']; });
+      request.on('trailers', trailers => { response.trailer = trailers['x-complete']; });
+      request.on('data', chunk => chunks.push(chunk));
+      request.on('end', () => {
+        const body = Buffer.concat(chunks);
+        response.length = body.length; response.hash = crypto.createHash('sha256').update(body).digest('hex');
+        result.responses.push(response);
+        if (result.responses.length === 3) { result.responses.sort((a, b) => a.id - b.id); client.close(); server.close(); }
+      });
+      request.end(Buffer.alloc(100000 + i * 111, 65 + i));
+    }
+  });
+});
diff --git a/tests/Unit/Node/fixtures/http2.json b/tests/Unit/Node/fixtures/http2.json
new file mode 100644
index 00000000..d85ae3da
--- /dev/null
+++ b/tests/Unit/Node/fixtures/http2.json
@@ -0,0 +1,42 @@
+{
+  "responses": [
+    {
+      "id": 0,
+      "status": 201,
+      "echo": "header compression across requests",
+      "cookies": [
+        "a=1",
+        "b=2"
+      ],
+      "trailer": "yes",
+      "length": 100000,
+      "hash": "e6631225e83d23bf67657e85109ad5deb3570e1405d7aaa23a2485ae8582c143"
+    },
+    {
+      "id": 1,
+      "status": 201,
+      "echo": "header compression across requests",
+      "cookies": [
+        "a=1",
+        "b=2"
+      ],
+      "trailer": "yes",
+      "length": 100111,
+      "hash": "d9aeb094db48c0daa051c9ba00cd149d7cc4309711b8823743fd162609107697"
+    },
+    {
+      "id": 2,
+      "status": 201,
+      "echo": "header compression across requests",
+      "cookies": [
+        "a=1",
+        "b=2"
+      ],
+      "trailer": "yes",
+      "length": 100222,
+      "hash": "f3165a334614e6059997db00e529a5bedc2c742f46a8611a821e3ad35da0fc14"
+    }
+  ],
+  "ping": true,
+  "errors": []
+}
diff --git a/tests/Unit/Node/fixtures/path-normalization.cjs b/tests/Unit/Node/fixtures/path-normalization.cjs
new file mode 100644
index 00000000..ae28c689
--- /dev/null
+++ b/tests/Unit/Node/fixtures/path-normalization.cjs
@@ -0,0 +1,32 @@
+'use strict';
+
+const path = require('node:path');
+const crypto = require('node:crypto');
+let seed = 0x6a09e667;
+function random() { seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0; return seed; }
+const segments = ['', '.', '..', '...', 'a', 'foo', 'a..', '.a', 'é', 'e\u0301', '😀', '\ud800', '\udfff', 'C:', 'D:', '?'];
+const inputs = ['', '.', '..', '../..', '/', '//', '///', '/..', '/a/../../b', 'a//b/../',
+  'C:\\', 'C:..', 'C:/a/../../b', '\\\\server\\share\\a\\..', '\\\\?\\C:\\a\\..',
+  '\\\\?\\UNC\\server\\share\\a\\..', 'a\\..\\b', 'a/..\\b', '/\ud800/../\udfff/'];
+for (let i = 0; i < 256; i++) {
+  let input = '';
+  const count = random() % 12 + 1;
+  for (let j = 0; j < count; j++) {
+    input += segments[random() % segments.length];
+    input += ['/', '\\', '//', '\\\\', '', '/\\'][random() % 6];
+  }
+  inputs.push(input);
+}
+function units(value) {
+  const result = [];
+  for (let i = 0; i < value.length; i++) result.push(value.charCodeAt(i).toString(16));
+  return result.join('.');
+}
+function digest(value) { return crypto.createHash('sha256').update(value).digest('hex'); }
+const results = inputs.map(input => [
+  units(path.posix.normalize(input)), units(path.win32.normalize(input)),
+  units(path.posix.resolve('/base', input)), units(path.win32.resolve('C:\\base', input)),
+]);
+const long = '/base' + '/foobar'.repeat(10000) + '/../tail';
+results.push([digest(path.posix.normalize(long)), digest(path.win32.normalize(long))]);
+globalThis.pathNormalizationResult = results;
diff --git a/tests/Unit/Node/fixtures/path-normalization.json b/tests/Unit/Node/fixtures/path-normalization.json
new file mode 100644
index 00000000..5c9d5d19
--- /dev/null
+++ b/tests/Unit/Node/fixtures/path-normalization.json
@@ -0,0 +1,1656 @@
+[
+  [
+    "2e",
+    "2e",
+    "2f.62.61.73.65",
+    "43.3a.5c.62.61.73.65"
+  ],
+  [
+    "2e",
+    "2e",
+    "2f.62.61.73.65",
+    "43.3a.5c.62.61.73.65"
+  ],
+  [
+    "2e.2e",
+    "2e.2e",
+    "2f",
+    "43.3a.5c"
+  ],
+  [
+    "2e.2e.2f.2e.2e",
+    "2e.2e.5c.2e.2e",
+    "2f",
+    "43.3a.5c"
+  ],
+  [
+    "2f",
+    "5c",
+    "2f",
+    "43.3a.5c"
+  ],
+  [
+    "2f",
+    "5c",
+    "2f",
+    "43.3a.5c"
+  ],
+  [
+    "2f",
+    "5c",
+    "2f",
+    "43.3a.5c"
+  ],
+  [
+    "2f",
+    "5c",
+    "2f",
+    "43.3a.5c"
+  ],
+  [
+    "2f.62",
+    "5c.62",
+    "2f.62",
+    "43.3a.5c.62"
+  ],
+  [
+    "61.2f",
+    "61.5c",
+    "2f.62.61.73.65.2f.61",
+    "43.3a.5c.62.61.73.65.5c.61"
+  ],
+  [
+    "43.3a.5c",
+    "43.3a.5c",
+    "2f.62.61.73.65.2f.43.3a.5c",
+    "43.3a.5c"
+  ],
+  [
+    "43.3a.2e.2e",
+    "43.3a.2e.2e",
+    "2f.62.61.73.65.2f.43.3a.2e.2e",
+    "43.3a.5c"
+  ],
+  [
+    "62",
+    "43.3a.5c.62",
+    "2f.62.61.73.65.2f.62",
+    "43.3a.5c.62"
+  ],
+  [
+    "5c.5c.73.65.72.76.65.72.5c.73.68.61.72.65.5c.61.5c.2e.2e",
+    "5c.5c.73.65.72.76.65.72.5c.73.68.61.72.65.5c",
+    "2f.62.61.73.65.2f.5c.5c.73.65.72.76.65.72.5c.73.68.61.72.65.5c.61.5c.2e.2e",
+    "5c.5c.73.65.72.76.65.72.5c.73.68.61.72.65.5c"
+  ],
+  [
+    "5c.5c.3f.5c.43.3a.5c.61.5c.2e.2e",
+    "5c.5c.3f.5c.43.3a",
+    "2f.62.61.73.65.2f.5c.5c.3f.5c.43.3a.5c.61.5c.2e.2e",
+    "5c.5c.3f.5c.43.3a"
+  ],
+  [
+    "5c.5c.3f.5c.55.4e.43.5c.73.65.72.76.65.72.5c.73.68.61.72.65.5c.61.5c.2e.2e",
+    "5c.5c.3f.5c.55.4e.43.5c.73.65.72.76.65.72.5c.73.68.61.72.65",
+    "2f.62.61.73.65.2f.5c.5c.3f.5c.55.4e.43.5c.73.65.72.76.65.72.5c.73.68.61.72.65.5c.61.5c.2e.2e",
+    "5c.5c.3f.5c.55.4e.43.5c.73.65.72.76.65.72.5c.73.68.61.72.65"
+  ],
+  [
+    "61.5c.2e.2e.5c.62",
+    "62",
+    "2f.62.61.73.65.2f.61.5c.2e.2e.5c.62",
+    "43.3a.5c.62.61.73.65.5c.62"
+  ],
+  [
+    "61.2f.2e.2e.5c.62",
+    "62",
+    "2f.62.61.73.65.2f.61.2f.2e.2e.5c.62",
+    "43.3a.5c.62.61.73.65.5c.62"
+  ],
+  [
+    "2f.dfff.2f",
+    "5c.dfff.5c",
+    "2f.dfff",
+    "43.3a.5c.dfff"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "2e.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.2f.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.5c.5c.61.2e.2e.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f",
+    "d800.5c.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2e.2f.d800.2f.66.6f.6f.2f",
+    "65.301.5c.2e.2e.2e.5c.43.3a.2e.61.2e.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.2e.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f",
+    "d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2e.2f.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2e.2f.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.5c.dfff.5c.44.3a.2f.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.5c.dfff.5c.44.3a.2f.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "2e.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f",
+    "d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.44.3a.5c.5c.2f.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.44.3a.5c.5c.2f.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.2f",
+    "2e.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2e.61.2f.d800.2f.66.6f.6f",
+    "d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a.2e.61.5c.d800.5c.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.2f.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.2f.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.2f.5c.2e.2e.2f.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.2f.5c.2e.2e.2f.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f",
+    "2e.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "2e.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.2e.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.2e.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.2e.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.2e.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.44.3a.2f.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.44.3a.2f.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "2e.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f",
+    "2e.5c.d800.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.43.3a",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.43.3a",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.66.6f.6f",
+    "65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.66.6f.6f",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.2e.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f",
+    "d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "2e.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.2f.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.61.2e.2e.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.2f",
+    "d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.2f.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f.2f",
+    "2e.5c.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2f.2e.d800.66.6f.6f.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.5c.2e.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2f.2e.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.5c.2e.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.2f.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.2f.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.2e.d800.66.6f.6f.2f",
+    "2e.5c.d800.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.2e.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.2e.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.2e.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.2e.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.2e.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.2f.5c.44.3a.5c.2f.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.2f.5c.44.3a.5c.2f.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.5c.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f",
+    "d800.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.2f.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.e9.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.2f.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.e9.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.3f.65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.3f.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.3f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.3f.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.2f",
+    "2e.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f",
+    "d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.44.3a.5c.2f.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.44.3a.2f.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.44.3a.5c.2f.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.44.3a.2f.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.44.3a.2f.5c.5c.2e.2e.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.44.3a.2f.5c.5c.2e.2e.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f",
+    "d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.2f.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.2f.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.2e.d800.2f.66.6f.6f.2f",
+    "2e.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.2e.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f.2f",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2e.61.2f.2e.d800.2f.66.6f.6f",
+    "d800.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.43.3a.2e.61.5c.2e.d800.5c.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2e.61.2f.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.43.3a.2e.61.5c.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.5c.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.66.6f.6f.3f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f.2f",
+    "2e.5c.2e.d800.66.6f.6f.3f.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.66.6f.6f.3f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.66.6f.6f.3f.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f",
+    "2e.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.d800.66.6f.6f.2f",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.44.3a.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.44.3a.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "2e.5c.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.dfff.5c.44.3a.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.dfff.5c.44.3a.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.2f.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.2e.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.2f.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.2f.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f",
+    "d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.5c.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.3f.65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.3f.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.3f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.3f.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.44.3a.2f.5c.5c.2e.2e.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.44.3a.2f.5c.5c.2e.2e.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.d800.66.6f.6f.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.d800.66.6f.6f.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.5c.44.3a.5c.2f.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.5c.44.3a.5c.2f.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "65.301.2e.2e.2e.5c.43.3a.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.5c.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.3f.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.3f.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.66.6f.6f.2f",
+    "2e.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c.2f.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c.2f.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.66.6f.6f.2f",
+    "2e.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.66.6f.6f.2f",
+    "2e.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "2e.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.2f",
+    "2e.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a.2e.61.2f.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a.2e.61.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a.2e.61.2f.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a.2e.61.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.61.5c.5c.61.2e.2e.2f.5c.e9.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f",
+    "d800.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.66.6f.6f",
+    "65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.66.6f.6f",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.5c.61.2f.5c.61.2e.2e.5c.e9.5c.5c.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.66.6f.6f",
+    "65.301.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.66.6f.6f",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f.2f.3f.65.301.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f.5c.3f.65.301.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f.2f.3f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f.5c.3f.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f",
+    "2e.5c.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.2f.5c.e9.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.2f.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.2f.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.44.3a.2f.5c.5c.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.44.3a.2f.5c.5c.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.66.6f.6f.2f",
+    "65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f.3f.65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.66.6f.6f.2f",
+    "2e.5c.d800.5c.66.6f.6f.5c.3f.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.2f.3f.65.301.2e.2e.2e.43.3a.2f.2e.61.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.5c.3f.65.301.2e.2e.2e.43.3a.5c.2e.61.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2e.d800.2f.66.6f.6f",
+    "d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.2e.d800.5c.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.5c.61.2e.2e.2f.5c.e9.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2e.2f.d800.66.6f.6f",
+    "65.301.5c.2e.2e.2e.5c.43.3a.2e.61.2e.5c.d800.66.6f.6f",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2e.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.2e.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.2f.5c.44.3a.2f.5c.5c.5c.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.e9.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.2f.5c.44.3a.2f.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2e.2e.2e.2f.43.3a.2e.61.2e.d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.2e.2e.2e.5c.43.3a.2e.61.2e.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2e.2e.2e.2f.43.3a.2e.61.2e.d800.2f.66.6f.6f.3f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.2e.2e.2e.5c.43.3a.2e.61.2e.d800.5c.66.6f.6f.3f.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.2f.5c.61.5c.61.2e.2e.2f.5c.e9.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.2f.66.6f.6f.2f",
+    "d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f",
+    "d800.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.2f.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.2f.5c.5c.5c.2e.2e.2f.5c.61.2f.5c.61.2e.2e.2f.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.5c.44.3a.5c.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.2f.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.e9.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.2f.5c.2e.2e.2f.5c.61.5c.61.2e.2e.5c.e9.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "2e.5c.2e.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f.2f.3f.65.301.2f.2e.2e.2e.43.3a.2f.2e.61.2e.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f.5c.3f.65.301.5c.2e.2e.2e.43.3a.5c.2e.61.2e.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.e9.2f.5c.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.2e.2e.2f.5c.61.5c.5c.61.2e.2e.5c.e9.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.2f.66.6f.6f.2f",
+    "2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c.d83d.de00.2f.5c.dfff.5c.44.3a.5c.5c.5c.2e.2e.5c.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f.2f",
+    "2e.5c.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.2e.d800.2f.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f.2e.61.2f.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.5c.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c.2e.61.5c.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.5c.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.5c.44.3a.5c.5c.5c.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a.2f",
+    "2e.5c.d800.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a.5c",
+    "2f.62.61.73.65.2f.d800.66.6f.6f.2f.3f.2f.65.301.2e.2e.2e.2f.43.3a",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f.5c.3f.5c.65.301.2e.2e.2e.5c.43.3a"
+  ],
+  [
+    "d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.2f.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.5c.dfff.2f.5c.44.3a.5c.2f.5c.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "d800.66.6f.6f",
+    "d800.66.6f.6f",
+    "2f.62.61.73.65.2f.d800.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.d800.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c",
+    "2e.5c.2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.61.2f.5c.61.2e.2e.5c.5c.e9.5c.5c.d83d.de00.5c.dfff.2f.5c.44.3a.5c.5c.2e.2e.5c.5c.61.5c.61.2e.2e.5c.5c.e9.5c.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9.5c.d83d.de00.5c.dfff.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "2e.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a.2f",
+    "2e.5c.2e.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a.5c",
+    "2f.62.61.73.65.2f.2e.d800.66.6f.6f.2f.3f.2f.65.301.2f.2e.2e.2e.43.3a",
+    "43.3a.5c.62.61.73.65.5c.2e.d800.66.6f.6f.5c.3f.5c.65.301.5c.2e.2e.2e.43.3a"
+  ],
+  [
+    "d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "2e.5c.d83d.de00.5c.dfff.5c.44.3a.5c",
+    "2f.62.61.73.65.2f.d83d.de00.5c.dfff.5c.5c.44.3a.5c.2f.5c",
+    "43.3a.5c.62.61.73.65.5c.d83d.de00.5c.dfff.5c.44.3a"
+  ],
+  [
+    "65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.2f.66.6f.6f.2f",
+    "65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.5c.66.6f.6f.5c",
+    "2f.62.61.73.65.2f.65.301.2f.2e.2e.2e.2f.43.3a.2e.61.2f.2e.d800.2f.66.6f.6f",
+    "43.3a.5c.62.61.73.65.5c.65.301.5c.2e.2e.2e.5c.43.3a.2e.61.5c.2e.d800.5c.66.6f.6f"
+  ],
+  [
+    "2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "2e.2e.5c.61.5c.61.2e.2e.5c.e9.5c",
+    "2f.62.61.73.65.2f.2e.2e.5c.5c.61.5c.5c.61.2e.2e.5c.5c.e9.2f.5c",
+    "43.3a.5c.61.5c.61.2e.2e.5c.e9"
+  ],
+  [
+    "db8a0aff14c0781f103f1a75616a6f7caf5f35c07abaacb69a22a96aafe16027",
+    "21d9a54c1a452123b4bf5b28c08d769fe4845cf04faf5fe01defd7fb5a8ec5d7"
+  ]
+]
diff --git a/tests/Unit/Node/fixtures/portable.cjs b/tests/Unit/Node/fixtures/portable.cjs
new file mode 100644
index 00000000..57b90325
--- /dev/null
+++ b/tests/Unit/Node/fixtures/portable.cjs
@@ -0,0 +1,46 @@
+'use strict';
+
+const path = require('node:path');
+const qs = require('node:querystring');
+const url = require('node:url');
+const util = require('node:util');
+const assert = require('node:assert');
+const out = {};
+
+out.paths = [path.posix.normalize('/foo/../bar//'), path.posix.relative('/a/b', '/a/c/d'),
+  path.win32.resolve('C:\\a\\b', '..\\c'), path.win32.relative('C:\\foo\\bar', 'C:\\foo\\baz'),
+  path.win32.parse('\\\\server\\share\\dir\\file.txt'), path.posix.parse('/a/.config'),
+  path.format({ dir: '/a', name: 'b', ext: 'txt' }), path.matchesGlob('src/a.js', 'src/*.js'),
+  path.matchesGlob('src/a/b.js', 'src/*.js'), path.matchesGlob('.secret', '*')];
+out.query = [qs.parse('x=1&x=2&space=a+b&bad=%E0%A4%A'),
+  qs.stringify({ x: ['a b', 'x+y'], n: 4, nil: null, nested: {} }),
+  qs.parse('a=1;b=2;c=3', ';', '=', { maxKeys: 2 }),
+  Object.getPrototypeOf(qs.parse('__proto__=x&constructor=y')) === null];
+out.urls = [url.parse('https://a:b@example.com:8443/a%20b?q=1#hash', true),
+  url.resolve('http://example.com/a/b', '../c?d'),
+  url.format({ protocol: 'https:', hostname: 'example.com', pathname: '/a b', query: { q: 'x y' } }),
+  url.domainToASCII('münich.example'), url.domainToUnicode('xn--mnich-kva.example'),
+  url.pathToFileURL('/tmp/a #%.txt').href, url.fileURLToPath('file:///tmp/a%20b'),
+  url.fileURLToPath('file:///C:/Users/A%20B', { windows: true }),
+  url.fileURLToPathBuffer('file:///tmp/%FF%FE').toString('hex'),
+  url.format(new URL('https://user:pass@xn--mnich-kva.example/a?q=1#h'), { unicode: true, auth: false, fragment: false }),
+  url.urlToHttpOptions(new URL('http://a:b@[::1]:8080/x?q=1'))];
+out.format = [util.format('%s %d %i %f %% %j', 'hello', 3, '4x', '5.2x', { a: 1 }),
+  util.formatWithOptions({ depth: 0 }, '%O', { a: { b: 1 } }),
+  util.formatWithOptions({ numericSeparator: true }, '%d %i', 1234567.123456, 1234567n),
+  util.format('%s', { a: { b: 1 } }), util.format('%d %i %f', Symbol(), Symbol(), Symbol()),
+  util.format('%s %d', -0, 1n), util.stripVTControlCharacters('\u001b[31mred\u001b[0m')];
+const circular = {}; circular.self = circular;
+out.format.push(util.format('%j', circular));
+try { util.format('%j', 1n); } catch (error) { out.format.push(error.name); }
+out.assertions = [];
+assert.deepStrictEqual(new Map([[{ a: 1 }, new Set([1, 2])]]), new Map([[{ a: 1 }, new Set([2, 1])]]));
+for (const fn of [() => assert.strictEqual(0, -0), () => assert.deepStrictEqual({ a: 1 }, { a: '1' }),
+  () => assert.throws(() => {}, TypeError), () => assert.match('abc', /z/)]) {
+  try { fn(); out.assertions.push('unexpected pass'); } catch (error) { out.assertions.push([error.name, error.code]); }
+}
+out.deep = [util.isDeepStrictEqual(new Set([1, 2]), new Set([2, 1])), util.isDeepStrictEqual({ a: 1 }, { a: '1' })];
+const customized = () => { throw new Error('should use the custom implementation'); };
+customized[Symbol.for('nodejs.util.promisify.custom')] = async () => 42;
+out.promisify = util.promisify(customized) === customized[Symbol.for('nodejs.util.promisify.custom')];
+globalThis.portableResult = out;
diff --git a/tests/Unit/Node/fixtures/portable.json b/tests/Unit/Node/fixtures/portable.json
new file mode 100644
index 00000000..e406b498
--- /dev/null
+++ b/tests/Unit/Node/fixtures/portable.json
@@ -0,0 +1,114 @@
+{
+  "paths": [
+    "/bar/",
+    "../c/d",
+    "C:\\a\\c",
+    "..\\baz",
+    {
+      "root": "\\\\server\\share\\",
+      "dir": "\\\\server\\share\\dir",
+      "base": "file.txt",
+      "ext": ".txt",
+      "name": "file"
+    },
+    {
+      "root": "/",
+      "dir": "/a",
+      "base": ".config",
+      "ext": "",
+      "name": ".config"
+    },
+    "/a/b.txt",
+    true,
+    false,
+    false
+  ],
+  "query": [
+    {
+      "x": [
+        "1",
+        "2"
+      ],
+      "space": "a b",
+      "bad": "�%A"
+    },
+    "x=a%20b&x=x%2By&n=4&nil=&nested=",
+    {
+      "a": "1",
+      "b": "2"
+    },
+    true
+  ],
+  "urls": [
+    {
+      "protocol": "https:",
+      "slashes": true,
+      "auth": "a:b",
+      "host": "example.com:8443",
+      "port": "8443",
+      "hostname": "example.com",
+      "hash": "#hash",
+      "search": "?q=1",
+      "query": {
+        "q": "1"
+      },
+      "pathname": "/a%20b",
+      "path": "/a%20b?q=1",
+      "href": "https://a:b@example.com:8443/a%20b?q=1#hash"
+    },
+    "http://example.com/c?d",
+    "https://example.com/a b?q=x%20y",
+    "xn--mnich-kva.example",
+    "münich.example",
+    "file:///tmp/a%20%23%25.txt",
+    "/tmp/a b",
+    "C:\\Users\\A B",
+    "2f746d702ffffe",
+    "https://münich.example/a?q=1",
+    {
+      "protocol": "http:",
+      "hostname": "::1",
+      "hash": "",
+      "search": "?q=1",
+      "pathname": "/x",
+      "path": "/x?q=1",
+      "href": "http://a:b@[::1]:8080/x?q=1",
+      "port": 8080,
+      "auth": "a:b"
+    }
+  ],
+  "format": [
+    "hello 3 4 5.2 % {\"a\":1}",
+    "{ a: [Object] }",
+    "1_234_567.123_456 1_234_567n",
+    "{ a: [Object] }",
+    "NaN NaN NaN",
+    "-0 1n",
+    "red",
+    "[Circular]",
+    "TypeError"
+  ],
+  "assertions": [
+    [
+      "AssertionError",
+      "ERR_ASSERTION"
+    ],
+    [
+      "AssertionError",
+      "ERR_ASSERTION"
+    ],
+    [
+      "AssertionError",
+      "ERR_ASSERTION"
+    ],
+    [
+      "AssertionError",
+      "ERR_ASSERTION"
+    ]
+  ],
+  "deep": [
+    true,
+    false
+  ],
+  "promisify": true
+}
diff --git a/tests/Unit/Node/fixtures/primitives/buffer.cjs b/tests/Unit/Node/fixtures/primitives/buffer.cjs
new file mode 100644
index 00000000..29e831cd
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/buffer.cjs
@@ -0,0 +1,50 @@
+'use strict';
+const buffer = require('buffer');
+const { Buffer } = buffer;
+const { StringDecoder } = require('string_decoder');
+require('./helpers.cjs').run(async () => {
+  const output = [];
+  for (const [text, encoding] of [['hello 🌍', 'utf8'], ['a\ud800z', 'utf8'], ['00ff1080f', 'hex'], ['SGVsbG8_', 'base64url'], ['é\uffff', 'latin1'], ['hello', 'utf16le']]) {
+    const value = Buffer.from(text, encoding);
+    output.push([encoding, value.toString('hex'), value.toString('base64url'), Buffer.byteLength(text, encoding), value instanceof Uint8Array, Buffer.isBuffer(value)]);
+  }
+  const backing = new Uint8Array([1, 2, 3, 4]);
+  const shared = Buffer.from(backing.buffer, 1, 2);
+  shared[0] = 8;
+  const copy = Buffer.from(shared);
+  const slice = shared.slice(1);
+  slice[0] = 9;
+  output.push(['views', [...backing], [...shared], [...copy], Buffer.isBuffer(slice)]);
+  const integer = Buffer.alloc(24);
+  integer.writeUInt32LE(4294967295, 0);
+  integer.writeInt16BE(-1234, 4);
+  integer.writeBigUInt64LE(18446744073709551615n, 8);
+  integer.writeDoubleBE(-0, 16);
+  output.push(['numbers', integer.toString('hex'), integer.readUInt32LE(), integer.readInt16BE(4), String(integer.readBigUInt64LE(8)), Object.is(integer.readDoubleBE(16), -0)]);
+  const target = Buffer.alloc(8, 'ab');
+  Buffer.from('XYZ').copy(target, 2, 0, 2);
+  output.push(['mutations', target.toString(), target.indexOf('XY'), target.lastIndexOf('ab'), target.includes(Buffer.from('XY')), Buffer.compare(Buffer.from('a'), Buffer.from('b'))]);
+  const largeFill = Buffer.alloc(1024 * 100, '.');
+  const patternFill = Buffer.alloc(1024 * 100 + 1, 'é!');
+  output.push(['large-fill', largeFill.length, largeFill.toString().length, largeFill[0], largeFill[largeFill.length - 1], patternFill.subarray(-7).toString('hex')]);
+  const overlappingFill = Buffer.from([1, 2, 3, 4, 5, 6]);
+  overlappingFill.fill(overlappingFill.subarray(1, 3), 0);
+  output.push(['overlapping-fill', [...overlappingFill]]);
+  const longString = '.'.repeat(102400);
+  output.push(['large-utf8', Buffer.byteLength(longString), Buffer.from(longString).toString() === longString]);
+  const limitedUtf8 = Buffer.alloc(7, 0x21);
+  const shortWrite = limitedUtf8.write('🌍a', 1, 3, 'utf8');
+  const wholeWrite = limitedUtf8.write('🌍a', 1, 5, 'utf8');
+  output.push(['utf8-write-boundaries', shortWrite, wholeWrite, limitedUtf8.toString('hex'), Buffer.from('a\ud800z').toString('hex')]);
+  output.push(['raw-bytes', Buffer.copyBytesFrom(new Uint16Array([0x1234, 0xabcd]), 1, 1).toString('hex')]);
+  const decoder = new StringDecoder('utf8');
+  const unicode = Buffer.from('a🌍b');
+  output.push(['decode', decoder.write(unicode.subarray(0, 3)), decoder.write(unicode.subarray(3, 4)), decoder.end(unicode.subarray(4))]);
+  const incomplete = new StringDecoder('utf8');
+  output.push(['decode-incomplete', incomplete.write(Buffer.from([0xf0, 0x9f])), incomplete.end()]);
+  output.push(['validity', buffer.isUtf8(Buffer.from('🌍')), buffer.isUtf8(Buffer.from([0xff])), buffer.isAscii(Buffer.from('ascii')), buffer.isAscii(Buffer.from('é'))]);
+  for (const action of [() => Buffer.alloc(-1), () => Buffer.from(2), () => Buffer.alloc(2).readUInt32LE(), () => Buffer.copyBytesFrom(new DataView(new ArrayBuffer(2)))]) {
+    try { action(); output.push('unexpected-success'); } catch (error) { output.push(error.name); }
+  }
+  return output;
+});
diff --git a/tests/Unit/Node/fixtures/primitives/buffer.json b/tests/Unit/Node/fixtures/primitives/buffer.json
new file mode 100644
index 00000000..8bf730ca
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/buffer.json
@@ -0,0 +1,141 @@
+[
+  [
+    "utf8",
+    "68656c6c6f20f09f8c8d",
+    "aGVsbG8g8J-MjQ",
+    10,
+    true,
+    true
+  ],
+  [
+    "utf8",
+    "61efbfbd7a",
+    "Ye-_vXo",
+    5,
+    true,
+    true
+  ],
+  [
+    "hex",
+    "00ff1080",
+    "AP8QgA",
+    4,
+    true,
+    true
+  ],
+  [
+    "base64url",
+    "48656c6c6f3f",
+    "SGVsbG8_",
+    6,
+    true,
+    true
+  ],
+  [
+    "latin1",
+    "e9ff",
+    "6f8",
+    2,
+    true,
+    true
+  ],
+  [
+    "utf16le",
+    "680065006c006c006f00",
+    "aABlAGwAbABvAA",
+    10,
+    true,
+    true
+  ],
+  [
+    "views",
+    [
+      1,
+      8,
+      9,
+      4
+    ],
+    [
+      8,
+      9
+    ],
+    [
+      8,
+      3
+    ],
+    true
+  ],
+  [
+    "numbers",
+    "fffffffffb2e0000ffffffffffffffff8000000000000000",
+    4294967295,
+    -1234,
+    "18446744073709551615",
+    true
+  ],
+  [
+    "mutations",
+    "abXYabab",
+    2,
+    6,
+    true,
+    -1
+  ],
+  [
+    "large-fill",
+    102400,
+    102400,
+    46,
+    46,
+    "a921c3a921c3a9"
+  ],
+  [
+    "overlapping-fill",
+    [
+      2,
+      3,
+      2,
+      3,
+      2,
+      3
+    ]
+  ],
+  [
+    "large-utf8",
+    102400,
+    true
+  ],
+  [
+    "utf8-write-boundaries",
+    0,
+    5,
+    "21f09f8c8d6121",
+    "61efbfbd7a"
+  ],
+  [
+    "raw-bytes",
+    "cdab"
+  ],
+  [
+    "decode",
+    "a",
+    "",
+    "🌍b"
+  ],
+  [
+    "decode-incomplete",
+    "",
+    "�"
+  ],
+  [
+    "validity",
+    true,
+    false,
+    true,
+    false
+  ],
+  "RangeError",
+  "TypeError",
+  "RangeError",
+  "TypeError"
+]
diff --git a/tests/Unit/Node/fixtures/primitives/buffer.mjs b/tests/Unit/Node/fixtures/primitives/buffer.mjs
new file mode 100644
index 00000000..7986c4cf
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/buffer.mjs
@@ -0,0 +1 @@
+import './buffer.cjs';
diff --git a/tests/Unit/Node/fixtures/primitives/child-process.cjs b/tests/Unit/Node/fixtures/primitives/child-process.cjs
new file mode 100644
index 00000000..dea6e4b4
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/child-process.cjs
@@ -0,0 +1,101 @@
+'use strict';
+const cp = require('child_process');
+const { once } = require('events');
+const { promisify } = require('util');
+const { AsyncLocalStorage } = require('async_hooks');
+const fs = require('fs');
+const path = require('path');
+require('./helpers.cjs').run(async () => {
+  const output = [];
+  const binary = Buffer.from([0, 255, 128, 10, 65]);
+  const copied = cp.spawnSync('/bin/cat', [], { input: binary });
+  output.push(['sync-binary', Buffer.isBuffer(copied.stdout), copied.stdout.toString('hex'), copied.status, copied.signal, copied.output[0], copied.output[1] === copied.stdout]);
+  const status = cp.spawnSync('/bin/sh', ['-c', 'printf "%s" "$ONE"; printf error >&2; exit 7'], { env: { ONE: 'value' }, encoding: 'utf8' });
+  output.push(['sync-status', status.stdout, status.stderr, status.status, status.signal]);
+  output.push(['literal-args', cp.execFileSync('/bin/sh', ['-c', 'printf "%s|%s" "$1" "$2"', 'args', 'with spaces', '$(literal)'], { encoding: 'utf8' })]);
+  output.push(['shell', cp.execSync('printf "%s" "shell result"', { encoding: 'utf8' })]);
+  const directory = fs.mkdtempSync(path.join(require('os').tmpdir(), 'phasis-child-'));
+  try {
+    const cwd = cp.spawnSync('/bin/pwd', [], { cwd: directory, encoding: 'utf8' });
+    output.push(['cwd', path.basename(cwd.stdout.trim()) === path.basename(directory)]);
+  } finally { fs.rmSync(directory, { recursive: true, force: true }); }
+  const missing = cp.spawnSync('/phasis-missing-child-executable', ['argument']);
+  output.push(['missing', missing.error.code, missing.error.path, missing.error.spawnargs, missing.status, missing.signal, missing.stdout]);
+  const missingCwd = cp.spawnSync('/bin/pwd', [], { cwd: '/phasis-missing-child-directory' });
+  output.push(['missing-cwd', missingCwd.error.code]);
+  const timeout = cp.spawnSync('/bin/sleep', ['2'], { timeout: 20 });
+  output.push(['timeout', timeout.error.code, timeout.status, timeout.signal]);
+  const limit = cp.spawnSync('/bin/cat', [], { input: Buffer.alloc(4096, 'x'), maxBuffer: 16 });
+  output.push(['output-limit', limit.error.code, limit.stdout.length > 16]);
+  try { cp.execFileSync('/bin/sh', ['-c', 'printf failed >&2; exit 4'], { stdio: ['ignore', 'pipe', 'pipe'] }); }
+  catch (error) { output.push(['exec-error', error.status, error.signal, error.stderr.toString()]); }
+  await new Promise((resolve, reject) => {
+    const child = cp.spawn('/bin/cat');
+    const events = [];
+    const chunks = [];
+    child.once('error', reject);
+    child.once('spawn', () => events.push('spawn'));
+    child.once('exit', (code, signal) => events.push(['exit', code, signal]));
+    child.stdout.on('data', (chunk) => chunks.push(chunk));
+    child.once('close', (code, signal) => {
+      events.push(['close', code, signal]);
+      output.push(['async-binary', Buffer.concat(chunks).toString('hex'), events, child.exitCode, child.signalCode, child.killed]);
+      resolve();
+    });
+    child.stdin.write(binary.subarray(0, 2));
+    child.stdin.write(Buffer.alloc(0));
+    child.stdin.end(binary.subarray(2));
+  });
+  const executed = await promisify(cp.execFile)('/bin/sh', ['-c', 'printf async; printf warning >&2']);
+  output.push(['promisify', executed.stdout, executed.stderr]);
+  const payload = Buffer.alloc(300000, 'abcdef');
+  const piped = cp.spawn('/bin/cat');
+  const pipeChunks = [];
+  let ended = false;
+  piped.stdout.on('data', (chunk) => pipeChunks.push(chunk));
+  piped.stdout.on('end', () => { ended = true; });
+  const pipeClosed = once(piped, 'close');
+  const accepted = piped.stdin.write(payload);
+  if (!accepted) await once(piped.stdin, 'drain');
+  piped.stdin.end();
+  await pipeClosed;
+  output.push(['pipe-backpressure', accepted, Buffer.concat(pipeChunks).toString() === payload.toString(), ended]);
+  try { await promisify(cp.execFile)('/bin/sh', ['-c', 'printf abcdefghijklmnopqrstuvwxyz'], { maxBuffer: 4 }); }
+  catch (error) { output.push(['async-output-limit', error.code, error.stdout]); }
+  await new Promise((resolve) => cp.execFile('/bin/sh', ['-c', 'printf output; printf failed >&2; exit 3'], (error, stdout, stderr) => {
+    output.push(['async-exec-error', error.code, error.signal, error.killed, stdout, stderr]);
+    resolve();
+  }));
+  await new Promise((resolve, reject) => {
+    const child = cp.spawn('/bin/sleep', ['2'], { stdio: 'ignore' });
+    child.once('error', reject);
+    child.once('spawn', () => child.kill('SIGTERM'));
+    child.once('close', (code, signal) => { output.push(['kill', code, signal, child.killed, child.kill()]); resolve(); });
+  });
+  await new Promise((resolve) => {
+    const child = cp.spawn('/phasis-missing-child-executable');
+    const events = [];
+    child.on('error', (error) => events.push(error.code));
+    child.on('close', () => { events.push('close'); output.push(['async-missing', events]); resolve(); });
+  });
+  await new Promise((resolve, reject) => {
+    const controller = new AbortController();
+    const child = cp.spawn('/bin/sleep', ['2'], { signal: controller.signal, stdio: 'ignore' });
+    let aborted;
+    child.once('spawn', () => controller.abort('cancelled'));
+    child.once('error', (error) => { aborted = [error.name, error.code, error.cause]; });
+    child.once('close', (code, signal) => { output.push(['abort', aborted, code, signal]); resolve(); });
+  });
+  const storage = new AsyncLocalStorage();
+  await storage.run('child-context', async () => {
+    const child = cp.spawn('/bin/echo', ['context']);
+    let context;
+    child.on('spawn', () => { context = storage.getStore(); });
+    await once(child, 'close');
+    output.push(['async-context', context, storage.getStore()]);
+  });
+  const worker = cp.spawnSync(process.execPath, [path.join(__dirname, 'child-worker.cjs'), 'argument'], { input: binary, encoding: 'utf8' });
+  if (worker.error || worker.status !== 0) throw worker.error || new Error(worker.stderr);
+  output.push(['javascript-child', JSON.parse(worker.stdout), worker.status]);
+  return output;
+});
diff --git a/tests/Unit/Node/fixtures/primitives/child-process.json b/tests/Unit/Node/fixtures/primitives/child-process.json
new file mode 100644
index 00000000..df73035d
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/child-process.json
@@ -0,0 +1,144 @@
+[
+  [
+    "sync-binary",
+    true,
+    "00ff800a41",
+    0,
+    null,
+    null,
+    true
+  ],
+  [
+    "sync-status",
+    "value",
+    "error",
+    7,
+    null
+  ],
+  [
+    "literal-args",
+    "with spaces|$(literal)"
+  ],
+  [
+    "shell",
+    "shell result"
+  ],
+  [
+    "cwd",
+    true
+  ],
+  [
+    "missing",
+    "ENOENT",
+    "/phasis-missing-child-executable",
+    [
+      "argument"
+    ],
+    null,
+    null,
+    null
+  ],
+  [
+    "missing-cwd",
+    "ENOENT"
+  ],
+  [
+    "timeout",
+    "ETIMEDOUT",
+    null,
+    "SIGTERM"
+  ],
+  [
+    "output-limit",
+    "ENOBUFS",
+    true
+  ],
+  [
+    "exec-error",
+    4,
+    null,
+    "failed"
+  ],
+  [
+    "async-binary",
+    "00ff800a41",
+    [
+      "spawn",
+      [
+        "exit",
+        0,
+        null
+      ],
+      [
+        "close",
+        0,
+        null
+      ]
+    ],
+    0,
+    null,
+    false
+  ],
+  [
+    "promisify",
+    "async",
+    "warning"
+  ],
+  [
+    "pipe-backpressure",
+    false,
+    true,
+    true
+  ],
+  [
+    "async-output-limit",
+    "ERR_CHILD_PROCESS_STDIO_MAXBUFFER",
+    "abcd"
+  ],
+  [
+    "async-exec-error",
+    3,
+    null,
+    false,
+    "output",
+    "failed"
+  ],
+  [
+    "kill",
+    null,
+    "SIGTERM",
+    true,
+    false
+  ],
+  [
+    "async-missing",
+    [
+      "ENOENT",
+      "close"
+    ]
+  ],
+  [
+    "abort",
+    [
+      "AbortError",
+      "ABORT_ERR",
+      "cancelled"
+    ],
+    null,
+    "SIGTERM"
+  ],
+  [
+    "async-context",
+    "child-context",
+    "child-context"
+  ],
+  [
+    "javascript-child",
+    {
+      "data": "00ff800a41",
+      "argument": "argument",
+      "module": "child-worker.cjs"
+    },
+    0
+  ]
+]
diff --git a/tests/Unit/Node/fixtures/primitives/child-process.mjs b/tests/Unit/Node/fixtures/primitives/child-process.mjs
new file mode 100644
index 00000000..d9deb8da
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/child-process.mjs
@@ -0,0 +1 @@
+import './child-process.cjs';
diff --git a/tests/Unit/Node/fixtures/primitives/child-worker.cjs b/tests/Unit/Node/fixtures/primitives/child-worker.cjs
new file mode 100644
index 00000000..11d618fb
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/child-worker.cjs
@@ -0,0 +1,7 @@
+'use strict';
+const chunks = [];
+process.stdin.on('data', (chunk) => chunks.push(chunk));
+process.stdin.on('end', () => {
+  const output = { data: Buffer.concat(chunks).toString('hex'), argument: process.argv[2], module: require('path').basename(__filename) };
+  process.stdout.write(JSON.stringify(output), () => process.exit(0));
+});
diff --git a/tests/Unit/Node/fixtures/primitives/events.cjs b/tests/Unit/Node/fixtures/primitives/events.cjs
new file mode 100644
index 00000000..308fafc3
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/events.cjs
@@ -0,0 +1,49 @@
+'use strict';
+const events = require('events');
+const { EventEmitter, once, on, errorMonitor, captureRejectionSymbol } = events;
+require('./helpers.cjs').run(async () => {
+  const output = [];
+  const emitter = new EventEmitter();
+  const calls = [];
+  const second = () => calls.push('second');
+  emitter.on('value', function () { calls.push(this === emitter ? 'first' : 'bad-this'); emitter.removeListener('value', second); });
+  emitter.on('value', second);
+  emitter.prependOnceListener('value', () => calls.push('once'));
+  output.push(['emit-return', emitter.emit('value'), emitter.emit('missing')]);
+  emitter.emit('value');
+  output.push(['mutation', calls, emitter.listenerCount('value'), emitter.rawListeners('value').length]);
+  const symbol = Symbol('key');
+  emitter.on(symbol, second);
+  output.push(['symbol', emitter.eventNames().map(String), emitter.listenerCount(symbol, second)]);
+  const monitored = new EventEmitter();
+  const monitor = [];
+  monitored.on(errorMonitor, (error) => monitor.push(error.message));
+  try { monitored.emit('error', new Error('expected')); } catch (error) { monitor.push(error.message); }
+  output.push(['error-monitor', monitor]);
+  const captured = new EventEmitter({ captureRejections: true });
+  captured.on('work', async (value) => { throw new Error(value); });
+  const rejection = new Promise((resolve) => { captured[captureRejectionSymbol] = (error, name, value) => resolve([error.message, name, value]); });
+  captured.emit('work', 'rejected');
+  output.push(['capture', await rejection]);
+  const awaited = once(emitter, 'ready');
+  emitter.emit('ready', 1, 2);
+  output.push(['once', await awaited, emitter.listenerCount('ready'), emitter.listenerCount('error')]);
+  const controller = new AbortController();
+  const aborted = once(emitter, 'never', { signal: controller.signal });
+  controller.abort('stop');
+  try { await aborted; } catch (error) { output.push(['abort', error.name, error.code, error.cause, emitter.listenerCount('never')]); }
+  const iterator = on(emitter, 'item', { close: ['finish'] });
+  emitter.emit('item', 'a');
+  emitter.emit('item', 'b');
+  emitter.emit('finish');
+  const values = [];
+  for await (const item of iterator) values.push(item);
+  output.push(['iterator', values, emitter.listenerCount('item'), emitter.listenerCount('finish')]);
+  const listenerController = new AbortController();
+  let count = 0;
+  const disposable = events.addAbortListener(listenerController.signal, () => count++);
+  disposable[Symbol.dispose]();
+  listenerController.abort();
+  output.push(['disposed', count]);
+  return output;
+});
diff --git a/tests/Unit/Node/fixtures/primitives/events.json b/tests/Unit/Node/fixtures/primitives/events.json
new file mode 100644
index 00000000..719d85dd
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/events.json
@@ -0,0 +1,74 @@
+[
+  [
+    "emit-return",
+    true,
+    false
+  ],
+  [
+    "mutation",
+    [
+      "once",
+      "first",
+      "second",
+      "first"
+    ],
+    1,
+    1
+  ],
+  [
+    "symbol",
+    [
+      "value",
+      "Symbol(key)"
+    ],
+    1
+  ],
+  [
+    "error-monitor",
+    [
+      "expected",
+      "expected"
+    ]
+  ],
+  [
+    "capture",
+    [
+      "rejected",
+      "work",
+      "rejected"
+    ]
+  ],
+  [
+    "once",
+    [
+      1,
+      2
+    ],
+    0,
+    0
+  ],
+  [
+    "abort",
+    "AbortError",
+    "ABORT_ERR",
+    "stop",
+    0
+  ],
+  [
+    "iterator",
+    [
+      [
+        "a"
+      ],
+      [
+        "b"
+      ]
+    ],
+    0,
+    0
+  ],
+  [
+    "disposed",
+    0
+  ]
+]
diff --git a/tests/Unit/Node/fixtures/primitives/events.mjs b/tests/Unit/Node/fixtures/primitives/events.mjs
new file mode 100644
index 00000000..528d5b5b
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/events.mjs
@@ -0,0 +1 @@
+import './events.cjs';
diff --git a/tests/Unit/Node/fixtures/primitives/fs.cjs b/tests/Unit/Node/fixtures/primitives/fs.cjs
new file mode 100644
index 00000000..4a3dfae0
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/fs.cjs
@@ -0,0 +1,110 @@
+'use strict';
+const fs = require('node:fs');
+const path = require('node:path');
+const os = require('node:os');
+const { pipeline } = require('node:stream/promises');
+const { Transform } = require('node:stream');
+const { once } = require('node:events');
+const { promisify } = require('node:util');
+
+require('./helpers.cjs').run(async () => {
+  const output = [];
+  const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'phasis-fs-oracle-'));
+  const file = path.join(directory, 'bytes');
+  try {
+    fs.writeFileSync(file, Buffer.from([0, 1, 127, 128, 254, 255]));
+    output.push(['binary', fs.readFileSync(file).toString('hex'), fs.readFileSync(new URL('file://' + file)).equals(fs.readFileSync(Buffer.from(file)))]);
+    fs.writeFileSync(file, 'hello 😀', 'utf8');
+    fs.appendFileSync(file, '!');
+    output.push(['text', fs.readFileSync(file, 'utf8'), fs.readFileSync(file).length]);
+
+    const fd = fs.openSync(file, 'r+');
+    const backing = Buffer.alloc(8, 46);
+    const destination = new Uint8Array(backing.buffer, backing.byteOffset + 2, 4);
+    const positional = fs.readSync(fd, destination, 1, 2, 1);
+    const sequential = Buffer.alloc(2);
+    fs.readSync(fd, sequential, 0, 2, null);
+    fs.writeSync(fd, 'X', 0, 'utf8');
+    const rest = fs.readFileSync(fd, 'utf8');
+    output.push(['descriptor', positional, backing.toString('hex'), sequential.toString(), rest, fs.readFileSync(file, 'utf8')]);
+    fs.ftruncateSync(fd, 5);
+    fs.fsyncSync(fd);
+    fs.closeSync(fd);
+    try { fs.closeSync(fd); } catch (error) { output.push(['closed', error.code, error.syscall]); }
+
+    const before = fs.statSync(file);
+    fs.utimesSync(file, 1000000000, new Date(1000000020000));
+    const stat = fs.statSync(file);
+    const big = fs.statSync(file, { bigint: true });
+    output.push(['stat', stat instanceof fs.Stats, stat.isFile(), stat.isDirectory(), stat.size, stat.mtimeMs, stat.atime instanceof Date, typeof big.size, typeof big.mtimeNs, before.mode & 0o777]);
+    const missing = path.join(directory, 'missing');
+    output.push(['missing', fs.existsSync(missing), fs.statSync(missing, { throwIfNoEntry: false }) === undefined]);
+    for (const [operation, fn] of [['stat', () => fs.statSync(missing)], ['open', () => fs.openSync(missing)], ['read', () => fs.readFileSync(directory)], ['exclusive', () => fs.writeFileSync(file, 'no', { flag: 'wx' })]]) {
+      try { fn(); } catch (error) { output.push(['error', operation, error.name, error.code, error.syscall]); }
+    }
+
+    const child = path.join(directory, 'child', 'nested');
+    output.push(['mkdir', fs.mkdirSync(child, { recursive: true }) === path.join(directory, 'child'), fs.mkdirSync(child, { recursive: true }) === undefined]);
+    fs.writeFileSync(path.join(child, 'a'), 'A');
+    fs.symlinkSync('bytes', path.join(directory, 'link'));
+    fs.linkSync(file, path.join(directory, 'hard'));
+    output.push(['links', fs.lstatSync(path.join(directory, 'link')).isSymbolicLink(), fs.readlinkSync(path.join(directory, 'link')), fs.realpathSync(path.join(directory, 'link')) === file, fs.statSync(path.join(directory, 'hard')).ino === fs.statSync(file).ino]);
+    output.push(['directory', fs.readdirSync(directory, { withFileTypes: true }).map(entry => [entry.name, entry.isDirectory(), entry.isSymbolicLink(), entry.parentPath === directory])]);
+    fs.copyFileSync(file, path.join(directory, 'copy'));
+    fs.renameSync(path.join(directory, 'copy'), path.join(directory, 'renamed'));
+    output.push(['copy', fs.readFileSync(path.join(directory, 'renamed'), 'utf8')]);
+
+    const order = [];
+    const asyncFile = path.join(directory, 'async');
+    await new Promise((resolve, reject) => {
+      fs.writeFile(asyncFile, 'callback', error => { if (error) { reject(error); return; } order.push('callback'); resolve(); });
+      order.push('sync');
+    });
+    output.push(['callback', order, await fs.promises.readFile(asyncFile, 'utf8'), await promisify(fs.readFile)(asyncFile, 'utf8')]);
+    const handle = await fs.promises.open(asyncFile, 'r+');
+    const target = Buffer.alloc(4);
+    const read = await handle.read(target, 1, 2, 2);
+    const write = await handle.write('!', 0, 'utf8');
+    const closeEvents = [];
+    handle.on('close', () => closeEvents.push('close'));
+    await handle.close(); await handle.close();
+    output.push(['filehandle', read.bytesRead, read.buffer === target, target.toString('hex'), write.bytesWritten, write.buffer, handle.fd, closeEvents]);
+
+    fs.writeFileSync(file, '0123456789');
+    const ranged = fs.createReadStream(file, { start: 2, end: 7, highWaterMark: 2 });
+    const rangeEvents = [];
+    ranged.on('open', () => rangeEvents.push('open'));
+    ranged.on('ready', () => rangeEvents.push('ready'));
+    ranged.on('end', () => rangeEvents.push('end'));
+    ranged.on('close', () => rangeEvents.push('close'));
+    const parts = [];
+    for await (const part of ranged) parts.push(part);
+    output.push(['readstream', Buffer.concat(parts).toString(), ranged.bytesRead, ranged.fd, rangeEvents]);
+
+    const copied = path.join(directory, 'stream-copy');
+    const writer = fs.createWriteStream(copied, { highWaterMark: 2 });
+    await pipeline(fs.createReadStream(file, { highWaterMark: 2 }), new Transform({ transform(chunk, encoding, done) { done(null, Buffer.from(chunk.toString().replace(/0/g, 'X'))); } }), writer);
+    output.push(['pipeline', fs.readFileSync(copied, 'utf8'), writer.bytesWritten, writer.fd]);
+    const keptFd = fs.openSync(file, 'r');
+    const kept = fs.createReadStream(undefined, { fd: keptFd, autoClose: false, end: 1 });
+    for await (const part of kept) {}
+    output.push(['kept-fd', fs.fstatSync(keptFd).size]);
+    fs.closeSync(keptFd);
+    const errored = fs.createReadStream(missing);
+    const streamError = await new Promise(resolve => errored.on('error', resolve));
+    output.push(['stream-error', streamError.code, errored.destroyed]);
+
+    const dir = await fs.promises.opendir(child);
+    const entries = [];
+    for await (const entry of dir) entries.push([entry.name, entry.isFile()]);
+    try { dir.readSync(); } catch (error) { output.push(['opendir', entries, error.code]); }
+    const controller = new AbortController(); controller.abort('stop');
+    try { await fs.promises.readFile(file, { signal: controller.signal }); }
+    catch (error) { output.push(['abort', error.name, error.code, error.cause]); }
+    await fs.promises.writeFile(path.join(directory, 'iterable'), (async function* () { yield 'one'; yield Buffer.from('two'); })());
+    output.push(['iterable-write', fs.readFileSync(path.join(directory, 'iterable'), 'utf8')]);
+  } finally {
+    fs.rmSync(directory, { recursive: true, force: true });
+  }
+  return output;
+});
diff --git a/tests/Unit/Node/fixtures/primitives/fs.json b/tests/Unit/Node/fixtures/primitives/fs.json
new file mode 100644
index 00000000..2e38f047
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/fs.json
@@ -0,0 +1,183 @@
+[
+  [
+    "binary",
+    "00017f80feff",
+    true
+  ],
+  [
+    "text",
+    "hello 😀!",
+    11
+  ],
+  [
+    "descriptor",
+    2,
+    "2e2e2e656c2e2e2e",
+    "he",
+    "llo 😀!",
+    "Xello 😀!"
+  ],
+  [
+    "closed",
+    "EBADF",
+    "close"
+  ],
+  [
+    "stat",
+    true,
+    true,
+    false,
+    5,
+    1000000020000,
+    true,
+    "bigint",
+    "bigint",
+    420
+  ],
+  [
+    "missing",
+    false,
+    true
+  ],
+  [
+    "error",
+    "stat",
+    "Error",
+    "ENOENT",
+    "stat"
+  ],
+  [
+    "error",
+    "open",
+    "Error",
+    "ENOENT",
+    "open"
+  ],
+  [
+    "error",
+    "read",
+    "Error",
+    "EISDIR",
+    "read"
+  ],
+  [
+    "error",
+    "exclusive",
+    "Error",
+    "EEXIST",
+    "open"
+  ],
+  [
+    "mkdir",
+    true,
+    true
+  ],
+  [
+    "links",
+    true,
+    "bytes",
+    false,
+    true
+  ],
+  [
+    "directory",
+    [
+      [
+        "bytes",
+        false,
+        false,
+        true
+      ],
+      [
+        "child",
+        true,
+        false,
+        true
+      ],
+      [
+        "hard",
+        false,
+        false,
+        true
+      ],
+      [
+        "link",
+        false,
+        true,
+        true
+      ]
+    ]
+  ],
+  [
+    "copy",
+    "Xello"
+  ],
+  [
+    "callback",
+    [
+      "sync",
+      "callback"
+    ],
+    "callback",
+    "callback"
+  ],
+  [
+    "filehandle",
+    2,
+    true,
+    "006c6c00",
+    1,
+    "!",
+    -1,
+    [
+      "close"
+    ]
+  ],
+  [
+    "readstream",
+    "234567",
+    6,
+    null,
+    [
+      "open",
+      "ready",
+      "end",
+      "close"
+    ]
+  ],
+  [
+    "pipeline",
+    "X123456789",
+    10,
+    null
+  ],
+  [
+    "kept-fd",
+    10
+  ],
+  [
+    "stream-error",
+    "ENOENT",
+    true
+  ],
+  [
+    "opendir",
+    [
+      [
+        "a",
+        true
+      ]
+    ],
+    "ERR_DIR_CLOSED"
+  ],
+  [
+    "abort",
+    "AbortError",
+    "ABORT_ERR",
+    "stop"
+  ],
+  [
+    "iterable-write",
+    "onetwo"
+  ]
+]
diff --git a/tests/Unit/Node/fixtures/primitives/fs.mjs b/tests/Unit/Node/fixtures/primitives/fs.mjs
new file mode 100644
index 00000000..ac97ae10
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/fs.mjs
@@ -0,0 +1 @@
+import './fs.cjs';
diff --git a/tests/Unit/Node/fixtures/primitives/helpers.cjs b/tests/Unit/Node/fixtures/primitives/helpers.cjs
new file mode 100644
index 00000000..c1fcc887
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/helpers.cjs
@@ -0,0 +1,11 @@
+'use strict';
+exports.run = function (work) {
+  Promise.resolve().then(work).then((result) => {
+    globalThis.__nodePrimitiveResult = JSON.stringify(result);
+    console.log(globalThis.__nodePrimitiveResult);
+  }, (error) => {
+    globalThis.__nodePrimitiveError = String(error.stack || error);
+    console.error(globalThis.__nodePrimitiveError);
+    process.exitCode = 1;
+  });
+};
diff --git a/tests/Unit/Node/fixtures/primitives/stream-web.cjs b/tests/Unit/Node/fixtures/primitives/stream-web.cjs
new file mode 100644
index 00000000..32ec909d
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/stream-web.cjs
@@ -0,0 +1,44 @@
+'use strict';
+const { Readable, Writable, Duplex } = require('stream');
+const { finished } = require('stream/promises');
+const consumers = require('stream/consumers');
+const { TextEncoderStream, TextDecoderStream } = require('stream/web');
+require('./helpers.cjs').run(async () => {
+  const output = [];
+  const web = new ReadableStream({ start(controller) { controller.enqueue(new Uint8Array([97, 98])); controller.enqueue(new Uint8Array([99])); controller.close(); } });
+  output.push(['from-web', await consumers.text(Readable.fromWeb(web)), web.locked]);
+  const node = Readable.from(['one', 'two']);
+  const reader = Readable.toWeb(node).getReader();
+  const values = [];
+  while (true) { const item = await reader.read(); if (item.done) break; values.push(item.value); }
+  output.push(['to-web', values, node.readableEnded]);
+  const received = [];
+  const webSink = new WritableStream({ write(value) { received.push(new TextDecoder().decode(value)); } });
+  const nodeSink = Writable.fromWeb(webSink);
+  nodeSink.write('first');
+  nodeSink.end('second');
+  await finished(nodeSink);
+  output.push(['writable-from-web', received, webSink.locked]);
+  const nativeReceived = [];
+  const nativeSink = new Writable({ write(chunk, encoding, callback) { nativeReceived.push(chunk.toString()); callback(); } });
+  const writer = Writable.toWeb(nativeSink).getWriter();
+  await writer.write('third');
+  await writer.close();
+  output.push(['writable-to-web', nativeReceived, nativeSink.writableFinished]);
+  const source = new ReadableStream({ start(controller) { controller.enqueue('a\ud83c'); controller.enqueue('\udf0db'); controller.close(); } });
+  const encoded = source.pipeThrough(new TextEncoderStream());
+  const decoded = encoded.pipeThrough(new TextDecoderStream());
+  output.push(['text-streams', await consumers.text(decoded)]);
+  const pair = new TransformStream({ transform(value, controller) { controller.enqueue(value); } });
+  const duplex = Duplex.fromWeb(pair);
+  duplex.end('duplex');
+  output.push(['duplex', await consumers.text(duplex)]);
+  let cancelled;
+  const cancellable = Readable.fromWeb(new ReadableStream({ cancel(reason) { cancelled = reason.message; } }));
+  cancellable.on('error', () => {});
+  cancellable.destroy(new Error('cancelled'));
+  try { await finished(cancellable); } catch {}
+  output.push(['cancel', cancelled]);
+  output.push(['consumers', await consumers.json(Readable.from(['{"ok":', 'true}'])), [...new Uint8Array(await consumers.arrayBuffer(Readable.from(['hi'])))]]);
+  return output;
+});
diff --git a/tests/Unit/Node/fixtures/primitives/stream-web.json b/tests/Unit/Node/fixtures/primitives/stream-web.json
new file mode 100644
index 00000000..ce41a4ce
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/stream-web.json
@@ -0,0 +1,52 @@
+[
+  [
+    "from-web",
+    "abc",
+    true
+  ],
+  [
+    "to-web",
+    [
+      "one",
+      "two"
+    ],
+    true
+  ],
+  [
+    "writable-from-web",
+    [
+      "first",
+      "second"
+    ],
+    true
+  ],
+  [
+    "writable-to-web",
+    [
+      "third"
+    ],
+    true
+  ],
+  [
+    "text-streams",
+    "a🌍b"
+  ],
+  [
+    "duplex",
+    "duplex"
+  ],
+  [
+    "cancel",
+    "cancelled"
+  ],
+  [
+    "consumers",
+    {
+      "ok": true
+    },
+    [
+      104,
+      105
+    ]
+  ]
+]
diff --git a/tests/Unit/Node/fixtures/primitives/stream-web.mjs b/tests/Unit/Node/fixtures/primitives/stream-web.mjs
new file mode 100644
index 00000000..dc8dbdae
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/stream-web.mjs
@@ -0,0 +1 @@
+import './stream-web.cjs';
diff --git a/tests/Unit/Node/fixtures/primitives/stream.cjs b/tests/Unit/Node/fixtures/primitives/stream.cjs
new file mode 100644
index 00000000..1542a831
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/stream.cjs
@@ -0,0 +1,43 @@
+'use strict';
+const { Readable, Writable, Transform, PassThrough } = require('stream');
+const { pipeline, finished } = require('stream/promises');
+const { Buffer } = require('buffer');
+require('./helpers.cjs').run(async () => {
+  const output = [];
+  const chunks = [];
+  const transform = new Transform({ transform(chunk, encoding, callback) { callback(null, chunk.toString().toUpperCase()); } });
+  const destination = new Writable({ highWaterMark: 1, write(chunk, encoding, callback) { chunks.push(chunk.toString()); process.nextTick(callback); } });
+  await pipeline(Readable.from(['hello', 'world']), transform, destination);
+  output.push(['pipeline', chunks, destination.writableFinished, transform.destroyed]);
+  const asyncValues = [];
+  for await (const chunk of Readable.from([1, 2, 3])) asyncValues.push(chunk);
+  output.push(['async-iterate', asyncValues]);
+  const corked = [];
+  const sink = new Writable({ write(chunk, encoding, callback) { corked.push(['single', chunk.toString()]); callback(); }, writev(chunks, callback) { corked.push(['batch', chunks.map((item) => item.chunk.toString())]); callback(); } });
+  sink.cork();
+  sink.write('a');
+  sink.write('b');
+  sink.uncork();
+  sink.end('c');
+  await finished(sink);
+  output.push(['writev', corked, sink.writableEnded]);
+  const backpressure = [];
+  let complete;
+  const bounded = new Writable({ highWaterMark: 1, write(chunk, encoding, callback) { complete = callback; } });
+  backpressure.push(bounded.write('x'), bounded.writableNeedDrain, bounded.writableLength);
+  bounded.on('drain', () => backpressure.push('drain'));
+  complete();
+  await new Promise((resolve) => process.nextTick(resolve));
+  bounded.end();
+  await finished(bounded);
+  output.push(['backpressure', backpressure]);
+  const bytes = Readable.from([Buffer.from([0xf0, 0x9f]), Buffer.from([0x8c, 0x8d])]);
+  bytes.setEncoding('utf8');
+  let text = '';
+  for await (const chunk of bytes) text += chunk;
+  output.push(['decoder', text]);
+  const broken = new Transform({ transform(chunk, encoding, callback) { callback(new Error('pipeline failed')); } });
+  try { await pipeline(Readable.from(['x']), broken, new PassThrough()); } catch (error) { output.push(['pipeline-error', error.message, broken.destroyed]); }
+  output.push(['operators', await Readable.from([1, 2, 3, 4]).map(async (value) => value * 2).filter((value) => value > 4).toArray()]);
+  return output;
+});
diff --git a/tests/Unit/Node/fixtures/primitives/stream.json b/tests/Unit/Node/fixtures/primitives/stream.json
new file mode 100644
index 00000000..879f7ee9
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/stream.json
@@ -0,0 +1,61 @@
+[
+  [
+    "pipeline",
+    [
+      "HELLO",
+      "WORLD"
+    ],
+    true,
+    true
+  ],
+  [
+    "async-iterate",
+    [
+      1,
+      2,
+      3
+    ]
+  ],
+  [
+    "writev",
+    [
+      [
+        "batch",
+        [
+          "a",
+          "b"
+        ]
+      ],
+      [
+        "single",
+        "c"
+      ]
+    ],
+    true
+  ],
+  [
+    "backpressure",
+    [
+      false,
+      true,
+      1,
+      "drain"
+    ]
+  ],
+  [
+    "decoder",
+    "🌍"
+  ],
+  [
+    "pipeline-error",
+    "pipeline failed",
+    true
+  ],
+  [
+    "operators",
+    [
+      6,
+      8
+    ]
+  ]
+]
diff --git a/tests/Unit/Node/fixtures/primitives/stream.mjs b/tests/Unit/Node/fixtures/primitives/stream.mjs
new file mode 100644
index 00000000..2ebc33dc
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/stream.mjs
@@ -0,0 +1 @@
+import './stream.cjs';
diff --git a/tests/Unit/Node/fixtures/primitives/vm.cjs b/tests/Unit/Node/fixtures/primitives/vm.cjs
new file mode 100644
index 00000000..7e523c5b
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/vm.cjs
@@ -0,0 +1,59 @@
+'use strict';
+const vm = require('node:vm');
+const { AsyncLocalStorage } = require('node:async_hooks');
+require('./helpers.cjs').run(async () => {
+  const result = [];
+  const shared = { number: 5 };
+  const sandbox = { value: 2, shared };
+  result.push(['create', vm.isContext(sandbox), vm.createContext(sandbox) === sandbox, vm.createContext(sandbox) === sandbox, vm.isContext(sandbox)]);
+  const global = vm.runInContext('this', sandbox);
+  result.push(['global', global !== sandbox, vm.runInContext('this === globalThis', sandbox), sandbox.Array === undefined, Object.keys(sandbox).sort()]);
+  result.push(['intrinsics', vm.runInContext('Array', sandbox) !== Array, vm.runInContext('Object', sandbox) !== Object, vm.runInContext('[]', sandbox) instanceof Array, vm.runInContext('typeof process', sandbox)]);
+  vm.runInContext('value += 3; shared.number += 4; var exposed = 7; let hidden = 11;', sandbox);
+  result.push(['bindings', sandbox.value, shared.number, sandbox.exposed, sandbox.hidden === undefined, vm.runInContext('hidden + exposed', sandbox)]);
+  sandbox.value = 31;
+  result.push(['live', vm.runInContext('value', sandbox)]);
+  Object.defineProperty(sandbox, 'double', { get() { return this.value * 2; }, configurable: true, enumerable: true });
+  result.push(['accessor', vm.runInContext('double', sandbox)]);
+  const script = new vm.Script('var total = (typeof total === "undefined" ? 0 : total) + value; total', { filename: 'vm-count.js' });
+  const other = vm.createContext({ value: 4 });
+  result.push(['script', script.runInContext(sandbox), script.runInContext(other), script.runInContext(sandbox), sandbox.total, other.total]);
+  const innerArray = vm.runInContext('Array', sandbox);
+  const closure = vm.runInContext('(function () { return [value, hidden]; })', sandbox);
+  const returned = closure();
+  result.push(['closure', [...returned], returned instanceof innerArray, returned instanceof Array]);
+  result.push(['symbols', vm.runInContext('Symbol.iterator', sandbox) === Symbol.iterator, vm.runInContext('Symbol.for("shared-vm-symbol")', sandbox) === Symbol.for('shared-vm-symbol')]);
+  try { vm.runInContext('throw new Error("inside")', sandbox, { filename: 'vm-fixture.js' }); }
+  catch (error) { result.push(['error', error.message, error instanceof Error, String(error.stack).includes('vm-fixture.js')]); }
+  try { vm.runInContext('while (true) {}', sandbox, { timeout: 1 }); }
+  catch (error) { result.push(['timeout', error.code]); }
+  result.push(['after-timeout', vm.runInContext('value + 1', sandbox)]);
+  result.push(['compile-function', vm.compileFunction('return prefix + value', ['value'], { parsingContext: vm.createContext({ prefix: '>' }) })('ok')]);
+  result.push(['this-context', vm.runInThisContext('typeof shared'), vm.runInNewContext('value += 1; value', { value: 10 })]);
+  const storage = new AsyncLocalStorage();
+  const order = [];
+  await storage.run('request', async () => {
+    const nested = vm.createContext({ current: () => storage.getStore() });
+    result.push(['context', vm.runInContext('current()', nested), storage.getStore()]);
+    process.nextTick(() => order.push('tick:' + storage.getStore()));
+    Promise.resolve().then(() => order.push('promise:' + storage.getStore()));
+    await new Promise(resolve => setTimeout(() => { order.push('timer:' + storage.getStore()); resolve(); }, 1));
+  });
+  result.push(['outer-scheduling', order, storage.getStore() === undefined, [] instanceof Array, ({}).constructor === Object]);
+  const originalThen = Promise.prototype.then;
+  let resolveAdopted;
+  const adopted = new Promise(resolve => { resolveAdopted = resolve; });
+  Promise.prototype.then = function () { throw new Error('intercepted'); };
+  vm.createContext({});
+  resolveAdopted(Promise.resolve(1));
+  Promise.prototype.then = originalThen;
+  result.push(['patched-then', await adopted.then(() => 'unobserved', error => error.message)]);
+  const foreignGenerator = vm.runInContext('(function* () { yield 1; return 2; })', sandbox);
+  const foreignObject = vm.runInContext('Object', sandbox);
+  const iterator = foreignGenerator();
+  const localIterator = (function* () { yield 0; })();
+  const first = iterator.next();
+  const second = localIterator.next.call(iterator);
+  result.push(['generator-realms', Object.getPrototypeOf(Object.prototype) === null, Object.getPrototypeOf(foreignObject.prototype) === null, Object.getPrototypeOf(first) === foreignObject.prototype, Object.getPrototypeOf(second) === Object.prototype, first.value, second.value]);
+  return result;
+});
diff --git a/tests/Unit/Node/fixtures/primitives/vm.json b/tests/Unit/Node/fixtures/primitives/vm.json
new file mode 100644
index 00000000..7e7b7d28
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/vm.json
@@ -0,0 +1,116 @@
+[
+  [
+    "create",
+    false,
+    true,
+    true,
+    true
+  ],
+  [
+    "global",
+    true,
+    true,
+    true,
+    [
+      "shared",
+      "value"
+    ]
+  ],
+  [
+    "intrinsics",
+    true,
+    true,
+    false,
+    "undefined"
+  ],
+  [
+    "bindings",
+    5,
+    9,
+    7,
+    true,
+    18
+  ],
+  [
+    "live",
+    31
+  ],
+  [
+    "accessor",
+    62
+  ],
+  [
+    "script",
+    31,
+    4,
+    62,
+    62,
+    4
+  ],
+  [
+    "closure",
+    [
+      31,
+      11
+    ],
+    true,
+    false
+  ],
+  [
+    "symbols",
+    true,
+    true
+  ],
+  [
+    "error",
+    "inside",
+    false,
+    true
+  ],
+  [
+    "timeout",
+    "ERR_SCRIPT_EXECUTION_TIMEOUT"
+  ],
+  [
+    "after-timeout",
+    32
+  ],
+  [
+    "compile-function",
+    ">ok"
+  ],
+  [
+    "this-context",
+    "undefined",
+    11
+  ],
+  [
+    "context",
+    "request",
+    "request"
+  ],
+  [
+    "outer-scheduling",
+    [
+      "promise:request",
+      "tick:request",
+      "timer:request"
+    ],
+    true,
+    true,
+    true
+  ],
+  [
+    "patched-then",
+    "intercepted"
+  ],
+  [
+    "generator-realms",
+    true,
+    true,
+    true,
+    true,
+    1,
+    2
+  ]
+]
diff --git a/tests/Unit/Node/fixtures/primitives/vm.mjs b/tests/Unit/Node/fixtures/primitives/vm.mjs
new file mode 100644
index 00000000..6aa47cb2
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/vm.mjs
@@ -0,0 +1 @@
+import './vm.cjs';
diff --git a/tests/Unit/Node/fixtures/primitives/zlib-inputs.json b/tests/Unit/Node/fixtures/primitives/zlib-inputs.json
new file mode 100644
index 00000000..40ed999e
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/zlib-inputs.json
@@ -0,0 +1,6 @@
+{
+  "gzip": "H4sIAAAAAAAAE8tIzcnJV/gwv6eXQSEpMy+xqPLwfoUMsCCYBAB6XThkIAAAAA==",
+  "deflate": "eJzLSM3JyVf4ML+nl0EhKTMvsajy8H6FDLAgmAQA4U8NbA==",
+  "deflateRaw": "y0jNyclX+DC/p5dBISkzL7Go8vB+hQywIJgEAA==",
+  "brotliCompress": "iw+AaGVsbG8g8J+MjQAgYmluYXJ5w78gaGVsbG8gaGVsbG8D"
+}
diff --git a/tests/Unit/Node/fixtures/primitives/zlib.cjs b/tests/Unit/Node/fixtures/primitives/zlib.cjs
new file mode 100644
index 00000000..c109a903
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/zlib.cjs
@@ -0,0 +1,49 @@
+'use strict';
+const zlib = require('node:zlib');
+const { Readable, Writable } = require('node:stream');
+const { pipeline } = require('node:stream/promises');
+const { promisify } = require('node:util');
+const upstream = require('./zlib-inputs.json');
+
+require('./helpers.cjs').run(async () => {
+  const result = [];
+  const input = Buffer.from('hello 🌍\0 binary\xff hello hello');
+  for (const [compress, decompress] of [['gzip', 'gunzip'], ['deflate', 'inflate'], ['deflateRaw', 'inflateRaw'], ['brotliCompress', 'brotliDecompress']]) {
+    const encoded = zlib[compress + 'Sync'](input);
+    result.push(['roundtrip', compress, zlib[decompress + 'Sync'](encoded).equals(input), zlib[decompress + 'Sync'](Buffer.from(upstream[compress], 'base64')).equals(input)]);
+    result.push(['callback', compress, (await promisify(zlib[decompress])(await promisify(zlib[compress])(input))).equals(input)]);
+  }
+  result.push(['unzip', zlib.unzipSync(Buffer.from(upstream.gzip, 'base64')).equals(input), zlib.unzipSync(Buffer.from(upstream.deflate, 'base64')).equals(input)]);
+  const dictionary = Buffer.from('hello world universe');
+  const dictCompressed = zlib.deflateSync('hello world world', { dictionary });
+  result.push(['dictionary', zlib.inflateSync(dictCompressed, { dictionary }).toString()]);
+  for (const [name, data] of [['invalid', Buffer.from('invalid')], ['truncated', Buffer.from(upstream.gzip, 'base64').subarray(0, -3)]]) {
+    try { zlib.gunzipSync(data); }
+    catch (error) { result.push(['error', name, error.code, error.errno]); }
+  }
+  try { zlib.gunzipSync(Buffer.from(upstream.gzip, 'base64'), { maxOutputLength: 5 }); }
+  catch (error) { result.push(['limit', error.code]); }
+  const joined = Buffer.concat([Buffer.from(upstream.gzip, 'base64'), Buffer.from(upstream.gzip, 'base64')]);
+  result.push(['concatenated', zlib.gunzipSync(joined).equals(Buffer.concat([input, input]))]);
+  result.push(['checksum', zlib.crc32('hello'), zlib.crc32('world', zlib.crc32('hello'))]);
+
+  for (const [name, data] of [['Gunzip', upstream.gzip], ['Inflate', upstream.deflate], ['BrotliDecompress', upstream.brotliCompress]]) {
+    const encoded = Buffer.from(data, 'base64');
+    const chunks = Array.from(encoded, byte => Buffer.from([byte]));
+    const decoder = zlib['create' + name]();
+    const output = [];
+    await pipeline(Readable.from(chunks), decoder, new Writable({ write(chunk, encoding, done) { output.push(chunk); done(); } }));
+    result.push(['stream', name, Buffer.concat(output).equals(input), decoder.bytesWritten === encoded.length, decoder.destroyed]);
+  }
+  const gzip = zlib.createGzip({ chunkSize: 64 });
+  const encoded = [];
+  gzip.on('data', chunk => encoded.push(chunk));
+  gzip.write('first');
+  await new Promise((resolve, reject) => gzip.flush(zlib.constants.Z_SYNC_FLUSH, error => error ? reject(error) : resolve()));
+  const hadOutput = encoded.length > 0;
+  await new Promise((resolve, reject) => { gzip.on('error', reject); gzip.on('end', resolve); gzip.end('second'); });
+  result.push(['flush', hadOutput, zlib.gunzipSync(Buffer.concat(encoded)).toString()]);
+  const info = zlib.gunzipSync(Buffer.from(upstream.gzip, 'base64'), { info: true });
+  result.push(['info', info.buffer.equals(input), info.engine.bytesWritten === Buffer.from(upstream.gzip, 'base64').length]);
+  return result;
+});
diff --git a/tests/Unit/Node/fixtures/primitives/zlib.json b/tests/Unit/Node/fixtures/primitives/zlib.json
new file mode 100644
index 00000000..bd287b82
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/zlib.json
@@ -0,0 +1,111 @@
+[
+  [
+    "roundtrip",
+    "gzip",
+    true,
+    true
+  ],
+  [
+    "callback",
+    "gzip",
+    true
+  ],
+  [
+    "roundtrip",
+    "deflate",
+    true,
+    true
+  ],
+  [
+    "callback",
+    "deflate",
+    true
+  ],
+  [
+    "roundtrip",
+    "deflateRaw",
+    true,
+    true
+  ],
+  [
+    "callback",
+    "deflateRaw",
+    true
+  ],
+  [
+    "roundtrip",
+    "brotliCompress",
+    true,
+    true
+  ],
+  [
+    "callback",
+    "brotliCompress",
+    true
+  ],
+  [
+    "unzip",
+    true,
+    true
+  ],
+  [
+    "dictionary",
+    "hello world world"
+  ],
+  [
+    "error",
+    "invalid",
+    "Z_DATA_ERROR",
+    -3
+  ],
+  [
+    "error",
+    "truncated",
+    "Z_BUF_ERROR",
+    -5
+  ],
+  [
+    "limit",
+    "ERR_BUFFER_TOO_LARGE"
+  ],
+  [
+    "concatenated",
+    true
+  ],
+  [
+    "checksum",
+    907060870,
+    4192936109
+  ],
+  [
+    "stream",
+    "Gunzip",
+    true,
+    true,
+    true
+  ],
+  [
+    "stream",
+    "Inflate",
+    true,
+    true,
+    true
+  ],
+  [
+    "stream",
+    "BrotliDecompress",
+    true,
+    true,
+    true
+  ],
+  [
+    "flush",
+    true,
+    "firstsecond"
+  ],
+  [
+    "info",
+    true,
+    true
+  ]
+]
diff --git a/tests/Unit/Node/fixtures/primitives/zlib.mjs b/tests/Unit/Node/fixtures/primitives/zlib.mjs
new file mode 100644
index 00000000..811922d0
--- /dev/null
+++ b/tests/Unit/Node/fixtures/primitives/zlib.mjs
@@ -0,0 +1 @@
+import './zlib.cjs';
diff --git a/tests/Unit/Runtime/AsyncReturnCallTest.php b/tests/Unit/Runtime/AsyncReturnCallTest.php
new file mode 100644
index 00000000..88f03f35
--- /dev/null
+++ b/tests/Unit/Runtime/AsyncReturnCallTest.php
@@ -0,0 +1,95 @@
+ */
+    public static function executionModes(): iterable
+    {
+        yield 'normal' => [false];
+        yield 'budgeted interpreter' => [true];
+    }
+
+    #[DataProvider('executionModes')]
+    public function testAsyncReturnsEvaluateCallsBeforeSettlingTheirPromises(bool $budgeted): void
+    {
+        $engine = $this->engine($budgeted);
+        $engine->eval(<<<'JS'
+'use strict';
+var calls = [];
+var result;
+function create(name) { calls.push(name); return { body: name }; }
+async function immediate() { return create('immediate'); }
+async function suspended() { await 0; return create('suspended'); }
+async function nested() { return immediate(); }
+var arrow = async () => { return create('arrow'); };
+var object = { async method() { return create('method'); } };
+Promise.all([immediate(), suspended(), nested(), arrow(), object.method()])
+    .then(values => { result = values.map(value => value.body); });
+JS);
+
+        self::assertSame(
+            ['immediate', 'suspended', 'immediate', 'arrow', 'method'],
+            $engine->eval('result;'),
+        );
+        self::assertSame(
+            ['immediate', 'immediate', 'arrow', 'method', 'suspended'],
+            $engine->eval('calls;'),
+        );
+    }
+
+    #[DataProvider('executionModes')]
+    public function testAsyncReturnedCallFailuresRejectTheOuterPromise(bool $budgeted): void
+    {
+        $engine = $this->engine($budgeted);
+        $engine->eval(<<<'JS'
+'use strict';
+var result;
+var expected = new Error('called');
+function fail() { throw expected; }
+async function immediate() { return fail(); }
+async function suspended() { await 0; return fail(); }
+Promise.all([immediate().catch(error => error === expected), suspended().catch(error => error === expected)])
+    .then(values => { result = values; });
+JS);
+
+        self::assertSame([true, true], $engine->eval('result;'));
+    }
+
+    #[DataProvider('executionModes')]
+    public function testGeneratorReturnCallsBecomeIteratorCompletionValues(bool $budgeted): void
+    {
+        $engine = $this->engine($budgeted);
+        $engine->eval(<<<'JS'
+'use strict';
+var asyncResult;
+function create() { return { body: 'done' }; }
+function* syncGenerator() { yield 'start'; return create(); }
+async function* asyncGenerator() { yield 'start'; return create(); }
+var sync = syncGenerator();
+var first = sync.next();
+var last = sync.next();
+var async = asyncGenerator();
+async.next().then(() => async.next()).then(value => { asyncResult = [value.done, value.value.body]; });
+JS);
+
+        self::assertSame([false, 'start', true, 'done'], $engine->eval('[first.done, first.value, last.done, last.value.body];'));
+        self::assertSame([true, 'done'], $engine->eval('asyncResult;'));
+    }
+
+    private function engine(bool $budgeted): Engine
+    {
+        $engine = new Engine();
+        if ($budgeted) {
+            $engine->setExecutionBudget(5);
+        }
+        return $engine;
+    }
+}
diff --git a/tests/Unit/Runtime/CrossRealmGeneratorTest.php b/tests/Unit/Runtime/CrossRealmGeneratorTest.php
new file mode 100644
index 00000000..9af8a1a6
--- /dev/null
+++ b/tests/Unit/Runtime/CrossRealmGeneratorTest.php
@@ -0,0 +1,80 @@
+ */
+    public static function generatorBodies(): iterable
+    {
+        yield 'snapshot' => ['yield 1; return 2;'];
+        yield 'fiber' => ['try { yield 1; return 2; } finally {}'];
+    }
+
+    #[DataProvider('generatorBodies')]
+    public function testCreationKeepsForeignAndCustomPrototypeChainsIntact(string $body): void
+    {
+        $foreign = new Engine();
+        $foreign->eval('var generator = function* () { ' . $body . ' }; var originalPrototype = generator.prototype;');
+        $caller = new Engine();
+        $caller->setGlobalJsValue('foreignGenerator', $foreign->getGlobalEnv()->get('generator'));
+        $caller->setGlobalJsValue('ForeignObject', $foreign->getGlobalEnv()->get('Object'));
+        self::assertTrue($caller->eval(<<<'JS'
+const foreign = foreignGenerator();
+Object.getPrototypeOf(ForeignObject.prototype) === null && Object.getPrototypeOf(Object.prototype) === null;
+JS));
+        self::assertTrue($caller->eval(<<<'JS'
+const custom = Object.create(null);
+foreignGenerator.prototype = custom;
+const customized = foreignGenerator();
+Object.getPrototypeOf(customized) === custom && Object.getPrototypeOf(custom) === null;
+JS));
+        $foreign->eval('generator.prototype = null;');
+        self::assertTrue($caller->eval(<<<'JS'
+const fallback = foreignGenerator();
+Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(fallback))) === ForeignObject.prototype;
+JS));
+    }
+
+    #[DataProvider('generatorBodies')]
+    public function testResultObjectsBelongToInvokedNextAndReturnMethods(string $body): void
+    {
+        $foreign = new Engine();
+        $foreign->eval('var generator = function* () { ' . $body . ' };');
+        $caller = new Engine();
+        $caller->setGlobalJsValue('foreignGenerator', $foreign->getGlobalEnv()->get('generator'));
+        $caller->setGlobalJsValue('ForeignObject', $foreign->getGlobalEnv()->get('Object'));
+        self::assertTrue($caller->eval(<<<'JS'
+const iterator = foreignGenerator();
+const local = (function* () { yield 0; })();
+const first = iterator.next();
+const second = local.next.call(iterator);
+const third = iterator.return(3);
+const fourth = local.return.call(iterator, 4);
+Object.getPrototypeOf(first) === ForeignObject.prototype && first.value === 1 && !first.done &&
+Object.getPrototypeOf(second) === Object.prototype && second.value === 2 && second.done &&
+Object.getPrototypeOf(third) === ForeignObject.prototype && third.value === 3 && third.done &&
+Object.getPrototypeOf(fourth) === Object.prototype && fourth.value === 4 && fourth.done;
+JS));
+    }
+
+    public function testIteratorResultsDefineOwnDataPropertiesWithoutPrototypeSetters(): void
+    {
+        $engine = new Engine();
+        self::assertSame('1:true:0', $engine->eval(<<<'JS'
+let calls = 0;
+Object.defineProperty(Object.prototype, 'value', { __proto__: null, set() { calls++; }, configurable: true });
+Object.defineProperty(Object.prototype, 'done', { __proto__: null, set() { calls++; }, configurable: true });
+const result = (function* () { return 1; })().next();
+delete Object.prototype.value;
+delete Object.prototype.done;
+[result.value, result.done, calls].join(':');
+JS));
+    }
+}
diff --git a/tests/Unit/Runtime/FunctionArgumentsAnalysisTest.php b/tests/Unit/Runtime/FunctionArgumentsAnalysisTest.php
new file mode 100644
index 00000000..885125d2
--- /dev/null
+++ b/tests/Unit/Runtime/FunctionArgumentsAnalysisTest.php
@@ -0,0 +1,39 @@
+eval(<<<'JS'
+function factory() {
+  return function capture() {
+    return [() => arguments[0], function own() { return arguments[0]; }];
+  };
+}
+const first = factory()('first');
+const second = factory()('second');
+[first[0](), second[0](), second[1]('inner')].join(':');
+JS));
+    }
+
+    public function testRepeatedDefaultParametersAndEvalCanStillObserveArguments(): void
+    {
+        $engine = new Engine();
+        self::assertSame('two:3:4:undefined', $engine->eval(<<<'JS'
+function factory() {
+  return function capture(value, previous = arguments[0]) {
+    return previous + ':' + eval('arguments[2]');
+  };
+}
+[factory()('one', 'two', 3), factory()(4)].join(':');
+JS));
+    }
+}
diff --git a/tests/Unit/Runtime/GlobalObjectEnvironmentTest.php b/tests/Unit/Runtime/GlobalObjectEnvironmentTest.php
index aa7d10a1..f511dfbb 100644
--- a/tests/Unit/Runtime/GlobalObjectEnvironmentTest.php
+++ b/tests/Unit/Runtime/GlobalObjectEnvironmentTest.php
@@ -9,6 +9,41 @@
 
 class GlobalObjectEnvironmentTest extends TestCase
 {
+    public function testDeletedConfigurableGlobalsDoNotRestoreSavedBindings(): void
+    {
+        $engine = new Engine();
+        self::assertSame(['object', true, 'undefined', 'ReferenceError', 17], $engine->eval(<<<'JS'
+const values = [typeof performance];
+values.push(delete globalThis.performance, typeof performance);
+try { (() => { 'use strict'; performance = 3; })(); } catch (error) { values.push(error.name); }
+globalThis.performance = 17;
+values.push(performance);
+values;
+JS));
+    }
+
+    public function testDeletedGlobalCanResolveAnInheritedPropertyAndLexicalShadowSurvives(): void
+    {
+        $engine = new Engine();
+        self::assertSame([9, 20, false], $engine->eval(<<<'JS'
+globalThis.replaceable = 3;
+replaceable = 4;
+delete globalThis.replaceable;
+Object.defineProperty(Object.prototype, 'replaceable', { value: 9, configurable: true });
+const first = replaceable;
+let shadow = 20;
+globalThis.shadow = 5;
+delete globalThis.shadow;
+[first, shadow, 'shadow' in globalThis];
+JS));
+    }
+
+    public function testLazyGlobalCanBeReplacedBeforeFirstRead(): void
+    {
+        $engine = new Engine();
+        self::assertSame(42, $engine->eval('"use strict"; globalThis.fetch = () => 42; fetch();'));
+    }
+
     public function testGlobalVarCreatesAnOwnPropertyWithoutInvokingInheritedAccessors(): void
     {
         foreach (['', '"use strict";'] as $directive) {

From 29380037aeb41bb1c4c7010855fa0e9af455f24a Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" 
Date: Fri, 23 Oct 2026 18:45:10 +0000
Subject: [PATCH 02/99] Update COMPAT.md from CI [skip ci]

---
 COMPAT.md   |  44 +++++++--------
 compat.json | 150 +++++++++++++++++++++++++++-------------------------
 2 files changed, 101 insertions(+), 93 deletions(-)

diff --git a/COMPAT.md b/COMPAT.md
index 9456d544..7255dfaa 100644
--- a/COMPAT.md
+++ b/COMPAT.md
@@ -3,13 +3,13 @@
 Generated from a completed `test262` pass. Do not edit by hand.
 
 - Refresh: `./bin/compat-report`
-- Snapshot time: `2026-10-23T16:03:28+00:00`
+- Snapshot time: `2026-10-23T18:45:09+00:00`
 - Chunk size: `25`
 - Timeout: `300s`
 - Jobs: `4`
 - Groups: `161`
 - Test files: `53616`
-- Git: `fix/test262-compliance-20261023` @ `8f305b5c` (dirty)
+- Git: `feat/express-hono-compatibility` @ `3ac7add4` (dirty)
 
 ## Summary
 
@@ -198,26 +198,26 @@ Generated from a completed `test262` pass. Do not edit by hand.
 
 | Group | Kind | Duration | Files | Sample |
 |---|---|---:|---:|---|
-| staging/sm | NORMAL | 270.309s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` |
-| staging/sm | NORMAL | 268.329s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` |
-| staging/sm | NORMAL | 263.033s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` |
-| staging/sm | NORMAL | 261.889s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` |
-| staging/sm | NORMAL | 259.048s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` |
-| staging/sm | NORMAL | 228.625s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` |
-| built-ins/decodeURIComponent | NORMAL | 225.385s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` |
-| staging/sm | NORMAL | 213.468s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` |
-| built-ins/decodeURI | NORMAL | 205.779s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` |
-| staging/sm | NORMAL | 192.702s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` |
-| staging/sm | NORMAL | 165.142s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` |
-| staging/sm | NORMAL | 138.127s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` |
-| built-ins/TypedArray | NORMAL | 78.193s | 3 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end.js` | -| built-ins/decodeURI | NORMAL | 69.761s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | -| built-ins/decodeURIComponent | NORMAL | 69.395s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | -| staging/sm | NORMAL | 62.442s | 1 | `test262/test/staging/sm/Array/toSpliced-dense.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.976s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Cuneiform.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Cypriot.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Cypro_Minoan.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.944s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Linear_A.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Linear_B.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lisu.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.836s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.263s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js` | +| built-ins/decodeURIComponent | NORMAL | 290.158s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| built-ins/decodeURI | NORMAL | 262.427s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| staging/sm | NORMAL | 173.911s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 173.728s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 172.730s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 171.487s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 169.559s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 149.649s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| staging/sm | NORMAL | 148.734s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 145.401s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| staging/sm | NORMAL | 135.000s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| staging/sm | NORMAL | 116.964s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| built-ins/decodeURI | NORMAL | 94.553s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | +| built-ins/decodeURIComponent | NORMAL | 94.443s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | +| built-ins/TypedArray | NORMAL | 77.784s | 3 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end.js` | +| language/literals | NORMAL | 70.363s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | +| intl402/DateTimeFormat | NORMAL | 68.395s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | +| staging/sm | NORMAL | 63.850s | 1 | `test262/test/staging/sm/Array/toSpliced-dense.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.852s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/IDS_Trinary_Operator.js`
`test262/test/built-ins/RegExp/property-escapes/generated/ID_Continue.js`
`test262/test/built-ins/RegExp/property-escapes/generated/ID_Start.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Ideographic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Join_Control.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.712s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Dash.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Default_Ignorable_Code_Point.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Deprecated.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Diacritic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Emoji.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 3315aa76..365f03ba 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-23T16:03:28+00:00", - "updatedAt": "2026-10-23T16:03:28+00:00", + "generatedAt": "2026-10-23T18:45:09+00:00", + "updatedAt": "2026-10-23T18:45:09+00:00", "complete": true, "git": { - "branch": "fix/test262-compliance-20261023", - "commit": "8f305b5c", + "branch": "feat/express-hono-compatibility", + "commit": "3ac7add4", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "b1febb17a2c362ebd13089d15b373dfb893ba458", - "runIdentity": "a86d7ea584bb57f1fbf242fcd625f2b237204ab14ddf6f9d6b624086bd9a4ef5" + "fingerprint": "94ed41d682b079b976f2e9b4fd63434c3659259c", + "runIdentity": "3355ba33b0d9db4fa165fcde286b12d8895562484fbde1543a1004c859e8421a" }, "discovery": { "groupCount": 161, @@ -2717,36 +2717,36 @@ "blockedChunks": [], "slowChunks": [ { - "group": "staging/sm", + "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 270.309, + "durationSec": 290.158, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" ] }, { - "group": "staging/sm", + "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 268.329, + "durationSec": 262.427, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 263.033, + "durationSec": 173.911, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 261.889, + "durationSec": 173.728, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" @@ -2755,52 +2755,43 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 259.048, + "durationSec": 172.73, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 228.625, - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" - ] - }, - { - "group": "built-ins/decodeURIComponent", - "kind": "normal", - "durationSec": 225.385, + "durationSec": 171.487, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 213.468, + "durationSec": 169.559, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { - "group": "built-ins/decodeURI", + "group": "staging/sm", "kind": "normal", - "durationSec": 205.779, + "durationSec": 149.649, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 192.702, + "durationSec": 148.734, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" @@ -2809,7 +2800,7 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 165.142, + "durationSec": 145.401, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" @@ -2818,27 +2809,25 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 138.127, + "durationSec": 135, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { - "group": "built-ins/TypedArray", + "group": "staging/sm", "kind": "normal", - "durationSec": 78.193, - "filesCount": 3, + "durationSec": 116.964, + "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js", - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end.js" + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 69.761, + "durationSec": 94.553, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", @@ -2851,7 +2840,7 @@ { "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 69.395, + "durationSec": 94.443, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", @@ -2862,56 +2851,75 @@ ] }, { - "group": "staging/sm", + "group": "built-ins/TypedArray", "kind": "normal", - "durationSec": 62.442, - "filesCount": 1, + "durationSec": 77.784, + "filesCount": 3, "sampleFiles": [ - "test262/test/staging/sm/Array/toSpliced-dense.js" + "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", + "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js", + "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end.js" ] }, { - "group": "built-ins/RegExp/property-escapes/generated", + "group": "language/literals", "kind": "normal", - "durationSec": 59.976, - "filesCount": 3, + "durationSec": 70.363, + "filesCount": 25, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Cuneiform.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Cypriot.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Cypro_Minoan.js" + "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", + "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", + "...", + "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", + "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" ] }, { - "group": "built-ins/RegExp/property-escapes/generated", + "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 59.944, - "filesCount": 3, + "durationSec": 68.395, + "filesCount": 12, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Linear_A.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Linear_B.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lisu.js" + "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", + "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js", + "...", + "test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js", + "test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js" + ] + }, + { + "group": "staging/sm", + "kind": "normal", + "durationSec": 63.85, + "filesCount": 1, + "sampleFiles": [ + "test262/test/staging/sm/Array/toSpliced-dense.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.836, - "filesCount": 3, + "durationSec": 59.852, + "filesCount": 5, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js" + "test262/test/built-ins/RegExp/property-escapes/generated/IDS_Trinary_Operator.js", + "test262/test/built-ins/RegExp/property-escapes/generated/ID_Continue.js", + "test262/test/built-ins/RegExp/property-escapes/generated/ID_Start.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Ideographic.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Join_Control.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.263, - "filesCount": 3, + "durationSec": 59.712, + "filesCount": 5, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Dash.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Default_Ignorable_Code_Point.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Deprecated.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Diacritic.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Emoji.js" ] } ] From 0cef9bc9e53c2676105c358e297080c3c9856484 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 21:19:03 +0200 Subject: [PATCH 03/99] Preserve runtime state across compiled calls and VM realms --- CHANGELOG.md | 6 +- phpcs.xml | 2 + src/BuiltIn/Streams/ByteStream.php | 12 +- src/BuiltIn/Streams/ReadableStream.php | 18 +- src/BuiltIn/Streams/StreamHelpers.php | 15 + src/BuiltIn/Streams/TransformStream.php | 6 +- src/BuiltIn/Streams/WritableStream.php | 14 +- src/BuiltIn/StreamsConstructor.php | 14 + src/BuiltIn/String/StringMisc.php | 16 - src/BuiltIn/String/StringSearch.php | 5 +- src/Bytecode/CompiledFunction.php | 15 +- src/Bytecode/Compiler.php | 80 ++- src/Bytecode/Frame.php | 17 +- src/Bytecode/HandlerEntry.php | 7 +- src/Bytecode/Op.php | 8 + .../Parts/CompilerBailoutAnalysis.php | 61 +- src/Bytecode/Parts/CompilerExpression.php | 134 +++- src/Bytecode/Parts/CompilerScope.php | 19 + src/Bytecode/Parts/CompilerStatement.php | 219 +++--- src/Bytecode/SavedFrame.php | 16 + src/Bytecode/VM.php | 69 +- src/Node/VmBindings.php | 5 +- src/Node/VmGlobalObject.php | 57 +- src/Runtime/Interpreter.php | 1 + src/Runtime/Parts/ExpressionEvaluation.php | 81 +-- .../Parts/Helpers/IteratorProtocol.php | 63 +- src/Runtime/Parts/Helpers/RegExpHelpers.php | 512 ++++---------- src/Runtime/Parts/StatementExecution.php | 4 +- src/Spec/AbstractOperations.php | 21 +- src/Value/JsPromise.php | 2 +- src/Value/JsWeakMap.php | 33 +- tests/Frameworks/express/run.py | 2 +- tests/Frameworks/hono/README.md | 6 +- tests/Frameworks/hono/build-selftest.mjs | 16 +- .../hono/fixtures/scheduling-entry.mjs | 7 + .../hono/fixtures/scheduling.test.mjs | 28 + tests/Frameworks/hono/harness.mjs | 2 + tests/Frameworks/hono/scheduling.config.mjs | 8 + tests/Frameworks/hono/selftest.py | 30 +- tests/Unit/BuiltIn/AsyncContextTest.php | 34 + tests/Unit/BuiltIn/StringSearchCacheTest.php | 25 + tests/Unit/BuiltIn/WeakMapLifetimeTest.php | 90 +++ .../BuiltIn/fixtures/string-search-cache.js | 61 ++ .../BuiltIn/fixtures/string-search-cache.json | 1 + tests/Unit/Bytecode/ArgumentsBindingTest.php | 39 + tests/Unit/Bytecode/ArrayBindingTest.php | 41 ++ tests/Unit/Bytecode/CapturedBindingTest.php | 16 + .../Unit/Bytecode/CompilationFailuresTest.php | 23 +- .../Bytecode/CompilationTemplatesTest.php | 28 +- tests/Unit/Bytecode/CustomCallstackTest.php | 6 +- tests/Unit/Bytecode/FinallyCompletionTest.php | 42 ++ tests/Unit/Bytecode/FrameLifetimeTest.php | 59 ++ tests/Unit/Bytecode/LogicalAssignmentTest.php | 38 + tests/Unit/Bytecode/RelationalObjectTest.php | 41 ++ tests/Unit/Bytecode/SpreadCallTest.php | 38 + tests/Unit/Bytecode/TailCallTest.php | 54 +- .../Unit/Bytecode/fixtures/array-bindings.js | 77 ++ .../Bytecode/fixtures/array-bindings.json | 436 ++++++++++++ .../Bytecode/fixtures/finally-completions.js | 89 +++ .../fixtures/finally-completions.json | 172 +++++ .../Bytecode/fixtures/logical-assignments.js | 37 + .../fixtures/logical-assignments.json | 668 ++++++++++++++++++ .../Bytecode/fixtures/relational-objects.js | 51 ++ .../Bytecode/fixtures/relational-objects.json | 68 ++ tests/Unit/Bytecode/fixtures/spread-calls.js | 86 +++ .../Unit/Bytecode/fixtures/spread-calls.json | 295 ++++++++ tests/Unit/Node/StreamRealmTest.php | 78 ++ tests/Unit/Node/VmLazyIntrinsicsTest.php | 66 ++ tests/Unit/Runtime/RegExpPreparationTest.php | 52 ++ 69 files changed, 3654 insertions(+), 788 deletions(-) create mode 100644 tests/Frameworks/hono/fixtures/scheduling-entry.mjs create mode 100644 tests/Frameworks/hono/fixtures/scheduling.test.mjs create mode 100644 tests/Frameworks/hono/scheduling.config.mjs create mode 100644 tests/Unit/BuiltIn/StringSearchCacheTest.php create mode 100644 tests/Unit/BuiltIn/WeakMapLifetimeTest.php create mode 100644 tests/Unit/BuiltIn/fixtures/string-search-cache.js create mode 100644 tests/Unit/BuiltIn/fixtures/string-search-cache.json create mode 100644 tests/Unit/Bytecode/ArgumentsBindingTest.php create mode 100644 tests/Unit/Bytecode/ArrayBindingTest.php create mode 100644 tests/Unit/Bytecode/FinallyCompletionTest.php create mode 100644 tests/Unit/Bytecode/FrameLifetimeTest.php create mode 100644 tests/Unit/Bytecode/LogicalAssignmentTest.php create mode 100644 tests/Unit/Bytecode/RelationalObjectTest.php create mode 100644 tests/Unit/Bytecode/SpreadCallTest.php create mode 100644 tests/Unit/Bytecode/fixtures/array-bindings.js create mode 100644 tests/Unit/Bytecode/fixtures/array-bindings.json create mode 100644 tests/Unit/Bytecode/fixtures/finally-completions.js create mode 100644 tests/Unit/Bytecode/fixtures/finally-completions.json create mode 100644 tests/Unit/Bytecode/fixtures/logical-assignments.js create mode 100644 tests/Unit/Bytecode/fixtures/logical-assignments.json create mode 100644 tests/Unit/Bytecode/fixtures/relational-objects.js create mode 100644 tests/Unit/Bytecode/fixtures/relational-objects.json create mode 100644 tests/Unit/Bytecode/fixtures/spread-calls.js create mode 100644 tests/Unit/Bytecode/fixtures/spread-calls.json create mode 100644 tests/Unit/Node/StreamRealmTest.php create mode 100644 tests/Unit/Node/VmLazyIntrinsicsTest.php create mode 100644 tests/Unit/Runtime/RegExpPreparationTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d5f09079..73b79ba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ - Live Fetch request and response bodies retain streaming, cancellation and clone behavior; Node fetch can communicate with servers in the same engine. - Promise reactions preserve registration-time async context; cross-realm generators preserve their realm prototypes; global-property deletion and CommonJS cache behavior remain observable. - JSON property names and Unicode separators, callable proxies, and UTF-16 string indexing preserve JavaScript behavior across framework workloads. +- Recursive compiled calls keep captured bindings separate, completed VM frames release their references, and WeakMap entries no longer retain otherwise unreachable keys. +- Stream controllers, readers and writers retain their originating realm after VM context creation; pending Promise finalizers retain their registered async context. - Temporal calendar fields, arithmetic, rounding, parsing, timezone boundaries, and Intl formatting use consistent calendar data and option validation. - Module evaluation, source and typed imports, resource disposal, cross-realm intrinsics, numeric serialization, and compiled global bindings follow current language semantics. - Array callbacks observe mutations and holes, and global declarations create own properties without invoking inherited accessors. @@ -21,7 +23,9 @@ - Intl option precedence, legacy constructors, plural notation, numbering systems, and plain date/time formatting. ### Changed -- Bytecode compilation handles captured bindings, default initializers, spread arrays, object prototypes, regular-expression literals and strict tail calls; reusable syntax templates keep closure state separate. +- Bytecode compilation handles captured bindings, default initializers, array bindings, spread calls, computed methods, object prototypes, regular-expression literals and strict tail calls; reusable syntax templates keep closure state separate. +- Protected returns preserve finalizer completion order in bytecode, and logical assignments and object relational operators use the shared JavaScript semantics. +- Bounded regular-expression preparation and cached UTF-16 searches reduce repeated work while preserving fresh objects and observable coercions. - The test262 runner executes both variants of unflagged scripts, preserves raw sources and module parse goals, requires async completion, and checks negative-test error types and phases. - Compatibility shards retain full file manifests; merging rejects overlapping or stale results and keeps missing coverage visible. Incomplete or failing coverage cannot round up to 100%. diff --git a/phpcs.xml b/phpcs.xml index 64215a35..2142ca65 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -19,6 +19,8 @@ tests/Jsx/*/* tests/Unit/Formatter/fixtures/* + tests/Unit/BuiltIn/fixtures/* + tests/Unit/Bytecode/fixtures/* tests/Wpt/fixtures/* tests/Wpt/testharness-shim.js tests/Wpt/upstream/* diff --git a/src/BuiltIn/Streams/ByteStream.php b/src/BuiltIn/Streams/ByteStream.php index 1ed656e5..704f909e 100644 --- a/src/BuiltIn/Streams/ByteStream.php +++ b/src/BuiltIn/Streams/ByteStream.php @@ -114,7 +114,7 @@ function (JsValue $this_, array $args): JsValue { $newTarget = $this_->get('[[NewTarget]]'); if ($newTarget instanceof JsObject) { $ntProto = $newTarget->get('prototype'); - $useProto = $ntProto instanceof JsObject ? $ntProto : self::$byobReaderPrototype; + $useProto = $ntProto instanceof JsObject ? $ntProto : self::getByobReaderPrototype(); $this_->setPrototype($useProto); } self::setUpBYOBReader($this_, $stream); @@ -154,12 +154,12 @@ function (JsValue $this_, array $args): JsValue { public static function getControllerPrototype(): ?JsObject { - return self::$controllerPrototype; + return StreamHelpers::intrinsicPrototype('ReadableByteStreamController'); } public static function getByobReaderPrototype(): ?JsObject { - return self::$byobReaderPrototype; + return StreamHelpers::intrinsicPrototype('ReadableStreamBYOBReader'); } public static function isReadableByteStreamController(JsValue $v): bool @@ -436,7 +436,7 @@ public static function setUpReadableByteStreamControllerFromUnderlyingSource( JsValue $underlyingSource, float $highWaterMark ): void { - $controller = new JsObject(self::$controllerPrototype); + $controller = new JsObject(self::getControllerPrototype()); $controller->setInternalProperty('[[IsReadableByteStreamController]]', true); $controller->setInternalProperty('[[Stream]]', $stream); StreamHelpers::resetQueue($controller); @@ -612,7 +612,7 @@ public static function byteControllerGetBYOBRequest(JsObject $controller): JsVal $firstDesc['byteOffset'] + $firstDesc['bytesFilled'], $remaining ); - $req = new JsObject(self::$byobRequestPrototype); + $req = new JsObject(StreamHelpers::intrinsicPrototype('ReadableStreamBYOBRequest')); $req->setInternalProperty('[[IsReadableStreamBYOBRequest]]', true); $req->setInternalProperty('[[Controller]]', $controller); $req->setInternalProperty('[[View]]', $view); @@ -784,7 +784,7 @@ public static function acquireBYOBReader(JsObject $stream): JsObject if (\Phasis\BuiltIn\Streams\ReadableStream::isReadableStreamLocked($stream)) { throw new TypeError('Stream is locked'); } - $reader = new JsObject(self::$byobReaderPrototype); + $reader = new JsObject(self::getByobReaderPrototype()); self::setUpBYOBReader($reader, $stream); return $reader; } diff --git a/src/BuiltIn/Streams/ReadableStream.php b/src/BuiltIn/Streams/ReadableStream.php index fd214271..6875044b 100644 --- a/src/BuiltIn/Streams/ReadableStream.php +++ b/src/BuiltIn/Streams/ReadableStream.php @@ -67,17 +67,17 @@ final class ReadableStream public static function getPrototype(): ?JsObject { - return self::$prototype; + return StreamHelpers::intrinsicPrototype('ReadableStream'); } public static function getControllerPrototype(): ?JsObject { - return self::$controllerPrototype; + return StreamHelpers::intrinsicPrototype('ReadableStreamDefaultController'); } public static function getReaderPrototype(): ?JsObject { - return self::$readerPrototype; + return StreamHelpers::intrinsicPrototype('ReadableStreamDefaultReader'); } public static function install(Environment $env): JsFunction @@ -99,7 +99,7 @@ function (JsValue $this_, array $args): JsValue { $newTarget = $this_->get('[[NewTarget]]'); if ($newTarget instanceof JsObject) { $ntProto = $newTarget->get('prototype'); - $useProto = $ntProto instanceof JsObject ? $ntProto : self::$prototype; + $useProto = $ntProto instanceof JsObject ? $ntProto : self::getPrototype(); $this_->setPrototype($useProto); } @@ -211,7 +211,7 @@ function (JsValue $this_, array $args): JsValue { $newTarget = $this_->get('[[NewTarget]]'); if ($newTarget instanceof JsObject) { $ntProto = $newTarget->get('prototype'); - $useProto = $ntProto instanceof JsObject ? $ntProto : self::$readerPrototype; + $useProto = $ntProto instanceof JsObject ? $ntProto : self::getReaderPrototype(); $this_->setPrototype($useProto); } self::setUpDefaultReader($this_, $stream); @@ -605,7 +605,7 @@ public static function setUpDefaultControllerFromUnderlyingSource( float $highWaterMark, ?JsFunction $sizeAlgorithm ): void { - $controller = new JsObject(self::$controllerPrototype); + $controller = new JsObject(self::getControllerPrototype()); $controller->setInternalProperty('[[IsReadableStreamDefaultController]]', true); $controller->setInternalProperty('[[Stream]]', $stream); StreamHelpers::resetQueue($controller); @@ -961,7 +961,7 @@ public static function acquireDefaultReader(JsObject $stream): JsObject if (self::isReadableStreamLocked($stream)) { throw new TypeError('ReadableStream is locked'); } - $reader = new JsObject(self::$readerPrototype); + $reader = new JsObject(self::getReaderPrototype()); self::setUpDefaultReader($reader, $stream); return $reader; } @@ -1351,7 +1351,7 @@ public static function readableStreamFromIterable(JsValue $iterable): JsObject } $iteratorRecord = self::getIteratorFlattenable($iterable); - $stream = new JsObject(self::$prototype); + $stream = new JsObject(self::getPrototype()); self::initializeStream($stream); $pullAlgorithm = function () use ($stream, $iteratorRecord): JsPromise { @@ -1403,7 +1403,7 @@ public static function readableStreamFromIterable(JsValue $iterable): JsObject return StreamHelpers::toPromise($result); }; - $controller = new JsObject(self::$controllerPrototype); + $controller = new JsObject(self::getControllerPrototype()); $controller->setInternalProperty('[[IsReadableStreamDefaultController]]', true); $controller->setInternalProperty('[[Stream]]', $stream); StreamHelpers::resetQueue($controller); diff --git a/src/BuiltIn/Streams/StreamHelpers.php b/src/BuiltIn/Streams/StreamHelpers.php index 544ce2fb..9d4283eb 100644 --- a/src/BuiltIn/Streams/StreamHelpers.php +++ b/src/BuiltIn/Streams/StreamHelpers.php @@ -39,6 +39,21 @@ */ final class StreamHelpers { + /** Resolve the executing method's intrinsic, independently of replaced globals or other realms. */ + public static function intrinsicPrototype(string $name): ?JsObject + { + $env = \Phasis\Engine::getCurrentRealm()?->getGlobalEnv(); + if ($env === null) { + return null; + } + $prototype = $env->getIntrinsic($name . '.prototype'); + if ($prototype === null) { + $env->get($name); + $prototype = $env->getIntrinsic($name . '.prototype'); + } + return $prototype instanceof JsObject ? $prototype : null; + } + /** Stream states. */ public const STATE_READABLE = 'readable'; public const STATE_CLOSED = 'closed'; diff --git a/src/BuiltIn/Streams/TransformStream.php b/src/BuiltIn/Streams/TransformStream.php index eaeec2bd..85710866 100644 --- a/src/BuiltIn/Streams/TransformStream.php +++ b/src/BuiltIn/Streams/TransformStream.php @@ -51,7 +51,7 @@ final class TransformStream public static function getPrototype(): ?JsObject { - return self::$prototype; + return StreamHelpers::intrinsicPrototype('TransformStream'); } public static function install(Environment $env): JsFunction @@ -71,7 +71,7 @@ function (JsValue $this_, array $args): JsValue { $newTarget = $this_->get('[[NewTarget]]'); if ($newTarget instanceof JsObject) { $ntProto = $newTarget->get('prototype'); - $useProto = $ntProto instanceof JsObject ? $ntProto : self::$prototype; + $useProto = $ntProto instanceof JsObject ? $ntProto : self::getPrototype(); $this_->setPrototype($useProto); } $transformer = $args[0] ?? JsUndefined::instance(); @@ -298,7 +298,7 @@ public static function initialize( } // Build controller. - $controller = new JsObject(self::$controllerPrototype); + $controller = new JsObject(StreamHelpers::intrinsicPrototype('TransformStreamDefaultController')); $controller->setInternalProperty('[[IsTransformStreamDefaultController]]', true); $controller->setInternalProperty('[[Stream]]', $ts); $controller->setInternalProperty('[[Finished]]', false); diff --git a/src/BuiltIn/Streams/WritableStream.php b/src/BuiltIn/Streams/WritableStream.php index 53a6e90c..adefad65 100644 --- a/src/BuiltIn/Streams/WritableStream.php +++ b/src/BuiltIn/Streams/WritableStream.php @@ -66,17 +66,17 @@ final class WritableStream public static function getPrototype(): ?JsObject { - return self::$prototype; + return StreamHelpers::intrinsicPrototype('WritableStream'); } public static function getControllerPrototype(): ?JsObject { - return self::$controllerPrototype; + return StreamHelpers::intrinsicPrototype('WritableStreamDefaultController'); } public static function getWriterPrototype(): ?JsObject { - return self::$writerPrototype; + return StreamHelpers::intrinsicPrototype('WritableStreamDefaultWriter'); } public static function install(Environment $env): JsFunction @@ -98,7 +98,7 @@ function (JsValue $this_, array $args): JsValue { $newTarget = $this_->get('[[NewTarget]]'); if ($newTarget instanceof JsObject) { $ntProto = $newTarget->get('prototype'); - $useProto = $ntProto instanceof JsObject ? $ntProto : self::$prototype; + $useProto = $ntProto instanceof JsObject ? $ntProto : self::getPrototype(); $this_->setPrototype($useProto); } $underlyingSink = $args[0] ?? JsUndefined::instance(); @@ -168,7 +168,7 @@ function (JsValue $this_, array $args): JsValue { $newTarget = $this_->get('[[NewTarget]]'); if ($newTarget instanceof JsObject) { $ntProto = $newTarget->get('prototype'); - $useProto = $ntProto instanceof JsObject ? $ntProto : self::$writerPrototype; + $useProto = $ntProto instanceof JsObject ? $ntProto : self::getWriterPrototype(); $this_->setPrototype($useProto); } self::setUpDefaultWriter($this_, $stream); @@ -509,7 +509,7 @@ public static function setUpDefaultController( float $highWaterMark, ?JsFunction $sizeAlgorithm ): void { - $controller = new JsObject(self::$controllerPrototype); + $controller = new JsObject(self::getControllerPrototype()); $controller->setInternalProperty('[[IsWritableStreamDefaultController]]', true); $controller->setInternalProperty('[[Stream]]', $stream); StreamHelpers::resetQueue($controller); @@ -598,7 +598,7 @@ public static function acquireDefaultWriter(JsObject $stream): JsObject if (self::isLocked($stream)) { throw new TypeError('WritableStream is locked'); } - $writer = new JsObject(self::$writerPrototype); + $writer = new JsObject(self::getWriterPrototype()); self::setUpDefaultWriter($writer, $stream); return $writer; } diff --git a/src/BuiltIn/StreamsConstructor.php b/src/BuiltIn/StreamsConstructor.php index c4ded51e..6dc16bc2 100644 --- a/src/BuiltIn/StreamsConstructor.php +++ b/src/BuiltIn/StreamsConstructor.php @@ -10,6 +10,7 @@ use Phasis\BuiltIn\Streams\TransformStream; use Phasis\BuiltIn\Streams\WritableStream; use Phasis\Runtime\Environment; +use Phasis\Value\JsObject; /** * Entry point for the WHATWG Streams API. @@ -41,5 +42,18 @@ public static function install(Environment $env): void WritableStream::install($env); TransformStream::install($env); QueuingStrategy::install($env); + $names = [ + 'ReadableStream', 'ReadableStreamDefaultController', 'ReadableStreamDefaultReader', + 'ReadableByteStreamController', 'ReadableStreamBYOBReader', 'ReadableStreamBYOBRequest', + 'WritableStream', 'WritableStreamDefaultController', 'WritableStreamDefaultWriter', + 'TransformStream', 'TransformStreamDefaultController', + ]; + foreach ($names as $name) { + $constructor = $env->get($name); + $prototype = $constructor instanceof JsObject ? $constructor->get('prototype') : null; + if ($prototype instanceof JsObject) { + $env->setIntrinsic($name . '.prototype', $prototype); + } + } } } diff --git a/src/BuiltIn/String/StringMisc.php b/src/BuiltIn/String/StringMisc.php index 3670161e..2cd9b782 100644 --- a/src/BuiltIn/String/StringMisc.php +++ b/src/BuiltIn/String/StringMisc.php @@ -76,22 +76,6 @@ private static function extractString(JsValue $this_): string if ($this_ instanceof JsString) { return $this_->value; } - if ($this_ instanceof JsObject) { - $prim = $this_->get('[[PrimitiveValue]]'); - if ($prim instanceof JsString) { - return $prim->value; - } - // Object wrapping a non-string primitive (e.g. new Object(42), - // new Object(true)): convert the inner primitive to string so - // that String.prototype methods called on the wrapper produce - // the same result as in V8. - if ( - !($prim instanceof JsUndefined) - && !($prim instanceof JsObject) - ) { - return TypeConversion::toString($prim); - } - } return TypeConversion::toString($this_); } diff --git a/src/BuiltIn/String/StringSearch.php b/src/BuiltIn/String/StringSearch.php index 8378a416..f9e7cab4 100644 --- a/src/BuiltIn/String/StringSearch.php +++ b/src/BuiltIn/String/StringSearch.php @@ -99,8 +99,9 @@ private static function indexOf(): \Closure // byte strings and search by byte, then divide by 2. Using // mb_strpos with UTF-8 counts codepoints which misaligns for // strings that contain surrogate pairs (chars above U+FFFF). - $hayU16 = JsString::utf8ToUtf16LE($str); - $needleU16 = JsString::utf8ToUtf16LE($search); + $hayU16 = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); + $needle = $args[0] ?? null; + $needleU16 = $needle instanceof JsString ? $needle->utf16LE() : JsString::utf8ToUtf16LE($search); $hayLen = strlen($hayU16) / 2; $posFloat = isset($args[1]) diff --git a/src/Bytecode/CompiledFunction.php b/src/Bytecode/CompiledFunction.php index 136bb609..8e1ce95c 100644 --- a/src/Bytecode/CompiledFunction.php +++ b/src/Bytecode/CompiledFunction.php @@ -20,6 +20,14 @@ */ final class CompiledFunction { + /** + * Ordered flat array bindings reuse the interpreter's iterator protocol. + * Captured identifiers retain their live Environment binding. + * + * @var list}> + */ + public array $arrayBindings = []; + /** * Inline cache for LOAD_NAME, indexed by PC. Stores the resolved * JsValue at first dispatch; subsequent LOAD_NAMEs at the same PC @@ -28,8 +36,12 @@ final class CompiledFunction * Only declarative bindings are cached. Object-backed globals, * getters, imports and with bindings are resolved on every read. * Environment::set invalidates cached values through a global counter. + * The originating environment must also match: recursive activations of + * one function share bytecode but have distinct captured local bindings. + * Weak references to environments and object values keep the cache from + * retaining a completed activation through a returned closure or object. * - * @var array + * @var array, 1: int, 2: \WeakReference<\Phasis\Runtime\Environment>}> */ public array $loadNameIc = []; @@ -181,6 +193,7 @@ public function __construct( public readonly bool $needsArgsBinding = true, public readonly bool $canSkipEnvAlloc = false, public readonly bool $parametersFromEnvironment = false, + public readonly bool $hasTailCalls = false, ) { } } diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index dd2a98b5..a843e1ef 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -96,6 +96,10 @@ final class Compiler private bool $hasTailCalls = false; + private bool $argumentsAllowed = false; + + private bool $needsArguments = false; + /** @var array Captured function-scope bindings and declaration kinds. */ private array $capturedLocals = []; @@ -164,6 +168,11 @@ final class Compiler */ private array $classNodes = []; + /** + * @var list}> + */ + private array $arrayBindings = []; + /** * Source-like display string for each CALL_METHOD opcode emitted, * keyed by the PC of the opcode. The VM reads this on the @@ -192,19 +201,22 @@ final class Compiler private int $tryEntryStackDepth = 0; /** - * Phase 2 finally guard: stack of loopStack sizes captured at - * each try-with-finally entry. Used to detect whether a - * break / continue inside the protected block targets a loop - * outside the try (bail) versus a nested loop entirely within - * the try (fine — finally still runs because the inner break - * doesn't escape the try). A non-empty stack also forces return - * inside the protected block to bail, since we'd have to inline - * the finally body before RET to preserve spec semantics. + * Loop depths at each active finalizer keep unsupported escaping loop + * completions on the interpreter path. * * @var list */ private array $finallyLoopBoundaries = []; + /** + * Return jumps target the innermost pending finalizer. A finalizer's + * body is compiled after removing its own context, so a return there + * overrides the saved completion and proceeds to any outer finalizer. + * + * @var list}> + */ + private array $finallyContexts = []; + /** * THROW opcode operand: a single int that the VM uses to look * up the right exception via thrown JsValue. Throw lowering @@ -285,11 +297,16 @@ private function compileFunction(JsFunction $fn): CompiledFunction } $this->inGenerator = true; } - $this->tailCallsEnabled = $fn->isStrict() && !$fn->isGenerator(); - if ($this->tailCallsEnabled) { - $this->checkTailCallShapes($fn->getBody()); - } $body = $fn->getBody(); + $functionStrict = $fn->isStrict() + || ($body instanceof BlockStatement && self::programHasUseStrictDirective($body->body)); + $this->tailCallsEnabled = $functionStrict && !$fn->isGenerator(); + // Unmapped arguments and zero-parameter ordinary functions can use + // the interpreter's existing arguments object without slot aliases. + // Sloppy mapped parameter lists retain the interpreter path. + $this->argumentsAllowed = !$fn->isGenerator() && ( + $fn->isArrow() || $functionStrict || $fn->getParams() === [] + ); $isExpressionBody = !$body instanceof BlockStatement; if ($isExpressionBody && !$body instanceof Node) { throw new CompilerBailout('non-AST body'); @@ -343,10 +360,11 @@ private function compileFunction(JsFunction $fn): CompiledFunction slotCount: max(1, count($this->localNames)), nestedFns: $this->nestedFns, needsThis: $needsEnvThis, - needsArgsBinding: $this->capturedLocals !== [], + needsArgsBinding: $this->capturedLocals !== [] || $this->needsArguments, canSkipEnvAlloc: !$needsEnvThis && !$this->parametersFromEnvironment - && $this->capturedLocals === [] && !$this->hasTailCalls, + && $this->capturedLocals === [] && !$this->needsArguments, parametersFromEnvironment: $this->parametersFromEnvironment, + hasTailCalls: $this->hasTailCalls, ); $cf->callMethodDisplays = $this->callMethodDisplays; return $cf; @@ -355,6 +373,9 @@ private function compileFunction(JsFunction $fn): CompiledFunction // Pre-walk: collect every var/let/const/function name in // the body so each is assigned a unique frame slot up front. $this->collectFunctionLocals($body->body); + if ($this->needsArguments && isset($this->localSlots['arguments'])) { + throw new CompilerBailout('local arguments binding'); + } $this->collectCapturedLocals($body); // TDZ guard: bail if any let/const name appears in source @@ -392,40 +413,20 @@ private function compileFunction(JsFunction $fn): CompiledFunction slotCount: max(1, count($this->localNames)), nestedFns: $this->nestedFns, needsThis: $needsEnvThis, - needsArgsBinding: $this->capturedLocals !== [], + needsArgsBinding: $this->capturedLocals !== [] || $this->needsArguments, canSkipEnvAlloc: !$needsEnvThis && !$this->parametersFromEnvironment - && $this->capturedLocals === [] && $this->nestedFns === [] && !$this->hasTailCalls, + && $this->capturedLocals === [] && $this->nestedFns === [] + && !$this->needsArguments, parametersFromEnvironment: $this->parametersFromEnvironment, + hasTailCalls: $this->hasTailCalls, ); $cf->handlers = $this->handlers; $cf->classNodes = $this->classNodes; + $cf->arrayBindings = $this->arrayBindings; $cf->callMethodDisplays = $this->callMethodDisplays; return $cf; } - private function checkTailCallShapes(Node $node): void - { - if ( - $node instanceof FunctionDeclaration - || $node instanceof \Phasis\Ast\Expression\FunctionExpression - || $node instanceof \Phasis\Ast\Expression\ArrowFunction - || $node instanceof \Phasis\Ast\Declaration\ClassDeclaration - || $node instanceof \Phasis\Ast\Expression\ClassExpression - ) { - return; - } - if ($node instanceof \Phasis\Ast\Statement\TryStatement && self::bytecodeBailsForTailCall($node)) { - throw new CompilerBailout('tail calls in try statement'); - } - foreach (get_object_vars($node) as $value) { - foreach (is_array($value) ? $value : [$value] as $child) { - if ($child instanceof Node) { - $this->checkTailCallShapes($child); - } - } - } - } - private function parameterInitializerCanCapture(Node $node): bool { if ( @@ -566,6 +567,7 @@ public function compileProgram(\Phasis\Ast\Program $program): CompiledFunction ); $cf->handlers = $this->handlers; $cf->classNodes = $this->classNodes; + $cf->arrayBindings = $this->arrayBindings; $cf->callMethodDisplays = $this->callMethodDisplays; return $cf; } diff --git a/src/Bytecode/Frame.php b/src/Bytecode/Frame.php index c7df4582..b0258fd0 100644 --- a/src/Bytecode/Frame.php +++ b/src/Bytecode/Frame.php @@ -48,8 +48,8 @@ public function __construct( * Reuse this Frame for a new call. Resets state that varies per * call (env, thisValue, locals, stack pointer) and grows the * locals array if the new slot count is larger than what's - * currently allocated. Stack is left in place — sp = 0 makes any - * leftover entries unreachable. + * currently allocated. Completed calls release all references before + * their frames return to the pool. * * Param slots [0..paramCount-1] are NOT cleared here because the * caller's param-binding loop overwrites them immediately. Skipping @@ -83,4 +83,17 @@ public function reset( $this->locals[$i] = $undefined; } } + + /** Release completed activation references while retaining reusable local slots. */ + public function release(JsValue $undefined): void + { + unset($this->env); + $this->thisValue = $undefined; + $count = count($this->locals); + for ($i = 0; $i < $count; $i++) { + $this->locals[$i] = $undefined; + } + $this->stack = []; + $this->sp = 0; + } } diff --git a/src/Bytecode/HandlerEntry.php b/src/Bytecode/HandlerEntry.php index 3650568a..4b6ae81e 100644 --- a/src/Bytecode/HandlerEntry.php +++ b/src/Bytecode/HandlerEntry.php @@ -14,10 +14,9 @@ * parameter's local slot, resets the operand stack to the entry depth, * and jumps to catchPc. * - * Phase 1 covers `try / catch` only. `try / finally` and `try / catch / - * finally` keep using the tree-walker (compiler bails) because the - * completion-record dance for re-triggering pending return/break/continue - * after finally still needs design work. + * Finalizer handlers save the thrown value in an internal local slot. + * The compiler routes normal, throw and return completions through the + * finalizer outside these protected ranges before resuming the completion. */ final class HandlerEntry { diff --git a/src/Bytecode/Op.php b/src/Bytecode/Op.php index 645b7b19..9667c9ea 100644 --- a/src/Bytecode/Op.php +++ b/src/Bytecode/Op.php @@ -67,6 +67,9 @@ final class Op public const ARRAY_APPEND = 34; // Append a data element to the array below it on the stack. public const ARRAY_SPREAD = 35; // Consume an iterable into the array below it on the stack. public const ARRAY_HOLE = 36; // Extend the array's length without defining an element. + public const BIND_ARRAY = 37; // I: pop iterable, initialize the indexed flat binding pattern in order. + public const IN = 38; // Pop object and key, perform HasProperty after ToPropertyKey. + public const INSTANCEOF = 39; // Pop constructor and value, use InstanceofOperator. // ---- Arithmetic & comparison ---------------------------------------- public const ADD = 40; @@ -130,6 +133,8 @@ final class Op public const JUMP_IF_LOCAL_GT_CONST = 79; // for `i <= N` test // ---- Calls & returns ----------------------------------------------- + // Each call opcode accepts argc=-1 for a compiler-owned dense argument + // array on top of the stack, allowing spread without changing call order. public const CALL = 80; // I — argc; callee at stack[-argc-1] public const CALL_METHOD = 81; // I — argc; stack: [obj, method, args...] // Pops method + args, peeks obj as receiver, @@ -212,6 +217,8 @@ public static function operandCount(int $op): int case self::NEQ: case self::SEQ: case self::SNEQ: + case self::IN: + case self::INSTANCEOF: case self::NOT: case self::TYPEOF: case self::BAND: @@ -246,6 +253,7 @@ public static function operandCount(int $op): int case self::STORE_NAME: case self::DEFINE_NAME: case self::INITIALIZE_NAME: + case self::BIND_ARRAY: case self::TYPEOF_NAME: case self::DELETE_NAME: case self::JUMP: diff --git a/src/Bytecode/Parts/CompilerBailoutAnalysis.php b/src/Bytecode/Parts/CompilerBailoutAnalysis.php index 6aa63ce0..ef71e87d 100644 --- a/src/Bytecode/Parts/CompilerBailoutAnalysis.php +++ b/src/Bytecode/Parts/CompilerBailoutAnalysis.php @@ -259,11 +259,15 @@ private function scanBailout(mixed $statements): void return; } $node = $statements; - if ($node instanceof Identifier && ($node->name === 'eval' || $node->name === 'arguments')) { - // `arguments` in body forces argsObj construction; let - // the tree-walker keep that path. `eval` is dynamic. + if ($node instanceof Identifier && $node->name === 'eval') { throw new CompilerBailout('uses ' . $node->name); } + if ($node instanceof Identifier && $node->name === 'arguments') { + if (!$this->argumentsAllowed) { + throw new CompilerBailout('uses mapped or unavailable arguments'); + } + $this->needsArguments = true; + } if ($node instanceof Identifier && $node->name === '[[NewTarget]]') { // `new.target` reads need an env binding the VM-compiled // prologue skips. Bail to keep the prologue-skip optimization @@ -867,55 +871,4 @@ private static function programHasUseStrictDirective(array $statements): bool } return false; } - - private static function bytecodeBailsForTailCall(\Phasis\Ast\Node $body): bool - { - if ($body instanceof ReturnStatement) { - return $body->argument !== null - && self::tailCallExpr($body->argument); - } - if ( - $body instanceof \Phasis\Ast\Declaration\FunctionDeclaration - || $body instanceof \Phasis\Ast\Expression\FunctionExpression - || $body instanceof \Phasis\Ast\Expression\ArrowFunction - ) { - return false; - } - foreach ((array) $body as $value) { - if ($value instanceof \Phasis\Ast\Node) { - if (self::bytecodeBailsForTailCall($value)) { - return true; - } - continue; - } - if (is_array($value)) { - foreach ($value as $item) { - if ($item instanceof \Phasis\Ast\Node && self::bytecodeBailsForTailCall($item)) { - return true; - } - } - } - } - return false; - } - - private static function tailCallExpr(\Phasis\Ast\Node $node): bool - { - if ($node instanceof CallExpression) { - return true; - } - if ($node instanceof ConditionalExpression) { - return self::tailCallExpr($node->consequent) - || self::tailCallExpr($node->alternate); - } - if ($node instanceof \Phasis\Ast\Expression\LogicalExpression) { - return self::tailCallExpr($node->left) - || self::tailCallExpr($node->right); - } - if ($node instanceof \Phasis\Ast\Expression\SequenceExpression) { - $exprs = $node->expressions; - return $exprs !== [] && self::tailCallExpr($exprs[count($exprs) - 1]); - } - return false; - } } diff --git a/src/Bytecode/Parts/CompilerExpression.php b/src/Bytecode/Parts/CompilerExpression.php index a10dae59..0b54debe 100644 --- a/src/Bytecode/Parts/CompilerExpression.php +++ b/src/Bytecode/Parts/CompilerExpression.php @@ -323,16 +323,8 @@ private function compileTemplate(TemplateLiteral $node): void private function compileNew(NewExpression $node): void { - foreach ($node->arguments as $arg) { - if ($arg instanceof SpreadElement) { - throw new CompilerBailout('spread in new'); - } - } $this->compileExpression($node->callee); - foreach ($node->arguments as $arg) { - $this->compileExpression($arg); - } - $this->emit(Op::NEW_CALL, count($node->arguments)); + $this->emit(Op::NEW_CALL, $this->compileArguments($node->arguments)); } /** @@ -582,9 +574,6 @@ private function compileIdentifier(Identifier $node): void private function compileBinary(BinaryExpression $node): void { - // Bail on operators that need special left-side handling (in, - // instanceof, with-private-field) for now. They're not on the - // hot path of fib / loop microbenchmarks. $op = $node->operator; $opcode = match ($op) { '+' => Op::ADD, @@ -601,6 +590,8 @@ private function compileBinary(BinaryExpression $node): void '!=' => Op::NEQ, '===' => Op::SEQ, '!==' => Op::SNEQ, + 'in' => Op::IN, + 'instanceof' => Op::INSTANCEOF, '&' => Op::BAND, '|' => Op::BOR, '^' => Op::BXOR, @@ -627,7 +618,7 @@ private function compileConditional(ConditionalExpression $node): void private function compileCall(CallExpression $node): void { - // No optional calls / direct eval / spread args yet. + // Optional chains and direct eval retain the interpreter path. if ($node->optional) { throw new CompilerBailout('optional call'); } @@ -637,11 +628,6 @@ private function compileCall(CallExpression $node): void if ($node->callee instanceof Identifier && $node->callee->name === 'super') { throw new CompilerBailout('super call'); } - foreach ($node->arguments as $arg) { - if ($arg instanceof SpreadElement) { - throw new CompilerBailout('spread call argument'); - } - } // Method call: `obj.m(...)` and `obj[k](...)`. Emit // CALL_METHOD with the receiver on the stack so the dispatcher @@ -652,12 +638,6 @@ private function compileCall(CallExpression $node): void && !($node->callee->property instanceof PrivateIdentifier) && !($node->callee->object instanceof Identifier && $node->callee->object->name === 'super') ) { - if ($node->callee->computed) { - throw new CompilerBailout('computed method call'); - } - if (!($node->callee->property instanceof Identifier)) { - throw new CompilerBailout('non-identifier method name'); - } // Spec evaluation order: look up the method (and surface // any TypeError on null/undefined receivers) BEFORE // evaluating any arguments. Stack layout: @@ -668,16 +648,21 @@ private function compileCall(CallExpression $node): void // `this`, leaves result. $this->compileExpression($node->callee->object); $this->emit(Op::DUP); - $this->emit(Op::LOAD_MEMBER, $this->internName($node->callee->property->name)); - foreach ($node->arguments as $arg) { - $this->compileExpression($arg); + if ($node->callee->computed) { + $this->compileExpression($node->callee->property); + $this->emit(Op::LOAD_COMPUTED); + } elseif ($node->callee->property instanceof Identifier) { + $this->emit(Op::LOAD_MEMBER, $this->internName($node->callee->property->name)); + } else { + throw new CompilerBailout('non-identifier method name'); } + $argc = $this->compileArguments($node->arguments); // Render the call-site source for the "is not a function" // error before emit so the PC we record actually points at // the CALL_METHOD opcode. $display = $this->renderMethodCallDisplay($node->callee); $callMethodPc = count($this->code); - $this->emit(Op::CALL_METHOD, count($node->arguments)); + $this->emit(Op::CALL_METHOD, $argc); if ($display !== null) { $this->callMethodDisplays[$callMethodPc] = $display; } @@ -687,10 +672,37 @@ private function compileCall(CallExpression $node): void // Direct function call: callee is anything except a member // expression (i.e. `f(...)` not `obj.m(...)`). $this->compileExpression($node->callee); - foreach ($node->arguments as $arg) { - $this->compileExpression($arg); + $this->emit(Op::CALL, $this->compileArguments($node->arguments)); + } + + /** + * Return the fixed argument count, or -1 for an internal dense argument + * array. The array is never exposed to JavaScript; spread consumes each + * iterator before evaluating the next argument. + * + * @param list $arguments + */ + private function compileArguments(array $arguments): int + { + $hasSpread = false; + foreach ($arguments as $argument) { + $hasSpread = $hasSpread || $argument instanceof SpreadElement; + } + if ($hasSpread) { + $this->emit(Op::NEW_ARRAY, 0); + } + foreach ($arguments as $argument) { + if ($argument instanceof SpreadElement) { + $this->compileExpression($argument->argument); + $this->emit(Op::ARRAY_SPREAD); + } else { + $this->compileExpression($argument); + if ($hasSpread) { + $this->emit(Op::ARRAY_APPEND); + } + } } - $this->emit(Op::CALL, count($node->arguments)); + return $hasSpread ? -1 : count($arguments); } private function compileMember(MemberExpression $node): void @@ -724,12 +736,13 @@ private function compileAssignment(AssignmentExpression $node): void } $left = $node->left; $op = $node->operator; + if ($op === '&&=' || $op === '||=' || $op === '??=') { + $this->compileLogicalAssignment($node); + return; + } // Compound op (`+=`, `-=`, ...) gets lowered to: // load lhs; compile rhs; ; - // Logical compound (`&&=` / `||=` / `??=`) goes to the - // tree-walker because of subtle short-circuit semantics - // around with-environments. $binaryOpcode = match ($op) { '=' => null, '+=' => Op::ADD, @@ -866,4 +879,57 @@ private function compileAssignment(AssignmentExpression $node): void throw new CompilerBailout('unsupported assignment target'); } + + private function compileLogicalAssignment(AssignmentExpression $node): void + { + $left = $node->left; + $receiverSlot = null; + $nameIndex = null; + if ($left instanceof Identifier) { + $slot = $this->localSlots[$left->name] ?? null; + if ($slot === null || isset($this->constSlots[$slot]) || $left->name === 'arguments') { + throw new CompilerBailout('logical assignment requires a mutable local binding'); + } + if (self::initNeedsNamedEvaluation($node->right)) { + throw new CompilerBailout('logical assignment needs named evaluation'); + } + $this->emitLoadLocal($slot); + } elseif ( + $left instanceof MemberExpression && !$left->optional && !$left->computed + && $left->property instanceof Identifier + && !($left->object instanceof Identifier && $left->object->name === 'super') + ) { + // Save the receiver before its getter or RHS can change the + // source binding. Each reference and getter is evaluated once. + $receiverSlot = count($this->localNames); + $this->localNames[] = '[[logicalReceiver]]'; + $nameIndex = $this->internName($left->property->name); + $this->compileExpression($left->object); + $this->emit(Op::DUP); + $this->emit(Op::STORE_LOCAL, $receiverSlot); + $this->emit(Op::LOAD_MEMBER, $nameIndex); + } else { + throw new CompilerBailout('unsupported logical assignment reference'); + } + + if ($node->operator === '??=') { + $assign = $this->emitJump(Op::JUMP_IF_NULLISH); + $end = $this->emitJump(Op::JUMP); + $this->patchJumpToHere($assign); + } else { + $end = $this->emitJump($node->operator === '&&=' + ? Op::JUMP_IF_FALSY_KEEP : Op::JUMP_IF_TRUTHY_KEEP); + } + if ($receiverSlot !== null) { + $this->emit(Op::LOAD_LOCAL, $receiverSlot); + } + $this->compileExpression($node->right); + if ($receiverSlot !== null) { + $this->emit(Op::STORE_MEMBER, $nameIndex); + } else { + $this->emit(Op::DUP); + $this->emitStoreLocal($slot); + } + $this->patchJumpToHere($end); + } } diff --git a/src/Bytecode/Parts/CompilerScope.php b/src/Bytecode/Parts/CompilerScope.php index 055b7172..3c4a8d9a 100644 --- a/src/Bytecode/Parts/CompilerScope.php +++ b/src/Bytecode/Parts/CompilerScope.php @@ -376,6 +376,25 @@ private function collectStatementLocals(Node $stmt): void } continue; } + if ($decl->id instanceof ArrayPattern) { + foreach ($decl->id->elements as $element) { + if ($element === null) { + continue; + } + $target = $element instanceof RestElement ? $element->argument : $element; + if (!$target instanceof Identifier) { + throw new CompilerBailout('complex array pattern'); + } + if ($isLexical && isset($this->localSlots[$target->name])) { + throw new CompilerBailout('let/const pattern shadowing'); + } + if (!$isLexical) { + $this->varDeclaredNames[$target->name] = true; + } + $this->declareLocal($target->name); + } + continue; + } throw new CompilerBailout('destructuring declaration'); } return; diff --git a/src/Bytecode/Parts/CompilerStatement.php b/src/Bytecode/Parts/CompilerStatement.php index daf523d8..635d6b28 100644 --- a/src/Bytecode/Parts/CompilerStatement.php +++ b/src/Bytecode/Parts/CompilerStatement.php @@ -63,15 +63,15 @@ trait CompilerStatement private function compileStatement(Node $node): void { if ($node instanceof ReturnStatement) { - if ($this->finallyLoopBoundaries !== []) { - throw new CompilerBailout('return inside try-with-finally'); + if ($this->inGenerator && $this->finallyLoopBoundaries !== []) { + throw new CompilerBailout('generator return inside try-with-finally'); } if ($node->argument === null) { $this->emit(Op::LOAD_UNDEF); } else { $this->compileReturnExpression($node->argument); } - $this->emit(Op::RET); + $this->emitReturnCompletion(); return; } if ($node instanceof ExpressionStatement) { @@ -234,30 +234,45 @@ private function compileReturnExpression(Node $expression): void $this->hasTailCalls = true; } + /** Consume a return value, routing it through each pending finalizer. */ + private function emitReturnCompletion(): void + { + if ($this->finallyContexts === []) { + $this->emit(Op::RET); + return; + } + $index = count($this->finallyContexts) - 1; + $context = $this->finallyContexts[$index]; + $this->emit(Op::STORE_LOCAL, $context['valueSlot']); + $this->emit(Op::LOAD_TRUE); + $this->emit(Op::STORE_LOCAL, $context['completionSlot']); + $this->finallyContexts[$index]['jumps'][] = $this->emitJump(Op::JUMP); + } + /** - * Lower try/catch/finally through handlers and duplicated finally bodies. - * Returns and loop exits that would escape a protected finally block bail - * to the tree-walker rather than bypassing its completion semantics. + * Keep finalizers outside their protected ranges so their abrupt + * completions override, rather than re-enter, the pending completion. */ private function compileTryCatch(\Phasis\Ast\Statement\TryStatement $node): void { - $hasFinally = $node->finalizer !== null; - $hasCatch = $node->handler !== null; $stackBase = $this->tryEntryStackDepth; - $finallyBoundary = count($this->loopStack); + $tailCallsWereEnabled = $this->tailCallsEnabled; + $this->tailCallsEnabled = false; - // Phase 1 fast path: try / catch with no finalizer. The - // implementation is the original Phase 1 layout. - if (!$hasFinally) { + if ($node->finalizer === null) { $tryStart = count($this->code); - foreach ($node->block->body as $stmt) { - $this->compileStatement($stmt); + try { + foreach ($node->block->body as $stmt) { + $this->compileStatement($stmt); + } + } finally { + $this->tailCallsEnabled = $tailCallsWereEnabled; } $tryEnd = count($this->code); $jmpPastCatch = $this->emitJump(Op::JUMP); $catchPc = count($this->code); $exceptionSlot = -1; - if ($node->handler->param instanceof \Phasis\Ast\Expression\Identifier) { + if ($node->handler->param instanceof Identifier) { $name = $node->handler->param->name; $exceptionSlot = $this->localSlots[$name] ?? $this->declareLocal($name); @@ -276,131 +291,85 @@ private function compileTryCatch(\Phasis\Ast\Statement\TryStatement $node): void return; } - // Phase 2: finalizer present (with or without catch). - // Layout (annotated PCs): - // [tryStart..tryEnd) : try body - // tryEnd : JUMP -> finallyNormalPc - // tryHandlerCatchPc : (catch present) catch param - // mirror + catch body, then - // JUMP -> finallyNormalPc - // (no catch) JUMP -> finallyRethrowPc - // catchHandlerCatchPc : JUMP -> finallyRethrowPc - // finallyNormalPc : finally body, JUMP -> afterTryPc - // finallyRethrowPc : finally body, LOAD rethrowSlot, THROW - // afterTryPc : continuation - $rethrowSlot = count($this->localNames); - $this->localNames[] = '[[finallyRethrow]]'; + // undefined, false and true distinguish normal, throw and return. + // The pending value stays in its own slot across nested finalizers. + $valueSlot = count($this->localNames); + $this->localNames[] = '[[finallyValue]]'; + $completionSlot = count($this->localNames); + $this->localNames[] = '[[finallyCompletion]]'; + $this->finallyContexts[] = [ + 'valueSlot' => $valueSlot, + 'completionSlot' => $completionSlot, + 'jumps' => [], + ]; + $this->finallyLoopBoundaries[] = count($this->loopStack); $tryStart = count($this->code); - $this->finallyLoopBoundaries[] = $finallyBoundary; foreach ($node->block->body as $stmt) { $this->compileStatement($stmt); } - array_pop($this->finallyLoopBoundaries); $tryEnd = count($this->code); - $jmpFromTry = $this->emitJump(Op::JUMP); - - $tryHandlerCatchPc = count($this->code); - $tryHandlerExceptionSlot = -1; - $catchStart = -1; - $catchEnd = -1; - $jmpFromCatch = -1; - $jmpFromTryHandlerNoCatch = -1; + $this->emit(Op::LOAD_UNDEF); + $this->emit(Op::STORE_LOCAL, $completionSlot); + $normalJumps = [$this->emitJump(Op::JUMP)]; + $catchPc = count($this->code); + $exceptionSlot = $valueSlot; - if ($hasCatch) { - // Handler1 stores the thrown value in the catch param - // slot. Mirror it into rethrowSlot so a catch-body throw - // can later observe its OWN exception, not the original. - if ($node->handler->param instanceof \Phasis\Ast\Expression\Identifier) { + if ($node->handler !== null) { + if ($node->handler->param instanceof Identifier) { $name = $node->handler->param->name; - $tryHandlerExceptionSlot = $this->localSlots[$name] + $exceptionSlot = $this->localSlots[$name] ?? $this->declareLocal($name); - $this->emit(Op::LOAD_LOCAL, $tryHandlerExceptionSlot); - $this->emit(Op::STORE_LOCAL, $rethrowSlot); - } else { - // No catch param: still need to seed rethrowSlot from - // the param slot so handler2 can re-throw on - // catch-body exceptions. Allocate a temp. - $tryHandlerExceptionSlot = count($this->localNames); - $this->localNames[] = '[[catchTmp]]'; - $this->emit(Op::LOAD_LOCAL, $tryHandlerExceptionSlot); - $this->emit(Op::STORE_LOCAL, $rethrowSlot); } $catchStart = count($this->code); - $this->finallyLoopBoundaries[] = $finallyBoundary; foreach ($node->handler->body->body as $stmt) { $this->compileStatement($stmt); } - array_pop($this->finallyLoopBoundaries); $catchEnd = count($this->code); - $jmpFromCatch = $this->emitJump(Op::JUMP); - } else { - // No catch: handler1 stores the thrown value directly in - // rethrowSlot, then jumps to the rethrow-finally inline. - $tryHandlerExceptionSlot = $rethrowSlot; - $jmpFromTryHandlerNoCatch = $this->emitJump(Op::JUMP); + $this->emit(Op::LOAD_UNDEF); + $this->emit(Op::STORE_LOCAL, $completionSlot); + $normalJumps[] = $this->emitJump(Op::JUMP); + $this->handlers[] = new HandlerEntry( + tryStart: $catchStart, + tryEnd: $catchEnd, + catchPc: count($this->code), + exceptionSlot: $valueSlot, + stackBase: $stackBase, + ); } + $this->emit(Op::LOAD_FALSE); + $this->emit(Op::STORE_LOCAL, $completionSlot); - // Handler2 (only meaningful if there's a catch): catches - // exceptions thrown inside the catch body and routes them - // through finally before re-raising. - $catchHandlerCatchPc = $hasCatch ? count($this->code) : -1; - $jmpFromHandler2 = -1; - if ($hasCatch) { - $jmpFromHandler2 = $this->emitJump(Op::JUMP); + $context = array_pop($this->finallyContexts); + foreach ([...$normalJumps, ...$context['jumps']] as $jump) { + $this->patchJumpToHere($jump); } - - // Finally inlines. - $finallyNormalPc = count($this->code); - $this->finallyLoopBoundaries[] = $finallyBoundary; + $this->tailCallsEnabled = $tailCallsWereEnabled; foreach ($node->finalizer->body as $stmt) { $this->compileStatement($stmt); } array_pop($this->finallyLoopBoundaries); - $jmpAfterTry = $this->emitJump(Op::JUMP); - $finallyRethrowPc = count($this->code); - $this->finallyLoopBoundaries[] = $finallyBoundary; - foreach ($node->finalizer->body as $stmt) { - $this->compileStatement($stmt); - } - array_pop($this->finallyLoopBoundaries); - $this->emit(Op::LOAD_LOCAL, $rethrowSlot); + $this->emit(Op::LOAD_LOCAL, $completionSlot); + $this->emit(Op::LOAD_FALSE); + $this->emit(Op::SEQ); + $notThrow = $this->emitJump(Op::JUMP_IF_FALSE); + $this->emit(Op::LOAD_LOCAL, $valueSlot); $this->emit(Op::THROW); - - // afterTry. patchJumpToHere targets the current PC; the - // jmpAfterTry was emitted right before this comment so it - // already lines up. - $this->patchJumpToHere($jmpAfterTry); - $this->code[$jmpFromTry] = $finallyNormalPc - ($jmpFromTry - 1); - if ($jmpFromCatch !== -1) { - $this->code[$jmpFromCatch] = $finallyNormalPc - ($jmpFromCatch - 1); - } - if ($jmpFromTryHandlerNoCatch !== -1) { - $this->code[$jmpFromTryHandlerNoCatch] = - $finallyRethrowPc - ($jmpFromTryHandlerNoCatch - 1); - } - if ($jmpFromHandler2 !== -1) { - $this->code[$jmpFromHandler2] = - $finallyRethrowPc - ($jmpFromHandler2 - 1); - } + $this->patchJumpToHere($notThrow); + $this->emit(Op::LOAD_LOCAL, $completionSlot); + $normal = $this->emitJump(Op::JUMP_IF_FALSE); + $this->emit(Op::LOAD_LOCAL, $valueSlot); + $this->emitReturnCompletion(); + $this->patchJumpToHere($normal); $this->handlers[] = new HandlerEntry( tryStart: $tryStart, tryEnd: $tryEnd, - catchPc: $tryHandlerCatchPc, - exceptionSlot: $tryHandlerExceptionSlot, + catchPc: $catchPc, + exceptionSlot: $exceptionSlot, stackBase: $stackBase, ); - if ($hasCatch) { - $this->handlers[] = new HandlerEntry( - tryStart: $catchStart, - tryEnd: $catchEnd, - catchPc: $catchHandlerCatchPc, - exceptionSlot: $rethrowSlot, - stackBase: $stackBase, - ); - } } private function compileIf(IfStatement $node): void @@ -605,6 +574,36 @@ private function compileVarDecl(VariableDeclaration $node): void throw new CompilerBailout('using declaration'); } foreach ($node->declarations as $decl) { + if ($decl->id instanceof ArrayPattern) { + if ($decl->init === null) { + throw new CompilerBailout('destructure without init'); + } + $elements = []; + foreach ($decl->id->elements as $element) { + if ($element === null) { + $elements[] = null; + continue; + } + $target = $element instanceof RestElement ? $element->argument : $element; + if (!$target instanceof Identifier) { + throw new CompilerBailout('complex array pattern'); + } + $slot = $this->localSlots[$target->name]; + $elements[] = [ + 'slot' => $slot, + 'capturedName' => isset($this->capturedLocals[$target->name]) ? $target->name : null, + 'rest' => $element instanceof RestElement, + ]; + if ($node->kind === 'const') { + $this->constSlots[$slot] = true; + } + } + $this->compileExpression($decl->init); + $index = count($this->arrayBindings); + $this->arrayBindings[] = ['kind' => $node->kind, 'elements' => $elements]; + $this->emit(Op::BIND_ARRAY, $index); + continue; + } if ($decl->id instanceof ObjectPattern) { if ($decl->init === null) { throw new CompilerBailout('destructure without init'); diff --git a/src/Bytecode/SavedFrame.php b/src/Bytecode/SavedFrame.php index bbe11ed1..cccc7d30 100644 --- a/src/Bytecode/SavedFrame.php +++ b/src/Bytecode/SavedFrame.php @@ -98,4 +98,20 @@ final class SavedFrame * or unwinds. */ public ?JsObject $newObject = null; + + /** Release a restored caller so an inactive pooled entry cannot retain its realm. */ + public function release(): void + { + unset($this->cf, $this->env, $this->thisValue, $this->callee); + $this->code = []; + $this->consts = []; + $this->names = []; + $this->nestedFns = []; + $this->stack = []; + $this->locals = []; + $this->loopCounts = []; + $this->restore = []; + $this->newObject = null; + $this->isConstruct = false; + } } diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 4014c4f2..e578aa58 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -31,6 +31,19 @@ public function __construct(private readonly Interpreter $interp) { } + /** @return list */ + private function unpackArgumentList(JsValue $value): array + { + if (!$value instanceof \Phasis\Value\JsArray || !$value->isDenseMode()) { + throw new \LogicException('Compiled argument list must be a dense array'); + } + // The compiler creates this array and only appends data properties. + // It cannot contain holes or be exposed to a user-defined accessor. + /** @var list $arguments */ + $arguments = $value->getDenseElements(); + return $arguments; + } + /** * Property-read helper shared by LOAD_MEMBER (with a literal name) * and CALL_METHOD (which fetches the callee). For plain @@ -880,8 +893,13 @@ public function execute( // `fib` inside fib's body otherwise burns ~10 hash // ops per call, repeated on every recursive entry. $ic = $cf->loadNameIc[$pc] ?? null; - if ($ic !== null && $ic[1] === \Phasis\Runtime\Environment::$globalBindingsVersion) { - $stack[$sp++] = $ic[0]; + if ( + $ic !== null + && $ic[1] === \Phasis\Runtime\Environment::$globalBindingsVersion + && $ic[2]->get() === $env + && ($cachedNameValue = $ic[0] instanceof \WeakReference ? $ic[0]->get() : $ic[0]) !== null + ) { + $stack[$sp++] = $cachedNameValue; } else { $name = $names[$code[$pc + 1]]; $resolved = $env->get($name, $strict); @@ -890,8 +908,9 @@ public function execute( // declarative bindings covered by its version. if ($env->findBindingDepth($name) !== null) { $cf->loadNameIc[$pc] = [ - $resolved, + $resolved instanceof JsObject ? \WeakReference::create($resolved) : $resolved, \Phasis\Runtime\Environment::$globalBindingsVersion, + \WeakReference::create($env), ]; } else { unset($cf->loadNameIc[$pc]); @@ -1101,6 +1120,17 @@ public function execute( $pc++; break; + case Op::IN: + case Op::INSTANCEOF: + $right = $stack[--$sp]; + $left = $stack[--$sp]; + $result = $op === Op::IN + ? AbstractOperations::inOperator($left, $right) + : AbstractOperations::instanceofOperator($left, $right); + $stack[$sp++] = $result ? $true : $false; + $pc++; + break; + // ---- Bitwise -------------------------------------------- // Fast path: both operands are JsNumber with int-valued // doubles in int32 range. ToInt32 is the identity here, so @@ -1443,8 +1473,9 @@ public function execute( case Op::TAIL_CALL: case Op::TAIL_CALL_METHOD: $argc = $code[$pc + 1]; - $base = $sp - $argc; - $args = $argc === 0 ? [] : array_slice($stack, $base, $argc); + $base = $sp - ($argc === -1 ? 1 : $argc); + $args = $argc === -1 ? $this->unpackArgumentList($stack[$base]) + : ($argc === 0 ? [] : array_slice($stack, $base, $argc)); $callee = $stack[$base - 1]; $methodCall = $code[$pc] === Op::TAIL_CALL_METHOD; $receiver = $methodCall ? $stack[$base - 2] : $undef; @@ -1472,6 +1503,10 @@ public function execute( $args = [$stack[$base]]; } elseif ($argc === 2) { $args = [$stack[$base], $stack[$base + 1]]; + } elseif ($argc === -1) { + $base = $sp - 1; + $args = $this->unpackArgumentList($stack[$base]); + $argc = count($args); } else { $args = array_slice($stack, $base, $argc); } @@ -1613,7 +1648,8 @@ public function execute( // strict / arrow / sloppy callees. $inlineable = $callee->vmInlineCallCache; if ($inlineable === null) { - $inlineable = $eligible && $callee->getBoundTarget() === null; + $inlineable = $eligible && !$callee->compiled->hasTailCalls + && $callee->getBoundTarget() === null; if ($inlineable) { $callee->vmInlineCallCache = true; } @@ -1756,6 +1792,15 @@ public function execute( $array->setLength($array->getLength() + 1); $pc++; break; + case Op::BIND_ARRAY: + $this->interp->vmBindArray( + $stack[--$sp], + $cf->arrayBindings[$code[$pc + 1]], + $locals, + $env, + ); + $pc += 2; + break; case Op::SET_PROP: // Stack: [obj, val] -> [obj]; effect: obj.name = val. $val = $stack[--$sp]; @@ -1797,6 +1842,10 @@ public function execute( $args = [$stack[$base]]; } elseif ($argc === 2) { $args = [$stack[$base], $stack[$base + 1]]; + } elseif ($argc === -1) { + $base = $sp - 1; + $args = $this->unpackArgumentList($stack[$base]); + $argc = count($args); } else { $args = array_slice($stack, $base, $argc); } @@ -1841,6 +1890,7 @@ public function execute( if ($newInlineable === null) { $newInlineable = $callee->compiled !== null && $callee->compiled->canSkipEnvAlloc + && !$callee->compiled->hasTailCalls && $callee->isConstructable() && !$callee->isDerivedConstructor() && $callee->getBoundTarget() === null @@ -1966,6 +2016,10 @@ public function execute( $args = [$stack[$base]]; } elseif ($argc === 2) { $args = [$stack[$base], $stack[$base + 1]]; + } elseif ($argc === -1) { + $base = $sp - 1; + $args = $this->unpackArgumentList($stack[$base]); + $argc = count($args); } else { $args = array_slice($stack, $base, $argc); } @@ -2133,6 +2187,7 @@ public function execute( $methodInlineable = $method->vmInlineCallCache; if ($methodInlineable === null) { $methodInlineable = $methodEligible + && !$method->compiled->hasTailCalls && $method->getBoundTarget() === null; if ($methodInlineable) { $method->vmInlineCallCache = true; @@ -2645,6 +2700,7 @@ public function execute( $strict = $sf->strict; $hasHandlers = $sf->hasHandlers; $pc = $sf->returnPc; + $sf->release(); $stack[$sp++] = $finalResult; break; } @@ -2759,6 +2815,7 @@ public function execute( $strict = $sf->strict; $hasHandlers = $sf->hasHandlers; $pc = $sf->returnPc - 2; + $sf->release(); } // Convert the PHP exception to a JsValue for the catch // parameter. JsThrowable wraps a user-thrown JS value; diff --git a/src/Node/VmBindings.php b/src/Node/VmBindings.php index 35ab4782..a77827ff 100644 --- a/src/Node/VmBindings.php +++ b/src/Node/VmBindings.php @@ -64,12 +64,11 @@ private function context(JsObject $sandbox, JsObject $options): JsObject } $state = VmRealmState::capture(); try { - // Materialize intrinsics before linking the sandbox so lazy installation cannot leak globals into it. - $engine = new Engine(eager: true); + $engine = new Engine(); $engine->getInterpreter()->inheritLimits($this->owner->getInterpreter()); $env = $engine->getGlobalEnv(); $intrinsics = self::object($env->get('globalThis')); - $global = new VmGlobalObject($sandbox, $intrinsics); + $global = new VmGlobalObject($sandbox, $intrinsics, $engine); $env->defineVar('this', $global); $env->defineVar('globalThis', $global); $intrinsics->set('globalThis', $global); diff --git a/src/Node/VmGlobalObject.php b/src/Node/VmGlobalObject.php index 139bbe83..a211fbaa 100644 --- a/src/Node/VmGlobalObject.php +++ b/src/Node/VmGlobalObject.php @@ -4,6 +4,7 @@ namespace Phasis\Node; +use Phasis\Engine; use Phasis\Object\PropertyDescriptor; use Phasis\Value\JsObject; use Phasis\Value\JsString; @@ -13,8 +14,14 @@ /** Contextified global properties with private intrinsics and a live external sandbox. */ final class VmGlobalObject extends JsObject { - public function __construct(private readonly JsObject $sandbox, private readonly JsObject $intrinsics) - { + /** @var array Deleted names must not reappear when a sibling intrinsic realizes. */ + private array $deletedIntrinsics = []; + + public function __construct( + private readonly JsObject $sandbox, + private readonly JsObject $intrinsics, + private readonly Engine $engine, + ) { parent::__construct($intrinsics->getPrototype()); } @@ -28,6 +35,7 @@ public function getWithValueReceiver(string $name, JsValue $receiver): JsValue if ($this->sandbox->has($name)) { return $this->sandbox->getWithValueReceiver($name, $receiver); } + $this->materializeIntrinsic($name); return $this->intrinsics->getWithValueReceiver($name, $receiver); } @@ -59,7 +67,12 @@ public function defineOwnProperty(string $name, PropertyDescriptor $descriptor): public function getOwnPropertyDescriptor(string $name): ?PropertyDescriptor { - return $this->sandbox->getOwnPropertyDescriptor($name) ?? $this->intrinsics->getOwnPropertyDescriptor($name); + $descriptor = $this->sandbox->getOwnPropertyDescriptor($name); + if ($descriptor !== null) { + return $descriptor; + } + $this->materializeIntrinsic($name); + return $this->intrinsics->getOwnPropertyDescriptor($name); } public function getOwnPropertyDescriptorRaw(string $name): ?PropertyDescriptor @@ -70,9 +83,43 @@ public function getOwnPropertyDescriptorRaw(string $name): ?PropertyDescriptor public function delete(string $name, bool $strict = false): bool { if ($this->sandbox->hasOwnProperty($name)) { - return $this->sandbox->delete($name, $strict); + if (!$this->sandbox->delete($name, $strict)) { + return false; + } + } + $deleted = $this->intrinsics->delete($name, $strict); + if ($deleted && $this->engine->getLazyBuiltinRegistry()->has($name)) { + $this->deletedIntrinsics[$name] = true; + } + return $deleted; + } + + /** Install one intrinsic family privately, without overwriting sandbox globals. */ + private function materializeIntrinsic(string $name): void + { + if (!$this->engine->getLazyBuiltinRegistry()->has($name)) { + return; + } + $descriptor = $this->intrinsics->getOwnPropertyDescriptorRaw($name); + if ($descriptor === null || !$descriptor->isAccessorDescriptor()) { + return; + } + $state = VmRealmState::capture(); + $environment = $this->engine->getGlobalEnv(); + $linked = $environment->getLinkedObject(); + $environment->linkGlobalObject($this->intrinsics); + try { + VmRealmState::activate($this->engine); + $this->intrinsics->get($name); + foreach ($this->deletedIntrinsics as $deletedName => $_) { + $this->intrinsics->delete($deletedName); + } + } finally { + if ($linked !== null) { + $environment->linkGlobalObject($linked); + } + $state->restore(); } - return $this->intrinsics->delete($name, $strict); } /** @return list */ diff --git a/src/Runtime/Interpreter.php b/src/Runtime/Interpreter.php index 26a30835..b54c2aad 100644 --- a/src/Runtime/Interpreter.php +++ b/src/Runtime/Interpreter.php @@ -181,6 +181,7 @@ public function releaseInlineVmFrame(): void { if ($this->framePoolDepth > 0) { $this->framePoolDepth--; + $this->framePool[$this->framePoolDepth]->release(JsUndefined::instance()); } } diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index dcd11c84..cbf76b12 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -332,7 +332,7 @@ private function evalBinaryExpression(BinaryExpression $node, Environment $env): '&' => $this->bitwiseBinaryOp($left, $right, '&'), '|' => $this->bitwiseBinaryOp($left, $right, '|'), '^' => $this->bitwiseBinaryOp($left, $right, '^'), - 'in' => $this->evalInOperator($left, $right), + 'in' => new JsBoolean(AbstractOperations::inOperator($left, $right)), 'instanceof' => new JsBoolean(AbstractOperations::instanceofOperator($left, $right)), default => throw new InternalError("Unknown binary operator: {$node->operator}"), }; @@ -741,29 +741,6 @@ private function bigIntToDecimal(string $value): string return $value; } - private function evalInOperator(JsValue $left, JsValue $right): JsValue - { - if (!$right instanceof JsObject) { - throw new TypeError( - 'Cannot use "in" operator to search for "' - . ( - $left instanceof JsSymbol - ? $left->toString() - : TypeConversion::toString($left) - ) - . '" in ' . TypeConversion::toString($right) - ); - } - // Spec §13.10.2 step 5: the key goes through ToPropertyKey, which - // returns the unboxed Symbol for a Symbol wrapper instead of - // attempting ToString on it. - $propKey = TypeConversion::toPropertyKey($left); - if ($propKey instanceof JsSymbol) { - return new JsBoolean($right->hasBySymbol($propKey)); - } - return new JsBoolean($right->has(TypeConversion::toString($propKey))); - } - private function evalLogicalExpression(LogicalExpression $node, Environment $env): JsValue { $left = $this->evaluate($node->left, $env); @@ -1520,6 +1497,13 @@ private function evalCallExpression(CallExpression $node, Environment $env): JsV $rawCallKey = null; if ($node->callee->computed) { $rawCallKey = $this->evaluate($node->callee->property, $env); + // RequireObjectCoercible precedes ToPropertyKey, so a null + // receiver must not invoke the computed key's coercion hook. + if ($rawObj instanceof JsNull || $rawObj instanceof JsUndefined) { + throw new TypeError('Cannot read properties of ' + . ($rawObj instanceof JsNull ? 'null' : 'undefined')); + } + $rawCallKey = TypeConversion::toPropertyKey($rawCallKey); } $isSymbolCallKey = $rawCallKey instanceof JsSymbol; $key = $isSymbolCallKey ? '' : ($node->callee->computed @@ -1611,7 +1595,7 @@ private function evalCallExpression(CallExpression $node, Environment $env): JsV } $obj = $rawObj instanceof JsObject ? $rawObj : TypeConversion::toObject($rawObj); $callee = $isSymbolCallKey ? $obj->getBySymbol($rawCallKey) : $obj->get($key); - $thisValue = $obj; + $thisValue = $rawObj; $isMethodCall = true; } else { // Per spec 12.3.4.1 step 4.b: if the callee is an identifier resolved @@ -3772,39 +3756,14 @@ private function evaluateArguments(array $argNodes, Environment $env): array */ private function spreadInto(JsValue $iterable, array &$target): void { - $iterator = $this->getIterator($iterable); - if ($iterator !== null) { - $nextMethod = $iterator->get('next'); - if ($nextMethod instanceof JsFunction) { - while (true) { - $result = $this->callFunction($nextMethod, $iterator, []); - // Spec IteratorStep: if next() does not return an Object, - // throw TypeError instead of treating it as iteration end. - if (!$result instanceof JsObject) { - throw new TypeError('iterator.next() returned a non-object value'); - } - if (TypeConversion::toBoolean($result->get('done'))) { - break; - } - $target[] = $result->get('value'); - } - return; - } - } - - // Fallback for plain JsArray without Symbol.iterator. - if ($iterable instanceof JsArray) { - $len = $iterable->getLength(); - for ($i = 0; $i < $len; $i++) { - $target[] = $iterable->get((string) $i); + [$iterator, $nextMethod] = $this->getIteratorOrThrow($iterable); + $done = false; + while (!$done) { + $value = $this->iteratorNext($iterator, $nextMethod, $done); + if (!$done) { + $target[] = $value; } - return; } - - // Per spec, if the value is not iterable, throw TypeError. - throw new TypeError( - TypeConversion::toString($iterable) . ' is not iterable', - ); } /** @param JsValue[] $args */ @@ -6214,8 +6173,8 @@ private function tryRunOnVm( // Pool a Frame per active call depth: at depth N, reuse // framePool[N] if it exists, else allocate one and stash it. // Reset clears non-param slots only; param slots are about - // to be overwritten by the param-binding loop. Stack is left - // in place since sp = 0 makes prior entries unreachable. + // to be overwritten by the param-binding loop. Released frames + // retain their slot layout but no values from completed calls. $depth = $this->framePoolDepth; if ($depth < count($this->framePool)) { $frame = $this->framePool[$depth]; @@ -6246,7 +6205,9 @@ private function tryRunOnVm( try { return $this->vm->execute($cf, $frame); } finally { - $this->framePoolDepth = $depth; + while ($this->framePoolDepth > $depth) { + $this->framePool[--$this->framePoolDepth]->release($undef); + } } } @@ -6729,7 +6690,7 @@ private function bindArrayPattern(ArrayPattern $pattern, JsValue $value, Environ $done = true; // rest consumes remaining elements break; } - $elemValue = $this->iteratorNext($iterator, $nextMethod, $done); + $elemValue = $this->iteratorNext($iterator, $nextMethod, $done, $element !== null); if ($element === null) { // Elision: advance iterator but discard value. continue; diff --git a/src/Runtime/Parts/Helpers/IteratorProtocol.php b/src/Runtime/Parts/Helpers/IteratorProtocol.php index c4308416..5b98ac3f 100644 --- a/src/Runtime/Parts/Helpers/IteratorProtocol.php +++ b/src/Runtime/Parts/Helpers/IteratorProtocol.php @@ -103,6 +103,50 @@ */ trait IteratorProtocol { + /** + * Initialize a compiled flat array binding without reading ahead. Iterator + * methods can observe each earlier binding through captured closures. + * + * @param array{kind: string, elements: list} $binding + * @param list $locals + */ + public function vmBindArray(JsValue $value, array $binding, array &$locals, Environment $env): void + { + [$iterator, $nextMethod] = $this->getIteratorOrThrow($value); + $done = false; + try { + foreach ($binding['elements'] as $element) { + if ($element === null) { + $this->iteratorNext($iterator, $nextMethod, $done, false); + continue; + } + $item = $element['rest'] + ? $this->iteratorRest($iterator, $nextMethod, $done) + : $this->iteratorNext($iterator, $nextMethod, $done); + $name = $element['capturedName']; + if ($name === null) { + $slot = $element['slot']; + if (!isset($locals[$slot])) { + throw new \LogicException('Array binding references an unallocated local slot'); + } + $locals[$slot] = $item; + } elseif ($binding['kind'] === 'var') { + $env->set($name, $item); + } else { + $env->initialize($name, $item); + } + } + } catch (\Throwable $error) { + if (!$done) { + $this->iteratorClose($iterator, $error); + } + throw $error; + } + if (!$done) { + $this->iteratorClose($iterator); + } + } + /** * Get the iterator for a value; throw TypeError if not iterable. * Returns [iterator, nextMethod]. The next-method may be any JsValue; @@ -132,7 +176,7 @@ private function getIteratorOrThrow(JsValue $value): array * Advance an iterator one step. Returns the value, or undefined when done. * Sets $done to true once the iterator reports done. */ - private function iteratorNext(JsObject $iterator, JsValue $nextMethod, bool &$done): JsValue + private function iteratorNext(JsObject $iterator, JsValue $nextMethod, bool &$done, bool $readValue = true): JsValue { if ($done) { return JsUndefined::instance(); @@ -161,11 +205,16 @@ private function iteratorNext(JsObject $iterator, JsValue $nextMethod, bool &$do $done = true; throw new \Phasis\Exceptions\TypeError('Iterator result is not an object'); } - if (TypeConversion::toBoolean($result->get('done'))) { + try { + if (!TypeConversion::toBoolean($result->get('done'))) { + return $readValue ? $result->get('value') : JsUndefined::instance(); + } + } catch (\Throwable $error) { $done = true; - return JsUndefined::instance(); + throw $error; } - return $result->get('value'); + $done = true; + return JsUndefined::instance(); } /** @@ -217,7 +266,7 @@ private function iteratorClose(JsObject $iterator, ?\Throwable $completion = nul } return; } - if (!$returnMethod instanceof JsFunction) { + if (!$returnMethod instanceof JsFunction && !($returnMethod instanceof JsProxy && $returnMethod->isCallable())) { if ($completionIsThrow) { throw $completion; } @@ -231,7 +280,9 @@ private function iteratorClose(JsObject $iterator, ?\Throwable $completion = nul $innerResult = null; if ($innerException === null) { try { - $innerResult = $this->callFunction($returnMethod, $iterator, []); + $innerResult = $returnMethod instanceof JsProxy + ? $returnMethod->apply($iterator, []) + : $this->callFunction($returnMethod, $iterator, []); } catch (\Throwable $e) { $innerException = $e; } diff --git a/src/Runtime/Parts/Helpers/RegExpHelpers.php b/src/Runtime/Parts/Helpers/RegExpHelpers.php index d7b2ff0a..f7f44b94 100644 --- a/src/Runtime/Parts/Helpers/RegExpHelpers.php +++ b/src/Runtime/Parts/Helpers/RegExpHelpers.php @@ -159,8 +159,143 @@ public function callNew(JsValue $callee, array $args): JsValue return $newObj; } + /** @var array, names: list, custom: bool}> */ + private array $preparedRegExpPatterns = []; + private function createRegExpObject(string $pattern, string $flags): JsObject { + $originalPattern = $pattern; + $prepared = $this->prepareRegExpPattern($pattern, $flags); + $pattern = $prepared['pattern']; + $sortedFlags = $prepared['flags']; + $pcrePattern = $prepared['pcre']; + $groupNameMap = $prepared['groups']; + + $regexpProto = $this->globalEnv->getIntrinsic('RegExpPrototype'); + if (!$regexpProto instanceof JsObject && $this->globalEnv->has('RegExp')) { + // Force lazy installation before reading the private intrinsic. + $this->globalEnv->get('RegExp'); + $regexpProto = $this->globalEnv->getIntrinsic('RegExpPrototype'); + } + $obj = new JsObject($regexpProto instanceof JsObject ? $regexpProto : null); + + // Internal slots for compile() and prototype getters. + // These are not affected by user-visible property overrides. + // [[OriginalSource]] preserves the literal pattern text users wrote + // (including any pathological leading zeros in `\u{0…0XXXX}` escapes + // that the canonical-form pre-pass elided from the working pattern). + $obj->defineOwnProperty( + '[[OriginalSource]]', + PropertyDescriptor::data(new JsString($originalPattern), false, false, false), + ); + $obj->defineOwnProperty( + '[[OriginalFlags]]', + PropertyDescriptor::data(new JsString($sortedFlags), false, false, false), + ); + // Per spec, source/flags/global/ignoreCase/multiline/dotAll/unicode/ + // unicodeSets/sticky/hasIndices are prototype accessor properties, not + // own data properties. Do not install them as own properties so that + // Object.defineProperty overrides and the prototype getters work correctly. + // lastIndex is writable but not enumerable, not configurable per spec. + $obj->defineOwnProperty('lastIndex', PropertyDescriptor::data(JsNumber::of(0.0), true, false, false)); + + // Store the compiled PCRE pattern as a non-enumerable internal slot so prototype + // methods (exec, test) installed on RegExp.prototype can access it via $this_. + $obj->defineOwnProperty( + '[[PCREPattern]]', + PropertyDescriptor::data(new JsString($pcrePattern), false, false, false), + ); + // [[GroupNameMap]] is the safe-name → original-name mapping used by + // exec/match to reconstruct user-visible named-capture keys. + if (!empty($groupNameMap)) { + $mapValue = JsObject::createNullPrototype(); + foreach ($groupNameMap as $safe => $orig) { + $mapValue->defineOwnProperty( + $safe, + PropertyDescriptor::data(new JsString($orig), false, false, false), + ); + } + $obj->defineOwnProperty( + '[[GroupNameMap]]', + PropertyDescriptor::data($mapValue, false, false, false), + ); + } + + // [[CustomMatcher]] is set when the pattern uses a feature that + // PCRE2 cannot match exactly: + // - lookbehind containing capture groups (capture order), + // - quantified group containing captures (capture reset), + // - any `.` in non-unicode mode (PCRE2 matches UTF-8 code + // points; ES non-unicode mode requires UTF-16 code units, + // so `.` must NOT match an astral character). + // exec() routes through the in-engine matcher in those cases. + if ($prepared['custom']) { + try { + // The AST parser consumes ordinary alternatives after Unicode string sets are lowered. + $customPattern = str_contains($flags, 'v') ? $this->transformVFlagPattern($pattern) : $pattern; + $regexAst = (new \Phasis\Regex\Parser($customPattern, $flags))->parse(); + $obj->defineOwnProperty( + '[[CustomRegexAst]]', + PropertyDescriptor::data( + new \Phasis\Value\JsHostValue($regexAst), + false, + false, + false, + ), + ); + $obj->defineOwnProperty( + '[[CustomRegexFlags]]', + PropertyDescriptor::data( + new JsString($flags), + false, + false, + false, + ), + ); + } catch (\Throwable) { + // If our parser bails on something it doesn't model + // yet, fall back to PCRE2. + } + } + + // [[NamedGroupNames]] preserves every distinct named group in the + // pattern in source order. exec() uses this to pre-populate the + // result.groups object so groups that did not participate in the + // match still appear (with value undefined) — required by the + // duplicate-named-groups proposal. + $namedGroupNames = $prepared['names']; + if (!empty($namedGroupNames)) { + $namedListArr = []; + foreach ($namedGroupNames as $n) { + $namedListArr[] = new JsString($n); + } + $obj->defineOwnProperty( + '[[NamedGroupNames]]', + PropertyDescriptor::data( + JsArray::fromArray($namedListArr), + false, + false, + false, + ), + ); + } + + return $obj; + } + + /** + * Reuse immutable preprocessing only; every instance keeps fresh lastIndex, + * prototype, named-group objects and custom matcher state. + * @return array{pattern: string, flags: string, pcre: string, groups: array, names: list, custom: bool} + */ + private function prepareRegExpPattern(string $pattern, string $flags): array + { + $key = strlen($pattern) <= 4096 && strlen($flags) <= 8 + ? strlen($flags) . ':' . $flags . $pattern + : null; + if ($key !== null && isset($this->preparedRegExpPatterns[$key])) { + return $this->preparedRegExpPatterns[$key]; + } // Pathological `\u{0…0XXXX}` braced escapes (test262 // unicode-braced.js / unicode-class-braced.js construct 16M-char // patterns) make every downstream char-by-char scan an O(n) @@ -169,7 +304,6 @@ private function createRegExpObject(string $pattern, string $flags): JsObject // and the custom-matcher parser all work on a small string. // [[OriginalSource]] is set later from $originalPattern, so the // user-visible `.source` still reflects what the program wrote. - $originalPattern = $pattern; if ( (str_contains($flags, 'u') || str_contains($flags, 'v')) && strlen($pattern) > 64 @@ -212,14 +346,6 @@ private function createRegExpObject(string $pattern, string $flags): JsObject throw $e; } - $regexpProto = $this->globalEnv->getIntrinsic('RegExpPrototype'); - if (!$regexpProto instanceof JsObject && $this->globalEnv->has('RegExp')) { - // Force lazy installation before reading the private intrinsic. - $this->globalEnv->get('RegExp'); - $regexpProto = $this->globalEnv->getIntrinsic('RegExpPrototype'); - } - $obj = new JsObject($regexpProto instanceof JsObject ? $regexpProto : null); - // Per spec §22.2.5.3 get RegExp.prototype.flags, flags are returned in canonical order: // d, g, i, m, s, u, v, y (alphabetical subset of valid flag characters). $canonicalFlagOrder = 'dgimsuvy'; @@ -230,30 +356,6 @@ private function createRegExpObject(string $pattern, string $flags): JsObject } } - // Per spec §22.2.6, regexp instance own properties are non-writable, non-enumerable. - // source and flags are configurable (per modern ES), others are non-configurable. - // Making all configurable to allow Object.defineProperty overrides in tests. - $noenum = static fn (JsValue $v) => PropertyDescriptor::data($v, false, false, true); - // Internal slots for compile() and prototype getters. - // These are not affected by user-visible property overrides. - // [[OriginalSource]] preserves the literal pattern text users wrote - // (including any pathological leading zeros in `\u{0…0XXXX}` escapes - // that the canonical-form pre-pass elided from the working pattern). - $obj->defineOwnProperty( - '[[OriginalSource]]', - PropertyDescriptor::data(new JsString($originalPattern), false, false, false), - ); - $obj->defineOwnProperty( - '[[OriginalFlags]]', - PropertyDescriptor::data(new JsString($sortedFlags), false, false, false), - ); - // Per spec, source/flags/global/ignoreCase/multiline/dotAll/unicode/ - // unicodeSets/sticky/hasIndices are prototype accessor properties, not - // own data properties. Do not install them as own properties so that - // Object.defineProperty overrides and the prototype getters work correctly. - // lastIndex is writable but not enumerable, not configurable per spec. - $obj->defineOwnProperty('lastIndex', PropertyDescriptor::data(JsNumber::of(0.0), true, false, false)); - // Build PCRE pattern. $pcreFlags = ''; if (str_contains($flags, 'i')) { @@ -339,339 +441,21 @@ private function createRegExpObject(string $pattern, string $flags): JsObject } } - $isGlobal = str_contains($flags, 'g'); - $isSticky = str_contains($flags, 'y'); - $hasIndices = str_contains($flags, 'd'); - - // Analyze the original ES pattern for repeated groups that need - // ES-compliant capture reset and nullable quantifier handling. - $repeatedGroupAnalysis = self::analyzeRepeatedGroups($pattern); - $hasRepeatedGroupFixes = !empty($repeatedGroupAnalysis['repeatedGroups']) - || !empty($repeatedGroupAnalysis['nullableNonCapturingGroups']); - - // Build the PCRE flags string (without the delimiter and 'u') for inner patterns. - $innerPcreFlags = $pcreFlags . 'u'; - - // Transform function for building PCRE patterns from ES sub-patterns. - $self = $this; - $transformFn = static function (string $esSubPattern) use ($self, $flags): string { - $transformed = $self->transformEsPatternForPcre($esSubPattern, $flags); - return $self->escapeForPcreDelimiter($transformed); - }; - - // Store the compiled PCRE pattern as a non-enumerable internal slot so prototype - // methods (exec, test) installed on RegExp.prototype can access it via $this_. - $obj->defineOwnProperty( - '[[PCREPattern]]', - PropertyDescriptor::data(new JsString($pcrePattern), false, false, false), - ); - // [[GroupNameMap]] is the safe-name → original-name mapping used by - // exec/match to reconstruct user-visible named-capture keys. - if (!empty($groupNameMap)) { - $mapValue = JsObject::createNullPrototype(); - foreach ($groupNameMap as $safe => $orig) { - $mapValue->defineOwnProperty( - $safe, - PropertyDescriptor::data(new JsString($orig), false, false, false), - ); + $prepared = [ + 'pattern' => $pattern, + 'flags' => $sortedFlags, + 'pcre' => $pcrePattern, + 'groups' => $groupNameMap, + 'names' => self::extractNamedGroupNames($pattern), + 'custom' => self::patternNeedsCustomMatcher($pattern, $flags), + ]; + if ($key !== null && !$prepared['custom'] && strlen($pcrePattern) <= 16384) { + if (count($this->preparedRegExpPatterns) >= 128) { + array_shift($this->preparedRegExpPatterns); } - $obj->defineOwnProperty( - '[[GroupNameMap]]', - PropertyDescriptor::data($mapValue, false, false, false), - ); + $this->preparedRegExpPatterns[$key] = $prepared; } - - // [[CustomMatcher]] is set when the pattern uses a feature that - // PCRE2 cannot match exactly: - // - lookbehind containing capture groups (capture order), - // - quantified group containing captures (capture reset), - // - any `.` in non-unicode mode (PCRE2 matches UTF-8 code - // points; ES non-unicode mode requires UTF-16 code units, - // so `.` must NOT match an astral character). - // exec() routes through the in-engine matcher in those cases. - if (self::patternNeedsCustomMatcher($pattern, $flags)) { - try { - // The AST parser consumes ordinary alternatives after Unicode string sets are lowered. - $customPattern = str_contains($flags, 'v') ? $this->transformVFlagPattern($pattern) : $pattern; - $regexAst = (new \Phasis\Regex\Parser($customPattern, $flags))->parse(); - $obj->defineOwnProperty( - '[[CustomRegexAst]]', - PropertyDescriptor::data( - new \Phasis\Value\JsHostValue($regexAst), - false, - false, - false, - ), - ); - $obj->defineOwnProperty( - '[[CustomRegexFlags]]', - PropertyDescriptor::data( - new JsString($flags), - false, - false, - false, - ), - ); - } catch (\Throwable) { - // If our parser bails on something it doesn't model - // yet, fall back to PCRE2. - } - } - - // [[NamedGroupNames]] preserves every distinct named group in the - // pattern in source order. exec() uses this to pre-populate the - // result.groups object so groups that did not participate in the - // match still appear (with value undefined) — required by the - // duplicate-named-groups proposal. - $namedGroupNames = self::extractNamedGroupNames($pattern); - if (!empty($namedGroupNames)) { - $namedListArr = []; - foreach ($namedGroupNames as $n) { - $namedListArr[] = new JsString($n); - } - $obj->defineOwnProperty( - '[[NamedGroupNames]]', - PropertyDescriptor::data( - JsArray::fromArray($namedListArr), - false, - false, - false, - ), - ); - } - - // exec(): handles lastIndex for global/sticky regexes per spec 22.2.5.2. - $execFn = function ( - JsValue $this_, - array $args - ) use ( - $pcrePattern, - $obj, - $isGlobal, - $isSticky, - $hasIndices, - $hasRepeatedGroupFixes, - $repeatedGroupAnalysis, - $innerPcreFlags, - $transformFn, - ): JsValue { - // Per spec: if no argument, convert undefined to "undefined". - $str = isset($args[0]) ? TypeConversion::toString($args[0]) - : TypeConversion::toString(JsUndefined::instance()); - // lastIndex is a UTF-16 code unit offset; comparing it - // against mb_strlen (codepoints) short-circuits any iter - // that has stepped past mb_strlen units into the second - // half of an astral. Use UTF-16 unit count instead. - $strLen = (int) (strlen(JsString::utf8ToUtf16LE($str)) / 2); - - // Per spec step 4: always read lastIndex (for observable side effects - // like valueOf calls), even when global/sticky are unset. - $lastIndexVal = $obj->get('lastIndex'); - $lastIndex = TypeConversion::toLength($lastIndexVal); - - if (!$isGlobal && !$isSticky) { - $lastIndex = 0; - } - - if ($lastIndex > $strLen) { - if ($isGlobal || $isSticky) { - // Per spec: Set(R, "lastIndex", 0, Throw=true). - $obj->set('lastIndex', JsNumber::of(0.0), true); - } - return JsNull::instance(); - } - - // Use byte offset for PCRE: convert character offset to byte offset. - $byteOffset = strlen(mb_substr($str, 0, $lastIndex, 'UTF-8')); - - if (@preg_match($pcrePattern, $str, $matches, PREG_OFFSET_CAPTURE | PREG_UNMATCHED_AS_NULL, $byteOffset)) { - $matchBytePos = $matches[0][1]; - // For sticky regex, the match must start exactly at lastIndex. - if ($isSticky && $matchBytePos !== $byteOffset) { - // Per spec: Set(R, "lastIndex", 0, Throw=true). - $obj->set('lastIndex', JsNumber::of(0.0), true); - return JsNull::instance(); - } - - // Apply ES-compliant fixes for repeated groups. - if ($hasRepeatedGroupFixes) { - // Fix 1: Extend match for nullable quantified groups. - $matches = self::fixNullableQuantifier( - $matches, - $repeatedGroupAnalysis, - $str, - $innerPcreFlags, - $transformFn, - ); - // Fix 2: Reset captures inside repeated groups to last iteration values. - $matches = self::fixRepeatedGroupCaptures( - $matches, - $repeatedGroupAnalysis, - $innerPcreFlags, - $transformFn, - ); - // Fix 3: Reset captures inside nullable non-capturing groups. - // Per ES spec RepeatMatcher step 2.b: when min=0 and the body - // matched zero-length, the repetition fails and captures inside - // are reset to undefined. - $matches = self::fixNullableNonCapturingGroupCaptures( - $matches, - $repeatedGroupAnalysis, - ); - } - - // Convert byte position back to character position. - $matchCharPos = mb_strlen(substr($str, 0, $matches[0][1]), 'UTF-8'); - $matchStr = $matches[0][0]; - $matchCharLen = mb_strlen($matchStr, 'UTF-8'); - - if ($isGlobal || $isSticky) { - // Per spec: Set(R, "lastIndex", matchEnd, Throw=true). - $obj->set('lastIndex', JsNumber::of((float) ($matchCharPos + $matchCharLen)), true); - } - - // Build result array with numeric capture groups. - $numericCount = 0; - $elements = []; - foreach ($matches as $key => $match) { - if (is_int($key)) { - $elements[] = ($match[1] === -1 || $match[0] === null) - ? JsUndefined::instance() - : new JsString($match[0]); - $numericCount++; - } - } - $result = JsArray::fromArray($elements); - // Per spec, index/input/groups are added via CreateDataProperty. - $result->defineOwnProperty( - 'index', - PropertyDescriptor::data(JsNumber::of((float) $matchCharPos), true, true, true), - ); - $result->defineOwnProperty( - 'input', - PropertyDescriptor::data(new JsString($str), true, true, true), - ); - - // Named capture groups. - $groups = new JsObject(null); - $hasGroups = false; - foreach ($matches as $key => $match) { - if (is_string($key)) { - $hasGroups = true; - $groups->defineOwnProperty($key, PropertyDescriptor::data( - ($match[1] === -1 || $match[0] === null) - ? JsUndefined::instance() - : new JsString($match[0]), - true, - true, - true, - )); - } - } - $result->defineOwnProperty( - 'groups', - PropertyDescriptor::data( - $hasGroups ? $groups : JsUndefined::instance(), - true, - true, - true, - ), - ); - - if ($hasIndices) { - $indEls = []; - foreach ($matches as $ik => $im) { - if (!is_int($ik)) { - continue; - } - if ($im[1] === -1 || $im[0] === null) { - $indEls[] = JsUndefined::instance(); - } else { - $isc = mb_strlen( - substr($str, 0, $im[1]), - 'UTF-8' - ); - $iec = $isc + mb_strlen( - $im[0], - 'UTF-8' - ); - $indEls[] = JsArray::fromArray([ - JsNumber::of((float) $isc), - JsNumber::of((float) $iec), - ]); - } - } - $iArr = JsArray::fromArray($indEls); - $iGrp = new JsObject(null); - $iHasGrp = false; - foreach ($matches as $ik => $im) { - if (!is_string($ik)) { - continue; - } - $iHasGrp = true; - if ($im[1] === -1 || $im[0] === null) { - $iGrp->defineOwnProperty( - $ik, - PropertyDescriptor::data( - JsUndefined::instance() - ) - ); - } else { - $igsc = mb_strlen( - substr($str, 0, $im[1]), - 'UTF-8' - ); - $igec = $igsc + mb_strlen( - $im[0], - 'UTF-8' - ); - $iGrp->defineOwnProperty( - $ik, - PropertyDescriptor::data( - JsArray::fromArray([ - JsNumber::of((float) $igsc), - JsNumber::of((float) $igec), - ]) - ) - ); - } - } - $iArr->defineOwnProperty( - 'groups', - PropertyDescriptor::data( - $iHasGrp - ? $iGrp - : JsUndefined::instance(), - true, - true, - true - ) - ); - $result->defineOwnProperty( - 'indices', - PropertyDescriptor::data( - $iArr, - true, - true, - true - ) - ); - } - - return $result; - } - - if ($isGlobal || $isSticky) { - // Per spec: Set(R, "lastIndex", 0, Throw=true). - $obj->set('lastIndex', JsNumber::of(0.0), true); - } - return JsNull::instance(); - }; - // exec, test, toString are inherited from RegExp.prototype. - // Do NOT install own properties here; the prototype methods read - // [[PCREPattern]] and flags from the instance via 'this'. - - return $obj; + return $prepared; } /** diff --git a/src/Runtime/Parts/StatementExecution.php b/src/Runtime/Parts/StatementExecution.php index 114c4c6f..e5a7deb9 100644 --- a/src/Runtime/Parts/StatementExecution.php +++ b/src/Runtime/Parts/StatementExecution.php @@ -236,7 +236,7 @@ private function assignVarBinding(Node $pattern, JsValue $value, Environment $en $done = true; break; } - $elemValue = $this->iteratorNext($iterator, $nextMethod, $done); + $elemValue = $this->iteratorNext($iterator, $nextMethod, $done, $element !== null); if ($element === null) { continue; } @@ -2303,7 +2303,7 @@ private function assignPatternToEnv(Node $pattern, JsValue $value, Environment $ $done = true; break; } - $elemValue = $this->iteratorNext($iterator, $nextMethod, $done); + $elemValue = $this->iteratorNext($iterator, $nextMethod, $done, $element !== null); if ($element === null) { continue; } diff --git a/src/Spec/AbstractOperations.php b/src/Spec/AbstractOperations.php index caa6e90d..bd015f51 100644 --- a/src/Spec/AbstractOperations.php +++ b/src/Spec/AbstractOperations.php @@ -526,6 +526,18 @@ public static function deletePropertyReference(JsValue $object, JsValue $key, bo return $deleted; } + /** Check the right-hand type before coercing the key, as required by `in`. */ + public static function inOperator(JsValue $left, JsValue $right): bool + { + if (!$right instanceof JsObject) { + throw new TypeError('Right-hand side of in is not an object'); + } + $key = TypeConversion::toPropertyKey($left); + return $key instanceof JsSymbol + ? $right->hasBySymbol($key) + : $right->has($key->toJsString()); + } + /** * 13.10.2 InstanceofOperator(V, target). * @@ -547,10 +559,15 @@ public static function instanceofOperator(JsValue $left, JsValue $right): bool // GetMethod returns undefined for both undefined and null property values. // Step 4: if instOfHandler is defined, return ToBoolean(Call(instOfHandler, C, [O])). if (!$instOfHandler instanceof JsUndefined && !$instOfHandler instanceof JsNull) { - if (!$instOfHandler instanceof JsFunction) { + if ( + !$instOfHandler instanceof JsFunction + && !($instOfHandler instanceof \Phasis\Value\JsProxy && $instOfHandler->isCallable()) + ) { throw new TypeError('Right-hand side of instanceof is not callable'); } - $result = $instOfHandler->call($right, [$left]); + $result = $instOfHandler instanceof \Phasis\Value\JsProxy + ? $instOfHandler->apply($right, [$left]) + : $instOfHandler->call($right, [$left]); return TypeConversion::toBoolean($result); } diff --git a/src/Value/JsPromise.php b/src/Value/JsPromise.php index c5de5cec..5e4144c9 100644 --- a/src/Value/JsPromise.php +++ b/src/Value/JsPromise.php @@ -593,7 +593,7 @@ public function finallyHandler(array $args): self } return JsUndefined::instance(); }, 1); - $this->pendingHandlers[] = [$fulfilled, $rejected, null]; + $this->pendingHandlers[] = [$fulfilled, $rejected, null, AsyncContextStorage::active()->snapshot()]; return $child; } diff --git a/src/Value/JsWeakMap.php b/src/Value/JsWeakMap.php index ceb447cd..54b6a677 100644 --- a/src/Value/JsWeakMap.php +++ b/src/Value/JsWeakMap.php @@ -9,26 +9,19 @@ /** * JavaScript WeakMap object. * - * Backed by the same storage as JsMap, but is a distinct type so that - * Map.prototype methods correctly reject it via instanceof checks. - * PHP does not have weak references for arbitrary values, so entries - * are stored strongly (no garbage collection of unreferenced keys). - * - * Keys must be JsObject or non-registered JsSymbol per spec; both are - * PHP objects so spl_object_id provides O(1) lookup keyed by identity, - * which matches the spec's reference equality requirement for WeakMap. + * Native weak keys preserve object identity without making a long-lived + * JavaScript collection keep every past key alive. Values remain strongly + * referenced while their keys are live. */ class JsWeakMap extends JsObject { - /** @var array Map of spl_object_id(key) => value. */ - private array $values = []; - - /** @var array Map of spl_object_id(key) => key (keeps key alive). */ - private array $keys = []; + /** @var \WeakMap */ + private \WeakMap $values; public function __construct(?JsObject $prototype = null) { parent::__construct($prototype); + $this->values = new \WeakMap(); } public function weakMapGet(JsValue $key): JsValue @@ -36,8 +29,7 @@ public function weakMapGet(JsValue $key): JsValue if (!$key instanceof JsObject && !$key instanceof JsSymbol) { return JsUndefined::instance(); } - $id = spl_object_id($key); - return $this->values[$id] ?? JsUndefined::instance(); + return $this->values[$key] ?? JsUndefined::instance(); } public function weakMapSet(JsValue $key, JsValue $value): void @@ -49,9 +41,7 @@ public function weakMapSet(JsValue $key, JsValue $value): void ) { throw new \Phasis\Exceptions\TypeError('Invalid value used as weak map key'); } - $id = spl_object_id($key); - $this->keys[$id] = $key; - $this->values[$id] = $value; + $this->values[$key] = $value; } public function weakMapHas(JsValue $key): bool @@ -59,7 +49,7 @@ public function weakMapHas(JsValue $key): bool if (!$key instanceof JsObject && !$key instanceof JsSymbol) { return false; } - return isset($this->values[spl_object_id($key)]) || array_key_exists(spl_object_id($key), $this->values); + return isset($this->values[$key]); } public function weakMapDelete(JsValue $key): bool @@ -67,11 +57,10 @@ public function weakMapDelete(JsValue $key): bool if (!$key instanceof JsObject && !$key instanceof JsSymbol) { return false; } - $id = spl_object_id($key); - if (!array_key_exists($id, $this->values)) { + if (!isset($this->values[$key])) { return false; } - unset($this->values[$id], $this->keys[$id]); + unset($this->values[$key]); return true; } diff --git a/tests/Frameworks/express/run.py b/tests/Frameworks/express/run.py index 6ebb8b75..0e5ffdfa 100644 --- a/tests/Frameworks/express/run.py +++ b/tests/Frameworks/express/run.py @@ -64,7 +64,7 @@ def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--runtime", choices=("node", "phasis", "both"), default="both") parser.add_argument("--jobs", type=int, choices=(1, 2), default=1) - parser.add_argument("--timeout", type=float, default=120) + parser.add_argument("--timeout", type=float, default=1800) parser.add_argument("--output", type=Path, required=True) args = parser.parse_args() if args.timeout <= 0: diff --git a/tests/Frameworks/hono/README.md b/tests/Frameworks/hono/README.md index 1b5f7e90..3c5a66aa 100644 --- a/tests/Frameworks/hono/README.md +++ b/tests/Frameworks/hono/README.md @@ -60,7 +60,11 @@ Captured real timers and monotonic time keep deadlines effective under fake timers and synchronous or microtask starvation. Failed suite setup is recorded as a suite failure with blocked cases, separately from upstream skip declarations. The self-test compares intentional async, synchronous, microtask, mock-timer -and hook deadline failures against the actual pinned Vitest runner. +and hook deadline failures against the actual pinned Vitest runner. It also +compares `nextTick`, Promise, microtask and immediate ordering across hooks, +synchronous tests, asynchronous tests and an explicit host turn. Execution +starts after a microtask boundary, matching Vitest's asynchronous collection; +the runner does not insert extra host turns between tests. Every invocation writes an immutable run directory under `results/runs/`. Its manifest records the upstream revision, project, complete project diff --git a/tests/Frameworks/hono/build-selftest.mjs b/tests/Frameworks/hono/build-selftest.mjs index 1d181267..4b6703b5 100644 --- a/tests/Frameworks/hono/build-selftest.mjs +++ b/tests/Frameworks/hono/build-selftest.mjs @@ -5,10 +5,12 @@ import { fileURLToPath } from 'node:url'; const directory = dirname(fileURLToPath(import.meta.url)); const output = resolve(directory, '.generated/selftest'); await mkdir(output, { recursive: true }); -await build({ - entryPoints: [resolve(directory, 'fixtures/timeouts-entry.mjs')], - outfile: resolve(output, 'timeouts.cjs'), bundle: true, platform: 'node', - format: 'cjs', target: 'es2022', banner: { js: '"use strict";' }, logLevel: 'warning', -}); -await writeFile(resolve(output, 'timeouts.mjs'), - "import {createRequire} from 'node:module';\nconst require = createRequire(import.meta.url);\nrequire('./timeouts.cjs');\n"); +for (const name of ['timeouts', 'scheduling']) { + await build({ + entryPoints: [resolve(directory, 'fixtures/' + name + '-entry.mjs')], + outfile: resolve(output, name + '.cjs'), bundle: true, platform: 'node', + format: 'cjs', target: 'es2022', banner: { js: '"use strict";' }, logLevel: 'warning', + }); + await writeFile(resolve(output, name + '.mjs'), + "import {createRequire} from 'node:module';\nconst require = createRequire(import.meta.url);\nrequire('./" + name + ".cjs');\n"); +} diff --git a/tests/Frameworks/hono/fixtures/scheduling-entry.mjs b/tests/Frameworks/hono/fixtures/scheduling-entry.mjs new file mode 100644 index 00000000..bed9a896 --- /dev/null +++ b/tests/Frameworks/hono/fixtures/scheduling-entry.mjs @@ -0,0 +1,7 @@ +import { run } from '../harness.mjs'; +import './scheduling.test.mjs'; +run().then(report => { + globalThis.__honoReport = report; + if (globalThis.__honoComplete) globalThis.__honoComplete(); + else process.stdout.write('__PHASIS_HONO_REPORT__' + JSON.stringify(report) + '\n', () => process.exit(0)); +}); diff --git a/tests/Frameworks/hono/fixtures/scheduling.test.mjs b/tests/Frameworks/hono/fixtures/scheduling.test.mjs new file mode 100644 index 00000000..1d27cc49 --- /dev/null +++ b/tests/Frameworks/hono/fixtures/scheduling.test.mjs @@ -0,0 +1,28 @@ +const trace = []; +let index = 0; +const schedule = phase => { + trace.push(phase); + process.nextTick(() => trace.push(phase + ':nextTick')); + Promise.resolve().then(() => trace.push(phase + ':promise')); + queueMicrotask(() => trace.push(phase + ':microtask')); + setImmediate(() => trace.push(phase + ':immediate')); +}; +beforeEach(() => schedule('before' + (++index))); +afterEach(() => schedule('after' + index)); +it('synchronous lifecycle', () => { + schedule('test1'); + expect(index).toBe(1); +}); +it('promise lifecycle', async () => { + schedule('test2'); + await Promise.resolve(); + trace.push('await2'); + expect(index).toBe(2); +}); +it('explicit host turn', async () => { + schedule('test3'); + await new Promise(resolve => setImmediate(resolve)); + trace.push('await3'); + expect(index).toBe(3); +}); +afterAll(() => process.stdout.write('__PHASIS_HONO_SCHEDULE__' + JSON.stringify(trace) + '\n')); diff --git a/tests/Frameworks/hono/harness.mjs b/tests/Frameworks/hono/harness.mjs index 1613fa9e..d320743e 100644 --- a/tests/Frameworks/hono/harness.mjs +++ b/tests/Frameworks/hono/harness.mjs @@ -289,6 +289,8 @@ async function runSuite(current, ancestors, results, inheritedError) { } } export async function run() { + // Vitest starts test execution after asynchronous module collection. + await Promise.resolve(); while (pendingCollections.length) await Promise.all(pendingCollections.splice(0)); const results = []; await runSuite(root, [], results); diff --git a/tests/Frameworks/hono/scheduling.config.mjs b/tests/Frameworks/hono/scheduling.config.mjs new file mode 100644 index 00000000..88f3b320 --- /dev/null +++ b/tests/Frameworks/hono/scheduling.config.mjs @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +export default defineConfig({ + root: dirname(fileURLToPath(import.meta.url)), + test: { globals: true, maxWorkers: 1, include: ['fixtures/scheduling.test.mjs'], + disableConsoleIntercept: true, coverage: { enabled: false } }, +}); diff --git a/tests/Frameworks/hono/selftest.py b/tests/Frameworks/hono/selftest.py index 2dbaa203..9d81401d 100644 --- a/tests/Frameworks/hono/selftest.py +++ b/tests/Frameworks/hono/selftest.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Differentially verify harness deadlines against the actual pinned Vitest runner.""" +"""Verify harness deadlines and job scheduling against the actual pinned Vitest runner.""" from datetime import datetime, timezone import json from uuid import uuid4 @@ -59,6 +59,34 @@ def main(): if len(report['suiteErrors']) != 1 or not report['suiteErrors'][0]['error']['message'].startswith('Hook timed out in 30ms.'): failures.append('suite setup failure was not preserved') manifest['results'][runtime] = {'cases': len(report['results']), 'differences': failures} + schedules = {} + for runtime in ['native', 'node', 'phasis']: + script = DIRECTORY / '.generated/selftest/scheduling.mjs' + if runtime == 'native': + command = ['node', str(DIRECTORY.parent / 'node_modules/vitest/vitest.mjs'), 'run', + '--config', str(DIRECTORY / 'scheduling.config.mjs'), '--reporter=json', + '--outputFile=' + str(archive / 'scheduling-native.json')] + elif runtime == 'node': + command = ['node', str(script)] + else: + command = ['php', '-d', 'memory_limit=1G', str(DIRECTORY / 'run-php.php'), str(script)] + status, output = execute(command, 60, log_file=archive / ('scheduling-' + runtime + '.log')) + prefix = '__PHASIS_HONO_SCHEDULE__' + traces = [json.loads(line[len(prefix):]) for line in output.splitlines() if line.startswith(prefix)] + if status != 0 or len(traces) != 1: + raise RuntimeError(runtime + ' did not finish the scheduling fixtures') + schedules[runtime] = traces[0] + if runtime == 'native': + report = json.loads((archive / 'scheduling-native.json').read_text()) + if report['numPassedTests'] != 3 or report['numFailedTests'] != 0: + raise RuntimeError('Native scheduling fixture inventory changed unexpectedly') + else: + reports = [json.loads(line[len(PREFIX):]) for line in output.splitlines() if line.startswith(PREFIX)] + if len(reports) != 1 or reports[0]['counts']['pass'] != 3 or reports[0]['counts']['fail']: + raise RuntimeError(runtime + ' failed the scheduling fixtures') + if schedules[runtime] != schedules['native']: + manifest['results'][runtime]['differences'].append('lifecycle job scheduling differs') + manifest['scheduling'] = schedules (archive / 'manifest.json').write_text(json.dumps(manifest, indent=2)) print(json.dumps(manifest['results'])) print('Run manifest:', archive / 'manifest.json') diff --git a/tests/Unit/BuiltIn/AsyncContextTest.php b/tests/Unit/BuiltIn/AsyncContextTest.php index 2b9be3a1..ffcacdba 100644 --- a/tests/Unit/BuiltIn/AsyncContextTest.php +++ b/tests/Unit/BuiltIn/AsyncContextTest.php @@ -5,6 +5,12 @@ namespace Phasis\Tests\Unit\BuiltIn; use Phasis\Engine; +use Phasis\Runtime\AsyncContextStorage; +use Phasis\Value\JsFunction; +use Phasis\Value\JsObject; +use Phasis\Value\JsPromise; +use Phasis\Value\JsString; +use Phasis\Value\JsUndefined; use PHPUnit\Framework\TestCase; /** @@ -98,6 +104,34 @@ public function testPendingPromiseReactionsRetainRegistrationContext(): void self::assertSame('outside', $engine->eval('context.get()')); } + public function testNativePendingFinallySubscriptionsRetainRegistrationContext(): void + { + new Engine(); + $storage = AsyncContextStorage::active(); + $variable = new JsObject(); + $seen = []; + $snapshot = $storage->snapshot(); + try { + foreach (['resolve', 'reject'] as $settle) { + $promise = new JsPromise(); + $storage->set($variable, new JsString('registered:' . $settle)); + $child = $promise->finallyHandler([JsFunction::fromCallable('', function () use ($storage, $variable, &$seen): JsUndefined { + $seen[] = $storage->getRaw($variable)?->toJsString(); + return JsUndefined::instance(); + })]); + $storage->set($variable, new JsString('settlement')); + $promise->{$settle}(new JsString('original')); + JsPromise::drainMicrotasks(); + self::assertSame($promise->getState(), $child->getState()); + self::assertSame('original', $child->getResolvedValue()->toJsString()); + self::assertSame('settlement', $storage->getRaw($variable)?->toJsString()); + } + self::assertSame(['registered:resolve', 'registered:reject'], $seen); + } finally { + $storage->restore($snapshot); + } + } + public function testContextPropagatesAcrossQueueMicrotask(): void { $engine = new Engine(); diff --git a/tests/Unit/BuiltIn/StringSearchCacheTest.php b/tests/Unit/BuiltIn/StringSearchCacheTest.php new file mode 100644 index 00000000..fd9f4250 --- /dev/null +++ b/tests/Unit/BuiltIn/StringSearchCacheTest.php @@ -0,0 +1,25 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/string-search-cache.js')); + self::assertSame( + trim((string) file_get_contents(__DIR__ . '/fixtures/string-search-cache.json')), + $engine->eval('JSON.stringify(stringSearchCacheResult)'), + ); + $function = $engine->getGlobalEnv()->get('cachedSearch'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, 'The search fixture must also exercise warmed bytecode dispatch.'); + } +} diff --git a/tests/Unit/BuiltIn/WeakMapLifetimeTest.php b/tests/Unit/BuiltIn/WeakMapLifetimeTest.php new file mode 100644 index 00000000..89b6a188 --- /dev/null +++ b/tests/Unit/BuiltIn/WeakMapLifetimeTest.php @@ -0,0 +1,90 @@ +set('key', $key); + $map->weakMapSet($key, $value); + $keyReference = \WeakReference::create($key); + $valueReference = \WeakReference::create($value); + unset($key, $value); + gc_collect_cycles(); + self::assertNull($keyReference->get()); + self::assertNull($valueReference->get()); + self::assertInstanceOf(JsUndefined::class, $map->weakMapGet(new JsObject())); + } + + public function testAReferencedKeyRetainsItsValueUntilDeleteOrCollectionOfTheMap(): void + { + foreach ([new JsObject(), new JsSymbol('key')] as $key) { + $map = new JsWeakMap(); + $value = new JsObject(); + $valueReference = \WeakReference::create($value); + $map->weakMapSet($key, $value); + unset($value); + gc_collect_cycles(); + self::assertSame($valueReference->get(), $map->weakMapGet($key)); + self::assertNotNull($valueReference->get()); + self::assertTrue($map->weakMapDelete($key)); + self::assertNull($valueReference->get()); + self::assertFalse($map->weakMapDelete($key)); + + $value = new JsObject(); + $valueReference = \WeakReference::create($value); + $mapReference = \WeakReference::create($map); + $map->weakMapSet($key, $value); + unset($map, $value); + gc_collect_cycles(); + self::assertNull($mapReference->get()); + self::assertNull($valueReference->get()); + } + } + + public function testIndependentCollectionsAndReplacementPreserveNodeSemantics(): void + { + $engine = new Engine(); + self::assertSame([true, false, true, 9, 12, true, false, true, false, true], $engine->eval(<<<'JS' +const key = Object.freeze({}), symbol = Symbol('key'); +const first = new WeakMap(), second = new WeakMap(); +first.set(key, undefined).set(symbol, 7); +second.set(key, 12); +const observations = [first.has(key), first.get(key) !== undefined, second.has(key)]; +first.set(key, 9); +observations.push(first.get(key), second.get(key), first.delete(symbol), first.has(symbol)); +let invalid = false; +try { first.set(Symbol.for('registered'), 1); } catch (error) { invalid = error instanceof TypeError; } +observations.push(invalid, first.has(Symbol.for('registered')), first.get({}) === undefined); +observations; +JS)); + } + + public function testAnExternallyReferencedKeyDoesNotKeepAValueToMapCycleAlive(): void + { + $key = new JsObject(); + $map = new JsWeakMap(); + $value = new JsObject(); + $value->set('map', $map); + $map->weakMapSet($key, $value); + $mapReference = \WeakReference::create($map); + $valueReference = \WeakReference::create($value); + unset($map, $value); + gc_collect_cycles(); + self::assertNull($mapReference->get()); + self::assertNull($valueReference->get()); + } +} diff --git a/tests/Unit/BuiltIn/fixtures/string-search-cache.js b/tests/Unit/BuiltIn/fixtures/string-search-cache.js new file mode 100644 index 00000000..0ba49c0b --- /dev/null +++ b/tests/Unit/BuiltIn/fixtures/string-search-cache.js @@ -0,0 +1,61 @@ +function cachedSearch(value, needle, position) { + return value.indexOf(needle, position); +} +var searchResults = []; +var values = ['', 'aabaa', 'A\0B', 'A😀B😀', '\ud800\u6100b', '\udfff', '\ud83d', '\ude00', '\u0000\u0001', 'undefined']; +var needles = ['', 'a', '\0', 'B', '😀', '\ud83d', '\ude00', '\ud800', '\udfff', '\u6261', '\u0100', 'undefined']; +var positions = [undefined, null, NaN, -Infinity, Infinity, -7, -0, 0, 1, 1.9, 3, 999]; +for (var round = 0; round < 2; round++) { + for (var value of values) { + for (var needle of needles) { + for (var position of positions) searchResults.push(cachedSearch(value, needle, position)); + } + } + var log = []; + var receiver = { toString() { log.push('receiver'); return 'cabca'; } }; + var needle = { toString() { log.push('needle'); receiver.toString = () => ''; return 'a'; } }; + var position = { valueOf() { log.push('position'); needle.toString = () => 'b'; return 1; } }; + searchResults.push(String.prototype.indexOf.call(receiver, needle, position), log.slice()); + log = []; + searchResults.push(String.prototype.indexOf.call(receiver, needle, position), log.slice()); + var boxed = new String('cabca'); + boxed.toString = function () { log.push('boxed'); return '😀x😀'; }; + searchResults.push(String.prototype.indexOf.call(boxed, '\ude00', 1), log.slice()); + var original = String.prototype.indexOf; + var replacementNeedle = { toString() { String.prototype.indexOf = () => 42; return 'a'; } }; + try { + searchResults.push(cachedSearch('cabca', replacementNeedle, 0), cachedSearch('cabca', 'a', 0)); + } finally { String.prototype.indexOf = original; } + for (var bad of [Symbol('needle'), { [Symbol.toPrimitive]() { return Symbol('needle'); } }]) { + try { cachedSearch('abc', bad, 0); } catch (error) { searchResults.push(error.name); } + } +} +var wrapperCases = [ + ['charAt', 2], ['charCodeAt', 2], ['indexOf', 'A'], ['lastIndexOf', 'A'], + ['includes', 'A'], ['startsWith', ' '], ['endsWith', ' '], ['slice', 1, 4], + ['substring', 1, 4], ['concat', '!'], ['at', 2], ['codePointAt', 2], + ['toLowerCase'], ['toUpperCase'], ['trim'], ['trimStart'], ['trimEnd'], + ['repeat', 2], ['padStart', 10, '-'], ['padEnd', 10, '-'], ['normalize'], + ['isWellFormed'], ['toWellFormed'], ['substr', 1, 3], ['anchor', 'target'], + ['split', 'A'], ['replace', 'A', 'Z'], ['replaceAll', 'A', 'Z'] +]; +var wrapperResults = []; +for (var primitive of ['ignored', 42, true]) { + var wrapper = Object(primitive); + wrapper.toString = function () { return ' A😀A '; }; + for (var entry of wrapperCases) { + wrapperResults.push([typeof primitive, entry[0], String.prototype[entry[0]].apply(wrapper, entry.slice(1))]); + } + wrapper[Symbol.toPrimitive] = function (hint) { + if (hint !== 'string') throw new Error('Wrong coercion hint'); + return ' A😀A '; + }; + for (var entry of wrapperCases) { + wrapperResults.push([typeof primitive, entry[0], String.prototype[entry[0]].apply(wrapper, entry.slice(1))]); + } +} +var fakeSlotReads = 0; +var ordinary = { toString() { return 'correct'; } }; +Object.defineProperty(ordinary, '[[PrimitiveValue]]', { get() { fakeSlotReads++; return 'incorrect'; } }); +wrapperResults.push(String.prototype.indexOf.call(ordinary, 'correct'), fakeSlotReads); +globalThis.stringSearchCacheResult = { searches: searchResults, wrappers: wrapperResults }; diff --git a/tests/Unit/BuiltIn/fixtures/string-search-cache.json b/tests/Unit/BuiltIn/fixtures/string-search-cache.json new file mode 100644 index 00000000..df52ff5c --- /dev/null +++ b/tests/Unit/BuiltIn/fixtures/string-search-cache.json @@ -0,0 +1 @@ +{"searches":[0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,5,0,0,0,1,1,3,5,0,0,0,0,-1,0,0,0,1,1,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,3,0,0,0,1,1,3,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,1,1,1,1,1,-1,-1,2,2,2,2,-1,2,2,2,2,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,6,0,0,0,1,1,3,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,3,3,3,-1,3,3,3,3,3,3,-1,1,1,1,1,-1,1,1,1,1,1,4,-1,1,1,1,1,-1,1,1,1,1,1,4,-1,2,2,2,2,-1,2,2,2,2,2,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,3,0,0,0,1,1,3,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,1,0,0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,1,0,0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,1,0,0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,2,0,0,0,1,1,2,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,9,0,0,0,1,1,3,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,1,["receiver","needle","position"],-1,["position"],1,["position","boxed"],1,42,"TypeError","TypeError",0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,5,0,0,0,1,1,3,5,0,0,0,0,-1,0,0,0,1,1,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,3,0,0,0,1,1,3,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,1,1,1,1,1,-1,-1,2,2,2,2,-1,2,2,2,2,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,6,0,0,0,1,1,3,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,3,3,3,-1,3,3,3,3,3,3,-1,1,1,1,1,-1,1,1,1,1,1,4,-1,1,1,1,1,-1,1,1,1,1,1,4,-1,2,2,2,2,-1,2,2,2,2,2,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,3,0,0,0,1,1,3,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,1,0,0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,1,0,0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,1,0,0,0,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,2,0,0,0,1,1,2,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,9,0,0,0,1,1,3,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,0,0,0,-1,-1,-1,-1,1,["receiver","needle","position"],-1,["position"],1,["position","boxed"],1,42,"TypeError","TypeError"],"wrappers":[["string","charAt","\ud83d"],["string","charCodeAt",55357],["string","indexOf",1],["string","lastIndexOf",4],["string","includes",true],["string","startsWith",true],["string","endsWith",true],["string","slice","A😀"],["string","substring","A😀"],["string","concat"," A😀A !"],["string","at","\ud83d"],["string","codePointAt",128512],["string","toLowerCase"," a😀a "],["string","toUpperCase"," A😀A "],["string","trim","A😀A"],["string","trimStart","A😀A "],["string","trimEnd"," A😀A"],["string","repeat"," A😀A A😀A "],["string","padStart","---- A😀A "],["string","padEnd"," A😀A ----"],["string","normalize"," A😀A "],["string","isWellFormed",true],["string","toWellFormed"," A😀A "],["string","substr","A😀"],["string","anchor"," A😀A "],["string","split",[" ","😀"," "]],["string","replace"," Z😀A "],["string","replaceAll"," Z😀Z "],["string","charAt","\ud83d"],["string","charCodeAt",55357],["string","indexOf",1],["string","lastIndexOf",4],["string","includes",true],["string","startsWith",true],["string","endsWith",true],["string","slice","A😀"],["string","substring","A😀"],["string","concat"," A😀A !"],["string","at","\ud83d"],["string","codePointAt",128512],["string","toLowerCase"," a😀a "],["string","toUpperCase"," A😀A "],["string","trim","A😀A"],["string","trimStart","A😀A "],["string","trimEnd"," A😀A"],["string","repeat"," A😀A A😀A "],["string","padStart","---- A😀A "],["string","padEnd"," A😀A ----"],["string","normalize"," A😀A "],["string","isWellFormed",true],["string","toWellFormed"," A😀A "],["string","substr","A😀"],["string","anchor"," A😀A "],["string","split",[" ","😀"," "]],["string","replace"," Z😀A "],["string","replaceAll"," Z😀Z "],["number","charAt","\ud83d"],["number","charCodeAt",55357],["number","indexOf",1],["number","lastIndexOf",4],["number","includes",true],["number","startsWith",true],["number","endsWith",true],["number","slice","A😀"],["number","substring","A😀"],["number","concat"," A😀A !"],["number","at","\ud83d"],["number","codePointAt",128512],["number","toLowerCase"," a😀a "],["number","toUpperCase"," A😀A "],["number","trim","A😀A"],["number","trimStart","A😀A "],["number","trimEnd"," A😀A"],["number","repeat"," A😀A A😀A "],["number","padStart","---- A😀A "],["number","padEnd"," A😀A ----"],["number","normalize"," A😀A "],["number","isWellFormed",true],["number","toWellFormed"," A😀A "],["number","substr","A😀"],["number","anchor"," A😀A "],["number","split",[" ","😀"," "]],["number","replace"," Z😀A "],["number","replaceAll"," Z😀Z "],["number","charAt","\ud83d"],["number","charCodeAt",55357],["number","indexOf",1],["number","lastIndexOf",4],["number","includes",true],["number","startsWith",true],["number","endsWith",true],["number","slice","A😀"],["number","substring","A😀"],["number","concat"," A😀A !"],["number","at","\ud83d"],["number","codePointAt",128512],["number","toLowerCase"," a😀a "],["number","toUpperCase"," A😀A "],["number","trim","A😀A"],["number","trimStart","A😀A "],["number","trimEnd"," A😀A"],["number","repeat"," A😀A A😀A "],["number","padStart","---- A😀A "],["number","padEnd"," A😀A ----"],["number","normalize"," A😀A "],["number","isWellFormed",true],["number","toWellFormed"," A😀A "],["number","substr","A😀"],["number","anchor"," A😀A "],["number","split",[" ","😀"," "]],["number","replace"," Z😀A "],["number","replaceAll"," Z😀Z "],["boolean","charAt","\ud83d"],["boolean","charCodeAt",55357],["boolean","indexOf",1],["boolean","lastIndexOf",4],["boolean","includes",true],["boolean","startsWith",true],["boolean","endsWith",true],["boolean","slice","A😀"],["boolean","substring","A😀"],["boolean","concat"," A😀A !"],["boolean","at","\ud83d"],["boolean","codePointAt",128512],["boolean","toLowerCase"," a😀a "],["boolean","toUpperCase"," A😀A "],["boolean","trim","A😀A"],["boolean","trimStart","A😀A "],["boolean","trimEnd"," A😀A"],["boolean","repeat"," A😀A A😀A "],["boolean","padStart","---- A😀A "],["boolean","padEnd"," A😀A ----"],["boolean","normalize"," A😀A "],["boolean","isWellFormed",true],["boolean","toWellFormed"," A😀A "],["boolean","substr","A😀"],["boolean","anchor"," A😀A "],["boolean","split",[" ","😀"," "]],["boolean","replace"," Z😀A "],["boolean","replaceAll"," Z😀Z "],["boolean","charAt","\ud83d"],["boolean","charCodeAt",55357],["boolean","indexOf",1],["boolean","lastIndexOf",4],["boolean","includes",true],["boolean","startsWith",true],["boolean","endsWith",true],["boolean","slice","A😀"],["boolean","substring","A😀"],["boolean","concat"," A😀A !"],["boolean","at","\ud83d"],["boolean","codePointAt",128512],["boolean","toLowerCase"," a😀a "],["boolean","toUpperCase"," A😀A "],["boolean","trim","A😀A"],["boolean","trimStart","A😀A "],["boolean","trimEnd"," A😀A"],["boolean","repeat"," A😀A A😀A "],["boolean","padStart","---- A😀A "],["boolean","padEnd"," A😀A ----"],["boolean","normalize"," A😀A "],["boolean","isWellFormed",true],["boolean","toWellFormed"," A😀A "],["boolean","substr","A😀"],["boolean","anchor"," A😀A "],["boolean","split",[" ","😀"," "]],["boolean","replace"," Z😀A "],["boolean","replaceAll"," Z😀Z "],0,0]} diff --git a/tests/Unit/Bytecode/ArgumentsBindingTest.php b/tests/Unit/Bytecode/ArgumentsBindingTest.php new file mode 100644 index 00000000..6f77e29d --- /dev/null +++ b/tests/Unit/Bytecode/ArgumentsBindingTest.php @@ -0,0 +1,39 @@ +eval(<<<'JS' +function zero() { return [arguments.length, arguments[0], arguments.callee === zero]; } +function strict(a) { 'use strict'; arguments[0] = 7; return [a, arguments[0], arguments.length]; } +function outer() { return (() => arguments[0])(); } +[zero(4, 5), zero(9), strict(3), strict(8), outer(6), outer(11)]; +JS)); + foreach (['zero', 'strict', 'outer'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise bytecode.'); + self::assertFalse($function->compiled->canSkipEnvAlloc); + } + } + + public function testMappedParametersAndShadowedArgumentsKeepInterpreterSemantics(): void + { + $engine = new Engine(); + self::assertSame([[7, 8], [7, 8], 3, 2], $engine->eval(<<<'JS' +function mapped(a) { arguments[0] = 7; const result = a; a = 8; return [result, arguments[0]]; } +function shadowed() { var arguments; return arguments.length; } +[mapped(1), mapped(2), shadowed(1, 2, 3), shadowed(4, 5)]; +JS)); + } +} diff --git a/tests/Unit/Bytecode/ArrayBindingTest.php b/tests/Unit/Bytecode/ArrayBindingTest.php new file mode 100644 index 00000000..56ccadb0 --- /dev/null +++ b/tests/Unit/Bytecode/ArrayBindingTest.php @@ -0,0 +1,41 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/array-bindings.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/array-bindings.json', + $engine->eval('JSON.stringify(arrayBindingResult)'), + ); + foreach (['first', 'pair', 'elided', 'empty', 'rest', 'duplicate', 'captured'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise the bytecode path.'); + } + } + + public function testInterpreterArrayBindingsMatchTheSameNodeOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/array-bindings.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/array-bindings.json', + $engine->eval('JSON.stringify(arrayBindingResult)'), + ); + $function = $engine->getGlobalEnv()->get('first'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled); + } +} diff --git a/tests/Unit/Bytecode/CapturedBindingTest.php b/tests/Unit/Bytecode/CapturedBindingTest.php index d8cd964c..fe0ac225 100644 --- a/tests/Unit/Bytecode/CapturedBindingTest.php +++ b/tests/Unit/Bytecode/CapturedBindingTest.php @@ -131,6 +131,22 @@ function advance() { counter += 2; limit = 5; } $this->assertCompiled($engine, 'loop'); } + public function testRecursiveActivationsCannotReuseInnerCapturedNameCacheValues(): void + { + $engine = new Engine(); + self::assertSame([['a' => ['b' => 3]], ['a' => ['b' => 5]]], $engine->eval(<<<'JS' +function clone(source) { + var result = {}; + Object.keys(source).forEach(function (key) { + result[key] = source[key] instanceof Object ? clone(source[key]) : source[key]; + }); + return result; +} +[clone({a: {b: 3}}), clone({a: {b: 5}})]; +JS)); + $this->assertCompiled($engine, 'clone'); + } + private function assertCompiled(Engine $engine, string $name): void { $function = $engine->getGlobalEnv()->get($name); diff --git a/tests/Unit/Bytecode/CompilationFailuresTest.php b/tests/Unit/Bytecode/CompilationFailuresTest.php index de125585..98d6317b 100644 --- a/tests/Unit/Bytecode/CompilationFailuresTest.php +++ b/tests/Unit/Bytecode/CompilationFailuresTest.php @@ -15,28 +15,27 @@ final class CompilationFailuresTest extends TestCase { - public function testStrictTailCallBailoutDoesNotDisableSloppyCompilationOfTheSameSyntax(): void + public function testAsyncBailoutDoesNotDisableOrdinaryCompilationOfTheSameSyntax(): void { $engine = new Engine(); $engine->eval(<<<'JS' function helper(value) { return value + 1; } -function template(value) { try { return helper(value); } catch (error) { return 0; } } +function template(value) { return helper(value); } JS); $template = $engine->getGlobalEnv()->get('template'); self::assertInstanceOf(JsFunction::class, $template); - $strict = new JsFunction('strict', $template->getParams(), $template->getBody(), $template->getClosure(), strict: true); - self::assertNull(JsToPhp::compile($strict)); + $async = new JsFunction('async', $template->getParams(), $template->getBody(), $template->getClosure(), isAsync: true); + self::assertNull(JsToPhp::compile($async)); try { - (new Compiler())->compile($strict); - self::fail('Strict tail calls require the interpreter trampoline.'); + (new Compiler())->compile($async); + self::fail('Async functions require the interpreter.'); } catch (CompilerBailout $error) { - self::assertStringContainsString('tail', $error->getMessage()); + self::assertSame('non-ordinary function kind', $error->getMessage()); } - $sloppy = new JsFunction('sloppy', $template->getParams(), $template->getBody(), $template->getClosure()); - self::assertInstanceOf(CompiledFunction::class, (new Compiler())->compile($sloppy)); - $engine->setGlobalJsValue('strict', $strict); - $engine->setGlobalJsValue('sloppy', $sloppy); - self::assertSame('3:5', $engine->eval('[strict(2), sloppy(4)].join(":")')); + $ordinary = new JsFunction('ordinary', $template->getParams(), $template->getBody(), $template->getClosure()); + self::assertInstanceOf(CompiledFunction::class, (new Compiler())->compile($ordinary)); + $engine->setGlobalJsValue('ordinary', $ordinary); + self::assertSame(5, $engine->eval('ordinary(4)')); } public function testMethodBailoutDoesNotDisableOrdinaryNumericCompilation(): void diff --git a/tests/Unit/Bytecode/CompilationTemplatesTest.php b/tests/Unit/Bytecode/CompilationTemplatesTest.php index a77ead60..58f82400 100644 --- a/tests/Unit/Bytecode/CompilationTemplatesTest.php +++ b/tests/Unit/Bytecode/CompilationTemplatesTest.php @@ -29,7 +29,7 @@ function make(value) { return function read() { return value.amount; }; } self::assertNotNull($second->compiled); self::assertNotSame($first->compiled, $second->compiled); self::assertSame($first->compiled->code, $second->compiled->code); - $first->compiled->loadNameIc[9876] = [JsNumber::of(30), 0]; + $first->compiled->loadNameIc[9876] = [JsNumber::of(30), 0, \WeakReference::create($first->getClosure())]; self::assertArrayNotHasKey(9876, $second->compiled->loadNameIc); self::assertSame([1, 9, 1, 9], $engine->eval('[first(), second(), first(), second()]')); } @@ -51,4 +51,30 @@ public function testTemplateDoesNotKeepDiscardedSyntaxOrEnvironmentsAlive(): voi self::assertNull($bodyReference->get()); self::assertNull($closureReference->get()); } + + public function testWarmedNameCacheDoesNotRetainAnObjectContainingAClosure(): void + { + $engine = new Engine(); + $engine->eval(<<<'JS' +function make(value) { return {read: function () { return value; }}; } +let held = make(7); +function readCached() { return [held]; } +readCached(); readCached(); +JS); + $held = $engine->getGlobalEnv()->get('held'); + self::assertInstanceOf(\Phasis\Value\JsObject::class, $held); + $read = $held->get('read'); + self::assertInstanceOf(JsFunction::class, $read); + $activation = \WeakReference::create($read->getClosure()); + $holder = \WeakReference::create($held); + $cached = $engine->getGlobalEnv()->get('readCached'); + self::assertInstanceOf(JsFunction::class, $cached); + self::assertNotNull($cached->compiled); + self::assertNotEmpty($cached->compiled->loadNameIc); + $engine->eval('held = undefined;'); + unset($held, $read); + gc_collect_cycles(); + self::assertNull($holder->get()); + self::assertNull($activation->get()); + } } diff --git a/tests/Unit/Bytecode/CustomCallstackTest.php b/tests/Unit/Bytecode/CustomCallstackTest.php index 8e8200c0..bfe51f4d 100644 --- a/tests/Unit/Bytecode/CustomCallstackTest.php +++ b/tests/Unit/Bytecode/CustomCallstackTest.php @@ -112,12 +112,8 @@ function fib(n) { $this->assertSame(610, $sum); } - public function testFinallyTreeWalkerFallbackStillWorks(): void + public function testFinallyRunsBeforeAnExceptionUnwindsToTheCaller(): void { - // try/finally bails out of the bytecode compiler today, so - // these run on the tree-walker — the inlined path isn't - // involved. Pinning the test ensures the slow-path RET - // semantics keep matching the inlined-path RET. $engine = new Engine(); $result = $engine->eval(<<<'JS' "use strict"; diff --git a/tests/Unit/Bytecode/FinallyCompletionTest.php b/tests/Unit/Bytecode/FinallyCompletionTest.php new file mode 100644 index 00000000..15faa6f1 --- /dev/null +++ b/tests/Unit/Bytecode/FinallyCompletionTest.php @@ -0,0 +1,42 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/finally-completions.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/finally-completions.json', + $engine->eval('JSON.stringify(finallyCompletionResult)'), + ); + foreach (['complete', 'nested', 'outerCatch', 'returnExpression', 'looped', 'finallyTail'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise the bytecode path.'); + } + self::assertSame(5000, $engine->eval('finallyTail(5000, 0)')); + } + + public function testInterpreterFinalizersMatchTheSameNodeOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/finally-completions.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/finally-completions.json', + $engine->eval('JSON.stringify(finallyCompletionResult)'), + ); + $function = $engine->getGlobalEnv()->get('complete'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled); + } +} diff --git a/tests/Unit/Bytecode/FrameLifetimeTest.php b/tests/Unit/Bytecode/FrameLifetimeTest.php new file mode 100644 index 00000000..2bc2c87a --- /dev/null +++ b/tests/Unit/Bytecode/FrameLifetimeTest.php @@ -0,0 +1,59 @@ +eval(<<<'JS' +function inner(value) { return [this, value].length; } +function outer(value) { return inner.call(value, value) + inner(value); } +outer({}); outer({}); +JS); + $value = new JsObject(); + $reference = \WeakReference::create($value); + $engine->setGlobalJsValue('temporary', $value); + self::assertSame(4, $engine->eval('outer(temporary)')); + $engine->setGlobalJsValue('temporary', JsUndefined::instance()); + unset($value); + gc_collect_cycles(); + self::assertTrue($reference->get() === null, 'Completed frames must release arguments and receivers.'); + } + + public function testExceptionUnwindingReleasesPooledFrames(): void + { + $engine = new Engine(); + $engine->eval(<<<'JS' +function inner(value) { throw value; } +function outer(value) { try { inner(value); } catch (error) { return 7; } } +outer({}); outer({}); +JS); + $value = new JsObject(); + $reference = \WeakReference::create($value); + $engine->setGlobalJsValue('temporary', $value); + self::assertSame(7, $engine->eval('outer(temporary)')); + $engine->setGlobalJsValue('temporary', JsUndefined::instance()); + unset($value); + gc_collect_cycles(); + self::assertTrue($reference->get() === null, 'Unwound frames must release their arguments.'); + } + + public function testReturningAClosureKeepsItsActivationAlive(): void + { + $engine = new Engine(); + self::assertSame([3, 4, 11, 5], $engine->eval(<<<'JS' +function factory(value) { return function () { return ++value; }; } +const first = factory(2), second = factory(10); +[first(), first(), second(), first()]; +JS)); + } +} diff --git a/tests/Unit/Bytecode/LogicalAssignmentTest.php b/tests/Unit/Bytecode/LogicalAssignmentTest.php new file mode 100644 index 00000000..beca0aad --- /dev/null +++ b/tests/Unit/Bytecode/LogicalAssignmentTest.php @@ -0,0 +1,38 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/logical-assignments.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/logical-assignments.json', + $engine->eval('JSON.stringify(logicalAssignmentResult)'), + ); + foreach (['assignAnd', 'assignOr', 'assignNull', 'memberAnd', 'memberOr', 'memberNull', 'captured'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise bytecode.'); + } + } + + public function testInterpreterMatchesTheSameOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/logical-assignments.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/logical-assignments.json', + $engine->eval('JSON.stringify(logicalAssignmentResult)'), + ); + } +} diff --git a/tests/Unit/Bytecode/RelationalObjectTest.php b/tests/Unit/Bytecode/RelationalObjectTest.php new file mode 100644 index 00000000..aa1087e1 --- /dev/null +++ b/tests/Unit/Bytecode/RelationalObjectTest.php @@ -0,0 +1,41 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/relational-objects.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/relational-objects.json', + $engine->eval('JSON.stringify(relationalObjectResult)'), + ); + foreach (['contains', 'instance', 'containsOrdered', 'instanceOrdered'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise the bytecode path.'); + } + } + + public function testInterpreterObjectOperatorsMatchTheSameNodeOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/relational-objects.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/relational-objects.json', + $engine->eval('JSON.stringify(relationalObjectResult)'), + ); + $function = $engine->getGlobalEnv()->get('contains'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled); + } +} diff --git a/tests/Unit/Bytecode/SpreadCallTest.php b/tests/Unit/Bytecode/SpreadCallTest.php new file mode 100644 index 00000000..256cd4b1 --- /dev/null +++ b/tests/Unit/Bytecode/SpreadCallTest.php @@ -0,0 +1,38 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/spread-calls.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/spread-calls.json', + $engine->eval('JSON.stringify(spreadCallResult)'), + ); + foreach (['callMethod', 'spreadCall', 'spreadMethod', 'spreadNew', 'tailSpread', 'tailMethod'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise bytecode.'); + } + } + + public function testInterpreterUsesTheSameIteratorSemantics(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/spread-calls.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/spread-calls.json', + $engine->eval('JSON.stringify(spreadCallResult)'), + ); + } +} diff --git a/tests/Unit/Bytecode/TailCallTest.php b/tests/Unit/Bytecode/TailCallTest.php index 3aaadba5..92d4d40a 100644 --- a/tests/Unit/Bytecode/TailCallTest.php +++ b/tests/Unit/Bytecode/TailCallTest.php @@ -10,6 +10,40 @@ final class TailCallTest extends TestCase { + public function testCompiledProtectedCallsRetainTheirCatchAndCatchTailsRecur(): void + { + $engine = new Engine(); + self::assertSame(['0', '8', 'finally', '9'], $engine->eval(<<<'JS' +'use strict'; +function fail(value) { throw new Error(String(value)); } +function recover(count) { + try { return fail(count); } + catch (error) { + if (count === 0) return error.message; + return recover(count - 1); + } +} +function nested() { + try { + try { return fail(7); } + catch (first) { return fail(8); } + } catch (second) { return second.message; } +} +const order = [recover(2000), nested()]; +function finalized() { + try { return fail(9); } + finally { order.push('finally'); } +} +try { finalized(); } catch (error) { order.push(error.message); } +order; +JS)); + foreach (['recover', 'nested'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must use bytecode.'); + } + } + public function testStrictTailCallsDoNotGrowTheStackThroughCompiledCallers(): void { $engine = new Engine(); @@ -25,7 +59,25 @@ function wrapper() { let result = tail(10000, 0); result += tail(10000, 0); retu $function = $engine->getGlobalEnv()->get('tail'); self::assertInstanceOf(JsFunction::class, $function); self::assertNotNull($function->compiled); - self::assertFalse($function->compiled->canSkipEnvAlloc); + self::assertTrue($function->compiled->canSkipEnvAlloc); + self::assertTrue($function->compiled->hasTailCalls); + } + + public function testTailReturningConstructorsAndMethodsKeepTheirCompletionValues(): void + { + $engine = new Engine(); + self::assertSame([4, 5, 6, 7], $engine->eval(<<<'JS' +function value(n) { return n; } +function result(n) { return { value: n }; } +function TailObject(n) { 'use strict'; return result(n); } +function TailPrimitive(n) { 'use strict'; this.value = n; return value(9); } +function invoke(n) { 'use strict'; return this.base + value(n); } +function factory(n) { return new TailObject(n).value + new TailPrimitive(n).value; } +const receiver = { base: 1, invoke }; +const first = factory(1); +const second = factory(2); +[new TailObject(4).value, new TailPrimitive(5).value, receiver.invoke(5), receiver.invoke(6)]; +JS)); } public function testTailMethodsPreserveReceiverAndLookupBeforeArguments(): void diff --git a/tests/Unit/Bytecode/fixtures/array-bindings.js b/tests/Unit/Bytecode/fixtures/array-bindings.js new file mode 100644 index 00000000..0c4df4b5 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/array-bindings.js @@ -0,0 +1,77 @@ +'use strict'; + +function first(value) { const [a] = value; return a; } +function pair(value) { let [a, b] = value; return [a, b]; } +function elided(value) { const [, a] = value; return a; } +function empty(value) { const [] = value; return 'empty'; } +function rest(value) { const [a, ...remaining] = value; return [a, remaining]; } +function duplicate(value) { var [a, a] = value; return a; } +function captured(value) { + function observe() { return a; } + value.observe = observe; + const [a, b] = value; + return [a, b, observe()]; +} +function makeIterable(mode, trace) { + let step = 0; + const source = { + [Symbol.iterator]() { + trace.push('iterator'); + return { + get next() { + trace.push('get next'); + return function () { + step++; + trace.push('next:' + step); + if (source.observe) { + try { trace.push('observe:' + source.observe()); } + catch (error) { trace.push('observe:' + error.name); } + } + if (mode === 'next') throw 'next failure'; + return { + get done() { + trace.push('done:' + step); + if (mode === 'done') throw 'done failure'; + return step > 2; + }, + get value() { + trace.push('value:' + step); + if (mode === 'value' || (mode === 'hole' && step === 1)) throw 'value failure'; + return step * 10; + } + }; + }; + }, + get return() { + trace.push('get return'); + if (mode === 'return getter') throw 'return getter failure'; + if (mode === 'proxy') return new Proxy(function () { trace.push('proxy return'); return {}; }, {}); + return function () { + trace.push('return'); + if (mode === 'return value') return 1; + return {}; + }; + } + }; + } + }; + return source; +} +var arrayBindingResult = []; +for (let repeat = 0; repeat < 2; repeat++) { + for (const test of [ + [first, 'normal'], [pair, 'normal'], [elided, 'hole'], [empty, 'normal'], + [rest, 'normal'], [duplicate, 'normal'], [captured, 'normal'], + [first, 'next'], [first, 'done'], [first, 'value'], [first, 'proxy'], + [first, 'return getter'], [first, 'return value'] + ]) { + const trace = []; + try { arrayBindingResult.push([test[0].name, test[1], test[0](makeIterable(test[1], trace)), trace]); } + catch (error) { arrayBindingResult.push([test[0].name, test[1], error instanceof Error ? error.name : String(error), trace]); } + } + arrayBindingResult.push(pair([]), pair('😀x'), rest([1, 2, 3]), duplicate([4, 5])); + for (const value of [null, undefined, 2, {}]) { + try { first(value); } + catch (error) { arrayBindingResult.push(error.name); } + } +} diff --git a/tests/Unit/Bytecode/fixtures/array-bindings.json b/tests/Unit/Bytecode/fixtures/array-bindings.json new file mode 100644 index 00000000..42773c0b --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/array-bindings.json @@ -0,0 +1,436 @@ +[ + [ + "first", + "normal", + 10, + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "pair", + "normal", + [ + 10, + 20 + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "elided", + "hole", + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "empty", + "normal", + "empty", + [ + "iterator", + "get next", + "get return", + "return" + ] + ], + [ + "rest", + "normal", + [ + 10, + [ + 20 + ] + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "next:3", + "done:3" + ] + ], + [ + "duplicate", + "normal", + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "captured", + "normal", + [ + 10, + 20, + 10 + ], + [ + "iterator", + "get next", + "next:1", + "observe:ReferenceError", + "done:1", + "value:1", + "next:2", + "observe:10", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "first", + "next", + "next failure", + [ + "iterator", + "get next", + "next:1" + ] + ], + [ + "first", + "done", + "done failure", + [ + "iterator", + "get next", + "next:1", + "done:1" + ] + ], + [ + "first", + "value", + "value failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1" + ] + ], + [ + "first", + "proxy", + 10, + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "proxy return" + ] + ], + [ + "first", + "return getter", + "return getter failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return" + ] + ], + [ + "first", + "return value", + "TypeError", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + null, + null + ], + [ + "😀", + "x" + ], + [ + 1, + [ + 2, + 3 + ] + ], + 5, + "TypeError", + "TypeError", + "TypeError", + "TypeError", + [ + "first", + "normal", + 10, + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "pair", + "normal", + [ + 10, + 20 + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "elided", + "hole", + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "empty", + "normal", + "empty", + [ + "iterator", + "get next", + "get return", + "return" + ] + ], + [ + "rest", + "normal", + [ + 10, + [ + 20 + ] + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "next:3", + "done:3" + ] + ], + [ + "duplicate", + "normal", + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "captured", + "normal", + [ + 10, + 20, + 10 + ], + [ + "iterator", + "get next", + "next:1", + "observe:ReferenceError", + "done:1", + "value:1", + "next:2", + "observe:10", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "first", + "next", + "next failure", + [ + "iterator", + "get next", + "next:1" + ] + ], + [ + "first", + "done", + "done failure", + [ + "iterator", + "get next", + "next:1", + "done:1" + ] + ], + [ + "first", + "value", + "value failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1" + ] + ], + [ + "first", + "proxy", + 10, + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "proxy return" + ] + ], + [ + "first", + "return getter", + "return getter failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return" + ] + ], + [ + "first", + "return value", + "TypeError", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + null, + null + ], + [ + "😀", + "x" + ], + [ + 1, + [ + 2, + 3 + ] + ], + 5, + "TypeError", + "TypeError", + "TypeError", + "TypeError" +] diff --git a/tests/Unit/Bytecode/fixtures/finally-completions.js b/tests/Unit/Bytecode/fixtures/finally-completions.js new file mode 100644 index 00000000..26d5e77f --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/finally-completions.js @@ -0,0 +1,89 @@ +'use strict'; + +var finallyTrace = []; +function complete(mode) { + let value = 1; + try { + finallyTrace.push('try:' + mode); + if (mode === 0) return value; + if (mode === 1) return; + if (mode === 2) throw undefined; + if (mode >= 3) throw 'initial'; + } catch (error) { + finallyTrace.push('catch:' + String(error)); + if (mode === 2) return error; + if (mode === 3) return 'caught'; + throw 'replacement'; + } finally { + finallyTrace.push('finally:' + mode); + value = 2; + if (mode === 5) return 'override'; + if (mode === 6) throw 'final'; + } + return value; +} +function nested(mode) { + try { + try { + return 'initial'; + } finally { + finallyTrace.push('inner'); + if (mode === 0) return 'inner'; + if (mode === 1) throw 'inner'; + } + } finally { + finallyTrace.push('outer'); + if (mode === 2) return 'outer'; + } +} +function outerCatch() { + try { + try { return 'saved'; } + catch (inner) { return 'wrong catch'; } + finally { throw 'from finally'; } + } catch (outer) { + finallyTrace.push('outer catch'); + return outer; + } finally { + finallyTrace.push('outer cleanup'); + } +} +function returnExpression(object) { + try { return object.value; } + catch (error) { return error; } + finally { finallyTrace.push('expression cleanup'); } +} +function looped() { + let sum = 0; + for (let i = 0; i < 4; i++) { + try { + if (i === 3) return sum; + sum += i; + } finally { + finallyTrace.push('loop:' + i); + } + } +} +function finallyTail(count, result) { + try { throw 'discarded'; } + finally { + if (count === 0) return result; + return finallyTail(count - 1, result + 1); + } +} +var finallyCompletionResult = []; +for (let repeat = 0; repeat < 2; repeat++) { + for (let mode = -1; mode <= 6; mode++) { + try { finallyCompletionResult.push(['return', String(complete(mode))]); } + catch (error) { finallyCompletionResult.push(['throw', String(error)]); } + } + for (let mode = 0; mode < 3; mode++) { + try { finallyCompletionResult.push(['nested return', nested(mode)]); } + catch (error) { finallyCompletionResult.push(['nested throw', error]); } + } + finallyCompletionResult.push(outerCatch()); + finallyCompletionResult.push(returnExpression({get value() { throw 'getter'; }})); + finallyCompletionResult.push(returnExpression({value: 9})); + finallyCompletionResult.push(looped(), finallyTail(10, 0)); +} +finallyCompletionResult.push(finallyTrace); diff --git a/tests/Unit/Bytecode/fixtures/finally-completions.json b/tests/Unit/Bytecode/fixtures/finally-completions.json new file mode 100644 index 00000000..52d028a2 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/finally-completions.json @@ -0,0 +1,172 @@ +[ + [ + "return", + "2" + ], + [ + "return", + "1" + ], + [ + "return", + "undefined" + ], + [ + "return", + "undefined" + ], + [ + "return", + "caught" + ], + [ + "throw", + "replacement" + ], + [ + "return", + "override" + ], + [ + "throw", + "final" + ], + [ + "nested return", + "inner" + ], + [ + "nested throw", + "inner" + ], + [ + "nested return", + "outer" + ], + "from finally", + "getter", + 9, + 3, + 10, + [ + "return", + "2" + ], + [ + "return", + "1" + ], + [ + "return", + "undefined" + ], + [ + "return", + "undefined" + ], + [ + "return", + "caught" + ], + [ + "throw", + "replacement" + ], + [ + "return", + "override" + ], + [ + "throw", + "final" + ], + [ + "nested return", + "inner" + ], + [ + "nested throw", + "inner" + ], + [ + "nested return", + "outer" + ], + "from finally", + "getter", + 9, + 3, + 10, + [ + "try:-1", + "finally:-1", + "try:0", + "finally:0", + "try:1", + "finally:1", + "try:2", + "catch:undefined", + "finally:2", + "try:3", + "catch:initial", + "finally:3", + "try:4", + "catch:initial", + "finally:4", + "try:5", + "catch:initial", + "finally:5", + "try:6", + "catch:initial", + "finally:6", + "inner", + "outer", + "inner", + "outer", + "inner", + "outer", + "outer catch", + "outer cleanup", + "expression cleanup", + "expression cleanup", + "loop:0", + "loop:1", + "loop:2", + "loop:3", + "try:-1", + "finally:-1", + "try:0", + "finally:0", + "try:1", + "finally:1", + "try:2", + "catch:undefined", + "finally:2", + "try:3", + "catch:initial", + "finally:3", + "try:4", + "catch:initial", + "finally:4", + "try:5", + "catch:initial", + "finally:5", + "try:6", + "catch:initial", + "finally:6", + "inner", + "outer", + "inner", + "outer", + "inner", + "outer", + "outer catch", + "outer cleanup", + "expression cleanup", + "expression cleanup", + "loop:0", + "loop:1", + "loop:2", + "loop:3" + ] +] diff --git a/tests/Unit/Bytecode/fixtures/logical-assignments.js b/tests/Unit/Bytecode/fixtures/logical-assignments.js new file mode 100644 index 00000000..1ee70ce3 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/logical-assignments.js @@ -0,0 +1,37 @@ +function assignAnd(value, right) { return [value &&= right(), value]; } +function assignOr(value, right) { return [value ||= right(), value]; } +function assignNull(value, right) { return [value ??= right(), value]; } +function memberAnd(base, right) { return base().value &&= right(); } +function memberOr(base, right) { return base().value ||= right(); } +function memberNull(base, right) { return base().value ??= right(); } +function captured(value, right) { + const read = function readValue() { return value; }; + const result = value ??= right(); + return [result, read()]; +} +const logicalTrace = []; +const logicalResults = []; +for (let pass = 0; pass < 2; pass++) { + for (const value of [undefined, null, false, true, 0, 3, '', 'x']) { + const rhs = () => { logicalTrace.push('rhs'); return 7; }; + logicalResults.push(assignAnd(value, rhs), assignOr(value, rhs), assignNull(value, rhs), captured(value, rhs)); + for (const method of [memberAnd, memberOr, memberNull]) { + let object; + const original = object = { + get value() { logicalTrace.push('get'); return value; }, + set value(next) { logicalTrace.push('set ' + next); this.stored = next; }, + }; + const result = method(() => { logicalTrace.push('base'); return object; }, () => { + logicalTrace.push('rhs'); object = {}; return 9; + }); + logicalResults.push([result, original.stored, object.stored]); + } + } + const frozenTruthy = Object.freeze({ value: 1 }); + const frozenFalsy = Object.freeze({ value: 0 }); + logicalResults.push(memberOr(() => frozenTruthy, () => { throw new Error('unexpected rhs'); })); + logicalResults.push(memberAnd(() => frozenFalsy, () => { throw new Error('unexpected rhs'); })); + try { memberNull(() => null, () => { logicalTrace.push('unexpected rhs'); }); } + catch (error) { logicalResults.push(error.name); } +} +const logicalAssignmentResult = [logicalResults, logicalTrace]; diff --git a/tests/Unit/Bytecode/fixtures/logical-assignments.json b/tests/Unit/Bytecode/fixtures/logical-assignments.json new file mode 100644 index 00000000..bac997e0 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/logical-assignments.json @@ -0,0 +1,668 @@ +[ + [ + [ + null, + null + ], + [ + 7, + 7 + ], + [ + 7, + 7 + ], + [ + 7, + 7 + ], + [ + null, + null, + null + ], + [ + 9, + 9, + null + ], + [ + 9, + 9, + null + ], + [ + null, + null + ], + [ + 7, + 7 + ], + [ + 7, + 7 + ], + [ + 7, + 7 + ], + [ + null, + null, + null + ], + [ + 9, + 9, + null + ], + [ + 9, + 9, + null + ], + [ + false, + false + ], + [ + 7, + 7 + ], + [ + false, + false + ], + [ + false, + false + ], + [ + false, + null, + null + ], + [ + 9, + 9, + null + ], + [ + false, + null, + null + ], + [ + 7, + 7 + ], + [ + true, + true + ], + [ + true, + true + ], + [ + true, + true + ], + [ + 9, + 9, + null + ], + [ + true, + null, + null + ], + [ + true, + null, + null + ], + [ + 0, + 0 + ], + [ + 7, + 7 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + null, + null + ], + [ + 9, + 9, + null + ], + [ + 0, + null, + null + ], + [ + 7, + 7 + ], + [ + 3, + 3 + ], + [ + 3, + 3 + ], + [ + 3, + 3 + ], + [ + 9, + 9, + null + ], + [ + 3, + null, + null + ], + [ + 3, + null, + null + ], + [ + "", + "" + ], + [ + 7, + 7 + ], + [ + "", + "" + ], + [ + "", + "" + ], + [ + "", + null, + null + ], + [ + 9, + 9, + null + ], + [ + "", + null, + null + ], + [ + 7, + 7 + ], + [ + "x", + "x" + ], + [ + "x", + "x" + ], + [ + "x", + "x" + ], + [ + 9, + 9, + null + ], + [ + "x", + null, + null + ], + [ + "x", + null, + null + ], + 1, + 0, + "TypeError", + [ + null, + null + ], + [ + 7, + 7 + ], + [ + 7, + 7 + ], + [ + 7, + 7 + ], + [ + null, + null, + null + ], + [ + 9, + 9, + null + ], + [ + 9, + 9, + null + ], + [ + null, + null + ], + [ + 7, + 7 + ], + [ + 7, + 7 + ], + [ + 7, + 7 + ], + [ + null, + null, + null + ], + [ + 9, + 9, + null + ], + [ + 9, + 9, + null + ], + [ + false, + false + ], + [ + 7, + 7 + ], + [ + false, + false + ], + [ + false, + false + ], + [ + false, + null, + null + ], + [ + 9, + 9, + null + ], + [ + false, + null, + null + ], + [ + 7, + 7 + ], + [ + true, + true + ], + [ + true, + true + ], + [ + true, + true + ], + [ + 9, + 9, + null + ], + [ + true, + null, + null + ], + [ + true, + null, + null + ], + [ + 0, + 0 + ], + [ + 7, + 7 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + null, + null + ], + [ + 9, + 9, + null + ], + [ + 0, + null, + null + ], + [ + 7, + 7 + ], + [ + 3, + 3 + ], + [ + 3, + 3 + ], + [ + 3, + 3 + ], + [ + 9, + 9, + null + ], + [ + 3, + null, + null + ], + [ + 3, + null, + null + ], + [ + "", + "" + ], + [ + 7, + 7 + ], + [ + "", + "" + ], + [ + "", + "" + ], + [ + "", + null, + null + ], + [ + 9, + 9, + null + ], + [ + "", + null, + null + ], + [ + 7, + 7 + ], + [ + "x", + "x" + ], + [ + "x", + "x" + ], + [ + "x", + "x" + ], + [ + 9, + 9, + null + ], + [ + "x", + null, + null + ], + [ + "x", + null, + null + ], + 1, + 0, + "TypeError" + ], + [ + "rhs", + "rhs", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "set 9", + "rhs", + "rhs", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "set 9", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "base", + "get", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "base", + "get", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "base", + "get", + "rhs", + "rhs", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "set 9", + "rhs", + "rhs", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "set 9", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "base", + "get", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "base", + "get", + "rhs", + "base", + "get", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "rhs", + "base", + "get", + "rhs", + "set 9", + "base", + "get", + "base", + "get" + ] +] diff --git a/tests/Unit/Bytecode/fixtures/relational-objects.js b/tests/Unit/Bytecode/fixtures/relational-objects.js new file mode 100644 index 00000000..f0aae2b4 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/relational-objects.js @@ -0,0 +1,51 @@ +'use strict'; + +function contains(key, object) { return key in object; } +function instance(value, constructor) { return value instanceof constructor; } +function containsOrdered(left, right) { return left() in right(); } +function instanceOrdered(left, right) { return left() instanceof right(); } +var relationalObjectResult = []; +for (let repeat = 0; repeat < 2; repeat++) { + const trace = []; + const symbol = Symbol('key'); + const prototype = {[symbol]: 1, inherited: 2}; + const object = Object.create(prototype); + relationalObjectResult.push(contains('inherited', object), contains(symbol, object), + contains(Object(symbol), object), contains('missing', object)); + const key = {[Symbol.toPrimitive](hint) { trace.push('key:' + hint); return 'inherited'; }}; + const proxy = new Proxy(object, {has(target, name) { trace.push('has:' + String(name)); return Reflect.has(target, name); }}); + relationalObjectResult.push(containsOrdered( + () => { trace.push('left'); return key; }, + () => { trace.push('right'); return proxy; } + )); + for (const invalid of [null, undefined, 3, true, 'x', Symbol('rhs')]) { + try { contains(key, invalid); } + catch (error) { trace.push('invalid:' + error.name); } + } + function Constructor() {} + const instanceValue = new Constructor(); + relationalObjectResult.push(instance(instanceValue, Constructor), instance(instanceValue, Constructor.bind(null)), + instance({}, Constructor), instance(3, Constructor)); + const custom = { + get [Symbol.hasInstance]() { + trace.push('get hasInstance'); + return new Proxy(function (value) { + trace.push('hasInstance:' + (this === custom) + ':' + value); + return 'truthy'; + }, {}); + } + }; + relationalObjectResult.push(instanceOrdered( + () => { trace.push('instance left'); return 7; }, + () => { trace.push('instance right'); return custom; } + )); + const valueProxy = new Proxy(instanceValue, { + getPrototypeOf(target) { trace.push('get prototype'); return Reflect.getPrototypeOf(target); } + }); + relationalObjectResult.push(instance(valueProxy, Constructor)); + for (const invalid of [null, undefined, 3, {}, {[Symbol.hasInstance]: 1}]) { + try { instance(instanceValue, invalid); } + catch (error) { trace.push('invalid instance:' + error.name); } + } + relationalObjectResult.push(trace); +} diff --git a/tests/Unit/Bytecode/fixtures/relational-objects.json b/tests/Unit/Bytecode/fixtures/relational-objects.json new file mode 100644 index 00000000..00462925 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/relational-objects.json @@ -0,0 +1,68 @@ +[ + true, + true, + true, + false, + true, + true, + true, + false, + false, + true, + true, + [ + "left", + "right", + "key:string", + "has:inherited", + "invalid:TypeError", + "invalid:TypeError", + "invalid:TypeError", + "invalid:TypeError", + "invalid:TypeError", + "invalid:TypeError", + "instance left", + "instance right", + "get hasInstance", + "hasInstance:true:7", + "get prototype", + "invalid instance:TypeError", + "invalid instance:TypeError", + "invalid instance:TypeError", + "invalid instance:TypeError", + "invalid instance:TypeError" + ], + true, + true, + true, + false, + true, + true, + true, + false, + false, + true, + true, + [ + "left", + "right", + "key:string", + "has:inherited", + "invalid:TypeError", + "invalid:TypeError", + "invalid:TypeError", + "invalid:TypeError", + "invalid:TypeError", + "invalid:TypeError", + "instance left", + "instance right", + "get hasInstance", + "hasInstance:true:7", + "get prototype", + "invalid instance:TypeError", + "invalid instance:TypeError", + "invalid instance:TypeError", + "invalid instance:TypeError", + "invalid instance:TypeError" + ] +] diff --git a/tests/Unit/Bytecode/fixtures/spread-calls.js b/tests/Unit/Bytecode/fixtures/spread-calls.js new file mode 100644 index 00000000..94b2c49a --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/spread-calls.js @@ -0,0 +1,86 @@ +const callTrace = []; +function callMethod(object, key, value) { return object[key](value()); } +function spreadCall(fn, first, items, last) { return fn(first(), ...items, last()); } +function spreadMethod(object, key, items) { return object[key](...items); } +function spreadNew(ctor, items) { return new ctor(...items); } +function tailSpread(n, value) { 'use strict'; return n ? tailSpread(...[n - 1, value + 1]) : value; } +function tailMethod(object, key, items) { 'use strict'; return object[key](...items); } +function collect() { 'use strict'; return [this === undefined, Array.from(arguments)]; } +function makeIterable(kind) { + return { + [Symbol.iterator]() { + callTrace.push('iterator'); + let index = 0; + const iterator = { + get next() { + callTrace.push('get next'); + const next = function () { + callTrace.push('next ' + index); + if (kind === 'throw-next') throw new Error('next'); + if (kind === 'primitive') return 1; + const current = index++; + return { + get done() { + callTrace.push('done ' + current); + if (kind === 'throw-done') throw new Error('done'); + return current === 2; + }, + get value() { + callTrace.push('value ' + current); + if (kind === 'throw-value') throw new Error('value'); + return current + 4; + }, + }; + }; + return kind === 'proxy' ? new Proxy(next, {}) : next; + }, + return() { callTrace.push('close'); return {}; }, + }; + return iterator; + }, + }; +} +const callResults = []; +const methodKey = Symbol('method'); +const receiver = { + marker: 12, + get [methodKey]() { + callTrace.push('get method'); + return function () { return [this.marker, Array.from(arguments)]; }; + }, +}; +const key = { [Symbol.toPrimitive](hint) { callTrace.push('key ' + hint); return methodKey; } }; +for (let pass = 0; pass < 2; pass++) { + callResults.push(callMethod(receiver, key, () => { callTrace.push('arg'); return 3; })); + callResults.push(spreadCall(collect, + () => { callTrace.push('first'); return 1; }, makeIterable('proxy'), + () => { callTrace.push('last'); return 9; })); + callResults.push(spreadMethod(receiver, key, makeIterable('proxy'))); + callResults.push(tailMethod(receiver, methodKey, [8])); + const primitiveKey = Symbol('primitive'); + Number.prototype[primitiveKey] = function () { 'use strict'; return [typeof this, this]; }; + callResults.push(spreadMethod(7, primitiveKey, [])); + delete Number.prototype[primitiveKey]; + callResults.push(spreadCall(new Proxy(collect, { + apply(target, self, args) { callTrace.push('apply'); return Reflect.apply(target, self, args); }, + }), () => 1, [2], () => 3)); + callResults.push(spreadCall(collect, () => 1, [2, , 4], () => 5)); + callResults.push(spreadNew(function Record(a, b) { this.value = a + b; }, [2, 7]).value); + callResults.push(spreadNew(new Proxy(function Record() {}, { + construct(target, args) { callTrace.push('construct'); return { value: args[0] }; }, + }), [11]).value); + for (const kind of ['throw-next', 'throw-done', 'throw-value', 'primitive']) { + try { spreadMethod(receiver, methodKey, makeIterable(kind)); } + catch (error) { callResults.push([kind, error.name, error instanceof TypeError ? 'invalid' : error.message]); } + } + try { spreadMethod({ x: 1 }, 'x', makeIterable('proxy')); } + catch (error) { callResults.push(['not callable', error.name]); } + const notIterable = [1, 2]; + notIterable[Symbol.iterator] = undefined; + try { spreadMethod(receiver, methodKey, notIterable); } + catch (error) { callResults.push(['not iterable', error.name]); } + try { callMethod(null, key, () => { callTrace.push('unexpected arg'); }); } + catch (error) { callResults.push(['null receiver', error.name]); } +} +callResults.push(tailSpread(5000, 0)); +const spreadCallResult = [callResults, callTrace]; diff --git a/tests/Unit/Bytecode/fixtures/spread-calls.json b/tests/Unit/Bytecode/fixtures/spread-calls.json new file mode 100644 index 00000000..9a6b9b3c --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/spread-calls.json @@ -0,0 +1,295 @@ +[ + [ + [ + 12, + [ + 3 + ] + ], + [ + true, + [ + 1, + 4, + 5, + 9 + ] + ], + [ + 12, + [ + 4, + 5 + ] + ], + [ + 12, + [ + 8 + ] + ], + [ + "number", + 7 + ], + [ + true, + [ + 1, + 2, + 3 + ] + ], + [ + true, + [ + 1, + 2, + null, + 4, + 5 + ] + ], + 9, + 11, + [ + "throw-next", + "Error", + "next" + ], + [ + "throw-done", + "Error", + "done" + ], + [ + "throw-value", + "Error", + "value" + ], + [ + "primitive", + "TypeError", + "invalid" + ], + [ + "not callable", + "TypeError" + ], + [ + "not iterable", + "TypeError" + ], + [ + "null receiver", + "TypeError" + ], + [ + 12, + [ + 3 + ] + ], + [ + true, + [ + 1, + 4, + 5, + 9 + ] + ], + [ + 12, + [ + 4, + 5 + ] + ], + [ + 12, + [ + 8 + ] + ], + [ + "number", + 7 + ], + [ + true, + [ + 1, + 2, + 3 + ] + ], + [ + true, + [ + 1, + 2, + null, + 4, + 5 + ] + ], + 9, + 11, + [ + "throw-next", + "Error", + "next" + ], + [ + "throw-done", + "Error", + "done" + ], + [ + "throw-value", + "Error", + "value" + ], + [ + "primitive", + "TypeError", + "invalid" + ], + [ + "not callable", + "TypeError" + ], + [ + "not iterable", + "TypeError" + ], + [ + "null receiver", + "TypeError" + ], + 5000 + ], + [ + "key string", + "get method", + "arg", + "first", + "iterator", + "get next", + "next 0", + "done 0", + "value 0", + "next 1", + "done 1", + "value 1", + "next 2", + "done 2", + "last", + "key string", + "get method", + "iterator", + "get next", + "next 0", + "done 0", + "value 0", + "next 1", + "done 1", + "value 1", + "next 2", + "done 2", + "get method", + "apply", + "construct", + "get method", + "iterator", + "get next", + "next 0", + "get method", + "iterator", + "get next", + "next 0", + "done 0", + "get method", + "iterator", + "get next", + "next 0", + "done 0", + "value 0", + "get method", + "iterator", + "get next", + "next 0", + "iterator", + "get next", + "next 0", + "done 0", + "value 0", + "next 1", + "done 1", + "value 1", + "next 2", + "done 2", + "get method", + "key string", + "get method", + "arg", + "first", + "iterator", + "get next", + "next 0", + "done 0", + "value 0", + "next 1", + "done 1", + "value 1", + "next 2", + "done 2", + "last", + "key string", + "get method", + "iterator", + "get next", + "next 0", + "done 0", + "value 0", + "next 1", + "done 1", + "value 1", + "next 2", + "done 2", + "get method", + "apply", + "construct", + "get method", + "iterator", + "get next", + "next 0", + "get method", + "iterator", + "get next", + "next 0", + "done 0", + "get method", + "iterator", + "get next", + "next 0", + "done 0", + "value 0", + "get method", + "iterator", + "get next", + "next 0", + "iterator", + "get next", + "next 0", + "done 0", + "value 0", + "next 1", + "done 1", + "value 1", + "next 2", + "done 2", + "get method" + ] +] diff --git a/tests/Unit/Node/StreamRealmTest.php b/tests/Unit/Node/StreamRealmTest.php new file mode 100644 index 00000000..9e5aa7ea --- /dev/null +++ b/tests/Unit/Node/StreamRealmTest.php @@ -0,0 +1,78 @@ +eval(<<<'JS' +const names = ['ReadableStream', 'ReadableStreamDefaultController', 'ReadableStreamDefaultReader', + 'ReadableByteStreamController', 'ReadableStreamBYOBReader', 'ReadableStreamBYOBRequest', + 'WritableStream', 'WritableStreamDefaultController', 'WritableStreamDefaultWriter', + 'TransformStream', 'TransformStreamDefaultController']; +const constructors = Object.fromEntries(names.map(name => [name, globalThis[name]])); +require('vm').runInNewContext('0'); +for (const name of names) globalThis[name] = function replaced() { throw new Error(name); }; +const results = []; +const check = (value, name) => results.push(Object.getPrototypeOf(value) === constructors[name].prototype); +let controller; +const readable = new constructors.ReadableStream({start(value) { controller = value; }}); +check(readable, 'ReadableStream'); +check(controller, 'ReadableStreamDefaultController'); +check(readable.getReader(), 'ReadableStreamDefaultReader'); +let byteController; +const bytes = new constructors.ReadableStream({type: 'bytes', start(value) { byteController = value; }}); +check(byteController, 'ReadableByteStreamController'); +const reader = bytes.getReader({mode: 'byob'}); +check(reader, 'ReadableStreamBYOBReader'); +reader.read(new Uint8Array(1)); +const request = byteController.byobRequest; +check(request, 'ReadableStreamBYOBRequest'); +request.respond(1); +byteController.close(); +let writableController; +const writable = new constructors.WritableStream({start(value) { writableController = value; }}); +check(writable, 'WritableStream'); +check(writableController, 'WritableStreamDefaultController'); +check(writable.getWriter(), 'WritableStreamDefaultWriter'); +let transformController; +const transform = new constructors.TransformStream({start(value) { transformController = value; }}); +check(transform, 'TransformStream'); +check(transformController, 'TransformStreamDefaultController'); +results; +JS)); + } finally { + $engine->getNodeRuntime()?->close(); + } + } + + public function testOuterControllerPrototypeReplacementStillInterceptsEnqueueAfterVmCreation(): void + { + $engine = new Engine(node: true); + try { + self::assertSame(['intercepted', 'intercepted'], $engine->eval(<<<'JS' +const prototype = ReadableStreamDefaultController.prototype; +require('vm').runInNewContext('0'); +const errors = []; +prototype.enqueue = function () { throw new Error('intercepted'); }; +for (let i = 0; i < 2; i++) { + new ReadableStream({start(controller) { + try { controller.enqueue(1); } catch (error) { errors.push(error.message); } + controller.close(); + }}); +} +errors; +JS)); + } finally { + $engine->getNodeRuntime()?->close(); + } + } +} diff --git a/tests/Unit/Node/VmLazyIntrinsicsTest.php b/tests/Unit/Node/VmLazyIntrinsicsTest.php new file mode 100644 index 00000000..fde62ed5 --- /dev/null +++ b/tests/Unit/Node/VmLazyIntrinsicsTest.php @@ -0,0 +1,66 @@ +eval(<<<'JS' +const vm = require('vm'); +const marker = function CustomUint8Array() {}; +const sandbox = vm.createContext({ Uint8Array: marker }); +const observations = [Object.keys(sandbox)]; +observations.push(vm.runInContext(`(() => { + const listed = Object.getOwnPropertyNames(globalThis).includes('Map'); + const descriptor = Object.getOwnPropertyDescriptor(globalThis, 'Map'); + return [listed, descriptor.writable, descriptor.enumerable, descriptor.configurable, 'get' in descriptor]; +})()`, sandbox)); +observations.push([ + vm.runInContext('new Map([[1, 2]]).get(1)', sandbox), + Object.hasOwn(sandbox, 'Map'), + sandbox.Uint8Array === marker, + vm.runInContext('typeof Uint16Array', sandbox) +]); +const firstMap = vm.runInContext('Map', sandbox); +const secondMap = vm.runInNewContext('Map'); +observations.push([firstMap !== Map, secondMap !== firstMap, Object.getPrototypeOf(new firstMap()) === firstMap.prototype]); +observations.push(vm.runInContext('delete DisposableStack; [typeof AsyncDisposableStack, typeof DisposableStack]', sandbox)); +vm.runInContext('Map = 1; delete Map', sandbox); +observations.push([vm.runInContext('typeof Map', sandbox), Object.hasOwn(sandbox, 'Map')]); +observations; +JS)); + } + + public function testOutsideDescriptorAccessMaterializesTheDefiningRealm(): void + { + $engine = new Engine(node: true); + self::assertSame([true, true, true, false, true], $engine->eval(<<<'JS' +const vm = require('vm'); +const sandbox = vm.createContext({}); +const foreign = vm.runInContext('globalThis', sandbox); +const descriptor = Object.getOwnPropertyDescriptor(foreign, 'Intl'); +const foreignObject = vm.runInContext('Object', sandbox); +[ + descriptor.value !== Intl, + Object.getPrototypeOf(descriptor.value) === foreignObject.prototype, + descriptor.value === vm.runInContext('Intl', sandbox), + Object.hasOwn(sandbox, 'Intl'), + Object.getPrototypeOf({}) === Object.prototype +]; +JS)); + } +} diff --git a/tests/Unit/Runtime/RegExpPreparationTest.php b/tests/Unit/Runtime/RegExpPreparationTest.php new file mode 100644 index 00000000..53a99862 --- /dev/null +++ b/tests/Unit/Runtime/RegExpPreparationTest.php @@ -0,0 +1,52 @@ +a+)', 'g'], $engine->eval(<<<'JS' +const calls = []; +const pattern = { toString() { calls.push('pattern'); return '(?a+)'; } }; +const flags = { toString() { calls.push('flags'); return 'g'; } }; +const first = new RegExp(pattern, flags); +const second = new RegExp(pattern, flags); +first.lastIndex = 17; +first.compile('b', 'i'); +const result = second.exec('aa'); +[calls.join(','), first.test('B'), result.groups.word, second.lastIndex, second.source, second.flags]; +JS)); + } + + public function testPreparedPatternsDoNotRetainTheirInstances(): void + { + $engine = new Engine(); + $engine->eval('var disposable = new RegExp("(?a+)", "g"); new RegExp("(?a+)", "g");'); + $regexp = $engine->getGlobalEnv()->get('disposable'); + self::assertInstanceOf(JsObject::class, $regexp); + $reference = \WeakReference::create($regexp); + unset($regexp); + $engine->eval('disposable = null;'); + gc_collect_cycles(); + self::assertNull($reference->get()); + } + + public function testCachedNullCharactersCannotBypassInvalidFlagValidation(): void + { + $engine = new Engine(); + self::assertSame([true, true], $engine->eval(<<<'JS' +const seeded = new RegExp('a\0x', 'g'); +let rejected = false; +try { new RegExp('x', 'g\0a'); } catch (error) { rejected = error instanceof SyntaxError; } +[seeded.test('a\0x'), rejected]; +JS)); + } +} From 486033ef4b0edc9b419a7cbcb3b7ff9841567c28 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 23 Oct 2026 19:29:44 +0000 Subject: [PATCH 04/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 61 +++++++------- compat.json | 229 ++++++++++++++++++++++++++++------------------------ 2 files changed, 158 insertions(+), 132 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 7255dfaa..d28cbbbd 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,30 +3,30 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-23T18:45:09+00:00` +- Snapshot time: `2026-10-23T19:29:41+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `3ac7add4` (dirty) +- Git: `feat/express-hono-compatibility` @ `0cef9bc9` (dirty) ## Summary | Pass | Fail | Skip | Blocked | Pending | Running | Attempted | Known | Total | Pass Rate | |---:|---:|---:|---:|---:|---:|---:|---:|---:|---:| -| 53616 | 0 | 0 | 0 | 0 | 0 | 53616 | 53616 | 53616 | 100.0% | +| 53614 | 0 | 0 | 2 | 0 | 0 | 53614 | 53616 | 53616 | 99.9% | ## Top-Level Areas | Area | Status | Pass | Fail | Skip | Blocked | Pending | Running | Pass Rate | |---|---|---:|---:|---:|---:|---:|---:|---:| | annexB | PASS | 1086 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| built-ins | PASS | 23823 | 0 | 0 | 0 | 0 | 0 | 100.0% | +| built-ins | BLOCKED | 23822 | 0 | 0 | 1 | 0 | 0 | 99.9% | | harness | PASS | 116 | 0 | 0 | 0 | 0 | 0 | 100.0% | | intl402 | PASS | 3382 | 0 | 0 | 0 | 0 | 0 | 100.0% | | language | PASS | 23726 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| staging | PASS | 1483 | 0 | 0 | 0 | 0 | 0 | 100.0% | +| staging | BLOCKED | 1482 | 0 | 0 | 1 | 0 | 0 | 99.9% | ## Group Coverage @@ -124,7 +124,7 @@ Generated from a completed `test262` pass. Do not edit by hand. | built-ins/WeakRef | PASS | 29 | 0 | 0 | 0 | 0 | 0 | 100.0% | | built-ins/WeakSet | PASS | 85 | 0 | 0 | 0 | 0 | 0 | 100.0% | | built-ins/decodeURI | PASS | 55 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| built-ins/decodeURIComponent | PASS | 56 | 0 | 0 | 0 | 0 | 0 | 100.0% | +| built-ins/decodeURIComponent | BLOCKED | 55 | 0 | 0 | 1 | 0 | 0 | 99.9% | | built-ins/encodeURI | PASS | 31 | 0 | 0 | 0 | 0 | 0 | 100.0% | | built-ins/encodeURIComponent | PASS | 31 | 0 | 0 | 0 | 0 | 0 | 100.0% | | built-ins/eval | PASS | 10 | 0 | 0 | 0 | 0 | 0 | 100.0% | @@ -190,34 +190,41 @@ Generated from a completed `test262` pass. Do not edit by hand. | staging/decorators | PASS | 3 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/explicit-resource-management | PASS | 53 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/set-methods | PASS | 3 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| staging/sm | PASS | 1406 | 0 | 0 | 0 | 0 | 0 | 100.0% | +| staging/sm | BLOCKED | 1405 | 0 | 0 | 1 | 0 | 0 | 99.9% | | staging/source-phase-imports | PASS | 2 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/top-level-await | PASS | 1 | 0 | 0 | 0 | 0 | 0 | 100.0% | +## Blocked Chunks + +| Group | Kind | Files | Sample | Log | +|---|---|---:|---|---| +| built-ins/decodeURIComponent | CRASH | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | `.compat-state-builtins-lower-de/logs/f3e05d6b74efcc2f559417cc3812a891e061afb3.log` | +| staging/sm | ERROR | 1 | `test262/test/staging/sm/regress/regress-1507322-deep-weakmap.js` | `.compat-state-staging/logs/88d920a3605ea3645888b001a85c1db6abe87399.log` | + ## Slowest Chunks | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| built-ins/decodeURIComponent | NORMAL | 290.158s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| built-ins/decodeURI | NORMAL | 262.427s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| staging/sm | NORMAL | 173.911s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 173.728s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 172.730s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 171.487s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 169.559s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 149.649s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| staging/sm | NORMAL | 148.734s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| staging/sm | NORMAL | 145.401s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| staging/sm | NORMAL | 135.000s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| staging/sm | NORMAL | 116.964s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| built-ins/decodeURI | NORMAL | 94.553s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | -| built-ins/decodeURIComponent | NORMAL | 94.443s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | -| built-ins/TypedArray | NORMAL | 77.784s | 3 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end.js` | -| language/literals | NORMAL | 70.363s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | -| intl402/DateTimeFormat | NORMAL | 68.395s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | -| staging/sm | NORMAL | 63.850s | 1 | `test262/test/staging/sm/Array/toSpliced-dense.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.852s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/IDS_Trinary_Operator.js`
`test262/test/built-ins/RegExp/property-escapes/generated/ID_Continue.js`
`test262/test/built-ins/RegExp/property-escapes/generated/ID_Start.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Ideographic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Join_Control.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.712s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Dash.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Default_Ignorable_Code_Point.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Deprecated.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Diacritic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Emoji.js` | +| built-ins/decodeURI | NORMAL | 339.582s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| built-ins/decodeURIComponent | CRASH | 200.998s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| built-ins/decodeURI | NORMAL | 118.793s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | +| built-ins/decodeURIComponent | NORMAL | 117.558s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | +| staging/sm | NORMAL | 111.026s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 105.210s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 103.433s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 101.988s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 93.660s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| staging/sm | NORMAL | 91.624s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 89.372s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 84.784s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| language/literals | NORMAL | 84.199s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | +| staging/sm | NORMAL | 82.111s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| built-ins/TypedArray | NORMAL | 79.193s | 3 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end.js` | +| staging/sm | NORMAL | 70.267s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| annexB/built-ins/RegExp | NORMAL | 63.933s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.467s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.460s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Kaithi.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Kannada.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Katakana.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.283s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 365f03ba..2fa8e781 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-23T18:45:09+00:00", - "updatedAt": "2026-10-23T18:45:09+00:00", + "generatedAt": "2026-10-23T19:29:41+00:00", + "updatedAt": "2026-10-23T19:29:41+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "3ac7add4", + "commit": "0cef9bc9", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "94ed41d682b079b976f2e9b4fd63434c3659259c", - "runIdentity": "3355ba33b0d9db4fa165fcde286b12d8895562484fbde1543a1004c859e8421a" + "fingerprint": "8e553d824afc3ec9e06fcd3df4c41746adeb4019", + "runIdentity": "037d3bd075bf5d91559fdf9858948b6d0d8d69a1878381499d9538215288d7e4" }, "discovery": { "groupCount": 161, @@ -199,16 +199,16 @@ "test262": { "skippedFeatures": [], "totals": { - "pass": 53616, + "pass": 53614, "fail": 0, "skip": 0, - "blocked": 0, + "blocked": 2, "pending": 0, "running": 0, - "attempted": 53616, + "attempted": 53614, "known": 53616, "total": 53616, - "passRate": 100 + "passRate": 99.9 }, "areas": [ { @@ -227,17 +227,17 @@ }, { "name": "built-ins", - "status": "pass", - "pass": 23823, + "status": "blocked", + "pass": 23822, "fail": 0, "skip": 0, - "blocked": 0, + "blocked": 1, "pending": 0, "running": 0, - "attempted": 23823, + "attempted": 23822, "known": 23823, "total": 23823, - "passRate": 100 + "passRate": 99.9 }, { "name": "harness", @@ -283,17 +283,17 @@ }, { "name": "staging", - "status": "pass", - "pass": 1483, + "status": "blocked", + "pass": 1482, "fail": 0, "skip": 0, - "blocked": 0, + "blocked": 1, "pending": 0, "running": 0, - "attempted": 1483, + "attempted": 1482, "known": 1483, "total": 1483, - "passRate": 100 + "passRate": 99.9 } ], "groups": [ @@ -1680,17 +1680,17 @@ { "name": "built-ins/decodeURIComponent", "area": "built-ins", - "status": "pass", - "pass": 56, + "status": "blocked", + "pass": 55, "fail": 0, "skip": 0, - "blocked": 0, + "blocked": 1, "pending": 0, "running": 0, - "attempted": 56, + "attempted": 55, "known": 56, "total": 56, - "passRate": 100 + "passRate": 99.9 }, { "name": "built-ins/encodeURI", @@ -2670,17 +2670,17 @@ { "name": "staging/sm", "area": "staging", - "status": "pass", - "pass": 1406, + "status": "blocked", + "pass": 1405, "fail": 0, "skip": 0, - "blocked": 0, + "blocked": 1, "pending": 0, "running": 0, - "attempted": 1406, + "attempted": 1405, "known": 1406, "total": 1406, - "passRate": 100 + "passRate": 99.9 }, { "name": "staging/source-phase-imports", @@ -2714,48 +2714,77 @@ } ], "failures": [], - "blockedChunks": [], - "slowChunks": [ + "blockedChunks": [ { "group": "built-ins/decodeURIComponent", - "kind": "normal", - "durationSec": 290.158, + "kind": "crash", + "message": "PHP Fatal error: Maximum execution time of 200 seconds exceeded in /home/runner/work/phasis/phasis/src/Value/JsString.php on line 30", "filesCount": 1, "sampleFiles": [ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" - ] + ], + "logFile": ".compat-state-builtins-lower-de/logs/f3e05d6b74efcc2f559417cc3812a891e061afb3.log" }, + { + "group": "staging/sm", + "kind": "error", + "message": "Segmentation fault (core dumped)", + "filesCount": 1, + "sampleFiles": [ + "test262/test/staging/sm/regress/regress-1507322-deep-weakmap.js" + ], + "logFile": ".compat-state-staging/logs/88d920a3605ea3645888b001a85c1db6abe87399.log" + } + ], + "slowChunks": [ { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 262.427, + "durationSec": 339.582, "filesCount": 1, "sampleFiles": [ "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" ] }, { - "group": "staging/sm", - "kind": "normal", - "durationSec": 173.911, + "group": "built-ins/decodeURIComponent", + "kind": "crash", + "durationSec": 200.998, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" ] }, { - "group": "staging/sm", + "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 173.728, - "filesCount": 1, + "durationSec": 118.793, + "filesCount": 25, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", + "...", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" + ] + }, + { + "group": "built-ins/decodeURIComponent", + "kind": "normal", + "durationSec": 117.558, + "filesCount": 25, + "sampleFiles": [ + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", + "...", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 172.73, + "durationSec": 111.026, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" @@ -2764,7 +2793,7 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 171.487, + "durationSec": 105.21, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" @@ -2773,87 +2802,83 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 169.559, + "durationSec": 103.433, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 149.649, + "durationSec": 101.988, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 148.734, + "durationSec": 93.66, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 145.401, + "durationSec": 91.624, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 135, + "durationSec": 89.372, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 116.964, + "durationSec": 84.784, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { - "group": "built-ins/decodeURI", + "group": "language/literals", "kind": "normal", - "durationSec": 94.553, + "durationSec": 84.199, "filesCount": 25, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", + "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", + "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", "...", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" + "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", + "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" ] }, { - "group": "built-ins/decodeURIComponent", + "group": "staging/sm", "kind": "normal", - "durationSec": 94.443, - "filesCount": 25, + "durationSec": 82.111, + "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", - "...", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" ] }, { "group": "built-ins/TypedArray", "kind": "normal", - "durationSec": 77.784, + "durationSec": 79.193, "filesCount": 3, "sampleFiles": [ "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", @@ -2862,64 +2887,58 @@ ] }, { - "group": "language/literals", + "group": "staging/sm", "kind": "normal", - "durationSec": 70.363, - "filesCount": 25, + "durationSec": 70.267, + "filesCount": 1, "sampleFiles": [ - "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", - "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", - "...", - "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", - "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { - "group": "intl402/DateTimeFormat", + "group": "annexB/built-ins/RegExp", "kind": "normal", - "durationSec": 68.395, - "filesCount": 12, + "durationSec": 63.933, + "filesCount": 25, "sampleFiles": [ - "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", - "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js", + "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", + "test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js", "...", - "test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js", - "test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js" + "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js", + "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js" ] }, { - "group": "staging/sm", + "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 63.85, - "filesCount": 1, + "durationSec": 59.467, + "filesCount": 3, "sampleFiles": [ - "test262/test/staging/sm/Array/toSpliced-dense.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.852, - "filesCount": 5, + "durationSec": 59.46, + "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/IDS_Trinary_Operator.js", - "test262/test/built-ins/RegExp/property-escapes/generated/ID_Continue.js", - "test262/test/built-ins/RegExp/property-escapes/generated/ID_Start.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Ideographic.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Join_Control.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Kaithi.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Kannada.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Katakana.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.712, - "filesCount": 5, + "durationSec": 59.283, + "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Dash.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Default_Ignorable_Code_Point.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Deprecated.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Diacritic.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Emoji.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js" ] } ] From f788706cc1320ab68fed38ad0818171bb4bd7e7a Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 21:46:40 +0200 Subject: [PATCH 05/99] Preserve lexical lifetimes and track actual this-binding instructions --- src/Bytecode/Compiler.php | 14 +- src/Bytecode/JsToPhp.php | 2 +- .../Parts/CompilerBailoutAnalysis.php | 5 + src/Bytecode/Parts/CompilerBlockBindings.php | 180 ++++++++++++++++++ src/Bytecode/Parts/CompilerEmit.php | 3 + src/Bytecode/Parts/CompilerScope.php | 5 +- src/Bytecode/Parts/CompilerStatement.php | 5 +- src/Bytecode/Parts/JsToPhpEligibility.php | 16 +- src/Bytecode/Parts/JsToPhpScope.php | 23 ++- tests/Unit/Bytecode/BlockLifetimeTest.php | 44 +++++ tests/Unit/Bytecode/LexicalThisTest.php | 30 +++ .../Unit/Bytecode/ThisBindingMetadataTest.php | 88 +++++++++ .../Unit/Bytecode/fixtures/block-lifetimes.js | 75 ++++++++ .../Bytecode/fixtures/block-lifetimes.json | 88 +++++++++ tests/Unit/Bytecode/fixtures/lexical-this.js | 22 +++ .../Unit/Bytecode/fixtures/lexical-this.json | 1 + 16 files changed, 585 insertions(+), 16 deletions(-) create mode 100644 src/Bytecode/Parts/CompilerBlockBindings.php create mode 100644 tests/Unit/Bytecode/BlockLifetimeTest.php create mode 100644 tests/Unit/Bytecode/LexicalThisTest.php create mode 100644 tests/Unit/Bytecode/ThisBindingMetadataTest.php create mode 100644 tests/Unit/Bytecode/fixtures/block-lifetimes.js create mode 100644 tests/Unit/Bytecode/fixtures/block-lifetimes.json create mode 100644 tests/Unit/Bytecode/fixtures/lexical-this.js create mode 100644 tests/Unit/Bytecode/fixtures/lexical-this.json diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index a843e1ef..a6f69cd5 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -61,6 +61,7 @@ final class Compiler { use Parts\CompilerBailoutAnalysis; + use Parts\CompilerBlockBindings; use Parts\CompilerScope; use Parts\CompilerEmit; use Parts\CompilerStatement; @@ -103,6 +104,9 @@ final class Compiler /** @var array Captured function-scope bindings and declaration kinds. */ private array $capturedLocals = []; + /** @var array Uncaptured let bindings with proven disjoint block lifetimes. */ + private array $reusableBlockLocals = []; + /** @var list<\Phasis\Ast\Node> */ private array $nestedFns = []; @@ -258,6 +262,9 @@ final class Compiler */ private bool $thisFromFrame = false; + /** Operands can equal LOAD_THIS, so track actual instructions during emission. */ + private bool $hasLoadThis = false; + public function compile(JsFunction $fn): CompiledFunction { $template = CompilationTemplates::get($fn); @@ -349,7 +356,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction // (LOAD_THIS — arrows/generators) or when a nested arrow / // class outer-position lexically references this or super // and will resolve it through the env chain at run time. - $needsEnvThis = in_array(Op::LOAD_THIS, $this->code, true) + $needsEnvThis = $this->hasLoadThis || $this->nestedFnsLexicallyReferenceThis(); $cf = new CompiledFunction( code: $this->code, @@ -372,6 +379,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction // Pre-walk: collect every var/let/const/function name in // the body so each is assigned a unique frame slot up front. + $this->collectReusableBlockBindings($body); $this->collectFunctionLocals($body->body); if ($this->needsArguments && isset($this->localSlots['arguments'])) { throw new CompilerBailout('local arguments binding'); @@ -402,7 +410,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction // See the expression-body site above for the needsThis / // canSkipEnvAlloc semantics under frame-based this. - $needsEnvThis = in_array(Op::LOAD_THIS, $this->code, true) + $needsEnvThis = $this->hasLoadThis || $this->nestedFnsLexicallyReferenceThis(); $cf = new CompiledFunction( code: $this->code, @@ -548,7 +556,7 @@ public function compileProgram(\Phasis\Ast\Program $program): CompiledFunction $this->emit(Op::LOAD_LOCAL, $resultSlot); $this->emit(Op::RET); - $needsThis = in_array(Op::LOAD_THIS, $this->code, true); + $needsThis = $this->hasLoadThis; $cf = new CompiledFunction( code: $this->code, consts: $this->consts, diff --git a/src/Bytecode/JsToPhp.php b/src/Bytecode/JsToPhp.php index f5bee971..d994cc84 100644 --- a/src/Bytecode/JsToPhp.php +++ b/src/Bytecode/JsToPhp.php @@ -252,7 +252,7 @@ private static function compileFunction(JsFunction $fn): ?\Closure // the per-invocation environment that defines those bindings, // so emitting `$env->get('arguments')` would either throw // ReferenceError or read a stale binding from an outer scope. - if (self::bodyReferencesPerCallBindings($body)) { + if (self::bodyReferencesPerCallBindings($body, $fn->isArrow())) { return null; } // Refuse to compile bodies that contain nested block-scoped diff --git a/src/Bytecode/Parts/CompilerBailoutAnalysis.php b/src/Bytecode/Parts/CompilerBailoutAnalysis.php index ef71e87d..3c594643 100644 --- a/src/Bytecode/Parts/CompilerBailoutAnalysis.php +++ b/src/Bytecode/Parts/CompilerBailoutAnalysis.php @@ -434,6 +434,11 @@ private function ensureNoTdzViolations(array $body): void $declOrder = []; $idx = 0; $this->collectLetConstOrder($body, $declOrder, $idx); + // Independent block bindings were checked against each block's own + // declaration, rather than the flat source order used below. + foreach ($this->reusableBlockLocals as $name => $_) { + unset($declOrder[$name]); + } if ($declOrder === []) { return; } diff --git a/src/Bytecode/Parts/CompilerBlockBindings.php b/src/Bytecode/Parts/CompilerBlockBindings.php new file mode 100644 index 00000000..8aaf2031 --- /dev/null +++ b/src/Bytecode/Parts/CompilerBlockBindings.php @@ -0,0 +1,180 @@ +localSlots), true); + $this->collectBlockBindingDeclarations($body, null, $body, $declarations, $disallowed); + foreach ($declarations as $name => $blocks) { + if (isset($disallowed[$name]) || count($blocks) < 2 || count(array_unique($blocks)) !== count($blocks)) { + continue; + } + $initialized = false; + if ($this->blockBindingLifetimeIsIndependent($body, $name, array_fill_keys($blocks, true), null, $initialized)) { + $this->reusableBlockLocals[$name] = true; + } + } + } + + /** + * @param array> $declarations + * @param array $disallowed + */ + private function collectBlockBindingDeclarations( + Node $node, + ?BlockStatement $directBlock, + BlockStatement $functionBody, + array &$declarations, + array &$disallowed, + ): void { + if ($node instanceof FunctionDeclaration || $node instanceof ClassDeclaration) { + if ($node->id !== null) { + $disallowed[$node->id->name] = true; + } + return; + } + if ($node instanceof FunctionExpression || $node instanceof ArrowFunction || $node instanceof ClassExpression) { + return; + } + if ($node instanceof BlockStatement) { + foreach ($node->body as $statement) { + $this->collectBlockBindingDeclarations($statement, $node, $functionBody, $declarations, $disallowed); + } + return; + } + if ($node instanceof VariableDeclaration) { + foreach ($node->declarations as $declaration) { + $names = []; + $this->collectPatternBoundNames($declaration->id, $names); + foreach ($names as $name => $_) { + if ( + $node->kind === 'let' && $declaration->id instanceof Identifier + && $directBlock !== null && $directBlock !== $functionBody + ) { + $declarations[$name][] = spl_object_id($directBlock); + } else { + $disallowed[$name] = true; + } + } + } + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node) { + $this->collectBlockBindingDeclarations($child, null, $functionBody, $declarations, $disallowed); + } + } + } + } + + /** @param array $blocks */ + private function blockBindingLifetimeIsIndependent( + Node $node, + string $name, + array $blocks, + ?int $activeBlock, + bool &$initialized, + ): bool { + if ($node instanceof Identifier) { + return $node->name !== $name || ($activeBlock !== null && $initialized); + } + if ($node instanceof BlockStatement && isset($blocks[spl_object_id($node)])) { + if ($activeBlock !== null) { + return false; + } + $activeBlock = spl_object_id($node); + $blockInitialized = false; + foreach ($node->body as $statement) { + if (!$this->blockBindingLifetimeIsIndependent($statement, $name, $blocks, $activeBlock, $blockInitialized)) { + return false; + } + } + return true; + } + if ( + $node instanceof FunctionDeclaration || $node instanceof FunctionExpression || $node instanceof ArrowFunction + || $node instanceof ClassDeclaration || $node instanceof ClassExpression + ) { + // Even a shadowed use is conservatively excluded here. A fresh + // environment remains necessary for any possible closure capture. + return !$this->blockBindingNameOccurs($node, $name); + } + if ($node instanceof VariableDeclaration) { + foreach ($node->declarations as $declaration) { + if ( + $declaration->init !== null + && !$this->blockBindingLifetimeIsIndependent($declaration->init, $name, $blocks, $activeBlock, $initialized) + ) { + return false; + } + if ($declaration->id instanceof Identifier) { + if ($declaration->id->name === $name) { + if ($activeBlock === null || $initialized) { + return false; + } + $initialized = true; + } + } elseif ($this->blockBindingNameOccurs($declaration->id, $name)) { + return false; + } + } + return true; + } + if ($node instanceof MemberExpression && !$node->computed) { + return $this->blockBindingLifetimeIsIndependent($node->object, $name, $blocks, $activeBlock, $initialized); + } + if ($node instanceof Property && !$node->computed) { + return $this->blockBindingLifetimeIsIndependent($node->value, $name, $blocks, $activeBlock, $initialized); + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ( + $child instanceof Node + && !$this->blockBindingLifetimeIsIndependent($child, $name, $blocks, $activeBlock, $initialized) + ) { + return false; + } + } + } + return true; + } + + private function blockBindingNameOccurs(Node $node, string $name): bool + { + if ($node instanceof Identifier && $node->name === $name) { + return true; + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node && $this->blockBindingNameOccurs($child, $name)) { + return true; + } + } + } + return false; + } +} diff --git a/src/Bytecode/Parts/CompilerEmit.php b/src/Bytecode/Parts/CompilerEmit.php index c347233e..1c287ab2 100644 --- a/src/Bytecode/Parts/CompilerEmit.php +++ b/src/Bytecode/Parts/CompilerEmit.php @@ -60,6 +60,9 @@ trait CompilerEmit { private function emit(int $op, int ...$operands): void { + if ($op === Op::LOAD_THIS) { + $this->hasLoadThis = true; + } $this->code[] = $op; foreach ($operands as $o) { $this->code[] = $o; diff --git a/src/Bytecode/Parts/CompilerScope.php b/src/Bytecode/Parts/CompilerScope.php index 3c4a8d9a..dd157f8a 100644 --- a/src/Bytecode/Parts/CompilerScope.php +++ b/src/Bytecode/Parts/CompilerScope.php @@ -343,7 +343,10 @@ private function collectStatementLocals(Node $stmt): void // earlier var) would need separate slot allocation // per scope, which the flat-slot compiler doesn't // model. Bail. - if ($isLexical && isset($this->localSlots[$decl->id->name])) { + if ( + $isLexical && isset($this->localSlots[$decl->id->name]) + && !isset($this->reusableBlockLocals[$decl->id->name]) + ) { throw new CompilerBailout('let/const shadowing existing local'); } if (!$isLexical) { diff --git a/src/Bytecode/Parts/CompilerStatement.php b/src/Bytecode/Parts/CompilerStatement.php index 635d6b28..e593042d 100644 --- a/src/Bytecode/Parts/CompilerStatement.php +++ b/src/Bytecode/Parts/CompilerStatement.php @@ -691,7 +691,10 @@ private function compileVarDecl(VariableDeclaration $node): void if ($node->kind === 'const') { throw new CompilerBailout('const without initializer'); } - if ($node->kind === 'let' && isset($this->capturedLocals[$name])) { + if ( + $node->kind === 'let' + && (isset($this->capturedLocals[$name]) || isset($this->reusableBlockLocals[$name])) + ) { $this->emit(Op::LOAD_UNDEF); $this->emitInitializeLocal($slot, $node->kind); } diff --git a/src/Bytecode/Parts/JsToPhpEligibility.php b/src/Bytecode/Parts/JsToPhpEligibility.php index 8c75efd6..2f06dd6c 100644 --- a/src/Bytecode/Parts/JsToPhpEligibility.php +++ b/src/Bytecode/Parts/JsToPhpEligibility.php @@ -427,16 +427,17 @@ private static function exprHasTailCall(Node $node): bool return false; } - private static function bodyReferencesPerCallBindings(Node $node): bool + private static function bodyReferencesPerCallBindings(Node $node, bool $lexicalThis): bool { if ($node instanceof Identifier) { // 'super' / 'arguments' / 'new.target' — all per-call. return $node->name === 'arguments' || $node->name === 'super'; } - // ThisExpression is allowed: the compiled closure now accepts - // an explicit `$thisValue` parameter that emit binds to PHP - // `$thisValue`, so `this` reads in the body resolve to it - // directly rather than walking the closure env. + // The emitted receiver is the call's receiver. Lexical this needs + // the defining activation, including when a nested arrow captures it. + if ($node instanceof \Phasis\Ast\Expression\ThisExpression) { + return $lexicalThis; + } if ($node instanceof \Phasis\Ast\Expression\MetaProperty) { return true; } @@ -449,6 +450,7 @@ private static function bodyReferencesPerCallBindings(Node $node): bool ) { return false; } + $lexicalThis = $lexicalThis || $node instanceof \Phasis\Ast\Expression\ArrowFunction; // ArrowFunction bodies CAN see the outer arguments / this, // but we already bail on outer-local capture in // checkNestedCaptures; arguments isn't in declaredLocals so @@ -456,14 +458,14 @@ private static function bodyReferencesPerCallBindings(Node $node): bool // bodies too. foreach ((array) $node as $value) { if ($value instanceof Node) { - if (self::bodyReferencesPerCallBindings($value)) { + if (self::bodyReferencesPerCallBindings($value, $lexicalThis)) { return true; } continue; } if (is_array($value)) { foreach ($value as $item) { - if ($item instanceof Node && self::bodyReferencesPerCallBindings($item)) { + if ($item instanceof Node && self::bodyReferencesPerCallBindings($item, $lexicalThis)) { return true; } } diff --git a/src/Bytecode/Parts/JsToPhpScope.php b/src/Bytecode/Parts/JsToPhpScope.php index 26493176..de5f4e93 100644 --- a/src/Bytecode/Parts/JsToPhpScope.php +++ b/src/Bytecode/Parts/JsToPhpScope.php @@ -35,6 +35,23 @@ */ trait JsToPhpScope { + /** @var array Lexical bindings cannot alias another PHP local. */ + private array $lexicalLocalNames = []; + + private function registerLocalBinding(string $name, string $kind): void + { + if ( + isset($this->lexicalLocalNames[$name]) + || ($kind !== 'var' && isset($this->declaredLocals[$name])) + ) { + throw new Bailout('lexical binding shadows another local'); + } + if ($kind !== 'var') { + $this->lexicalLocalNames[$name] = true; + } + $this->declaredLocals[$name] = true; + } + /** * @param Node[] $statements */ @@ -54,7 +71,7 @@ private function collectLocalsIn(Node $node): void throw new Bailout('anonymous function declaration'); } $name = $node->id->name; - $this->declaredLocals[$name] = true; + $this->registerLocalBinding($name, 'var'); $this->markLocalAsFunction($name); return; } @@ -82,7 +99,7 @@ private function collectLocalsIn(Node $node): void if (!$prop->value instanceof Identifier) { throw new Bailout('non-identifier pattern target'); } - $this->declaredLocals[$prop->value->name] = true; + $this->registerLocalBinding($prop->value->name, $node->kind); } continue; } @@ -90,7 +107,7 @@ private function collectLocalsIn(Node $node): void throw new Bailout('non-identifier var'); } $name = $decl->id->name; - $this->declaredLocals[$name] = true; + $this->registerLocalBinding($name, $node->kind); if ($node->kind === 'const') { $this->constLocals[$name] = true; } diff --git a/tests/Unit/Bytecode/BlockLifetimeTest.php b/tests/Unit/Bytecode/BlockLifetimeTest.php new file mode 100644 index 00000000..fd15a213 --- /dev/null +++ b/tests/Unit/Bytecode/BlockLifetimeTest.php @@ -0,0 +1,44 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/block-lifetimes.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/block-lifetimes.json', + $engine->eval('JSON.stringify(blockLifetimeResult)'), + ); + foreach (['siblings', 'branches', 'looping', 'abrupt'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise bytecode.'); + } + foreach (['leaked', 'closures', 'nested', 'parameter', 'hoisted', 'beforeInit', 'selfInit', 'constMix'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled, $name . ' requires the lexical environment path.'); + self::assertNull($function->phpCompiled, $name . ' must also preserve lexical scopes in PHP compilation.'); + } + } + + public function testInterpreterMatchesTheSameNodeOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/block-lifetimes.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/block-lifetimes.json', + $engine->eval('JSON.stringify(blockLifetimeResult)'), + ); + } +} diff --git a/tests/Unit/Bytecode/LexicalThisTest.php b/tests/Unit/Bytecode/LexicalThisTest.php new file mode 100644 index 00000000..4c76aebb --- /dev/null +++ b/tests/Unit/Bytecode/LexicalThisTest.php @@ -0,0 +1,30 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/lexical-this.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/lexical-this.json', + $engine->eval('JSON.stringify(lexicalThisResult)'), + ); + foreach (['direct', 'capture', 'captureBlock', 'nestedCapture', 'first', 'second', 'block', 'nested'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->phpCompiled, $name . ' must preserve its lexical this binding.'); + } + $ordinary = $engine->getGlobalEnv()->get('ordinary'); + self::assertInstanceOf(JsFunction::class, $ordinary); + self::assertNotNull($ordinary->phpCompiled, 'Ordinary receiver reads remain eligible for PHP emission.'); + } +} diff --git a/tests/Unit/Bytecode/ThisBindingMetadataTest.php b/tests/Unit/Bytecode/ThisBindingMetadataTest.php new file mode 100644 index 00000000..0b210d9c --- /dev/null +++ b/tests/Unit/Bytecode/ThisBindingMetadataTest.php @@ -0,0 +1,88 @@ + 'p' . $index . '=' . $index, range(0, 15)); + $source = 'var ' . implode(', ', $declarations) . '; p15;'; + $compiled = (new Compiler())->compileProgram((new Parser($source))->parse()); + self::assertContains(Op::LOAD_THIS, $compiled->code); + self::assertFalse($compiled->needsThis); + self::assertSame(15, (new Engine())->eval($source)); + + $compiled = (new Compiler())->compileProgram((new Parser('this;'))->parse()); + self::assertTrue($compiled->needsThis); + self::assertTrue((new Engine())->eval('this === globalThis')); + } + + public function testAnOperandMatchingLoadThisDoesNotRequireAnEnvironmentBinding(): void + { + $engine = new Engine(); + $parameters = implode(', ', array_map(static fn (int $index): string => 'p' . $index, range(0, 15))); + $arguments = implode(', ', range(0, 15)); + $engine->eval("function ordinary({$parameters}) { return p15; }\n" + . "const expression = ({$parameters}) => p15;\n"); + + foreach (['ordinary', 'expression'] as $name) { + $compiled = $this->compiled($engine, $name); + self::assertSame(15, $engine->eval("{$name}({$arguments})")); + self::assertContains(Op::LOAD_THIS, $compiled->code, 'The fixture must contain the colliding operand.'); + self::assertFalse($compiled->needsThis); + self::assertTrue($compiled->canSkipEnvAlloc); + } + } + + public function testLexicalThisAndNestedArrowCapturesKeepTheirEnvironmentBinding(): void + { + $engine = new Engine(); + $engine->eval(<<<'JS' +globalThis.value = 17; +const owner = {value: 41}; +function capture() { return () => this.value; } +const direct = () => this.value; +function ordinary() { return this.value; } +function* generator() { yield this.value; return this.value; } +JS); + foreach (['capture', 'direct', 'ordinary', 'generator'] as $name) { + $this->compiled($engine, $name); + } + $engine->eval('const reader = capture.call(owner);'); + $this->compiled($engine, 'reader'); + self::assertSame([41, 17, 41, 41, 41], $engine->eval(<<<'JS' +const iterator = generator.call(owner); +[reader.call({value: 99}), direct.call({value: 99}), ordinary.call(owner), + iterator.next().value, iterator.next().value]; +JS)); + + foreach (['capture', 'reader', 'direct', 'generator'] as $name) { + $compiled = $this->compiled($engine, $name); + self::assertTrue($compiled->needsThis, $name); + self::assertFalse($compiled->canSkipEnvAlloc, $name); + } + $ordinary = $this->compiled($engine, 'ordinary'); + self::assertFalse($ordinary->needsThis); + self::assertTrue($ordinary->canSkipEnvAlloc); + } + + private function compiled(Engine $engine, string $name): CompiledFunction + { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + $function->compiled ??= (new Compiler())->compile($function); + + return $function->compiled; + } +} diff --git a/tests/Unit/Bytecode/fixtures/block-lifetimes.js b/tests/Unit/Bytecode/fixtures/block-lifetimes.js new file mode 100644 index 00000000..37b66756 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/block-lifetimes.js @@ -0,0 +1,75 @@ +function siblings(seed) { + const output = []; + { let value = seed; value++; output.push(value); } + { let value; output.push(value); value = seed * 2; output.push(value); } + return output; +} +function branches(flag, seed) { + const output = []; + if (flag) { let value = seed; if (value) output.push(value); } + else { let value = seed + 1; output.push(value); } + { let value = seed + 2; output.push(value); } + return output; +} +function looping(count) { + const output = []; + for (let index = 0; index < count; index++) { + { let value = index; if (value % 2) continue; output.push(value); } + { let value = index + 10; output.push(value); } + } + return output; +} +function abrupt(seed) { + const output = []; + try { let value = seed; output.push(value); throw new Error('stop'); } + catch (error) { output.push(error.message); } + finally { let value = seed + 1; output.push(value); } + return output; +} +function leaked() { + { let value = 1; } + { let value = 2; } + return typeof value; +} +function closures() { + let first; + { let value = 1; first = () => value; } + { let value = 2; return [first(), value]; } +} +function nested() { + const output = []; + { let value = 1; { let value = 2; output.push(value); } output.push(value); } + { let value = 3; output.push(value); } + return output; +} +function parameter(value) { + { let value = 1; } + { let value = 2; } + return value; +} +function hoisted() { + { let value = 1; } + { let value = 2; } + var value = 9; + return value; +} +function beforeInit() { + const output = []; + { try { output.push(value); } catch (error) { output.push(error.name); } let value = 1; output.push(value); } + { let value = 2; output.push(value); } + return output; +} +function selfInit() { + { let value = 1; } + { let value = value; return value; } +} +function constMix() { + { let value = 1; } + { const value = 2; return value; } +} +const blockLifetimeResult = []; +for (let pass = 0; pass < 2; pass++) { + blockLifetimeResult.push(siblings(pass + 1), branches(true, pass + 1), branches(false, pass + 1), + looping(4), abrupt(pass), leaked(), closures(), nested(), parameter(8), hoisted(), beforeInit(), constMix()); + try { selfInit(); } catch (error) { blockLifetimeResult.push(error.name); } +} diff --git a/tests/Unit/Bytecode/fixtures/block-lifetimes.json b/tests/Unit/Bytecode/fixtures/block-lifetimes.json new file mode 100644 index 00000000..834bd5d0 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/block-lifetimes.json @@ -0,0 +1,88 @@ +[ + [ + 2, + null, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 0, + 10, + 2, + 12 + ], + [ + 0, + "stop", + 1 + ], + "undefined", + [ + 1, + 2 + ], + [ + 2, + 1, + 3 + ], + 8, + 9, + [ + "ReferenceError", + 1, + 2 + ], + 2, + "ReferenceError", + [ + 3, + null, + 4 + ], + [ + 2, + 4 + ], + [ + 3, + 4 + ], + [ + 0, + 10, + 2, + 12 + ], + [ + 1, + "stop", + 2 + ], + "undefined", + [ + 1, + 2 + ], + [ + 2, + 1, + 3 + ], + 8, + 9, + [ + "ReferenceError", + 1, + 2 + ], + 2, + "ReferenceError" +] diff --git a/tests/Unit/Bytecode/fixtures/lexical-this.js b/tests/Unit/Bytecode/fixtures/lexical-this.js new file mode 100644 index 00000000..c98447f7 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/lexical-this.js @@ -0,0 +1,22 @@ +globalThis.value = 17; +var owner = {value: 41}; +var other = {value: 99}; +var direct = () => this.value; +function capture() { return () => this.value; } +function captureBlock() { const read = () => this.value; return read; } +function nestedCapture() { return () => () => this.value; } +function ordinary() { return this.value; } +var first = capture.call(owner); +var second = capture.call(other); +var block = captureBlock.call(owner); +var nested = nestedCapture.call(owner)(); +var observations = []; +for (var round = 0; round < 4; round++) { + observations.push([ + direct.call(other), direct.apply(other), direct.bind(other)(), + first.call(other), first.apply(other), first.bind(other)(), + Reflect.apply(first, other, []), second.call(owner), + block.call(other), nested.call(other), ordinary.call(owner), ordinary.call(other) + ]); +} +globalThis.lexicalThisResult = observations; diff --git a/tests/Unit/Bytecode/fixtures/lexical-this.json b/tests/Unit/Bytecode/fixtures/lexical-this.json new file mode 100644 index 00000000..4ad073aa --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/lexical-this.json @@ -0,0 +1 @@ +[[17,17,17,41,41,41,41,99,41,41,41,99],[17,17,17,41,41,41,41,99,41,41,41,99],[17,17,17,41,41,41,41,99,41,41,41,99],[17,17,17,41,41,41,41,99,41,41,41,99]] From d9cba683d389e0512ef84f64235a1b89c3919fdd Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 21:46:40 +0200 Subject: [PATCH 06/99] Compare filesystem link targets after resolving host aliases --- tests/Unit/Node/fixtures/primitives/fs.cjs | 3 ++- tests/Unit/Node/fixtures/primitives/fs.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Node/fixtures/primitives/fs.cjs b/tests/Unit/Node/fixtures/primitives/fs.cjs index 4a3dfae0..6a7fe892 100644 --- a/tests/Unit/Node/fixtures/primitives/fs.cjs +++ b/tests/Unit/Node/fixtures/primitives/fs.cjs @@ -48,7 +48,8 @@ require('./helpers.cjs').run(async () => { fs.writeFileSync(path.join(child, 'a'), 'A'); fs.symlinkSync('bytes', path.join(directory, 'link')); fs.linkSync(file, path.join(directory, 'hard')); - output.push(['links', fs.lstatSync(path.join(directory, 'link')).isSymbolicLink(), fs.readlinkSync(path.join(directory, 'link')), fs.realpathSync(path.join(directory, 'link')) === file, fs.statSync(path.join(directory, 'hard')).ino === fs.statSync(file).ino]); + // The temporary directory itself can be reached through a host symlink. + output.push(['links', fs.lstatSync(path.join(directory, 'link')).isSymbolicLink(), fs.readlinkSync(path.join(directory, 'link')), fs.realpathSync(path.join(directory, 'link')) === fs.realpathSync(file), fs.statSync(path.join(directory, 'hard')).ino === fs.statSync(file).ino]); output.push(['directory', fs.readdirSync(directory, { withFileTypes: true }).map(entry => [entry.name, entry.isDirectory(), entry.isSymbolicLink(), entry.parentPath === directory])]); fs.copyFileSync(file, path.join(directory, 'copy')); fs.renameSync(path.join(directory, 'copy'), path.join(directory, 'renamed')); diff --git a/tests/Unit/Node/fixtures/primitives/fs.json b/tests/Unit/Node/fixtures/primitives/fs.json index 2e38f047..e588ac7d 100644 --- a/tests/Unit/Node/fixtures/primitives/fs.json +++ b/tests/Unit/Node/fixtures/primitives/fs.json @@ -76,7 +76,7 @@ "links", true, "bytes", - false, + true, true ], [ From 088a983d402230c36c7c7440ae8a64d6271bb950 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 21:44:41 +0200 Subject: [PATCH 07/99] fix: release deep WeakMap value chains iteratively --- src/Value/JsWeakMap.php | 6 +-- src/Value/WeakMapValue.php | 47 ++++++++++++++++++++++ tests/Unit/BuiltIn/WeakMapLifetimeTest.php | 34 ++++++++++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/Value/WeakMapValue.php diff --git a/src/Value/JsWeakMap.php b/src/Value/JsWeakMap.php index 54b6a677..4b1184c1 100644 --- a/src/Value/JsWeakMap.php +++ b/src/Value/JsWeakMap.php @@ -15,7 +15,7 @@ */ class JsWeakMap extends JsObject { - /** @var \WeakMap */ + /** @var \WeakMap */ private \WeakMap $values; public function __construct(?JsObject $prototype = null) @@ -29,7 +29,7 @@ public function weakMapGet(JsValue $key): JsValue if (!$key instanceof JsObject && !$key instanceof JsSymbol) { return JsUndefined::instance(); } - return $this->values[$key] ?? JsUndefined::instance(); + return $this->values[$key]->value ?? JsUndefined::instance(); } public function weakMapSet(JsValue $key, JsValue $value): void @@ -41,7 +41,7 @@ public function weakMapSet(JsValue $key, JsValue $value): void ) { throw new \Phasis\Exceptions\TypeError('Invalid value used as weak map key'); } - $this->values[$key] = $value; + $this->values[$key] = new WeakMapValue($value); } public function weakMapHas(JsValue $key): bool diff --git a/src/Value/WeakMapValue.php b/src/Value/WeakMapValue.php new file mode 100644 index 00000000..7e0d2892 --- /dev/null +++ b/src/Value/WeakMapValue.php @@ -0,0 +1,47 @@ + */ + private static array $pending = []; + + private static bool $draining = false; + + public function __construct(public ?JsValue $value) + { + } + + public function __destruct() + { + if ($this->value === null) { + return; + } + + self::$pending[] = $this->value; + $this->value = null; + if (self::$draining) { + return; + } + + self::$draining = true; + try { + while (self::$pending !== []) { + $value = array_pop(self::$pending); + unset($value); + } + } finally { + self::$draining = false; + } + } +} diff --git a/tests/Unit/BuiltIn/WeakMapLifetimeTest.php b/tests/Unit/BuiltIn/WeakMapLifetimeTest.php index 89b6a188..3121c7bf 100644 --- a/tests/Unit/BuiltIn/WeakMapLifetimeTest.php +++ b/tests/Unit/BuiltIn/WeakMapLifetimeTest.php @@ -9,10 +9,44 @@ use Phasis\Value\JsSymbol; use Phasis\Value\JsUndefined; use Phasis\Value\JsWeakMap; +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; use PHPUnit\Framework\TestCase; final class WeakMapLifetimeTest extends TestCase { + #[RunInSeparateProcess] + #[PreserveGlobalState(false)] + public function testDeepWeakKeyChainsReleaseWithoutNativeStackOverflow(): void + { + if (function_exists('posix_setrlimit')) { + posix_setrlimit(POSIX_RLIMIT_CORE, 0, 0); + } + $map = new JsWeakMap(); + $head = new JsObject(); + $key = $head; + $references = [\WeakReference::create($head)]; + for ($index = 0; $index < 99999; $index++) { + $next = new JsObject(); + $map->weakMapSet($key, $next); + $key = $next; + if ($index === 50000 || $index === 99998) { + $references[] = \WeakReference::create($key); + } + } + unset($key, $next); + gc_collect_cycles(); + foreach ($references as $reference) { + self::assertTrue($reference->get() !== null, 'The live head must keep the complete chain reachable.'); + } + + unset($head); + foreach ($references as $reference) { + self::assertTrue($reference->get() === null, 'Releasing the head must release the complete chain.'); + } + self::assertInstanceOf(JsUndefined::class, $map->weakMapGet(new JsObject())); + } + public function testValuesAndKeysCanCollectTogetherWhileTheMapRemainsAlive(): void { $map = new JsWeakMap(); From ef390db5f8c2930cb7d15faa786a7f8b618c66f2 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 21:52:38 +0200 Subject: [PATCH 08/99] perf: defer ordinary function prototype allocation --- src/Bytecode/VM.php | 20 +- src/Runtime/Parts/ExpressionEvaluation.php | 22 +- src/Spec/AbstractOperations.php | 7 +- src/Value/JsFunction.php | 77 ++++++- .../Runtime/LazyFunctionPrototypeTest.php | 156 +++++++++++++ .../lazy-function-prototype.expected.json | 213 ++++++++++++++++++ .../fixtures/lazy-function-prototype.js | 140 ++++++++++++ 7 files changed, 612 insertions(+), 23 deletions(-) create mode 100644 tests/Unit/Runtime/LazyFunctionPrototypeTest.php create mode 100644 tests/Unit/Runtime/fixtures/lazy-function-prototype.expected.json create mode 100644 tests/Unit/Runtime/fixtures/lazy-function-prototype.js diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index e578aa58..35a11247 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -1904,17 +1904,19 @@ public function execute( } } if ($newInlineable) { - // Inline the dataSlots-fast-path of - // $callee->get('prototype'): regular - // function instances always carry - // `prototype` as an own data slot, - // so the hit lands in one array - // lookup with no method dispatch. - // Fall back to the spec getter only - // if the slot was deleted (rare). + // Default-attribute slots can be read directly. + // Other descriptors go through [[Get]], including + // deferred ordinary function prototypes. $proto = $callee->properties->dataSlots['prototype'] ?? $callee->get('prototype'); - $newObj = new JsObject($proto instanceof JsObject ? $proto : null); + if (!$proto instanceof JsObject) { + $realm = AbstractOperations::getFunctionRealm($callee); + $proto = $realm === null ? null : AbstractOperations::realmIntrinsicPrototype( + $realm->getGlobalEnv(), + 'Object', + ); + } + $newObj = new JsObject($proto); // Skip the [[NewTarget]] install // for function bodies that don't // read new.target / super(). The diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index cbf76b12..8b466d88 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -3292,7 +3292,11 @@ private function evalNewExpression(NewExpression $node, Environment $env): JsVal // Create a new object with the constructor's prototype $proto = $callee->get('prototype'); - $newObj = new JsObject($proto instanceof JsObject ? $proto : null); + if (!$proto instanceof JsObject) { + $realm = AbstractOperations::getFunctionRealm($callee); + $proto = $realm === null ? null : AbstractOperations::realmIntrinsicPrototype($realm->getGlobalEnv(), 'Object'); + } + $newObj = new JsObject($proto); // Mark as new.target so constructors can detect new vs call. // Use a non-enumerable, non-configurable property so it does not leak into iteration. $newObj->defineOwnProperty( @@ -3936,7 +3940,7 @@ private function callFunctionInner( /** * Install the .prototype property on a newly created function. * - * For normal functions: creates {constructor: fn} with Object.prototype as prototype. + * Normal functions defer their {constructor: fn} object until its value is read. * For generator functions: creates a plain object with %GeneratorPrototype% as prototype, * NO constructor property (per spec §27.3.4). */ @@ -3962,6 +3966,7 @@ private function installFunctionPrototype(JsFunction $fn, bool $isGenerator, boo $proto = new JsObject($generatorProto); // Non-constructable: generators can't be called with new. $fn->setNonConstructable(); + $fn->defineOwnProperty('prototype', PropertyDescriptor::data($proto, true, false, false)); } else { // Resolve %Object.prototype% for THIS realm so a sibling // Engine cannot leak its Object.prototype through the @@ -3977,13 +3982,8 @@ private function installFunctionPrototype(JsFunction $fn, bool $isGenerator, boo $objProto = $candidate; } } - $proto = new JsObject($objProto); - // Per spec, constructor is writable, non-enumerable, configurable. - $proto->defineOwnProperty('constructor', PropertyDescriptor::data($fn, true, false, true)); + $fn->installOrdinaryPrototype($objProto); } - // Per spec §27.3.4 / §10.2.4: .prototype is writable, non-enumerable, non-configurable for generators; - // writable, non-enumerable, non-configurable for regular functions too. - $fn->defineOwnProperty('prototype', PropertyDescriptor::data($proto, true, false, false)); // Annex B legacy `function.caller` / `function.arguments`: install // own slots (default null) on non-strict, non-arrow, non-async, @@ -6020,7 +6020,11 @@ public function vmNewExpression(JsValue $callee, array $args, Environment $env): // initializers, derived-constructor checks, and the // [[NewTarget]] cleanup all match the tree-walker exactly. $proto = $callee->get('prototype'); - $newObj = new JsObject($proto instanceof JsObject ? $proto : null); + if (!$proto instanceof JsObject) { + $realm = AbstractOperations::getFunctionRealm($callee); + $proto = $realm === null ? null : AbstractOperations::realmIntrinsicPrototype($realm->getGlobalEnv(), 'Object'); + } + $newObj = new JsObject($proto); $newObj->defineOwnProperty( '[[NewTarget]]', \Phasis\Object\PropertyDescriptor::data($callee, false, false, false), diff --git a/src/Spec/AbstractOperations.php b/src/Spec/AbstractOperations.php index bd015f51..a01d7715 100644 --- a/src/Spec/AbstractOperations.php +++ b/src/Spec/AbstractOperations.php @@ -115,11 +115,10 @@ public static function realmIntrinsicPrototype( \Phasis\Runtime\Environment $globalEnv, string $constructorName, ): ?JsObject { - // Map well-known constructor names that are not exposed as - // globals to their per-realm prototype slot. Each entry maps the - // constructor's [[Name]] to the reserved env binding holding - // realm's %ConstructorName.prototype% intrinsic. + // Retained intrinsics must win over mutable constructor globals. + // This also covers function constructors that have no named global. static $hiddenIntrinsics = [ + 'Object' => '__ObjectPrototype__', 'AsyncFunction' => '__AsyncFunctionPrototype__', 'GeneratorFunction' => '__GeneratorFunctionPrototype__', 'AsyncGeneratorFunction' => '__AsyncGeneratorFunctionPrototype__', diff --git a/src/Value/JsFunction.php b/src/Value/JsFunction.php index ff0385bb..87cfef8d 100644 --- a/src/Value/JsFunction.php +++ b/src/Value/JsFunction.php @@ -42,6 +42,56 @@ public static function getInterpreterInstance(): ?\Phasis\Runtime\Interpreter /** %AsyncGeneratorFunction.prototype% intrinsic. */ private static ?JsObject $asyncGeneratorFunctionPrototype = null; + /** An internal value that never escapes through JavaScript property reads. */ + private static ?JsObject $uninitializedOrdinaryPrototype = null; + + /** The defining realm's intrinsic, independent of later global Object assignments. */ + private ?JsObject $ordinaryPrototypeParent = null; + + /** + * Install the ordinary constructor's data property without creating the + * function/prototype/constructor cycle until its value is observed. + */ + public function installOrdinaryPrototype(?JsObject $objectPrototype): void + { + self::$uninitializedOrdinaryPrototype ??= JsObject::createNullPrototype(); + $this->ordinaryPrototypeParent = $objectPrototype ?? JsObject::getGlobalPrototype(); + $this->defineOwnProperty('prototype', \Phasis\Object\PropertyDescriptor::data( + self::$uninitializedOrdinaryPrototype, + true, + false, + false, + )); + } + + private function materializeOrdinaryPrototype(): void + { + $descriptor = $this->properties->descriptors['prototype'] ?? null; + if ( + self::$uninitializedOrdinaryPrototype === null + || $descriptor === null + || $descriptor->value !== self::$uninitializedOrdinaryPrototype + ) { + return; + } + + $prototype = $this->ordinaryPrototypeParent === null + ? JsObject::createNullPrototype() + : new JsObject($this->ordinaryPrototypeParent); + $prototype->defineOwnProperty('constructor', \Phasis\Object\PropertyDescriptor::data( + $this, + true, + false, + true, + )); + // Partial descriptor updates may already have frozen the property. + // Realization changes its representation, not its observable attributes. + $descriptor->value = $prototype; + $this->ordinaryPrototypeParent = null; + $this->properties->version++; + $this->properties->mutationVersion++; + } + public static function setFunctionPrototype(JsObject $proto): void { self::$functionPrototype = $proto; @@ -662,11 +712,36 @@ protected function getWithReceiver(string $name, JsObject $receiver): JsValue return $live; } } - return parent::getWithReceiver($name, $receiver); + return $this->getWithValueReceiver($name, $receiver); + } + + public function getWithValueReceiver(string $name, JsValue $receiver): JsValue + { + if ($name === 'prototype') { + $this->materializeOrdinaryPrototype(); + } + return parent::getWithValueReceiver($name, $receiver); + } + + public function getOwnPropertyDescriptorRaw(string $name): ?\Phasis\Object\PropertyDescriptor + { + if ($name === 'prototype') { + $this->materializeOrdinaryPrototype(); + } + return parent::getOwnPropertyDescriptorRaw($name); + } + + public function getProperties(): \Phasis\Object\PropertyMap + { + $this->materializeOrdinaryPrototype(); + return parent::getProperties(); } public function getOwnPropertyDescriptor(string $name): ?\Phasis\Object\PropertyDescriptor { + if ($name === 'prototype') { + $this->materializeOrdinaryPrototype(); + } if ($name === 'caller' || $name === 'arguments') { $live = $this->liveAnnexBValue($name); if ($live !== null) { diff --git a/tests/Unit/Runtime/LazyFunctionPrototypeTest.php b/tests/Unit/Runtime/LazyFunctionPrototypeTest.php new file mode 100644 index 00000000..91970e8d --- /dev/null +++ b/tests/Unit/Runtime/LazyFunctionPrototypeTest.php @@ -0,0 +1,156 @@ + */ + public static function executionModes(): iterable + { + yield 'bytecode' => [false]; + yield 'interpreter' => [true]; + } + + #[DataProvider('executionModes')] + public function testPrototypeObservationsMatchNode(bool $interpret): void + { + $source = file_get_contents(__DIR__ . '/fixtures/lazy-function-prototype.js'); + $oracle = file_get_contents(__DIR__ . '/fixtures/lazy-function-prototype.expected.json'); + self::assertIsString($source); + self::assertIsString($oracle); + $engine = new Engine(); + if ($interpret) { + $engine->setExecutionBudget(1_000_000); + } + + // The fixture snapshot is generated by Node v26.12.0. + self::assertSame(json_decode($oracle, true, flags: JSON_THROW_ON_ERROR), $engine->eval($source)); + } + + public function testUnobservedPrototypeDoesNotRequireCycleCollection(): void + { + $engine = new Engine(); + $engine->eval('function factory() { return function () { return 1; }; } factory(); factory();'); + gc_collect_cycles(); + $wasEnabled = gc_enabled(); + gc_disable(); + $runs = gc_status()['runs']; + + try { + foreach (['function () {}', 'factory()'] as $expression) { + $engine->eval('void (globalThis.temporary = ' . $expression . ');'); + $function = $engine->getGlobalEnv()->get('temporary'); + self::assertInstanceOf(JsFunction::class, $function); + $reference = \WeakReference::create($function); + self::assertTrue($function->hasOwnProperty('prototype')); + self::assertContains('prototype', $function->getOwnPropertyNames()); + $engine->setGlobalJsValue('temporary', JsUndefined::instance()); + unset($function); + + self::assertTrue($reference->get() === null, 'An unobserved prototype must not create a cycle.'); + } + self::assertSame($runs, gc_status()['runs']); + } finally { + if ($wasEnabled) { + gc_enable(); + } + } + } + + public function testAnEscapedPrototypeKeepsItsConstructorAlive(): void + { + $engine = new Engine(); + $engine->eval('void (globalThis.temporary = function () {});'); + $function = $engine->getGlobalEnv()->get('temporary'); + self::assertInstanceOf(JsFunction::class, $function); + $reference = \WeakReference::create($function); + $prototype = $function->get('prototype'); + self::assertInstanceOf(JsObject::class, $prototype); + $engine->setGlobalJsValue('temporary', JsUndefined::instance()); + unset($function); + gc_collect_cycles(); + + self::assertTrue($reference->get() !== null, 'The constructor property must retain its function strongly.'); + self::assertSame($reference->get(), $prototype->get('constructor')); + unset($prototype); + gc_collect_cycles(); + self::assertTrue($reference->get() === null, 'The materialized cycle must remain collectable.'); + } + + public function testRawDescriptorCopyContainsTheRealPrototype(): void + { + $engine = new Engine(); + $engine->eval('void (globalThis.temporary = function () {});'); + $function = $engine->getGlobalEnv()->get('temporary'); + self::assertInstanceOf(JsFunction::class, $function); + $descriptor = $function->getOwnPropertyDescriptorRaw('prototype'); + self::assertNotNull($descriptor); + $prototype = $descriptor->value; + self::assertInstanceOf(JsObject::class, $prototype); + self::assertSame($function, $prototype->get('constructor')); + self::assertSame($prototype, $function->get('prototype')); + } + + public function testPublicPropertyMapContainsTheRealPrototype(): void + { + $engine = new Engine(); + $engine->eval('void (globalThis.temporary = function () {});'); + $function = $engine->getGlobalEnv()->get('temporary'); + self::assertInstanceOf(JsFunction::class, $function); + $descriptor = $function->getProperties()->get('prototype'); + self::assertNotNull($descriptor); + $prototype = $descriptor->value; + self::assertInstanceOf(JsObject::class, $prototype); + self::assertSame($function, $prototype->get('constructor')); + self::assertSame($prototype, $function->get('prototype')); + } + + #[DataProvider('executionModes')] + public function testMaterializationUsesTheDefiningRealmIntrinsic(bool $interpret): void + { + $engine = new Engine(node: true); + if ($interpret) { + $engine->setExecutionBudget(1_000_000); + } + self::assertSame(array_fill(0, 18, true), $engine->eval(<<<'JS' +const vm = require('node:vm'); +const sandbox = vm.createContext({}); +const foreign = vm.runInContext('(function Foreign() {})', sandbox); +const foreignObjectPrototype = vm.runInContext('Object.prototype', sandbox); +vm.runInContext('Object = function Replacement() {}', sandbox); +const firstRead = Reflect.get(new Proxy(foreign, {}), 'prototype', 17); +const observations = [ + Object.getPrototypeOf(firstRead) === foreignObjectPrototype, + Object.getPrototypeOf(firstRead) !== Object.prototype, + firstRead.constructor === foreign, + Object.getPrototypeOf(new foreign()) === firstRead, + Object.getOwnPropertyDescriptor(foreign, 'prototype').value === firstRead +]; +function construct(Constructor) { return new Constructor(); } +// Warm the function and constructor so later calls include the VM inline path. +construct(foreign); construct(foreign); +for (const replacement of [null, undefined, {}]) { + foreign.prototype = replacement; + const expected = replacement && typeof replacement === 'object' ? replacement : foreignObjectPrototype; + observations.push( + Object.getPrototypeOf(new foreign()) === expected, + Object.getPrototypeOf(construct(foreign)) === expected, + Object.getPrototypeOf(Reflect.construct(foreign, [])) === expected, + Object.getPrototypeOf(new (foreign.bind(null))()) === expected + ); +} +const other = vm.runInNewContext('(function Other() {})'); +observations.push(Object.getPrototypeOf(other.prototype) !== foreignObjectPrototype); +observations; +JS)); + } +} diff --git a/tests/Unit/Runtime/fixtures/lazy-function-prototype.expected.json b/tests/Unit/Runtime/fixtures/lazy-function-prototype.expected.json new file mode 100644 index 00000000..ca941d27 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/lazy-function-prototype.expected.json @@ -0,0 +1,213 @@ +[ + [ + [ + "length", + "name", + "prototype", + "extra" + ], + [ + "length", + "name", + "prototype", + "extra" + ], + [ + true, + false, + false, + false, + false + ], + [ + "constructor" + ], + [ + true, + false, + true, + false, + false + ], + true, + true, + true, + true + ], + [ + true, + true, + true, + true + ], + [ + true, + true, + [ + true, + false, + false, + false, + false + ], + true + ], + [ + true, + true, + [ + true, + false, + false, + false, + false + ], + true + ], + [ + true, + true, + [ + true, + false, + false, + false, + false + ], + true + ], + [ + true, + true, + [ + true, + false, + false, + false, + false + ], + true + ], + [ + true, + true, + [ + true, + false, + false, + false, + false + ], + true + ], + [ + true, + false, + true, + false, + "TypeError", + [ + false, + false, + false, + false, + false + ] + ], + [ + "object", + true, + true, + true, + false, + false, + [ + false, + false, + false, + false, + false + ] + ], + [ + true, + false, + false, + false, + [ + true, + false, + false, + false, + false + ], + true, + true, + false + ], + [ + true, + false, + true, + false, + [ + true, + false, + false, + false, + false + ], + true, + true, + false + ], + [ + true, + false, + true, + true, + [ + false, + false, + false, + false, + false + ], + false, + true, + false + ], + [ + false, + "TypeError", + false, + false, + false, + true + ], + [ + "TypeError", + "TypeError", + "TypeError", + "TypeError", + "TypeError", + "TypeError", + true + ], + [ + true, + true, + true + ], + [ + true, + true, + false, + false, + false, + false, + true, + false, + true + ] +] diff --git a/tests/Unit/Runtime/fixtures/lazy-function-prototype.js b/tests/Unit/Runtime/fixtures/lazy-function-prototype.js new file mode 100644 index 00000000..4e35fda0 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/lazy-function-prototype.js @@ -0,0 +1,140 @@ +(() => { + 'use strict'; + const observations = []; + const attempt = callback => { + try { return callback(); } catch (error) { return error.name; } + }; + const attributes = descriptor => [ + descriptor.writable, descriptor.enumerable, descriptor.configurable, + 'get' in descriptor, 'set' in descriptor + ]; + + const first = function First() {}; + first.extra = 1; + const order = Reflect.ownKeys(first); + const descriptor = Object.getOwnPropertyDescriptor(first, 'prototype'); + const prototype = descriptor.value; + observations.push([ + order, Reflect.ownKeys(first), attributes(descriptor), + Reflect.ownKeys(prototype), attributes(Object.getOwnPropertyDescriptor(prototype, 'constructor')), + prototype.constructor === first, Object.getPrototypeOf(prototype) === Object.prototype, + prototype === first.prototype, Object.getPrototypeOf(new first()) === prototype + ]); + + const inherited = function Inherited() {}; + const child = Object.create(inherited); + const inheritedPrototype = child.prototype; + observations.push([ + inheritedPrototype === inherited.prototype, + Reflect.get(inherited, 'prototype', 17) === inheritedPrototype, + new Proxy(inherited, {}).prototype === inheritedPrototype, + Object.getOwnPropertyDescriptors(inherited).prototype.value === inheritedPrototype + ]); + + for (const value of [undefined, null, 23, 'replacement', { custom: true }]) { + const changed = function Changed() {}; + changed.prototype = value; + observations.push([ + changed.prototype === value, + Object.getOwnPropertyDescriptor(changed, 'prototype').value === value, + attributes(Object.getOwnPropertyDescriptor(changed, 'prototype')), + Object.getPrototypeOf(new changed()) === (typeof value === 'object' && value !== null ? value : Object.prototype) + ]); + } + + const defined = function Defined() {}; + const replacement = {}; + Object.defineProperty(defined, 'prototype', { value: replacement, writable: false }); + observations.push([ + defined.prototype === replacement, + Reflect.set(defined, 'prototype', {}), + Reflect.defineProperty(defined, 'prototype', { value: replacement }), + Reflect.defineProperty(defined, 'prototype', { value: undefined }), + attempt(() => { defined.prototype = null; }), + attributes(Object.getOwnPropertyDescriptor(defined, 'prototype')) + ]); + + const locked = function Locked() {}; + Object.defineProperty(locked, 'prototype', { writable: false }); + observations.push([ + typeof locked.prototype, locked.prototype.constructor === locked, + Object.getPrototypeOf(new locked()) === locked.prototype, + Reflect.defineProperty(locked, 'prototype', { value: locked.prototype }), + Reflect.defineProperty(locked, 'prototype', { value: {} }), + Reflect.defineProperty(locked, 'prototype', { writable: true }), + attributes(Object.getOwnPropertyDescriptor(locked, 'prototype')) + ]); + + for (const operation of [Object.preventExtensions, Object.seal, Object.freeze]) { + const restricted = function Restricted() {}; + // Node 26.12 reports a sealed strict function as frozen despite its writable + // prototype. An ordinary own property avoids that V8 anomaly; the prototype + // descriptor and replacement behavior are still checked directly below. + restricted.extra = 1; + operation(restricted); + const initial = restricted.prototype; + observations.push([ + initial.constructor === restricted, + Object.isExtensible(restricted), Object.isSealed(restricted), Object.isFrozen(restricted), + attributes(Object.getOwnPropertyDescriptor(restricted, 'prototype')), + Reflect.set(restricted, 'prototype', null), + Object.getPrototypeOf(new restricted()) === (restricted.prototype === null ? Object.prototype : initial), + Reflect.deleteProperty(restricted, 'prototype') + ]); + } + + const removed = function Removed() {}; + observations.push([ + Reflect.deleteProperty(removed, 'prototype'), + attempt(() => { delete removed.prototype; }), + Reflect.defineProperty(removed, 'prototype', { get() { return 1; } }), + Reflect.defineProperty(removed, 'prototype', { enumerable: true }), + Reflect.defineProperty(removed, 'prototype', { configurable: true }), + removed.prototype.constructor === removed + ]); + + const frozen = function Frozen() {}; + Object.defineProperty(frozen, 'prototype', { writable: false }); + const dishonest = new Proxy(frozen, { + get(target, name) { return name === 'prototype' ? {} : Reflect.get(target, name); }, + getOwnPropertyDescriptor(target, name) { + return name === 'prototype' + ? { value: {}, writable: false, enumerable: false, configurable: false } + : Reflect.getOwnPropertyDescriptor(target, name); + }, + defineProperty() { return true; }, + set() { return true; }, + deleteProperty() { return true; }, + ownKeys() { return ['length', 'name']; } + }); + observations.push([ + attempt(() => dishonest.prototype), + attempt(() => Object.getOwnPropertyDescriptor(dishonest, 'prototype')), + attempt(() => Reflect.defineProperty(dishonest, 'prototype', { value: {} })), + attempt(() => Reflect.set(dishonest, 'prototype', {})), + attempt(() => Reflect.deleteProperty(dishonest, 'prototype')), + attempt(() => Reflect.ownKeys(dishonest)), + frozen.prototype.constructor === frozen + ]); + + const mutable = function Mutable() {}; + const proxyValue = {}; + observations.push([ + new Proxy(mutable, { get() { return proxyValue; } }).prototype === proxyValue, + mutable.prototype !== proxyValue, + Reflect.getOwnPropertyDescriptor(new Proxy(mutable, {}), 'prototype').value === mutable.prototype + ]); + + const dynamic = new Function('"use strict"; return 3;'); + const method = { method() {} }.method; + const generator = function* () { yield 1; }; + observations.push([ + dynamic.prototype.constructor === dynamic, + new dynamic() instanceof dynamic, + Object.hasOwn(method, 'prototype'), Object.hasOwn(() => 1, 'prototype'), + Object.hasOwn(dynamic.bind(null), 'prototype'), Object.hasOwn(async function () {}, 'prototype'), + Object.hasOwn(generator, 'prototype'), Object.hasOwn(generator.prototype, 'constructor'), + Object.getPrototypeOf(generator()) === generator.prototype + ]); + return observations; +})(); From 962c30380c08a3ad56c3f313445b0d0d48a50c2e Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 21:53:46 +0200 Subject: [PATCH 09/99] Compile ordered array destructuring assignments --- src/Bytecode/CompiledFunction.php | 3 +- src/Bytecode/Compiler.php | 10 +- src/Bytecode/Parts/CompilerExpression.php | 54 + src/Bytecode/Parts/CompilerScope.php | 22 + .../Parts/Helpers/IteratorProtocol.php | 16 +- .../Parts/Helpers/ReferenceResolution.php | 2 +- tests/Unit/Bytecode/ArrayAssignmentTest.php | 43 + .../Bytecode/fixtures/array-assignments.js | 128 ++ .../Bytecode/fixtures/array-assignments.json | 1310 +++++++++++++++++ 9 files changed, 1579 insertions(+), 9 deletions(-) create mode 100644 tests/Unit/Bytecode/ArrayAssignmentTest.php create mode 100644 tests/Unit/Bytecode/fixtures/array-assignments.js create mode 100644 tests/Unit/Bytecode/fixtures/array-assignments.json diff --git a/src/Bytecode/CompiledFunction.php b/src/Bytecode/CompiledFunction.php index 8e1ce95c..08d7a9a4 100644 --- a/src/Bytecode/CompiledFunction.php +++ b/src/Bytecode/CompiledFunction.php @@ -4,6 +4,7 @@ namespace Phasis\Bytecode; +use Phasis\Ast\Node; use Phasis\Value\JsValue; /** @@ -24,7 +25,7 @@ final class CompiledFunction * Ordered flat array bindings reuse the interpreter's iterator protocol. * Captured identifiers retain their live Environment binding. * - * @var list}> + * @var list}> */ public array $arrayBindings = []; diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index a6f69cd5..30152795 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -173,10 +173,13 @@ final class Compiler private array $classNodes = []; /** - * @var list}> + * @var list}> */ private array $arrayBindings = []; + /** Interpreted assignment references need the activation's lexical this binding. */ + private bool $arrayAssignmentReferences = false; + /** * Source-like display string for each CALL_METHOD opcode emitted, * keyed by the PC of the opcode. The VM reads this on the @@ -356,7 +359,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction // (LOAD_THIS — arrows/generators) or when a nested arrow / // class outer-position lexically references this or super // and will resolve it through the env chain at run time. - $needsEnvThis = $this->hasLoadThis + $needsEnvThis = $this->arrayAssignmentReferences || $this->hasLoadThis || $this->nestedFnsLexicallyReferenceThis(); $cf = new CompiledFunction( code: $this->code, @@ -373,6 +376,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction parametersFromEnvironment: $this->parametersFromEnvironment, hasTailCalls: $this->hasTailCalls, ); + $cf->arrayBindings = $this->arrayBindings; $cf->callMethodDisplays = $this->callMethodDisplays; return $cf; } @@ -410,7 +414,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction // See the expression-body site above for the needsThis / // canSkipEnvAlloc semantics under frame-based this. - $needsEnvThis = $this->hasLoadThis + $needsEnvThis = $this->arrayAssignmentReferences || $this->hasLoadThis || $this->nestedFnsLexicallyReferenceThis(); $cf = new CompiledFunction( code: $this->code, diff --git a/src/Bytecode/Parts/CompilerExpression.php b/src/Bytecode/Parts/CompilerExpression.php index 0b54debe..b0a7262b 100644 --- a/src/Bytecode/Parts/CompilerExpression.php +++ b/src/Bytecode/Parts/CompilerExpression.php @@ -736,6 +736,10 @@ private function compileAssignment(AssignmentExpression $node): void } $left = $node->left; $op = $node->operator; + if ($op === '=' && ($left instanceof ArrayPattern || $left instanceof ArrayExpression)) { + $this->compileArrayAssignment($left, $node->right); + return; + } if ($op === '&&=' || $op === '||=' || $op === '??=') { $this->compileLogicalAssignment($node); return; @@ -880,6 +884,56 @@ private function compileAssignment(AssignmentExpression $node): void throw new CompilerBailout('unsupported assignment target'); } + /** Keep each reference and write beside its iterator step, including abrupt closing. */ + private function compileArrayAssignment(ArrayPattern|ArrayExpression $pattern, Node $right): void + { + $elements = []; + foreach ($pattern->elements as $element) { + if ($element === null) { + $elements[] = null; + continue; + } + $rest = $element instanceof RestElement || $element instanceof SpreadElement; + $target = $rest ? $element->argument : $element; + if ($target instanceof Identifier) { + if ($target->name === 'eval' || $target->name === 'arguments') { + throw new CompilerBailout('array assignment to eval/arguments'); + } + $slot = $this->localSlots[$target->name] ?? null; + if ($slot !== null) { + if (isset($this->constSlots[$slot])) { + throw new CompilerBailout('array assignment to const'); + } + $elements[] = [ + 'slot' => $slot, + 'capturedName' => isset($this->capturedLocals[$target->name]) ? $target->name : null, + 'rest' => $rest, + ]; + continue; + } + } elseif ( + !$target instanceof MemberExpression || $target->optional + || $target->property instanceof PrivateIdentifier + || ($target->object instanceof Identifier && $target->object->name === 'super') + ) { + throw new CompilerBailout('complex array assignment target'); + } + // Member references can invoke arbitrary getters and computed-key + // expressions. Their local dependencies use captured bindings, so + // the shared reference evaluator observes the live activation. + if ($this->inGenerator) { + throw new CompilerBailout('generator array assignment reference'); + } + $elements[] = ['target' => $target, 'rest' => $rest]; + $this->arrayAssignmentReferences = true; + } + $this->compileExpression($right); + $this->emit(Op::DUP); + $index = count($this->arrayBindings); + $this->arrayBindings[] = ['kind' => 'assignment', 'elements' => $elements]; + $this->emit(Op::BIND_ARRAY, $index); + } + private function compileLogicalAssignment(AssignmentExpression $node): void { $left = $node->left; diff --git a/src/Bytecode/Parts/CompilerScope.php b/src/Bytecode/Parts/CompilerScope.php index dd157f8a..c8112b8a 100644 --- a/src/Bytecode/Parts/CompilerScope.php +++ b/src/Bytecode/Parts/CompilerScope.php @@ -110,6 +110,28 @@ private function collectCapturedLocals(Node $body): void */ private function collectNestedLocalReferences(Node $node, bool $nested, array &$references, array $shadow = []): void { + if ( + $node instanceof AssignmentExpression + && ($node->left instanceof ArrayPattern || $node->left instanceof ArrayExpression) + ) { + foreach ($node->left->elements as $element) { + $target = $element instanceof RestElement || $element instanceof SpreadElement + ? $element->argument : $element; + if ($target instanceof Node) { + // The iterator helper evaluates member references between + // steps. Reify their local reads and writes in the same + // environment used by nested interpreted closures. + $this->collectNestedLocalReferences( + $target, + $nested || $target instanceof MemberExpression, + $references, + $shadow, + ); + } + } + $this->collectNestedLocalReferences($node->right, $nested, $references, $shadow); + return; + } if ($node instanceof Identifier) { if ($nested && isset($this->localSlots[$node->name]) && !isset($shadow[$node->name])) { $references[$node->name] = true; diff --git a/src/Runtime/Parts/Helpers/IteratorProtocol.php b/src/Runtime/Parts/Helpers/IteratorProtocol.php index 5b98ac3f..0e2dc131 100644 --- a/src/Runtime/Parts/Helpers/IteratorProtocol.php +++ b/src/Runtime/Parts/Helpers/IteratorProtocol.php @@ -104,10 +104,10 @@ trait IteratorProtocol { /** - * Initialize a compiled flat array binding without reading ahead. Iterator - * methods can observe each earlier binding through captured closures. + * Bind or assign a compiled flat array pattern without reading ahead. + * Iterator methods can observe each earlier write through captured closures. * - * @param array{kind: string, elements: list} $binding + * @param array{kind: string, elements: list} $binding * @param list $locals */ public function vmBindArray(JsValue $value, array $binding, array &$locals, Environment $env): void @@ -120,9 +120,17 @@ public function vmBindArray(JsValue $value, array $binding, array &$locals, Envi $this->iteratorNext($iterator, $nextMethod, $done, false); continue; } + $reference = isset($element['target']) ? $this->resolveReference($element['target'], $env) : null; $item = $element['rest'] ? $this->iteratorRest($iterator, $nextMethod, $done) : $this->iteratorNext($iterator, $nextMethod, $done); + if ($reference !== null) { + $reference->setValue($item); + continue; + } + if (isset($element['target'])) { + throw new \LogicException('Array assignment reference was not resolved'); + } $name = $element['capturedName']; if ($name === null) { $slot = $element['slot']; @@ -130,7 +138,7 @@ public function vmBindArray(JsValue $value, array $binding, array &$locals, Envi throw new \LogicException('Array binding references an unallocated local slot'); } $locals[$slot] = $item; - } elseif ($binding['kind'] === 'var') { + } elseif ($binding['kind'] === 'var' || $binding['kind'] === 'assignment') { $env->set($name, $item); } else { $env->initialize($name, $item); diff --git a/src/Runtime/Parts/Helpers/ReferenceResolution.php b/src/Runtime/Parts/Helpers/ReferenceResolution.php index ef8c77b1..06e3c412 100644 --- a/src/Runtime/Parts/Helpers/ReferenceResolution.php +++ b/src/Runtime/Parts/Helpers/ReferenceResolution.php @@ -417,7 +417,7 @@ private function destructureAssign(Node $target, JsValue $value, Environment $en } if ($elem === null) { // Elision: advance iterator but discard value. - $this->iteratorNext($iterator, $nextMethod, $done); + $this->iteratorNext($iterator, $nextMethod, $done, false); continue; } // Per spec 13.15.5.3 IteratorDestructuringAssignmentEvaluation: diff --git a/tests/Unit/Bytecode/ArrayAssignmentTest.php b/tests/Unit/Bytecode/ArrayAssignmentTest.php new file mode 100644 index 00000000..07ca1a4e --- /dev/null +++ b/tests/Unit/Bytecode/ArrayAssignmentTest.php @@ -0,0 +1,43 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/array-assignments.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/array-assignments.json', + $engine->eval('JSON.stringify(arrayAssignmentResult)'), + ); + $functions = ['first', 'pair', 'elided', 'empty', 'rest', 'duplicate', 'captured', + 'member', 'restMember', 'receiver', 'changedBase', 'partial', 'arrow']; + foreach ($functions as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise the bytecode path.'); + } + } + + public function testInterpretedAssignmentsMatchTheSameNodeOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/array-assignments.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/array-assignments.json', + $engine->eval('JSON.stringify(arrayAssignmentResult)'), + ); + $function = $engine->getGlobalEnv()->get('first'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled); + } +} diff --git a/tests/Unit/Bytecode/fixtures/array-assignments.js b/tests/Unit/Bytecode/fixtures/array-assignments.js new file mode 100644 index 00000000..43897714 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/array-assignments.js @@ -0,0 +1,128 @@ +'use strict'; + +function first(value) { let a; const result = ([a] = value); return [a, result === value]; } +function pair(value) { let a, b; [a, b] = value; return [a, b]; } +function elided(value) { let a; [, a] = value; return a; } +function empty(value) { return ([] = value) === value; } +function rest(value) { let a, remaining; [a, ...remaining] = value; return [a, remaining]; } +function duplicate(value) { let a; [a, a] = value; return a; } +function captured(value) { + let a = 1, b = 2; + value.observe = () => [a, b].join(':'); + [a, b] = value; + return [a, b]; +} +function member(value, target) { + let index = 0; + [target[(index++, target.key())]] = value; + return [index, target.x]; +} +function restMember(value, target) { + let a; + [a, ...target[target.key()]] = value; + return [a, target.x]; +} +function receiver(value) { [this.x] = value; return this.x; } +function changedBase(value) { + const before = {}; + const after = {}; + let target = before; + value.beforeNext = () => { target = after; }; + [target.x] = value; + return [before.x, after.x]; +} +function partial(value, target) { + let a = 'before'; + try { [a, target[target.key()]] = value; } + catch (error) { return [a, error instanceof Error ? error.name : error]; } + return [a, target.x]; +} +var arrow = value => ([] = value); + +function makeIterable(mode, trace) { + let step = 0; + const source = { + [Symbol.iterator]() { + trace.push('iterator'); + return { + get next() { + trace.push('get next'); + const next = function () { + step++; + trace.push('next:' + step); + if (source.observe) trace.push('observe:' + source.observe()); + if (source.beforeNext) source.beforeNext(); + if (mode === 'next') throw 'next failure'; + if (mode === 'primitive result') return 1; + return { + get done() { + trace.push('done:' + step); + if (mode === 'done') throw 'done failure'; + return step > 2; + }, + get value() { + trace.push('value:' + step); + if (mode === 'value' || (mode === 'hole' && step === 1)) throw 'value failure'; + return step * 10; + } + }; + }; + return mode === 'proxy next' ? new Proxy(next, {}) : next; + }, + get return() { + trace.push('get return'); + if (mode === 'return getter') throw 'return getter failure'; + const close = function () { + trace.push('return'); + if (mode === 'return value') return 1; + if (mode === 'return throw') throw 'return failure'; + return {}; + }; + return mode === 'proxy return' ? new Proxy(close, {}) : close; + } + }; + } + }; + return source; +} + +function makeTarget(mode, trace) { + const target = { + key() { + trace.push('target expression'); + if (mode === 'expression') throw 'target failure'; + return { + [Symbol.toPrimitive]() { + trace.push('key conversion'); + if (mode === 'key') throw 'key failure'; + return 'x'; + } + }; + } + }; + if (mode === 'setter') Object.defineProperty(target, 'x', { set(value) { trace.push('setter:' + value); throw 'setter failure'; } }); + return target; +} + +var arrayAssignmentResult = []; +for (let repeat = 0; repeat < 3; repeat++) { + for (const test of [ + [first, 'normal'], [pair, 'normal'], [elided, 'hole'], [empty, 'normal'], + [rest, 'normal'], [duplicate, 'normal'], [captured, 'normal'], [changedBase, 'normal'], + [first, 'next'], [first, 'done'], [first, 'value'], [first, 'primitive result'], + [first, 'proxy next'], [first, 'proxy return'], [first, 'return getter'], [first, 'return value'], + [member, 'normal', 'normal'], [member, 'normal', 'expression'], [member, 'normal', 'key'], + [member, 'return throw', 'setter'], [restMember, 'normal', 'normal'], + [restMember, 'normal', 'expression'], [partial, 'normal', 'setter'], [partial, 'normal', 'expression'] + ]) { + const trace = []; + try { arrayAssignmentResult.push([test[0].name, test[1], test[2], test[0](makeIterable(test[1], trace), makeTarget(test[2], trace)), trace]); } + catch (error) { arrayAssignmentResult.push([test[0].name, test[1], test[2], error instanceof Error ? error.name : error, trace]); } + } + arrayAssignmentResult.push(pair([]), pair('😀x'), rest([1, 2, 3]), duplicate([4, 5])); + arrayAssignmentResult.push(receiver.call({}, [7]), arrow([1]).join(',')); + for (const value of [null, undefined, 2, {}]) { + try { first(value); } + catch (error) { arrayAssignmentResult.push(error.name); } + } +} diff --git a/tests/Unit/Bytecode/fixtures/array-assignments.json b/tests/Unit/Bytecode/fixtures/array-assignments.json new file mode 100644 index 00000000..ec6867b0 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/array-assignments.json @@ -0,0 +1,1310 @@ +[ + [ + "first", + "normal", + null, + [ + 10, + true + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "pair", + "normal", + null, + [ + 10, + 20 + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "elided", + "hole", + null, + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "empty", + "normal", + null, + true, + [ + "iterator", + "get next", + "get return", + "return" + ] + ], + [ + "rest", + "normal", + null, + [ + 10, + [ + 20 + ] + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "next:3", + "done:3" + ] + ], + [ + "duplicate", + "normal", + null, + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "captured", + "normal", + null, + [ + 10, + 20 + ], + [ + "iterator", + "get next", + "next:1", + "observe:1:2", + "done:1", + "value:1", + "next:2", + "observe:10:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "changedBase", + "normal", + null, + [ + 10, + null + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "first", + "next", + null, + "next failure", + [ + "iterator", + "get next", + "next:1" + ] + ], + [ + "first", + "done", + null, + "done failure", + [ + "iterator", + "get next", + "next:1", + "done:1" + ] + ], + [ + "first", + "value", + null, + "value failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1" + ] + ], + [ + "first", + "primitive result", + null, + "TypeError", + [ + "iterator", + "get next", + "next:1" + ] + ], + [ + "first", + "proxy next", + null, + [ + 10, + true + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "first", + "proxy return", + null, + [ + 10, + true + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "first", + "return getter", + null, + "return getter failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return" + ] + ], + [ + "first", + "return value", + null, + "TypeError", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "member", + "normal", + "normal", + [ + 1, + 10 + ], + [ + "iterator", + "get next", + "target expression", + "next:1", + "done:1", + "value:1", + "key conversion", + "get return", + "return" + ] + ], + [ + "member", + "normal", + "expression", + "target failure", + [ + "iterator", + "get next", + "target expression", + "get return", + "return" + ] + ], + [ + "member", + "normal", + "key", + "key failure", + [ + "iterator", + "get next", + "target expression", + "next:1", + "done:1", + "value:1", + "key conversion", + "get return", + "return" + ] + ], + [ + "member", + "return throw", + "setter", + "setter failure", + [ + "iterator", + "get next", + "target expression", + "next:1", + "done:1", + "value:1", + "key conversion", + "setter:10", + "get return", + "return" + ] + ], + [ + "restMember", + "normal", + "normal", + [ + 10, + [ + 20 + ] + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "next:2", + "done:2", + "value:2", + "next:3", + "done:3", + "key conversion" + ] + ], + [ + "restMember", + "normal", + "expression", + "target failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "get return", + "return" + ] + ], + [ + "partial", + "normal", + "setter", + [ + 10, + "setter failure" + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "next:2", + "done:2", + "value:2", + "key conversion", + "setter:20", + "get return", + "return" + ] + ], + [ + "partial", + "normal", + "expression", + [ + 10, + "target failure" + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "get return", + "return" + ] + ], + [ + null, + null + ], + [ + "😀", + "x" + ], + [ + 1, + [ + 2, + 3 + ] + ], + 5, + 7, + "1", + "TypeError", + "TypeError", + "TypeError", + "TypeError", + [ + "first", + "normal", + null, + [ + 10, + true + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "pair", + "normal", + null, + [ + 10, + 20 + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "elided", + "hole", + null, + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "empty", + "normal", + null, + true, + [ + "iterator", + "get next", + "get return", + "return" + ] + ], + [ + "rest", + "normal", + null, + [ + 10, + [ + 20 + ] + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "next:3", + "done:3" + ] + ], + [ + "duplicate", + "normal", + null, + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "captured", + "normal", + null, + [ + 10, + 20 + ], + [ + "iterator", + "get next", + "next:1", + "observe:1:2", + "done:1", + "value:1", + "next:2", + "observe:10:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "changedBase", + "normal", + null, + [ + 10, + null + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "first", + "next", + null, + "next failure", + [ + "iterator", + "get next", + "next:1" + ] + ], + [ + "first", + "done", + null, + "done failure", + [ + "iterator", + "get next", + "next:1", + "done:1" + ] + ], + [ + "first", + "value", + null, + "value failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1" + ] + ], + [ + "first", + "primitive result", + null, + "TypeError", + [ + "iterator", + "get next", + "next:1" + ] + ], + [ + "first", + "proxy next", + null, + [ + 10, + true + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "first", + "proxy return", + null, + [ + 10, + true + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "first", + "return getter", + null, + "return getter failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return" + ] + ], + [ + "first", + "return value", + null, + "TypeError", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "member", + "normal", + "normal", + [ + 1, + 10 + ], + [ + "iterator", + "get next", + "target expression", + "next:1", + "done:1", + "value:1", + "key conversion", + "get return", + "return" + ] + ], + [ + "member", + "normal", + "expression", + "target failure", + [ + "iterator", + "get next", + "target expression", + "get return", + "return" + ] + ], + [ + "member", + "normal", + "key", + "key failure", + [ + "iterator", + "get next", + "target expression", + "next:1", + "done:1", + "value:1", + "key conversion", + "get return", + "return" + ] + ], + [ + "member", + "return throw", + "setter", + "setter failure", + [ + "iterator", + "get next", + "target expression", + "next:1", + "done:1", + "value:1", + "key conversion", + "setter:10", + "get return", + "return" + ] + ], + [ + "restMember", + "normal", + "normal", + [ + 10, + [ + 20 + ] + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "next:2", + "done:2", + "value:2", + "next:3", + "done:3", + "key conversion" + ] + ], + [ + "restMember", + "normal", + "expression", + "target failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "get return", + "return" + ] + ], + [ + "partial", + "normal", + "setter", + [ + 10, + "setter failure" + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "next:2", + "done:2", + "value:2", + "key conversion", + "setter:20", + "get return", + "return" + ] + ], + [ + "partial", + "normal", + "expression", + [ + 10, + "target failure" + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "get return", + "return" + ] + ], + [ + null, + null + ], + [ + "😀", + "x" + ], + [ + 1, + [ + 2, + 3 + ] + ], + 5, + 7, + "1", + "TypeError", + "TypeError", + "TypeError", + "TypeError", + [ + "first", + "normal", + null, + [ + 10, + true + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "pair", + "normal", + null, + [ + 10, + 20 + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "elided", + "hole", + null, + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "empty", + "normal", + null, + true, + [ + "iterator", + "get next", + "get return", + "return" + ] + ], + [ + "rest", + "normal", + null, + [ + 10, + [ + 20 + ] + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "next:3", + "done:3" + ] + ], + [ + "duplicate", + "normal", + null, + 20, + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "captured", + "normal", + null, + [ + 10, + 20 + ], + [ + "iterator", + "get next", + "next:1", + "observe:1:2", + "done:1", + "value:1", + "next:2", + "observe:10:2", + "done:2", + "value:2", + "get return", + "return" + ] + ], + [ + "changedBase", + "normal", + null, + [ + 10, + null + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "first", + "next", + null, + "next failure", + [ + "iterator", + "get next", + "next:1" + ] + ], + [ + "first", + "done", + null, + "done failure", + [ + "iterator", + "get next", + "next:1", + "done:1" + ] + ], + [ + "first", + "value", + null, + "value failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1" + ] + ], + [ + "first", + "primitive result", + null, + "TypeError", + [ + "iterator", + "get next", + "next:1" + ] + ], + [ + "first", + "proxy next", + null, + [ + 10, + true + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "first", + "proxy return", + null, + [ + 10, + true + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "first", + "return getter", + null, + "return getter failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return" + ] + ], + [ + "first", + "return value", + null, + "TypeError", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "get return", + "return" + ] + ], + [ + "member", + "normal", + "normal", + [ + 1, + 10 + ], + [ + "iterator", + "get next", + "target expression", + "next:1", + "done:1", + "value:1", + "key conversion", + "get return", + "return" + ] + ], + [ + "member", + "normal", + "expression", + "target failure", + [ + "iterator", + "get next", + "target expression", + "get return", + "return" + ] + ], + [ + "member", + "normal", + "key", + "key failure", + [ + "iterator", + "get next", + "target expression", + "next:1", + "done:1", + "value:1", + "key conversion", + "get return", + "return" + ] + ], + [ + "member", + "return throw", + "setter", + "setter failure", + [ + "iterator", + "get next", + "target expression", + "next:1", + "done:1", + "value:1", + "key conversion", + "setter:10", + "get return", + "return" + ] + ], + [ + "restMember", + "normal", + "normal", + [ + 10, + [ + 20 + ] + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "next:2", + "done:2", + "value:2", + "next:3", + "done:3", + "key conversion" + ] + ], + [ + "restMember", + "normal", + "expression", + "target failure", + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "get return", + "return" + ] + ], + [ + "partial", + "normal", + "setter", + [ + 10, + "setter failure" + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "next:2", + "done:2", + "value:2", + "key conversion", + "setter:20", + "get return", + "return" + ] + ], + [ + "partial", + "normal", + "expression", + [ + 10, + "target failure" + ], + [ + "iterator", + "get next", + "next:1", + "done:1", + "value:1", + "target expression", + "get return", + "return" + ] + ], + [ + null, + null + ], + [ + "😀", + "x" + ], + [ + 1, + [ + 2, + 3 + ] + ], + 5, + 7, + "1", + "TypeError", + "TypeError", + "TypeError", + "TypeError" +] From d44dcede9d21106d9138fc1afeb7b02ea98d77c6 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 21:53:56 +0200 Subject: [PATCH 10/99] Compile optional chains with shared tail-call resolution --- src/Bytecode/Parts/CompilerExpression.php | 125 +- src/Bytecode/Parts/CompilerStatement.php | 4 + src/Runtime/Parts/ExpressionEvaluation.php | 8 +- src/Runtime/Parts/StatementExecution.php | 136 +- tests/Unit/Bytecode/OptionalChainTest.php | 45 + .../Unit/Bytecode/fixtures/optional-chains.js | 86 ++ .../Bytecode/fixtures/optional-chains.json | 1148 +++++++++++++++++ 7 files changed, 1415 insertions(+), 137 deletions(-) create mode 100644 tests/Unit/Bytecode/OptionalChainTest.php create mode 100644 tests/Unit/Bytecode/fixtures/optional-chains.js create mode 100644 tests/Unit/Bytecode/fixtures/optional-chains.json diff --git a/src/Bytecode/Parts/CompilerExpression.php b/src/Bytecode/Parts/CompilerExpression.php index b0a7262b..82687646 100644 --- a/src/Bytecode/Parts/CompilerExpression.php +++ b/src/Bytecode/Parts/CompilerExpression.php @@ -618,9 +618,9 @@ private function compileConditional(ConditionalExpression $node): void private function compileCall(CallExpression $node): void { - // Optional chains and direct eval retain the interpreter path. - if ($node->optional) { - throw new CompilerBailout('optional call'); + if ($this->chainHasOptionalLink($node)) { + $this->compileOptionalChain($node); + return; } if ($node->callee instanceof Identifier && $node->callee->name === 'eval') { throw new CompilerBailout('direct eval'); @@ -707,8 +707,9 @@ private function compileArguments(array $arguments): int private function compileMember(MemberExpression $node): void { - if ($node->optional) { - throw new CompilerBailout('optional member'); + if ($this->chainHasOptionalLink($node)) { + $this->compileOptionalChain($node); + return; } if ($node->object instanceof Identifier && $node->object->name === 'super') { throw new CompilerBailout('super member access'); @@ -729,6 +730,120 @@ private function compileMember(MemberExpression $node): void $this->emit(Op::LOAD_MEMBER, $this->internName($node->property->name)); } + /** Parentheses affect propagation, but still require reference-preserving lowering. */ + private function chainHasOptionalLink(MemberExpression|CallExpression $node): bool + { + while ($node instanceof MemberExpression || $node instanceof CallExpression) { + if ($node->optional) { + return true; + } + $node = $node instanceof MemberExpression ? $node->object : $node->callee; + } + return false; + } + + /** + * Nullish branches leave the whole chain at once. No sentinel can escape + * into bindings or comparisons, and a grouped method retains its receiver. + */ + private function compileOptionalChain( + MemberExpression|CallExpression $node, + bool $reference = false, + bool $tail = false, + ): void { + $shortCircuits = []; + $this->compileChainLink($node, $shortCircuits, $reference, $tail); + if ($shortCircuits === []) { + return; + } + $ends = [$this->emitJump(Op::JUMP)]; + foreach ($shortCircuits as $branch) { + $this->patchJumpToHere($branch['jump']); + for ($discard = 0; $discard < $branch['discard']; $discard++) { + $this->emit(Op::POP); + } + if ($reference) { + $this->emit(Op::LOAD_UNDEF); + } + $this->emit(Op::LOAD_UNDEF); + $ends[] = $this->emitJump(Op::JUMP); + } + foreach ($ends as $end) { + $this->patchJumpToHere($end); + } + } + + /** @param list $shortCircuits */ + private function compileChainOperand(Node $node, array &$shortCircuits, bool $reference = false): void + { + if ($node instanceof MemberExpression || $node instanceof CallExpression) { + if ($node->parenthesized) { + // `(a?.b).c` must read `.c` from the completed undefined value. + // `(a?.b)()` additionally keeps the successful method receiver. + $this->compileOptionalChain($node, $reference); + } else { + $this->compileChainLink($node, $shortCircuits, $reference); + } + return; + } + $this->compileExpression($node); + } + + /** @param list $shortCircuits */ + private function compileChainLink( + MemberExpression|CallExpression $node, + array &$shortCircuits, + bool $reference = false, + bool $tail = false, + ): void { + if ($node instanceof MemberExpression) { + if ( + $node->property instanceof PrivateIdentifier + || ($node->object instanceof Identifier && $node->object->name === 'super') + ) { + throw new CompilerBailout('private/super optional chain'); + } + $this->compileChainOperand($node->object, $shortCircuits); + if ($node->optional) { + $shortCircuits[] = ['jump' => $this->emitJump(Op::JUMP_IF_NULLISH), 'discard' => 0]; + } + if ($reference) { + $this->emit(Op::DUP); + } + if ($node->computed) { + $this->compileExpression($node->property); + $this->emit(Op::LOAD_COMPUTED); + } elseif ($node->property instanceof Identifier) { + $this->emit(Op::LOAD_MEMBER, $this->internName($node->property->name)); + } else { + throw new CompilerBailout('non-identifier optional member'); + } + return; + } + if ($node->callee instanceof Identifier && ($node->callee->name === 'eval' || $node->callee->name === 'super')) { + throw new CompilerBailout('eval/super chain call'); + } + $method = $node->callee instanceof MemberExpression; + $this->compileChainOperand($node->callee, $shortCircuits, $method); + if ($node->optional) { + $shortCircuits[] = ['jump' => $this->emitJump(Op::JUMP_IF_NULLISH), 'discard' => $method ? 1 : 0]; + } + $argc = $this->compileArguments($node->arguments); + $pc = count($this->code); + $this->emit($tail + ? ($method ? Op::TAIL_CALL_METHOD : Op::TAIL_CALL) + : ($method ? Op::CALL_METHOD : Op::CALL), $argc); + if ($tail) { + $this->hasTailCalls = true; + } + if ($node->callee instanceof MemberExpression) { + $display = $this->renderMethodCallDisplay($node->callee); + if ($display !== null) { + $this->callMethodDisplays[$pc] = $display; + } + } + } + private function compileAssignment(AssignmentExpression $node): void { if ($node->leftParenthesized) { diff --git a/src/Bytecode/Parts/CompilerStatement.php b/src/Bytecode/Parts/CompilerStatement.php index e593042d..1685e856 100644 --- a/src/Bytecode/Parts/CompilerStatement.php +++ b/src/Bytecode/Parts/CompilerStatement.php @@ -179,6 +179,10 @@ private function compileStatement(Node $node): void /** Compile a return value, preserving strict tail positions recursively. */ private function compileReturnExpression(Node $expression): void { + if ($this->tailCallsEnabled && $expression instanceof CallExpression && $this->chainHasOptionalLink($expression)) { + $this->compileOptionalChain($expression, tail: true); + return; + } if ($this->tailCallsEnabled && $expression instanceof ConditionalExpression) { $this->compileExpression($expression->test); $alternate = $this->emitJump(Op::JUMP_IF_FALSE); diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index 8b466d88..e082d9bd 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -1245,7 +1245,8 @@ private function evalConditional(ConditionalExpression $node, Environment $env): : $this->evaluate($node->alternate, $env); } - private function evalCallExpression(CallExpression $node, Environment $env): JsValue + /** @return ($tail is true ? JsValue|TailCallThunk : JsValue) */ + private function evalCallExpression(CallExpression $node, Environment $env, bool $tail = false): JsValue|TailCallThunk { // Super call: super(args) inside a class constructor. // Calls the super class constructor with the current this and args. @@ -1465,7 +1466,7 @@ private function evalCallExpression(CallExpression $node, Environment $env): JsV $shortCircuits = $rawObj instanceof JsOptionalUndefined || ($node->callee->optional && ($rawObj instanceof JsNull || $rawObj instanceof JsUndefined)); if ($shortCircuits) { - if ($node->callee->parenthesized) { + if ($node->callee->parenthesized && !$node->optional) { // `(a?.b)()`: the parentheses end the chain, so the callee // is undefined and the call itself fails, after its // arguments are evaluated. @@ -1646,6 +1647,9 @@ private function evalCallExpression(CallExpression $node, Environment $env): JsV // We do NOT set thisValue = globalObject here so that explicit apply(globalObject) // calls pass the global object through without being cleared by executeFunction. + if ($tail && !$callee->isNative() && !$callee->isGenerator() && !$callee->isAsync()) { + return new TailCallThunk($callee, $thisValue, $args); + } return $this->callFunction($callee, $thisValue, $args); } diff --git a/src/Runtime/Parts/StatementExecution.php b/src/Runtime/Parts/StatementExecution.php index e5a7deb9..1ee2c2d2 100644 --- a/src/Runtime/Parts/StatementExecution.php +++ b/src/Runtime/Parts/StatementExecution.php @@ -2780,137 +2780,13 @@ private function evalTaggedTemplateTailCall(TaggedTemplate $node, Environment $e return new TailCallThunk($tag, $thisValue, $args); } - private function evalTailCall(CallExpression $node, Environment $env): TailCallThunk|JsValue|null + private function evalTailCall(CallExpression $node, Environment $env): TailCallThunk|JsValue { - // Resolve the callee and its this-binding. - $callee = null; - $thisValue = JsUndefined::instance(); - - if ($node->callee instanceof MemberExpression) { - // super.method() needs special resolution via HomeObject; bail to the - // regular call path which knows how to handle it. - if ( - $node->callee->object instanceof Identifier - && $node->callee->object->name === 'super' - ) { - return null; - } - // Private method calls (obj.#method()) resolve via the receiver's - // private-name slots; the regular call path handles this, so bail. - if ($node->callee->property instanceof PrivateIdentifier) { - return null; - } - // The receiver of a method call is usually side-effecting; if we - // evaluated it here and then bailed because the callee turned out - // to be a native method, execReturnStatement would re-evaluate - // the same expression and double-run side effects (observable via - // `return foo().then(a).then(b)` where `.then` is native). To - // avoid that, only attempt TCO when the receiver is statically - // proven side-effect-free (Identifier, ThisExpression, Literal, - // or recursively a side-effect-free MemberExpression). - if (!self::isSideEffectFreeAst($node->callee->object)) { - return null; - } - $obj = $this->evaluate($node->callee->object, $env); - // Computed member with a Symbol key must not be stringified; fall back to - // the regular call path (returning null) so getBySymbol is used correctly. - if ($node->callee->computed) { - $propVal = $this->evaluate($node->callee->property, $env); - if ($propVal instanceof \Phasis\Value\JsSymbol) { - return null; - } - $propName = TypeConversion::toString($propVal); - } else { - $propName = $node->callee->property instanceof Identifier - ? $node->callee->property->name - : TypeConversion::toString($this->evaluate($node->callee->property, $env)); - } - $callee = $obj instanceof JsObject ? $obj->get($propName) : null; - $thisValue = $obj; - } elseif ($node->callee instanceof Identifier) { - // super() is not eligible for TCO. - if ($node->callee->name === 'super') { - return null; - } - if ($env->has($node->callee->name)) { - $callee = $env->get($node->callee->name); - } - // Direct eval (identifier 'eval' resolving to native %eval%) is - // not eligible; a user-shadowed 'eval' bound to a regular - // function still is (it's just a function call). - if ( - $node->callee->name === 'eval' - && $callee instanceof JsFunction - && $callee->isNative() - && $callee->getName() === 'eval' - ) { - return null; - } - } else { - // CallExpression / NewExpression / SequenceExpression / etc. - // The classic `return getF()(n-1)` TCO shape lives here. We - // evaluate the callee once and then *finish the call inline* - // when the result turns out ineligible for a tail-call thunk - // (callable proxy, native, generator, async, non-callable). - // Bailing-to-null after a side-effecting evaluate would make - // execReturnStatement re-evaluate the whole expression and - // run the inner call twice — the precise pitfall that the - // MemberExpression branch above guards against with - // isSideEffectFreeAst. Here we can't statically prove - // side-effect-freedom (it's a call), so we commit to - // performing the call ourselves. - $callee = $this->evaluate($node->callee, $env); - $args = []; - foreach ($node->arguments as $arg) { - if ($arg instanceof SpreadElement) { - $spread = $this->evaluate($arg->argument, $env); - $this->spreadInto($spread, $args); - } else { - $args[] = $this->evaluate($arg, $env); - } - } - // Callable Proxy — forward through its apply trap. Not a tail - // call (proxy semantics need their handler dispatched on each - // hop), but spec-correctly invoked. - if ($callee instanceof \Phasis\Value\JsProxy) { - return $callee->apply(JsUndefined::instance(), $args); - } - if (!$callee instanceof JsFunction) { - $desc = $this->formatCalleeForError($node->callee, $callee); - throw new TypeError("{$desc} is not a function"); - } - // Native / generator / async: ineligible for TCO; call inline. - if ( - $callee->getNativeCallable() !== null - || $callee->isGenerator() - || $callee->isAsync() - ) { - return $this->callFunction($callee, JsUndefined::instance(), $args); - } - return new TailCallThunk($callee, JsUndefined::instance(), $args); - } - - if (!$callee instanceof JsFunction) { - return null; // Not a function, fall back to normal evaluation - } - - // Cannot TCO native functions, generators, async functions, or constructors - if ($callee->getNativeCallable() !== null || $callee->isGenerator() || $callee->isAsync()) { - return null; - } - - // Evaluate arguments - $args = []; - foreach ($node->arguments as $arg) { - if ($arg instanceof SpreadElement) { - $spread = $this->evaluate($arg->argument, $env); - $this->spreadInto($spread, $args); - } else { - $args[] = $this->evaluate($arg, $env); - } - } - - return new TailCallThunk($callee, $thisValue, $args); + // Resolve every reference, getter and argument exactly once through + // the ordinary call path. Probing and then falling back would repeat + // observable effects when a getter returns a native or missing method. + $result = $this->evalCallExpression($node, $env, true); + return $result instanceof JsOptionalUndefined ? JsUndefined::instance() : $result; } /** diff --git a/tests/Unit/Bytecode/OptionalChainTest.php b/tests/Unit/Bytecode/OptionalChainTest.php new file mode 100644 index 00000000..6e37bdc3 --- /dev/null +++ b/tests/Unit/Bytecode/OptionalChainTest.php @@ -0,0 +1,45 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/optional-chains.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/optional-chains.json', + $engine->eval('JSON.stringify(optionalChainResult)'), + ); + $functions = ['property', 'computed', 'method', 'optionalMethod', 'direct', 'continuation', + 'callContinuation', 'groupedProperty', 'groupedMethod', 'groupedOptionalMethod', + 'computedMethod', 'nested', 'spread', 'tail', 'tailUndefined', 'normalized', 'protectedCall']; + foreach ($functions as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise the bytecode path.'); + } + self::assertSame(5000, $engine->eval('tail(5000, 0)')); + } + + public function testInterpretedChainsMatchTheSameNodeOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/optional-chains.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/optional-chains.json', + $engine->eval('JSON.stringify(optionalChainResult)'), + ); + $function = $engine->getGlobalEnv()->get('property'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled); + } +} diff --git a/tests/Unit/Bytecode/fixtures/optional-chains.js b/tests/Unit/Bytecode/fixtures/optional-chains.js new file mode 100644 index 00000000..9681900f --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/optional-chains.js @@ -0,0 +1,86 @@ +'use strict'; + +function property(value) { return value?.x; } +function computed(value, trace) { return value?.[(trace.push('key'), 'x')]; } +function method(value, trace) { return value?.m((trace.push('argument'), 3)); } +function optionalMethod(value, trace) { return value.m?.((trace.push('argument'), 4)); } +function direct(value, trace) { return value?.((trace.push('argument'), 5)); } +function continuation(value, trace) { return value?.x[(trace.push('key'), 'y')].m((trace.push('argument'), 6)); } +function callContinuation(value, trace) { return value.m?.((trace.push('argument'), 7)).x; } +function groupedProperty(value) { return (value?.x).y; } +function groupedMethod(value, trace) { return (value?.m)((trace.push('argument'), 8)); } +function groupedOptionalMethod(value, trace) { return (value?.m)?.((trace.push('argument'), 9)); } +function computedMethod(value, trace) { return value?.[(trace.push('key'), 'm')]?.((trace.push('argument'), 10)); } +function nested(value, trace) { + function collect(a, b, c) { return [a, b, c]; } + return collect('before', [value?.x, (trace.push('middle'), value?.m?.(1))], 'after'); +} +function spread(value, iterable) { return value?.m?.(...iterable); } +function tail(count, value) { return count ? tail?.(count - 1, value + 1) : value; } +function tailUndefined(value) { return value?.m?.(); } +function normalized(value) { return [value?.x === undefined, tailUndefined(value) === undefined, Object.is(value?.x, undefined)]; } +function protectedCall(value, trace) { + try { return value?.m(); } + catch (error) { trace.push(error); return trace?.join(':'); } +} + +function makeObject(mode, trace) { + const object = { + tag: 'receiver', + get x() { + trace.push('get x'); + return mode === 'missing x' ? undefined : { + y: { tag: 'child', m(...args) { trace.push('child call:' + this.tag); return args; } } + }; + }, + get m() { + trace.push('get m'); + if (mode === 'missing m') return undefined; + if (mode === 'noncallable') return 1; + if (mode === 'getter') throw 'getter failure'; + if (mode === 'native') return Array.isArray; + const method = function (...args) { + trace.push('call:' + (this === object)); + if (mode === 'call') throw 'call failure'; + if (mode === 'return object') return { x: args.join(',') }; + return [this === object, args]; + }; + return mode === 'proxy' ? new Proxy(method, {}) : method; + } + }; + return object; +} + +var optionalChainResult = []; +for (let repeat = 0; repeat < 3; repeat++) { + for (const test of [ + [property, 'null'], [property, 'undefined'], [computed, 'null'], [computed, 'normal'], + [method, 'null'], [method, 'normal'], [method, 'missing m'], [method, 'getter'], + [method, 'native'], [method, 'proxy'], + [optionalMethod, 'normal'], [optionalMethod, 'missing m'], [optionalMethod, 'null'], [optionalMethod, 'noncallable'], + [continuation, 'null'], [continuation, 'normal'], [continuation, 'missing x'], + [callContinuation, 'missing m'], [callContinuation, 'return object'], + [groupedProperty, 'null'], [groupedProperty, 'missing x'], + [groupedMethod, 'null'], [groupedMethod, 'normal'], + [groupedOptionalMethod, 'null'], [groupedOptionalMethod, 'normal'], [groupedOptionalMethod, 'missing m'], + [computedMethod, 'null'], [computedMethod, 'normal'], [computedMethod, 'missing m'], + [nested, 'null'], [protectedCall, 'call'], [protectedCall, 'null'], [normalized, 'null'] + ]) { + const trace = []; + const input = test[1] === 'null' ? null : test[1] === 'undefined' ? undefined : makeObject(test[1], trace); + try { optionalChainResult.push([test[0].name, test[1], test[0](input, trace), trace]); } + catch (error) { optionalChainResult.push([test[0].name, test[1], error instanceof Error ? error.name : error, trace]); } + } + for (const value of [null, undefined, 1, function (number) { return [this === undefined, number]; }]) { + const trace = []; + try { optionalChainResult.push(['direct', direct(value, trace), trace]); } + catch (error) { optionalChainResult.push(['direct', error.name, trace]); } + } + for (const mode of ['null', 'missing m', 'normal']) { + const trace = []; + const iterable = { *[Symbol.iterator]() { trace.push('iterate'); yield 1; yield 2; } }; + optionalChainResult.push(['spread', mode, spread(mode === 'null' ? null : makeObject(mode, trace), iterable), trace]); + } + optionalChainResult.push(['tail', tail(20, 0)]); + optionalChainResult.push(['primitive', property(false), computed('', []), 'abc'?.slice?.(1)]); +} diff --git a/tests/Unit/Bytecode/fixtures/optional-chains.json b/tests/Unit/Bytecode/fixtures/optional-chains.json new file mode 100644 index 00000000..de16f393 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/optional-chains.json @@ -0,0 +1,1148 @@ +[ + [ + "property", + "null", + null, + [] + ], + [ + "property", + "undefined", + null, + [] + ], + [ + "computed", + "null", + null, + [] + ], + [ + "computed", + "normal", + { + "y": { + "tag": "child" + } + }, + [ + "key", + "get x" + ] + ], + [ + "method", + "null", + null, + [] + ], + [ + "method", + "normal", + [ + true, + [ + 3 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "method", + "missing m", + "TypeError", + [ + "get m", + "argument" + ] + ], + [ + "method", + "getter", + "getter failure", + [ + "get m" + ] + ], + [ + "method", + "native", + false, + [ + "get m", + "argument" + ] + ], + [ + "method", + "proxy", + [ + true, + [ + 3 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "optionalMethod", + "normal", + [ + true, + [ + 4 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "optionalMethod", + "missing m", + null, + [ + "get m" + ] + ], + [ + "optionalMethod", + "null", + "TypeError", + [] + ], + [ + "optionalMethod", + "noncallable", + "TypeError", + [ + "get m", + "argument" + ] + ], + [ + "continuation", + "null", + null, + [] + ], + [ + "continuation", + "normal", + [ + 6 + ], + [ + "get x", + "key", + "argument", + "child call:child" + ] + ], + [ + "continuation", + "missing x", + "TypeError", + [ + "get x", + "key" + ] + ], + [ + "callContinuation", + "missing m", + null, + [ + "get m" + ] + ], + [ + "callContinuation", + "return object", + "7", + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "groupedProperty", + "null", + "TypeError", + [] + ], + [ + "groupedProperty", + "missing x", + "TypeError", + [ + "get x" + ] + ], + [ + "groupedMethod", + "null", + "TypeError", + [ + "argument" + ] + ], + [ + "groupedMethod", + "normal", + [ + true, + [ + 8 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "groupedOptionalMethod", + "null", + null, + [] + ], + [ + "groupedOptionalMethod", + "normal", + [ + true, + [ + 9 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "groupedOptionalMethod", + "missing m", + null, + [ + "get m" + ] + ], + [ + "computedMethod", + "null", + null, + [] + ], + [ + "computedMethod", + "normal", + [ + true, + [ + 10 + ] + ], + [ + "key", + "get m", + "argument", + "call:true" + ] + ], + [ + "computedMethod", + "missing m", + null, + [ + "key", + "get m" + ] + ], + [ + "nested", + "null", + [ + "before", + [ + null, + null + ], + "after" + ], + [ + "middle" + ] + ], + [ + "protectedCall", + "call", + "get m:call:true:call failure", + [ + "get m", + "call:true", + "call failure" + ] + ], + [ + "protectedCall", + "null", + null, + [] + ], + [ + "normalized", + "null", + [ + true, + true, + true + ], + [] + ], + [ + "direct", + null, + [] + ], + [ + "direct", + null, + [] + ], + [ + "direct", + "TypeError", + [ + "argument" + ] + ], + [ + "direct", + [ + true, + 5 + ], + [ + "argument" + ] + ], + [ + "spread", + "null", + null, + [] + ], + [ + "spread", + "missing m", + null, + [ + "get m" + ] + ], + [ + "spread", + "normal", + [ + true, + [ + 1, + 2 + ] + ], + [ + "get m", + "iterate", + "call:true" + ] + ], + [ + "tail", + 20 + ], + [ + "primitive", + null, + null, + "bc" + ], + [ + "property", + "null", + null, + [] + ], + [ + "property", + "undefined", + null, + [] + ], + [ + "computed", + "null", + null, + [] + ], + [ + "computed", + "normal", + { + "y": { + "tag": "child" + } + }, + [ + "key", + "get x" + ] + ], + [ + "method", + "null", + null, + [] + ], + [ + "method", + "normal", + [ + true, + [ + 3 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "method", + "missing m", + "TypeError", + [ + "get m", + "argument" + ] + ], + [ + "method", + "getter", + "getter failure", + [ + "get m" + ] + ], + [ + "method", + "native", + false, + [ + "get m", + "argument" + ] + ], + [ + "method", + "proxy", + [ + true, + [ + 3 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "optionalMethod", + "normal", + [ + true, + [ + 4 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "optionalMethod", + "missing m", + null, + [ + "get m" + ] + ], + [ + "optionalMethod", + "null", + "TypeError", + [] + ], + [ + "optionalMethod", + "noncallable", + "TypeError", + [ + "get m", + "argument" + ] + ], + [ + "continuation", + "null", + null, + [] + ], + [ + "continuation", + "normal", + [ + 6 + ], + [ + "get x", + "key", + "argument", + "child call:child" + ] + ], + [ + "continuation", + "missing x", + "TypeError", + [ + "get x", + "key" + ] + ], + [ + "callContinuation", + "missing m", + null, + [ + "get m" + ] + ], + [ + "callContinuation", + "return object", + "7", + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "groupedProperty", + "null", + "TypeError", + [] + ], + [ + "groupedProperty", + "missing x", + "TypeError", + [ + "get x" + ] + ], + [ + "groupedMethod", + "null", + "TypeError", + [ + "argument" + ] + ], + [ + "groupedMethod", + "normal", + [ + true, + [ + 8 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "groupedOptionalMethod", + "null", + null, + [] + ], + [ + "groupedOptionalMethod", + "normal", + [ + true, + [ + 9 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "groupedOptionalMethod", + "missing m", + null, + [ + "get m" + ] + ], + [ + "computedMethod", + "null", + null, + [] + ], + [ + "computedMethod", + "normal", + [ + true, + [ + 10 + ] + ], + [ + "key", + "get m", + "argument", + "call:true" + ] + ], + [ + "computedMethod", + "missing m", + null, + [ + "key", + "get m" + ] + ], + [ + "nested", + "null", + [ + "before", + [ + null, + null + ], + "after" + ], + [ + "middle" + ] + ], + [ + "protectedCall", + "call", + "get m:call:true:call failure", + [ + "get m", + "call:true", + "call failure" + ] + ], + [ + "protectedCall", + "null", + null, + [] + ], + [ + "normalized", + "null", + [ + true, + true, + true + ], + [] + ], + [ + "direct", + null, + [] + ], + [ + "direct", + null, + [] + ], + [ + "direct", + "TypeError", + [ + "argument" + ] + ], + [ + "direct", + [ + true, + 5 + ], + [ + "argument" + ] + ], + [ + "spread", + "null", + null, + [] + ], + [ + "spread", + "missing m", + null, + [ + "get m" + ] + ], + [ + "spread", + "normal", + [ + true, + [ + 1, + 2 + ] + ], + [ + "get m", + "iterate", + "call:true" + ] + ], + [ + "tail", + 20 + ], + [ + "primitive", + null, + null, + "bc" + ], + [ + "property", + "null", + null, + [] + ], + [ + "property", + "undefined", + null, + [] + ], + [ + "computed", + "null", + null, + [] + ], + [ + "computed", + "normal", + { + "y": { + "tag": "child" + } + }, + [ + "key", + "get x" + ] + ], + [ + "method", + "null", + null, + [] + ], + [ + "method", + "normal", + [ + true, + [ + 3 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "method", + "missing m", + "TypeError", + [ + "get m", + "argument" + ] + ], + [ + "method", + "getter", + "getter failure", + [ + "get m" + ] + ], + [ + "method", + "native", + false, + [ + "get m", + "argument" + ] + ], + [ + "method", + "proxy", + [ + true, + [ + 3 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "optionalMethod", + "normal", + [ + true, + [ + 4 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "optionalMethod", + "missing m", + null, + [ + "get m" + ] + ], + [ + "optionalMethod", + "null", + "TypeError", + [] + ], + [ + "optionalMethod", + "noncallable", + "TypeError", + [ + "get m", + "argument" + ] + ], + [ + "continuation", + "null", + null, + [] + ], + [ + "continuation", + "normal", + [ + 6 + ], + [ + "get x", + "key", + "argument", + "child call:child" + ] + ], + [ + "continuation", + "missing x", + "TypeError", + [ + "get x", + "key" + ] + ], + [ + "callContinuation", + "missing m", + null, + [ + "get m" + ] + ], + [ + "callContinuation", + "return object", + "7", + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "groupedProperty", + "null", + "TypeError", + [] + ], + [ + "groupedProperty", + "missing x", + "TypeError", + [ + "get x" + ] + ], + [ + "groupedMethod", + "null", + "TypeError", + [ + "argument" + ] + ], + [ + "groupedMethod", + "normal", + [ + true, + [ + 8 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "groupedOptionalMethod", + "null", + null, + [] + ], + [ + "groupedOptionalMethod", + "normal", + [ + true, + [ + 9 + ] + ], + [ + "get m", + "argument", + "call:true" + ] + ], + [ + "groupedOptionalMethod", + "missing m", + null, + [ + "get m" + ] + ], + [ + "computedMethod", + "null", + null, + [] + ], + [ + "computedMethod", + "normal", + [ + true, + [ + 10 + ] + ], + [ + "key", + "get m", + "argument", + "call:true" + ] + ], + [ + "computedMethod", + "missing m", + null, + [ + "key", + "get m" + ] + ], + [ + "nested", + "null", + [ + "before", + [ + null, + null + ], + "after" + ], + [ + "middle" + ] + ], + [ + "protectedCall", + "call", + "get m:call:true:call failure", + [ + "get m", + "call:true", + "call failure" + ] + ], + [ + "protectedCall", + "null", + null, + [] + ], + [ + "normalized", + "null", + [ + true, + true, + true + ], + [] + ], + [ + "direct", + null, + [] + ], + [ + "direct", + null, + [] + ], + [ + "direct", + "TypeError", + [ + "argument" + ] + ], + [ + "direct", + [ + true, + 5 + ], + [ + "argument" + ] + ], + [ + "spread", + "null", + null, + [] + ], + [ + "spread", + "missing m", + null, + [ + "get m" + ] + ], + [ + "spread", + "normal", + [ + true, + [ + 1, + 2 + ] + ], + [ + "get m", + "iterate", + "call:true" + ] + ], + [ + "tail", + 20 + ], + [ + "primitive", + null, + null, + "bc" + ] +] From 4f6d1e913c5f6ba95daefa27ce690f7be45293a7 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:07:22 +0200 Subject: [PATCH 11/99] Bound Hono workers with configurable memory for full DOM inventories --- tests/Frameworks/hono/README.md | 9 +++++++-- tests/Frameworks/hono/run.py | 28 ++++++++++++++++++++++++---- tests/Frameworks/hono/test_runner.py | 23 +++++++++++++++++++++-- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/tests/Frameworks/hono/README.md b/tests/Frameworks/hono/README.md index 3c5a66aa..3c50fa15 100644 --- a/tests/Frameworks/hono/README.md +++ b/tests/Frameworks/hono/README.md @@ -32,9 +32,14 @@ runs both and compares every discovered case's identity and outcome. Each file runs in a separate process, sequentially, with a 1,800 second outer wall limit (`--timeout` overrides it). This lets large files finish hundreds of cases while retaining the original per-test and per-hook deadlines. -The PHP worker uses `XDEBUG_MODE=off`, a 1 GiB memory limit and a one million +The PHP worker uses `XDEBUG_MODE=off`, a 4 GiB memory limit and a one million iteration limit so the unchanged 100,000-entry parser and large-body stress -cases fit. A timeout kills the process group, including compiler children. +cases fit. Override memory with `--php-memory-limit 2G`; positive byte counts +and integer K/M/G suffixes are accepted. The largest jsdom file retains pending +Window initialization callbacks until a real host turn and measured a 2.83 GB +peak. The cap accommodates this peak without inserting extra host turns or +changing any test deadlines. The selected limit is recorded in the run manifest. +A timeout kills the process group, including compiler children. The worker closes host resources after the suite completes, as Vitest does when terminating its worker. This also cleans up servers that upstream runtime tests intentionally leave open. diff --git a/tests/Frameworks/hono/run.py b/tests/Frameworks/hono/run.py index c16554df..82fbbcf2 100644 --- a/tests/Frameworks/hono/run.py +++ b/tests/Frameworks/hono/run.py @@ -7,6 +7,7 @@ from uuid import uuid4 from inventory import inventory as upstream_inventory import os +import re import signal from pathlib import Path import subprocess @@ -92,14 +93,31 @@ def dependency_hash(): return hashlib.sha256((DIRECTORY.parent / 'package-lock.json').read_bytes()).hexdigest() -def main(): +def php_memory_limit(value): + match = re.fullmatch(r'([1-9][0-9]*)([KMG]?)', value, re.IGNORECASE) + if match is None: + raise argparse.ArgumentTypeError('Use a positive byte count or an integer with K, M or G, for example 4G') + suffix = match[2].upper() + multiplier = {'': 1, 'K': 1024, 'M': 1024 ** 2, 'G': 1024 ** 3}[suffix] + if len(match[1]) > len(str(sys.maxsize)) or int(match[1]) * multiplier > sys.maxsize: + raise argparse.ArgumentTypeError('The memory limit exceeds the platform integer range') + return match[1] + suffix + + +def parse_arguments(arguments=None): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('files', nargs='*') parser.add_argument('--timeout', type=float, default=1800) parser.add_argument('--project', choices=['main', 'jsx-runtime-default', 'jsx-runtime-dom', 'node'], default='main') parser.add_argument('--runtime', choices=['node', 'phasis', 'both'], default='both') parser.add_argument('--no-build', action='store_true') - args = parser.parse_args() + parser.add_argument('--php-memory-limit', type=php_memory_limit, default='4G', + help='Bounded PHP worker memory, in bytes or K/M/G notation (default: 4G)') + return parser, parser.parse_args(arguments) + + +def main(): + parser, args = parse_arguments() all_projects = upstream_inventory() project = all_projects['projects'][args.project] inventory = project.get('runtimeFiles', project['files']) @@ -119,7 +137,8 @@ def main(): metadata = {'id': run_id, 'upstream': UPSTREAM_METADATA, 'project': args.project, 'inventory': inventory, 'upstreamProjects': all_projects, 'selected': files, 'runtimes': args.runtime, - 'timeoutSeconds': args.timeout, 'runtimeSourceAtStart': source_hash(REPOSITORY / 'src'), + 'timeoutSeconds': args.timeout, 'phpMemoryLimit': args.php_memory_limit, + 'runtimeSourceAtStart': source_hash(REPOSITORY / 'src'), 'harnessSourceAtStart': harness_hash(), 'dependenciesAtStart': dependency_hash(), 'complete': False, 'files': manifest} @@ -151,7 +170,8 @@ def save_manifest(): if args.project != 'main': generated /= args.project script = str(generated / (identifier + '.mjs')) - command = ['node', script] if runtime == 'node' else ['php', '-d', 'memory_limit=1G', str(DIRECTORY / 'run-php.php'), script] + command = ['node', script] if runtime == 'node' else [ + 'php', '-d', 'memory_limit=' + args.php_memory_limit, str(DIRECTORY / 'run-php.php'), script] started = time.monotonic() status, output = execute(command, args.timeout, args.project, archive / (identifier + '-' + runtime + '.log')) diff --git a/tests/Frameworks/hono/test_runner.py b/tests/Frameworks/hono/test_runner.py index e06c22ed..dd56d276 100644 --- a/tests/Frameworks/hono/test_runner.py +++ b/tests/Frameworks/hono/test_runner.py @@ -1,10 +1,29 @@ -"""Verify that Hono workers cannot leave owned processes behind.""" +"""Verify bounded Hono worker options and process cleanup.""" +import contextlib +import io import os import sys import time import unittest -from run import execute +from run import execute, parse_arguments + + +class WorkerMemoryTest(unittest.TestCase): + def test_default_and_explicit_memory_limits(self): + _, default = parse_arguments([]) + self.assertEqual(default.php_memory_limit, '4G') + for source, expected in [('512m', '512M'), ('2G', '2G'), ('1024K', '1024K'), ('4096', '4096')]: + with self.subTest(source=source): + _, selected = parse_arguments(['--php-memory-limit', source]) + self.assertEqual(selected.php_memory_limit, expected) + + def test_unbounded_invalid_and_overflowing_limits_are_rejected(self): + for value in ['-1', '0', '4GB', '4.5G', 'unlimited', '2G ', str(sys.maxsize) + 'G', '9' * 5000]: + with self.subTest(value=value), contextlib.redirect_stderr(io.StringIO()): + with self.assertRaises(SystemExit) as error: + parse_arguments(['--php-memory-limit', value]) + self.assertEqual(error.exception.code, 2) class WorkerCleanupTest(unittest.TestCase): From 59890c23d3339073f6fc1ef2b3f6e0473394b18b Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:07:22 +0200 Subject: [PATCH 12/99] Model weak-reference liveness across collection in prototype tests --- tests/Unit/Runtime/LazyFunctionPrototypeTest.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/Unit/Runtime/LazyFunctionPrototypeTest.php b/tests/Unit/Runtime/LazyFunctionPrototypeTest.php index 91970e8d..71f34c67 100644 --- a/tests/Unit/Runtime/LazyFunctionPrototypeTest.php +++ b/tests/Unit/Runtime/LazyFunctionPrototypeTest.php @@ -79,11 +79,20 @@ public function testAnEscapedPrototypeKeepsItsConstructorAlive(): void unset($function); gc_collect_cycles(); - self::assertTrue($reference->get() !== null, 'The constructor property must retain its function strongly.'); - self::assertSame($reference->get(), $prototype->get('constructor')); + self::assertTrue(self::readFunctionReference($reference) !== null, 'The constructor must retain its function.'); + self::assertSame(self::readFunctionReference($reference), $prototype->get('constructor')); unset($prototype); gc_collect_cycles(); - self::assertTrue($reference->get() === null, 'The materialized cycle must remain collectable.'); + self::assertTrue(self::readFunctionReference($reference) === null, 'The cycle must remain collectable.'); + } + + /** + * @param \WeakReference $reference + * @phpstan-impure + */ + private static function readFunctionReference(\WeakReference $reference): ?JsFunction + { + return $reference->get(); } public function testRawDescriptorCopyContainsTheRealPrototype(): void From 7710866a11e42917577002f19e2fd306fe5a9cfa Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:11:31 +0200 Subject: [PATCH 13/99] Preserve proxy traps and receivers for symbol writes --- src/BuiltIn/ReflectObject.php | 73 +- src/Value/JsObject.php | 65 +- src/Value/JsProxy.php | 22 +- tests/Unit/Runtime/ProxySymbolSetTest.php | 39 + .../Unit/Runtime/fixtures/proxy-symbol-set.js | 130 ++++ .../Runtime/fixtures/proxy-symbol-set.json | 704 ++++++++++++++++++ 6 files changed, 914 insertions(+), 119 deletions(-) create mode 100644 tests/Unit/Runtime/ProxySymbolSetTest.php create mode 100644 tests/Unit/Runtime/fixtures/proxy-symbol-set.js create mode 100644 tests/Unit/Runtime/fixtures/proxy-symbol-set.json diff --git a/src/BuiltIn/ReflectObject.php b/src/BuiltIn/ReflectObject.php index 1324620b..d2147c85 100644 --- a/src/BuiltIn/ReflectObject.php +++ b/src/BuiltIn/ReflectObject.php @@ -73,17 +73,7 @@ public static function install(Environment $env): void $propKey = TypeConversion::toPropertyKey($key); if ($propKey instanceof JsSymbol) { - // Proxy symbol-keyed [[Set]] runs through the proxy's set - // trap (and its invariant validation). Falling through to - // ordinarySetSymbol would bypass the trap and lose the - // post-trap invariant checks (e.g. nw/nc data property). - if ($target instanceof \Phasis\Value\JsProxy) { - $target->setBySymbol($propKey, $value); - return new JsBoolean(true); - } - return new JsBoolean( - self::ordinarySetSymbol($target, $propKey, $value, $receiver) - ); + return new JsBoolean($target->setBySymbolWithValueReceiver($propKey, $value, $receiver)); } // Typed-array exotic [[Set]]: for a CanonicalNumericIndexString // we delegate to the typed array's [[Set]] when the receiver is @@ -703,67 +693,6 @@ private static function sameValue(JsValue $a, JsValue $b): bool return false; } - /** - * OrdinarySet for symbol-keyed properties with receiver support. - * - * Mirrors the OrdinarySetWithOwnDescriptor algorithm for symbol keys. - */ - private static function ordinarySetSymbol( - JsObject $target, - JsSymbol $key, - JsValue $value, - JsValue $receiver, - ): bool { - $ownDesc = $target->getSymbolPropertyDescriptor($key); - - if ($ownDesc === null) { - // Walk prototype chain. - $parent = $target->getPrototype(); - if ($parent !== null) { - return self::ordinarySetSymbol($parent, $key, $value, $receiver); - } - // No own, no parent: create writable data descriptor on receiver. - $ownDesc = PropertyDescriptor::data(JsUndefined::instance()); - } - - if ($ownDesc->isDataDescriptor()) { - if ($ownDesc->writable === false) { - return false; - } - if (!$receiver instanceof JsObject) { - return false; - } - $existingDesc = $receiver->getSymbolPropertyDescriptor($key); - if ($existingDesc !== null) { - if ($existingDesc->isAccessorDescriptor()) { - return false; - } - if ($existingDesc->writable === false) { - return false; - } - $receiver->definePropertyBySymbol($key, new PropertyDescriptor( - value: $value, - writable: $existingDesc->writable, - enumerable: $existingDesc->enumerable, - configurable: $existingDesc->configurable, - )); - return true; - } - if (!$receiver->isExtensible()) { - return false; - } - $receiver->definePropertyBySymbol($key, PropertyDescriptor::data($value)); - return true; - } - - // Accessor descriptor. - if ($ownDesc->set !== null) { - $ownDesc->set->call($receiver instanceof JsObject ? $receiver : $target, [$value]); - return true; - } - return false; - } - /** Validate that the first argument is an object. */ /** * @param array $args diff --git a/src/Value/JsObject.php b/src/Value/JsObject.php index db97f0d1..524fd7eb 100644 --- a/src/Value/JsObject.php +++ b/src/Value/JsObject.php @@ -513,55 +513,40 @@ public function defineOwnSymbolProperty(JsSymbol $symbol, PropertyDescriptor $de */ public function internalSetBySymbol(JsSymbol $symbol, JsValue $value, JsObject $receiver): bool { - $id = $symbol->getId(); - if (isset($this->symbolProperties[$id])) { - $desc = $this->symbolProperties[$id]; - if ($desc->set !== null) { - $desc->set->call($receiver, [$value]); - return true; - } - if ($desc->isAccessorDescriptor()) { - return false; - } - if ($desc->writable === false) { - return false; - } - // Per OrdinarySet: if the property is found on the receiver itself, - // update it in place. If found on a prototype, create a new own - // property on the receiver (do not mutate the prototype descriptor). - if ($this === $receiver) { - $desc->value = $value; - return true; + return $this->setBySymbolWithValueReceiver($symbol, $value, $receiver); + } + + /** Ordinary [[Set]] for a symbol key, preserving receiver exotic operations. */ + public function setBySymbolWithValueReceiver(JsSymbol $symbol, JsValue $value, JsValue $receiver): bool + { + $descriptor = $this->getSymbolPropertyDescriptor($symbol); + if ($descriptor === null) { + $prototype = $this->getPrototype(); + if ($prototype !== null) { + return $prototype->setBySymbolWithValueReceiver($symbol, $value, $receiver); } - // Found writable data on prototype: create own property on receiver. - if (!$receiver->extensible) { + $descriptor = PropertyDescriptor::data(JsUndefined::instance()); + } + if ($descriptor->isDataDescriptor()) { + if ($descriptor->writable === false || !$receiver instanceof JsObject) { return false; } - // Check if receiver already has its own symbol property. - if (isset($receiver->symbolProperties[$id])) { - $receiverDesc = $receiver->symbolProperties[$id]; - if ($receiverDesc->isAccessorDescriptor()) { - return false; - } - if ($receiverDesc->writable === false) { + // The receiver may be a Proxy. Read its own descriptor and define + // the value through its internal methods instead of writing into + // the proxy object's otherwise invisible symbol storage. + $existing = $receiver->getSymbolPropertyDescriptor($symbol); + if ($existing !== null) { + if ($existing->isAccessorDescriptor() || $existing->writable === false) { return false; } - $receiverDesc->value = $value; - return true; + return $receiver->definePropertyBySymbol($symbol, new PropertyDescriptor(value: $value)); } - $receiver->symbolProperties[$id] = PropertyDescriptor::data($value); - $receiver->symbolOrder[$id] = $symbol; - return true; - } - $proto = $this->getPrototype(); - if ($proto !== null) { - return $proto->internalSetBySymbol($symbol, $value, $receiver); + return $receiver->definePropertyBySymbol($symbol, PropertyDescriptor::data($value)); } - if (!$receiver->extensible) { + if ($descriptor->set === null) { return false; } - $receiver->symbolProperties[$id] = PropertyDescriptor::data($value); - $receiver->symbolOrder[$id] = $symbol; + $descriptor->set->call($receiver, [$value]); return true; } diff --git a/src/Value/JsProxy.php b/src/Value/JsProxy.php index 794cf82b..24286fce 100644 --- a/src/Value/JsProxy.php +++ b/src/Value/JsProxy.php @@ -1423,21 +1423,29 @@ public function getBySymbolWithReceiver(JsSymbol $symbol, JsValue $receiver): Js } public function setBySymbol(JsSymbol $symbol, JsValue $value, bool $strict = false): void + { + if (!$this->setBySymbolWithValueReceiver($symbol, $value, $this) && $strict) { + $key = self::formatKeyForError($symbol); + throw new TypeError("'set' on proxy: trap returned falsish for property {$key}"); + } + } + + /** Symbol [[Set]] preserves the receiver through the trap and target fallback. */ + public function setBySymbolWithValueReceiver(JsSymbol $symbol, JsValue $value, JsValue $receiver): bool { $this->assertNotRevoked('set'); $target = $this->target; $handler = $this->handler; $trap = $this->getTrap('set'); if ($trap !== null) { - $result = $trap->call($handler, [$target, $symbol, $value, $this]); - $boolean = \Phasis\Spec\TypeConversion::toBoolean($result); - if ($boolean) { - // Validate invariants per spec 10.5.9 step 14. - $this->validateSetInvariants($symbol, $value, $target); + $result = $trap->call($handler, [$target, $symbol, $value, $receiver]); + if (!\Phasis\Spec\TypeConversion::toBoolean($result)) { + return false; } - return; + $this->validateSetInvariants($symbol, $value, $target); + return true; } - $target->setBySymbol($symbol, $value); + return $target->setBySymbolWithValueReceiver($symbol, $value, $receiver); } public function hasBySymbol(JsSymbol $symbol): bool diff --git a/tests/Unit/Runtime/ProxySymbolSetTest.php b/tests/Unit/Runtime/ProxySymbolSetTest.php new file mode 100644 index 00000000..5b96f6c3 --- /dev/null +++ b/tests/Unit/Runtime/ProxySymbolSetTest.php @@ -0,0 +1,39 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/proxy-symbol-set.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/proxy-symbol-set.json', + $engine->eval('JSON.stringify(proxySymbolSetResult)'), + ); + $function = $engine->getGlobalEnv()->get('writeSymbol'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + } + + public function testInterpretedSymbolWritesMatchTheSameNodeOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/proxy-symbol-set.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/proxy-symbol-set.json', + $engine->eval('JSON.stringify(proxySymbolSetResult)'), + ); + $function = $engine->getGlobalEnv()->get('writeSymbol'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled); + } +} diff --git a/tests/Unit/Runtime/fixtures/proxy-symbol-set.js b/tests/Unit/Runtime/fixtures/proxy-symbol-set.js new file mode 100644 index 00000000..269fa080 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/proxy-symbol-set.js @@ -0,0 +1,130 @@ +'use strict'; + +function writeSymbol(target, key, value) { target[key] = value; return value; } +function readSymbol(target, key) { return target[key]; } +function outcome(action) { + try { return action(); } + catch (error) { return error.name; } +} + +var proxySymbolSetResult = []; +for (let repeat = 0; repeat < 3; repeat++) { + const key = Symbol('cache'); + const trace = []; + const target = {}; + const wrapper = new Proxy(target, { + set(object, property, value, receiver) { + trace.push(['set', property === key, receiver === wrapper]); + return Reflect.set(object, property, value, receiver); + }, + getOwnPropertyDescriptor(object, property) { + trace.push(['own', property === key]); + return Reflect.getOwnPropertyDescriptor(object, property); + }, + defineProperty(object, property, descriptor) { + trace.push(['define', property === key, Object.keys(descriptor).sort()]); + return Reflect.defineProperty(object, property, descriptor); + } + }); + writeSymbol(wrapper, key, 1); + writeSymbol(wrapper, key, 2); + proxySymbolSetResult.push(['normal', readSymbol(wrapper, key), target[key], trace]); + + const receiverTarget = {}; + const receiverTrace = []; + const receiver = new Proxy(receiverTarget, { + isExtensible() { throw new Error('Unexpected extensibility query'); }, + getOwnPropertyDescriptor(object, property) { + receiverTrace.push('own'); + return Reflect.getOwnPropertyDescriptor(object, property); + }, + defineProperty(object, property, descriptor) { + receiverTrace.push(['define', Object.keys(descriptor).sort()]); + return Reflect.defineProperty(object, property, descriptor); + } + }); + proxySymbolSetResult.push(['receiver', Reflect.set(target, key, 3, receiver), + Reflect.set(new Proxy(target, {}), key, 4, receiver), receiverTarget[key], target[key], receiverTrace]); + + const nestedTarget = {}; + const nested = new Proxy(new Proxy(nestedTarget, {}), {}); + writeSymbol(nested, key, 5); + proxySymbolSetResult.push(['nested fallback', nested[key], nestedTarget[key]]); + + const denied = new Proxy({}, { set() { return false; } }); + proxySymbolSetResult.push(['false set', Reflect.set(denied, key, 1), + outcome(() => writeSymbol(denied, key, 2)), + Function('target', 'key', 'return target[key] = 3')(denied, key), + outcome(() => Object.assign(denied, { [key]: 4 }))]); + const defineDenied = new Proxy({}, { defineProperty() { return false; } }); + proxySymbolSetResult.push(['false define', Reflect.set(defineDenied, key, 1), + outcome(() => writeSymbol(defineDenied, key, 2))]); + + const primitives = [undefined, null, 3, false, 'receiver', key]; + const primitiveResults = []; + for (const primitive of primitives) { + const ordinary = {}; + const proxy = new Proxy(ordinary, {}); + const setterTrace = []; + const accessor = Object.create(null, { + [key]: { set(value) { setterTrace.push([this === primitive, value]); } } + }); + primitiveResults.push([Reflect.set(proxy, key, 1, primitive), ordinary[key], + Reflect.set(new Proxy(accessor, {}), key, 2, primitive), + Reflect.set(accessor, key, 3, primitive), setterTrace]); + } + proxySymbolSetResult.push(['primitive receivers', primitiveResults]); + + const inheritedTrace = []; + const inherited = new Proxy({}, { + set(object, property, value, receiver) { + inheritedTrace.push([property === key, receiver === child]); + return Reflect.set(object, property, value, receiver); + } + }); + const child = Object.create(inherited); + writeSymbol(child, key, 8); + proxySymbolSetResult.push(['prototype proxy', child[key], Reflect.ownKeys(child).length, + Reflect.ownKeys(inherited).length, inheritedTrace]); + + const receiverReadOnly = Object.defineProperty({}, key, { value: 1 }); + const receiverAccessor = Object.defineProperty({}, key, { set() { throw 'unexpected setter'; } }); + proxySymbolSetResult.push(['receiver restrictions', + Reflect.set({}, key, 2, receiverReadOnly), + Reflect.set({}, key, 2, receiverAccessor), + Reflect.set({}, key, 2, Object.preventExtensions({})), + receiverReadOnly[key]]); + + const explicitReceiver = {}; + const receiverChecks = []; + const checkReceiver = new Proxy({}, { set(object, property, value, passed) { + receiverChecks.push(passed === explicitReceiver); + return true; + } }); + Reflect.set(checkReceiver, key, 1, explicitReceiver); + proxySymbolSetResult.push(['trap receiver', receiverChecks]); + + const frozen = Object.defineProperty({}, key, { value: NaN }); + const frozenProxy = new Proxy(frozen, { set() { return true; } }); + const getter = Object.defineProperty({}, key, { get() { return 1; } }); + proxySymbolSetResult.push(['invariants', Reflect.set(frozenProxy, key, NaN), + outcome(() => Reflect.set(frozenProxy, key, 1)), + outcome(() => Reflect.set(new Proxy(getter, { set() { return true; } }), key, 1))]); + + const revoked = Proxy.revocable({}, {}); + revoked.revoke(); + proxySymbolSetResult.push(['revoked', outcome(() => writeSymbol(revoked.proxy, key, 1)), + outcome(() => Reflect.set(revoked.proxy, key, 2))]); + const selfRevoked = Proxy.revocable(frozen, { set() { selfRevoked.revoke(); return true; } }); + proxySymbolSetResult.push(['revoked by trap', outcome(() => Reflect.set(selfRevoked.proxy, key, 1))]); + + const thrown = []; + for (const handler of [ + { getOwnPropertyDescriptor() { throw new RangeError('own'); } }, + { defineProperty() { throw new SyntaxError('define'); } }, + { set: 1 } + ]) { + thrown.push(outcome(() => Reflect.set(new Proxy({}, handler), key, 1))); + } + proxySymbolSetResult.push(['abrupt traps', thrown]); +} diff --git a/tests/Unit/Runtime/fixtures/proxy-symbol-set.json b/tests/Unit/Runtime/fixtures/proxy-symbol-set.json new file mode 100644 index 00000000..08175f73 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/proxy-symbol-set.json @@ -0,0 +1,704 @@ +[ + [ + "normal", + 2, + 2, + [ + [ + "set", + true, + true + ], + [ + "own", + true + ], + [ + "define", + true, + [ + "configurable", + "enumerable", + "value", + "writable" + ] + ], + [ + "set", + true, + true + ], + [ + "own", + true + ], + [ + "define", + true, + [ + "value" + ] + ] + ] + ], + [ + "receiver", + true, + true, + 4, + 2, + [ + "own", + [ + "define", + [ + "configurable", + "enumerable", + "value", + "writable" + ] + ], + "own", + [ + "define", + [ + "value" + ] + ] + ] + ], + [ + "nested fallback", + 5, + 5 + ], + [ + "false set", + false, + "TypeError", + 3, + "TypeError" + ], + [ + "false define", + false, + "TypeError" + ], + [ + "primitive receivers", + [ + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ] + ] + ], + [ + "prototype proxy", + 8, + 1, + 0, + [ + [ + true, + true + ] + ] + ], + [ + "receiver restrictions", + false, + false, + false, + 1 + ], + [ + "trap receiver", + [ + true + ] + ], + [ + "invariants", + true, + "TypeError", + "TypeError" + ], + [ + "revoked", + "TypeError", + "TypeError" + ], + [ + "revoked by trap", + "TypeError" + ], + [ + "abrupt traps", + [ + "RangeError", + "SyntaxError", + "TypeError" + ] + ], + [ + "normal", + 2, + 2, + [ + [ + "set", + true, + true + ], + [ + "own", + true + ], + [ + "define", + true, + [ + "configurable", + "enumerable", + "value", + "writable" + ] + ], + [ + "set", + true, + true + ], + [ + "own", + true + ], + [ + "define", + true, + [ + "value" + ] + ] + ] + ], + [ + "receiver", + true, + true, + 4, + 2, + [ + "own", + [ + "define", + [ + "configurable", + "enumerable", + "value", + "writable" + ] + ], + "own", + [ + "define", + [ + "value" + ] + ] + ] + ], + [ + "nested fallback", + 5, + 5 + ], + [ + "false set", + false, + "TypeError", + 3, + "TypeError" + ], + [ + "false define", + false, + "TypeError" + ], + [ + "primitive receivers", + [ + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ] + ] + ], + [ + "prototype proxy", + 8, + 1, + 0, + [ + [ + true, + true + ] + ] + ], + [ + "receiver restrictions", + false, + false, + false, + 1 + ], + [ + "trap receiver", + [ + true + ] + ], + [ + "invariants", + true, + "TypeError", + "TypeError" + ], + [ + "revoked", + "TypeError", + "TypeError" + ], + [ + "revoked by trap", + "TypeError" + ], + [ + "abrupt traps", + [ + "RangeError", + "SyntaxError", + "TypeError" + ] + ], + [ + "normal", + 2, + 2, + [ + [ + "set", + true, + true + ], + [ + "own", + true + ], + [ + "define", + true, + [ + "configurable", + "enumerable", + "value", + "writable" + ] + ], + [ + "set", + true, + true + ], + [ + "own", + true + ], + [ + "define", + true, + [ + "value" + ] + ] + ] + ], + [ + "receiver", + true, + true, + 4, + 2, + [ + "own", + [ + "define", + [ + "configurable", + "enumerable", + "value", + "writable" + ] + ], + "own", + [ + "define", + [ + "value" + ] + ] + ] + ], + [ + "nested fallback", + 5, + 5 + ], + [ + "false set", + false, + "TypeError", + 3, + "TypeError" + ], + [ + "false define", + false, + "TypeError" + ], + [ + "primitive receivers", + [ + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ], + [ + false, + null, + true, + true, + [ + [ + true, + 2 + ], + [ + true, + 3 + ] + ] + ] + ] + ], + [ + "prototype proxy", + 8, + 1, + 0, + [ + [ + true, + true + ] + ] + ], + [ + "receiver restrictions", + false, + false, + false, + 1 + ], + [ + "trap receiver", + [ + true + ] + ], + [ + "invariants", + true, + "TypeError", + "TypeError" + ], + [ + "revoked", + "TypeError", + "TypeError" + ], + [ + "revoked by trap", + "TypeError" + ], + [ + "abrupt traps", + [ + "RangeError", + "SyntaxError", + "TypeError" + ] + ] +] From c4a798c7120379429157828fca7ccb540f4d2c3a Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:10:03 +0200 Subject: [PATCH 14/99] Compile reference-preserving updates to environment bindings --- src/Bytecode/Op.php | 2 + src/Bytecode/Parts/CompilerExpression.php | 10 +- src/Bytecode/VM.php | 9 ++ src/Runtime/Parts/ExpressionEvaluation.php | 56 +++++----- tests/Unit/Bytecode/UpdateBindingTest.php | 66 ++++++++++++ .../Unit/Bytecode/fixtures/update-bindings.js | 102 ++++++++++++++++++ .../Bytecode/fixtures/update-bindings.json | 1 + 7 files changed, 209 insertions(+), 37 deletions(-) create mode 100644 tests/Unit/Bytecode/UpdateBindingTest.php create mode 100644 tests/Unit/Bytecode/fixtures/update-bindings.js create mode 100644 tests/Unit/Bytecode/fixtures/update-bindings.json diff --git a/src/Bytecode/Op.php b/src/Bytecode/Op.php index 9667c9ea..f897b94a 100644 --- a/src/Bytecode/Op.php +++ b/src/Bytecode/Op.php @@ -181,6 +181,7 @@ final class Op public const TYPEOF_NAME = 112; // N: typeof a binding, allowing unresolvable names but preserving TDZ. public const DELETE_NAME = 113; // N: delete an environment binding without reading its value. public const DELETE_PROPERTY = 114; // pop key and base, delete the property, push the Boolean result. + public const UPDATE_NAME = 115; // N I I: resolve a binding once, update by +/-1, push prefix/postfix result. public const LOOP_INIT = 120; public const LOOP_TICK = 121; @@ -280,6 +281,7 @@ public static function operandCount(int $op): int case self::NEW_REGEXP: return 2; // 3-operand opcodes + case self::UPDATE_NAME: case self::JUMP_IF_LOCAL_GE_CONST: case self::JUMP_IF_LOCAL_GE_LOCAL: case self::JUMP_IF_LOCAL_GT_LOCAL: diff --git a/src/Bytecode/Parts/CompilerExpression.php b/src/Bytecode/Parts/CompilerExpression.php index 82687646..7666309c 100644 --- a/src/Bytecode/Parts/CompilerExpression.php +++ b/src/Bytecode/Parts/CompilerExpression.php @@ -366,7 +366,7 @@ private function compileUpdate(UpdateExpression $node): void if ($name === 'eval' || $name === 'arguments') { throw new CompilerBailout('update eval/arguments'); } - if (isset($this->localSlots[$name])) { + if (isset($this->localSlots[$name]) && !isset($this->capturedLocals[$name])) { $slot = $this->localSlots[$name]; if (isset($this->constSlots[$slot])) { throw new CompilerBailout('update of const'); @@ -395,10 +395,10 @@ private function compileUpdate(UpdateExpression $node): void $this->emitStoreLocal($slot); return; } - // Free variable: bail to tree-walker (Reference path is - // spec-correct for Update on names that may resolve via - // a with-environment etc.). - throw new CompilerBailout('update free var'); + // Keep reference resolution and coercion in one instruction so + // getters or ToNumeric cannot redirect the eventual write. + $this->emit(Op::UPDATE_NAME, $this->internName($name), (int) $isInc, (int) $node->prefix); + return; } // Member targets (`o.x++`, `o[k]++`) come in a later phase. throw new CompilerBailout('update non-identifier'); diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 35a11247..8e9ed4c4 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -923,6 +923,15 @@ public function execute( $env->set($names[$code[$pc + 1]], $stack[--$sp], $strict); $pc += 2; break; + case Op::UPDATE_NAME: + $stack[$sp++] = $this->interp->vmUpdateName( + $env, + $names[$code[$pc + 1]], + (bool) $code[$pc + 2], + (bool) $code[$pc + 3], + ); + $pc += 4; + break; case Op::DEFINE_NAME: $env->defineVar($names[$code[$pc + 1]], $stack[--$sp]); $pc += 2; diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index e082d9bd..035fb32b 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -904,28 +904,8 @@ private function evalUpdateExpression(UpdateExpression $node, Environment $env): } } - // Fast path: `i++` / `++i` / `i--` / `--i` on a plain Identifier - // when there is no with-environment reachable from the current - // chain (covers both currently-active with statements and - // with-envs captured by an enclosing closure). Skips the - // Reference allocation, the deferred-key path, and the with- - // trap dance for the case that dominates loop counters. - if ( - $node->argument instanceof Identifier - && $this->withEnvObjects === [] - && $node->argument->name !== 'undefined' - && !$env->hasAnyWithObjectInChain() - ) { - $name = $node->argument->name; - $current = $env->get($name, $this->strictMode); - if ($current instanceof JsNumber) { - $delta = $node->operator === '++' ? 1.0 : -1.0; - $newValue = JsNumber::of($current->value + $delta); - $env->set($name, $newValue, $this->strictMode); - return $node->prefix ? $newValue : $current; - } - // Non-number paths (BigInt, ToNumeric coercion) fall through - // to the spec path below. + if ($node->argument instanceof Identifier) { + return $this->vmUpdateName($env, $node->argument->name, $node->operator === '++', $node->prefix); } $ref = $this->resolveReference($node->argument, $env); @@ -943,31 +923,43 @@ private function evalUpdateExpression(UpdateExpression $node, Environment $env): ); } - // Use ToNumeric (not ToNumber) so BigInt values are preserved. - // Use withGetBindingValue for spec-correct HasProperty trap order. - $oldNumeric = TypeConversion::toNumeric($this->withGetBindingValue($ref)); + return $this->updateReferenceValue($ref, $node->operator === '++', $node->prefix); + } + + /** Update an identifier through its original reference, shared by the VM and interpreter. */ + public function vmUpdateName(Environment $env, string $name, bool $increment, bool $prefix): JsValue + { + return $this->updateReferenceValue($this->resolveIdentifierReference($env, $name), $increment, $prefix); + } + + private function updateReferenceValue(Reference $ref, bool $increment, bool $prefix): JsValue + { + // GetValue must run exactly once, before any user-defined numeric + // conversion, while PutValue retains the originally resolved base. + $current = $this->withGetBindingValue($ref); + $oldNumeric = $current instanceof JsNumber ? $current : TypeConversion::toNumeric($current); if ($oldNumeric instanceof JsBigInt) { // BigInt::add(oldValue, BigInt::unit) per spec. $decVal = $this->bigIntToDecimal($oldNumeric->value); - $delta = $node->operator === '++' ? '1' : '-1'; + $delta = $increment ? '1' : '-1'; $raw = self::bigStrBcAdd($decVal, $delta); if ($raw === '-0') { $raw = '0'; } $newValue = new JsBigInt($raw); $this->withSetMutableBindingCheck($ref, $newValue); - return $node->prefix ? $newValue : $oldNumeric; + return $prefix ? $newValue : $oldNumeric; } - $oldValue = JsNumber::of( - $oldNumeric instanceof JsNumber ? $oldNumeric->value : TypeConversion::toNumber($oldNumeric), - ); - $delta = $node->operator === '++' ? 1.0 : -1.0; + $oldValue = $oldNumeric instanceof JsNumber + ? $oldNumeric + : JsNumber::of(TypeConversion::toNumber($oldNumeric)); + $delta = $increment ? 1.0 : -1.0; $newValue = JsNumber::of($oldValue->value + $delta); $this->withSetMutableBindingCheck($ref, $newValue); - return $node->prefix ? $newValue : $oldValue; + return $prefix ? $newValue : $oldValue; } private function evalAssignment(AssignmentExpression $node, Environment $env): JsValue diff --git a/tests/Unit/Bytecode/UpdateBindingTest.php b/tests/Unit/Bytecode/UpdateBindingTest.php new file mode 100644 index 00000000..817d46c6 --- /dev/null +++ b/tests/Unit/Bytecode/UpdateBindingTest.php @@ -0,0 +1,66 @@ +compileProgram((new Parser($source))->parse()); + self::assertContains(Op::UPDATE_NAME, $compiled->code); + self::assertSame([5, 7, 7, 5, 5, [1, 2, 3, 4, 5]], (new Engine())->eval($source)); + } + + public function testCompiledBindingUpdatesMatchTheNodeOracle(): void + { + $engine = $this->checkOracle(false); + foreach ([ + 'postIncrement', 'preIncrement', 'postDecrement', 'preDecrement', 'strictIncrement', + 'unknownIncrement', 'updateCaptured', 'updateConstant', 'updateDeadZone', + ] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise the bytecode path.'); + self::assertContains(Op::UPDATE_NAME, $function->compiled->code, $name); + } + } + + public function testInterpreterBindingUpdatesMatchTheSameNodeOracle(): void + { + $engine = $this->checkOracle(true); + $function = $engine->getGlobalEnv()->get('postIncrement'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled); + } + + private function checkOracle(bool $interpreter): Engine + { + $engine = new Engine(); + if ($interpreter) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/update-bindings.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/update-bindings.json', + $engine->eval('JSON.stringify(updateBindingResult)'), + ); + + return $engine; + } +} diff --git a/tests/Unit/Bytecode/fixtures/update-bindings.js b/tests/Unit/Bytecode/fixtures/update-bindings.js new file mode 100644 index 00000000..7914050f --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/update-bindings.js @@ -0,0 +1,102 @@ +globalThis.updateValue = undefined; +function postIncrement() { return updateValue++; } +function preIncrement() { return ++updateValue; } +function postDecrement() { return updateValue--; } +function preDecrement() { return --updateValue; } +function strictIncrement() { 'use strict'; return updateValue++; } +function unknownIncrement() { return missingUpdateBinding++; } +function updateCaptured(value) { + function read() { return value; } + var before = value++; + return [before, read(), --value, read()]; +} +function updateConstant() { return constantUpdateBinding++; } +function updateDeadZone() { return deadUpdateBinding++; } +function encodeUpdate(value) { + if (typeof value === 'bigint') return String(value) + 'n'; + if (typeof value === 'number') { + if (Object.is(value, -0)) return '-0'; + if (!Number.isFinite(value)) return String(value); + } + if (value === undefined) return 'undefined'; + return value; +} +function observeUpdate(action) { + try { return ['return', encodeUpdate(action())]; } + catch (error) { return ['throw', error.name]; } +} +const updateResults = []; +const updateTrace = []; +const updateOperations = [postIncrement, preIncrement, postDecrement, preDecrement]; +const updateInputs = [0, -0, 2.5, NaN, Infinity, -Infinity, true, false, null, undefined, + '12', '-0', '', 'nonnumeric', BigInt('9007199254740993'), Symbol('update')]; +for (let pass = 0; pass < 2; pass++) { + for (const operation of updateOperations) { + for (const input of updateInputs) { + updateValue = input; + updateResults.push([operation.name, observeUpdate(operation), encodeUpdate(updateValue)]); + } + updateValue = { [Symbol.toPrimitive](hint) { updateTrace.push(hint); return BigInt('7'); } }; + updateResults.push([observeUpdate(operation), encodeUpdate(updateValue)]); + updateValue = { valueOf() { updateTrace.push('valueOf'); return '9'; } }; + updateResults.push([observeUpdate(operation), encodeUpdate(updateValue)]); + } + updateResults.push(updateCaptured('6').map(encodeUpdate), updateCaptured(BigInt('9')).map(encodeUpdate)); + updateResults.push(observeUpdate(unknownIncrement)); + updateResults.push(observeUpdate(updateDeadZone)); +} +let deadUpdateBinding = 4; +updateResults.push(observeUpdate(updateDeadZone), deadUpdateBinding); +const constantUpdateBinding = { valueOf() { updateTrace.push('constant conversion'); return 3; } }; +updateResults.push(observeUpdate(updateConstant)); + +// Accessor reads occur once, and numeric conversion precedes PutValue. +delete globalThis.updateValue; +for (const operation of [postIncrement, preDecrement, strictIncrement]) { + let stored; + Object.defineProperty(globalThis, 'updateValue', { + configurable: true, + get() { + updateTrace.push('get'); + return { [Symbol.toPrimitive](hint) { updateTrace.push('convert ' + hint); return '11'; } }; + }, + set(value) { updateTrace.push('set ' + value); stored = value; }, + }); + updateResults.push([observeUpdate(operation), stored]); +} +Object.defineProperty(globalThis, 'updateValue', { value: 8, writable: false, configurable: true }); +updateResults.push(observeUpdate(postIncrement), updateValue, observeUpdate(strictIncrement), updateValue); +Object.defineProperty(globalThis, 'updateValue', { + configurable: true, + get() { updateTrace.push('throwing getter'); throw new RangeError('get'); }, +}); +updateResults.push(observeUpdate(postIncrement)); +delete globalThis.updateValue; + +for (const operation of [postIncrement, strictIncrement]) { + Object.defineProperty(globalThis, 'updateValue', { + configurable: true, + get() { + updateTrace.push('deleting getter'); + delete globalThis.updateValue; + return { valueOf() { updateTrace.push('conversion after delete'); return 2; } }; + }, + }); + updateResults.push(observeUpdate(operation), Object.hasOwn(globalThis, 'updateValue')); + delete globalThis.updateValue; +} +Object.defineProperty(globalThis, 'updateValue', { + configurable: true, + get() { updateTrace.push('conversion throws'); return { valueOf() { throw new SyntaxError('numeric'); } }; }, + set() { updateTrace.push('unexpected setter'); }, +}); +updateResults.push(observeUpdate(postIncrement)); +Object.defineProperty(globalThis, 'updateValue', { + configurable: true, + get() { updateTrace.push('setter will throw'); return '4'; }, + set(value) { updateTrace.push('throwing set ' + value); throw new RangeError('set'); }, +}); +updateResults.push(observeUpdate(preIncrement)); +delete globalThis.updateValue; + +const updateBindingResult = [updateResults, updateTrace]; diff --git a/tests/Unit/Bytecode/fixtures/update-bindings.json b/tests/Unit/Bytecode/fixtures/update-bindings.json new file mode 100644 index 00000000..1acb67d2 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/update-bindings.json @@ -0,0 +1 @@ +[[["postIncrement",["return",0],1],["postIncrement",["return","-0"],1],["postIncrement",["return",2.5],3.5],["postIncrement",["return","NaN"],"NaN"],["postIncrement",["return","Infinity"],"Infinity"],["postIncrement",["return","-Infinity"],"-Infinity"],["postIncrement",["return",1],2],["postIncrement",["return",0],1],["postIncrement",["return",0],1],["postIncrement",["return","NaN"],"NaN"],["postIncrement",["return",12],13],["postIncrement",["return","-0"],1],["postIncrement",["return",0],1],["postIncrement",["return","NaN"],"NaN"],["postIncrement",["return","9007199254740993n"],"9007199254740994n"],["postIncrement",["throw","TypeError"],null],[["return","7n"],"8n"],[["return",9],10],["preIncrement",["return",1],1],["preIncrement",["return",1],1],["preIncrement",["return",3.5],3.5],["preIncrement",["return","NaN"],"NaN"],["preIncrement",["return","Infinity"],"Infinity"],["preIncrement",["return","-Infinity"],"-Infinity"],["preIncrement",["return",2],2],["preIncrement",["return",1],1],["preIncrement",["return",1],1],["preIncrement",["return","NaN"],"NaN"],["preIncrement",["return",13],13],["preIncrement",["return",1],1],["preIncrement",["return",1],1],["preIncrement",["return","NaN"],"NaN"],["preIncrement",["return","9007199254740994n"],"9007199254740994n"],["preIncrement",["throw","TypeError"],null],[["return","8n"],"8n"],[["return",10],10],["postDecrement",["return",0],-1],["postDecrement",["return","-0"],-1],["postDecrement",["return",2.5],1.5],["postDecrement",["return","NaN"],"NaN"],["postDecrement",["return","Infinity"],"Infinity"],["postDecrement",["return","-Infinity"],"-Infinity"],["postDecrement",["return",1],0],["postDecrement",["return",0],-1],["postDecrement",["return",0],-1],["postDecrement",["return","NaN"],"NaN"],["postDecrement",["return",12],11],["postDecrement",["return","-0"],-1],["postDecrement",["return",0],-1],["postDecrement",["return","NaN"],"NaN"],["postDecrement",["return","9007199254740993n"],"9007199254740992n"],["postDecrement",["throw","TypeError"],null],[["return","7n"],"6n"],[["return",9],8],["preDecrement",["return",-1],-1],["preDecrement",["return",-1],-1],["preDecrement",["return",1.5],1.5],["preDecrement",["return","NaN"],"NaN"],["preDecrement",["return","Infinity"],"Infinity"],["preDecrement",["return","-Infinity"],"-Infinity"],["preDecrement",["return",0],0],["preDecrement",["return",-1],-1],["preDecrement",["return",-1],-1],["preDecrement",["return","NaN"],"NaN"],["preDecrement",["return",11],11],["preDecrement",["return",-1],-1],["preDecrement",["return",-1],-1],["preDecrement",["return","NaN"],"NaN"],["preDecrement",["return","9007199254740992n"],"9007199254740992n"],["preDecrement",["throw","TypeError"],null],[["return","6n"],"6n"],[["return",8],8],[6,7,6,6],["9n","10n","9n","9n"],["throw","ReferenceError"],["throw","ReferenceError"],["postIncrement",["return",0],1],["postIncrement",["return","-0"],1],["postIncrement",["return",2.5],3.5],["postIncrement",["return","NaN"],"NaN"],["postIncrement",["return","Infinity"],"Infinity"],["postIncrement",["return","-Infinity"],"-Infinity"],["postIncrement",["return",1],2],["postIncrement",["return",0],1],["postIncrement",["return",0],1],["postIncrement",["return","NaN"],"NaN"],["postIncrement",["return",12],13],["postIncrement",["return","-0"],1],["postIncrement",["return",0],1],["postIncrement",["return","NaN"],"NaN"],["postIncrement",["return","9007199254740993n"],"9007199254740994n"],["postIncrement",["throw","TypeError"],null],[["return","7n"],"8n"],[["return",9],10],["preIncrement",["return",1],1],["preIncrement",["return",1],1],["preIncrement",["return",3.5],3.5],["preIncrement",["return","NaN"],"NaN"],["preIncrement",["return","Infinity"],"Infinity"],["preIncrement",["return","-Infinity"],"-Infinity"],["preIncrement",["return",2],2],["preIncrement",["return",1],1],["preIncrement",["return",1],1],["preIncrement",["return","NaN"],"NaN"],["preIncrement",["return",13],13],["preIncrement",["return",1],1],["preIncrement",["return",1],1],["preIncrement",["return","NaN"],"NaN"],["preIncrement",["return","9007199254740994n"],"9007199254740994n"],["preIncrement",["throw","TypeError"],null],[["return","8n"],"8n"],[["return",10],10],["postDecrement",["return",0],-1],["postDecrement",["return","-0"],-1],["postDecrement",["return",2.5],1.5],["postDecrement",["return","NaN"],"NaN"],["postDecrement",["return","Infinity"],"Infinity"],["postDecrement",["return","-Infinity"],"-Infinity"],["postDecrement",["return",1],0],["postDecrement",["return",0],-1],["postDecrement",["return",0],-1],["postDecrement",["return","NaN"],"NaN"],["postDecrement",["return",12],11],["postDecrement",["return","-0"],-1],["postDecrement",["return",0],-1],["postDecrement",["return","NaN"],"NaN"],["postDecrement",["return","9007199254740993n"],"9007199254740992n"],["postDecrement",["throw","TypeError"],null],[["return","7n"],"6n"],[["return",9],8],["preDecrement",["return",-1],-1],["preDecrement",["return",-1],-1],["preDecrement",["return",1.5],1.5],["preDecrement",["return","NaN"],"NaN"],["preDecrement",["return","Infinity"],"Infinity"],["preDecrement",["return","-Infinity"],"-Infinity"],["preDecrement",["return",0],0],["preDecrement",["return",-1],-1],["preDecrement",["return",-1],-1],["preDecrement",["return","NaN"],"NaN"],["preDecrement",["return",11],11],["preDecrement",["return",-1],-1],["preDecrement",["return",-1],-1],["preDecrement",["return","NaN"],"NaN"],["preDecrement",["return","9007199254740992n"],"9007199254740992n"],["preDecrement",["throw","TypeError"],null],[["return","6n"],"6n"],[["return",8],8],[6,7,6,6],["9n","10n","9n","9n"],["throw","ReferenceError"],["throw","ReferenceError"],["return",4],5,["throw","TypeError"],[["return",11],12],[["return",10],10],[["return",11],12],["return",8],8,["throw","TypeError"],8,["throw","RangeError"],["return",2],true,["throw","ReferenceError"],false,["throw","SyntaxError"],["throw","RangeError"]],["number","valueOf","number","valueOf","number","valueOf","number","valueOf","number","valueOf","number","valueOf","number","valueOf","number","valueOf","constant conversion","get","convert number","set 12","get","convert number","set 10","get","convert number","set 12","throwing getter","deleting getter","conversion after delete","deleting getter","conversion after delete","conversion throws","setter will throw","throwing set 5"]] From 8bf8ad8e06735542d793df287bf2a7ca11113dd9 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:12:05 +0200 Subject: [PATCH 15/99] Format the update binding oracle regression --- tests/Unit/Bytecode/UpdateBindingTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Bytecode/UpdateBindingTest.php b/tests/Unit/Bytecode/UpdateBindingTest.php index 817d46c6..4b863e59 100644 --- a/tests/Unit/Bytecode/UpdateBindingTest.php +++ b/tests/Unit/Bytecode/UpdateBindingTest.php @@ -30,10 +30,11 @@ function observe() { seen.push(counter); } public function testCompiledBindingUpdatesMatchTheNodeOracle(): void { $engine = $this->checkOracle(false); - foreach ([ + $names = [ 'postIncrement', 'preIncrement', 'postDecrement', 'preDecrement', 'strictIncrement', 'unknownIncrement', 'updateCaptured', 'updateConstant', 'updateDeadZone', - ] as $name) { + ]; + foreach ($names as $name) { $function = $engine->getGlobalEnv()->get($name); self::assertInstanceOf(JsFunction::class, $function); self::assertNotNull($function->compiled, $name . ' must exercise the bytecode path.'); From 404eb73a59bb9aa89cb9301e238492190462785b Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:16:59 +0200 Subject: [PATCH 16/99] Preserve strict program assignment references during compilation --- src/Bytecode/CompiledFunction.php | 8 ++ src/Bytecode/Compiler.php | 8 +- src/Bytecode/Op.php | 2 + src/Bytecode/Parts/CompilerExpression.php | 41 +++++++-- src/Bytecode/VM.php | 8 ++ .../Bytecode/StrictProgramAssignmentTest.php | 84 +++++++++++++++++++ .../fixtures/strict-program-assignments.js | 71 ++++++++++++++++ .../fixtures/strict-program-assignments.json | 1 + 8 files changed, 212 insertions(+), 11 deletions(-) create mode 100644 tests/Unit/Bytecode/StrictProgramAssignmentTest.php create mode 100644 tests/Unit/Bytecode/fixtures/strict-program-assignments.js create mode 100644 tests/Unit/Bytecode/fixtures/strict-program-assignments.json diff --git a/src/Bytecode/CompiledFunction.php b/src/Bytecode/CompiledFunction.php index 08d7a9a4..2e82f2ed 100644 --- a/src/Bytecode/CompiledFunction.php +++ b/src/Bytecode/CompiledFunction.php @@ -135,6 +135,14 @@ final class CompiledFunction */ public array $classNodes = []; + /** + * Expressions whose bindings all live in the frame environment. The + * interpreter preserves their complete reference and evaluation order. + * + * @var list + */ + public array $interpretedExpressions = []; + /** * Source-style display strings for method-call sites, keyed by the * PC of the CALL_METHOD opcode. When the dispatched method turns diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index 30152795..ba69e8b2 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -172,6 +172,9 @@ final class Compiler */ private array $classNodes = []; + /** @var list Program expressions that need complete interpreter reference semantics. */ + private array $interpretedExpressions = []; + /** * @var list}> */ @@ -235,8 +238,8 @@ final class Compiler /** * Whether the program currently being compiled has a `"use strict"` * directive in its prologue (or was wrapped with one by the host). - * Used by compileAssignment to bail when a non-local identifier is - * the LHS: per spec, the LHS reference resolves BEFORE the RHS, so + * Used by compileAssignment to retain interpreter reference semantics + * when a non-local identifier is the LHS: the reference resolves before the RHS, so * a strict-mode unresolvable LHS must throw ReferenceError even * when the RHS happens to add the property to the global object as * a side effect (test262 language/identifier-resolution/ @@ -579,6 +582,7 @@ public function compileProgram(\Phasis\Ast\Program $program): CompiledFunction ); $cf->handlers = $this->handlers; $cf->classNodes = $this->classNodes; + $cf->interpretedExpressions = $this->interpretedExpressions; $cf->arrayBindings = $this->arrayBindings; $cf->callMethodDisplays = $this->callMethodDisplays; return $cf; diff --git a/src/Bytecode/Op.php b/src/Bytecode/Op.php index f897b94a..302888d4 100644 --- a/src/Bytecode/Op.php +++ b/src/Bytecode/Op.php @@ -182,6 +182,7 @@ final class Op public const DELETE_NAME = 113; // N: delete an environment binding without reading its value. public const DELETE_PROPERTY = 114; // pop key and base, delete the property, push the Boolean result. public const UPDATE_NAME = 115; // N I I: resolve a binding once, update by +/-1, push prefix/postfix result. + public const EVAL_EXPRESSION = 116; // I: evaluate an environment-only expression through the interpreter. public const LOOP_INIT = 120; public const LOOP_TICK = 121; @@ -257,6 +258,7 @@ public static function operandCount(int $op): int case self::BIND_ARRAY: case self::TYPEOF_NAME: case self::DELETE_NAME: + case self::EVAL_EXPRESSION: case self::JUMP: case self::JUMP_IF_TRUE: case self::JUMP_IF_FALSE: diff --git a/src/Bytecode/Parts/CompilerExpression.php b/src/Bytecode/Parts/CompilerExpression.php index 7666309c..834d0425 100644 --- a/src/Bytecode/Parts/CompilerExpression.php +++ b/src/Bytecode/Parts/CompilerExpression.php @@ -890,16 +890,18 @@ private function compileAssignment(AssignmentExpression $node): void throw new CompilerBailout('assignment to const'); } - // Strict-mode write to a non-local identifier: bail so the - // tree-walker can pre-resolve the LHS reference per spec - // (12.15.4 step 1: lref is evaluated BEFORE the RHS). - // The VM's STORE_NAME runs after RHS, so a side-effecting - // RHS that creates the global property would mask the - // unresolvable LHS — strict mode must surface ReferenceError - // (test262 language/identifier-resolution/ - // assign-to-global-undefined.js). + // The program environment owns its global bindings. Keep the + // complete assignment on the interpreter so a RHS that creates + // a missing global cannot change its already resolved reference. if (!$isLocal && $this->programIsStrict) { - throw new CompilerBailout('strict-mode non-local identifier assignment'); + if ($op !== '=') { + throw new CompilerBailout('strict-mode non-local compound assignment'); + } + $this->checkInterpretedExpressionBindings($node); + $index = count($this->interpretedExpressions); + $this->interpretedExpressions[] = $node; + $this->emit(Op::EVAL_EXPRESSION, $index); + return; } if ($op === '=') { if (self::initNeedsNamedEvaluation($node->right)) { @@ -999,6 +1001,27 @@ private function compileAssignment(AssignmentExpression $node): void throw new CompilerBailout('unsupported assignment target'); } + /** AST evaluation cannot observe values stored only in compiled local slots. */ + private function checkInterpretedExpressionBindings(Node $node): void + { + if ( + $node instanceof Identifier && isset($this->localSlots[$node->name]) + && !isset($this->capturedLocals[$node->name]) + ) { + throw new CompilerBailout('interpreted expression depends on a local slot'); + } + if ($node instanceof ThisExpression) { + $this->hasLoadThis = true; + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node) { + $this->checkInterpretedExpressionBindings($child); + } + } + } + } + /** Keep each reference and write beside its iterator step, including abrupt closing. */ private function compileArrayAssignment(ArrayPattern|ArrayExpression $pattern, Node $right): void { diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 8e9ed4c4..c27edcee 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -2645,6 +2645,14 @@ public function execute( $pc += 2; break; + case Op::EVAL_EXPRESSION: + $stack[$sp++] = $this->interp->evaluate( + $cf->interpretedExpressions[$code[$pc + 1]], + $env, + ); + $pc += 2; + break; + case Op::THROW: $val = $stack[--$sp]; $this->interp->throwJsValue($val); diff --git a/tests/Unit/Bytecode/StrictProgramAssignmentTest.php b/tests/Unit/Bytecode/StrictProgramAssignmentTest.php new file mode 100644 index 00000000..4da14a94 --- /dev/null +++ b/tests/Unit/Bytecode/StrictProgramAssignmentTest.php @@ -0,0 +1,84 @@ +eval($fixture . "\nstrictAssignmentCases;"); + self::assertIsArray($cases); + $results = []; + foreach ($cases as $case) { + $engine = new Engine(); + $engine->eval($case['setup']); + $compiled = (new Compiler())->compileProgram((new Parser($case['source']))->parse()); + self::assertContains(Op::EVAL_EXPRESSION, $compiled->code, $case['name']); + self::assertNotEmpty($compiled->interpretedExpressions, $case['name']); + try { + $completion = ['return', $engine->eval($case['source'])]; + } catch (JsThrowable $error) { + self::assertInstanceOf(JsObject::class, $error->jsValue); + $name = $error->jsValue->get('name'); + self::assertInstanceOf(JsString::class, $name); + $completion = ['throw', $name->value]; + } catch (RuntimeError $error) { + $completion = ['throw', (new \ReflectionClass($error))->getShortName()]; + } + $results[] = [$case['name'], $completion, $engine->eval($case['observation'])]; + } + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/strict-program-assignments.json', + json_encode($results, JSON_THROW_ON_ERROR), + ); + } + + public function testAnExpressionDependingOnACatchSlotKeepsTheInterpreterPath(): void + { + $source = <<<'JS' +"use strict"; +var target; +if (true) { try { throw 3; } catch (value) { target = value; } } +target; +JS; + try { + (new Compiler())->compileProgram((new Parser($source))->parse()); + self::fail('The interpreter cannot read a value kept only in a compiled catch slot.'); + } catch (CompilerBailout $error) { + self::assertSame('interpreted expression depends on a local slot', $error->getMessage()); + } + self::assertSame(3, (new Engine())->eval($source)); + } + + public function testARightHandSideCannotResolveAnAlreadyMissingReference(): void + { + // This is required by test262 assign-to-global-undefined.js. Node 26 + // currently resolves the reference late and is not the oracle here. + $source = '"use strict"; missing = (globalThis.missing = 5);'; + $compiled = (new Compiler())->compileProgram((new Parser($source))->parse()); + self::assertContains(Op::EVAL_EXPRESSION, $compiled->code); + $engine = new Engine(); + try { + $engine->eval($source); + self::fail('The original reference must remain unresolvable.'); + } catch (ReferenceError $error) { + self::assertSame('missing is not defined', $error->getMessage()); + } + self::assertSame(5, $engine->eval('globalThis.missing')); + } +} diff --git a/tests/Unit/Bytecode/fixtures/strict-program-assignments.js b/tests/Unit/Bytecode/fixtures/strict-program-assignments.js new file mode 100644 index 00000000..8883e7f1 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/strict-program-assignments.js @@ -0,0 +1,71 @@ +var strictAssignmentCases = [ + { + name: 'ordinary globals and completion', + setup: '', + source: '"use strict"; var target = 1; target = 3; target;', + observation: '[target, globalThis.target]', + }, + { + name: 'RHS throw precedes the unresolved write', + setup: 'var trace = []; function rhs() { trace.push("rhs"); throw new RangeError("rhs"); }', + source: '"use strict"; missing = rhs();', + observation: '[trace, Object.hasOwn(globalThis, "missing")]', + }, + { + name: 'assignment does not read the old accessor value', + setup: `var trace = []; + Object.defineProperty(globalThis, 'target', { + configurable: true, + get() { trace.push('unexpected getter'); throw new Error('get'); }, + set(value) { trace.push('set ' + value); } + }); + function rhs() { trace.push('rhs'); return 12; }`, + source: '"use strict"; target = rhs();', + observation: 'trace', + }, + { + name: 'RHS deletion is observed by the original global environment', + setup: `var trace = []; globalThis.target = 1; + function rhs() { trace.push('delete'); delete globalThis.target; return 8; }`, + source: '"use strict"; target = rhs();', + observation: '[trace, Object.hasOwn(globalThis, "target")]', + }, + { + name: 'RHS replaces the accessor before PutValue', + setup: `var trace = []; + Object.defineProperty(globalThis, 'target', { + configurable: true, set(value) { trace.push('old set ' + value); } + }); + function rhs() { + trace.push('rhs'); + Object.defineProperty(globalThis, 'target', { + configurable: true, set(value) { trace.push('new set ' + value); } + }); + return 9; + }`, + source: '"use strict"; target = rhs();', + observation: 'trace', + }, + { + name: 'setter throw follows the completed RHS', + setup: `var trace = []; + Object.defineProperty(globalThis, 'target', { + configurable: true, set(value) { trace.push('set ' + value); throw new SyntaxError('set'); } + }); + function rhs() { trace.push('rhs'); return 13; }`, + source: '"use strict"; target = rhs();', + observation: 'trace', + }, + { + name: 'anonymous function name inference remains interpreter-owned', + setup: 'var target;', + source: '"use strict"; target = function () {}; target.name;', + observation: 'target.name', + }, + { + name: 'this is the script global inside the fallback expression', + setup: 'var target;', + source: '"use strict"; target = this; target === globalThis;', + observation: 'target === globalThis', + }, +]; diff --git a/tests/Unit/Bytecode/fixtures/strict-program-assignments.json b/tests/Unit/Bytecode/fixtures/strict-program-assignments.json new file mode 100644 index 00000000..345ed781 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/strict-program-assignments.json @@ -0,0 +1 @@ +[["ordinary globals and completion",["return",3],[3,3]],["RHS throw precedes the unresolved write",["throw","RangeError"],[["rhs"],false]],["assignment does not read the old accessor value",["return",12],["rhs","set 12"]],["RHS deletion is observed by the original global environment",["throw","ReferenceError"],[["delete"],false]],["RHS replaces the accessor before PutValue",["return",9],["rhs","new set 9"]],["setter throw follows the completed RHS",["throw","SyntaxError"],["rhs","set 13"]],["anonymous function name inference remains interpreter-owned",["return","target"],"target"],["this is the script global inside the fallback expression",["return",true],true]] From a3dc370e9f2f5422a1dd24f9803da08ce7fcdbd0 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:35:23 +0200 Subject: [PATCH 17/99] Accelerate numeric typed-array writes with preserved coercion order --- src/Bytecode/VM.php | 17 + src/Value/JsTypedArray.php | 35 +- tests/Unit/Bytecode/TypedArrayWriteTest.php | 54 ++ .../Bytecode/fixtures/typed-array-writes.js | 55 ++ .../Bytecode/fixtures/typed-array-writes.json | 900 ++++++++++++++++++ 5 files changed, 1050 insertions(+), 11 deletions(-) create mode 100644 tests/Unit/Bytecode/TypedArrayWriteTest.php create mode 100644 tests/Unit/Bytecode/fixtures/typed-array-writes.js create mode 100644 tests/Unit/Bytecode/fixtures/typed-array-writes.json diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index c27edcee..b4a98c62 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -2624,6 +2624,23 @@ public function execute( break; } } + if ( + $obj instanceof \Phasis\Value\JsTypedArray && $key instanceof JsNumber + && $key->value >= 0 && $key->value < PHP_INT_MAX + ) { + $index = (int) $key->value; + if ((float) $index === $key->value) { + // Number keys have no observable coercion. Keep value + // conversion and detached/resizable checks in [[Set]]. + $ok = $obj->setIntegerIndex($index, $val); + if (!$ok && $this->interp->isStrictMode()) { + throw new TypeError('Cannot assign to an immutable TypedArray index'); + } + $stack[$sp++] = $val; + $pc++; + break; + } + } $this->writeComputed($obj, $key, $val); $stack[$sp++] = $val; $pc++; diff --git a/src/Value/JsTypedArray.php b/src/Value/JsTypedArray.php index f8cacc4a..e860a5d5 100644 --- a/src/Value/JsTypedArray.php +++ b/src/Value/JsTypedArray.php @@ -217,6 +217,9 @@ private function coerceTypedArrayValue(JsValue $value): JsValue if ($this->isBigInt) { return \Phasis\Spec\TypeConversion::toBigInt($value); } + if ($value instanceof JsNumber) { + return $value; + } $num = \Phasis\Spec\TypeConversion::toNumber($value); return new \Phasis\Value\JsNumber($num); } @@ -578,6 +581,25 @@ public function get(string $name): JsValue return parent::get($name); } + /** + * Set a numeric property whose key is already known to be an integer. + * Conversion must precede the bounds check because it can resize or + * detach the view. The result is the exotic [[Set]] success flag. + * + * @internal + */ + public function setIntegerIndex(int $index, JsValue $value): bool + { + if ($this->buffer->isImmutable()) { + return false; + } + $coerced = $this->coerceTypedArrayValue($value); + if ($index >= 0 && $index < $this->getLength()) { + $this->setIndex($index, $coerced); + } + return true; + } + public function set(string $name, JsValue $value, bool $strict = false): void { if ($this->buffer->isImmutable() && self::isCanonicalNumericIndex($name)) { @@ -596,11 +618,7 @@ public function set(string $name, JsValue $value, bool $strict = false): void $nameLen !== 0 && $nameLen <= 15 && ctype_digit($name) && ($name === '0' || $name[0] !== '0') ) { - $coerced = $this->coerceTypedArrayValue($value); - $index = (int) $name; - if ($index >= 0 && $index < $this->getLength()) { - $this->setIndex($index, $coerced); - } + $this->setIntegerIndex((int) $name, $value); return; } @@ -642,12 +660,7 @@ public function internalSet(string $name, JsValue $value, JsObject $receiver): b && ($name === '0' || $name[0] !== '0') && $receiver === $this ) { - $coerced = $this->coerceTypedArrayValue($value); - $index = (int) $name; - if ($index >= 0 && $index < $this->getLength()) { - $this->setIndex($index, $coerced); - } - return true; + return $this->setIntegerIndex((int) $name, $value); } if (self::isCanonicalNumericIndex($name)) { diff --git a/tests/Unit/Bytecode/TypedArrayWriteTest.php b/tests/Unit/Bytecode/TypedArrayWriteTest.php new file mode 100644 index 00000000..539e994f --- /dev/null +++ b/tests/Unit/Bytecode/TypedArrayWriteTest.php @@ -0,0 +1,54 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/typed-array-writes.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/typed-array-writes.json', + $engine->eval('JSON.stringify(typedArrayWriteResult)'), + ); + foreach (['strictStore', 'sloppyStore'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, 'The numeric stores must exercise bytecode.'); + } + } + + public function testInterpreterMatchesTheSameNodeOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/typed-array-writes.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/typed-array-writes.json', + $engine->eval('JSON.stringify(typedArrayWriteResult)'), + ); + } + + public function testImmutableViewsRejectWritesBeforeValueConversion(): void + { + $engine = new Engine(); + self::assertSame([false, 'TypeError', 0, 7], $engine->eval(<<<'JS' +const immutable = new Uint8Array(new Uint8Array([7]).buffer.transferToImmutable()); +let coercions = 0; +const value = {valueOf() { coercions++; return 9; }}; +function loose(view, key, value) { view[key] = value; return view[key] === value; } +function strict(view, key, value) { 'use strict'; view[key] = value; } +const result = [loose(immutable, 0, value)]; +try { strict(immutable, 0, value); } catch (error) { result.push(error.name); } +result.push(coercions, immutable[0]); +result; +JS)); + } +} diff --git a/tests/Unit/Bytecode/fixtures/typed-array-writes.js b/tests/Unit/Bytecode/fixtures/typed-array-writes.js new file mode 100644 index 00000000..4ae7732d --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/typed-array-writes.js @@ -0,0 +1,55 @@ +function strictStore(view, key, value) { 'use strict'; return view[key] = value; } +function sloppyStore(view, key, value) { return view[key] = value; } +function numberText(value) { return Object.is(value, -0) ? '-0' : String(value); } +const typedArrayWriteResult = []; +const constructors = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, + Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array]; +for (const Constructor of constructors) { + const bigint = Constructor === BigInt64Array || Constructor === BigUint64Array; + const values = bigint ? [1n, -1n, 18446744073709551623n] : [1.5, -1, 257, NaN, Infinity, -Infinity, -0]; + for (const value of values) { + const view = new Constructor(2); + const returned = strictStore(view, 0, value); + typedArrayWriteResult.push([Constructor.name, numberText(value), Object.is(returned, value), + numberText(view[0]), numberText(view[1])]); + } +} +for (const store of [strictStore, sloppyStore]) { + for (const key of [-0, '0', '-0', 1, 3, 1.5, -1, NaN, Infinity, 9007199254740991, '01']) { + const view = new Uint8Array(2); + const effects = []; + const value = {valueOf() { effects.push('value'); return 13; }}; + const returned = store(view, key, value); + typedArrayWriteResult.push([store.name, numberText(key), returned === value, effects, + numberText(view[0]), numberText(view[1]), Object.prototype.hasOwnProperty.call(view, key)]); + } + for (const key of [0, 9]) { + const effects = []; + let error; + try { store(new Uint8Array(1), key, {valueOf() { effects.push('value'); throw new RangeError('value'); }}); } + catch (caught) { error = caught.name; } + typedArrayWriteResult.push(['throw', store.name, key, effects, error]); + try { store(new BigInt64Array(1), key, 3); } + catch (caught) { typedArrayWriteResult.push(['bigint-number', key, caught.name]); } + try { store(new Uint8Array(1), key, 3n); } + catch (caught) { typedArrayWriteResult.push(['number-bigint', key, caught.name]); } + } + const effects = []; + const view = new Uint8Array(2); + const key = {[Symbol.toPrimitive](hint) { effects.push('key:' + hint); return '1'; }}; + store(view, key, {valueOf() { effects.push('value'); return 19; }}); + typedArrayWriteResult.push(['key-order', effects, view[1]]); + const buffer = new ArrayBuffer(4); + const detached = new Uint8Array(buffer); + let conversions = 0; + const value = {valueOf() { conversions++; structuredClone(buffer, {transfer:[buffer]}); return 27; }}; + const result = store(detached, 0, value); + typedArrayWriteResult.push(['detach', result === value, conversions, buffer.byteLength, numberText(detached[0])]); + const resizable = new ArrayBuffer(4, {maxByteLength:8}); + const fixed = new Uint8Array(resizable, 0, 4); + store(fixed, 0, {valueOf() { resizable.resize(1); return 23; }}); + typedArrayWriteResult.push(['shrink', fixed.length, numberText(fixed[0]), new Uint8Array(resizable)[0]]); + const tracking = new Uint8Array(resizable); + store(tracking, 5, {valueOf() { resizable.resize(8); return 29; }}); + typedArrayWriteResult.push(['grow', tracking.length, tracking[5]]); +} diff --git a/tests/Unit/Bytecode/fixtures/typed-array-writes.json b/tests/Unit/Bytecode/fixtures/typed-array-writes.json new file mode 100644 index 00000000..e5e9345f --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/typed-array-writes.json @@ -0,0 +1,900 @@ +[ + [ + "Int8Array", + "1.5", + true, + "1", + "0" + ], + [ + "Int8Array", + "-1", + true, + "-1", + "0" + ], + [ + "Int8Array", + "257", + true, + "1", + "0" + ], + [ + "Int8Array", + "NaN", + true, + "0", + "0" + ], + [ + "Int8Array", + "Infinity", + true, + "0", + "0" + ], + [ + "Int8Array", + "-Infinity", + true, + "0", + "0" + ], + [ + "Int8Array", + "-0", + true, + "0", + "0" + ], + [ + "Uint8Array", + "1.5", + true, + "1", + "0" + ], + [ + "Uint8Array", + "-1", + true, + "255", + "0" + ], + [ + "Uint8Array", + "257", + true, + "1", + "0" + ], + [ + "Uint8Array", + "NaN", + true, + "0", + "0" + ], + [ + "Uint8Array", + "Infinity", + true, + "0", + "0" + ], + [ + "Uint8Array", + "-Infinity", + true, + "0", + "0" + ], + [ + "Uint8Array", + "-0", + true, + "0", + "0" + ], + [ + "Uint8ClampedArray", + "1.5", + true, + "2", + "0" + ], + [ + "Uint8ClampedArray", + "-1", + true, + "0", + "0" + ], + [ + "Uint8ClampedArray", + "257", + true, + "255", + "0" + ], + [ + "Uint8ClampedArray", + "NaN", + true, + "0", + "0" + ], + [ + "Uint8ClampedArray", + "Infinity", + true, + "255", + "0" + ], + [ + "Uint8ClampedArray", + "-Infinity", + true, + "0", + "0" + ], + [ + "Uint8ClampedArray", + "-0", + true, + "0", + "0" + ], + [ + "Int16Array", + "1.5", + true, + "1", + "0" + ], + [ + "Int16Array", + "-1", + true, + "-1", + "0" + ], + [ + "Int16Array", + "257", + true, + "257", + "0" + ], + [ + "Int16Array", + "NaN", + true, + "0", + "0" + ], + [ + "Int16Array", + "Infinity", + true, + "0", + "0" + ], + [ + "Int16Array", + "-Infinity", + true, + "0", + "0" + ], + [ + "Int16Array", + "-0", + true, + "0", + "0" + ], + [ + "Uint16Array", + "1.5", + true, + "1", + "0" + ], + [ + "Uint16Array", + "-1", + true, + "65535", + "0" + ], + [ + "Uint16Array", + "257", + true, + "257", + "0" + ], + [ + "Uint16Array", + "NaN", + true, + "0", + "0" + ], + [ + "Uint16Array", + "Infinity", + true, + "0", + "0" + ], + [ + "Uint16Array", + "-Infinity", + true, + "0", + "0" + ], + [ + "Uint16Array", + "-0", + true, + "0", + "0" + ], + [ + "Int32Array", + "1.5", + true, + "1", + "0" + ], + [ + "Int32Array", + "-1", + true, + "-1", + "0" + ], + [ + "Int32Array", + "257", + true, + "257", + "0" + ], + [ + "Int32Array", + "NaN", + true, + "0", + "0" + ], + [ + "Int32Array", + "Infinity", + true, + "0", + "0" + ], + [ + "Int32Array", + "-Infinity", + true, + "0", + "0" + ], + [ + "Int32Array", + "-0", + true, + "0", + "0" + ], + [ + "Uint32Array", + "1.5", + true, + "1", + "0" + ], + [ + "Uint32Array", + "-1", + true, + "4294967295", + "0" + ], + [ + "Uint32Array", + "257", + true, + "257", + "0" + ], + [ + "Uint32Array", + "NaN", + true, + "0", + "0" + ], + [ + "Uint32Array", + "Infinity", + true, + "0", + "0" + ], + [ + "Uint32Array", + "-Infinity", + true, + "0", + "0" + ], + [ + "Uint32Array", + "-0", + true, + "0", + "0" + ], + [ + "Float16Array", + "1.5", + true, + "1.5", + "0" + ], + [ + "Float16Array", + "-1", + true, + "-1", + "0" + ], + [ + "Float16Array", + "257", + true, + "257", + "0" + ], + [ + "Float16Array", + "NaN", + true, + "NaN", + "0" + ], + [ + "Float16Array", + "Infinity", + true, + "Infinity", + "0" + ], + [ + "Float16Array", + "-Infinity", + true, + "-Infinity", + "0" + ], + [ + "Float16Array", + "-0", + true, + "-0", + "0" + ], + [ + "Float32Array", + "1.5", + true, + "1.5", + "0" + ], + [ + "Float32Array", + "-1", + true, + "-1", + "0" + ], + [ + "Float32Array", + "257", + true, + "257", + "0" + ], + [ + "Float32Array", + "NaN", + true, + "NaN", + "0" + ], + [ + "Float32Array", + "Infinity", + true, + "Infinity", + "0" + ], + [ + "Float32Array", + "-Infinity", + true, + "-Infinity", + "0" + ], + [ + "Float32Array", + "-0", + true, + "-0", + "0" + ], + [ + "Float64Array", + "1.5", + true, + "1.5", + "0" + ], + [ + "Float64Array", + "-1", + true, + "-1", + "0" + ], + [ + "Float64Array", + "257", + true, + "257", + "0" + ], + [ + "Float64Array", + "NaN", + true, + "NaN", + "0" + ], + [ + "Float64Array", + "Infinity", + true, + "Infinity", + "0" + ], + [ + "Float64Array", + "-Infinity", + true, + "-Infinity", + "0" + ], + [ + "Float64Array", + "-0", + true, + "-0", + "0" + ], + [ + "BigInt64Array", + "1", + true, + "1", + "0" + ], + [ + "BigInt64Array", + "-1", + true, + "-1", + "0" + ], + [ + "BigInt64Array", + "18446744073709551623", + true, + "7", + "0" + ], + [ + "BigUint64Array", + "1", + true, + "1", + "0" + ], + [ + "BigUint64Array", + "-1", + true, + "18446744073709551615", + "0" + ], + [ + "BigUint64Array", + "18446744073709551623", + true, + "7", + "0" + ], + [ + "strictStore", + "-0", + true, + [ + "value" + ], + "13", + "0", + true + ], + [ + "strictStore", + "0", + true, + [ + "value" + ], + "13", + "0", + true + ], + [ + "strictStore", + "-0", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "strictStore", + "1", + true, + [ + "value" + ], + "0", + "13", + true + ], + [ + "strictStore", + "3", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "strictStore", + "1.5", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "strictStore", + "-1", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "strictStore", + "NaN", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "strictStore", + "Infinity", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "strictStore", + "9007199254740991", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "strictStore", + "01", + true, + [], + "0", + "0", + true + ], + [ + "throw", + "strictStore", + 0, + [ + "value" + ], + "RangeError" + ], + [ + "bigint-number", + 0, + "TypeError" + ], + [ + "number-bigint", + 0, + "TypeError" + ], + [ + "throw", + "strictStore", + 9, + [ + "value" + ], + "RangeError" + ], + [ + "bigint-number", + 9, + "TypeError" + ], + [ + "number-bigint", + 9, + "TypeError" + ], + [ + "key-order", + [ + "key:string", + "value" + ], + 19 + ], + [ + "detach", + true, + 1, + 0, + "undefined" + ], + [ + "shrink", + 0, + "undefined", + 0 + ], + [ + "grow", + 8, + 29 + ], + [ + "sloppyStore", + "-0", + true, + [ + "value" + ], + "13", + "0", + true + ], + [ + "sloppyStore", + "0", + true, + [ + "value" + ], + "13", + "0", + true + ], + [ + "sloppyStore", + "-0", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "sloppyStore", + "1", + true, + [ + "value" + ], + "0", + "13", + true + ], + [ + "sloppyStore", + "3", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "sloppyStore", + "1.5", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "sloppyStore", + "-1", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "sloppyStore", + "NaN", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "sloppyStore", + "Infinity", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "sloppyStore", + "9007199254740991", + true, + [ + "value" + ], + "0", + "0", + false + ], + [ + "sloppyStore", + "01", + true, + [], + "0", + "0", + true + ], + [ + "throw", + "sloppyStore", + 0, + [ + "value" + ], + "RangeError" + ], + [ + "bigint-number", + 0, + "TypeError" + ], + [ + "number-bigint", + 0, + "TypeError" + ], + [ + "throw", + "sloppyStore", + 9, + [ + "value" + ], + "RangeError" + ], + [ + "bigint-number", + 9, + "TypeError" + ], + [ + "number-bigint", + 9, + "TypeError" + ], + [ + "key-order", + [ + "key:string", + "value" + ], + 19 + ], + [ + "detach", + true, + 1, + 0, + "undefined" + ], + [ + "shrink", + 0, + "undefined", + 0 + ], + [ + "grow", + 8, + 29 + ] +] From 81cb8a7e3eaec96ccca993c563eb1f3d902423f1 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:37:02 +0200 Subject: [PATCH 18/99] Compile independent const blocks with proven binding lifetimes --- src/Bytecode/Compiler.php | 2 +- src/Bytecode/Parts/CompilerBlockBindings.php | 35 ++- .../Unit/Bytecode/ConstBlockLifetimeTest.php | 47 ++++ .../fixtures/const-block-lifetimes.js | 105 +++++++++ .../fixtures/const-block-lifetimes.json | 200 ++++++++++++++++++ 5 files changed, 382 insertions(+), 7 deletions(-) create mode 100644 tests/Unit/Bytecode/ConstBlockLifetimeTest.php create mode 100644 tests/Unit/Bytecode/fixtures/const-block-lifetimes.js create mode 100644 tests/Unit/Bytecode/fixtures/const-block-lifetimes.json diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index ba69e8b2..1982b53b 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -104,7 +104,7 @@ final class Compiler /** @var array Captured function-scope bindings and declaration kinds. */ private array $capturedLocals = []; - /** @var array Uncaptured let bindings with proven disjoint block lifetimes. */ + /** @var array Uncaptured lexical bindings with proven disjoint block lifetimes. */ private array $reusableBlockLocals = []; /** @var list<\Phasis\Ast\Node> */ diff --git a/src/Bytecode/Parts/CompilerBlockBindings.php b/src/Bytecode/Parts/CompilerBlockBindings.php index 8aaf2031..5286c708 100644 --- a/src/Bytecode/Parts/CompilerBlockBindings.php +++ b/src/Bytecode/Parts/CompilerBlockBindings.php @@ -19,16 +19,17 @@ trait CompilerBlockBindings { /** - * Two uncaptured let bindings may share a slot when their blocks never - * overlap and every reference follows its own initialization. Keep all + * Uncaptured bindings of one declaration kind may share a slot when their + * blocks never overlap and every reference follows its own initialization. Keep all * shadowing, captures, pattern bindings and ambiguous lifetimes on the * interpreter path, which owns the general lexical-environment semantics. */ private function collectReusableBlockBindings(BlockStatement $body): void { $declarations = []; + $declarationKinds = []; $disallowed = array_fill_keys(array_keys($this->localSlots), true); - $this->collectBlockBindingDeclarations($body, null, $body, $declarations, $disallowed); + $this->collectBlockBindingDeclarations($body, null, $body, $declarations, $declarationKinds, $disallowed); foreach ($declarations as $name => $blocks) { if (isset($disallowed[$name]) || count($blocks) < 2 || count(array_unique($blocks)) !== count($blocks)) { continue; @@ -42,6 +43,7 @@ private function collectReusableBlockBindings(BlockStatement $body): void /** * @param array> $declarations + * @param array $declarationKinds * @param array $disallowed */ private function collectBlockBindingDeclarations( @@ -49,6 +51,7 @@ private function collectBlockBindingDeclarations( ?BlockStatement $directBlock, BlockStatement $functionBody, array &$declarations, + array &$declarationKinds, array &$disallowed, ): void { if ($node instanceof FunctionDeclaration || $node instanceof ClassDeclaration) { @@ -62,7 +65,14 @@ private function collectBlockBindingDeclarations( } if ($node instanceof BlockStatement) { foreach ($node->body as $statement) { - $this->collectBlockBindingDeclarations($statement, $node, $functionBody, $declarations, $disallowed); + $this->collectBlockBindingDeclarations( + $statement, + $node, + $functionBody, + $declarations, + $declarationKinds, + $disallowed, + ); } return; } @@ -72,9 +82,15 @@ private function collectBlockBindingDeclarations( $this->collectPatternBoundNames($declaration->id, $names); foreach ($names as $name => $_) { if ( - $node->kind === 'let' && $declaration->id instanceof Identifier + ($node->kind === 'let' || $node->kind === 'const') && $declaration->id instanceof Identifier && $directBlock !== null && $directBlock !== $functionBody ) { + // Readonly state is tracked per slot. Mixing let and + // const would require that state to follow each scope. + if (isset($declarationKinds[$name]) && $declarationKinds[$name] !== $node->kind) { + $disallowed[$name] = true; + } + $declarationKinds[$name] ??= $node->kind; $declarations[$name][] = spl_object_id($directBlock); } else { $disallowed[$name] = true; @@ -85,7 +101,14 @@ private function collectBlockBindingDeclarations( foreach (get_object_vars($node) as $value) { foreach (is_array($value) ? $value : [$value] as $child) { if ($child instanceof Node) { - $this->collectBlockBindingDeclarations($child, null, $functionBody, $declarations, $disallowed); + $this->collectBlockBindingDeclarations( + $child, + null, + $functionBody, + $declarations, + $declarationKinds, + $disallowed, + ); } } } diff --git a/tests/Unit/Bytecode/ConstBlockLifetimeTest.php b/tests/Unit/Bytecode/ConstBlockLifetimeTest.php new file mode 100644 index 00000000..5df5bb77 --- /dev/null +++ b/tests/Unit/Bytecode/ConstBlockLifetimeTest.php @@ -0,0 +1,47 @@ +eval((string) file_get_contents(__DIR__ . '/fixtures/const-block-lifetimes.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/const-block-lifetimes.json', + $engine->eval('JSON.stringify(constBlockLifetimeResult)'), + ); + foreach (['constSiblings', 'constBranches', 'constLoop', 'constWhile'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name . ' must exercise bytecode.'); + } + foreach ( + ['constWrite', 'constUpdate', 'constThenLet', 'letThenConst', 'constClosures', + 'constNested', 'constBeforeInit', 'constSelfInit', 'constOutside'] as $name + ) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled, $name . ' requires lexical environment semantics.'); + self::assertNull($function->phpCompiled); + } + } + + public function testInterpretedConstBlocksMatchTheSameNodeOracle(): void + { + $engine = new Engine(); + $engine->setExecutionBudget(10); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/const-block-lifetimes.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/const-block-lifetimes.json', + $engine->eval('JSON.stringify(constBlockLifetimeResult)'), + ); + } +} diff --git a/tests/Unit/Bytecode/fixtures/const-block-lifetimes.js b/tests/Unit/Bytecode/fixtures/const-block-lifetimes.js new file mode 100644 index 00000000..d0fd5e3b --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/const-block-lifetimes.js @@ -0,0 +1,105 @@ +'use strict'; + +function constSiblings(seed) { + const result = []; + { const value = seed; result.push(value); } + { const value = seed * 2; result.push(value); } + return result; +} +function constBranches(flag, seed) { + const result = []; + if (flag) { const value = seed; result.push(value); } + else { const value = seed + 1; result.push(value); } + { const value = seed + 2; result.push(value); } + return result; +} +function constLoop(count) { + const result = []; + for (let index = 0; index < count; index++) { + { const value = index; if (value % 2) continue; result.push(value); } + { const value = index + 10; result.push(value); } + } + return result; +} +function constWhile(input) { + const result = []; + let index = 0; + while (index < input.length) { + const value = input.charCodeAt(index++); + result.push(value); + if (value === 59) break; + } + while (index < input.length) { + const value = input.charCodeAt(index++); + if (value === 59) { + const part = index; + result.push(part); + } else if (value === 44) { + const part = index + 10; + result.push(part); + } + } + return result; +} +function constWrite(seed) { + const result = []; + { const value = seed; try { value = (result.push('rhs'), 9); } catch (error) { result.push(error.name, value); } } + { const value = seed + 1; try { value += (result.push('compound rhs'), 1); } catch (error) { result.push(error.name, value); } } + return result; +} +function constUpdate(seed) { + const result = []; + { const value = seed; try { value++; } catch (error) { result.push(error.name, value); } } + { const value = seed + 1; try { --value; } catch (error) { result.push(error.name, value); } } + return result; +} +function constThenLet(seed) { + const result = []; + { const value = seed; result.push(value); } + { let value = seed + 1; value++; result.push(value); } + return result; +} +function letThenConst(seed) { + const result = []; + { let value = seed; value++; result.push(value); } + { const value = seed + 1; result.push(value); } + return result; +} +function constClosures(count) { + const readers = []; + for (let index = 0; index < count; index++) { + { const value = index; readers.push(() => value); } + { const value = index + 10; readers.push(() => value); } + } + return readers.map(reader => reader()); +} +function constNested() { + const result = []; + { const value = 1; { const value = 2; result.push(value); } result.push(value); } + { const value = 3; result.push(value); } + return result; +} +function constBeforeInit() { + const result = []; + { try { result.push(value); } catch (error) { result.push(error.name); } const value = 1; result.push(value); } + { const value = 2; result.push(value); } + return result; +} +function constSelfInit() { + { const value = 1; } + { const value = value; return value; } +} +function constOutside() { + { const value = 1; } + { const value = 2; } + return typeof value; +} + +var constBlockLifetimeResult = []; +for (let repeat = 0; repeat < 3; repeat++) { + constBlockLifetimeResult.push(constSiblings(repeat + 1), constBranches(true, repeat), + constBranches(false, repeat), constLoop(4), constWhile('a;b;,c'), constWrite(repeat), + constUpdate(repeat), constThenLet(repeat), letThenConst(repeat), constClosures(3), + constNested(), constBeforeInit(), constOutside()); + try { constSelfInit(); } catch (error) { constBlockLifetimeResult.push(error.name); } +} diff --git a/tests/Unit/Bytecode/fixtures/const-block-lifetimes.json b/tests/Unit/Bytecode/fixtures/const-block-lifetimes.json new file mode 100644 index 00000000..046ff58b --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/const-block-lifetimes.json @@ -0,0 +1,200 @@ +[ + [ + 1, + 2 + ], + [ + 0, + 2 + ], + [ + 1, + 2 + ], + [ + 0, + 10, + 2, + 12 + ], + [ + 97, + 59, + 4, + 15 + ], + [ + "rhs", + "TypeError", + 0, + "compound rhs", + "TypeError", + 1 + ], + [ + "TypeError", + 0, + "TypeError", + 1 + ], + [ + 0, + 2 + ], + [ + 1, + 1 + ], + [ + 0, + 10, + 1, + 11, + 2, + 12 + ], + [ + 2, + 1, + 3 + ], + [ + "ReferenceError", + 1, + 2 + ], + "undefined", + "ReferenceError", + [ + 2, + 4 + ], + [ + 1, + 3 + ], + [ + 2, + 3 + ], + [ + 0, + 10, + 2, + 12 + ], + [ + 97, + 59, + 4, + 15 + ], + [ + "rhs", + "TypeError", + 1, + "compound rhs", + "TypeError", + 2 + ], + [ + "TypeError", + 1, + "TypeError", + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 2 + ], + [ + 0, + 10, + 1, + 11, + 2, + 12 + ], + [ + 2, + 1, + 3 + ], + [ + "ReferenceError", + 1, + 2 + ], + "undefined", + "ReferenceError", + [ + 3, + 6 + ], + [ + 2, + 4 + ], + [ + 3, + 4 + ], + [ + 0, + 10, + 2, + 12 + ], + [ + 97, + 59, + 4, + 15 + ], + [ + "rhs", + "TypeError", + 2, + "compound rhs", + "TypeError", + 3 + ], + [ + "TypeError", + 2, + "TypeError", + 3 + ], + [ + 2, + 4 + ], + [ + 3, + 3 + ], + [ + 0, + 10, + 1, + 11, + 2, + 12 + ], + [ + 2, + 1, + 3 + ], + [ + "ReferenceError", + 1, + 2 + ], + "undefined", + "ReferenceError" +] From f75d0f13d7fd3f2b2d1da40d78c94e52eea0ee24 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:44:53 +0200 Subject: [PATCH 19/99] Report Express case durations without changing upstream deadlines --- tests/Frameworks/express/runner.cjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Frameworks/express/runner.cjs b/tests/Frameworks/express/runner.cjs index a090dff0..b132507d 100644 --- a/tests/Frameworks/express/runner.cjs +++ b/tests/Frameworks/express/runner.cjs @@ -38,12 +38,12 @@ module.exports = function runExpressTests(files, options = {}) { }); runner.on('pass', (test) => { output.pass++; - output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'pass' }); + output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'pass', duration: test.duration }); if (output.tests.length % 100 === 0) checkpoint(); }); runner.on('fail', (test, error) => { output.fail++; - output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'fail', error: serializeError(error), responses }); + output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'fail', duration: test.duration, error: serializeError(error), responses }); checkpoint(); }); runner.on('pending', (test) => { From f16b549307a884b64713b096822d1bfeb4034309 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:41:14 +0200 Subject: [PATCH 20/99] Clamp array-like lengths before typed-array copy bounds checks --- src/BuiltIn/TypedArray/PrototypeMethods.php | 7 +--- tests/Unit/Runtime/ArrayBufferTest.php | 42 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/BuiltIn/TypedArray/PrototypeMethods.php b/src/BuiltIn/TypedArray/PrototypeMethods.php index cb9acceb..8923496b 100644 --- a/src/BuiltIn/TypedArray/PrototypeMethods.php +++ b/src/BuiltIn/TypedArray/PrototypeMethods.php @@ -113,7 +113,7 @@ function (JsValue $this_, array $args) use ($typeName): JsValue { $srcLen = $source->getLength(); $srcObj = $source; } elseif ($source instanceof JsObject) { - $srcLen = (int) TypeConversion::toNumber($source->get('length')); + $srcLen = TypeConversion::toLength($source->get('length')); $srcObj = $source; } elseif ($source instanceof JsString) { $str = $source->value; @@ -132,10 +132,7 @@ function (JsValue $this_, array $args) use ($typeName): JsValue { // wrapper whose prototype may carry length/indexed // properties (test262 monkey-patches Number.prototype). $srcObj = TypeConversion::toObject($source); - $srcLen = (int) TypeConversion::toNumber($srcObj->get('length')); - if ($srcLen < 0) { - $srcLen = 0; - } + $srcLen = TypeConversion::toLength($srcObj->get('length')); } // Per current spec, the size check uses the target length diff --git a/tests/Unit/Runtime/ArrayBufferTest.php b/tests/Unit/Runtime/ArrayBufferTest.php index 637722b4..7e563fd4 100644 --- a/tests/Unit/Runtime/ArrayBufferTest.php +++ b/tests/Unit/Runtime/ArrayBufferTest.php @@ -30,6 +30,48 @@ public function testLengthUsesToIndexValidation(): void $engine->eval('new ArrayBuffer(Infinity);'); } + public function testTypedArraySetClampsArrayLikeLengthsBeforeTheSizeCheck(): void + { + $engine = new Engine(); + $result = $engine->eval(<<<'JS' + const outcomes = []; + for (const length of [NaN, -Infinity, -3, 1.9, Infinity, 1e30]) { + for (const primitive of [false, true]) { + const effects = []; + const descriptors = { + length: {configurable: true, get() { + effects.push('length'); + return {valueOf() {effects.push('value'); return length;}}; + }}, + 0: {configurable: true, get() {effects.push('index'); return 7;}} + }; + const source = primitive ? 42 : Object.defineProperties({}, descriptors); + if (primitive) Object.defineProperties(Number.prototype, descriptors); + const target = new Uint8Array(2); + let error = null; + try { target.set(source); } catch (caught) {error = caught.name;} + finally { + if (primitive) { + delete Number.prototype.length; + delete Number.prototype[0]; + } + } + outcomes.push([error, Array.from(target), effects]); + } + } + JSON.stringify(outcomes); + JS); + + $empty = [null, [0, 0], ['length', 'value']]; + $copied = [null, [7, 0], ['length', 'value', 'index']]; + $large = ['RangeError', [0, 0], ['length', 'value']]; + self::assertSame( + json_encode([$empty, $empty, $empty, $empty, $empty, $empty, $copied, $copied, + $large, $large, $large, $large]), + $result, + ); + } + public function testImmutableSnapshotsKeepIndependentStorageAndRejectWritesBeforeCoercion(): void { $engine = new Engine(); From 6ece1d1a860e61ec28fe142aaf8ee2439e09688b Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:47:24 +0200 Subject: [PATCH 21/99] Document runtime fixes and link canonical compliance results --- CHANGELOG.md | 7 +++++-- README.md | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73b79ba1..98aa2984 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,9 @@ - Live Fetch request and response bodies retain streaming, cancellation and clone behavior; Node fetch can communicate with servers in the same engine. - Promise reactions preserve registration-time async context; cross-realm generators preserve their realm prototypes; global-property deletion and CommonJS cache behavior remain observable. - JSON property names and Unicode separators, callable proxies, and UTF-16 string indexing preserve JavaScript behavior across framework workloads. -- Recursive compiled calls keep captured bindings separate, completed VM frames release their references, and WeakMap entries no longer retain otherwise unreachable keys. +- Recursive compiled calls keep captured bindings separate, completed VM frames release their references, and WeakMap entries release unreachable keys without overflowing the host stack on deep chains. +- Symbol property writes preserve Proxy traps and receivers; typed-array copies clamp array-like lengths before checking destination bounds. +- Compiled identifier updates and strict program assignments retain their original references through coercion and right-hand-side effects. - Stream controllers, readers and writers retain their originating realm after VM context creation; pending Promise finalizers retain their registered async context. - Temporal calendar fields, arithmetic, rounding, parsing, timezone boundaries, and Intl formatting use consistent calendar data and option validation. - Module evaluation, source and typed imports, resource disposal, cross-realm intrinsics, numeric serialization, and compiled global bindings follow current language semantics. @@ -23,7 +25,8 @@ - Intl option precedence, legacy constructors, plural notation, numbering systems, and plain date/time formatting. ### Changed -- Bytecode compilation handles captured bindings, default initializers, array bindings, spread calls, computed methods, object prototypes, regular-expression literals and strict tail calls; reusable syntax templates keep closure state separate. +- Bytecode compilation handles captured bindings, default initializers, array bindings and assignments, optional chains, spread calls, computed methods, object prototypes, regular-expression literals and strict tail calls; reusable syntax templates keep closure state separate. +- Proven disjoint lexical scopes reuse frame slots, ordinary function prototypes materialize when observed, and numeric typed-array writes avoid redundant conversions while retaining buffer-resize and detachment behavior. - Protected returns preserve finalizer completion order in bytecode, and logical assignments and object relational operators use the shared JavaScript semantics. - Bounded regular-expression preparation and cached UTF-16 searches reduce repeated work while preserving fresh objects and observable coercions. - The test262 runner executes both variants of unflagged scripts, preserves raw sources and module parse goals, requires async completion, and checks negative-test error types and phases. diff --git a/README.md b/README.md index 61b547e9..9f51d103 100644 --- a/README.md +++ b/README.md @@ -138,9 +138,9 @@ CI runs PHPStan, PHPCS, the unit suite and the oracle regression on every push t | JavaScriptCore (Safari) | 99.4 % | | QuickJS | ~97 % | | Hermes (React Native) | ~95 % | -| **Phasis** | **100 %** | +| **Phasis** | **[Canonical results](./COMPAT.md)** | -Every test in the pinned test262 revision passes, every category. See [`COMPAT.md`](./COMPAT.md) for the latest snapshot. Other engines' numbers are from [test262.fyi](https://test262.fyi). +The complete CI matrix accounts for every discovered file in the pinned test262 revision. Its canonical report records passes, failures, skips and blocked tests by category. Other engines' numbers are from [test262.fyi](https://test262.fyi). ## Performance From abadb988bfbb598c3340596628e4e2017d22187d Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:48:01 +0200 Subject: [PATCH 22/99] Inline compiled functions with tail-call returns --- src/Bytecode/VM.php | 21 +++- tests/Unit/Bytecode/InlineTailCallTest.php | 79 ++++++++++++++ .../Bytecode/fixtures/inline-tail-calls.cjs | 101 ++++++++++++++++++ .../fixtures/inline-tail-calls.expected.json | 32 ++++++ 4 files changed, 228 insertions(+), 5 deletions(-) create mode 100644 tests/Unit/Bytecode/InlineTailCallTest.php create mode 100644 tests/Unit/Bytecode/fixtures/inline-tail-calls.cjs create mode 100644 tests/Unit/Bytecode/fixtures/inline-tail-calls.expected.json diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index b4a98c62..87f4f87d 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -7,6 +7,7 @@ use Phasis\Exceptions\InternalError; use Phasis\Exceptions\TypeError; use Phasis\Runtime\Interpreter; +use Phasis\Runtime\TailCallThunk; use Phasis\Spec\AbstractOperations; use Phasis\Spec\TypeConversion; use Phasis\Value\JsBoolean; @@ -1657,8 +1658,7 @@ public function execute( // strict / arrow / sloppy callees. $inlineable = $callee->vmInlineCallCache; if ($inlineable === null) { - $inlineable = $eligible && !$callee->compiled->hasTailCalls - && $callee->getBoundTarget() === null; + $inlineable = $eligible && $callee->getBoundTarget() === null; if ($inlineable) { $callee->vmInlineCallCache = true; } @@ -2197,9 +2197,7 @@ public function execute( } $methodInlineable = $method->vmInlineCallCache; if ($methodInlineable === null) { - $methodInlineable = $methodEligible - && !$method->compiled->hasTailCalls - && $method->getBoundTarget() === null; + $methodInlineable = $methodEligible && $method->getBoundTarget() === null; if ($methodInlineable) { $method->vmInlineCallCache = true; } @@ -2737,6 +2735,19 @@ public function execute( $hasHandlers = $sf->hasHandlers; $pc = $sf->returnPc; $sf->release(); + if ($finalResult instanceof TailCallThunk) { + // The returning activation is gone before the + // trampoline invokes its target. Keep the caller + // at the call instruction until that invocation + // completes so its catch/finally covers failures. + $pc -= 2; + $finalResult = $this->interp->callFunction( + $finalResult->function, + $finalResult->thisValue, + $finalResult->args, + ); + $pc += 2; + } $stack[$sp++] = $finalResult; break; } diff --git a/tests/Unit/Bytecode/InlineTailCallTest.php b/tests/Unit/Bytecode/InlineTailCallTest.php new file mode 100644 index 00000000..1b1d4f84 --- /dev/null +++ b/tests/Unit/Bytecode/InlineTailCallTest.php @@ -0,0 +1,79 @@ + */ + public static function executionModes(): iterable + { + yield 'bytecode' => [false]; + yield 'interpreter' => [true]; + } + + #[DataProvider('executionModes')] + public function testTailReturnsMatchNodeAcrossCallerAndCalleeKinds(bool $interpret): void + { + $engine = new Engine(node: true); + if ($interpret) { + $engine->setExecutionBudget(1_000_000); + } + $engine->execFile(__DIR__ . '/fixtures/inline-tail-calls.cjs'); + $result = $engine->eval('globalThis.__inlineTailObservations'); + self::assertIsString($result); + self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/inline-tail-calls.expected.json', $result); + if (!$interpret) { + $functions = $engine->getGlobalEnv()->get('__inlineTailFunctions'); + self::assertInstanceOf(JsArray::class, $functions); + foreach ($functions->getDenseElements() as $function) { + self::assertInstanceOf(JsFunction::class, $function); + self::assertTrue($function->vmInlineCallCache, $function->getName() . ' must use inline calls.'); + } + } + } + + public function testDeepTailRecursionFromAnInlineCalleeDoesNotRetainTheReturningFrame(): void + { + $engine = new Engine(); + self::assertSame([20000, 20001], $engine->eval(<<<'JS' +'use strict'; +function tail(count, total) { + return count === 0 ? total : tail(count - 1, total + 1); +} +function intermediate(count) { return tail(count, 0); } +function caller(count) { + const first = intermediate(count); + const second = intermediate(count + 1); + return [first, second]; +} +intermediate(1); +caller(1); +caller(20000); +JS)); + $function = $engine->getGlobalEnv()->get('intermediate'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertTrue($function->vmInlineCallCache); + } + + public function testTailTargetObservesTheCallerAfterTheInlineFrameIsRemoved(): void + { + $engine = new Engine(); + $engine->setGlobal('stackDepth', fn (): int => $engine->getInterpreter()->getCallStack()->depth()); + self::assertSame([1, 1], $engine->eval(<<<'JS' +'use strict'; +function returning() { return stackDepth(); } +function caller() { const value = returning(); return value; } +returning(); +[caller(), caller()]; +JS)); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } +} diff --git a/tests/Unit/Bytecode/fixtures/inline-tail-calls.cjs b/tests/Unit/Bytecode/fixtures/inline-tail-calls.cjs new file mode 100644 index 00000000..654a3c34 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/inline-tail-calls.cjs @@ -0,0 +1,101 @@ +'use strict'; + +const observations = []; +function identity(value) { return value; } +function fail(value) { throw new RangeError('range:' + value); } +function mixed(value) { + if (value === 0) return 40; + return value > 0 ? Math.max(value, 3) : fail(value); +} +function invoke(fn, value) { + const result = fn(value); + return result; +} +function invokeMethod(receiver, value) { + const result = receiver.invoke(value); + return result; +} +function protectedCall(fn, value) { + try { return fn(value); } + catch (error) { observations.push('catch'); return error.message; } + finally { observations.push('finally'); } +} +function cleanupCall(fn, value) { + try { return fn(value); } + finally { observations.push('cleanup'); } +} +function recoveredCleanup(fn, value) { + try { return cleanupCall(fn, value); } + catch (error) { return error.message; } +} + +mixed(0); +invoke(mixed, 0); +invokeMethod({ invoke: mixed }, 0); +observations.push(invoke(mixed, 0), invoke(mixed, 8), invokeMethod({ invoke: mixed }, 9)); +observations.push(protectedCall(mixed, -1), recoveredCleanup(mixed, -2)); +observations.push(protectedCall(mixed, 0)); + +function nativeFailure() { return JSON.parse('!'); } +function errorIdentity(fn) { + try { fn(); } + catch (error) { return error.constructor === SyntaxError; } +} +errorIdentity(nativeFailure); +observations.push(errorIdentity(nativeFailure), errorIdentity(nativeFailure)); + +function tailThis() { return identity(this); } +const receiver = { invoke: tailThis }; +receiver.invoke(); +observations.push(invokeMethod(receiver) === receiver, invoke(tailThis) === undefined); +function argumentsTail() { return Math.max(...arguments); } +argumentsTail(1, 2); +observations.push(invoke(argumentsTail, 13)); +function arrowFactory(argument) { + return () => identity([this.tag, arguments[0], argument]); +} +const arrow = arrowFactory.call({ tag: 'lexical' }, 17); +arrow(); +observations.push(invoke(arrow)); + +function TailPrimitive(value) { this.value = value; return Math.max(100, value); } +function TailObject(value) { return identity({ value }); } +function construct(Constructor, value) { return new Constructor(value); } +construct(TailPrimitive, 1); +construct(TailObject, 1); +observations.push(construct(TailPrimitive, 19).value, construct(TailObject, 23).value); + +const vm = require('node:vm'); +const sandbox = vm.createContext({}); +const foreign = vm.runInContext(`({ + Number, + SyntaxError, + target: function target(value) { + 'use strict'; + return value ? Object(value) : JSON.parse('!'); + } +})`, sandbox); +foreign.target(1); +invoke(foreign.target, 1); +observations.push(Object.getPrototypeOf(invoke(foreign.target, 7)) === foreign.Number.prototype); +function foreignError(fn) { + try { fn(0); } + catch (error) { return error.constructor === foreign.SyntaxError; } +} +observations.push(foreignError(foreign.target), foreignError(foreign.target)); +observations.push(Object.getPrototypeOf({}) === Object.prototype); + +async function asyncTarget(value) { return value + 3; } +function asyncTail(value) { return asyncTarget(value); } +asyncTail(0); +const asyncReceiver = { invoke: asyncTail }; +globalThis.__inlineTailDone = Promise.all([ + invoke(asyncTail, 27), + invokeMethod(asyncReceiver, 28), +]).then(values => { + observations.push(values); + globalThis.__inlineTailObservations = JSON.stringify(observations); + return observations; +}); + +globalThis.__inlineTailFunctions = [mixed, tailThis, asyncTail]; diff --git a/tests/Unit/Bytecode/fixtures/inline-tail-calls.expected.json b/tests/Unit/Bytecode/fixtures/inline-tail-calls.expected.json new file mode 100644 index 00000000..ddad3f6a --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/inline-tail-calls.expected.json @@ -0,0 +1,32 @@ +[ + 40, + 8, + 9, + "catch", + "finally", + "cleanup", + "range:-1", + "range:-2", + "finally", + 40, + true, + true, + true, + true, + 13, + [ + "lexical", + 17, + 17 + ], + 19, + 23, + true, + true, + true, + true, + [ + 30, + 31 + ] +] From 7d21bda71da96022577f43b600f73206bebc3c9b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 23 Oct 2026 20:59:30 +0000 Subject: [PATCH 23/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 61 +++++++------- compat.json | 227 ++++++++++++++++++++++++---------------------------- 2 files changed, 130 insertions(+), 158 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index d28cbbbd..729700c2 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,30 +3,30 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-23T19:29:41+00:00` +- Snapshot time: `2026-10-23T20:59:28+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `0cef9bc9` (dirty) +- Git: `feat/express-hono-compatibility` @ `abadb988` (dirty) ## Summary | Pass | Fail | Skip | Blocked | Pending | Running | Attempted | Known | Total | Pass Rate | |---:|---:|---:|---:|---:|---:|---:|---:|---:|---:| -| 53614 | 0 | 0 | 2 | 0 | 0 | 53614 | 53616 | 53616 | 99.9% | +| 53616 | 0 | 0 | 0 | 0 | 0 | 53616 | 53616 | 53616 | 100.0% | ## Top-Level Areas | Area | Status | Pass | Fail | Skip | Blocked | Pending | Running | Pass Rate | |---|---|---:|---:|---:|---:|---:|---:|---:| | annexB | PASS | 1086 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| built-ins | BLOCKED | 23822 | 0 | 0 | 1 | 0 | 0 | 99.9% | +| built-ins | PASS | 23823 | 0 | 0 | 0 | 0 | 0 | 100.0% | | harness | PASS | 116 | 0 | 0 | 0 | 0 | 0 | 100.0% | | intl402 | PASS | 3382 | 0 | 0 | 0 | 0 | 0 | 100.0% | | language | PASS | 23726 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| staging | BLOCKED | 1482 | 0 | 0 | 1 | 0 | 0 | 99.9% | +| staging | PASS | 1483 | 0 | 0 | 0 | 0 | 0 | 100.0% | ## Group Coverage @@ -124,7 +124,7 @@ Generated from a completed `test262` pass. Do not edit by hand. | built-ins/WeakRef | PASS | 29 | 0 | 0 | 0 | 0 | 0 | 100.0% | | built-ins/WeakSet | PASS | 85 | 0 | 0 | 0 | 0 | 0 | 100.0% | | built-ins/decodeURI | PASS | 55 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| built-ins/decodeURIComponent | BLOCKED | 55 | 0 | 0 | 1 | 0 | 0 | 99.9% | +| built-ins/decodeURIComponent | PASS | 56 | 0 | 0 | 0 | 0 | 0 | 100.0% | | built-ins/encodeURI | PASS | 31 | 0 | 0 | 0 | 0 | 0 | 100.0% | | built-ins/encodeURIComponent | PASS | 31 | 0 | 0 | 0 | 0 | 0 | 100.0% | | built-ins/eval | PASS | 10 | 0 | 0 | 0 | 0 | 0 | 100.0% | @@ -190,41 +190,34 @@ Generated from a completed `test262` pass. Do not edit by hand. | staging/decorators | PASS | 3 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/explicit-resource-management | PASS | 53 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/set-methods | PASS | 3 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| staging/sm | BLOCKED | 1405 | 0 | 0 | 1 | 0 | 0 | 99.9% | +| staging/sm | PASS | 1406 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/source-phase-imports | PASS | 2 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/top-level-await | PASS | 1 | 0 | 0 | 0 | 0 | 0 | 100.0% | -## Blocked Chunks - -| Group | Kind | Files | Sample | Log | -|---|---|---:|---|---| -| built-ins/decodeURIComponent | CRASH | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | `.compat-state-builtins-lower-de/logs/f3e05d6b74efcc2f559417cc3812a891e061afb3.log` | -| staging/sm | ERROR | 1 | `test262/test/staging/sm/regress/regress-1507322-deep-weakmap.js` | `.compat-state-staging/logs/88d920a3605ea3645888b001a85c1db6abe87399.log` | - ## Slowest Chunks | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| built-ins/decodeURI | NORMAL | 339.582s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| built-ins/decodeURIComponent | CRASH | 200.998s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| built-ins/decodeURI | NORMAL | 118.793s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | -| built-ins/decodeURIComponent | NORMAL | 117.558s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | -| staging/sm | NORMAL | 111.026s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 105.210s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 103.433s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 101.988s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 93.660s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| staging/sm | NORMAL | 91.624s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 89.372s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| staging/sm | NORMAL | 84.784s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| language/literals | NORMAL | 84.199s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | -| staging/sm | NORMAL | 82.111s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| built-ins/TypedArray | NORMAL | 79.193s | 3 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end.js` | -| staging/sm | NORMAL | 70.267s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| annexB/built-ins/RegExp | NORMAL | 63.933s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.467s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.460s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Kaithi.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Kannada.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Katakana.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.283s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js` | +| built-ins/decodeURIComponent | NORMAL | 164.778s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| built-ins/decodeURI | NORMAL | 152.068s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| staging/sm | NORMAL | 101.214s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 95.531s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 93.249s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 93.032s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 92.547s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 87.236s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| staging/sm | NORMAL | 86.367s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| staging/sm | NORMAL | 84.503s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 79.182s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| built-ins/decodeURIComponent | NORMAL | 73.724s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | +| built-ins/decodeURI | NORMAL | 73.305s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | +| built-ins/TypedArray | NORMAL | 67.029s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | +| staging/sm | NORMAL | 66.216s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.857s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.800s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Casemapped.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Lowercased.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_NFKC_Casefolded.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Titlecased.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Uppercased.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.646s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.553s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Rejang.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Runic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Samaritan.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.434s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Rejang.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Runic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Samaritan.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 2fa8e781..5ee71aab 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-23T19:29:41+00:00", - "updatedAt": "2026-10-23T19:29:41+00:00", + "generatedAt": "2026-10-23T20:59:28+00:00", + "updatedAt": "2026-10-23T20:59:28+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "0cef9bc9", + "commit": "abadb988", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "8e553d824afc3ec9e06fcd3df4c41746adeb4019", - "runIdentity": "037d3bd075bf5d91559fdf9858948b6d0d8d69a1878381499d9538215288d7e4" + "fingerprint": "72868dfbadaca547434f95b5de8c7b030e636d10", + "runIdentity": "a878cf1e2c8be2856f6265d62cde682ad28c89a9d2c09aecce536d3f4997918c" }, "discovery": { "groupCount": 161, @@ -199,16 +199,16 @@ "test262": { "skippedFeatures": [], "totals": { - "pass": 53614, + "pass": 53616, "fail": 0, "skip": 0, - "blocked": 2, + "blocked": 0, "pending": 0, "running": 0, - "attempted": 53614, + "attempted": 53616, "known": 53616, "total": 53616, - "passRate": 99.9 + "passRate": 100 }, "areas": [ { @@ -227,17 +227,17 @@ }, { "name": "built-ins", - "status": "blocked", - "pass": 23822, + "status": "pass", + "pass": 23823, "fail": 0, "skip": 0, - "blocked": 1, + "blocked": 0, "pending": 0, "running": 0, - "attempted": 23822, + "attempted": 23823, "known": 23823, "total": 23823, - "passRate": 99.9 + "passRate": 100 }, { "name": "harness", @@ -283,17 +283,17 @@ }, { "name": "staging", - "status": "blocked", - "pass": 1482, + "status": "pass", + "pass": 1483, "fail": 0, "skip": 0, - "blocked": 1, + "blocked": 0, "pending": 0, "running": 0, - "attempted": 1482, + "attempted": 1483, "known": 1483, "total": 1483, - "passRate": 99.9 + "passRate": 100 } ], "groups": [ @@ -1680,17 +1680,17 @@ { "name": "built-ins/decodeURIComponent", "area": "built-ins", - "status": "blocked", - "pass": 55, + "status": "pass", + "pass": 56, "fail": 0, "skip": 0, - "blocked": 1, + "blocked": 0, "pending": 0, "running": 0, - "attempted": 55, + "attempted": 56, "known": 56, "total": 56, - "passRate": 99.9 + "passRate": 100 }, { "name": "built-ins/encodeURI", @@ -2670,17 +2670,17 @@ { "name": "staging/sm", "area": "staging", - "status": "blocked", - "pass": 1405, + "status": "pass", + "pass": 1406, "fail": 0, "skip": 0, - "blocked": 1, + "blocked": 0, "pending": 0, "running": 0, - "attempted": 1405, + "attempted": 1406, "known": 1406, "total": 1406, - "passRate": 99.9 + "passRate": 100 }, { "name": "staging/source-phase-imports", @@ -2714,42 +2714,12 @@ } ], "failures": [], - "blockedChunks": [ - { - "group": "built-ins/decodeURIComponent", - "kind": "crash", - "message": "PHP Fatal error: Maximum execution time of 200 seconds exceeded in /home/runner/work/phasis/phasis/src/Value/JsString.php on line 30", - "filesCount": 1, - "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" - ], - "logFile": ".compat-state-builtins-lower-de/logs/f3e05d6b74efcc2f559417cc3812a891e061afb3.log" - }, - { - "group": "staging/sm", - "kind": "error", - "message": "Segmentation fault (core dumped)", - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/regress/regress-1507322-deep-weakmap.js" - ], - "logFile": ".compat-state-staging/logs/88d920a3605ea3645888b001a85c1db6abe87399.log" - } - ], + "blockedChunks": [], "slowChunks": [ - { - "group": "built-ins/decodeURI", - "kind": "normal", - "durationSec": 339.582, - "filesCount": 1, - "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" - ] - }, { "group": "built-ins/decodeURIComponent", - "kind": "crash", - "durationSec": 200.998, + "kind": "normal", + "durationSec": 164.778, "filesCount": 1, "sampleFiles": [ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" @@ -2758,69 +2728,61 @@ { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 118.793, - "filesCount": 25, + "durationSec": 152.068, + "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", - "...", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" ] }, { - "group": "built-ins/decodeURIComponent", + "group": "staging/sm", "kind": "normal", - "durationSec": 117.558, - "filesCount": 25, + "durationSec": 101.214, + "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", - "...", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" + "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 111.026, + "durationSec": 95.531, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 105.21, + "durationSec": 93.249, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 103.433, + "durationSec": 93.032, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 101.988, + "durationSec": 92.547, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 93.66, + "durationSec": 87.236, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" @@ -2829,16 +2791,16 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 91.624, + "durationSec": 86.367, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 89.372, + "durationSec": 84.503, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" @@ -2847,98 +2809,115 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 84.784, + "durationSec": 79.182, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { - "group": "language/literals", + "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 84.199, + "durationSec": 73.724, "filesCount": 25, "sampleFiles": [ - "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", - "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", "...", - "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", - "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" ] }, { - "group": "staging/sm", + "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 82.111, - "filesCount": 1, + "durationSec": 73.305, + "filesCount": 25, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", + "...", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" ] }, { "group": "built-ins/TypedArray", "kind": "normal", - "durationSec": 79.193, - "filesCount": 3, + "durationSec": 67.029, + "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js", - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end.js" + "...", + "test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js", + "test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 70.267, + "durationSec": 66.216, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { - "group": "annexB/built-ins/RegExp", + "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 63.933, - "filesCount": 25, + "durationSec": 59.857, + "filesCount": 3, "sampleFiles": [ - "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", - "test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js", - "...", - "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js", - "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.467, + "durationSec": 59.8, + "filesCount": 5, + "sampleFiles": [ + "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Casemapped.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Lowercased.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_NFKC_Casefolded.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Titlecased.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Uppercased.js" + ] + }, + { + "group": "built-ins/RegExp/property-escapes/generated", + "kind": "normal", + "durationSec": 59.646, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.46, + "durationSec": 59.553, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Kaithi.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Kannada.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Katakana.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Rejang.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Runic.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Samaritan.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.283, + "durationSec": 59.434, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Rejang.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Runic.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Samaritan.js" ] } ] From 700c5d67db43a438ed51e508880c4a581b4f8cb8 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:54:49 +0200 Subject: [PATCH 24/99] Format runtime oracle fixtures for the full code-standard gate --- .../fixtures/lazy-function-prototype.js | 109 +++++----- .../Unit/Runtime/fixtures/proxy-symbol-set.js | 200 +++++++++--------- 2 files changed, 164 insertions(+), 145 deletions(-) diff --git a/tests/Unit/Runtime/fixtures/lazy-function-prototype.js b/tests/Unit/Runtime/fixtures/lazy-function-prototype.js index 4e35fda0..e78cceb1 100644 --- a/tests/Unit/Runtime/fixtures/lazy-function-prototype.js +++ b/tests/Unit/Runtime/fixtures/lazy-function-prototype.js @@ -1,27 +1,31 @@ (() => { - 'use strict'; - const observations = []; - const attempt = callback => { - try { return callback(); } catch (error) { return error.name; } - }; - const attributes = descriptor => [ + 'use strict'; + const observations = []; + const attempt = callback => { + try { + return callback(); } catch (error) { + return error.name; } + }; + const attributes = descriptor => [ descriptor.writable, descriptor.enumerable, descriptor.configurable, 'get' in descriptor, 'set' in descriptor - ]; + ]; - const first = function First() {}; - first.extra = 1; - const order = Reflect.ownKeys(first); - const descriptor = Object.getOwnPropertyDescriptor(first, 'prototype'); - const prototype = descriptor.value; - observations.push([ + const first = function First() + {}; + first.extra = 1; + const order = Reflect.ownKeys(first); + const descriptor = Object.getOwnPropertyDescriptor(first, 'prototype'); + const prototype = descriptor.value; + observations.push([ order, Reflect.ownKeys(first), attributes(descriptor), Reflect.ownKeys(prototype), attributes(Object.getOwnPropertyDescriptor(prototype, 'constructor')), prototype.constructor === first, Object.getPrototypeOf(prototype) === Object.prototype, prototype === first.prototype, Object.getPrototypeOf(new first()) === prototype - ]); + ]); - const inherited = function Inherited() {}; + const inherited = function Inherited() + {}; const child = Object.create(inherited); const inheritedPrototype = child.prototype; observations.push([ @@ -31,18 +35,20 @@ Object.getOwnPropertyDescriptors(inherited).prototype.value === inheritedPrototype ]); - for (const value of [undefined, null, 23, 'replacement', { custom: true }]) { - const changed = function Changed() {}; +for (const value of [undefined, null, 23, 'replacement', { custom: true }]) { + const changed = function Changed() + {}; changed.prototype = value; observations.push([ - changed.prototype === value, - Object.getOwnPropertyDescriptor(changed, 'prototype').value === value, - attributes(Object.getOwnPropertyDescriptor(changed, 'prototype')), - Object.getPrototypeOf(new changed()) === (typeof value === 'object' && value !== null ? value : Object.prototype) + changed.prototype === value, + Object.getOwnPropertyDescriptor(changed, 'prototype').value === value, + attributes(Object.getOwnPropertyDescriptor(changed, 'prototype')), + Object.getPrototypeOf(new changed()) === (typeof value === 'object' && value !== null ? value : Object.prototype) ]); - } +} - const defined = function Defined() {}; + const defined = function Defined() + {}; const replacement = {}; Object.defineProperty(defined, 'prototype', { value: replacement, writable: false }); observations.push([ @@ -54,7 +60,8 @@ attributes(Object.getOwnPropertyDescriptor(defined, 'prototype')) ]); - const locked = function Locked() {}; + const locked = function Locked() + {}; Object.defineProperty(locked, 'prototype', { writable: false }); observations.push([ typeof locked.prototype, locked.prototype.constructor === locked, @@ -65,8 +72,9 @@ attributes(Object.getOwnPropertyDescriptor(locked, 'prototype')) ]); - for (const operation of [Object.preventExtensions, Object.seal, Object.freeze]) { - const restricted = function Restricted() {}; +for (const operation of [Object.preventExtensions, Object.seal, Object.freeze]) { + const restricted = function Restricted() + {}; // Node 26.12 reports a sealed strict function as frozen despite its writable // prototype. An ordinary own property avoids that V8 anomaly; the prototype // descriptor and replacement behavior are still checked directly below. @@ -74,16 +82,17 @@ operation(restricted); const initial = restricted.prototype; observations.push([ - initial.constructor === restricted, - Object.isExtensible(restricted), Object.isSealed(restricted), Object.isFrozen(restricted), - attributes(Object.getOwnPropertyDescriptor(restricted, 'prototype')), - Reflect.set(restricted, 'prototype', null), - Object.getPrototypeOf(new restricted()) === (restricted.prototype === null ? Object.prototype : initial), - Reflect.deleteProperty(restricted, 'prototype') + initial.constructor === restricted, + Object.isExtensible(restricted), Object.isSealed(restricted), Object.isFrozen(restricted), + attributes(Object.getOwnPropertyDescriptor(restricted, 'prototype')), + Reflect.set(restricted, 'prototype', null), + Object.getPrototypeOf(new restricted()) === (restricted.prototype === null ? Object.prototype : initial), + Reflect.deleteProperty(restricted, 'prototype') ]); - } +} - const removed = function Removed() {}; + const removed = function Removed() + {}; observations.push([ Reflect.deleteProperty(removed, 'prototype'), attempt(() => { delete removed.prototype; }), @@ -93,20 +102,21 @@ removed.prototype.constructor === removed ]); - const frozen = function Frozen() {}; + const frozen = function Frozen() + {}; Object.defineProperty(frozen, 'prototype', { writable: false }); const dishonest = new Proxy(frozen, { - get(target, name) { return name === 'prototype' ? {} : Reflect.get(target, name); }, - getOwnPropertyDescriptor(target, name) { - return name === 'prototype' - ? { value: {}, writable: false, enumerable: false, configurable: false } - : Reflect.getOwnPropertyDescriptor(target, name); - }, - defineProperty() { return true; }, - set() { return true; }, - deleteProperty() { return true; }, - ownKeys() { return ['length', 'name']; } - }); + get(target, name) { return name === 'prototype' ? {} : Reflect.get(target, name); }, + getOwnPropertyDescriptor(target, name) { + return name === 'prototype' + ? { value : {}, writable : false, enumerable : false, configurable : false } + : Reflect.getOwnPropertyDescriptor(target, name); + }, + defineProperty() { return true; }, + set() { return true; }, + deleteProperty() { return true; }, + ownKeys() { return ['length', 'name']; } + }); observations.push([ attempt(() => dishonest.prototype), attempt(() => Object.getOwnPropertyDescriptor(dishonest, 'prototype')), @@ -117,7 +127,8 @@ frozen.prototype.constructor === frozen ]); - const mutable = function Mutable() {}; + const mutable = function Mutable() + {}; const proxyValue = {}; observations.push([ new Proxy(mutable, { get() { return proxyValue; } }).prototype === proxyValue, @@ -127,7 +138,9 @@ const dynamic = new Function('"use strict"; return 3;'); const method = { method() {} }.method; - const generator = function* () { yield 1; }; + const generator = function * () + { + yield 1; }; observations.push([ dynamic.prototype.constructor === dynamic, new dynamic() instanceof dynamic, diff --git a/tests/Unit/Runtime/fixtures/proxy-symbol-set.js b/tests/Unit/Runtime/fixtures/proxy-symbol-set.js index 269fa080..69538388 100644 --- a/tests/Unit/Runtime/fixtures/proxy-symbol-set.js +++ b/tests/Unit/Runtime/fixtures/proxy-symbol-set.js @@ -1,130 +1,136 @@ 'use strict'; -function writeSymbol(target, key, value) { target[key] = value; return value; } -function readSymbol(target, key) { return target[key]; } -function outcome(action) { - try { return action(); } - catch (error) { return error.name; } +function writeSymbol(target, key, value) +{ + target[key] = value; return value; } +function readSymbol(target, key) +{ + return target[key]; } +function outcome(action) +{ + try { + return action(); } catch (error) { + return error.name; } } var proxySymbolSetResult = []; for (let repeat = 0; repeat < 3; repeat++) { - const key = Symbol('cache'); - const trace = []; - const target = {}; - const wrapper = new Proxy(target, { - set(object, property, value, receiver) { - trace.push(['set', property === key, receiver === wrapper]); - return Reflect.set(object, property, value, receiver); - }, - getOwnPropertyDescriptor(object, property) { - trace.push(['own', property === key]); - return Reflect.getOwnPropertyDescriptor(object, property); - }, - defineProperty(object, property, descriptor) { - trace.push(['define', property === key, Object.keys(descriptor).sort()]); - return Reflect.defineProperty(object, property, descriptor); - } - }); - writeSymbol(wrapper, key, 1); - writeSymbol(wrapper, key, 2); - proxySymbolSetResult.push(['normal', readSymbol(wrapper, key), target[key], trace]); + const key = Symbol('cache'); + const trace = []; + const target = {}; + const wrapper = new Proxy(target, { + set(object, property, value, receiver) { + trace.push(['set', property === key, receiver === wrapper]); + return Reflect.set(object, property, value, receiver); + }, + getOwnPropertyDescriptor(object, property) { + trace.push(['own', property === key]); + return Reflect.getOwnPropertyDescriptor(object, property); + }, + defineProperty(object, property, descriptor) { + trace.push(['define', property === key, Object.keys(descriptor).sort()]); + return Reflect.defineProperty(object, property, descriptor); + } + }); + writeSymbol(wrapper, key, 1); + writeSymbol(wrapper, key, 2); + proxySymbolSetResult.push(['normal', readSymbol(wrapper, key), target[key], trace]); - const receiverTarget = {}; - const receiverTrace = []; - const receiver = new Proxy(receiverTarget, { - isExtensible() { throw new Error('Unexpected extensibility query'); }, - getOwnPropertyDescriptor(object, property) { - receiverTrace.push('own'); - return Reflect.getOwnPropertyDescriptor(object, property); - }, - defineProperty(object, property, descriptor) { - receiverTrace.push(['define', Object.keys(descriptor).sort()]); - return Reflect.defineProperty(object, property, descriptor); - } - }); - proxySymbolSetResult.push(['receiver', Reflect.set(target, key, 3, receiver), + const receiverTarget = {}; + const receiverTrace = []; + const receiver = new Proxy(receiverTarget, { + isExtensible() { throw new Error('Unexpected extensibility query'); }, + getOwnPropertyDescriptor(object, property) { + receiverTrace.push('own'); + return Reflect.getOwnPropertyDescriptor(object, property); + }, + defineProperty(object, property, descriptor) { + receiverTrace.push(['define', Object.keys(descriptor).sort()]); + return Reflect.defineProperty(object, property, descriptor); + } + }); + proxySymbolSetResult.push(['receiver', Reflect.set(target, key, 3, receiver), Reflect.set(new Proxy(target, {}), key, 4, receiver), receiverTarget[key], target[key], receiverTrace]); - const nestedTarget = {}; - const nested = new Proxy(new Proxy(nestedTarget, {}), {}); - writeSymbol(nested, key, 5); - proxySymbolSetResult.push(['nested fallback', nested[key], nestedTarget[key]]); + const nestedTarget = {}; + const nested = new Proxy(new Proxy(nestedTarget, {}), {}); + writeSymbol(nested, key, 5); + proxySymbolSetResult.push(['nested fallback', nested[key], nestedTarget[key]]); - const denied = new Proxy({}, { set() { return false; } }); - proxySymbolSetResult.push(['false set', Reflect.set(denied, key, 1), + const denied = new Proxy({}, { set() { return false; } }); + proxySymbolSetResult.push(['false set', Reflect.set(denied, key, 1), outcome(() => writeSymbol(denied, key, 2)), Function('target', 'key', 'return target[key] = 3')(denied, key), outcome(() => Object.assign(denied, { [key]: 4 }))]); - const defineDenied = new Proxy({}, { defineProperty() { return false; } }); - proxySymbolSetResult.push(['false define', Reflect.set(defineDenied, key, 1), + const defineDenied = new Proxy({}, { defineProperty() { return false; } }); + proxySymbolSetResult.push(['false define', Reflect.set(defineDenied, key, 1), outcome(() => writeSymbol(defineDenied, key, 2))]); - const primitives = [undefined, null, 3, false, 'receiver', key]; - const primitiveResults = []; - for (const primitive of primitives) { - const ordinary = {}; - const proxy = new Proxy(ordinary, {}); - const setterTrace = []; - const accessor = Object.create(null, { - [key]: { set(value) { setterTrace.push([this === primitive, value]); } } - }); - primitiveResults.push([Reflect.set(proxy, key, 1, primitive), ordinary[key], - Reflect.set(new Proxy(accessor, {}), key, 2, primitive), - Reflect.set(accessor, key, 3, primitive), setterTrace]); - } - proxySymbolSetResult.push(['primitive receivers', primitiveResults]); - - const inheritedTrace = []; - const inherited = new Proxy({}, { - set(object, property, value, receiver) { - inheritedTrace.push([property === key, receiver === child]); - return Reflect.set(object, property, value, receiver); + const primitives = [undefined, null, 3, false, 'receiver', key]; + const primitiveResults = []; + for (const primitive of primitives) { + const ordinary = {}; + const proxy = new Proxy(ordinary, {}); + const setterTrace = []; + const accessor = Object.create(null, { + [key]: { set(value) { setterTrace.push([this === primitive, value]); } } + }); + primitiveResults.push([Reflect.set(proxy, key, 1, primitive), ordinary[key], + Reflect.set(new Proxy(accessor, {}), key, 2, primitive), + Reflect.set(accessor, key, 3, primitive), setterTrace]); } - }); - const child = Object.create(inherited); - writeSymbol(child, key, 8); - proxySymbolSetResult.push(['prototype proxy', child[key], Reflect.ownKeys(child).length, + proxySymbolSetResult.push(['primitive receivers', primitiveResults]); + + const inheritedTrace = []; + const inherited = new Proxy({}, { + set(object, property, value, receiver) { + inheritedTrace.push([property === key, receiver === child]); + return Reflect.set(object, property, value, receiver); + } + }); + const child = Object.create(inherited); + writeSymbol(child, key, 8); + proxySymbolSetResult.push(['prototype proxy', child[key], Reflect.ownKeys(child).length, Reflect.ownKeys(inherited).length, inheritedTrace]); - const receiverReadOnly = Object.defineProperty({}, key, { value: 1 }); - const receiverAccessor = Object.defineProperty({}, key, { set() { throw 'unexpected setter'; } }); - proxySymbolSetResult.push(['receiver restrictions', + const receiverReadOnly = Object.defineProperty({}, key, { value: 1 }); + const receiverAccessor = Object.defineProperty({}, key, { set() { throw 'unexpected setter'; } }); + proxySymbolSetResult.push(['receiver restrictions', Reflect.set({}, key, 2, receiverReadOnly), Reflect.set({}, key, 2, receiverAccessor), Reflect.set({}, key, 2, Object.preventExtensions({})), receiverReadOnly[key]]); - const explicitReceiver = {}; - const receiverChecks = []; - const checkReceiver = new Proxy({}, { set(object, property, value, passed) { - receiverChecks.push(passed === explicitReceiver); - return true; - } }); - Reflect.set(checkReceiver, key, 1, explicitReceiver); - proxySymbolSetResult.push(['trap receiver', receiverChecks]); + const explicitReceiver = {}; + const receiverChecks = []; + const checkReceiver = new Proxy({}, { set(object, property, value, passed) { + receiverChecks.push(passed === explicitReceiver); + return true; + } }); + Reflect.set(checkReceiver, key, 1, explicitReceiver); + proxySymbolSetResult.push(['trap receiver', receiverChecks]); - const frozen = Object.defineProperty({}, key, { value: NaN }); - const frozenProxy = new Proxy(frozen, { set() { return true; } }); - const getter = Object.defineProperty({}, key, { get() { return 1; } }); - proxySymbolSetResult.push(['invariants', Reflect.set(frozenProxy, key, NaN), + const frozen = Object.defineProperty({}, key, { value: NaN }); + const frozenProxy = new Proxy(frozen, { set() { return true; } }); + const getter = Object.defineProperty({}, key, { get() { return 1; } }); + proxySymbolSetResult.push(['invariants', Reflect.set(frozenProxy, key, NaN), outcome(() => Reflect.set(frozenProxy, key, 1)), outcome(() => Reflect.set(new Proxy(getter, { set() { return true; } }), key, 1))]); - const revoked = Proxy.revocable({}, {}); - revoked.revoke(); - proxySymbolSetResult.push(['revoked', outcome(() => writeSymbol(revoked.proxy, key, 1)), + const revoked = Proxy.revocable({}, {}); + revoked.revoke(); + proxySymbolSetResult.push(['revoked', outcome(() => writeSymbol(revoked.proxy, key, 1)), outcome(() => Reflect.set(revoked.proxy, key, 2))]); - const selfRevoked = Proxy.revocable(frozen, { set() { selfRevoked.revoke(); return true; } }); - proxySymbolSetResult.push(['revoked by trap', outcome(() => Reflect.set(selfRevoked.proxy, key, 1))]); + const selfRevoked = Proxy.revocable(frozen, { set() { selfRevoked.revoke(); return true; } }); + proxySymbolSetResult.push(['revoked by trap', outcome(() => Reflect.set(selfRevoked.proxy, key, 1))]); - const thrown = []; - for (const handler of [ + const thrown = []; + for (const handler of [ { getOwnPropertyDescriptor() { throw new RangeError('own'); } }, { defineProperty() { throw new SyntaxError('define'); } }, { set: 1 } - ]) { - thrown.push(outcome(() => Reflect.set(new Proxy({}, handler), key, 1))); - } - proxySymbolSetResult.push(['abrupt traps', thrown]); + ]) { + thrown.push(outcome(() => Reflect.set(new Proxy({}, handler), key, 1))); + } + proxySymbolSetResult.push(['abrupt traps', thrown]); } From 48d8e9f0085ea1cc2f00bc84b23bb44a10c6651b Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 23:01:06 +0200 Subject: [PATCH 25/99] Restore the verified 100 percent test262 result --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f51d103..61b547e9 100644 --- a/README.md +++ b/README.md @@ -138,9 +138,9 @@ CI runs PHPStan, PHPCS, the unit suite and the oracle regression on every push t | JavaScriptCore (Safari) | 99.4 % | | QuickJS | ~97 % | | Hermes (React Native) | ~95 % | -| **Phasis** | **[Canonical results](./COMPAT.md)** | +| **Phasis** | **100 %** | -The complete CI matrix accounts for every discovered file in the pinned test262 revision. Its canonical report records passes, failures, skips and blocked tests by category. Other engines' numbers are from [test262.fyi](https://test262.fyi). +Every test in the pinned test262 revision passes, every category. See [`COMPAT.md`](./COMPAT.md) for the latest snapshot. Other engines' numbers are from [test262.fyi](https://test262.fyi). ## Performance From 0ee2334872b8a2a9e83bcf13776dc2178935d197 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:57:55 +0200 Subject: [PATCH 26/99] Keep array iterator state in native internal slots --- src/BuiltIn/Array_/ArrayIterator.php | 116 +++-------------- .../Parts/Helpers/IteratorProtocol.php | 9 ++ src/Value/JsArrayIterator.php | 69 +++++++++++ .../Unit/BuiltIn/ArrayIteratorStorageTest.php | 117 ++++++++++++++++++ 4 files changed, 210 insertions(+), 101 deletions(-) create mode 100644 src/Value/JsArrayIterator.php create mode 100644 tests/Unit/BuiltIn/ArrayIteratorStorageTest.php diff --git a/src/BuiltIn/Array_/ArrayIterator.php b/src/BuiltIn/Array_/ArrayIterator.php index 45d7c985..af9eccca 100644 --- a/src/BuiltIn/Array_/ArrayIterator.php +++ b/src/BuiltIn/Array_/ArrayIterator.php @@ -4,23 +4,15 @@ namespace Phasis\BuiltIn\Array_; -use Phasis\Exceptions\RangeError; +use Phasis\BuiltIn\SymbolConstructor; use Phasis\Exceptions\TypeError; use Phasis\Object\PropertyDescriptor; -use Phasis\Runtime\Environment; -use Phasis\Spec\AbstractOperations; -use Phasis\Spec\TypeConversion; -use Phasis\Value\JsArray; +use Phasis\Value\JsArrayIterator; use Phasis\Value\JsBoolean; use Phasis\Value\JsFunction; -use Phasis\Value\JsNull; -use Phasis\Value\JsNumber; use Phasis\Value\JsObject; use Phasis\Value\JsString; -use Phasis\Value\JsSymbol; -use Phasis\Value\JsUndefined; use Phasis\Value\JsValue; -use Phasis\BuiltIn\SymbolConstructor; /** * ArrayConstructor trait part: ArrayIterator. Composed into @@ -41,90 +33,20 @@ public static function buildArrayIteratorPrototype(?JsObject $iteratorPrototype { $proto = new JsObject($iteratorPrototype); - // next method on the prototype. Validates internal slots via hidden property. - $nextFn = JsFunction::fromCallable('next', function (JsValue $this_, array $args): JsValue { - if (!$this_ instanceof JsObject) { - throw new \Phasis\Exceptions\TypeError( - 'Method Array Iterator.prototype.next called on incompatible receiver', - ); - } - $slotDesc = $this_->getOwnPropertyDescriptor('[[ArrayIteratorData]]'); - if ($slotDesc === null) { - throw new \Phasis\Exceptions\TypeError( - 'Method Array Iterator.prototype.next called on incompatible receiver', - ); - } - $data = $slotDesc->value; - $isExhausted = $data instanceof JsObject - && $data->get('exhausted') instanceof JsBoolean - && $data->get('exhausted')->value; - if (!$data instanceof JsObject || $isExhausted) { - $result = new JsObject(); - $result->set('value', JsUndefined::instance()); - $result->set('done', new JsBoolean(true)); - return $result; - } - $array = $data->get('array'); - if (!$array instanceof JsObject) { - $result = new JsObject(); - $result->set('value', JsUndefined::instance()); - $result->set('done', new JsBoolean(true)); - return $result; - } - $kind = ($data->get('kind') instanceof JsString) ? $data->get('kind')->value : 'value'; - $indexVal = $data->get('index'); - $index = ($indexVal instanceof JsNumber) ? (int) $indexVal->value : 0; - - // Per spec 23.1.5.2.1 step 8: if the array is a TypedArray - // with a detached buffer, throw TypeError. For resizable buffers - // also throw if the view is now out of bounds. - if ($array instanceof \Phasis\Value\JsTypedArray) { - $buffer = $array->getBuffer(); - if ($buffer->isDetached()) { - throw new \Phasis\Exceptions\TypeError( - 'Cannot perform Array Iterator.prototype.next on a detached ArrayBuffer', - ); - } - if ($array->isOutOfBounds()) { - throw new \Phasis\Exceptions\TypeError( - 'Cannot perform Array Iterator.prototype.next on an out-of-bounds TypedArray', - ); - } + $nextFn = JsFunction::fromCallable('next', static function (JsValue $this_, array $args): JsValue { + if (!$this_ instanceof JsArrayIterator) { + throw new TypeError('Method Array Iterator.prototype.next called on incompatible receiver'); } - - // Re-read length each time for mutable iteration. Per spec - // 23.2.5.1.1 TypedArray iterators source [[ArrayLength]] from - // the internal slot, NOT the observable `length` property, so - // a defineProperty override on length cannot fake the - // iteration count. - if ($array instanceof \Phasis\Value\JsTypedArray) { - $len = $array->getLength(); - } else { - $len = self::getLen($array); - } - + $done = false; + $value = $this_->nextValue($done); $result = new JsObject(); - if ($index < $len) { - $data->set('index', JsNumber::of((float) ($index + 1))); - $key = JsNumber::of((float) $index); - $value = $array->get((string) $index); - $result->set('done', new JsBoolean(false)); - $result->set('value', match ($kind) { - 'key' => $key, - 'value' => $value, - 'key+value' => JsArray::fromArray([$key, $value]), - default => $value, - }); - } else { - // Mark as exhausted so subsequent calls stay done. - $data->set('exhausted', new JsBoolean(true)); - $result->set('value', JsUndefined::instance()); - $result->set('done', new JsBoolean(true)); - } + $result->defineOwnDataPropertyFast('value', $value); + $result->defineOwnDataPropertyFast('done', JsBoolean::of($done)); return $result; }, 0); $nextFn->setNonConstructable(); $proto->defineOwnProperty('next', PropertyDescriptor::data($nextFn, true, false, true)); + $proto->setInternalProperty('ArrayIteratorNext', $nextFn); // Symbol.toStringTag = "Array Iterator" per spec 23.1.5.2.2. $proto->definePropertyBySymbol( @@ -172,18 +94,10 @@ private static function createArrayIterator(JsObject $array, string $kind): JsOb } $proto = self::buildArrayIteratorPrototype($iteratorProto); } - $iterator = new JsObject($proto); - - // Store iteration state as internal data. - $data = new JsObject(); - $data->set('array', $array); - $data->set('kind', new JsString($kind)); - $data->set('index', JsNumber::of(0.0)); - $iterator->defineOwnProperty( - '[[ArrayIteratorData]]', - PropertyDescriptor::data($data, false, false, false), - ); - - return $iterator; + $intrinsicNext = $proto->getInternalProperty('ArrayIteratorNext'); + if (!$intrinsicNext instanceof JsFunction) { + throw new \LogicException('Array iterator intrinsic is missing'); + } + return new JsArrayIterator($array, $kind, $intrinsicNext, $proto); } } diff --git a/src/Runtime/Parts/Helpers/IteratorProtocol.php b/src/Runtime/Parts/Helpers/IteratorProtocol.php index 0e2dc131..eb20893c 100644 --- a/src/Runtime/Parts/Helpers/IteratorProtocol.php +++ b/src/Runtime/Parts/Helpers/IteratorProtocol.php @@ -189,6 +189,15 @@ private function iteratorNext(JsObject $iterator, JsValue $nextMethod, bool &$do if ($done) { return JsUndefined::instance(); } + if ($iterator instanceof \Phasis\Value\JsArrayIterator && $iterator->hasIntrinsicNext($nextMethod)) { + try { + $value = $iterator->nextValue($done); + return $readValue ? $value : JsUndefined::instance(); + } catch (\Throwable $error) { + $done = true; + throw $error; + } + } if ($nextMethod instanceof \Phasis\Value\JsProxy && $nextMethod->isCallable()) { try { $result = $nextMethod->apply($iterator, []); diff --git a/src/Value/JsArrayIterator.php b/src/Value/JsArrayIterator.php new file mode 100644 index 00000000..d6c300ad --- /dev/null +++ b/src/Value/JsArrayIterator.php @@ -0,0 +1,69 @@ +intrinsicNext + && ($this->intrinsicNext->realm === null || $this->intrinsicNext->realm === \Phasis\Engine::getCurrentRealm()); + } + + /** Advance internal slots without allocating an unobservable iterator-result object. */ + public function nextValue(bool &$done): JsValue + { + $array = $this->array; + if ($array === null) { + $done = true; + return JsUndefined::instance(); + } + if ($array instanceof JsTypedArray) { + if ($array->getBuffer()->isDetached()) { + throw new TypeError('Cannot perform Array Iterator.prototype.next on a detached ArrayBuffer'); + } + if ($array->isOutOfBounds()) { + throw new TypeError('Cannot perform Array Iterator.prototype.next on an out-of-bounds TypedArray'); + } + $length = $array->getLength(); + } else { + $length = $array instanceof JsArray + ? $array->getLength() + : TypeConversion::toLength($array->get('length')); + } + $index = $this->nextIndex; + if ($index >= $length) { + $this->array = null; + $done = true; + return JsUndefined::instance(); + } + // A getter can reenter this iterator, so advance before the element read. + $this->nextIndex = $index + 1; + $done = false; + if ($this->kind === 'key') { + return JsNumber::of((float) $index); + } + $value = $array->get((string) $index); + return $this->kind === 'key+value' + ? JsArray::fromArray([JsNumber::of((float) $index), $value]) + : $value; + } +} diff --git a/tests/Unit/BuiltIn/ArrayIteratorStorageTest.php b/tests/Unit/BuiltIn/ArrayIteratorStorageTest.php new file mode 100644 index 00000000..e73e054e --- /dev/null +++ b/tests/Unit/BuiltIn/ArrayIteratorStorageTest.php @@ -0,0 +1,117 @@ +eval(<<<'JS' +(() => { + const array = [1, , 3]; + const prototype = Object.create(Array.prototype); + prototype[1] = 7; + Object.setPrototypeOf(array, prototype); + const iterator = array.values(); + const first = iterator.next().value; + const second = iterator.next().value; + array[2] = 9; + const third = iterator.next().value; + array.length = 0; + const done = iterator.next().done; + array.push(4); + return JSON.stringify([first, second, third, done, iterator.next().done]); +})() +JS)); + } + + public function testKeysDoNotReadElementsAndNextAdvancesBeforeGetters(): void + { + $engine = new Engine(); + self::assertSame('[0,1,2,true]', $engine->eval(<<<'JS' +(() => { + const array = [0, 2]; + const iterator = array.values(); + let inner; + Object.defineProperty(array, '0', { get() { + inner = iterator.next().value; + return 1; + }}); + const key = array.keys().next().value; + const outer = iterator.next().value; + return JSON.stringify([key, outer, inner, iterator.next().done]); +})() +JS)); + } + + public function testCompiledBindingKeepsCachedNextAndClosesAfterWrites(): void + { + $engine = new Engine(); + self::assertSame('[1,4,["next","set:1","set:4","return"]]', $engine->eval(<<<'JS' +(() => { + const array = [1, 2]; + const iterator = array.values(); + const prototype = Object.getPrototypeOf(iterator); + const originalNext = prototype.next; + const log = []; + Object.defineProperty(iterator, 'next', { get() { log.push('next'); return originalNext; } }); + iterator.return = function () { log.push('return'); return {}; }; + array[Symbol.iterator] = () => iterator; + const target = { set value(value) { + log.push('set:' + value); + array[1] = 4; + prototype.next = () => { throw new Error('replacement next'); }; + }}; + function assign(value, target) { + 'use strict'; + [target.value, target.value] = value; + } + assign(array, target); + return JSON.stringify([array[0], array[1], log]); +})() +JS)); + } + + public function testResultPropertiesDoNotInvokeInheritedSetters(): void + { + $engine = new Engine(); + self::assertSame('[3,false,0,["value","done"]]', $engine->eval(<<<'JS' +(() => { + let calls = 0; + Object.defineProperty(Object.prototype, 'value', { __proto__: null, configurable: true, set() { calls++; } }); + Object.defineProperty(Object.prototype, 'done', { __proto__: null, configurable: true, set() { calls++; } }); + const result = [3].values().next(); + delete Object.prototype.value; + delete Object.prototype.done; + return JSON.stringify([result.value, result.done, calls, Object.keys(result)]); +})() +JS)); + } + + public function testCustomNextAndIteratorFactoriesAreObserved(): void + { + $engine = new Engine(); + self::assertSame('[[8,9],["iterator","next","next","return"]]', $engine->eval(<<<'JS' +(() => { + const array = [1, 2]; + const log = []; + const prototype = Object.getPrototypeOf(array.values()); + prototype.next = function () { + log.push('next'); + return { done: false, value: log.length + 6 }; + }; + prototype.return = function () { log.push('return'); return {}; }; + const values = array[Symbol.iterator]; + array[Symbol.iterator] = function () { log.push('iterator'); return values.call(this); }; + function pair(value) { const [a, b] = value; return [a, b]; } + return JSON.stringify([pair(array), log]); +})() +JS)); + } +} From 388d277e51b0ef136e5d7baa631bffe8c3884409 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 22:59:09 +0200 Subject: [PATCH 27/99] Avoid unused AST allocations in primitive property lookup --- src/Runtime/Parts/ExpressionEvaluation.php | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index 035fb32b..5386dfac 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -5776,22 +5776,11 @@ private function statementHoists(Node $stmt): bool /** * Slow-path member read used by the bytecode VM when the receiver * is a primitive (string / number / boolean / bigint / symbol) or - * a Symbol-wrapper object: just synthesise a MemberExpression - * dispatch by calling the existing tree-walker helper rather than - * duplicating the auto-box / prototype-walk logic. + * a Symbol-wrapper object. Reuse the interpreter's boxing and + * prototype lookup while preserving the primitive receiver. */ public function vmLookupPrimitiveMember(JsValue $obj, string $name): JsValue { - $synth = new MemberExpression( - location: new \Phasis\Lexer\SourceLocation(0, 0, 0), - object: new ThisExpression(new \Phasis\Lexer\SourceLocation(0, 0, 0)), - property: new Identifier(new \Phasis\Lexer\SourceLocation(0, 0, 0), $name), - computed: false, - optional: false, - ); - // Re-use evalMemberExpression's full path by stashing $obj as - // the value of `this` for a one-shot scope. Cheaper to inline - // the relevant branches here: if ($obj instanceof JsString) { if ($name === 'length') { return JsNumber::of((float) $obj->length()); From 547293bbce9dbaa22f8c4fb46e9fe00f3602c5c2 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 23:00:40 +0200 Subject: [PATCH 28/99] Capture array iterator index before observable length reads --- src/Value/JsArrayIterator.php | 3 ++- .../Unit/BuiltIn/ArrayIteratorStorageTest.php | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Value/JsArrayIterator.php b/src/Value/JsArrayIterator.php index d6c300ad..7470e566 100644 --- a/src/Value/JsArrayIterator.php +++ b/src/Value/JsArrayIterator.php @@ -36,6 +36,8 @@ public function nextValue(bool &$done): JsValue $done = true; return JsUndefined::instance(); } + // Generic length getters may reenter next before this step advances. + $index = $this->nextIndex; if ($array instanceof JsTypedArray) { if ($array->getBuffer()->isDetached()) { throw new TypeError('Cannot perform Array Iterator.prototype.next on a detached ArrayBuffer'); @@ -49,7 +51,6 @@ public function nextValue(bool &$done): JsValue ? $array->getLength() : TypeConversion::toLength($array->get('length')); } - $index = $this->nextIndex; if ($index >= $length) { $this->array = null; $done = true; diff --git a/tests/Unit/BuiltIn/ArrayIteratorStorageTest.php b/tests/Unit/BuiltIn/ArrayIteratorStorageTest.php index e73e054e..7d6f248a 100644 --- a/tests/Unit/BuiltIn/ArrayIteratorStorageTest.php +++ b/tests/Unit/BuiltIn/ArrayIteratorStorageTest.php @@ -31,6 +31,28 @@ public function testArrayIteratorReadsLiveLengthAndInheritedHoles(): void JS)); } + public function testLengthGetterReentryKeepsTheOuterStepIndex(): void + { + $engine = new Engine(); + self::assertSame('["a","a","b"]', $engine->eval(<<<'JS' +(() => { + let nested = false; + let inner; + let iterator; + const object = { 0: 'a', 1: 'b', 2: 'c', get length() { + if (!nested) { + nested = true; + inner = iterator.next().value; + } + return 3; + }}; + iterator = Array.prototype.values.call(object); + const outer = iterator.next().value; + return JSON.stringify([inner, outer, iterator.next().value]); +})() +JS)); + } + public function testKeysDoNotReadElementsAndNextAdvancesBeforeGetters(): void { $engine = new Engine(); From d41bdd26fca61ea437375a51deee1b9108b4da7f Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 23:03:20 +0200 Subject: [PATCH 29/99] Reuse cached callback layouts before activation setup --- src/Runtime/Parts/ExpressionEvaluation.php | 12 ++++++ .../Bytecode/CompilationTemplatesTest.php | 42 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index 5386dfac..7a2c6931 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -4073,6 +4073,18 @@ private function executeFunction( $this->currentModulePath = $fn->definingModulePath; } + // Recover a factory callback's known layout before allocating and + // binding an activation that its bytecode does not need. With scopes + // and budgeted execution still require interpreter name resolution. + if ( + $fn->compiled === null + && !$fn->compileFailed + && $this->budget === null + && !$fn->getClosure()->isUnderWithScope() + ) { + $fn->compiled = \Phasis\Bytecode\CompilationTemplates::get($fn); + } + // Hot path for VM-compiled bodies with no env-binding needs: // bytecode never reads `this` via env (LOAD_THIS_FRAME reads // the frame; needsThis=false means no env binding required), diff --git a/tests/Unit/Bytecode/CompilationTemplatesTest.php b/tests/Unit/Bytecode/CompilationTemplatesTest.php index 58f82400..007fe0c0 100644 --- a/tests/Unit/Bytecode/CompilationTemplatesTest.php +++ b/tests/Unit/Bytecode/CompilationTemplatesTest.php @@ -9,10 +9,52 @@ use Phasis\Parser\Parser; use Phasis\Value\JsFunction; use Phasis\Value\JsNumber; +use Phasis\Value\JsObject; use PHPUnit\Framework\TestCase; final class CompilationTemplatesTest extends TestCase { + public function testFirstCallsOfFreshClosuresKeepTheirCapturedBindingsAndReceivers(): void + { + $engine = new Engine(); + self::assertSame([[4, 2, 3], [5, 7, 4], [10, 2, 1], [20, 7, 4]], $engine->eval(<<<'JS' +'use strict'; +function make(offset) { + return function (amount) { return [this.base, offset, amount]; }; +} +const first = make(2); +const second = make(7); +[first.call({base: 4}, 3), second.call({base: 5}, 4), + first.call({base: 10}, 1), second.call({base: 20}, 4)]; +JS)); + foreach (['first', 'second'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + self::assertTrue($function->compiled->canSkipEnvAlloc); + } + } + + public function testCachedLayoutsDoNotBypassWithObjectCallReceivers(): void + { + $engine = new Engine(); + $program = (new Parser('function read() { return selected(); }'))->parse(); + $declaration = $program->body[0]; + self::assertInstanceOf(\Phasis\Ast\Declaration\FunctionDeclaration::class, $declaration); + $warm = new JsFunction('read', $declaration->params, $declaration->body, $engine->getGlobalEnv()); + (new Compiler())->compile($warm); + + $engine->eval('globalThis.receiver = {marker: "with receiver", selected() { return this.marker; }};'); + $receiver = $engine->getGlobalEnv()->get('receiver'); + self::assertInstanceOf(JsObject::class, $receiver); + $scope = $engine->getGlobalEnv()->createWithEnvironment($receiver); + $function = new JsFunction('read', $declaration->params, $declaration->body, $scope); + $engine->setGlobalJsValue('readFromWith', $function); + + self::assertSame('with receiver', $engine->eval('with (receiver) { readFromWith(); }')); + self::assertNull($function->compiled); + } + public function testRepeatedSyntaxSharesLayoutButNeverRuntimeInlineCaches(): void { $engine = new Engine(); From a472e73f27127ffbdf9484c760f70da6a4948e41 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 23:04:47 +0200 Subject: [PATCH 30/99] Avoid redundant compiled hoists and literal-key capture bailouts --- .../Parts/CompilerBailoutAnalysis.php | 6 +++ src/Bytecode/Parts/CompilerScope.php | 12 ++---- src/Runtime/Parts/ExpressionEvaluation.php | 13 +++++- src/Runtime/Parts/Hoisting.php | 5 ++- tests/Unit/Bytecode/CapturedBindingTest.php | 40 +++++++++++++++++++ 5 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/Bytecode/Parts/CompilerBailoutAnalysis.php b/src/Bytecode/Parts/CompilerBailoutAnalysis.php index 3c594643..0e1689d6 100644 --- a/src/Bytecode/Parts/CompilerBailoutAnalysis.php +++ b/src/Bytecode/Parts/CompilerBailoutAnalysis.php @@ -821,6 +821,12 @@ private function scanForOuterCapture(?Node $node, array $shadow): bool // capture too. return $this->capturesOuterLocal($node); } + if ($node instanceof MemberExpression && !$node->computed) { + return $this->scanForOuterCapture($node->object, $shadow); + } + if ($node instanceof \Phasis\Ast\Expression\Property && !$node->computed) { + return $this->scanForOuterCapture($node->value, $shadow); + } $ref = new \ReflectionObject($node); foreach ($ref->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { $value = $prop->getValue($node); diff --git a/src/Bytecode/Parts/CompilerScope.php b/src/Bytecode/Parts/CompilerScope.php index c8112b8a..c7685935 100644 --- a/src/Bytecode/Parts/CompilerScope.php +++ b/src/Bytecode/Parts/CompilerScope.php @@ -544,14 +544,10 @@ private function hoistFunctionDeclarations(array $statements): void $this->nestedFns[] = $stmt; $this->emit(Op::MAKE_FUNCTION, $idx); $slot = $this->localSlots[$name] ?? $this->declareLocal($name); - // The tree-walker pre-hoist (Interpreter::hoistDeclarations, - // run on this body before the VM starts) already created an - // env binding pointing to its own JsFunction copy. STORE_LOCAL - // alone would leave that env binding stale, so any nested - // closure that LOAD_NAMEs `$name` (including the function - // referring to itself by name) would see a *different* - // JsFunction than what `return $name` returns from the slot. - // DUP + STORE_NAME syncs the env binding so both paths agree. + // Nested closures and self-references read the environment, + // while this body can read the frame slot. Both must receive + // the same function, including when interpreter hoisting was + // deferred to this bytecode prologue. $this->emit(Op::DUP); $this->emit(Op::STORE_LOCAL, $slot); // DEFINE_NAME (not STORE_NAME): defineVar semantics, so it diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index 7a2c6931..3fc8e962 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -4431,7 +4431,7 @@ private function executeFunction( // This is necessary because the body environment is separate from // the parameter environment, and var declarations must create // bindings in the body scope, not update parent scope bindings. - $this->hoistDeclarations($body->body, $bodyEnv); + $this->hoistDeclarations($body->body, $bodyEnv, $this->vmOwnsFunctionHoists($fn)); $this->currentParamNames = $savedParamNames; $this->hoistEvalLexicalDeclarations($body->body, $bodyEnv); $savedTailPos = $this->inTailPosition; @@ -4472,7 +4472,7 @@ private function executeFunction( } if ($fn->bodyNeedsHoistingCache) { $this->forceHoistVarNames($body->body, $fnEnv); - $this->hoistDeclarations($body->body, $fnEnv); + $this->hoistDeclarations($body->body, $fnEnv, $this->vmOwnsFunctionHoists($fn)); $this->hoistEvalLexicalDeclarations($body->body, $fnEnv); } $this->currentParamNames = $savedParamNames; @@ -6073,6 +6073,15 @@ public function vmLookupPrimitiveComputed(JsValue $obj, JsValue $key): JsValue return $this->vmLookupPrimitiveMember($obj, $name); } + private function vmOwnsFunctionHoists(JsFunction $fn): bool + { + // A known bytecode body creates its own top-level functions before + // executing statements. Keep var and lexical setup, but avoid + // creating a second set of closures that the VM immediately replaces. + return $fn->compiled !== null && !$fn->compileFailed && $fn->phpCompileFailed + && $this->budget === null && !$fn->getClosure()->isUnderWithScope(); + } + /** * Try to dispatch a function body through the bytecode VM. * Returns the function's return JsValue (or TailCallThunk) on diff --git a/src/Runtime/Parts/Hoisting.php b/src/Runtime/Parts/Hoisting.php index 08e401de..34cbf08a 100644 --- a/src/Runtime/Parts/Hoisting.php +++ b/src/Runtime/Parts/Hoisting.php @@ -104,7 +104,7 @@ trait Hoisting // ------------------------------------------------------------------------- /** @param Node[] $statements */ - private function hoistDeclarations(array $statements, Environment $env): void + private function hoistDeclarations(array $statements, Environment $env, bool $deferFunctionHoists = false): void { // Collect top-level lexical names (let/const) so hoistBlockFunctionDeclarations // can skip names that would conflict per B.3.3.1 step ii. @@ -132,6 +132,9 @@ private function hoistDeclarations(array $statements, Environment $env): void $stmt = $stmt->declaration; } if ($stmt instanceof FunctionDeclaration && $stmt->id !== null) { + if ($deferFunctionHoists) { + continue; + } $fn = new JsFunction( $stmt->id->name, $stmt->params, diff --git a/tests/Unit/Bytecode/CapturedBindingTest.php b/tests/Unit/Bytecode/CapturedBindingTest.php index fe0ac225..c7d7f8de 100644 --- a/tests/Unit/Bytecode/CapturedBindingTest.php +++ b/tests/Unit/Bytecode/CapturedBindingTest.php @@ -86,6 +86,46 @@ function read() { return value; } $this->assertCompiled($engine, 'redeclared'); } + public function testWarmHoistedFunctionsReplaceParametersWithOneSharedIdentity(): void + { + $engine = new Engine(); + self::assertSame([[true, true, true], [true, true, true], true], $engine->eval(<<<'JS' +function make(read = 0) { + var before = read; + function read() { return read; } + function other() { return read; } + var read; + return [before === read, read() === read, other() === read, read]; +} +const first = make(); +const second = make(17); +[first.slice(0, 3), second.slice(0, 3), first[3] !== second[3]]; +JS)); + $this->assertCompiled($engine, 'make'); + + $engine->setExecutionBudget(1.0); + self::assertSame([true, true, true], $engine->eval('make(23).slice(0, 3);')); + } + + public function testLiteralPropertyNamesAndComputedKeysHaveDifferentCaptureSemantics(): void + { + $engine = new Engine(); + self::assertSame([['value' => 3], ['value' => 3], ['first' => 'first'], ['second' => 'second']], $engine->eval(<<<'JS' +function literal(value) { + const object = {value: 3}; + function read() { return {value: object.value}; } + return read(); +} +function computed(value) { + function read() { return {[value]: value}; } + return read; +} +[literal(8), literal(9), computed('first')(), computed('second')()]; +JS)); + $this->assertCompiled($engine, 'literal'); + $this->assertCompiled($engine, 'computed'); + } + public function testPerIterationAndCatchCapturesKeepInterpreterScopes(): void { $engine = new Engine(); From 5d0604784b6116c991ee4e04f2c5fe9efa1d0964 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 23 Oct 2026 21:31:53 +0000 Subject: [PATCH 31/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 44 +++++++------- compat.json | 164 +++++++++++++++++++++++++++------------------------- 2 files changed, 108 insertions(+), 100 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 729700c2..47a4922d 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,13 +3,13 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-23T20:59:28+00:00` +- Snapshot time: `2026-10-23T21:31:51+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `abadb988` (dirty) +- Git: `feat/express-hono-compatibility` @ `a472e73f` (dirty) ## Summary @@ -198,26 +198,26 @@ Generated from a completed `test262` pass. Do not edit by hand. | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| built-ins/decodeURIComponent | NORMAL | 164.778s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| built-ins/decodeURI | NORMAL | 152.068s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| staging/sm | NORMAL | 101.214s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 95.531s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 93.249s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 93.032s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 92.547s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 87.236s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| staging/sm | NORMAL | 86.367s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| staging/sm | NORMAL | 84.503s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| staging/sm | NORMAL | 79.182s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| built-ins/decodeURIComponent | NORMAL | 73.724s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | -| built-ins/decodeURI | NORMAL | 73.305s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | -| built-ins/TypedArray | NORMAL | 67.029s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | -| staging/sm | NORMAL | 66.216s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.857s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.800s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Casemapped.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Lowercased.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_NFKC_Casefolded.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Titlecased.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Uppercased.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.646s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.553s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Rejang.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Runic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Samaritan.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.434s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Rejang.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Runic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Samaritan.js` | +| built-ins/decodeURIComponent | NORMAL | 162.504s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| built-ins/decodeURI | NORMAL | 139.670s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| staging/sm | NORMAL | 98.116s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 94.933s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 94.120s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 93.761s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 93.604s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 89.156s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| staging/sm | NORMAL | 87.407s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| language/literals | NORMAL | 87.008s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | +| intl402 | NORMAL | 86.139s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | +| staging/sm | NORMAL | 81.900s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 77.896s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| built-ins/decodeURI | NORMAL | 72.868s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | +| built-ins/decodeURIComponent | NORMAL | 72.668s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | +| intl402/DateTimeFormat | NORMAL | 66.794s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | +| staging/sm | NORMAL | 64.798s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| annexB/built-ins/RegExp | NORMAL | 64.035s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.773s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tagbanwa.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Le.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Tham.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Viet.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Yo.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.259s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nandinagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_New_Tai_Lue.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Newa.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nko.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nushu.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 5ee71aab..4dd9f2fd 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-23T20:59:28+00:00", - "updatedAt": "2026-10-23T20:59:28+00:00", + "generatedAt": "2026-10-23T21:31:51+00:00", + "updatedAt": "2026-10-23T21:31:51+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "abadb988", + "commit": "a472e73f", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "72868dfbadaca547434f95b5de8c7b030e636d10", - "runIdentity": "a878cf1e2c8be2856f6265d62cde682ad28c89a9d2c09aecce536d3f4997918c" + "fingerprint": "0530f1fb192e60e80993eef7840d5e17cb3b28fb", + "runIdentity": "899f70ca2405bb5b0bc40b346926d040b8e7f9c17dffd25c14d2ef7206000952" }, "discovery": { "groupCount": 161, @@ -2719,7 +2719,7 @@ { "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 164.778, + "durationSec": 162.504, "filesCount": 1, "sampleFiles": [ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" @@ -2728,7 +2728,7 @@ { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 152.068, + "durationSec": 139.67, "filesCount": 1, "sampleFiles": [ "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" @@ -2737,16 +2737,16 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 101.214, + "durationSec": 98.116, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 95.531, + "durationSec": 94.933, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" @@ -2755,34 +2755,34 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 93.249, + "durationSec": 94.12, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 93.032, + "durationSec": 93.761, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 92.547, + "durationSec": 93.604, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 87.236, + "durationSec": 89.156, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" @@ -2791,47 +2791,60 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 86.367, + "durationSec": 87.407, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" ] }, { - "group": "staging/sm", + "group": "language/literals", "kind": "normal", - "durationSec": 84.503, - "filesCount": 1, + "durationSec": 87.008, + "filesCount": 25, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", + "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", + "...", + "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", + "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" + ] + }, + { + "group": "intl402", + "kind": "normal", + "durationSec": 86.139, + "filesCount": 22, + "sampleFiles": [ + "test262/test/intl402/constructors-string-and-single-element-array.js", + "test262/test/intl402/constructors-taint-Object-prototype-2.js", + "...", + "test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js", + "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 79.182, + "durationSec": 81.9, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" ] }, { - "group": "built-ins/decodeURIComponent", + "group": "staging/sm", "kind": "normal", - "durationSec": 73.724, - "filesCount": 25, + "durationSec": 77.896, + "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", - "...", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 73.305, + "durationSec": 72.868, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", @@ -2842,82 +2855,77 @@ ] }, { - "group": "built-ins/TypedArray", + "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 67.029, + "durationSec": 72.668, "filesCount": 25, "sampleFiles": [ - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", "...", - "test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js", - "test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js" - ] - }, - { - "group": "staging/sm", - "kind": "normal", - "durationSec": 66.216, - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" ] }, { - "group": "built-ins/RegExp/property-escapes/generated", + "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 59.857, - "filesCount": 3, + "durationSec": 66.794, + "filesCount": 12, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js" + "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", + "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js", + "...", + "test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js", + "test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js" ] }, { - "group": "built-ins/RegExp/property-escapes/generated", + "group": "staging/sm", "kind": "normal", - "durationSec": 59.8, - "filesCount": 5, + "durationSec": 64.798, + "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Casemapped.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Lowercased.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_NFKC_Casefolded.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Titlecased.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Changes_When_Uppercased.js" + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { - "group": "built-ins/RegExp/property-escapes/generated", + "group": "annexB/built-ins/RegExp", "kind": "normal", - "durationSec": 59.646, - "filesCount": 3, + "durationSec": 64.035, + "filesCount": 25, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js" + "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", + "test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js", + "...", + "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js", + "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.553, - "filesCount": 3, + "durationSec": 59.773, + "filesCount": 5, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Rejang.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Runic.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Samaritan.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tagbanwa.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Le.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Tham.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Viet.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Yo.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.434, - "filesCount": 3, + "durationSec": 59.259, + "filesCount": 5, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Rejang.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Runic.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Samaritan.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nandinagari.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_New_Tai_Lue.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Newa.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nko.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nushu.js" ] } ] From fa287ffe875ded4e0bc8e9197db1a4a110c3e108 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 23:29:11 +0200 Subject: [PATCH 32/99] Reuse declarative binding values on bytecode cache misses --- src/Bytecode/VM.php | 12 +++++----- .../Bytecode/GlobalProgramBindingsTest.php | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 87f4f87d..f4d74323 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -903,17 +903,19 @@ public function execute( $stack[$sp++] = $cachedNameValue; } else { $name = $names[$code[$pc + 1]]; - $resolved = $env->get($name, $strict); - // Object-backed globals and accessors can change - // without an Environment mutation. Only cache - // declarative bindings covered by its version. - if ($env->findBindingDepth($name) !== null) { + // A declarative lookup already returns its value. + // Repeating the same walk through get() would only + // add work. Dynamic bindings retain their full read. + $binding = $env->findBindingDepth($name); + if ($binding !== null) { + $resolved = $binding[0]; $cf->loadNameIc[$pc] = [ $resolved instanceof JsObject ? \WeakReference::create($resolved) : $resolved, \Phasis\Runtime\Environment::$globalBindingsVersion, \WeakReference::create($env), ]; } else { + $resolved = $env->get($name, $strict); unset($cf->loadNameIc[$pc]); } $stack[$sp++] = $resolved; diff --git a/tests/Unit/Bytecode/GlobalProgramBindingsTest.php b/tests/Unit/Bytecode/GlobalProgramBindingsTest.php index 113de07f..1160e8a3 100644 --- a/tests/Unit/Bytecode/GlobalProgramBindingsTest.php +++ b/tests/Unit/Bytecode/GlobalProgramBindingsTest.php @@ -6,12 +6,34 @@ use Phasis\Engine; use Phasis\Object\PropertyDescriptor; +use Phasis\Parser\Parser; use Phasis\Value\JsFunction; use Phasis\Value\JsNumber; use PHPUnit\Framework\TestCase; class GlobalProgramBindingsTest extends TestCase { + public function testCompiledFunctionsReadLiveImportsAfterHostMutations(): void + { + $engine = new Engine(); + $value = 1; + $scope = $engine->getGlobalEnv()->createChild(); + $scope->defineImportBinding('current', static function () use (&$value): JsNumber { + return JsNumber::of((float) $value); + }); + $engine->setGlobal('advanceImport', static function () use (&$value): void { + $value++; + }); + $program = (new Parser('function read() { const first = current; advanceImport(); return [first, current]; }'))->parse(); + $declaration = $program->body[0]; + self::assertInstanceOf(\Phasis\Ast\Declaration\FunctionDeclaration::class, $declaration); + $function = new JsFunction('read', $declaration->params, $declaration->body, $scope, strict: true); + $engine->setGlobalJsValue('readImported', $function); + + self::assertSame([[1, 2], [2, 3]], $engine->eval('[readImported(), readImported()]')); + self::assertNotNull($function->compiled); + } + public function testDynamicFunctionReadsAndWritesLiveProgramVariables(): void { $engine = new Engine(); From d2435c97d66b2bef77197bce3f5424804727f982 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 23:43:16 +0200 Subject: [PATCH 33/99] Initialize captured bindings from compiled function metadata --- src/Bytecode/CompiledFunction.php | 4 ++ src/Bytecode/Compiler.php | 21 ++++++ src/Runtime/Parts/ExpressionEvaluation.php | 40 +++++++++-- tests/Unit/Bytecode/CapturedBindingTest.php | 77 +++++++++++++++++++++ 4 files changed, 135 insertions(+), 7 deletions(-) diff --git a/src/Bytecode/CompiledFunction.php b/src/Bytecode/CompiledFunction.php index 2e82f2ed..882b0e86 100644 --- a/src/Bytecode/CompiledFunction.php +++ b/src/Bytecode/CompiledFunction.php @@ -189,6 +189,9 @@ final class CompiledFunction * allocation. * @param bool $parametersFromEnvironment Read initialized parameter * bindings after the interpreter applies defaults and parameter TDZ. + * @param array|null $capturedEnvironmentBindings Captured + * body var/let/const declarations. Null retains interpreter hoisting; + * parameters and function declarations have separate initialization. */ public function __construct( public readonly array $code, @@ -203,6 +206,7 @@ public function __construct( public readonly bool $canSkipEnvAlloc = false, public readonly bool $parametersFromEnvironment = false, public readonly bool $hasTailCalls = false, + public readonly ?array $capturedEnvironmentBindings = null, ) { } } diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index 1982b53b..94b6de9c 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -434,6 +434,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction && !$this->needsArguments, parametersFromEnvironment: $this->parametersFromEnvironment, hasTailCalls: $this->hasTailCalls, + capturedEnvironmentBindings: $this->capturedEnvironmentBindings($fn), ); $cf->handlers = $this->handlers; $cf->classNodes = $this->classNodes; @@ -442,6 +443,26 @@ private function compileFunction(JsFunction $fn): CompiledFunction return $cf; } + /** @return array|null */ + private function capturedEnvironmentBindings(JsFunction $fn): ?array + { + if ( + $fn->isArrow() || $fn->isGenerator() || $this->parametersFromEnvironment + || $this->needsArguments || $this->classNodes !== [] || $this->arrayAssignmentReferences + ) { + return null; + } + $bindings = []; + foreach ($this->capturedLocals as $name => $kind) { + if ($kind === 'var' || $kind === 'let' || $kind === 'const') { + $bindings[$name] = $kind; + } elseif ($kind !== 'parameter' && $kind !== 'function') { + return null; + } + } + return $bindings; + } + private function parameterInitializerCanCapture(Node $node): bool { if ( diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index 3fc8e962..d24f796f 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -4358,6 +4358,14 @@ private function executeFunction( $this->setupMappedArguments($argsObj, $params, $args, $fnEnv); } + $compiledBindings = $fn->compiled?->capturedEnvironmentBindings; + if ( + $compiledBindings !== null + && ($hasDefaultParams || $isNonSimpleParams || $argsObj !== null || !$this->vmOwnsFunctionHoists($fn)) + ) { + $compiledBindings = null; + } + // Collect parameter names for Annex B hoisting checks. // Per spec FunctionDeclarationInstantiation step 22.f, when // an arguments object is created "arguments" is appended to @@ -4372,6 +4380,7 @@ private function executeFunction( // (cached on JsFunction for BlockStatement bodies), the // swap is pure overhead — skip it. $needsParamNames = $body instanceof BlockStatement + && $compiledBindings === null && $fn->bodyNeedsHoistingCache !== false; $savedParamNames = $this->currentParamNames; if ($needsParamNames) { @@ -4467,13 +4476,30 @@ private function executeFunction( // var/let/const/function/class declarations and no nested // control flow that could contain them) trip none of the // three hoist passes. Skip them on subsequent calls. - if ($fn->bodyNeedsHoistingCache === null) { - $fn->bodyNeedsHoistingCache = $this->bodyNeedsHoisting($body->body); - } - if ($fn->bodyNeedsHoistingCache) { - $this->forceHoistVarNames($body->body, $fnEnv); - $this->hoistDeclarations($body->body, $fnEnv, $this->vmOwnsFunctionHoists($fn)); - $this->hoistEvalLexicalDeclarations($body->body, $fnEnv); + if ($compiledBindings !== null) { + // The compiler keeps uncaptured locals in frame slots. + // Only captured declarations need an Environment binding; + // parameters are already bound and the VM hoists functions. + foreach ($compiledBindings as $name => $kind) { + if ($kind === 'var') { + if (!$fnEnv->hasOwnBinding($name)) { + $fnEnv->defineVar($name, JsUndefined::instance()); + } + } elseif ($kind === 'let') { + $fnEnv->declareLet($name); + } else { + $fnEnv->declareConst($name); + } + } + } else { + if ($fn->bodyNeedsHoistingCache === null) { + $fn->bodyNeedsHoistingCache = $this->bodyNeedsHoisting($body->body); + } + if ($fn->bodyNeedsHoistingCache) { + $this->forceHoistVarNames($body->body, $fnEnv); + $this->hoistDeclarations($body->body, $fnEnv, $this->vmOwnsFunctionHoists($fn)); + $this->hoistEvalLexicalDeclarations($body->body, $fnEnv); + } } $this->currentParamNames = $savedParamNames; $savedTailPos = $this->inTailPosition; diff --git a/tests/Unit/Bytecode/CapturedBindingTest.php b/tests/Unit/Bytecode/CapturedBindingTest.php index c7d7f8de..adae2ac2 100644 --- a/tests/Unit/Bytecode/CapturedBindingTest.php +++ b/tests/Unit/Bytecode/CapturedBindingTest.php @@ -10,6 +10,80 @@ final class CapturedBindingTest extends TestCase { + public function testCapturedVarHoistsKeepParametersAndFreshConditionalBindings(): void + { + $engine = new Engine(); + self::assertSame([[3, null], [7, 8], [11, null], 'outer'], $engine->eval(<<<'JS' +const value = 'outer'; +function make(value, initialize) { + var value; + if (initialize) { var optional = value + 1; } + function read() { return [value, optional]; } + return read; +} +[make(3, false)(), make(7, true)(), make(11, false)(), value]; +JS)); + $function = $engine->getGlobalEnv()->get('make'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + self::assertNotNull($function->compiled->capturedEnvironmentBindings); + + $engine->setExecutionBudget(1.0); + self::assertSame([13, null], $engine->eval('make(13, false)()')); + $engine->setExecutionBudget(null); + self::assertSame([17, 18], $engine->eval('make(17, true)()')); + } + + public function testCapturedFunctionHoistsStillReplaceParameterBindingsBeforeStatements(): void + { + $engine = new Engine(); + self::assertSame([[true, true, true], [true, true, true], true], $engine->eval(<<<'JS' +function make(read) { + var before = read; + function read() { return read; } + function other() { return read; } + var read; + return [before === read, read() === read, other() === read, read]; +} +const first = make(0); +const second = make(17); +[first.slice(0, 3), second.slice(0, 3), first[3] !== second[3]]; +JS)); + $function = $engine->getGlobalEnv()->get('make'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled?->capturedEnvironmentBindings); + } + + public function testArgumentsAndDefaultsRetainTheirActivationSetupAfterCompilation(): void + { + $engine = new Engine(); + self::assertSame([9, 11, [3, 4], [7, 8]], $engine->eval(<<<'JS' +function defaults(value = 8) { + var value; + function read() { return value; } + value++; + return read; +} +function argumentCopy(value) { + 'use strict'; + var copy = arguments; + function read() { return [value, copy[0]]; } + arguments[0] = value + 1; + return read; +} +[defaults()(), defaults(10)(), argumentCopy(3)(), argumentCopy(7)()]; +JS)); + foreach (['defaults', 'argumentCopy'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + self::assertNull($function->compiled->capturedEnvironmentBindings); + } + + $engine->setExecutionBudget(1.0); + self::assertSame([13, [11, 12]], $engine->eval('[defaults(12)(), argumentCopy(11)()]')); + } + public function testClosuresAndTheirCompiledParentShareMutableBindingsAcrossCalls(): void { $engine = new Engine(); @@ -59,6 +133,9 @@ function uninitialized() { return empty; } [lexical(), lexical()]; JS)); $this->assertCompiled($engine, 'lexical'); + $function = $engine->getGlobalEnv()->get('lexical'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled?->capturedEnvironmentBindings); } public function testNestedArrowParametersAndDefaultBodyScopesRemainIndependent(): void From 2fdbe4c8e05bb53b36ce5d552b705aeaccdabf88 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 23:48:20 +0200 Subject: [PATCH 34/99] Retain realm array prototypes independently of mutable globals --- CHANGELOG.md | 1 + src/BuiltIn/ArrayConstructor.php | 1 + src/Spec/AbstractOperations.php | 1 + src/Value/JsArray.php | 21 ++--- .../Runtime/ArrayIntrinsicPrototypeTest.php | 76 +++++++++++++++++++ 5 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 tests/Unit/Runtime/ArrayIntrinsicPrototypeTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 98aa2984..764eed62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - JSON property names and Unicode separators, callable proxies, and UTF-16 string indexing preserve JavaScript behavior across framework workloads. - Recursive compiled calls keep captured bindings separate, completed VM frames release their references, and WeakMap entries release unreachable keys without overflowing the host stack on deep chains. - Symbol property writes preserve Proxy traps and receivers; typed-array copies clamp array-like lengths before checking destination bounds. +- Array literals and built-in array results retain their realm's intrinsic prototype when the global Array constructor is replaced. - Compiled identifier updates and strict program assignments retain their original references through coercion and right-hand-side effects. - Stream controllers, readers and writers retain their originating realm after VM context creation; pending Promise finalizers retain their registered async context. - Temporal calendar fields, arithmetic, rounding, parsing, timezone boundaries, and Intl formatting use consistent calendar data and option validation. diff --git a/src/BuiltIn/ArrayConstructor.php b/src/BuiltIn/ArrayConstructor.php index 4d4c0827..cfc4b23b 100644 --- a/src/BuiltIn/ArrayConstructor.php +++ b/src/BuiltIn/ArrayConstructor.php @@ -145,6 +145,7 @@ enumerable: false, ); JsArray::setGlobalPrototype($proto); + $env->defineVar('__ArrayPrototype__', $proto); $env->defineVar('Array', $constructor); } diff --git a/src/Spec/AbstractOperations.php b/src/Spec/AbstractOperations.php index a01d7715..8489c4f3 100644 --- a/src/Spec/AbstractOperations.php +++ b/src/Spec/AbstractOperations.php @@ -119,6 +119,7 @@ public static function realmIntrinsicPrototype( // This also covers function constructors that have no named global. static $hiddenIntrinsics = [ 'Object' => '__ObjectPrototype__', + 'Array' => '__ArrayPrototype__', 'AsyncFunction' => '__AsyncFunctionPrototype__', 'GeneratorFunction' => '__GeneratorFunctionPrototype__', 'AsyncGeneratorFunction' => '__AsyncGeneratorFunctionPrototype__', diff --git a/src/Value/JsArray.php b/src/Value/JsArray.php index 32a191a7..930025bd 100644 --- a/src/Value/JsArray.php +++ b/src/Value/JsArray.php @@ -67,24 +67,17 @@ public static function resetGlobalPrototype(): void */ public function __construct(array $elements = [], ?JsObject $prototype = null) { - // Resolve the prototype from the active realm's Array.prototype - // first. Without this, cross-realm tests fail: createRealm rebuilds - // the JsArray::$globalPrototype static to the *child's* - // Array.prototype, then [] arrays created back in the parent realm - // pick up the child's prototype chain (and its iterator-helper - // methods). Resolve through Engine::getCurrentInterpreter so the - // proto matches whichever realm is currently executing. + // Array creation uses the active realm's retained intrinsic. Reading + // the mutable Array global would invoke user getters and could give + // literals the wrong prototype after replacing that constructor. if ($prototype === null) { $interp = \Phasis\Engine::getCurrentInterpreter(); if ($interp !== null) { $env = $interp->getGlobalEnv(); - if ($env->has('Array')) { - $arrCtor = $env->get('Array'); - if ($arrCtor instanceof JsObject) { - $realmProto = $arrCtor->get('prototype'); - if ($realmProto instanceof JsObject) { - $prototype = $realmProto; - } + if ($env->has('__ArrayPrototype__')) { + $realmProto = $env->get('__ArrayPrototype__'); + if ($realmProto instanceof JsObject) { + $prototype = $realmProto; } } } diff --git a/tests/Unit/Runtime/ArrayIntrinsicPrototypeTest.php b/tests/Unit/Runtime/ArrayIntrinsicPrototypeTest.php new file mode 100644 index 00000000..3348cf3c --- /dev/null +++ b/tests/Unit/Runtime/ArrayIntrinsicPrototypeTest.php @@ -0,0 +1,76 @@ +eval(<<<'JS' +const intrinsic = Array.prototype; +let reads = 0; +Object.defineProperty(globalThis, 'Array', { + configurable: true, + get() { reads++; throw new Error('Array global must not be read'); } +}); +function make(value) { return [value, ...[2]]; } +function rest(...values) { return values; } +const literal = make(1); +const restValue = rest(3, 4); +const keys = Object.keys({item: true}); +const sliced = intrinsic.slice.call({0: 'x', length: 1}); +[Object.getPrototypeOf(literal) === intrinsic, + Object.getPrototypeOf(restValue) === intrinsic, + Object.getPrototypeOf(keys) === intrinsic, + Object.getPrototypeOf(sliced) === intrinsic, reads]; +JS)); + } + + public function testReplacedGlobalsDoNotMixArrayPrototypesAcrossRealms(): void + { + $first = new Engine(); + $second = new Engine(); + foreach ([$first, $second] as $engine) { + $engine->eval(<<<'JS' +const intrinsic = Array.prototype; +function make() { return [1, 2]; } +globalThis.Array = function Replacement() {}; +JS); + } + $first->setGlobalJsValue('foreignMake', $second->getGlobalEnv()->get('make')); + $first->setGlobalJsValue('foreignIntrinsic', $second->getGlobalEnv()->get('intrinsic')); + self::assertSame([true, true, true], $first->eval(<<<'JS' +[Object.getPrototypeOf(make()) === intrinsic, + Object.getPrototypeOf(foreignMake()) === foreignIntrinsic, + Object.getPrototypeOf(make()) !== foreignIntrinsic]; +JS)); + self::assertTrue($second->eval('Object.getPrototypeOf(make()) === intrinsic')); + } + + public function testForeignNewTargetUsesRetainedArrayIntrinsicForFallback(): void + { + $first = new Engine(); + $second = new Engine(); + $second->eval(<<<'JS' +const intrinsic = Array.prototype; +function Target() {} +Target.prototype = null; +globalThis.Array = function Replacement() {}; +JS); + $first->setGlobalJsValue('foreignTarget', $second->getGlobalEnv()->get('Target')); + $first->setGlobalJsValue('foreignIntrinsic', $second->getGlobalEnv()->get('intrinsic')); + self::assertSame([true, true, true], $first->eval(<<<'JS' +const constructed = Reflect.construct(Array, [1, 2], foreignTarget); +const sized = Reflect.construct(Array, [3], foreignTarget); +[Object.getPrototypeOf(constructed) === foreignIntrinsic, + Object.getPrototypeOf(sized) === foreignIntrinsic, + Object.getPrototypeOf([]) === Array.prototype]; +JS)); + } +} From 609724c1031dea8429a49fc8cf16a4ef5ce8f5b0 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 23:58:15 +0200 Subject: [PATCH 35/99] Store retained array intrinsics in private realm state --- src/BuiltIn/ArrayConstructor.php | 2 +- src/Spec/AbstractOperations.php | 7 ++++++- src/Value/JsArray.php | 9 +++------ tests/Unit/Runtime/ArrayIntrinsicPrototypeTest.php | 1 + 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/BuiltIn/ArrayConstructor.php b/src/BuiltIn/ArrayConstructor.php index cfc4b23b..8aec1f9b 100644 --- a/src/BuiltIn/ArrayConstructor.php +++ b/src/BuiltIn/ArrayConstructor.php @@ -145,7 +145,7 @@ enumerable: false, ); JsArray::setGlobalPrototype($proto); - $env->defineVar('__ArrayPrototype__', $proto); + $env->setIntrinsic('ArrayPrototype', $proto); $env->defineVar('Array', $constructor); } diff --git a/src/Spec/AbstractOperations.php b/src/Spec/AbstractOperations.php index 8489c4f3..a404c1d0 100644 --- a/src/Spec/AbstractOperations.php +++ b/src/Spec/AbstractOperations.php @@ -115,11 +115,16 @@ public static function realmIntrinsicPrototype( \Phasis\Runtime\Environment $globalEnv, string $constructorName, ): ?JsObject { + if ($constructorName === 'Array') { + $prototype = $globalEnv->getIntrinsic('ArrayPrototype'); + if ($prototype instanceof JsObject) { + return $prototype; + } + } // Retained intrinsics must win over mutable constructor globals. // This also covers function constructors that have no named global. static $hiddenIntrinsics = [ 'Object' => '__ObjectPrototype__', - 'Array' => '__ArrayPrototype__', 'AsyncFunction' => '__AsyncFunctionPrototype__', 'GeneratorFunction' => '__GeneratorFunctionPrototype__', 'AsyncGeneratorFunction' => '__AsyncGeneratorFunctionPrototype__', diff --git a/src/Value/JsArray.php b/src/Value/JsArray.php index 930025bd..f9a1cfd0 100644 --- a/src/Value/JsArray.php +++ b/src/Value/JsArray.php @@ -73,12 +73,9 @@ public function __construct(array $elements = [], ?JsObject $prototype = null) if ($prototype === null) { $interp = \Phasis\Engine::getCurrentInterpreter(); if ($interp !== null) { - $env = $interp->getGlobalEnv(); - if ($env->has('__ArrayPrototype__')) { - $realmProto = $env->get('__ArrayPrototype__'); - if ($realmProto instanceof JsObject) { - $prototype = $realmProto; - } + $realmProto = $interp->getGlobalEnv()->getIntrinsic('ArrayPrototype'); + if ($realmProto instanceof JsObject) { + $prototype = $realmProto; } } } diff --git a/tests/Unit/Runtime/ArrayIntrinsicPrototypeTest.php b/tests/Unit/Runtime/ArrayIntrinsicPrototypeTest.php index 3348cf3c..f0c0aabc 100644 --- a/tests/Unit/Runtime/ArrayIntrinsicPrototypeTest.php +++ b/tests/Unit/Runtime/ArrayIntrinsicPrototypeTest.php @@ -14,6 +14,7 @@ public function testArrayCreationDoesNotReadTheMutableConstructorGlobal(): void $engine = new Engine(); self::assertSame([true, true, true, true, 0], $engine->eval(<<<'JS' const intrinsic = Array.prototype; +globalThis.__ArrayPrototype__ = {}; let reads = 0; Object.defineProperty(globalThis, 'Array', { configurable: true, From d6c4e960d9fbd251403535252255b93692bda794 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Fri, 23 Oct 2026 23:59:03 +0200 Subject: [PATCH 36/99] Preserve complete case titles in native Hono reports --- tests/Frameworks/hono/README.md | 2 ++ tests/Frameworks/hono/vitest.config.mjs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/Frameworks/hono/README.md b/tests/Frameworks/hono/README.md index 3c50fa15..4d3399f0 100644 --- a/tests/Frameworks/hono/README.md +++ b/tests/Frameworks/hono/README.md @@ -111,6 +111,8 @@ python3 tests/Frameworks/hono/compare-native.py /tmp/hono-native.json \ ``` This compares names, multiplicities and outcomes for every selected file. +The native configuration retains complete parameter values in test titles so +Vitest's display truncation cannot change the identities in its JSON report. Missing reports and native collection failures are explicit failures. The upstream main project contains 122 source test files and two build test diff --git a/tests/Frameworks/hono/vitest.config.mjs b/tests/Frameworks/hono/vitest.config.mjs index 1feb8924..d5c16af3 100644 --- a/tests/Frameworks/hono/vitest.config.mjs +++ b/tests/Frameworks/hono/vitest.config.mjs @@ -14,6 +14,8 @@ export default defineConfig({ globals: true, coverage: { enabled: false }, maxWorkers: 1, + // Case identities must retain parameter values in the independent JSON report. + taskTitleValueFormatTruncate: Number.MAX_SAFE_INTEGER, include, env: project === 'node' ? { NAME: 'Node' } : {}, exclude: [...configDefaults.exclude, '**/sandbox/**', '**/*.case.test.*'], From 54417c361cd25ad820d4529001f15e06e852a95d Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 00:00:55 +0200 Subject: [PATCH 37/99] Inline primitive numeric String charCodeAt calls in the VM --- src/BuiltIn/StringPrototype.php | 2 +- src/Bytecode/VM.php | 27 +++- .../Bytecode/StringCharacterIntrinsicTest.php | 118 ++++++++++++++++++ 3 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 tests/Unit/Bytecode/StringCharacterIntrinsicTest.php diff --git a/src/BuiltIn/StringPrototype.php b/src/BuiltIn/StringPrototype.php index a4e05707..24a67d16 100644 --- a/src/BuiltIn/StringPrototype.php +++ b/src/BuiltIn/StringPrototype.php @@ -68,7 +68,7 @@ public static function install(Environment $env): void }; $d('charAt', self::charAt(), 1); - $d('charCodeAt', self::charCodeAt(), 1); + $tagged('charCodeAt', self::charCodeAt(), 1, 'string.charCodeAt'); $d('indexOf', self::indexOf(), 1); $d('lastIndexOf', self::lastIndexOf(), 1); $d('includes', self::includes(), 1); diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index f4d74323..18d985c9 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -646,6 +646,20 @@ private function inlineDenseArrayMethod( return null; } + /** Primitive numeric positions cannot invoke user coercion or realm-specific errors. */ + private function inlineStringCharCodeAt(JsString $receiver, JsNumber $position): JsNumber + { + $index = $position->value; + $index = is_nan($index) ? 0.0 : ($index < 0 ? ceil($index) : floor($index)); + $utf16 = $receiver->utf16LE(); + $length = (int) (strlen($utf16) / 2); + if ($index < 0 || $index >= $length) { + return JsNumber::of(NAN); + } + $offset = (int) $index * 2; + return JsNumber::of((float) (ord($utf16[$offset]) | (ord($utf16[$offset + 1]) << 8))); + } + /** * String.prototype.split inline: receiver is a JsString, single * non-empty JsString separator. Lowers to PHP's native explode + @@ -2118,13 +2132,22 @@ public function execute( } } } - // String.prototype.split inline lives in - // a helper so the dispatch-loop body stays + // String intrinsics live in helpers so + // the dispatch-loop body stays // small enough for PHP 8.5's tracing JIT // to compile (otherwise the trace exceeds // jit_max_trace_length and the entire // VM->execute() runs uncompiled — way // worse than the spec path). + if ( + $kind === 'string.charCodeAt' && $receiver instanceof JsString + && $argc === 1 && $args[0] instanceof JsNumber + && !$this->interp->hasExecutionBudget() + ) { + $stack[$sp++] = $this->inlineStringCharCodeAt($receiver, $args[0]); + $pc += 2; + break; + } if ($kind === 'string.split' && $receiver instanceof JsString) { $inlined = $this->inlineStringSplit($receiver, $args, $argc); if ($inlined !== null) { diff --git a/tests/Unit/Bytecode/StringCharacterIntrinsicTest.php b/tests/Unit/Bytecode/StringCharacterIntrinsicTest.php new file mode 100644 index 00000000..456eff7f --- /dev/null +++ b/tests/Unit/Bytecode/StringCharacterIntrinsicTest.php @@ -0,0 +1,118 @@ +eval(<<<'JS' +function codes(text, positions) { + const values = []; + for (let i = 0; i < positions.length; i++) values.push(text.charCodeAt(positions[i])); + return JSON.stringify(values); +} +codes('é😀x', [-Infinity, -1.9, -0.5, -0, NaN, 0, 0.8, 1, 1.9, 2, 3, 4, Infinity]); +JS), + ); + $function = $engine->getGlobalEnv()->get('codes'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + self::assertSame('[55296,120,56320]', $engine->eval('codes("\uD800x\uDC00", [0, 1, 2])')); + self::assertSame('[null]', $engine->eval('codes("", [0])')); + } + + public function testPrimitiveNumericCallsUseTheIntrinsicBody(): void + { + $engine = new Engine(); + $function = $engine->getGlobalEnv()->get('String')->get('prototype')->get('charCodeAt'); + self::assertInstanceOf(JsFunction::class, $function); + $native = $function->getNativeCallable(); + self::assertNotNull($native); + $calls = 0; + $property = new \ReflectionProperty(JsFunction::class, 'nativeCallable'); + $property->setValue($function, static function (JsValue $receiver, array $arguments) use ($native, &$calls): JsValue { + ++$calls; + return $native($receiver, $arguments); + }); + try { + self::assertSame([233, 55357], $engine->eval(<<<'JS' +function read(text) { return [text.charCodeAt(0), text.charCodeAt(1)]; } +read('é😀'); +JS)); + self::assertSame(0, $calls); + } finally { + $property->setValue($function, $native); + } + } + + public function testCustomMethodsAndCoercionAreObservedOnce(): void + { + $engine = new Engine(); + self::assertSame([[121], ['receiver', 'index'], ['custom', 'custom'], [0, 1]], $engine->eval(<<<'JS' +function read(text, position) { return [text.charCodeAt(position)]; } +function pair(text) { return [text.charCodeAt(0), text.charCodeAt(1)]; } +const events = []; +const original = String.prototype.charCodeAt; +const receiver = { charCodeAt: original, toString() { events.push('receiver'); return 'xy'; } }; +const index = { valueOf() { events.push('index'); return 1; } }; +const first = read(receiver, index); +const calls = []; +String.prototype.charCodeAt = function (position) { calls.push(position); return 'custom'; }; +const second = pair('abc'); +String.prototype.charCodeAt = original; +[first, events, second, calls]; +JS)); + } + + public function testBorrowedRealmFunctionRetainsItsErrorIdentity(): void + { + $engine = new Engine(); + $foreign = new Engine(); + $function = $foreign->getGlobalEnv()->get('String')->get('prototype')->get('charCodeAt'); + self::assertInstanceOf(JsFunction::class, $function); + $engine->setGlobalJsValue('foreignChar', $function); + $engine->setGlobalJsValue('foreignTypeError', $foreign->getGlobalEnv()->get('TypeError')); + self::assertSame([[55357], true], $engine->eval(<<<'JS' +String.prototype.foreign = foreignChar; +function read(text, index) { return [text.foreign(index)]; } +const result = read('é😀', 1); +let sameRealm = false; +try { read('abc', Symbol()); } catch (error) { sameRealm = error.constructor === foreignTypeError; } +[result, sameRealm]; +JS)); + self::assertSame($foreign, $function->realm); + } + + public function testBudgetEnabledDuringACompiledCallStillStopsBeforeTheIntrinsic(): void + { + $engine = new Engine(); + $expired = false; + $engine->setGlobal('expireBudget', static function () use ($engine, &$expired): void { + if ($expired) { + $engine->setExecutionBudget(-1); + } + }); + self::assertSame([97], $engine->eval(<<<'JS' +function read(text, index) { expireBudget(); const value = text.charCodeAt(index); return [value]; } +read('abc', 0); +JS)); + $function = $engine->getGlobalEnv()->get('read'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + $expired = true; + $this->expectException(BudgetExceeded::class); + $engine->eval("read('abc', 0)"); + } +} From 77b0d8385e41131a9f66a2b6739b940457f62be0 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 00:14:23 +0200 Subject: [PATCH 38/99] Fix primitive property Reference receiver semantics --- src/Runtime/Reference.php | 40 +- src/Value/JsObject.php | 22 ++ src/Value/JsProxy.php | 11 +- .../fixtures/primitive-reference-updates.js | 94 +++++ .../fixtures/primitive-reference-updates.json | 357 ++++++++++++++++++ .../Runtime/PrimitiveReferenceUpdateTest.php | 34 ++ 6 files changed, 519 insertions(+), 39 deletions(-) create mode 100644 tests/Unit/Bytecode/fixtures/primitive-reference-updates.js create mode 100644 tests/Unit/Bytecode/fixtures/primitive-reference-updates.json create mode 100644 tests/Unit/Runtime/PrimitiveReferenceUpdateTest.php diff --git a/src/Runtime/Reference.php b/src/Runtime/Reference.php index deb774f6..dec39a54 100644 --- a/src/Runtime/Reference.php +++ b/src/Runtime/Reference.php @@ -57,8 +57,8 @@ public function __construct( * Resolve the deferred property key to a string name. * Performs ToPropertyKey on the stored raw key (so a Symbol wrapper's * @@toPrimitive returning the unboxed Symbol promotes the reference - * into a Symbol-keyed reference). The result is cached so that the - * ToPrimitive/ToString sequence runs at most once per reference. + * into a Symbol-keyed reference). GetValue normalizes the Reference's + * name, so PutValue must retain that key through later user coercion. */ private function resolvedName(): string { @@ -123,7 +123,11 @@ public function getValue(): JsValue return $this->base->get($name); } - return JsUndefined::instance(); + $wrapper = TypeConversion::toObject($this->base); + $name = $this->resolvedName(); + return $this->symbolKey !== null + ? $wrapper->getBySymbolWithReceiver($this->symbolKey, $this->base) + : $wrapper->getWithValueReceiver($name, $this->base); } /** Assign a value through this reference. */ @@ -186,33 +190,11 @@ public function setValue(JsValue $value): void // write that would create a new own property on the primitive must // fail; accessors (including proxy set traps) still run, observing // the primitive as the receiver. - $wrapper = \Phasis\Spec\TypeConversion::toObject($this->base); + $wrapper = TypeConversion::toObject($this->base); $name = $this->resolvedName(); - $cursor = $wrapper; - $handled = false; - while ($cursor !== null) { - // Proxies intercept [[Set]] directly rather than exposing - // own property descriptors, so give them a turn at the chain. - if ($cursor instanceof \Phasis\Value\JsProxy) { - $handled = $cursor->internalSet($name, $value, $wrapper); - break; - } - $desc = $cursor->getOwnPropertyDescriptor($name); - if ($desc === null) { - $cursor = $cursor->getPrototype(); - continue; - } - if ($desc->isAccessorDescriptor()) { - if ($desc->set instanceof \Phasis\Value\JsFunction) { - $desc->set->call($this->base, [$value]); - $handled = true; - } - break; - } - // Data descriptor found in chain; the write would create a - // new own property on the primitive receiver, which fails. - break; - } + $handled = $this->symbolKey !== null + ? $wrapper->setBySymbolWithValueReceiver($this->symbolKey, $value, $this->base) + : $wrapper->setWithValueReceiver($name, $value, $this->base); if ($handled) { return; } diff --git a/src/Value/JsObject.php b/src/Value/JsObject.php index 524fd7eb..9da92885 100644 --- a/src/Value/JsObject.php +++ b/src/Value/JsObject.php @@ -304,6 +304,28 @@ public function set(string $name, JsValue $value, bool $strict = false): void } } + /** Ordinary [[Set]] with a receiver that may be a primitive. */ + public function setWithValueReceiver(string $name, JsValue $value, JsValue $receiver): bool + { + if ($receiver instanceof JsObject) { + return $this->internalSet($name, $value, $receiver); + } + if ($this->isModuleNamespace && !self::isInternalSlot($name)) { + return false; + } + $descriptor = $this->getOwnPropertyDescriptor($name); + if ($descriptor === null) { + $prototype = $this->getPrototype(); + return $prototype !== null && $prototype->setWithValueReceiver($name, $value, $receiver); + } + if ($descriptor->isDataDescriptor() || $descriptor->set === null) { + // OrdinarySet cannot create an own data property on a primitive. + return false; + } + $descriptor->set->call($receiver, [$value]); + return true; + } + /** * ES spec: OrdinarySet ( O, P, V, Receiver ). * diff --git a/src/Value/JsProxy.php b/src/Value/JsProxy.php index 24286fce..499750a5 100644 --- a/src/Value/JsProxy.php +++ b/src/Value/JsProxy.php @@ -388,16 +388,7 @@ public function setWithValueReceiver(string $name, JsValue $value, JsValue $rece $this->validateSetInvariants($name, $value, $target); return true; } - // No trap: forward to target.[[Set]](P, V, Receiver). Target is - // a JsObject which only accepts JsObject receivers; coerce the - // (potentially primitive) receiver to itself by using the target - // as the receiver when it's not an Object — the underlying spec - // semantics for OrdinarySet then return false for primitive - // receivers on data descriptors. - if ($receiver instanceof JsObject) { - return $target->internalSet($name, $value, $receiver); - } - return $target->internalSet($name, $value, $target); + return $target->setWithValueReceiver($name, $value, $receiver); } /** diff --git a/tests/Unit/Bytecode/fixtures/primitive-reference-updates.js b/tests/Unit/Bytecode/fixtures/primitive-reference-updates.js new file mode 100644 index 00000000..e5963879 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/primitive-reference-updates.js @@ -0,0 +1,94 @@ +function primitiveMemberPost(base) { return base.value++; } +function primitiveMemberStrict(base) { 'use strict'; return base.value++; } +function primitiveComputedPost(base, key) { return base[key]++; } +function primitiveComputedStrict(base, key) { 'use strict'; return base[key]++; } +function encodePrimitiveUpdate(value) { + if (typeof value === 'bigint' || typeof value === 'symbol') return String(value); + if (typeof value === 'number' && !Number.isFinite(value)) return String(value); + if (value === undefined) return 'undefined'; + return value; +} +function observePrimitiveUpdate(action) { + try { return ['return', encodePrimitiveUpdate(action())]; } + catch (error) { return ['throw', error.name]; } +} +const primitiveUpdateResults = []; +const primitiveUpdateTrace = []; +const primitiveUpdateSymbol = Symbol('value'); +for (const sample of [1, true, 'xy', BigInt('2'), Symbol('primitive')]) { + const prototype = Object.getPrototypeOf(Object(sample)); + Object.defineProperty(prototype, 'value', { + configurable: true, + get: function () { + 'use strict'; + primitiveUpdateTrace.push(['get', typeof this, this === sample]); + return '4'; + }, + set: function (value) { + 'use strict'; + primitiveUpdateTrace.push(['set', typeof this, this === sample, value]); + }, + }); + Object.defineProperty(prototype, primitiveUpdateSymbol, { + configurable: true, + get: function () { + 'use strict'; + primitiveUpdateTrace.push(['symbol get', typeof this, this === sample]); + return BigInt('9'); + }, + set: function (value) { + 'use strict'; + primitiveUpdateTrace.push(['symbol set', typeof this, this === sample, String(value)]); + }, + }); + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveMemberPost(sample))); + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveMemberStrict(sample))); + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveComputedPost(sample, primitiveUpdateSymbol))); + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveComputedStrict(sample, Object(primitiveUpdateSymbol)))); + delete prototype.value; + delete prototype[primitiveUpdateSymbol]; +} + +for (const key of ['0', 'length']) { + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveComputedPost('12', key))); + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveComputedStrict('12', key))); +} + +const primitiveProxyTarget = {value: 3}; +primitiveUpdateResults.push(Reflect.set(new Proxy(primitiveProxyTarget, {}), 'value', 4, 1), primitiveProxyTarget.value); +const originalNumberPrototype = Object.getPrototypeOf(Number.prototype); +const primitiveProxy = new Proxy({ + get proxied() { + 'use strict'; + primitiveUpdateTrace.push(['proxy getter', typeof this, this === 1]); + return 2; + }, + set proxied(value) { + 'use strict'; + primitiveUpdateTrace.push(['proxy setter', typeof this, this === 1, value]); + }, + data: 3, +}, {}); +try { + Object.setPrototypeOf(Number.prototype, primitiveProxy); + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveComputedStrict(1, 'proxied'))); + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveComputedPost(1, 'data'))); + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveComputedStrict(1, 'data'))); +} finally { + Object.setPrototypeOf(Number.prototype, originalNumberPrototype); +} + +const primitiveSetTrap = new Proxy({}, { + get(target, key, receiver) { return key === 'proxied' ? 2 : Reflect.get(target, key, receiver); }, + set(target, key, value, receiver) { + primitiveUpdateTrace.push(['set trap', typeof receiver, receiver === 1, value]); + return true; + }, +}); +try { + Object.setPrototypeOf(Number.prototype, primitiveSetTrap); + primitiveUpdateResults.push(observePrimitiveUpdate(() => primitiveComputedStrict(1, 'proxied'))); +} finally { + Object.setPrototypeOf(Number.prototype, originalNumberPrototype); +} +const primitiveReferenceUpdateResult = [primitiveUpdateResults, primitiveUpdateTrace]; diff --git a/tests/Unit/Bytecode/fixtures/primitive-reference-updates.json b/tests/Unit/Bytecode/fixtures/primitive-reference-updates.json new file mode 100644 index 00000000..f48d9f74 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/primitive-reference-updates.json @@ -0,0 +1,357 @@ +[ + [ + [ + "return", + 4 + ], + [ + "return", + 4 + ], + [ + "return", + "9" + ], + [ + "return", + "9" + ], + [ + "return", + 4 + ], + [ + "return", + 4 + ], + [ + "return", + "9" + ], + [ + "return", + "9" + ], + [ + "return", + 4 + ], + [ + "return", + 4 + ], + [ + "return", + "9" + ], + [ + "return", + "9" + ], + [ + "return", + 4 + ], + [ + "return", + 4 + ], + [ + "return", + "9" + ], + [ + "return", + "9" + ], + [ + "return", + 4 + ], + [ + "return", + 4 + ], + [ + "return", + "9" + ], + [ + "return", + "9" + ], + [ + "return", + 1 + ], + [ + "throw", + "TypeError" + ], + [ + "return", + 2 + ], + [ + "throw", + "TypeError" + ], + false, + 3, + [ + "return", + 2 + ], + [ + "return", + 3 + ], + [ + "throw", + "TypeError" + ], + [ + "return", + 2 + ] + ], + [ + [ + "get", + "number", + true + ], + [ + "set", + "number", + true, + 5 + ], + [ + "get", + "number", + true + ], + [ + "set", + "number", + true, + 5 + ], + [ + "symbol get", + "number", + true + ], + [ + "symbol set", + "number", + true, + "10" + ], + [ + "symbol get", + "number", + true + ], + [ + "symbol set", + "number", + true, + "10" + ], + [ + "get", + "boolean", + true + ], + [ + "set", + "boolean", + true, + 5 + ], + [ + "get", + "boolean", + true + ], + [ + "set", + "boolean", + true, + 5 + ], + [ + "symbol get", + "boolean", + true + ], + [ + "symbol set", + "boolean", + true, + "10" + ], + [ + "symbol get", + "boolean", + true + ], + [ + "symbol set", + "boolean", + true, + "10" + ], + [ + "get", + "string", + true + ], + [ + "set", + "string", + true, + 5 + ], + [ + "get", + "string", + true + ], + [ + "set", + "string", + true, + 5 + ], + [ + "symbol get", + "string", + true + ], + [ + "symbol set", + "string", + true, + "10" + ], + [ + "symbol get", + "string", + true + ], + [ + "symbol set", + "string", + true, + "10" + ], + [ + "get", + "bigint", + true + ], + [ + "set", + "bigint", + true, + 5 + ], + [ + "get", + "bigint", + true + ], + [ + "set", + "bigint", + true, + 5 + ], + [ + "symbol get", + "bigint", + true + ], + [ + "symbol set", + "bigint", + true, + "10" + ], + [ + "symbol get", + "bigint", + true + ], + [ + "symbol set", + "bigint", + true, + "10" + ], + [ + "get", + "symbol", + true + ], + [ + "set", + "symbol", + true, + 5 + ], + [ + "get", + "symbol", + true + ], + [ + "set", + "symbol", + true, + 5 + ], + [ + "symbol get", + "symbol", + true + ], + [ + "symbol set", + "symbol", + true, + "10" + ], + [ + "symbol get", + "symbol", + true + ], + [ + "symbol set", + "symbol", + true, + "10" + ], + [ + "proxy getter", + "number", + true + ], + [ + "proxy setter", + "number", + true, + 3 + ], + [ + "set trap", + "number", + true, + 3 + ] + ] +] diff --git a/tests/Unit/Runtime/PrimitiveReferenceUpdateTest.php b/tests/Unit/Runtime/PrimitiveReferenceUpdateTest.php new file mode 100644 index 00000000..94473b71 --- /dev/null +++ b/tests/Unit/Runtime/PrimitiveReferenceUpdateTest.php @@ -0,0 +1,34 @@ +checkOracle(false); + } + + public function testBudgetedPrimitiveReferencesMatchTheSameOracle(): void + { + $this->checkOracle(true); + } + + private function checkOracle(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/../Bytecode/fixtures/primitive-reference-updates.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/../Bytecode/fixtures/primitive-reference-updates.json', + $engine->eval('JSON.stringify(primitiveReferenceUpdateResult)'), + ); + } +} From 6cefe1719d98e4dcdedd9566716e91f4fcea3cc8 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 00:14:30 +0200 Subject: [PATCH 39/99] Compile property increment and decrement updates --- src/Bytecode/Op.php | 4 + src/Bytecode/Parts/CompilerExpression.php | 17 +- src/Bytecode/VM.php | 31 + src/Runtime/Parts/ExpressionEvaluation.php | 38 +- tests/Unit/Bytecode/UpdateMemberTest.php | 118 + .../Unit/Bytecode/fixtures/update-members.js | 142 + .../Bytecode/fixtures/update-members.json | 2447 +++++++++++++++++ 7 files changed, 2791 insertions(+), 6 deletions(-) create mode 100644 tests/Unit/Bytecode/UpdateMemberTest.php create mode 100644 tests/Unit/Bytecode/fixtures/update-members.js create mode 100644 tests/Unit/Bytecode/fixtures/update-members.json diff --git a/src/Bytecode/Op.php b/src/Bytecode/Op.php index 302888d4..7747f9dd 100644 --- a/src/Bytecode/Op.php +++ b/src/Bytecode/Op.php @@ -183,6 +183,8 @@ final class Op public const DELETE_PROPERTY = 114; // pop key and base, delete the property, push the Boolean result. public const UPDATE_NAME = 115; // N I I: resolve a binding once, update by +/-1, push prefix/postfix result. public const EVAL_EXPRESSION = 116; // I: evaluate an environment-only expression through the interpreter. + public const UPDATE_MEMBER = 117; // N I I: update a literal property, preserving its resolved base. + public const UPDATE_COMPUTED = 118; // I I: update a computed property, coercing its key once. public const LOOP_INIT = 120; public const LOOP_TICK = 121; @@ -281,9 +283,11 @@ public static function operandCount(int $op): int return 1; // 2-operand opcodes case self::NEW_REGEXP: + case self::UPDATE_COMPUTED: return 2; // 3-operand opcodes case self::UPDATE_NAME: + case self::UPDATE_MEMBER: case self::JUMP_IF_LOCAL_GE_CONST: case self::JUMP_IF_LOCAL_GE_LOCAL: case self::JUMP_IF_LOCAL_GT_LOCAL: diff --git a/src/Bytecode/Parts/CompilerExpression.php b/src/Bytecode/Parts/CompilerExpression.php index 834d0425..db811be0 100644 --- a/src/Bytecode/Parts/CompilerExpression.php +++ b/src/Bytecode/Parts/CompilerExpression.php @@ -400,7 +400,22 @@ private function compileUpdate(UpdateExpression $node): void $this->emit(Op::UPDATE_NAME, $this->internName($name), (int) $isInc, (int) $node->prefix); return; } - // Member targets (`o.x++`, `o[k]++`) come in a later phase. + if ( + $arg instanceof MemberExpression && !$arg->optional + && !$arg->property instanceof PrivateIdentifier + && !($arg->object instanceof Identifier && $arg->object->name === 'super') + ) { + $this->compileExpression($arg->object); + if ($arg->computed) { + $this->compileExpression($arg->property); + $this->emit(Op::UPDATE_COMPUTED, (int) $isInc, (int) $node->prefix); + } elseif ($arg->property instanceof Identifier) { + $this->emit(Op::UPDATE_MEMBER, $this->internName($arg->property->name), (int) $isInc, (int) $node->prefix); + } else { + throw new CompilerBailout('unsupported update property'); + } + return; + } throw new CompilerBailout('update non-identifier'); } diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 18d985c9..bdb8fbcb 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -949,6 +949,37 @@ public function execute( ); $pc += 4; break; + case Op::UPDATE_MEMBER: + $obj = $stack[--$sp]; + $name = $names[$code[$pc + 1]]; + $increment = (bool) $code[$pc + 2]; + $prefix = (bool) $code[$pc + 3]; + if ( + $obj instanceof JsObject && get_class($obj) === JsObject::class + && ($old = $obj->properties->dataSlots[$name] ?? null) instanceof JsNumber + ) { + // Plain own data slots have no getter, setter, or + // coercion hooks. Preserve the same mutation barriers + // as an ordinary writable-property assignment. + $updated = JsNumber::of($old->value + ($increment ? 1.0 : -1.0)); + $obj->properties->setDataSlot($name, $updated); + $stack[$sp++] = $prefix ? $updated : $old; + } else { + $stack[$sp++] = $this->interp->vmUpdateMember($obj, $name, $increment, $prefix); + } + $pc += 4; + break; + case Op::UPDATE_COMPUTED: + $key = $stack[--$sp]; + $obj = $stack[--$sp]; + $stack[$sp++] = $this->interp->vmUpdateMember( + $obj, + $key, + (bool) $code[$pc + 1], + (bool) $code[$pc + 2], + ); + $pc += 3; + break; case Op::DEFINE_NAME: $env->defineVar($names[$code[$pc + 1]], $stack[--$sp]); $pc += 2; diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index d24f796f..9220f169 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -923,7 +923,7 @@ private function evalUpdateExpression(UpdateExpression $node, Environment $env): ); } - return $this->updateReferenceValue($ref, $node->operator === '++', $node->prefix); + return $this->updateReferenceValue($ref, $node->operator === '++', $node->prefix, false); } /** Update an identifier through its original reference, shared by the VM and interpreter. */ @@ -932,11 +932,31 @@ public function vmUpdateName(Environment $env, string $name, bool $increment, bo return $this->updateReferenceValue($this->resolveIdentifierReference($env, $name), $increment, $prefix); } - private function updateReferenceValue(Reference $ref, bool $increment, bool $prefix): JsValue + /** Update a property through one Reference, including computed-key and numeric coercion. */ + public function vmUpdateMember(JsValue $base, string|JsValue $key, bool $increment, bool $prefix): JsValue + { + $name = is_string($key) ? $key + : ($key instanceof JsObject || $key instanceof JsSymbol ? '' : TypeConversion::toString($key)); + // RequireObjectCoercible precedes object-key coercion for updates. + if ($base instanceof JsNull || $base instanceof JsUndefined) { + $type = $base instanceof JsNull ? 'null' : 'undefined'; + throw new TypeError("Cannot read properties of {$type} (reading '{$name}')"); + } + $ref = new Reference( + $base, + $name, + $this->strictMode, + symbolKey: $key instanceof JsSymbol ? $key : null, + rawKey: $key instanceof JsObject ? $key : null, + ); + return $this->updateReferenceValue($ref, $increment, $prefix, false); + } + + private function updateReferenceValue(Reference $ref, bool $increment, bool $prefix, bool $bindingReference = true): JsValue { // GetValue must run exactly once, before any user-defined numeric // conversion, while PutValue retains the originally resolved base. - $current = $this->withGetBindingValue($ref); + $current = $bindingReference ? $this->withGetBindingValue($ref) : $ref->getValue(); $oldNumeric = $current instanceof JsNumber ? $current : TypeConversion::toNumeric($current); if ($oldNumeric instanceof JsBigInt) { @@ -948,7 +968,11 @@ private function updateReferenceValue(Reference $ref, bool $increment, bool $pre $raw = '0'; } $newValue = new JsBigInt($raw); - $this->withSetMutableBindingCheck($ref, $newValue); + if ($bindingReference) { + $this->withSetMutableBindingCheck($ref, $newValue); + } else { + $ref->setValue($newValue); + } return $prefix ? $newValue : $oldNumeric; } @@ -957,7 +981,11 @@ private function updateReferenceValue(Reference $ref, bool $increment, bool $pre : JsNumber::of(TypeConversion::toNumber($oldNumeric)); $delta = $increment ? 1.0 : -1.0; $newValue = JsNumber::of($oldValue->value + $delta); - $this->withSetMutableBindingCheck($ref, $newValue); + if ($bindingReference) { + $this->withSetMutableBindingCheck($ref, $newValue); + } else { + $ref->setValue($newValue); + } return $prefix ? $newValue : $oldValue; } diff --git a/tests/Unit/Bytecode/UpdateMemberTest.php b/tests/Unit/Bytecode/UpdateMemberTest.php new file mode 100644 index 00000000..130b802f --- /dev/null +++ b/tests/Unit/Bytecode/UpdateMemberTest.php @@ -0,0 +1,118 @@ +checkOracle(false); + $members = [ + 'memberPostIncrement', 'memberPreIncrement', 'memberPostDecrement', 'memberPreDecrement', + 'strictMemberIncrement', 'updateGlobalMember', + 'primitiveMemberPost', 'primitiveMemberStrict', + ]; + foreach ($members as $name) { + $this->assertUsesOpcode($engine, $name, Op::UPDATE_MEMBER); + } + $computed = [ + 'computedPostIncrement', 'computedPreIncrement', 'computedPostDecrement', 'computedPreDecrement', + 'strictComputedIncrement', 'computedExpressionIncrement', 'updateGlobalComputed', + 'primitiveComputedPost', 'primitiveComputedStrict', + ]; + foreach ($computed as $name) { + $this->assertUsesOpcode($engine, $name, Op::UPDATE_COMPUTED); + } + } + + public function testInterpreterPropertyUpdatesMatchTheSameNodeOracle(): void + { + $this->checkOracle(true); + } + + public function testProgramPropertyUpdatesUseTheLiveGlobalBinding(): void + { + self::assertSame([1, 3, 3], (new Engine())->eval(<<<'JS' +var value = 1; +var alias = globalThis; +var first = alias.value++; +var second = ++globalThis.value; +[first, second, value]; +JS)); + } + + public function testComputedObjectKeysRetainTheirNormalizedReferenceName(): void + { + // Node 26.12 coerces these keys twice. Follow GetValue's normalized + // Reference name and the pinned test262 S11.*_A6_T3 cases instead. + $source = <<<'JS' +function specUpdate(base, key) { return base[key]++; } +const symbol = Symbol('key'); +const target = {first: 1, second: 20, [symbol]: 10}; +let conversions = 0; +const key = { + [Symbol.toPrimitive]() { return ['first', symbol, 'second'][conversions++]; } +}; +const seen = [specUpdate(target, key), target.first, specUpdate(target, key), target[symbol], + specUpdate(target, key), target.second, conversions]; +let throws = 0; +const throwingKey = {toString() { if (throws++) throw new RangeError('later reference'); return 'first'; }}; +seen.push(specUpdate(target, throwingKey), target.first); +try { specUpdate(target, throwingKey); } catch (error) { seen.push(error.name); } +seen.push(throws); +const mutableKey = {toString() { return 'first'; }}; +const changing = { + first: {valueOf() { mutableKey.toString = function () { return symbol; }; return 3; }}, + [symbol]: 10 +}; +seen.push(specUpdate(changing, mutableKey), changing.first, changing[symbol], + specUpdate(changing, mutableKey), changing[symbol]); +seen; +JS; + foreach ([false, true] as $budgeted) { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + self::assertSame([1, 2, 10, 11, 20, 21, 3, 2, 3, 'RangeError', 2, 3, 4, 10, 10, 11], $engine->eval($source)); + if (!$budgeted) { + $this->assertUsesOpcode($engine, 'specUpdate', Op::UPDATE_COMPUTED); + } + } + } + + private function assertUsesOpcode(Engine $engine, string $name, int $opcode): void + { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name); + self::assertContains($opcode, $function->compiled->code, $name); + } + + private function checkOracle(bool $interpreter): Engine + { + $engine = new Engine(); + if ($interpreter) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/update-members.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/update-members.json', + $engine->eval('JSON.stringify(updateMemberResult)'), + ); + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/primitive-reference-updates.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/primitive-reference-updates.json', + $engine->eval('JSON.stringify(primitiveReferenceUpdateResult)'), + ); + + return $engine; + } +} diff --git a/tests/Unit/Bytecode/fixtures/update-members.js b/tests/Unit/Bytecode/fixtures/update-members.js new file mode 100644 index 00000000..6c9bd914 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/update-members.js @@ -0,0 +1,142 @@ +function memberPostIncrement(base) { return base.value++; } +function memberPreIncrement(base) { return ++base.value; } +function memberPostDecrement(base) { return base.value--; } +function memberPreDecrement(base) { return --base.value; } +function computedPostIncrement(base, key) { return base[key]++; } +function computedPreIncrement(base, key) { return ++base[key]; } +function computedPostDecrement(base, key) { return base[key]--; } +function computedPreDecrement(base, key) { return --base[key]; } +function strictMemberIncrement(base) { 'use strict'; return base.value++; } +function strictComputedIncrement(base, key) { 'use strict'; return base[key]++; } +function computedExpressionIncrement(base, key) { return base[key()]++; } +function updateGlobalMember() { return memberUpdateTarget.value++; } +function updateGlobalComputed() { return memberUpdateTarget[memberUpdateKey]++; } +function encodeMemberUpdate(value) { + if (typeof value === 'bigint') return String(value) + 'n'; + if (typeof value === 'symbol') return String(value); + if (typeof value === 'number') { + if (Object.is(value, -0)) return '-0'; + if (!Number.isFinite(value)) return String(value); + } + if (value === undefined) return 'undefined'; + return value; +} +function observeMemberUpdate(action) { + try { return ['return', encodeMemberUpdate(action())]; } + catch (error) { return ['throw', error.name]; } +} +const memberUpdateResults = []; +const memberUpdateTrace = []; +const memberUpdateOperations = [memberPostIncrement, memberPreIncrement, memberPostDecrement, memberPreDecrement, + computedPostIncrement, computedPreIncrement, computedPostDecrement, computedPreDecrement]; +const memberUpdateInputs = [0, -0, 2.5, NaN, Infinity, -Infinity, true, false, null, undefined, + '12', '-0', '', 'nonnumeric', BigInt('9007199254740993'), Symbol('update')]; +for (let pass = 0; pass < 2; pass++) { + for (const operation of memberUpdateOperations) { + for (const input of memberUpdateInputs) { + const base = {value: input}; + memberUpdateResults.push([operation.name, observeMemberUpdate(() => operation(base, 'value')), + encodeMemberUpdate(base.value)]); + } + const base = {value: { [Symbol.toPrimitive](hint) { memberUpdateTrace.push(hint); return BigInt('7'); } }}; + memberUpdateResults.push([observeMemberUpdate(() => operation(base, 'value')), encodeMemberUpdate(base.value)]); + } +} + +for (const operation of [memberPostIncrement, memberPreDecrement, strictMemberIncrement, + computedPostIncrement, strictComputedIncrement]) { + const base = {}; + let stored; + Object.defineProperty(base, 'value', { + configurable: true, + get() { + memberUpdateTrace.push('get'); + return { [Symbol.toPrimitive](hint) { memberUpdateTrace.push('convert ' + hint); return '11'; } }; + }, + set(value) { memberUpdateTrace.push('set ' + value); stored = value; }, + }); + memberUpdateResults.push([observeMemberUpdate(() => operation(base, 'value')), stored]); + Object.defineProperty(base, 'value', {value: 8, writable: false, configurable: true}); + memberUpdateResults.push(observeMemberUpdate(() => operation(base, 'value')), base.value); + Object.defineProperty(base, 'value', { + configurable: true, + get() { memberUpdateTrace.push('throwing getter'); throw new RangeError('get'); }, + }); + memberUpdateResults.push(observeMemberUpdate(() => operation(base, 'value'))); + Object.defineProperty(base, 'value', { + configurable: true, + get() { return { valueOf() { memberUpdateTrace.push('conversion throws'); throw new SyntaxError('number'); } }; }, + set() { memberUpdateTrace.push('unexpected setter'); }, + }); + memberUpdateResults.push(observeMemberUpdate(() => operation(base, 'value'))); + Object.defineProperty(base, 'value', { + configurable: true, + get() { return '4'; }, + set(value) { memberUpdateTrace.push('throwing set ' + value); throw new RangeError('set'); }, + }); + memberUpdateResults.push(observeMemberUpdate(() => operation(base, 'value'))); +} + +for (const operation of [computedPostIncrement, computedPreDecrement, strictComputedIncrement]) { + const target = {value: '3'}; + const proxy = new Proxy(target, { + get(object, key, receiver) { memberUpdateTrace.push('proxy get ' + String(key)); return Reflect.get(object, key, receiver); }, + set(object, key, value, receiver) { + memberUpdateTrace.push('proxy set ' + String(key) + '=' + value); + return Reflect.set(object, key, value, receiver); + }, + }); + const key = 'value'; + memberUpdateResults.push([observeMemberUpdate(() => operation(proxy, key)), target.value]); + const refusing = new Proxy({value: 3}, { + set(object, key, value) { memberUpdateTrace.push('refuse ' + value); return false; }, + }); + memberUpdateResults.push(observeMemberUpdate(() => operation(refusing, 'value'))); +} + +const memberUpdateSymbol = Symbol('slot'); +for (const operation of [computedPostIncrement, computedPreDecrement]) { + const base = {[memberUpdateSymbol]: BigInt('9')}; + const key = Object(memberUpdateSymbol); + memberUpdateResults.push([observeMemberUpdate(() => operation(base, key)), encodeMemberUpdate(base[memberUpdateSymbol])]); +} + +let memberUpdateTarget; +let memberUpdateKey; +for (const operation of [updateGlobalMember, updateGlobalComputed]) { + memberUpdateTarget = {value: { + valueOf() { memberUpdateTrace.push('numeric base replacement'); memberUpdateTarget = {value: 50}; return 4; }, + }}; + memberUpdateKey = 'value'; + const original = memberUpdateTarget; + memberUpdateResults.push([observeMemberUpdate(operation), original.value, memberUpdateTarget.value]); +} + +for (const base of [null, undefined]) { + const key = { toString() { memberUpdateTrace.push('unexpected null key coercion'); return 'value'; } }; + memberUpdateResults.push(observeMemberUpdate(() => computedExpressionIncrement(base, () => { + memberUpdateTrace.push('key expression'); return key; + }))); +} +for (const operation of [memberPostIncrement, strictMemberIncrement, computedPostIncrement, strictComputedIncrement]) { + memberUpdateResults.push(observeMemberUpdate(() => operation(3, 'value'))); +} + +const memberUpdateInherited = { + get value() { memberUpdateTrace.push('inherited get ' + this.tag); return '6'; }, + set value(value) { memberUpdateTrace.push('inherited set ' + this.tag + '=' + value); }, +}; +const memberUpdateReceiver = Object.create(memberUpdateInherited); +memberUpdateReceiver.tag = 'receiver'; +memberUpdateResults.push(observeMemberUpdate(() => memberPostIncrement(memberUpdateReceiver))); + +function memberUpdateWithinWith(object) { with (object) { return memberPostIncrement(object); } } +const memberUpdateWithTarget = {value: '4'}; +const memberUpdateWithObject = new Proxy(memberUpdateWithTarget, { + has(object, key) { memberUpdateTrace.push('with has ' + String(key)); return Reflect.has(object, key); }, + get(object, key, receiver) { memberUpdateTrace.push('with get ' + String(key)); return Reflect.get(object, key, receiver); }, + set(object, key, value, receiver) { memberUpdateTrace.push('with set ' + String(key)); return Reflect.set(object, key, value, receiver); }, +}); +memberUpdateResults.push(observeMemberUpdate(() => memberUpdateWithinWith(memberUpdateWithObject)), memberUpdateWithTarget.value); + +const updateMemberResult = [memberUpdateResults, memberUpdateTrace]; diff --git a/tests/Unit/Bytecode/fixtures/update-members.json b/tests/Unit/Bytecode/fixtures/update-members.json new file mode 100644 index 00000000..a8f45d5d --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/update-members.json @@ -0,0 +1,2447 @@ +[ + [ + [ + "memberPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + "-0" + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + 2.5 + ], + 3.5 + ], + [ + "memberPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostIncrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "memberPostIncrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "memberPostIncrement", + [ + "return", + 1 + ], + 2 + ], + [ + "memberPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostIncrement", + [ + "return", + 12 + ], + 13 + ], + [ + "memberPostIncrement", + [ + "return", + "-0" + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostIncrement", + [ + "return", + "9007199254740993n" + ], + "9007199254740994n" + ], + [ + "memberPostIncrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "7n" + ], + "8n" + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + 3.5 + ], + 3.5 + ], + [ + "memberPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreIncrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "memberPreIncrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "memberPreIncrement", + [ + "return", + 2 + ], + 2 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreIncrement", + [ + "return", + 13 + ], + 13 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreIncrement", + [ + "return", + "9007199254740994n" + ], + "9007199254740994n" + ], + [ + "memberPreIncrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "8n" + ], + "8n" + ], + [ + "memberPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + "-0" + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + 2.5 + ], + 1.5 + ], + [ + "memberPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostDecrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "memberPostDecrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "memberPostDecrement", + [ + "return", + 1 + ], + 0 + ], + [ + "memberPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostDecrement", + [ + "return", + 12 + ], + 11 + ], + [ + "memberPostDecrement", + [ + "return", + "-0" + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostDecrement", + [ + "return", + "9007199254740993n" + ], + "9007199254740992n" + ], + [ + "memberPostDecrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "7n" + ], + "6n" + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + 1.5 + ], + 1.5 + ], + [ + "memberPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreDecrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "memberPreDecrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "memberPreDecrement", + [ + "return", + 0 + ], + 0 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreDecrement", + [ + "return", + 11 + ], + 11 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreDecrement", + [ + "return", + "9007199254740992n" + ], + "9007199254740992n" + ], + [ + "memberPreDecrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "6n" + ], + "6n" + ], + [ + "computedPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + "-0" + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + 2.5 + ], + 3.5 + ], + [ + "computedPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostIncrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "computedPostIncrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "computedPostIncrement", + [ + "return", + 1 + ], + 2 + ], + [ + "computedPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostIncrement", + [ + "return", + 12 + ], + 13 + ], + [ + "computedPostIncrement", + [ + "return", + "-0" + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostIncrement", + [ + "return", + "9007199254740993n" + ], + "9007199254740994n" + ], + [ + "computedPostIncrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "7n" + ], + "8n" + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + 3.5 + ], + 3.5 + ], + [ + "computedPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreIncrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "computedPreIncrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "computedPreIncrement", + [ + "return", + 2 + ], + 2 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreIncrement", + [ + "return", + 13 + ], + 13 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreIncrement", + [ + "return", + "9007199254740994n" + ], + "9007199254740994n" + ], + [ + "computedPreIncrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "8n" + ], + "8n" + ], + [ + "computedPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + "-0" + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + 2.5 + ], + 1.5 + ], + [ + "computedPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostDecrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "computedPostDecrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "computedPostDecrement", + [ + "return", + 1 + ], + 0 + ], + [ + "computedPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostDecrement", + [ + "return", + 12 + ], + 11 + ], + [ + "computedPostDecrement", + [ + "return", + "-0" + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostDecrement", + [ + "return", + "9007199254740993n" + ], + "9007199254740992n" + ], + [ + "computedPostDecrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "7n" + ], + "6n" + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + 1.5 + ], + 1.5 + ], + [ + "computedPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreDecrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "computedPreDecrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "computedPreDecrement", + [ + "return", + 0 + ], + 0 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreDecrement", + [ + "return", + 11 + ], + 11 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreDecrement", + [ + "return", + "9007199254740992n" + ], + "9007199254740992n" + ], + [ + "computedPreDecrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "6n" + ], + "6n" + ], + [ + "memberPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + "-0" + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + 2.5 + ], + 3.5 + ], + [ + "memberPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostIncrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "memberPostIncrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "memberPostIncrement", + [ + "return", + 1 + ], + 2 + ], + [ + "memberPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostIncrement", + [ + "return", + 12 + ], + 13 + ], + [ + "memberPostIncrement", + [ + "return", + "-0" + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "memberPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostIncrement", + [ + "return", + "9007199254740993n" + ], + "9007199254740994n" + ], + [ + "memberPostIncrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "7n" + ], + "8n" + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + 3.5 + ], + 3.5 + ], + [ + "memberPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreIncrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "memberPreIncrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "memberPreIncrement", + [ + "return", + 2 + ], + 2 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreIncrement", + [ + "return", + 13 + ], + 13 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "memberPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreIncrement", + [ + "return", + "9007199254740994n" + ], + "9007199254740994n" + ], + [ + "memberPreIncrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "8n" + ], + "8n" + ], + [ + "memberPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + "-0" + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + 2.5 + ], + 1.5 + ], + [ + "memberPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostDecrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "memberPostDecrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "memberPostDecrement", + [ + "return", + 1 + ], + 0 + ], + [ + "memberPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostDecrement", + [ + "return", + 12 + ], + 11 + ], + [ + "memberPostDecrement", + [ + "return", + "-0" + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "memberPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPostDecrement", + [ + "return", + "9007199254740993n" + ], + "9007199254740992n" + ], + [ + "memberPostDecrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "7n" + ], + "6n" + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + 1.5 + ], + 1.5 + ], + [ + "memberPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreDecrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "memberPreDecrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "memberPreDecrement", + [ + "return", + 0 + ], + 0 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreDecrement", + [ + "return", + 11 + ], + 11 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "memberPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "memberPreDecrement", + [ + "return", + "9007199254740992n" + ], + "9007199254740992n" + ], + [ + "memberPreDecrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "6n" + ], + "6n" + ], + [ + "computedPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + "-0" + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + 2.5 + ], + 3.5 + ], + [ + "computedPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostIncrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "computedPostIncrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "computedPostIncrement", + [ + "return", + 1 + ], + 2 + ], + [ + "computedPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostIncrement", + [ + "return", + 12 + ], + 13 + ], + [ + "computedPostIncrement", + [ + "return", + "-0" + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + 0 + ], + 1 + ], + [ + "computedPostIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostIncrement", + [ + "return", + "9007199254740993n" + ], + "9007199254740994n" + ], + [ + "computedPostIncrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "7n" + ], + "8n" + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + 3.5 + ], + 3.5 + ], + [ + "computedPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreIncrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "computedPreIncrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "computedPreIncrement", + [ + "return", + 2 + ], + 2 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreIncrement", + [ + "return", + 13 + ], + 13 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + 1 + ], + 1 + ], + [ + "computedPreIncrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreIncrement", + [ + "return", + "9007199254740994n" + ], + "9007199254740994n" + ], + [ + "computedPreIncrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "8n" + ], + "8n" + ], + [ + "computedPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + "-0" + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + 2.5 + ], + 1.5 + ], + [ + "computedPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostDecrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "computedPostDecrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "computedPostDecrement", + [ + "return", + 1 + ], + 0 + ], + [ + "computedPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostDecrement", + [ + "return", + 12 + ], + 11 + ], + [ + "computedPostDecrement", + [ + "return", + "-0" + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + 0 + ], + -1 + ], + [ + "computedPostDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPostDecrement", + [ + "return", + "9007199254740993n" + ], + "9007199254740992n" + ], + [ + "computedPostDecrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "7n" + ], + "6n" + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + 1.5 + ], + 1.5 + ], + [ + "computedPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreDecrement", + [ + "return", + "Infinity" + ], + "Infinity" + ], + [ + "computedPreDecrement", + [ + "return", + "-Infinity" + ], + "-Infinity" + ], + [ + "computedPreDecrement", + [ + "return", + 0 + ], + 0 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreDecrement", + [ + "return", + 11 + ], + 11 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + -1 + ], + -1 + ], + [ + "computedPreDecrement", + [ + "return", + "NaN" + ], + "NaN" + ], + [ + "computedPreDecrement", + [ + "return", + "9007199254740992n" + ], + "9007199254740992n" + ], + [ + "computedPreDecrement", + [ + "throw", + "TypeError" + ], + "Symbol(update)" + ], + [ + [ + "return", + "6n" + ], + "6n" + ], + [ + [ + "return", + 11 + ], + 12 + ], + [ + "return", + 8 + ], + 8, + [ + "throw", + "RangeError" + ], + [ + "throw", + "SyntaxError" + ], + [ + "throw", + "RangeError" + ], + [ + [ + "return", + 10 + ], + 10 + ], + [ + "return", + 7 + ], + 8, + [ + "throw", + "RangeError" + ], + [ + "throw", + "SyntaxError" + ], + [ + "throw", + "RangeError" + ], + [ + [ + "return", + 11 + ], + 12 + ], + [ + "throw", + "TypeError" + ], + 8, + [ + "throw", + "RangeError" + ], + [ + "throw", + "SyntaxError" + ], + [ + "throw", + "RangeError" + ], + [ + [ + "return", + 11 + ], + 12 + ], + [ + "return", + 8 + ], + 8, + [ + "throw", + "RangeError" + ], + [ + "throw", + "SyntaxError" + ], + [ + "throw", + "RangeError" + ], + [ + [ + "return", + 11 + ], + 12 + ], + [ + "throw", + "TypeError" + ], + 8, + [ + "throw", + "RangeError" + ], + [ + "throw", + "SyntaxError" + ], + [ + "throw", + "RangeError" + ], + [ + [ + "return", + 3 + ], + 4 + ], + [ + "return", + 3 + ], + [ + [ + "return", + 2 + ], + 2 + ], + [ + "return", + 2 + ], + [ + [ + "return", + 3 + ], + 4 + ], + [ + "throw", + "TypeError" + ], + [ + [ + "return", + "9n" + ], + "10n" + ], + [ + [ + "return", + "8n" + ], + "8n" + ], + [ + [ + "return", + 4 + ], + 5, + 50 + ], + [ + [ + "return", + 4 + ], + 5, + 50 + ], + [ + "throw", + "TypeError" + ], + [ + "throw", + "TypeError" + ], + [ + "return", + "NaN" + ], + [ + "throw", + "TypeError" + ], + [ + "return", + "NaN" + ], + [ + "throw", + "TypeError" + ], + [ + "return", + 6 + ], + [ + "return", + 4 + ], + 5 + ], + [ + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "number", + "get", + "convert number", + "set 12", + "throwing getter", + "conversion throws", + "throwing set 5", + "get", + "convert number", + "set 10", + "throwing getter", + "conversion throws", + "throwing set 3", + "get", + "convert number", + "set 12", + "throwing getter", + "conversion throws", + "throwing set 5", + "get", + "convert number", + "set 12", + "throwing getter", + "conversion throws", + "throwing set 5", + "get", + "convert number", + "set 12", + "throwing getter", + "conversion throws", + "throwing set 5", + "proxy get value", + "proxy set value=4", + "refuse 4", + "proxy get value", + "proxy set value=2", + "refuse 2", + "proxy get value", + "proxy set value=4", + "refuse 4", + "numeric base replacement", + "numeric base replacement", + "key expression", + "key expression", + "inherited get receiver", + "inherited set receiver=7", + "with has memberPostIncrement", + "with has object", + "with get value", + "with set value" + ] +] From bcced36a3e787fc45b2ddc964aa00abf8b9d63f2 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 00:17:10 +0200 Subject: [PATCH 40/99] Read numeric TypedArray elements through indexed getters --- src/Bytecode/VM.php | 13 + tests/Unit/Bytecode/TypedArrayReadTest.php | 41 + .../Bytecode/fixtures/typed-array-reads.js | 63 ++ .../Bytecode/fixtures/typed-array-reads.json | 999 ++++++++++++++++++ 4 files changed, 1116 insertions(+) create mode 100644 tests/Unit/Bytecode/TypedArrayReadTest.php create mode 100644 tests/Unit/Bytecode/fixtures/typed-array-reads.js create mode 100644 tests/Unit/Bytecode/fixtures/typed-array-reads.json diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index bdb8fbcb..acbf3856 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -2513,6 +2513,19 @@ public function execute( } } } + if ( + $obj instanceof \Phasis\Value\JsTypedArray && $key instanceof JsNumber + && $key->value >= 0 && $key->value < PHP_INT_MAX + ) { + $index = (int) $key->value; + if ((float) $index === $key->value) { + // Numeric integer keys need no property-key coercion. + // Keep detached and resizable checks in the getter. + $stack[$sp++] = $obj->getIndex($index); + $pc++; + break; + } + } $stack[$sp++] = $this->lookupComputed($obj, $key); $pc++; break; diff --git a/tests/Unit/Bytecode/TypedArrayReadTest.php b/tests/Unit/Bytecode/TypedArrayReadTest.php new file mode 100644 index 00000000..b6ec69c5 --- /dev/null +++ b/tests/Unit/Bytecode/TypedArrayReadTest.php @@ -0,0 +1,41 @@ + */ + public static function executionModes(): iterable + { + yield 'bytecode' => [false]; + yield 'interpreter' => [true]; + } + + #[DataProvider('executionModes')] + public function testIndexedReadsPreserveNodeKeysAndBufferChanges(bool $interpret): void + { + $engine = new Engine(); + if ($interpret) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/typed-array-reads.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/typed-array-reads.json', + $engine->eval('JSON.stringify(typedArrayReadResult)'), + ); + $function = $engine->getGlobalEnv()->get('indexedRead'); + self::assertInstanceOf(JsFunction::class, $function); + if ($interpret) { + self::assertNull($function->compiled); + } else { + self::assertNotNull($function->compiled, 'Numeric reads must exercise bytecode.'); + } + } +} diff --git a/tests/Unit/Bytecode/fixtures/typed-array-reads.js b/tests/Unit/Bytecode/fixtures/typed-array-reads.js new file mode 100644 index 00000000..f1592be6 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/typed-array-reads.js @@ -0,0 +1,63 @@ +function indexedRead(view, key) { return [view[key]]; } +function readText(value) { return typeof value + ':' + (Object.is(value, -0) ? '-0' : String(value)); } +const typedArrayReadResult = []; +const constructors = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, + Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array]; +for (const Constructor of constructors) { + const bigint = Constructor === BigInt64Array || Constructor === BigUint64Array; + const view = new Constructor(bigint ? [1n, -1n, 257n] : [7, -0, 257]); + for (const key of [-0, 0, 1, 2, 3, 0.5, -1, NaN, Infinity, -Infinity, 9007199254740991, + 1e16, 1e20, 1e21, 9223372036854775807]) { + typedArrayReadResult.push([Constructor.name, readText(key), readText(indexedRead(view, key)[0])]); + } +} + +const effects = []; +const view = new Uint8Array([17, 19]); +const prototype = Object.create(Uint8Array.prototype); +Object.setPrototypeOf(view, prototype); +for (const name of ['0', '2', '-0', 'NaN', 'Infinity']) { + Object.defineProperty(prototype, name, {get() { effects.push('invalid:' + name); return 99; }}); +} +Object.defineProperty(prototype, '01', {get() { effects.push('ordinary:' + (this === view)); return 31; }}); +prototype['1000000000000000000000'] = 37; +const symbol = Symbol('value'); +prototype[symbol] = 41; +for (const key of [0, -0, 2, NaN, Infinity, '0', '-0', '01', '1000000000000000000000', symbol]) { + typedArrayReadResult.push(['prototype', readText(key), readText(indexedRead(view, key)[0])]); +} +const objectKey = {[Symbol.toPrimitive](hint) { effects.push('key:' + hint); return '1'; }}; +typedArrayReadResult.push(['object-key', readText(indexedRead(view, objectKey)[0]), effects]); + +const proxyEffects = []; +const proxy = new Proxy(view, {get(target, key, receiver) { + proxyEffects.push(String(key)); + return key === '0' ? 53 : Reflect.get(target, key, receiver); +}}); +typedArrayReadResult.push(['proxy', indexedRead(proxy, 0)[0], proxyEffects]); + +const buffer = new ArrayBuffer(8, {maxByteLength: 16}); +new Uint16Array(buffer).set([11, 22, 33, 44]); +const fixed = new Uint16Array(buffer, 2, 2); +const tracking = new Uint16Array(buffer, 2); +typedArrayReadResult.push(['before-resize', indexedRead(fixed, 0)[0], indexedRead(fixed, 1)[0], + indexedRead(tracking, 2)[0]]); +buffer.resize(3); +typedArrayReadResult.push(['shrunk', fixed.length, tracking.length, readText(indexedRead(fixed, 0)[0]), + readText(indexedRead(tracking, 0)[0])]); +buffer.resize(12); +typedArrayReadResult.push(['grown', fixed.length, tracking.length, indexedRead(fixed, 0)[0], + indexedRead(fixed, 1)[0], indexedRead(tracking, 2)[0]]); +const shrinkingKey = {[Symbol.toPrimitive]() { buffer.resize(2); return '0'; }}; +typedArrayReadResult.push(['coercion-resize', readText(indexedRead(fixed, shrinkingKey)[0]), + readText(indexedRead(tracking, 0)[0])]); + +const detachedBuffer = new ArrayBuffer(2); +const detached = new Uint8Array(detachedBuffer); +detached[0] = 61; +const detachingKey = {[Symbol.toPrimitive]() { + structuredClone(detachedBuffer, {transfer: [detachedBuffer]}); + return '0'; +}}; +typedArrayReadResult.push(['coercion-detach', readText(indexedRead(detached, detachingKey)[0]), + readText(indexedRead(detached, 0)[0]), readText(indexedRead(detached, '0')[0])]); diff --git a/tests/Unit/Bytecode/fixtures/typed-array-reads.json b/tests/Unit/Bytecode/fixtures/typed-array-reads.json new file mode 100644 index 00000000..51755b92 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/typed-array-reads.json @@ -0,0 +1,999 @@ +[ + [ + "Int8Array", + "number:-0", + "number:7" + ], + [ + "Int8Array", + "number:0", + "number:7" + ], + [ + "Int8Array", + "number:1", + "number:0" + ], + [ + "Int8Array", + "number:2", + "number:1" + ], + [ + "Int8Array", + "number:3", + "undefined:undefined" + ], + [ + "Int8Array", + "number:0.5", + "undefined:undefined" + ], + [ + "Int8Array", + "number:-1", + "undefined:undefined" + ], + [ + "Int8Array", + "number:NaN", + "undefined:undefined" + ], + [ + "Int8Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "Int8Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Int8Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Int8Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Int8Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Int8Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "Int8Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:-0", + "number:7" + ], + [ + "Uint8Array", + "number:0", + "number:7" + ], + [ + "Uint8Array", + "number:1", + "number:0" + ], + [ + "Uint8Array", + "number:2", + "number:1" + ], + [ + "Uint8Array", + "number:3", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:0.5", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:-1", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:NaN", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "Uint8Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:-0", + "number:7" + ], + [ + "Uint8ClampedArray", + "number:0", + "number:7" + ], + [ + "Uint8ClampedArray", + "number:1", + "number:0" + ], + [ + "Uint8ClampedArray", + "number:2", + "number:255" + ], + [ + "Uint8ClampedArray", + "number:3", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:0.5", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:-1", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:NaN", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:Infinity", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:1e+21", + "undefined:undefined" + ], + [ + "Uint8ClampedArray", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "Int16Array", + "number:-0", + "number:7" + ], + [ + "Int16Array", + "number:0", + "number:7" + ], + [ + "Int16Array", + "number:1", + "number:0" + ], + [ + "Int16Array", + "number:2", + "number:257" + ], + [ + "Int16Array", + "number:3", + "undefined:undefined" + ], + [ + "Int16Array", + "number:0.5", + "undefined:undefined" + ], + [ + "Int16Array", + "number:-1", + "undefined:undefined" + ], + [ + "Int16Array", + "number:NaN", + "undefined:undefined" + ], + [ + "Int16Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "Int16Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Int16Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Int16Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Int16Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Int16Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "Int16Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:-0", + "number:7" + ], + [ + "Uint16Array", + "number:0", + "number:7" + ], + [ + "Uint16Array", + "number:1", + "number:0" + ], + [ + "Uint16Array", + "number:2", + "number:257" + ], + [ + "Uint16Array", + "number:3", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:0.5", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:-1", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:NaN", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "Uint16Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "Int32Array", + "number:-0", + "number:7" + ], + [ + "Int32Array", + "number:0", + "number:7" + ], + [ + "Int32Array", + "number:1", + "number:0" + ], + [ + "Int32Array", + "number:2", + "number:257" + ], + [ + "Int32Array", + "number:3", + "undefined:undefined" + ], + [ + "Int32Array", + "number:0.5", + "undefined:undefined" + ], + [ + "Int32Array", + "number:-1", + "undefined:undefined" + ], + [ + "Int32Array", + "number:NaN", + "undefined:undefined" + ], + [ + "Int32Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "Int32Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Int32Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Int32Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Int32Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Int32Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "Int32Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:-0", + "number:7" + ], + [ + "Uint32Array", + "number:0", + "number:7" + ], + [ + "Uint32Array", + "number:1", + "number:0" + ], + [ + "Uint32Array", + "number:2", + "number:257" + ], + [ + "Uint32Array", + "number:3", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:0.5", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:-1", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:NaN", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "Uint32Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "Float16Array", + "number:-0", + "number:7" + ], + [ + "Float16Array", + "number:0", + "number:7" + ], + [ + "Float16Array", + "number:1", + "number:-0" + ], + [ + "Float16Array", + "number:2", + "number:257" + ], + [ + "Float16Array", + "number:3", + "undefined:undefined" + ], + [ + "Float16Array", + "number:0.5", + "undefined:undefined" + ], + [ + "Float16Array", + "number:-1", + "undefined:undefined" + ], + [ + "Float16Array", + "number:NaN", + "undefined:undefined" + ], + [ + "Float16Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "Float16Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Float16Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Float16Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Float16Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Float16Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "Float16Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "Float32Array", + "number:-0", + "number:7" + ], + [ + "Float32Array", + "number:0", + "number:7" + ], + [ + "Float32Array", + "number:1", + "number:-0" + ], + [ + "Float32Array", + "number:2", + "number:257" + ], + [ + "Float32Array", + "number:3", + "undefined:undefined" + ], + [ + "Float32Array", + "number:0.5", + "undefined:undefined" + ], + [ + "Float32Array", + "number:-1", + "undefined:undefined" + ], + [ + "Float32Array", + "number:NaN", + "undefined:undefined" + ], + [ + "Float32Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "Float32Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Float32Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Float32Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Float32Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Float32Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "Float32Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "Float64Array", + "number:-0", + "number:7" + ], + [ + "Float64Array", + "number:0", + "number:7" + ], + [ + "Float64Array", + "number:1", + "number:-0" + ], + [ + "Float64Array", + "number:2", + "number:257" + ], + [ + "Float64Array", + "number:3", + "undefined:undefined" + ], + [ + "Float64Array", + "number:0.5", + "undefined:undefined" + ], + [ + "Float64Array", + "number:-1", + "undefined:undefined" + ], + [ + "Float64Array", + "number:NaN", + "undefined:undefined" + ], + [ + "Float64Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "Float64Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "Float64Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "Float64Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "Float64Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "Float64Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "Float64Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:-0", + "bigint:1" + ], + [ + "BigInt64Array", + "number:0", + "bigint:1" + ], + [ + "BigInt64Array", + "number:1", + "bigint:-1" + ], + [ + "BigInt64Array", + "number:2", + "bigint:257" + ], + [ + "BigInt64Array", + "number:3", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:0.5", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:-1", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:NaN", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "BigInt64Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:-0", + "bigint:1" + ], + [ + "BigUint64Array", + "number:0", + "bigint:1" + ], + [ + "BigUint64Array", + "number:1", + "bigint:18446744073709551615" + ], + [ + "BigUint64Array", + "number:2", + "bigint:257" + ], + [ + "BigUint64Array", + "number:3", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:0.5", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:-1", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:NaN", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:Infinity", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:-Infinity", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:9007199254740991", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:10000000000000000", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:100000000000000000000", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:1e+21", + "undefined:undefined" + ], + [ + "BigUint64Array", + "number:9223372036854776000", + "undefined:undefined" + ], + [ + "prototype", + "number:0", + "number:17" + ], + [ + "prototype", + "number:-0", + "number:17" + ], + [ + "prototype", + "number:2", + "undefined:undefined" + ], + [ + "prototype", + "number:NaN", + "undefined:undefined" + ], + [ + "prototype", + "number:Infinity", + "undefined:undefined" + ], + [ + "prototype", + "string:0", + "number:17" + ], + [ + "prototype", + "string:-0", + "undefined:undefined" + ], + [ + "prototype", + "string:01", + "number:31" + ], + [ + "prototype", + "string:1000000000000000000000", + "number:37" + ], + [ + "prototype", + "symbol:Symbol(value)", + "number:41" + ], + [ + "object-key", + "number:19", + [ + "ordinary:true", + "key:string" + ] + ], + [ + "proxy", + 53, + [ + "0" + ] + ], + [ + "before-resize", + 22, + 33, + 44 + ], + [ + "shrunk", + 0, + 0, + "undefined:undefined", + "undefined:undefined" + ], + [ + "grown", + 2, + 5, + 22, + 0, + 0 + ], + [ + "coercion-resize", + "undefined:undefined", + "undefined:undefined" + ], + [ + "coercion-detach", + "undefined:undefined", + "undefined:undefined", + "undefined:undefined" + ] +] From fb4108cf282deea3f53d20943bd325062e93fd66 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 23 Oct 2026 22:42:16 +0000 Subject: [PATCH 41/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 44 +++++++------- compat.json | 164 ++++++++++++++++++++++++++-------------------------- 2 files changed, 103 insertions(+), 105 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 47a4922d..d1edb983 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,13 +3,13 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-23T21:31:51+00:00` +- Snapshot time: `2026-10-23T22:42:14+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `a472e73f` (dirty) +- Git: `feat/express-hono-compatibility` @ `bcced36a` (dirty) ## Summary @@ -198,26 +198,26 @@ Generated from a completed `test262` pass. Do not edit by hand. | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| built-ins/decodeURIComponent | NORMAL | 162.504s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| built-ins/decodeURI | NORMAL | 139.670s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| staging/sm | NORMAL | 98.116s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 94.933s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 94.120s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 93.761s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 93.604s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 89.156s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| staging/sm | NORMAL | 87.407s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| language/literals | NORMAL | 87.008s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | -| intl402 | NORMAL | 86.139s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | -| staging/sm | NORMAL | 81.900s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| staging/sm | NORMAL | 77.896s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| built-ins/decodeURI | NORMAL | 72.868s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | -| built-ins/decodeURIComponent | NORMAL | 72.668s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | -| intl402/DateTimeFormat | NORMAL | 66.794s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | -| staging/sm | NORMAL | 64.798s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| annexB/built-ins/RegExp | NORMAL | 64.035s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.773s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tagbanwa.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Le.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Tham.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Viet.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Yo.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.259s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nandinagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_New_Tai_Lue.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Newa.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nko.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nushu.js` | +| staging/sm | NORMAL | 178.113s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 177.236s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 174.932s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 173.783s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 172.134s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 161.071s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| built-ins/decodeURIComponent | NORMAL | 160.213s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| staging/sm | NORMAL | 151.531s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| staging/sm | NORMAL | 145.027s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| built-ins/decodeURI | NORMAL | 142.401s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| staging/sm | NORMAL | 140.809s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| staging/sm | NORMAL | 99.334s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| intl402 | NORMAL | 89.761s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | +| language/literals | NORMAL | 86.762s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | +| built-ins/TypedArray | NORMAL | 72.654s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | +| built-ins/decodeURIComponent | NORMAL | 72.198s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | +| built-ins/decodeURI | NORMAL | 71.191s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | +| intl402/DateTimeFormat | NORMAL | 67.042s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | +| annexB/built-ins/RegExp | NORMAL | 64.604s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.430s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Linear_A.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Linear_B.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Lisu.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 4dd9f2fd..22e7fa47 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-23T21:31:51+00:00", - "updatedAt": "2026-10-23T21:31:51+00:00", + "generatedAt": "2026-10-23T22:42:14+00:00", + "updatedAt": "2026-10-23T22:42:14+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "a472e73f", + "commit": "bcced36a", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "0530f1fb192e60e80993eef7840d5e17cb3b28fb", - "runIdentity": "899f70ca2405bb5b0bc40b346926d040b8e7f9c17dffd25c14d2ef7206000952" + "fingerprint": "334feb69abfcc6f625451b033c0456e0e9e4b5cf", + "runIdentity": "5b2a1450979babf9804570e09487114d3a631c0ae316d415bfdd99472deca6e4" }, "discovery": { "groupCount": 161, @@ -2717,36 +2717,36 @@ "blockedChunks": [], "slowChunks": [ { - "group": "built-ins/decodeURIComponent", + "group": "staging/sm", "kind": "normal", - "durationSec": 162.504, + "durationSec": 178.113, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" ] }, { - "group": "built-ins/decodeURI", + "group": "staging/sm", "kind": "normal", - "durationSec": 139.67, + "durationSec": 177.236, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 98.116, + "durationSec": 174.932, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 94.933, + "durationSec": 173.783, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" @@ -2755,7 +2755,7 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 94.12, + "durationSec": 172.134, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" @@ -2764,56 +2764,70 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 93.761, + "durationSec": 161.071, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" + ] + }, + { + "group": "built-ins/decodeURIComponent", + "kind": "normal", + "durationSec": 160.213, + "filesCount": 1, + "sampleFiles": [ + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 93.604, + "durationSec": 151.531, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 89.156, + "durationSec": 145.027, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + ] + }, + { + "group": "built-ins/decodeURI", + "kind": "normal", + "durationSec": 142.401, + "filesCount": 1, + "sampleFiles": [ + "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 87.407, + "durationSec": 140.809, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { - "group": "language/literals", + "group": "staging/sm", "kind": "normal", - "durationSec": 87.008, - "filesCount": 25, + "durationSec": 99.334, + "filesCount": 1, "sampleFiles": [ - "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", - "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", - "...", - "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", - "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { "group": "intl402", "kind": "normal", - "durationSec": 86.139, + "durationSec": 89.761, "filesCount": 22, "sampleFiles": [ "test262/test/intl402/constructors-string-and-single-element-array.js", @@ -2824,40 +2838,35 @@ ] }, { - "group": "staging/sm", - "kind": "normal", - "durationSec": 81.9, - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" - ] - }, - { - "group": "staging/sm", + "group": "language/literals", "kind": "normal", - "durationSec": 77.896, - "filesCount": 1, + "durationSec": 86.762, + "filesCount": 25, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" + "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", + "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", + "...", + "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", + "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" ] }, { - "group": "built-ins/decodeURI", + "group": "built-ins/TypedArray", "kind": "normal", - "durationSec": 72.868, + "durationSec": 72.654, "filesCount": 25, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", + "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", + "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js", "...", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" + "test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js", + "test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js" ] }, { "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 72.668, + "durationSec": 72.198, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", @@ -2867,10 +2876,23 @@ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" ] }, + { + "group": "built-ins/decodeURI", + "kind": "normal", + "durationSec": 71.191, + "filesCount": 25, + "sampleFiles": [ + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", + "...", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" + ] + }, { "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 66.794, + "durationSec": 67.042, "filesCount": 12, "sampleFiles": [ "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", @@ -2880,19 +2902,10 @@ "test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js" ] }, - { - "group": "staging/sm", - "kind": "normal", - "durationSec": 64.798, - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" - ] - }, { "group": "annexB/built-ins/RegExp", "kind": "normal", - "durationSec": 64.035, + "durationSec": 64.604, "filesCount": 25, "sampleFiles": [ "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", @@ -2905,27 +2918,12 @@ { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.773, - "filesCount": 5, - "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tagbanwa.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Le.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Tham.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Viet.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Yo.js" - ] - }, - { - "group": "built-ins/RegExp/property-escapes/generated", - "kind": "normal", - "durationSec": 59.259, - "filesCount": 5, + "durationSec": 59.43, + "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nandinagari.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_New_Tai_Lue.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Newa.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nko.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nushu.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Linear_A.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Linear_B.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Lisu.js" ] } ] From 53731b675c81cdf06abd48a512ea32a358ab04af Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 00:36:27 +0200 Subject: [PATCH 42/99] Honor callable iterator proxies and primitive iterator overrides --- src/Runtime/Parts/StatementExecution.php | 85 +----- tests/Unit/Runtime/IteratorMethodTest.php | 26 ++ .../Unit/Runtime/fixtures/iterator-methods.js | 75 +++++ .../Runtime/fixtures/iterator-methods.json | 277 ++++++++++++++++++ 4 files changed, 391 insertions(+), 72 deletions(-) create mode 100644 tests/Unit/Runtime/IteratorMethodTest.php create mode 100644 tests/Unit/Runtime/fixtures/iterator-methods.js create mode 100644 tests/Unit/Runtime/fixtures/iterator-methods.json diff --git a/src/Runtime/Parts/StatementExecution.php b/src/Runtime/Parts/StatementExecution.php index 1ee2c2d2..5a21ee1f 100644 --- a/src/Runtime/Parts/StatementExecution.php +++ b/src/Runtime/Parts/StatementExecution.php @@ -1605,7 +1605,7 @@ private function execForOfStatement(ForOfStatement $node, Environment $env, ?str if ($iterator !== null) { $nextMethod = $iterator->get('next'); - if (!$nextMethod instanceof JsFunction) { + if (!$nextMethod instanceof JsFunction && !($nextMethod instanceof \Phasis\Value\JsProxy && $nextMethod->isCallable())) { throw new TypeError('Iterator result next is not a function'); } @@ -1637,7 +1637,7 @@ private function execForOfStatement(ForOfStatement $node, Environment $env, ?str } // Per spec GetMethod: non-callable → TypeError. - if (!$returnMethod instanceof JsFunction) { + if (!$returnMethod instanceof JsFunction && !($returnMethod instanceof \Phasis\Value\JsProxy && $returnMethod->isCallable())) { if ($isOriginalThrow) { return null; } @@ -1648,7 +1648,9 @@ private function execForOfStatement(ForOfStatement $node, Environment $env, ?str // Step 3c: innerResult = Call(return, iterator). try { - $innerResult = $this->callFunction($returnMethod, $iterator, []); + $innerResult = $returnMethod instanceof \Phasis\Value\JsProxy + ? $returnMethod->apply($iterator, []) + : $this->callFunction($returnMethod, $iterator, []); // Step 5: if original was throw, return it (ignore return() result). if ($isOriginalThrow) { return null; @@ -1682,7 +1684,9 @@ private function execForOfStatement(ForOfStatement $node, Environment $env, ?str throw new InternalError('Maximum loop iterations exceeded'); } - $result = $this->callFunction($nextMethod, $iterator, []); + $result = $nextMethod instanceof \Phasis\Value\JsProxy + ? $nextMethod->apply($iterator, []) + : $this->callFunction($nextMethod, $iterator, []); // For for-await-of, unwrap the promise returned by the async iterator. if ($node->await) { $result = $this->forAwaitUnwrap($result, $env); @@ -2163,77 +2167,14 @@ private function awaitValue(JsValue $value): JsValue private function getIterator(JsValue $iterable): ?JsObject { - // String iteration: produce a code-point iterator that correctly - // handles surrogate pairs and lone surrogates per spec 22.1.5.2.1. - if ($iterable instanceof JsString) { - $chars = []; - $u16 = JsString::utf8ToUtf16LE($iterable->value); - $u16Len = (int) (strlen($u16) / 2); - $si = 0; - while ($si < $u16Len) { - $cu = ord($u16[$si * 2]) | (ord($u16[$si * 2 + 1]) << 8); - if ($cu >= 0xD800 && $cu <= 0xDBFF && $si + 1 < $u16Len) { - $next = ord($u16[($si + 1) * 2]) | (ord($u16[($si + 1) * 2 + 1]) << 8); - if ($next >= 0xDC00 && $next <= 0xDFFF) { - // Valid surrogate pair: combine into a single code point. - $cp = ($cu - 0xD800) * 0x400 + ($next - 0xDC00) + 0x10000; - $chars[] = mb_chr($cp, 'UTF-8'); - $si += 2; - continue; - } - } - // Lone surrogate or BMP character. - $chars[] = JsString::utf16CodeUnitToUtf8($cu); - $si++; - } - $index = 0; - $total = count($chars); - - $iterator = new JsObject(); - $nextFn = function () use (&$index, $total, &$chars): JsValue { - $result = new JsObject(); - if ($index < $total) { - $result->set('value', new JsString($chars[$index])); - $result->set('done', new JsBoolean(false)); - $index++; - } else { - $result->set('value', JsUndefined::instance()); - $result->set('done', new JsBoolean(true)); - } - return $result; - }; - $iterator->set('next', JsFunction::fromCallable('next', $nextFn)); - return $iterator; - } - - // For non-string primitives, GetMethod(V, @@iterator) looks up on the - // wrapper prototype; an installed Symbol.iterator there must be called - // with the primitive as its receiver. - if ( - $iterable instanceof JsNumber - || $iterable instanceof JsBoolean - || $iterable instanceof \Phasis\Value\JsBigInt - || $iterable instanceof JsSymbol - ) { - $wrapper = TypeConversion::toObject($iterable); - $iterSym = \Phasis\BuiltIn\SymbolConstructor::iterator(); - $method = $wrapper->getBySymbol($iterSym); - if (!$method instanceof JsFunction) { - return null; - } - $result = $this->callFunction($method, $iterable, []); - if (!$result instanceof JsObject) { - throw new TypeError('Iterator method did not return an object'); - } - return $result; - } - if (!$iterable instanceof JsObject) { + if ($iterable instanceof JsNull || $iterable instanceof JsUndefined) { return null; } - - // Check for Symbol.iterator method. + // GetV boxes primitives for lookup but retains the original receiver + // for accessors and calls, including overridden string iterators. + $wrapper = $iterable instanceof JsObject ? $iterable : TypeConversion::toObject($iterable); $iterSym = \Phasis\BuiltIn\SymbolConstructor::iterator(); - $iteratorMethod = $iterable->getBySymbol($iterSym); + $iteratorMethod = $wrapper->getBySymbolWithReceiver($iterSym, $iterable); $isCallable = $iteratorMethod instanceof JsFunction || ($iteratorMethod instanceof \Phasis\Value\JsProxy && $iteratorMethod->isCallable()); diff --git a/tests/Unit/Runtime/IteratorMethodTest.php b/tests/Unit/Runtime/IteratorMethodTest.php new file mode 100644 index 00000000..b57396fc --- /dev/null +++ b/tests/Unit/Runtime/IteratorMethodTest.php @@ -0,0 +1,26 @@ +setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/iterator-methods.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/iterator-methods.json', + $engine->eval('JSON.stringify(iteratorMethodsResult)'), + ); + } + } +} diff --git a/tests/Unit/Runtime/fixtures/iterator-methods.js b/tests/Unit/Runtime/fixtures/iterator-methods.js new file mode 100644 index 00000000..91b86939 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/iterator-methods.js @@ -0,0 +1,75 @@ +function methodLoop(input, mode, trace) { + const values = []; + for (const value of input) { + trace.push('body:' + value); + values.push(value); + if (mode === 'break') break; + if (mode === 'return') return value; + if (mode === 'throw') throw new RangeError('body'); + } + return values; +} +function methodObserve(action) { + try { return ['return', action()]; } + catch (error) { return ['throw', error.name]; } +} +const iteratorMethodsResult = []; +for (const mode of ['normal', 'break', 'return', 'throw']) { + for (const revoked of ['none', 'next', 'return']) { + const trace = []; + let index = 0; + const iterator = {}; + const next = Proxy.revocable(function () { + return {done: index >= 2, value: ++index}; + }, { + apply(target, receiver, args) { + trace.push('next receiver:' + (receiver === iterator) + ':' + args.length); + return Reflect.apply(target, receiver, args); + }, + }); + const close = Proxy.revocable(function () { return {}; }, { + apply(target, receiver, args) { + trace.push('return receiver:' + (receiver === iterator) + ':' + args.length); + return Reflect.apply(target, receiver, args); + }, + }); + iterator.next = next.proxy; + iterator.return = close.proxy; + if (revoked === 'next') next.revoke(); + if (revoked === 'return') close.revoke(); + const input = {}; + input[Symbol.iterator] = new Proxy(function () { return iterator; }, { + apply(target, receiver, args) { + trace.push('iterator receiver:' + (receiver === input) + ':' + args.length); + return Reflect.apply(target, receiver, args); + }, + }); + iteratorMethodsResult.push([mode, revoked, methodObserve(function () { return methodLoop(input, mode, trace); }), trace]); + } +} +for (const sample of ['abc', 7, true, BigInt('8'), Symbol('sample')]) { + const prototype = Object.getPrototypeOf(Object(sample)); + const previous = Object.getOwnPropertyDescriptor(prototype, Symbol.iterator); + const trace = []; + try { + Object.defineProperty(prototype, Symbol.iterator, { + configurable: true, + get: function () { + 'use strict'; + trace.push('getter receiver:' + typeof this + ':' + (this === sample)); + return new Proxy(function () { return [9].values(); }, { + apply(target, receiver, args) { + trace.push('method receiver:' + typeof receiver + ':' + (receiver === sample)); + return Reflect.apply(target, receiver, args); + }, + }); + }, + }); + iteratorMethodsResult.push([typeof sample, methodObserve(function () { return methodLoop(sample, 'normal', trace); }), trace]); + Object.defineProperty(prototype, Symbol.iterator, {value: undefined, configurable: true}); + iteratorMethodsResult.push([typeof sample, 'missing', methodObserve(function () { return methodLoop(sample, 'normal', []); })]); + } finally { + if (previous) Object.defineProperty(prototype, Symbol.iterator, previous); + else delete prototype[Symbol.iterator]; + } +} diff --git a/tests/Unit/Runtime/fixtures/iterator-methods.json b/tests/Unit/Runtime/fixtures/iterator-methods.json new file mode 100644 index 00000000..791e392b --- /dev/null +++ b/tests/Unit/Runtime/fixtures/iterator-methods.json @@ -0,0 +1,277 @@ +[ + [ + "normal", + "none", + [ + "return", + [ + 1, + 2 + ] + ], + [ + "iterator receiver:true:0", + "next receiver:true:0", + "body:1", + "next receiver:true:0", + "body:2", + "next receiver:true:0" + ] + ], + [ + "normal", + "next", + [ + "throw", + "TypeError" + ], + [ + "iterator receiver:true:0" + ] + ], + [ + "normal", + "return", + [ + "return", + [ + 1, + 2 + ] + ], + [ + "iterator receiver:true:0", + "next receiver:true:0", + "body:1", + "next receiver:true:0", + "body:2", + "next receiver:true:0" + ] + ], + [ + "break", + "none", + [ + "return", + [ + 1 + ] + ], + [ + "iterator receiver:true:0", + "next receiver:true:0", + "body:1", + "return receiver:true:0" + ] + ], + [ + "break", + "next", + [ + "throw", + "TypeError" + ], + [ + "iterator receiver:true:0" + ] + ], + [ + "break", + "return", + [ + "throw", + "TypeError" + ], + [ + "iterator receiver:true:0", + "next receiver:true:0", + "body:1" + ] + ], + [ + "return", + "none", + [ + "return", + 1 + ], + [ + "iterator receiver:true:0", + "next receiver:true:0", + "body:1", + "return receiver:true:0" + ] + ], + [ + "return", + "next", + [ + "throw", + "TypeError" + ], + [ + "iterator receiver:true:0" + ] + ], + [ + "return", + "return", + [ + "throw", + "TypeError" + ], + [ + "iterator receiver:true:0", + "next receiver:true:0", + "body:1" + ] + ], + [ + "throw", + "none", + [ + "throw", + "RangeError" + ], + [ + "iterator receiver:true:0", + "next receiver:true:0", + "body:1", + "return receiver:true:0" + ] + ], + [ + "throw", + "next", + [ + "throw", + "TypeError" + ], + [ + "iterator receiver:true:0" + ] + ], + [ + "throw", + "return", + [ + "throw", + "RangeError" + ], + [ + "iterator receiver:true:0", + "next receiver:true:0", + "body:1" + ] + ], + [ + "string", + [ + "return", + [ + 9 + ] + ], + [ + "getter receiver:string:true", + "method receiver:string:true", + "body:9" + ] + ], + [ + "string", + "missing", + [ + "throw", + "TypeError" + ] + ], + [ + "number", + [ + "return", + [ + 9 + ] + ], + [ + "getter receiver:number:true", + "method receiver:number:true", + "body:9" + ] + ], + [ + "number", + "missing", + [ + "throw", + "TypeError" + ] + ], + [ + "boolean", + [ + "return", + [ + 9 + ] + ], + [ + "getter receiver:boolean:true", + "method receiver:boolean:true", + "body:9" + ] + ], + [ + "boolean", + "missing", + [ + "throw", + "TypeError" + ] + ], + [ + "bigint", + [ + "return", + [ + 9 + ] + ], + [ + "getter receiver:bigint:true", + "method receiver:bigint:true", + "body:9" + ] + ], + [ + "bigint", + "missing", + [ + "throw", + "TypeError" + ] + ], + [ + "symbol", + [ + "return", + [ + 9 + ] + ], + [ + "getter receiver:symbol:true", + "method receiver:symbol:true", + "body:9" + ] + ], + [ + "symbol", + "missing", + [ + "throw", + "TypeError" + ] + ] +] From e083162c96043dcb82f86dfe06690df9382baa27 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 00:38:36 +0200 Subject: [PATCH 43/99] Preserve RegExp legacy state in custom matching --- src/BuiltIn/RegExp_/RegExpExec.php | 128 +- src/Regex/Matcher.php | 38 +- tests/Unit/Runtime/RegExpPredicateTest.php | 34 + tests/Unit/Runtime/RegExpReplaceTest.php | 46 + .../Unit/Runtime/fixtures/regexp-predicate.js | 103 ++ .../Runtime/fixtures/regexp-predicate.json | 1366 +++++++++++++++++ tests/Unit/Runtime/fixtures/regexp-replace.js | 126 ++ .../Unit/Runtime/fixtures/regexp-replace.json | 865 +++++++++++ 8 files changed, 2657 insertions(+), 49 deletions(-) create mode 100644 tests/Unit/Runtime/RegExpPredicateTest.php create mode 100644 tests/Unit/Runtime/RegExpReplaceTest.php create mode 100644 tests/Unit/Runtime/fixtures/regexp-predicate.js create mode 100644 tests/Unit/Runtime/fixtures/regexp-predicate.json create mode 100644 tests/Unit/Runtime/fixtures/regexp-replace.js create mode 100644 tests/Unit/Runtime/fixtures/regexp-replace.json diff --git a/src/BuiltIn/RegExp_/RegExpExec.php b/src/BuiltIn/RegExp_/RegExpExec.php index 13f6801e..b57cacce 100644 --- a/src/BuiltIn/RegExp_/RegExpExec.php +++ b/src/BuiltIn/RegExp_/RegExpExec.php @@ -44,6 +44,11 @@ private static function isIntrinsicExec(JsObject $obj): bool $current = $obj; $guard = 0; while ($current !== null && $guard++ < 32) { + // Descriptor inspection must not introduce Proxy traps or other + // exotic operations before the ordinary RegExpExec lookup. + if (get_class($current) !== JsObject::class) { + return false; + } $desc = $current->getOwnPropertyDescriptor('exec'); if ($desc !== null) { if ($desc->isAccessorDescriptor()) { @@ -75,6 +80,52 @@ public static function recordLegacyMatch( self::$legacyGroups = $groups; } + /** @param list $groups */ + private static function recordLegacyCaptureValues( + string $input, + string $matched, + string $left, + string $right, + array $groups, + ): void { + self::recordLegacyMatch( + $input, + $matched, + $left, + $right, + $groups === [] ? '' : $groups[array_key_last($groups)], + $groups, + ); + } + + /** @return \Closure(string, string, string, list): void */ + private static function legacyMatchRecorder(string $input): \Closure + { + return static function (string $matched, string $left, string $right, array $groups) use ($input): void { + self::recordLegacyCaptureValues($input, $matched, $left, $right, $groups); + }; + } + + /** @param array $matches */ + private static function recordLegacyPcreMatch(string $input, array $matches): void + { + $matched = (string) $matches[0][0]; + $start = (int) $matches[0][1]; + $groups = []; + foreach ($matches as $key => $match) { + if (is_int($key) && $key > 0) { + $groups[] = ($match[1] === -1 || $match[0] === null) ? '' : (string) $match[0]; + } + } + self::recordLegacyCaptureValues( + $input, + $matched, + substr($input, 0, $start), + substr($input, $start + strlen($matched)), + $groups, + ); + } + /** * RegExp.prototype.exec(string) - spec §22.2.6.2 * @@ -439,28 +490,7 @@ private static function execMethod(): \Closure } // Annex B legacy: record state for RegExp.lastMatch / $1..$9 etc. - $matchByteEnd = $matches[0][1] + strlen((string) $matches[0][0]); - $leftCtxBytes = substr($str, 0, $matches[0][1]); - $rightCtxBytes = (string) substr($str, $matchByteEnd); - $groupStrings = []; - $lastNonEmpty = ''; - foreach ($matches as $key => $match) { - if (is_int($key) && $key > 0) { - $g = ($match[1] === -1 || $match[0] === null) ? '' : (string) $match[0]; - $groupStrings[] = $g; - if ($g !== '') { - $lastNonEmpty = $g; - } - } - } - self::recordLegacyMatch( - $str, - (string) $matches[0][0], - $leftCtxBytes, - $rightCtxBytes, - $lastNonEmpty, - $groupStrings, - ); + self::recordLegacyPcreMatch($str, $matches); return $result; } @@ -639,6 +669,20 @@ private static function execCustomMatcher( )); } + $legacyGroups = []; + foreach ($match['captures'] as $index => $capture) { + if ($index > 0) { + $legacyGroups[] = $capture[2] ?? ''; + } + } + $wholeInput = $matchCharPos === 0 && $matchStr === $str; + self::recordLegacyCaptureValues( + $str, + $matchStr, + $matchCharPos === 0 ? '' : self::sliceUtf16Range($str, 0, $matchCharPos), + $wholeInput ? '' : self::sliceUtf16Range($str, $matchCharEnd, PHP_INT_MAX), + $legacyGroups, + ); return $result; } @@ -710,23 +754,22 @@ private static function applyRepeatedGroupFixes( /** * Predicate fast path for `RegExp.prototype.test`. Returns true / - * false when the receiver still has the intrinsic exec and a - * [[CustomRegexAst]] internal slot, so we can decide the boolean - * without materialising the JsObject result (capture slicing, - * indices array, named groups). Returns null to signal the caller - * should fall back to the spec-shaped slow path — anything with - * a custom exec override, sticky/global lastIndex side effects, - * or only-PCRE2 routing where Annex B legacy recording is still - * required. + * false when the receiver still has intrinsic exec and a custom matcher. + * Match strings and captures still update legacy state, while result + * objects, indices arrays and named-group objects are not exposed. + * Custom exec, observable lastIndex coercion and global/sticky updates + * keep the full RegExpExec path. * * For a 1.1M-codepoint input matched by `/^\D+$/u`, the slow path - * would call internalIndexToUtf16 twice (start + end) and slice - * the entire input — three O(N) walks that don't influence the - * boolean. This path skips them. + * would convert both indices and slice the entire input. The streaming + * predicate can report that whole-input match without those extra walks. */ private static function regExpTestFast(JsObject $rx, string $S): ?bool { - if (!self::isIntrinsicExec($rx)) { + if ( + !self::isIntrinsicExec($rx) + || !$rx->getOwnPropertyDescriptor('lastIndex')?->value instanceof JsNumber + ) { return null; } $pcreDesc = $rx->getOwnPropertyDescriptor('[[PCREPattern]]'); @@ -738,22 +781,15 @@ private static function regExpTestFast(JsObject $rx, string $S): ?bool ? $origFlagsDesc->value->value : ''; // Sticky / global write to lastIndex on every call (and on no - // match, reset to 0). Annex B legacy state recording on a - // successful match is also observable. Both are intentional - // side effects of the spec's RegExpExec abstract op; defer to - // the slow path so those observable effects stay correct. + // match, reset to 0), so they keep the full RegExpExec path. if ( str_contains($origFlags, 'g') || str_contains($origFlags, 'y') ) { return null; } - // Custom matcher path: this is the only branch in the slow - // path that already skips Annex B legacy state recording, so - // bypassing the JsObject build here matches existing - // observable behaviour exactly. Short-circuiting the PCRE2 - // branch would also have to update the legacy slots after a - // successful match, so that case stays on the slow path. + // Predicate matching retains the same legacy captures and contexts as + // exec without allocating a JavaScript match-result array. $customAstDesc = $rx->getOwnPropertyDescriptor('[[CustomRegexAst]]'); $customFlagsDesc = $rx->getOwnPropertyDescriptor('[[CustomRegexFlags]]'); if ( @@ -767,7 +803,7 @@ private static function regExpTestFast(JsObject $rx, string $S): ?bool $customAstDesc->value->value, $customFlagsDesc->value->value, ); - return $matcher->matchTest($S, 0); + return $matcher->matchTest($S, 0, self::legacyMatchRecorder($S)); } catch (\Phasis\Regex\MatcherBudgetExceeded) { // Pattern triggered catastrophic backtracking in the // tree-walker; let the slow path try PCRE2 instead. @@ -824,7 +860,7 @@ private static function regExpTestFast(JsObject $rx, string $S): ?bool ), ); $matcher = new \Phasis\Regex\Matcher($regexAst, $patFlags); - return $matcher->matchTest($S, 0); + return $matcher->matchTest($S, 0, self::legacyMatchRecorder($S)); } catch (\Phasis\Regex\MatcherBudgetExceeded) { return null; } catch (\Throwable) { diff --git a/src/Regex/Matcher.php b/src/Regex/Matcher.php index c50ad45a..5849871a 100644 --- a/src/Regex/Matcher.php +++ b/src/Regex/Matcher.php @@ -223,9 +223,12 @@ public function match(string $inputUtf8, int $startCodeUnit, bool $anchored = fa * record (skips capture-slice extraction and per-group UTF-16 * conversion). For inputs in the millions of code points (e.g. * test262's CharacterClassEscapes corpus) this is the difference - * between two O(N) post-match walks and zero. + * between two O(N) post-match walks and zero. An optional observer receives + * the strings needed by RegExp's legacy match state, without result objects. + * + * @param ?\Closure(string, string, string, list): void $onMatch */ - public function matchTest(string $inputUtf8, int $startCodeUnit): bool + public function matchTest(string $inputUtf8, int $startCodeUnit, ?\Closure $onMatch = null): bool { // Vectorized fast path for `^\p{X}+$` / `^\P{X}+$` style // anchored-greedy unicode-property patterns. test262's property- @@ -238,13 +241,17 @@ public function matchTest(string $inputUtf8, int $startCodeUnit): bool if ($startCodeUnit === 0 && $this->unicode && !$this->multiline) { $shape = $this->detectAnchoredPropertyShape(); if ($shape !== null) { - return self::sweepAnchoredProperty( + $matched = self::sweepAnchoredProperty( $inputUtf8, $shape['table'], $shape['propertyNegated'], $shape['min'], $shape['max'], ); + if ($matched && $onMatch !== null) { + $onMatch($inputUtf8, '', '', []); + } + return $matched; } } $this->input = $this->unicode @@ -287,6 +294,9 @@ public function matchTest(string $inputUtf8, int $startCodeUnit): bool } } if ($negated ? !$hit : $hit) { + if ($onMatch !== null) { + $this->reportTestMatch($inputUtf8, $pos, $pos + 1, [], $onMatch); + } return true; } } @@ -298,9 +308,31 @@ public function matchTest(string $inputUtf8, int $startCodeUnit): bool $caps = $captures; $end = $this->matchNode($this->pattern->body, $pos, $caps, /*direction=*/+1); if ($end !== null) { + if ($onMatch !== null) { + $this->reportTestMatch($inputUtf8, $pos, $end, $caps, $onMatch); + } return true; } } return false; } + + /** + * @param array $captures + * @param \Closure(string, string, string, list): void $onMatch + */ + private function reportTestMatch(string $input, int $start, int $end, array $captures, \Closure $onMatch): void + { + $groups = []; + for ($index = 1; $index <= $this->pattern->groupCount; $index++) { + $capture = $captures[$index] ?? null; + $groups[] = $capture === null ? '' : $this->sliceCapture($input, $capture[0], $capture[1]); + } + $onMatch( + $start === 0 && $end === $this->inputLen ? $input : $this->sliceCapture($input, $start, $end), + $start === 0 ? '' : $this->sliceCapture($input, 0, $start), + $end === $this->inputLen ? '' : $this->sliceCapture($input, $end, $this->inputLen), + $groups, + ); + } } diff --git a/tests/Unit/Runtime/RegExpPredicateTest.php b/tests/Unit/Runtime/RegExpPredicateTest.php new file mode 100644 index 00000000..4666ac91 --- /dev/null +++ b/tests/Unit/Runtime/RegExpPredicateTest.php @@ -0,0 +1,34 @@ +checkOracle(false); + } + + public function testBudgetedPredicatesMatchTheSameNodeOracle(): void + { + $this->checkOracle(true); + } + + private function checkOracle(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/regexp-predicate.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/regexp-predicate.json', + $engine->eval('JSON.stringify(regexpPredicateResult)'), + ); + } +} diff --git a/tests/Unit/Runtime/RegExpReplaceTest.php b/tests/Unit/Runtime/RegExpReplaceTest.php new file mode 100644 index 00000000..823a576a --- /dev/null +++ b/tests/Unit/Runtime/RegExpReplaceTest.php @@ -0,0 +1,46 @@ +checkOracle(false); + } + + public function testBudgetedReplacementMatchesTheSameOracle(): void + { + $this->checkOracle(true); + } + + public function testFlagGettersRunInTheSpecificationOrder(): void + { + self::assertSame([ + 'hasIndices', 'global', 'ignoreCase', 'multiline', 'dotAll', 'unicode', 'unicodeSets', 'sticky', + ], (new Engine())->eval(<<<'JS' +const seen = []; +const target = new Proxy({}, {get(target, name) { seen.push(name); return false; }}); +Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags').get.call(target); +seen; +JS)); + } + + private function checkOracle(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/regexp-replace.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/regexp-replace.json', + $engine->eval('JSON.stringify(regexpReplaceResult)'), + ); + } +} diff --git a/tests/Unit/Runtime/fixtures/regexp-predicate.js b/tests/Unit/Runtime/fixtures/regexp-predicate.js new file mode 100644 index 00000000..384735d8 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/regexp-predicate.js @@ -0,0 +1,103 @@ +const regexpPredicateResult = []; +const regexpPredicateTrace = []; +function recordPredicate(regexp, input) { + const value = regexp.test(input); + recordPredicateState(regexp, value); +} +function recordPredicateState(regexp, value) { + regexpPredicateResult.push([value, regexp.lastIndex, + RegExp.input, RegExp.lastMatch, RegExp.leftContext, RegExp.rightContext, + RegExp.lastParen, RegExp.$1, RegExp.$2]); +} +for (const regexp of [/a/, /(a)(b)/, /(?a)(b)/, /a(?=b)/, /a(?!c)/, + /(?:ab|cd)/, /[a-z]+/i, /α/u, /a/d, /a/g, /a/y]) { + for (const input of ['zabz', 'abc', 'z', 'αa', '😀a', '']) { + /(seed)(value)/.exec('seedvalue'); + regexp.lastIndex = 0; + recordPredicate(regexp, input); + } +} +for (const [regexp, input] of [[/./, 'a😀b'], [/./u, 'a😀b'], [/./g, '😀'], + [/(a(b)?)+/, 'zabaaz'], [/(?<=(a))b/, 'zabz'], [/(?:(a)|b)+/, 'zabz'], + [/[\ud800-\udfff]/u, 'a\ud800b'], [/^\p{Any}+$/u, '\ud800a'], + [/(a)()/, 'a'], [/(a)|(b)/, 'a'], [/(a)(b)?/, 'a']]) { + /(seed)(value)/.exec('seedvalue'); + recordPredicateState(regexp, regexp.exec(input) !== null); + regexp.lastIndex = 0; + recordPredicate(regexp, input); + regexp.lastIndex = 0; + recordPredicate(regexp, 'zzz'); +} +for (const index of [-0, NaN, Infinity, -4, 3]) { + const regexp = /a/; + regexp.lastIndex = index; + regexpPredicateResult.push([regexp.test('aba'), Object.is(regexp.lastIndex, index), + Object.is(regexp.lastIndex, -0)]); +} + +const recompiledDuringIndex = /a/; +recompiledDuringIndex.lastIndex = { + valueOf() { + regexpPredicateTrace.push('lastIndex coercion'); + recompiledDuringIndex.compile('b', ''); + return 17; + } +}; +recordPredicate(recompiledDuringIndex, 'b'); + +const inputChangesMatcher = /a/; +recordPredicate(inputChangesMatcher, { + toString() { + regexpPredicateTrace.push('input coercion'); + inputChangesMatcher.compile('b', ''); + return 'b'; + } +}); + +const builtinExec = RegExp.prototype.exec; +const getterExec = /a/; +Object.defineProperty(getterExec, 'exec', { + get() { regexpPredicateTrace.push('exec getter'); return builtinExec; } +}); +recordPredicate(getterExec, 'ba'); + +const customExec = /a/; +customExec.exec = function (input) { + regexpPredicateTrace.push(['custom exec', input, this === customExec]); + return {0: 'different', index: 0, length: 1}; +}; +recordPredicate(customExec, 'ba'); + +const proxyChain = /a/; +Object.setPrototypeOf(proxyChain, new Proxy(RegExp.prototype, { + get(target, key, receiver) { + regexpPredicateTrace.push('get ' + String(key)); + return Reflect.get(target, key, receiver); + }, + getOwnPropertyDescriptor(target, key) { + regexpPredicateTrace.push('descriptor ' + String(key)); + return Reflect.getOwnPropertyDescriptor(target, key); + }, + getPrototypeOf(target) { + regexpPredicateTrace.push('prototype'); + return Reflect.getPrototypeOf(target); + } +})); +recordPredicate(proxyChain, 'ba'); +regexpPredicateResult.push(regexpPredicateTrace); + +function encodePredicateSurrogates(value) { + if (Array.isArray(value)) return value.map(encodePredicateSurrogates); + if (typeof value !== 'string') return value; + const units = []; + let containsSurrogate = false; + for (let index = 0; index < value.length; index++) { + const unit = value.charCodeAt(index); + units.push(unit); + if (unit >= 0xd800 && unit <= 0xdfff) containsSurrogate = true; + } + return containsSurrogate ? {utf16: units} : value; +} +for (let index = 0; index < regexpPredicateResult.length; index++) { + regexpPredicateResult[index] = encodePredicateSurrogates(regexpPredicateResult[index]); +} diff --git a/tests/Unit/Runtime/fixtures/regexp-predicate.json b/tests/Unit/Runtime/fixtures/regexp-predicate.json new file mode 100644 index 00000000..23c118d1 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/regexp-predicate.json @@ -0,0 +1,1366 @@ +[ + [ + true, + 0, + "zabz", + "a", + "z", + "bz", + "", + "", + "" + ], + [ + true, + 0, + "abc", + "a", + "", + "bc", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "\u03b1a", + "a", + "\u03b1", + "", + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 55357, + 56832, + 97 + ] + }, + "a", + { + "utf16": [ + 55357, + 56832 + ] + }, + "", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "zabz", + "ab", + "z", + "z", + "b", + "a", + "b" + ], + [ + true, + 0, + "abc", + "ab", + "", + "c", + "b", + "a", + "b" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "zabz", + "ab", + "z", + "z", + "b", + "a", + "b" + ], + [ + true, + 0, + "abc", + "ab", + "", + "c", + "b", + "a", + "b" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "zabz", + "a", + "z", + "bz", + "", + "", + "" + ], + [ + true, + 0, + "abc", + "a", + "", + "bc", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "zabz", + "a", + "z", + "bz", + "", + "", + "" + ], + [ + true, + 0, + "abc", + "a", + "", + "bc", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "\u03b1a", + "a", + "\u03b1", + "", + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 55357, + 56832, + 97 + ] + }, + "a", + { + "utf16": [ + 55357, + 56832 + ] + }, + "", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "zabz", + "ab", + "z", + "z", + "", + "", + "" + ], + [ + true, + 0, + "abc", + "ab", + "", + "c", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "zabz", + "zabz", + "", + "", + "", + "", + "" + ], + [ + true, + 0, + "abc", + "abc", + "", + "", + "", + "", + "" + ], + [ + true, + 0, + "z", + "z", + "", + "", + "", + "", + "" + ], + [ + true, + 0, + "\u03b1a", + "a", + "\u03b1", + "", + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 55357, + 56832, + 97 + ] + }, + "a", + { + "utf16": [ + 55357, + 56832 + ] + }, + "", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "\u03b1a", + "\u03b1", + "", + "a", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "zabz", + "a", + "z", + "bz", + "", + "", + "" + ], + [ + true, + 0, + "abc", + "a", + "", + "bc", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + "\u03b1a", + "a", + "\u03b1", + "", + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 55357, + 56832, + 97 + ] + }, + "a", + { + "utf16": [ + 55357, + 56832 + ] + }, + "", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 2, + "zabz", + "a", + "z", + "bz", + "", + "", + "" + ], + [ + true, + 1, + "abc", + "a", + "", + "bc", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 2, + "\u03b1a", + "a", + "\u03b1", + "", + "", + "", + "" + ], + [ + true, + 3, + { + "utf16": [ + 55357, + 56832, + 97 + ] + }, + "a", + { + "utf16": [ + 55357, + 56832 + ] + }, + "", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 1, + "abc", + "a", + "", + "bc", + "", + "", + "" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + false, + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + true, + 0, + { + "utf16": [ + 97, + 55357, + 56832, + 98 + ] + }, + "a", + "", + { + "utf16": [ + 55357, + 56832, + 98 + ] + }, + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 97, + 55357, + 56832, + 98 + ] + }, + "a", + "", + { + "utf16": [ + 55357, + 56832, + 98 + ] + }, + "", + "", + "" + ], + [ + true, + 0, + "zzz", + "z", + "", + "zz", + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 97, + 55357, + 56832, + 98 + ] + }, + "a", + "", + { + "utf16": [ + 55357, + 56832, + 98 + ] + }, + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 97, + 55357, + 56832, + 98 + ] + }, + "a", + "", + { + "utf16": [ + 55357, + 56832, + 98 + ] + }, + "", + "", + "" + ], + [ + true, + 0, + "zzz", + "z", + "", + "zz", + "", + "", + "" + ], + [ + true, + 1, + { + "utf16": [ + 55357, + 56832 + ] + }, + { + "utf16": [ + 55357 + ] + }, + "", + { + "utf16": [ + 56832 + ] + }, + "", + "", + "" + ], + [ + true, + 1, + { + "utf16": [ + 55357, + 56832 + ] + }, + { + "utf16": [ + 55357 + ] + }, + "", + { + "utf16": [ + 56832 + ] + }, + "", + "", + "" + ], + [ + true, + 1, + "zzz", + "z", + "", + "zz", + "", + "", + "" + ], + [ + true, + 0, + "zabaaz", + "abaa", + "z", + "z", + "", + "a", + "" + ], + [ + true, + 0, + "zabaaz", + "abaa", + "z", + "z", + "", + "a", + "" + ], + [ + false, + 0, + "zabaaz", + "abaa", + "z", + "z", + "", + "a", + "" + ], + [ + true, + 0, + "zabz", + "b", + "za", + "z", + "a", + "a", + "" + ], + [ + true, + 0, + "zabz", + "b", + "za", + "z", + "a", + "a", + "" + ], + [ + false, + 0, + "zabz", + "b", + "za", + "z", + "a", + "a", + "" + ], + [ + true, + 0, + "zabz", + "ab", + "z", + "z", + "", + "", + "" + ], + [ + true, + 0, + "zabz", + "ab", + "z", + "z", + "", + "", + "" + ], + [ + false, + 0, + "zabz", + "ab", + "z", + "z", + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 97, + 55296, + 98 + ] + }, + { + "utf16": [ + 55296 + ] + }, + "a", + "b", + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 97, + 55296, + 98 + ] + }, + { + "utf16": [ + 55296 + ] + }, + "a", + "b", + "", + "", + "" + ], + [ + false, + 0, + { + "utf16": [ + 97, + 55296, + 98 + ] + }, + { + "utf16": [ + 55296 + ] + }, + "a", + "b", + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 55296, + 97 + ] + }, + { + "utf16": [ + 55296, + 97 + ] + }, + "", + "", + "", + "", + "" + ], + [ + true, + 0, + { + "utf16": [ + 55296, + 97 + ] + }, + { + "utf16": [ + 55296, + 97 + ] + }, + "", + "", + "", + "", + "" + ], + [ + true, + 0, + "zzz", + "zzz", + "", + "", + "", + "", + "" + ], + [ + true, + 0, + "a", + "a", + "", + "", + "", + "a", + "" + ], + [ + true, + 0, + "a", + "a", + "", + "", + "", + "a", + "" + ], + [ + false, + 0, + "a", + "a", + "", + "", + "", + "a", + "" + ], + [ + true, + 0, + "a", + "a", + "", + "", + "", + "a", + "" + ], + [ + true, + 0, + "a", + "a", + "", + "", + "", + "a", + "" + ], + [ + false, + 0, + "a", + "a", + "", + "", + "", + "a", + "" + ], + [ + true, + 0, + "a", + "a", + "", + "", + "", + "a", + "" + ], + [ + true, + 0, + "a", + "a", + "", + "", + "", + "a", + "" + ], + [ + false, + 0, + "a", + "a", + "", + "", + "", + "a", + "" + ], + [ + true, + true, + true + ], + [ + true, + true, + false + ], + [ + true, + true, + false + ], + [ + true, + true, + false + ], + [ + true, + true, + false + ], + [ + true, + 0, + "b", + "b", + "", + "", + "", + "", + "" + ], + [ + true, + 0, + "b", + "b", + "", + "", + "", + "", + "" + ], + [ + true, + 0, + "ba", + "a", + "b", + "", + "", + "", + "" + ], + [ + true, + 0, + "ba", + "a", + "b", + "", + "", + "", + "" + ], + [ + true, + 0, + "ba", + "a", + "b", + "", + "", + "", + "" + ], + [ + "lastIndex coercion", + "input coercion", + "exec getter", + [ + "custom exec", + "ba", + true + ], + "get test", + "get exec" + ] +] diff --git a/tests/Unit/Runtime/fixtures/regexp-replace.js b/tests/Unit/Runtime/fixtures/regexp-replace.js new file mode 100644 index 00000000..6f5baf5b --- /dev/null +++ b/tests/Unit/Runtime/fixtures/regexp-replace.js @@ -0,0 +1,126 @@ +const regexpReplaceResult = []; +function recordReplace(regexp, input, replacement) { + const result = regexp[Symbol.replace](input, replacement); + regexpReplaceResult.push([result, regexp.lastIndex, + RegExp.input, RegExp.lastMatch, RegExp.leftContext, RegExp.rightContext, + RegExp.lastParen, RegExp.$1, RegExp.$2]); +} + +for (const regexp of [/[-.+?()[\]{}|\\]/g, /a/, /a/g, /a/gi, /a/dg, /a/gu, + /(?:ab|cd)+/g, /a(?=b)/g, /a(?!c)/g, /z/g, /^a/mg]) { + for (const replacement of ['X', '\\$&', '$$|$&|$`|$\'|$1|$01|$', '']) { + /(seed)(value)/.exec('seedvalue'); + regexp.lastIndex = 4; + recordReplace(regexp, 'a.ab-cd+a\na[b]\\', replacement); + } +} + +for (const [regexp, input] of [[/a*/g, 'abc'], [/(?:)/g, 'ab'], [/(a)?b/g, 'bab'], + [/(?a)/g, 'aab'], [/(?:a?)*b/g, 'aab'], [/./gu, 'a😀b'], + [/./g, '\ud800a'], [/a/y, 'ba'], [/a/gy, 'aa-ba']]) { + recordReplace(regexp, input, '[$&][$1][$]'); +} + +for (const index of [-0, NaN, Infinity, -4, 3]) { + for (const regexp of [/a/, /a/g]) { + regexp.lastIndex = index; + const result = 'aba'.replace(regexp, 'x'); + regexpReplaceResult.push([result, Object.is(regexp.lastIndex, index), Object.is(regexp.lastIndex, -0)]); + } +} + +const regexpReplaceTrace = []; +const getterExec = /a/g; +const intrinsicExec = RegExp.prototype.exec; +Object.defineProperty(getterExec, 'exec', { + get() { regexpReplaceTrace.push('exec getter'); return intrinsicExec; } +}); +recordReplace(getterExec, 'aba', '$&$&'); + +const customExec = /a/g; +let customCalls = 0; +customExec.exec = function (input) { + regexpReplaceTrace.push(['exec call', input, this === customExec]); + return customCalls++ === 0 ? {0: 'ab', 1: 'capture', length: 2, index: 1} : null; +}; +recordReplace(customExec, 'zabz', '$1:$&'); + +const prototypeProxy = new Proxy(RegExp.prototype, { + get(target, key, receiver) { + regexpReplaceTrace.push('get ' + String(key)); + return Reflect.get(target, key, receiver); + }, + getOwnPropertyDescriptor(target, key) { + regexpReplaceTrace.push('descriptor ' + String(key)); + return Reflect.getOwnPropertyDescriptor(target, key); + }, + getPrototypeOf(target) { + regexpReplaceTrace.push('prototype'); + return Reflect.getPrototypeOf(target); + } +}); +const proxyChain = /a/g; +// Node 26.12 reads sticky before unicodeSets, unlike ECMA-262's getter order. +// Keep this oracle focused on exec traps; flag getter order is tested separately. +Object.defineProperty(proxyChain, 'flags', {value: 'g'}); +Object.setPrototypeOf(proxyChain, prototypeProxy); +const proxyResult = RegExp.prototype[Symbol.replace].call(proxyChain, 'aba', '$&$&'); +regexpReplaceResult.push([proxyResult, proxyChain.lastIndex]); + +const indexObject = /a/; +indexObject.lastIndex = {valueOf() { regexpReplaceTrace.push('lastIndex'); return 17; }}; +recordReplace(indexObject, 'aba', 'x'); + +for (const regexp of [/a/, /a/g]) { + Object.defineProperty(regexp, 'lastIndex', {writable: false}); + try { recordReplace(regexp, 'aba', 'x'); } + catch (error) { regexpReplaceResult.push(error.name); } +} + +const flagOverride = /a/; +Object.defineProperty(flagOverride, 'flags', { + get() { regexpReplaceTrace.push('flags getter'); return 'g'; } +}); +let overriddenCalls = 0; +flagOverride.exec = function (input) { + regexpReplaceTrace.push('overridden exec'); + return overriddenCalls++ === 0 ? {0: 'a', length: 1, index: 0} : null; +}; +recordReplace(flagOverride, 'aba', 'x'); + +const recompiled = /a/g; +recordReplace(recompiled, { + toString() { regexpReplaceTrace.push('input conversion'); return 'aba'; } +}, { + toString() { + regexpReplaceTrace.push('replacement conversion'); + recompiled.compile('b', 'g'); + return '$&$&'; + } +}); + +const functional = /a/g; +const functionalOutput = 'aba'.replace(functional, function (match, index, input) { + regexpReplaceTrace.push(['replacement callback', match, index, input, functional.lastIndex, RegExp.lastMatch]); + /z/.exec('z'); + functional.exec = function () { throw new Error('results must already be collected'); }; + return index; +}); +regexpReplaceResult.push(functionalOutput); +regexpReplaceResult.push(regexpReplaceTrace); + +function encodeReplaceSurrogates(value) { + if (Array.isArray(value)) return value.map(encodeReplaceSurrogates); + if (typeof value !== 'string') return value; + const units = []; + let containsSurrogate = false; + for (let index = 0; index < value.length; index++) { + const unit = value.charCodeAt(index); + units.push(unit); + if (unit >= 0xd800 && unit <= 0xdfff) containsSurrogate = true; + } + return containsSurrogate ? {utf16: units} : value; +} +for (let index = 0; index < regexpReplaceResult.length; index++) { + regexpReplaceResult[index] = encodeReplaceSurrogates(regexpReplaceResult[index]); +} diff --git a/tests/Unit/Runtime/fixtures/regexp-replace.json b/tests/Unit/Runtime/fixtures/regexp-replace.json new file mode 100644 index 00000000..cecb4d11 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/regexp-replace.json @@ -0,0 +1,865 @@ +[ + [ + "aXabXcdXa\naXbXX", + 0, + "a.ab-cd+a\na[b]\\", + "\\", + "a.ab-cd+a\na[b]", + "", + "", + "", + "" + ], + [ + "a\\.ab\\-cd\\+a\na\\[b\\]\\\\", + 0, + "a.ab-cd+a\na[b]\\", + "\\", + "a.ab-cd+a\na[b]", + "", + "", + "", + "" + ], + [ + "a$|.|a|ab-cd+a\na[b]\\|$1|$01|$ab$|-|a.ab|cd+a\na[b]\\|$1|$01|$cd$|+|a.ab-cd|a\na[b]\\|$1|$01|$a\na$|[|a.ab-cd+a\na|b]\\|$1|$01|$b$|]|a.ab-cd+a\na[b|\\|$1|$01|$$|\\|a.ab-cd+a\na[b]||$1|$01|$", + 0, + "a.ab-cd+a\na[b]\\", + "\\", + "a.ab-cd+a\na[b]", + "", + "", + "", + "" + ], + [ + "aabcda\nab", + 0, + "a.ab-cd+a\na[b]\\", + "\\", + "a.ab-cd+a\na[b]", + "", + "", + "", + "" + ], + [ + "X.ab-cd+a\na[b]\\", + 4, + "a.ab-cd+a\na[b]\\", + "a", + "", + ".ab-cd+a\na[b]\\", + "", + "", + "" + ], + [ + "\\a.ab-cd+a\na[b]\\", + 4, + "a.ab-cd+a\na[b]\\", + "a", + "", + ".ab-cd+a\na[b]\\", + "", + "", + "" + ], + [ + "$|a||.ab-cd+a\na[b]\\|$1|$01|$.ab-cd+a\na[b]\\", + 4, + "a.ab-cd+a\na[b]\\", + "a", + "", + ".ab-cd+a\na[b]\\", + "", + "", + "" + ], + [ + ".ab-cd+a\na[b]\\", + 4, + "a.ab-cd+a\na[b]\\", + "a", + "", + ".ab-cd+a\na[b]\\", + "", + "", + "" + ], + [ + "X.Xb-cd+X\nX[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "\\a.\\ab-cd+\\a\n\\a[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "$|a||.ab-cd+a\na[b]\\|$1|$01|$.$|a|a.|b-cd+a\na[b]\\|$1|$01|$b-cd+$|a|a.ab-cd+|\na[b]\\|$1|$01|$\n$|a|a.ab-cd+a\n|[b]\\|$1|$01|$[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + ".b-cd+\n[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "X.Xb-cd+X\nX[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "\\a.\\ab-cd+\\a\n\\a[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "$|a||.ab-cd+a\na[b]\\|$1|$01|$.$|a|a.|b-cd+a\na[b]\\|$1|$01|$b-cd+$|a|a.ab-cd+|\na[b]\\|$1|$01|$\n$|a|a.ab-cd+a\n|[b]\\|$1|$01|$[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + ".b-cd+\n[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "X.Xb-cd+X\nX[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "\\a.\\ab-cd+\\a\n\\a[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "$|a||.ab-cd+a\na[b]\\|$1|$01|$.$|a|a.|b-cd+a\na[b]\\|$1|$01|$b-cd+$|a|a.ab-cd+|\na[b]\\|$1|$01|$\n$|a|a.ab-cd+a\n|[b]\\|$1|$01|$[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + ".b-cd+\n[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "X.Xb-cd+X\nX[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "\\a.\\ab-cd+\\a\n\\a[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "$|a||.ab-cd+a\na[b]\\|$1|$01|$.$|a|a.|b-cd+a\na[b]\\|$1|$01|$b-cd+$|a|a.ab-cd+|\na[b]\\|$1|$01|$\n$|a|a.ab-cd+a\n|[b]\\|$1|$01|$[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + ".b-cd+\n[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "a.X-X+a\na[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "cd", + "a.ab-", + "+a\na[b]\\", + "", + "", + "" + ], + [ + "a.\\ab-\\cd+a\na[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "cd", + "a.ab-", + "+a\na[b]\\", + "", + "", + "" + ], + [ + "a.$|ab|a.|-cd+a\na[b]\\|$1|$01|$-$|cd|a.ab-|+a\na[b]\\|$1|$01|$+a\na[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "cd", + "a.ab-", + "+a\na[b]\\", + "", + "", + "" + ], + [ + "a.-+a\na[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "cd", + "a.ab-", + "+a\na[b]\\", + "", + "", + "" + ], + [ + "a.Xb-cd+a\na[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.", + "b-cd+a\na[b]\\", + "", + "", + "" + ], + [ + "a.\\ab-cd+a\na[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.", + "b-cd+a\na[b]\\", + "", + "", + "" + ], + [ + "a.$|a|a.|b-cd+a\na[b]\\|$1|$01|$b-cd+a\na[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.", + "b-cd+a\na[b]\\", + "", + "", + "" + ], + [ + "a.b-cd+a\na[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.", + "b-cd+a\na[b]\\", + "", + "", + "" + ], + [ + "X.Xb-cd+X\nX[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "\\a.\\ab-cd+\\a\n\\a[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "$|a||.ab-cd+a\na[b]\\|$1|$01|$.$|a|a.|b-cd+a\na[b]\\|$1|$01|$b-cd+$|a|a.ab-cd+|\na[b]\\|$1|$01|$\n$|a|a.ab-cd+a\n|[b]\\|$1|$01|$[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + ".b-cd+\n[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "a.ab-cd+a\na[b]\\", + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + "a.ab-cd+a\na[b]\\", + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + "a.ab-cd+a\na[b]\\", + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + "a.ab-cd+a\na[b]\\", + 0, + "seedvalue", + "seedvalue", + "", + "", + "value", + "seed", + "value" + ], + [ + "X.ab-cd+a\nX[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "\\a.ab-cd+a\n\\a[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "$|a||.ab-cd+a\na[b]\\|$1|$01|$.ab-cd+a\n$|a|a.ab-cd+a\n|[b]\\|$1|$01|$[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + ".ab-cd+a\n[b]\\", + 0, + "a.ab-cd+a\na[b]\\", + "a", + "a.ab-cd+a\n", + "[b]\\", + "", + "", + "" + ], + [ + "[a][$1][$][][$1][$]b[][$1][$]c[][$1][$]", + 0, + "abc", + "", + "abc", + "", + "", + "", + "" + ], + [ + "[][$1][$]a[][$1][$]b[][$1][$]", + 0, + "ab", + "", + "ab", + "", + "", + "", + "" + ], + [ + "[b][][$][ab][a][$]", + 0, + "bab", + "ab", + "b", + "", + "a", + "a", + "" + ], + [ + "[a][a][a][a][a][a]b", + 0, + "aab", + "a", + "a", + "b", + "a", + "a", + "" + ], + [ + "[aab][$1][$]", + 0, + "aab", + "aab", + "", + "", + "", + "", + "" + ], + [ + { + "utf16": [ + 91, + 97, + 93, + 91, + 36, + 49, + 93, + 91, + 36, + 60, + 110, + 97, + 109, + 101, + 62, + 93, + 91, + 55357, + 56832, + 93, + 91, + 36, + 49, + 93, + 91, + 36, + 60, + 110, + 97, + 109, + 101, + 62, + 93, + 91, + 98, + 93, + 91, + 36, + 49, + 93, + 91, + 36, + 60, + 110, + 97, + 109, + 101, + 62, + 93 + ] + }, + 0, + { + "utf16": [ + 97, + 55357, + 56832, + 98 + ] + }, + "b", + { + "utf16": [ + 97, + 55357, + 56832 + ] + }, + "", + "", + "", + "" + ], + [ + { + "utf16": [ + 91, + 55296, + 93, + 91, + 36, + 49, + 93, + 91, + 36, + 60, + 110, + 97, + 109, + 101, + 62, + 93, + 91, + 97, + 93, + 91, + 36, + 49, + 93, + 91, + 36, + 60, + 110, + 97, + 109, + 101, + 62, + 93 + ] + }, + 0, + { + "utf16": [ + 55296, + 97 + ] + }, + "a", + { + "utf16": [ + 55296 + ] + }, + "", + "", + "", + "" + ], + [ + "ba", + 0, + { + "utf16": [ + 55296, + 97 + ] + }, + "a", + { + "utf16": [ + 55296 + ] + }, + "", + "", + "", + "" + ], + [ + "[a][$1][$][a][$1][$]-ba", + 0, + "aa-ba", + "a", + "a", + "-ba", + "", + "", + "" + ], + [ + "xba", + true, + true + ], + [ + "xbx", + false, + false + ], + [ + "xba", + true, + false + ], + [ + "xbx", + false, + false + ], + [ + "xba", + true, + false + ], + [ + "xbx", + false, + false + ], + [ + "xba", + true, + false + ], + [ + "xbx", + false, + false + ], + [ + "xba", + true, + false + ], + [ + "xbx", + false, + false + ], + [ + "aabaa", + 0, + "aba", + "a", + "ab", + "", + "", + "", + "" + ], + [ + "zcapture:abz", + 0, + "aba", + "a", + "ab", + "", + "", + "", + "" + ], + [ + "aabaa", + 0 + ], + [ + "xba", + {}, + "aba", + "a", + "", + "ba", + "", + "", + "" + ], + [ + "xba", + 0, + "aba", + "a", + "", + "ba", + "", + "", + "" + ], + "TypeError", + [ + "xba", + 0, + "aba", + "a", + "", + "ba", + "", + "", + "" + ], + [ + "abba", + 0, + "aba", + "b", + "a", + "a", + "", + "", + "" + ], + "0b2", + [ + "exec getter", + "exec getter", + "exec getter", + [ + "exec call", + "zabz", + true + ], + [ + "exec call", + "zabz", + true + ], + "get exec", + "get exec", + "get exec", + "lastIndex", + "flags getter", + "overridden exec", + "overridden exec", + "input conversion", + "replacement conversion", + [ + "replacement callback", + "a", + 0, + "aba", + 0, + "a" + ], + [ + "replacement callback", + "a", + 2, + "aba", + 0, + "z" + ] + ] +] From 0b0ee1e3372f22cb336b408cd40bb00793c35e4d Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 00:49:01 +0200 Subject: [PATCH 44/99] Compile ordinary for-of loops with shared iterator semantics --- src/Bytecode/Compiler.php | 2 + src/Bytecode/Op.php | 6 + src/Bytecode/Parts/CompilerForOf.php | 283 +++ src/Bytecode/Parts/CompilerScope.php | 16 + src/Bytecode/Parts/CompilerStatement.php | 6 +- src/Bytecode/VM.php | 32 + .../Parts/Helpers/IteratorProtocol.php | 21 + tests/Unit/Bytecode/ForOfTest.php | 90 + tests/Unit/Bytecode/fixtures/for-of.js | 223 +++ tests/Unit/Bytecode/fixtures/for-of.json | 1632 +++++++++++++++++ 10 files changed, 2310 insertions(+), 1 deletion(-) create mode 100644 src/Bytecode/Parts/CompilerForOf.php create mode 100644 tests/Unit/Bytecode/ForOfTest.php create mode 100644 tests/Unit/Bytecode/fixtures/for-of.js create mode 100644 tests/Unit/Bytecode/fixtures/for-of.json diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index 94b6de9c..7e654c78 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -61,6 +61,7 @@ final class Compiler { use Parts\CompilerBailoutAnalysis; + use Parts\CompilerForOf; use Parts\CompilerBlockBindings; use Parts\CompilerScope; use Parts\CompilerEmit; @@ -386,6 +387,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction // Pre-walk: collect every var/let/const/function name in // the body so each is assigned a unique frame slot up front. + $this->forOfBody = $body; $this->collectReusableBlockBindings($body); $this->collectFunctionLocals($body->body); if ($this->needsArguments && isset($this->localSlots['arguments'])) { diff --git a/src/Bytecode/Op.php b/src/Bytecode/Op.php index 7747f9dd..f1084266 100644 --- a/src/Bytecode/Op.php +++ b/src/Bytecode/Op.php @@ -188,6 +188,9 @@ final class Op public const LOOP_INIT = 120; public const LOOP_TICK = 121; + public const ITERATOR_INIT = 122; // L: acquire an iterator and cached next in adjacent private slots. + public const ITERATOR_NEXT = 123; // L I J: check loop limits, push the next value or branch when done. + public const ITERATOR_CLOSE = 124; // L L L: close with the pending completion and value. // ---- Sentinel / bailout placeholder ------------------------------- public const NOP = 0; @@ -280,6 +283,7 @@ public static function operandCount(int $op): int case self::MAKE_CLASS: case self::LOOP_INIT: case self::LOOP_TICK: + case self::ITERATOR_INIT: return 1; // 2-operand opcodes case self::NEW_REGEXP: @@ -287,6 +291,8 @@ public static function operandCount(int $op): int return 2; // 3-operand opcodes case self::UPDATE_NAME: + case self::ITERATOR_NEXT: + case self::ITERATOR_CLOSE: case self::UPDATE_MEMBER: case self::JUMP_IF_LOCAL_GE_CONST: case self::JUMP_IF_LOCAL_GE_LOCAL: diff --git a/src/Bytecode/Parts/CompilerForOf.php b/src/Bytecode/Parts/CompilerForOf.php new file mode 100644 index 00000000..109e9bd8 --- /dev/null +++ b/src/Bytecode/Parts/CompilerForOf.php @@ -0,0 +1,283 @@ +forOfScopesValidated) { + return; + } + $loops = []; + $this->collectForOfNodes($body, $loops); + if ($loops === []) { + return; + } + foreach ($loops as $loop) { + if ( + $this->inGenerator || $loop->await || !$loop->left instanceof VariableDeclaration + || !in_array($loop->left->kind, ['var', 'let', 'const'], true) + || count($loop->left->declarations) !== 1 + || !$loop->left->declarations[0]->id instanceof Identifier + ) { + throw new CompilerBailout('unsupported for-of binding or function kind'); + } + if ($loop->left->kind !== 'var') { + $name = $loop->left->declarations[0]->id->name; + if ( + $this->forOfNameOutsideScope($body, $name, $loop) + || $this->forOfNameOutsideScope($loop->right, $name, null) + ) { + throw new CompilerBailout('for-of lexical binding escapes its iteration scope'); + } + } + } + $this->validateForOfBlockScopes($body, $body); + $this->forOfScopesValidated = true; + } + + /** @param list $loops */ + private function collectForOfNodes(Node $node, array &$loops): void + { + if ($this->forOfNestedScope($node)) { + return; + } + if ($node instanceof ForOfStatement) { + $loops[] = $node; + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node) { + $this->collectForOfNodes($child, $loops); + } + } + } + } + + private function validateForOfBlockScopes(Node $node, BlockStatement $body): void + { + if ($this->forOfNestedScope($node)) { + return; + } + if ($node instanceof CatchClause && $node->param instanceof Identifier) { + $name = $node->param->name; + if ( + $this->forOfNameOutsideScope($body, $name, $node) + || $this->forOfNameHasVarBinding($body, $name) + ) { + // A catch binding is fresh on every entry, including when a + // var declaration of the same name occurs inside its body. + throw new CompilerBailout('for-of catch binding needs a separate environment'); + } + } + $declarations = []; + if ($node instanceof BlockStatement && $node !== $body) { + $declarations = $node->body; + } elseif ($node instanceof ForStatement && $node->init instanceof VariableDeclaration) { + $declarations = [$node->init]; + } + foreach ($declarations as $declaration) { + if ($declaration instanceof ClassDeclaration && $declaration->id !== null) { + if ($this->forOfNameOutsideScope($body, $declaration->id->name, $node)) { + throw new CompilerBailout('for-of class binding escapes its block'); + } + continue; + } + if (!$declaration instanceof VariableDeclaration || $declaration->kind === 'var') { + continue; + } + foreach ($declaration->declarations as $binding) { + $names = []; + $this->collectPatternBoundNames($binding->id, $names); + foreach ($names as $name => $_) { + if ($this->forOfNameOutsideScope($body, $name, $node)) { + throw new CompilerBailout('for-of function has an escaping block binding'); + } + } + } + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node) { + $this->validateForOfBlockScopes($child, $body); + } + } + } + } + + private function forOfNameHasVarBinding(Node $node, string $name): bool + { + if ($this->forOfNestedScope($node)) { + return false; + } + if ($node instanceof VariableDeclaration && $node->kind === 'var') { + foreach ($node->declarations as $declaration) { + $names = []; + $this->collectPatternBoundNames($declaration->id, $names); + if (isset($names[$name])) { + return true; + } + } + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node && $this->forOfNameHasVarBinding($child, $name)) { + return true; + } + } + } + return false; + } + + private function forOfNameOutsideScope(Node $node, string $name, ?Node $scope): bool + { + if ($node === $scope) { + return false; + } + if ($node instanceof Identifier) { + return $node->name === $name; + } + if ($node instanceof MemberExpression && !$node->computed) { + return $this->forOfNameOutsideScope($node->object, $name, $scope); + } + if ($node instanceof Property && !$node->computed) { + return $this->forOfNameOutsideScope($node->value, $name, $scope); + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node && $this->forOfNameOutsideScope($child, $name, $scope)) { + return true; + } + } + } + return false; + } + + private function forOfNestedScope(Node $node): bool + { + return $node instanceof FunctionDeclaration || $node instanceof FunctionExpression + || $node instanceof ArrowFunction || $node instanceof ClassDeclaration || $node instanceof ClassExpression; + } + + private function compileForOf(ForOfStatement $node): void + { + // Program bindings and generators use different lifetime machinery. + if ( + !$this->forOfScopesValidated || $this->inGenerator || $node->await || !$node->left instanceof VariableDeclaration + || count($node->left->declarations) !== 1 || !$node->left->declarations[0]->id instanceof Identifier + ) { + throw new CompilerBailout('unsupported for-of statement'); + } + $name = $node->left->declarations[0]->id->name; + if (!isset($this->localSlots[$name]) || !in_array($node->left->kind, ['var', 'let', 'const'], true)) { + throw new CompilerBailout('for-of requires an ordinary local binding'); + } + $iteratorSlot = count($this->localNames); + $this->localNames[] = '[[iterator]]'; + $this->localNames[] = '[[iteratorNext]]'; + $valueSlot = count($this->localNames); + $this->localNames[] = '[[iteratorCompletionValue]]'; + $completionSlot = count($this->localNames); + $this->localNames[] = '[[iteratorCompletion]]'; + + $this->compileExpression($node->right); + $this->emit(Op::ITERATOR_INIT, $iteratorSlot); + $loopId = $this->loopCount++; + $this->emit(Op::LOOP_INIT, $loopId); + $loopStart = count($this->code); + $nextPc = count($this->code); + $this->emit(Op::ITERATOR_NEXT, $iteratorSlot, $loopId, 0); + + // IteratorStepValue failures do not close the iterator. Only binding + // initialization and the body are inside the synthetic close handler. + $bodyStart = count($this->code); + $slot = $this->localSlots[$name]; + $this->emitInitializeLocal($slot, $node->left->kind); + if ($node->left->kind === 'const') { + $this->constSlots[$slot] = true; + } + $tailCallsWereEnabled = $this->tailCallsEnabled; + $this->tailCallsEnabled = false; + $this->finallyContexts[] = [ + 'valueSlot' => $valueSlot, + 'completionSlot' => $completionSlot, + 'jumps' => [], + ]; + $this->finallyLoopBoundaries[] = count($this->loopStack); + $this->loopStack[] = ['continue' => -1, 'breaks' => [], 'continues' => []]; + $this->forOfBodyDepth++; + try { + $this->compileStatement($node->body); + } finally { + $this->forOfBodyDepth--; + } + $bodyEnd = count($this->code); + $this->emit(Op::JUMP, $loopStart - count($this->code)); + $frame = array_pop($this->loopStack); + $breakTarget = count($this->code); + $this->emit(Op::LOAD_UNDEF); + $this->emit(Op::STORE_LOCAL, $completionSlot); + $breakClose = $this->emitJump(Op::JUMP); + $catchPc = count($this->code); + $this->emit(Op::LOAD_FALSE); + $this->emit(Op::STORE_LOCAL, $completionSlot); + $context = array_pop($this->finallyContexts); + foreach ([$breakClose, ...$context['jumps']] as $jump) { + $this->patchJumpToHere($jump); + } + array_pop($this->finallyLoopBoundaries); + $this->tailCallsEnabled = $tailCallsWereEnabled; + $this->emit(Op::ITERATOR_CLOSE, $iteratorSlot, $completionSlot, $valueSlot); + $this->emit(Op::LOAD_LOCAL, $completionSlot); + $afterBreak = $this->emitJump(Op::JUMP_IF_FALSE); + $this->emit(Op::LOAD_LOCAL, $valueSlot); + $this->emitReturnCompletion(); + $this->patchJumpToHere($afterBreak); + $this->code[$nextPc + 3] = count($this->code) - $nextPc; + foreach ($frame['continues'] as $index) { + $this->code[$index] = $loopStart - ($index - 1); + } + foreach ($frame['breaks'] as $index) { + $this->code[$index] = $breakTarget - ($index - 1); + } + $this->handlers[] = new HandlerEntry( + tryStart: $bodyStart, + tryEnd: $bodyEnd, + catchPc: $catchPc, + exceptionSlot: $valueSlot, + stackBase: $this->tryEntryStackDepth, + ); + } +} diff --git a/src/Bytecode/Parts/CompilerScope.php b/src/Bytecode/Parts/CompilerScope.php index c7685935..f2409c56 100644 --- a/src/Bytecode/Parts/CompilerScope.php +++ b/src/Bytecode/Parts/CompilerScope.php @@ -357,6 +357,15 @@ private function collectFunctionLocals(array $statements): void private function collectStatementLocals(Node $stmt): void { + if ($stmt instanceof \Phasis\Ast\Statement\ForOfStatement) { + if ($this->forOfBody === null || !$stmt->left instanceof VariableDeclaration) { + throw new CompilerBailout('for-of assignment target'); + } + $this->validateForOfScopes($this->forOfBody); + $this->collectStatementLocals($stmt->left); + $this->collectStatementLocals($stmt->body); + return; + } if ($stmt instanceof VariableDeclaration) { $isLexical = $stmt->kind === 'let' || $stmt->kind === 'const'; foreach ($stmt->declarations as $decl) { @@ -644,6 +653,13 @@ private function collectInnerDeclaredNames(array $statements, array &$out): void */ private function collectInnerDeclaredNamesNode(Node $node, array &$out): void { + if ($node instanceof \Phasis\Ast\Statement\ForOfStatement) { + if ($node->left instanceof VariableDeclaration) { + $this->collectInnerDeclaredNamesNode($node->left, $out); + } + $this->collectInnerDeclaredNamesNode($node->body, $out); + return; + } if ($node instanceof VariableDeclaration) { foreach ($node->declarations as $decl) { $this->collectPatternBoundNames($decl->id, $out); diff --git a/src/Bytecode/Parts/CompilerStatement.php b/src/Bytecode/Parts/CompilerStatement.php index 1685e856..743e7a69 100644 --- a/src/Bytecode/Parts/CompilerStatement.php +++ b/src/Bytecode/Parts/CompilerStatement.php @@ -99,6 +99,10 @@ private function compileStatement(Node $node): void $this->compileFor($node); return; } + if ($node instanceof \Phasis\Ast\Statement\ForOfStatement) { + $this->compileForOf($node); + return; + } if ($node instanceof WhileStatement) { $this->compileWhile($node); return; @@ -697,7 +701,7 @@ private function compileVarDecl(VariableDeclaration $node): void } if ( $node->kind === 'let' - && (isset($this->capturedLocals[$name]) || isset($this->reusableBlockLocals[$name])) + && ($this->forOfBodyDepth > 0 || isset($this->capturedLocals[$name]) || isset($this->reusableBlockLocals[$name])) ) { $this->emit(Op::LOAD_UNDEF); $this->emitInitializeLocal($slot, $node->kind); diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index acbf3856..34eb3374 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -821,6 +821,38 @@ public function execute( } $pc += 2; break; + case Op::ITERATOR_INIT: + $iteratorSlot = $code[$pc + 1]; + [$locals[$iteratorSlot], $locals[$iteratorSlot + 1]] = $this->interp->vmGetIterator($stack[--$sp]); + $pc += 2; + break; + case Op::ITERATOR_NEXT: + // Match the interpreter's host-budget checkpoint + // before its iteration limit and iterator effects. + if ($this->interp->hasExecutionBudget()) { + $this->interp->checkBudget(); + } + if (++$loopCounts[$code[$pc + 2]] > $this->interp->getMaxLoopIterations()) { + throw new InternalError('Maximum loop iterations exceeded'); + } + $iteratorSlot = $code[$pc + 1]; + $iterator = $locals[$iteratorSlot]; + assert($iterator instanceof JsObject); + $done = false; + $value = $this->interp->vmIteratorNext($iterator, $locals[$iteratorSlot + 1], $done); + if ($done) { + $pc += $code[$pc + 3]; + } else { + $stack[$sp++] = $value; + $pc += 4; + } + break; + case Op::ITERATOR_CLOSE: + $iterator = $locals[$code[$pc + 1]]; + assert($iterator instanceof JsObject); + $this->interp->vmIteratorClose($iterator, $locals[$code[$pc + 2]], $locals[$code[$pc + 3]]); + $pc += 4; + break; case Op::POP: $sp--; $pc++; diff --git a/src/Runtime/Parts/Helpers/IteratorProtocol.php b/src/Runtime/Parts/Helpers/IteratorProtocol.php index eb20893c..c3dd9f29 100644 --- a/src/Runtime/Parts/Helpers/IteratorProtocol.php +++ b/src/Runtime/Parts/Helpers/IteratorProtocol.php @@ -103,6 +103,27 @@ */ trait IteratorProtocol { + /** @return array{JsObject, JsValue} Iterator and cached next method for a compiled for-of loop. */ + public function vmGetIterator(JsValue $value): array + { + return $this->getIteratorOrThrow($value); + } + + /** Advance a compiled for-of loop with the shared IteratorStepValue semantics. */ + public function vmIteratorNext(JsObject $iterator, JsValue $nextMethod, bool &$done): JsValue + { + return $this->iteratorNext($iterator, $nextMethod, $done); + } + + /** Close a compiled loop; a pending throw takes precedence over close failures. */ + public function vmIteratorClose(JsObject $iterator, JsValue $completion, JsValue $value): void + { + $this->iteratorClose( + $iterator, + $completion instanceof JsBoolean && !$completion->value ? new \Phasis\Exceptions\JsThrowable($value) : null, + ); + } + /** * Bind or assign a compiled flat array pattern without reading ahead. * Iterator methods can observe each earlier write through captured closures. diff --git a/tests/Unit/Bytecode/ForOfTest.php b/tests/Unit/Bytecode/ForOfTest.php new file mode 100644 index 00000000..e5ebbbf6 --- /dev/null +++ b/tests/Unit/Bytecode/ForOfTest.php @@ -0,0 +1,90 @@ +checkOracle(false); + $compiledNames = [ + 'collectLoop', 'stopLoop', 'continueLoop', 'returnLoop', + 'throwLoop', 'nestedLoop', 'varCaptureLoop', 'resetLetLoop', + ]; + foreach ($compiledNames as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name); + $opcodes = []; + for ($pc = 0; $pc < count($function->compiled->code); $pc += 1 + Op::operandCount($function->compiled->code[$pc])) { + $opcodes[] = $function->compiled->code[$pc]; + } + self::assertContains(Op::ITERATOR_NEXT, $opcodes, $name); + } + $interpretedNames = [ + 'letCaptureLoop', 'outsideLoop', 'headerTdzLoop', 'shadowLoop', + 'blockOutsideLoop', 'catchCaptureLoop', 'classOutsideLoop', + ]; + foreach ($interpretedNames as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled, $name . ' needs the interpreter scope model.'); + } + } + + public function testBudgetedInterpreterMatchesTheSameNodeOracle(): void + { + $this->checkOracle(true); + } + + public function testBudgetEnabledDuringIterationPrecedesLoopLimitAndTheNextStep(): void + { + $engine = new Engine(); + $expire = false; + $engine->setGlobal('expireBudget', static function () use ($engine, &$expire): void { + if ($expire) { + $engine->setExecutionBudget(-1); + } + }); + self::assertSame(2, $engine->eval(<<<'JS' +function budgetLoop(input) { + let count = 0; + for (const value of input) { + if (count === 0) expireBudget(); + count++; + } + return count; +} +budgetLoop([1, 2]); +JS)); + $function = $engine->getGlobalEnv()->get('budgetLoop'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + $expire = true; + $engine->setLimit('maxLoopIterations', 1); + $this->expectException(BudgetExceeded::class); + $engine->eval('budgetLoop([1, 2])'); + } + + private function checkOracle(bool $budgeted): Engine + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/for-of.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/for-of.json', + $engine->eval('JSON.stringify(forOfResult)'), + ); + return $engine; + } +} diff --git a/tests/Unit/Bytecode/fixtures/for-of.js b/tests/Unit/Bytecode/fixtures/for-of.js new file mode 100644 index 00000000..283d771d --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/for-of.js @@ -0,0 +1,223 @@ +function collectLoop(input, log) { + const values = []; + for (const value of input) { + log.push('body:' + value); + values.push(value); + } + return values; +} +function stopLoop(input, log) { + const values = []; + for (const value of input) { + log.push('body:' + value); + values.push(value); + if (value === 2) break; + } + return values; +} +function continueLoop(input, log) { + const values = []; + for (let value of input) { + if (value === 2) continue; + value += 10; + log.push('body:' + value); + values.push(value); + } + return values; +} +function returnLoop(input, log) { + for (const value of input) { + log.push('body:' + value); + return value; + } + return 'empty'; +} +function throwLoop(input, log) { + for (const value of input) { + log.push('body:' + value); + throw new RangeError('body'); + } +} +function identityThrowLoop(input, marker) { + for (const value of input) { throw marker; } +} +function nestedLoop(outer, inner, log) { + for (const first of outer) { + for (const second of inner) { + log.push('body:' + first + ':' + second); + return first + second; + } + } + return 0; +} +function varCaptureLoop(input) { + const readers = []; + for (var value of input) readers.push(function () { return value; }); + return [readers.map(function (reader) { return reader(); }), value]; +} +function letCaptureLoop(input) { + const readers = []; + for (let value of input) readers.push(function () { return value; }); + return readers.map(function (reader) { return reader(); }); +} +function outsideLoop(input) { + for (const hidden of input) {} + return typeof hidden; +} +function headerTdzLoop() { + for (let item of [item]) {} +} +function shadowLoop(item) { + for (const item of [1, 2]) {} + return item; +} +function blockOutsideLoop(input) { + for (const value of input) { let hidden = value; } + return typeof hidden; +} +function resetLetLoop(input) { + const result = []; + for (const value of input) { + let temporary; + if (value === 1) temporary = 7; + result.push(temporary); + } + return result; +} +function catchCaptureLoop(input) { + const readers = []; + for (const value of input) { + try { throw value; } + catch (error) { + for (var error of [value]) {} + readers.push(function () { return error; }); + } + } + return readers.map(function (reader) { return reader(); }); +} +function classOutsideLoop(input) { + for (const value of input) { class Hidden {} } + return typeof Hidden; +} +function finalizerLoop(input, log) { + try { + for (const value of input) { + try { + return value; + } finally { + log.push('inner finally'); + } + } + } finally { + log.push('outer finally'); + } +} +function catchLoop(input, log) { + try { + for (const value of input) { + try { + if (value === 1) throw new Error('caught inside'); + } catch (inner) { + log.push('inner:' + inner.name); + } + if (value === 2) throw new RangeError('caught outside'); + } + } catch (outer) { + log.push('outer:' + outer.name); + } + return 'finished'; +} +function loopIterable(log, mode, prefix) { + let index = 0; + const iterator = { + get next() { + log.push(prefix + 'get next'); + return function () { + log.push(prefix + 'next:' + index); + if (mode === 'next throws') throw new SyntaxError('next'); + if (mode === 'next primitive') return 1; + return { + get done() { + log.push(prefix + 'done:' + index); + if (mode === 'done throws') throw new SyntaxError('done'); + return index >= 3; + }, + get value() { + log.push(prefix + 'value:' + index); + if (mode === 'value throws') throw new SyntaxError('value'); + return ++index; + }, + }; + }; + }, + get return() { + log.push(prefix + 'get return'); + if (mode === 'return getter throws') throw new TypeError('return getter'); + if (mode === 'return missing') return undefined; + if (mode === 'return null') return null; + if (mode === 'return noncallable') return 1; + return function () { + log.push(prefix + 'return'); + if (mode === 'return throws') throw new TypeError('return'); + if (mode === 'return primitive') return 1; + return {}; + }; + }, + }; + return { + [Symbol.iterator]() { + log.push(prefix + 'iterator'); + return iterator; + }, + }; +} +function observeLoop(action) { + try { return ['return', action()]; } + catch (error) { return ['throw', error.name]; } +} +const forOfResult = []; +for (const operation of [collectLoop, stopLoop, continueLoop, returnLoop, throwLoop, finalizerLoop, catchLoop]) { + for (const mode of ['normal', 'next throws', 'next primitive', 'done throws', 'value throws', + 'return missing', 'return null', 'return noncallable', 'return getter throws', 'return throws', 'return primitive']) { + const log = []; + const input = loopIterable(log, mode, ''); + const result = observeLoop(function () { return operation(input, log); }); + forOfResult.push([operation.name, mode, result, log]); + } +} +for (const mode of ['normal', 'return getter throws', 'return primitive']) { + const log = []; + const result = observeLoop(function () { + return nestedLoop(loopIterable(log, 'normal', 'outer '), loopIterable(log, mode, 'inner '), log); + }); + forOfResult.push(['nested', mode, result, log]); +} +forOfResult.push(varCaptureLoop([1, 2, 3]), letCaptureLoop([1, 2, 3]), outsideLoop([1]), + observeLoop(headerTdzLoop), shadowLoop(9), blockOutsideLoop([1]), resetLetLoop([1, 2]), + catchCaptureLoop([1, 2]), classOutsideLoop([1])); +forOfResult.push(collectLoop('a\u{1F600}\uD800', []).map(function (value) { + return [value.length, value.charCodeAt(0), value.charCodeAt(1)]; +}), collectLoop(new Set([1, 2]), [])); +const originalLoopThrow = {}; +const closeLoopThrow = {}; +const identityIterator = { + [Symbol.iterator]() { return this; }, + next() { return {done: false, value: 1}; }, + return() { throw closeLoopThrow; }, +}; +try { identityThrowLoop(identityIterator, originalLoopThrow); } +catch (error) { forOfResult.push(['original throw identity', error === originalLoopThrow]); } +try { returnLoop(identityIterator, []); } +catch (error) { forOfResult.push(['close throw identity', error === closeLoopThrow]); } +const reentrantLog = []; +const reentrantIterator = { + [Symbol.iterator]() { return this; }, + next() { return {done: false, value: 41}; }, + return() { + reentrantLog.push('outer return'); + const inner = returnLoop(loopIterable(reentrantLog, 'normal', 'inner '), reentrantLog); + reentrantLog.push('inner result:' + inner); + return {}; + }, +}; +forOfResult.push(['reentrant', returnLoop(reentrantIterator, reentrantLog), reentrantLog]); diff --git a/tests/Unit/Bytecode/fixtures/for-of.json b/tests/Unit/Bytecode/fixtures/for-of.json new file mode 100644 index 00000000..62af8477 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/for-of.json @@ -0,0 +1,1632 @@ +[ + [ + "collectLoop", + "normal", + [ + "return", + [ + 1, + 2, + 3 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "next:2", + "done:2", + "value:2", + "body:3", + "next:3", + "done:3" + ] + ], + [ + "collectLoop", + "next throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "collectLoop", + "next primitive", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "collectLoop", + "done throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0" + ] + ], + [ + "collectLoop", + "value throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0" + ] + ], + [ + "collectLoop", + "return missing", + [ + "return", + [ + 1, + 2, + 3 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "next:2", + "done:2", + "value:2", + "body:3", + "next:3", + "done:3" + ] + ], + [ + "collectLoop", + "return null", + [ + "return", + [ + 1, + 2, + 3 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "next:2", + "done:2", + "value:2", + "body:3", + "next:3", + "done:3" + ] + ], + [ + "collectLoop", + "return noncallable", + [ + "return", + [ + 1, + 2, + 3 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "next:2", + "done:2", + "value:2", + "body:3", + "next:3", + "done:3" + ] + ], + [ + "collectLoop", + "return getter throws", + [ + "return", + [ + 1, + 2, + 3 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "next:2", + "done:2", + "value:2", + "body:3", + "next:3", + "done:3" + ] + ], + [ + "collectLoop", + "return throws", + [ + "return", + [ + 1, + 2, + 3 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "next:2", + "done:2", + "value:2", + "body:3", + "next:3", + "done:3" + ] + ], + [ + "collectLoop", + "return primitive", + [ + "return", + [ + 1, + 2, + 3 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "next:2", + "done:2", + "value:2", + "body:3", + "next:3", + "done:3" + ] + ], + [ + "stopLoop", + "normal", + [ + "return", + [ + 1, + 2 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "get return", + "return" + ] + ], + [ + "stopLoop", + "next throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "stopLoop", + "next primitive", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "stopLoop", + "done throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0" + ] + ], + [ + "stopLoop", + "value throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0" + ] + ], + [ + "stopLoop", + "return missing", + [ + "return", + [ + 1, + 2 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "get return" + ] + ], + [ + "stopLoop", + "return null", + [ + "return", + [ + 1, + 2 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "get return" + ] + ], + [ + "stopLoop", + "return noncallable", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "get return" + ] + ], + [ + "stopLoop", + "return getter throws", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "get return" + ] + ], + [ + "stopLoop", + "return throws", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "get return", + "return" + ] + ], + [ + "stopLoop", + "return primitive", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "next:1", + "done:1", + "value:1", + "body:2", + "get return", + "return" + ] + ], + [ + "continueLoop", + "normal", + [ + "return", + [ + 11, + 13 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:11", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "body:13", + "next:3", + "done:3" + ] + ], + [ + "continueLoop", + "next throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "continueLoop", + "next primitive", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "continueLoop", + "done throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0" + ] + ], + [ + "continueLoop", + "value throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0" + ] + ], + [ + "continueLoop", + "return missing", + [ + "return", + [ + 11, + 13 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:11", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "body:13", + "next:3", + "done:3" + ] + ], + [ + "continueLoop", + "return null", + [ + "return", + [ + 11, + 13 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:11", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "body:13", + "next:3", + "done:3" + ] + ], + [ + "continueLoop", + "return noncallable", + [ + "return", + [ + 11, + 13 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:11", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "body:13", + "next:3", + "done:3" + ] + ], + [ + "continueLoop", + "return getter throws", + [ + "return", + [ + 11, + 13 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:11", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "body:13", + "next:3", + "done:3" + ] + ], + [ + "continueLoop", + "return throws", + [ + "return", + [ + 11, + 13 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:11", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "body:13", + "next:3", + "done:3" + ] + ], + [ + "continueLoop", + "return primitive", + [ + "return", + [ + 11, + 13 + ] + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:11", + "next:1", + "done:1", + "value:1", + "next:2", + "done:2", + "value:2", + "body:13", + "next:3", + "done:3" + ] + ], + [ + "returnLoop", + "normal", + [ + "return", + 1 + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return", + "return" + ] + ], + [ + "returnLoop", + "next throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "returnLoop", + "next primitive", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "returnLoop", + "done throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0" + ] + ], + [ + "returnLoop", + "value throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0" + ] + ], + [ + "returnLoop", + "return missing", + [ + "return", + 1 + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return" + ] + ], + [ + "returnLoop", + "return null", + [ + "return", + 1 + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return" + ] + ], + [ + "returnLoop", + "return noncallable", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return" + ] + ], + [ + "returnLoop", + "return getter throws", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return" + ] + ], + [ + "returnLoop", + "return throws", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return", + "return" + ] + ], + [ + "returnLoop", + "return primitive", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return", + "return" + ] + ], + [ + "throwLoop", + "normal", + [ + "throw", + "RangeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return", + "return" + ] + ], + [ + "throwLoop", + "next throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "throwLoop", + "next primitive", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0" + ] + ], + [ + "throwLoop", + "done throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0" + ] + ], + [ + "throwLoop", + "value throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0" + ] + ], + [ + "throwLoop", + "return missing", + [ + "throw", + "RangeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return" + ] + ], + [ + "throwLoop", + "return null", + [ + "throw", + "RangeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return" + ] + ], + [ + "throwLoop", + "return noncallable", + [ + "throw", + "RangeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return" + ] + ], + [ + "throwLoop", + "return getter throws", + [ + "throw", + "RangeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return" + ] + ], + [ + "throwLoop", + "return throws", + [ + "throw", + "RangeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return", + "return" + ] + ], + [ + "throwLoop", + "return primitive", + [ + "throw", + "RangeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "body:1", + "get return", + "return" + ] + ], + [ + "finalizerLoop", + "normal", + [ + "return", + 1 + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner finally", + "get return", + "return", + "outer finally" + ] + ], + [ + "finalizerLoop", + "next throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "outer finally" + ] + ], + [ + "finalizerLoop", + "next primitive", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "outer finally" + ] + ], + [ + "finalizerLoop", + "done throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "outer finally" + ] + ], + [ + "finalizerLoop", + "value throws", + [ + "throw", + "SyntaxError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "outer finally" + ] + ], + [ + "finalizerLoop", + "return missing", + [ + "return", + 1 + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner finally", + "get return", + "outer finally" + ] + ], + [ + "finalizerLoop", + "return null", + [ + "return", + 1 + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner finally", + "get return", + "outer finally" + ] + ], + [ + "finalizerLoop", + "return noncallable", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner finally", + "get return", + "outer finally" + ] + ], + [ + "finalizerLoop", + "return getter throws", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner finally", + "get return", + "outer finally" + ] + ], + [ + "finalizerLoop", + "return throws", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner finally", + "get return", + "return", + "outer finally" + ] + ], + [ + "finalizerLoop", + "return primitive", + [ + "throw", + "TypeError" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner finally", + "get return", + "return", + "outer finally" + ] + ], + [ + "catchLoop", + "normal", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner:Error", + "next:1", + "done:1", + "value:1", + "get return", + "return", + "outer:RangeError" + ] + ], + [ + "catchLoop", + "next throws", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "outer:SyntaxError" + ] + ], + [ + "catchLoop", + "next primitive", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "outer:TypeError" + ] + ], + [ + "catchLoop", + "done throws", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "outer:SyntaxError" + ] + ], + [ + "catchLoop", + "value throws", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "outer:SyntaxError" + ] + ], + [ + "catchLoop", + "return missing", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner:Error", + "next:1", + "done:1", + "value:1", + "get return", + "outer:RangeError" + ] + ], + [ + "catchLoop", + "return null", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner:Error", + "next:1", + "done:1", + "value:1", + "get return", + "outer:RangeError" + ] + ], + [ + "catchLoop", + "return noncallable", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner:Error", + "next:1", + "done:1", + "value:1", + "get return", + "outer:RangeError" + ] + ], + [ + "catchLoop", + "return getter throws", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner:Error", + "next:1", + "done:1", + "value:1", + "get return", + "outer:RangeError" + ] + ], + [ + "catchLoop", + "return throws", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner:Error", + "next:1", + "done:1", + "value:1", + "get return", + "return", + "outer:RangeError" + ] + ], + [ + "catchLoop", + "return primitive", + [ + "return", + "finished" + ], + [ + "iterator", + "get next", + "next:0", + "done:0", + "value:0", + "inner:Error", + "next:1", + "done:1", + "value:1", + "get return", + "return", + "outer:RangeError" + ] + ], + [ + "nested", + "normal", + [ + "return", + 2 + ], + [ + "outer iterator", + "outer get next", + "outer next:0", + "outer done:0", + "outer value:0", + "inner iterator", + "inner get next", + "inner next:0", + "inner done:0", + "inner value:0", + "body:1:1", + "inner get return", + "inner return", + "outer get return", + "outer return" + ] + ], + [ + "nested", + "return getter throws", + [ + "throw", + "TypeError" + ], + [ + "outer iterator", + "outer get next", + "outer next:0", + "outer done:0", + "outer value:0", + "inner iterator", + "inner get next", + "inner next:0", + "inner done:0", + "inner value:0", + "body:1:1", + "inner get return", + "outer get return", + "outer return" + ] + ], + [ + "nested", + "return primitive", + [ + "throw", + "TypeError" + ], + [ + "outer iterator", + "outer get next", + "outer next:0", + "outer done:0", + "outer value:0", + "inner iterator", + "inner get next", + "inner next:0", + "inner done:0", + "inner value:0", + "body:1:1", + "inner get return", + "inner return", + "outer get return", + "outer return" + ] + ], + [ + [ + 3, + 3, + 3 + ], + 3 + ], + [ + 1, + 2, + 3 + ], + "undefined", + [ + "throw", + "ReferenceError" + ], + 9, + "undefined", + [ + 7, + null + ], + [ + 1, + 2 + ], + "undefined", + [ + [ + 1, + 97, + null + ], + [ + 2, + 55357, + 56832 + ], + [ + 1, + 55296, + null + ] + ], + [ + 1, + 2 + ], + [ + "original throw identity", + true + ], + [ + "close throw identity", + true + ], + [ + "reentrant", + 41, + [ + "body:41", + "outer return", + "inner iterator", + "inner get next", + "inner next:0", + "inner done:0", + "inner value:0", + "body:1", + "inner get return", + "inner return", + "inner result:1" + ] + ] +] From 667f8c2508bb213d9e423e3ce16a0e90f4bac399 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 01:00:38 +0200 Subject: [PATCH 45/99] Invalidate cached reads after binding declarations and deletion --- src/Runtime/Environment.php | 5 + .../CachedBindingInvalidationTest.php | 95 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 tests/Unit/Bytecode/CachedBindingInvalidationTest.php diff --git a/src/Runtime/Environment.php b/src/Runtime/Environment.php index 8f3e29c4..30ff67fe 100644 --- a/src/Runtime/Environment.php +++ b/src/Runtime/Environment.php @@ -206,6 +206,7 @@ public function hasAnyWithObjectInChain(): bool */ public function defineImportBinding(string $name, \Closure $resolver): void { + self::$globalBindingsVersion++; $this->importBindings[$name] = $resolver; $this->lexical[$name] = true; $this->constants[$name] = true; @@ -255,6 +256,7 @@ public function defineVar(string $name, JsValue $value): void */ public function defineGlobalVar(string $name, JsValue $value, bool $configurable = false): void { + self::$globalBindingsVersion++; $this->bindings[$name] = $value; if ($this->linkedObject !== null) { $existingProp = $this->linkedObject->getOwnPropertyDescriptor($name); @@ -286,6 +288,7 @@ public function defineGlobalVar(string $name, JsValue $value, bool $configurable /** Define a binding that can be removed with `delete`. Used for built-in globals. */ public function defineDeletable(string $name, JsValue $value): void { + self::$globalBindingsVersion++; $this->bindings[$name] = $value; $this->deletable[$name] = true; } @@ -299,6 +302,7 @@ public function defineDeletable(string $name, JsValue $value): void public function defineAnnexBVar(string $name, JsValue $value, bool $configurable = false): void { if (!array_key_exists($name, $this->bindings)) { + self::$globalBindingsVersion++; $this->bindings[$name] = $value; // For global scope (linked object), also create the property. // Per spec, scripts use CreateGlobalFunctionBinding(F, undefined, false) @@ -879,6 +883,7 @@ public function deleteBinding(string $name): bool } if (isset($this->deletable[$name])) { unset($this->bindings[$name], $this->deletable[$name]); + self::$globalBindingsVersion++; // Mirror the delete to the linked global object, if any, so // typeof/has lookups don't see the property after delete. if ($this->linkedObject !== null) { diff --git a/tests/Unit/Bytecode/CachedBindingInvalidationTest.php b/tests/Unit/Bytecode/CachedBindingInvalidationTest.php new file mode 100644 index 00000000..1e63a86c --- /dev/null +++ b/tests/Unit/Bytecode/CachedBindingInvalidationTest.php @@ -0,0 +1,95 @@ + */ + public static function mutations(): iterable + { + foreach (['bytecode', 'php'] as $tier) { + $mutations = ['replace-deletable', 'shadow-deletable', 'delete-deletable', 'shadow-annex-b', 'shadow-import', 'replace-global']; + foreach ($mutations as $mutation) { + yield $tier . '-' . $mutation => [$tier, $mutation]; + } + } + } + + #[DataProvider('mutations')] + public function testCachedReadsObserveHostBindingMutations(string $tier, string $mutation): void + { + $engine = new Engine(); + $parent = $engine->getGlobalEnv()->createChild(); + $parent->defineVar('current', JsNumber::of(2)); + $scope = $parent->createChild(); + if ($mutation === 'replace-global') { + $scope = $engine->getGlobalEnv(); + $scope->defineGlobalVar('current', JsNumber::of(1)); + } elseif (in_array($mutation, ['replace-deletable', 'delete-deletable'], true)) { + $scope->defineDeletable('current', JsNumber::of(1)); + } else { + $parent->set('current', JsNumber::of(1)); + } + $read = $this->reader($engine, $scope, $tier); + self::assertSame(1.0, $read()); + switch ($mutation) { + case 'replace-deletable': + case 'shadow-deletable': + $scope->defineDeletable('current', JsNumber::of(2)); + break; + case 'delete-deletable': + self::assertTrue($scope->deleteBinding('current')); + break; + case 'shadow-annex-b': + $scope->defineAnnexBVar('current', JsNumber::of(2)); + break; + case 'shadow-import': + $scope->defineImportBinding('current', static fn (): JsNumber => JsNumber::of(2)); + break; + case 'replace-global': + $scope->defineGlobalVar('current', JsNumber::of(2)); + break; + } + self::assertSame(2.0, $scope->get('current')->value); + self::assertSame(2.0, $read()); + } + + /** @return \Closure(): float */ + private function reader(Engine $engine, Environment $scope, string $tier): \Closure + { + // Activation setup must not incidentally invalidate the warmed binding cache. + $declaration = (new Parser('function read() { return current + 0; }'))->parse()->body[0]; + self::assertInstanceOf(FunctionDeclaration::class, $declaration); + $function = new JsFunction('read', $declaration->params, $declaration->body, $scope); + $undefined = JsUndefined::instance(); + if ($tier === 'php') { + $compiled = JsToPhp::compile($function); + self::assertInstanceOf(\Closure::class, $compiled); + return static fn (): float => $compiled([], $undefined, $scope, $engine->getInterpreter(), [])->value; + } + $compiled = (new Compiler())->compile($function); + self::assertContains(Op::LOAD_NAME, $compiled->code); + $vm = new VM($engine->getInterpreter()); + return static fn (): float => $vm->execute( + $compiled, + new Frame($scope, $undefined, $compiled->slotCount, $undefined), + )->value; + } +} From d266a724b631beb4d9c8ad5419291e51020fbcc8 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 01:02:20 +0200 Subject: [PATCH 46/99] Preserve callee realms through optimized calls and string lookups --- src/Bytecode/VM.php | 13 +++ src/Runtime/Parts/ExpressionEvaluation.php | 9 ++- .../Unit/Runtime/StringPrototypeRealmTest.php | 80 +++++++++++++++++++ 3 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 tests/Unit/Runtime/StringPrototypeRealmTest.php diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 34eb3374..2984523c 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -719,6 +719,7 @@ public function execute( ?JsValue $resumeValue = null, bool $resumeThrow = false, ): JsValue|YieldResult { + $executionRealm = (\Phasis\Engine::getCurrentInterpreter() ?? $this->interp)->getRealm(); $loopCounts = $resumeFrom->loopCounts ?? []; $code = $cf->code; $consts = $cf->consts; @@ -1625,6 +1626,13 @@ public function execute( (TypeConversion::toString($callee) ?: 'value') . ' is not a function' ); } + // Cross-realm calls need the ordinary realm switch; + // cached eligibility describes only function shape. + if ($callee->realm !== null && $callee->realm !== $executionRealm) { + $stack[$sp++] = $this->interp->callFunction($callee, $undef, $args); + $pc += 2; + break; + } // Fast path for the global URI built-ins (encodeURI, // decodeURI, encodeURIComponent, decodeURIComponent). // These are single-realm, never callable as @@ -2137,6 +2145,11 @@ public function execute( } throw new TypeError($display . ' is not a function'); } + if ($method->realm !== null && $method->realm !== $executionRealm) { + $stack[$sp++] = $this->interp->callFunction($method, $receiver, $args); + $pc += 2; + break; + } // Inline path for tagged hot built-ins: when the // receiver shape matches what the built-in's spec // path simplifies to (plain JsArray for array diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index 9220f169..a00fb3a8 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -1534,7 +1534,8 @@ private function evalCallExpression(CallExpression $node, Environment $env, bool // String method calls: look up on __StringPrototype__ if ($rawObj instanceof JsString && !$isSymbolCallKey) { - $proto = $this->cachedStringPrototype ??= $this->resolveCachedPrototype('__StringPrototype__'); + $realmInterpreter = \Phasis\Engine::getCurrentInterpreter() ?? $this; + $proto = $realmInterpreter->cachedStringPrototype ??= $realmInterpreter->resolveCachedPrototype('__StringPrototype__'); if ($proto instanceof JsObject) { $method = $proto->get($key); if ($method instanceof JsFunction) { @@ -5861,7 +5862,8 @@ public function vmLookupPrimitiveMember(JsValue $obj, string $name): JsValue } return JsUndefined::instance(); } - $proto = $this->cachedStringPrototype ??= $this->resolveCachedPrototype('__StringPrototype__'); + $realmInterpreter = \Phasis\Engine::getCurrentInterpreter() ?? $this; + $proto = $realmInterpreter->cachedStringPrototype ??= $realmInterpreter->resolveCachedPrototype('__StringPrototype__'); if ($proto instanceof JsObject) { $val = $proto->getWithValueReceiver($name, $obj); if (!$val instanceof JsUndefined) { @@ -7009,7 +7011,8 @@ private function evalMemberExpression(MemberExpression $node, Environment $env): // primitive string as their `this` (per spec OrdinaryGet for a // primitive receiver). Method-call this-binding is handled by // the CallExpression evaluator, not here. - $proto = $this->cachedStringPrototype ??= $this->resolveCachedPrototype('__StringPrototype__'); + $realmInterpreter = \Phasis\Engine::getCurrentInterpreter() ?? $this; + $proto = $realmInterpreter->cachedStringPrototype ??= $realmInterpreter->resolveCachedPrototype('__StringPrototype__'); if ($proto instanceof JsObject) { $val = $proto->getWithValueReceiver($key, $obj); if (!$val instanceof JsUndefined) { diff --git a/tests/Unit/Runtime/StringPrototypeRealmTest.php b/tests/Unit/Runtime/StringPrototypeRealmTest.php new file mode 100644 index 00000000..2398629a --- /dev/null +++ b/tests/Unit/Runtime/StringPrototypeRealmTest.php @@ -0,0 +1,80 @@ +checkRealmLookups(false); + } + + public function testInterpretedStringLookupsUseTheCalleeRealm(): void + { + $this->checkRealmLookups(true); + } + + private function checkRealmLookups(bool $budgeted): void + { + $foreign = new Engine(); + $caller = new Engine(); + foreach ([$foreign, $caller] as $index => $engine) { + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->setGlobal('marker', $index + 1); + $engine->eval(<<<'JS' +String.prototype.realmMethod = function () { return marker; }; +Object.defineProperty(String.prototype, 'realmProperty', { + configurable: true, + get: function () { 'use strict'; return marker + ':' + typeof this + ':' + this; } +}); +function namedMethod(text) { return text.realmMethod(); } +function computedMethod(text, key) { return text[key](); } +function namedProperty(text) { return text.realmProperty; } +function computedProperty(text, key) { return text[key]; } +function readCode(text) { return text.charCodeAt(0); } +function callBack(text, callback) { return [callback(text), text.realmProperty]; } +namedMethod('x'); +computedMethod('x', 'realmMethod'); +namedProperty('x'); +computedProperty('x', 'realmProperty'); +readCode('x'); +callBack('x', namedMethod); +JS); + } + foreach (['namedMethod', 'computedMethod', 'namedProperty', 'computedProperty', 'readCode', 'callBack'] as $name) { + $function = $foreign->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + if (!$budgeted) { + self::assertNotNull($function->compiled, $name); + } + $caller->setGlobalJsValue('foreign' . ucfirst($name), $function); + } + $caller->eval('String.prototype.charCodeAt = () => 999; const foreignContainer = { read: foreignNamedMethod };'); + self::assertSame( + [1, 1, '1:string:x', '1:string:x', 120, 1, [2, '1:string:x'], 2, '2:string:x', 999], + $caller->eval(<<<'JS' +[ + foreignNamedMethod('x'), + foreignComputedMethod('x', 'realmMethod'), + foreignNamedProperty('x'), + foreignComputedProperty('x', 'realmProperty'), + foreignReadCode('x'), + foreignContainer.read('x'), + foreignCallBack('x', namedMethod), + namedMethod('x'), + namedProperty('x'), + readCode('x') +] +JS), + ); + self::assertSame([1, '1:string:x', 120], $foreign->eval("[namedMethod('x'), namedProperty('x'), readCode('x')]")); + } +} From d8f1070523472146832abda3ed17749c7803bcb5 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 01:07:08 +0200 Subject: [PATCH 47/99] Compile guarded read-only ASCII string loops --- src/Bytecode/JsToPhp.php | 34 +- src/Bytecode/Parts/JsToPhpEmitExpression.php | 14 + src/Bytecode/Parts/JsToPhpEmitStatement.php | 10 +- src/Bytecode/Parts/JsToPhpStringScanners.php | 147 +++++++ src/Bytecode/StringScannerPlan.php | 417 +++++++++++++++++++ src/Runtime/CallStack.php | 6 + src/Runtime/Parts/ExpressionEvaluation.php | 25 ++ src/Value/JsString.php | 9 +- tests/Unit/Bytecode/StringScannerTest.php | 408 ++++++++++++++++++ 9 files changed, 1063 insertions(+), 7 deletions(-) create mode 100644 src/Bytecode/Parts/JsToPhpStringScanners.php create mode 100644 src/Bytecode/StringScannerPlan.php create mode 100644 tests/Unit/Bytecode/StringScannerTest.php diff --git a/src/Bytecode/JsToPhp.php b/src/Bytecode/JsToPhp.php index d994cc84..d76549f8 100644 --- a/src/Bytecode/JsToPhp.php +++ b/src/Bytecode/JsToPhp.php @@ -62,6 +62,7 @@ final class JsToPhp use Parts\JsToPhpScope; use Parts\JsToPhpEmitStatement; use Parts\JsToPhpEmitExpression; + use Parts\JsToPhpStringScanners; /** @var array */ private array $declaredLocals = []; @@ -208,7 +209,7 @@ public static function compile(JsFunction $fn): ?\Closure return null; } $compiled = self::compileFunction($fn); - if ($compiled === null) { + if ($compiled === null && !StringScannerPlan::maySpecialize($fn)) { CompilationFailures::remember($fn, 'php', 'unsupported syntax'); } return $compiled; @@ -268,7 +269,8 @@ private static function compileFunction(JsFunction $fn): ?\Closure } $standard = self::compileWith($fn, false); if ($standard === null) { - return null; + $scanner = StringScannerPlan::analyze($fn); + return $scanner !== null ? self::compileWith($fn, false, $scanner) : null; } // Try to also compile a numeric-mode variant for the hot // JsToPhp-to-JsToPhp dispatch path. Eligibility is the same @@ -289,7 +291,7 @@ private static function compileFunction(JsFunction $fn): ?\Closure * or null on bailout. Sets $fn->phpCompiledNodes when the * standard pass succeeds. */ - private static function compileWith(JsFunction $fn, bool $numeric): ?\Closure + private static function compileWith(JsFunction $fn, bool $numeric, ?StringScannerPlan $scanner = null): ?\Closure { $body = $fn->getBody(); $isExpressionBody = !$body instanceof BlockStatement; @@ -298,6 +300,10 @@ private static function compileWith(JsFunction $fn, bool $numeric): ?\Closure } $compiler = new self(); $compiler->numericMode = $numeric; + $compiler->scannerPlan = $scanner; + foreach ($scanner->stringParameters ?? [] as $name => $_) { + $compiler->localTypes[$name] = 'string'; + } try { $params = $fn->getParams(); foreach ($params as $p) { @@ -396,6 +402,9 @@ private static function compileWith(JsFunction $fn, bool $numeric): ?\Closure $signature = $numeric ? 'function (array $rawArgs, $thisValue, $env, $interp, $nestedFns)' : 'function ($args, $thisValue, $env, $interp, $nestedFns)'; + if ($scanner !== null) { + $signature .= ' use ($scannerGuards, $scannerRealm)'; + } // Guard against unbounded recursion. The interpreter's // CallStack enforces its own (much larger) limit, but a // JsToPhp closure dispatching through phpCompiled bypasses @@ -422,11 +431,26 @@ private static function compileWith(JsFunction $fn, bool $numeric): ?\Closure . $bodyPrologue . $compiler->out . $bodyEpilogue . "};"; try { - /** @var \Closure $closure */ - $closure = eval($php); + if ($scanner !== null) { + $factory = self::scannerClosureFactory($body, $php); + if ($factory === null) { + return null; + } + $realm = $fn->realm; + if ($realm === null) { + return null; + } + $guards = array_column($scanner->predicates, 'reference'); + $closure = $factory($guards, \WeakReference::create($realm)); + } else { + $closure = eval($php); + } } catch (\Throwable) { return null; } + if (!$closure instanceof \Closure) { + return null; + } if (!$numeric) { $fn->phpCompiledNodes = $compiler->nestedFnNodes; } diff --git a/src/Bytecode/Parts/JsToPhpEmitExpression.php b/src/Bytecode/Parts/JsToPhpEmitExpression.php index 36f75534..9bce7dc1 100644 --- a/src/Bytecode/Parts/JsToPhpEmitExpression.php +++ b/src/Bytecode/Parts/JsToPhpEmitExpression.php @@ -124,6 +124,9 @@ private function inferExpressionType(Node $node): string return 'unknown'; } if ($node instanceof Identifier) { + if (isset($this->scannerSubstitutions[$node->name])) { + return 'numeric'; + } if (isset($this->declaredLocals[$node->name])) { $kind = $this->localTypes[$node->name] ?? 'numeric'; return $kind === 'numeric' ? 'numeric' : 'unknown'; @@ -133,6 +136,10 @@ private function inferExpressionType(Node $node): string return 'numeric'; } if ($node instanceof CallExpression) { + $scannerType = $this->scannerCallType($node); + if ($scannerType !== null) { + return $scannerType; + } // CallExpression results are not statically typeable — the // callee may return any JsValue, including JsUndefined. We // used to claim 'numeric' here, which let @@ -181,6 +188,9 @@ private function emitExpression(Node $node): string throw new Bailout('non-numeric literal'); } if ($node instanceof Identifier) { + if (isset($this->scannerSubstitutions[$node->name])) { + return $this->scannerSubstitutions[$node->name]; + } if (isset($this->declaredLocals[$node->name])) { // Non-numeric locals can't be used in the numeric // expression pipeline (the caller would feed a JsValue @@ -616,6 +626,10 @@ private function emitExpression(Node $node): string */ private function emitCallExpression(CallExpression $node): string { + $scannerCall = $this->emitScannerCall($node); + if ($scannerCall !== null) { + return $scannerCall; + } // Method call shortcut: `arr.push(val)` on an array-typed // local goes straight to JsArray::push without resolving the // method through the prototype chain. Returns the new length diff --git a/src/Bytecode/Parts/JsToPhpEmitStatement.php b/src/Bytecode/Parts/JsToPhpEmitStatement.php index b53e970b..2dcd9536 100644 --- a/src/Bytecode/Parts/JsToPhpEmitStatement.php +++ b/src/Bytecode/Parts/JsToPhpEmitStatement.php @@ -40,11 +40,16 @@ trait JsToPhpEmitStatement */ private function emitPrologue(array $params): void { + $this->emitScannerGuards(); foreach ($params as $idx => $param) { if (!$param instanceof Identifier) { throw new Bailout('non-identifier param'); } $name = $param->name; + if (isset($this->scannerPlan?->stringParameters[$name])) { + $this->emitScannerStringParameter($name, $idx); + continue; + } // Params are always numeric in our profile — inferring // object-typed parameters would require call-site type // info we don't have. Object-typed locals can only come @@ -138,6 +143,9 @@ private function emitStatement(Node $node): void return; } if ($node instanceof ExpressionStatement) { + if ($this->scannerPlan !== null && $node->expression instanceof Literal && is_string($node->expression->value)) { + return; + } // For a discarded call result we don't need the JsNumber // unbox assertion that emitCallExpression appends — it // forces a Bailout when the callee returns anything but a @@ -234,7 +242,7 @@ private function emitStatement(Node $node): void $callRaw = $this->emitFunctionValuedCall($decl->init); $this->flushPending(); $this->emitLine($this->slotVar($name) . ' = ' . $callRaw . ';'); - } elseif ($kind === 'numeric' && $decl->init instanceof CallExpression) { + } elseif ($kind === 'numeric' && $decl->init instanceof CallExpression && $this->scannerPlan === null) { // `let r = callExpr()` where r's static type defaults // to numeric. emitExpression would emit the call THEN // a runtime `instanceof JsNumber` check that throws diff --git a/src/Bytecode/Parts/JsToPhpStringScanners.php b/src/Bytecode/Parts/JsToPhpStringScanners.php new file mode 100644 index 00000000..d7d1f96f --- /dev/null +++ b/src/Bytecode/Parts/JsToPhpStringScanners.php @@ -0,0 +1,147 @@ + Numeric predicate parameters substituted by already evaluated temporaries. */ + private array $scannerSubstitutions = []; + + /** @var ?\WeakMap> */ + private static ?\WeakMap $scannerFactories = null; + + private function emitScannerGuards(): void + { + if ($this->scannerPlan === null) { + return; + } + $this->emitLine('$_scanner_context = \\Phasis\\Engine::getCurrentInterpreter();'); + $this->emitLine('if ($interp->hasExecutionBudget() || $_scanner_context?->hasExecutionBudget()' + . ' || $scannerRealm->get() !== $interp->getRealm() || $_scanner_context?->getRealm() !== $interp->getRealm()) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("scanner context changed"); }'); + $frames = $this->scannerPlan->predicates === [] ? 1 : 2; + $this->emitLine('if (!$interp->hasPureCallCapacity(' . $frames . ')) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("scanner call depth"); }'); + if ($this->scannerPlan->usesCharacterRead) { + $this->emitLine('if (!$interp->hasCachedStringIntrinsic("charCodeAt", "string.charCodeAt")) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("scanner intrinsic changed"); }'); + } + if ($this->scannerPlan->predicates === []) { + return; + } + $index = 0; + foreach ($this->scannerPlan->predicates as $name => $_) { + $this->emitLine('$_scanner_binding = $env->findBindingDepth(' . var_export($name, true) . ');'); + $this->emitLine('if ($_scanner_binding === null || $_scanner_binding[0] !== $scannerGuards[' . $index . ']->get()) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("scanner predicate changed"); }'); + ++$index; + } + } + + private function emitScannerStringParameter(string $name, int $index): void + { + $variable = $this->slotVar($name); + $this->emitLine($variable . ' = $args[' . $index . '] ?? null;'); + $this->emitLine('if (!(' . $variable . ' instanceof \\Phasis\\Value\\JsString)' + . ' || get_class(' . $variable . ') !== \\Phasis\\Value\\JsString::class || !' . $variable . '->isAscii()) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("scanner string assumption"); }'); + $this->emitLine($variable . ' = ' . $variable . '->value;'); + } + + private function scannerCallType(CallExpression $expression): ?string + { + if ($this->scannerPlan === null) { + return null; + } + if ($expression->callee instanceof Identifier && isset($this->scannerPlan->predicates[$expression->callee->name])) { + return 'boolean'; + } + if ( + $expression->callee instanceof MemberExpression && $expression->callee->object instanceof Identifier + && isset($this->scannerPlan->stringParameters[$expression->callee->object->name]) + && $expression->callee->property instanceof Identifier && $expression->callee->property->name === 'charCodeAt' + ) { + return 'numeric'; + } + return null; + } + + private function emitScannerCall(CallExpression $expression): ?string + { + $type = $this->scannerCallType($expression); + if ($type === null || $this->scannerPlan === null) { + return null; + } + if ($type === 'numeric' && $expression->callee instanceof MemberExpression) { + $receiver = $expression->callee->object; + if (!$receiver instanceof Identifier) { + throw new Bailout('scanner receiver is not a local'); + } + $position = $this->newTemp('scanner_pos'); + $value = $this->newTemp('scanner_code'); + $index = $this->emitExpression($expression->arguments[0]); + $string = $this->slotVar($receiver->name); + $this->pendingStatements[] = $position . ' = ' . $index . ';'; + $this->pendingStatements[] = $position . ' = is_nan(' . $position . ') ? 0.0 : (' + . $position . ' < 0 ? ceil(' . $position . ') : floor(' . $position . '));'; + $this->pendingStatements[] = $value . ' = ' . $position . ' < 0 || ' . $position . ' >= strlen(' . $string . ')' + . ' ? NAN : (float) ord(' . $string . '[(int) ' . $position . ']);'; + return $value; + } + if (!$expression->callee instanceof Identifier) { + throw new Bailout('scanner predicate is not a named binding'); + } + $predicate = $this->scannerPlan->predicates[$expression->callee->name]; + $arguments = []; + foreach ($expression->arguments as $argument) { + $value = $this->emitExpression($argument); + $temporary = $this->newTemp('scanner_arg'); + $this->pendingStatements[] = $temporary . ' = ' . $value . ';'; + $arguments[] = $temporary; + } + $saved = $this->scannerSubstitutions; + $this->scannerSubstitutions = array_combine($predicate['parameters'], $arguments); + try { + return $this->emitExpression($predicate['body']); + } finally { + $this->scannerSubstitutions = $saved; + } + } + + /** Compile shared PHP code without retaining any function, realm or lexical environment. */ + private static function scannerClosureFactory(Node $body, string $source): ?\Closure + { + self::$scannerFactories ??= new \WeakMap(); + $key = hash('sha256', $source); + $entries = self::$scannerFactories[$body] ?? []; + if (isset($entries[$key])) { + return $entries[$key]; + } + try { + $factory = eval('return static function ($scannerGuards, $scannerRealm) { ' . $source . ' };'); + } catch (\Throwable) { + return null; + } + if (!$factory instanceof \Closure) { + return null; + } + if (count($entries) >= 8) { + array_shift($entries); + } + $entries[$key] = $factory; + self::$scannerFactories[$body] = $entries; + return $factory; + } +} diff --git a/src/Bytecode/StringScannerPlan.php b/src/Bytecode/StringScannerPlan.php new file mode 100644 index 00000000..9285f788 --- /dev/null +++ b/src/Bytecode/StringScannerPlan.php @@ -0,0 +1,417 @@ + */ + public array $stringParameters = []; + + /** @var array, body: Node, reference: \WeakReference}> */ + public array $predicates = []; + + public bool $usesCharacterRead = false; + + /** @var array */ + private array $parameters = []; + + /** @var array */ + private array $numericBindings = []; + + /** @var array */ + private array $declarations = []; + + private int $loops = 0; + + private function __construct(private readonly JsFunction $function) + { + } + + /** Keep environment-dependent specialization failures out of the shared syntax cache. */ + public static function maySpecialize(JsFunction $function): bool + { + $body = $function->getBody(); + if (!$body instanceof BlockStatement) { + return false; + } + $plan = new self($function); + foreach ($function->getParams() as $parameter) { + if ($parameter instanceof Identifier) { + $plan->parameters[$parameter->name] = true; + } + } + $plan->findStringParameters($body); + return $plan->stringParameters !== []; + } + + /** Reject ambiguous types, scope effects and user callbacks before emitting any code. */ + public static function analyze(JsFunction $function): ?self + { + $body = $function->getBody(); + if (!$body instanceof BlockStatement || $function->realm === null || $function->getBoundTarget() !== null) { + return null; + } + $plan = new self($function); + foreach ($function->getParams() as $parameter) { + if (!$parameter instanceof Identifier || isset($plan->parameters[$parameter->name])) { + return null; + } + $plan->parameters[$parameter->name] = true; + } + $plan->findStringParameters($body); + if ($plan->stringParameters === []) { + return null; + } + $plan->numericBindings = array_diff_key($plan->parameters, $plan->stringParameters); + if (!$plan->collectDeclarations($body)) { + return null; + } + $safeNames = []; + foreach (array_keys($plan->parameters + $plan->numericBindings) as $name) { + $safe = preg_replace('/[^A-Za-z0-9_]/', '_', $name); + if (isset($safeNames[$safe])) { + return null; + } + $safeNames[$safe] = true; + } + $initialized = array_diff_key($plan->parameters, $plan->stringParameters); + return $plan->validateBlock($body, $initialized, 0, true) && $plan->loops > 0 ? $plan : null; + } + + private function findStringParameters(Node $node): void + { + if ( + $node instanceof MemberExpression && !$node->computed && $node->object instanceof Identifier + && $node->property instanceof Identifier && isset($this->parameters[$node->object->name]) + && in_array($node->property->name, ['length', 'charCodeAt'], true) + ) { + $this->stringParameters[$node->object->name] = true; + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node) { + $this->findStringParameters($child); + } + } + } + } + + private function collectDeclarations(Node $node): bool + { + if ($node instanceof VariableDeclaration) { + foreach ($node->declarations as $declaration) { + if ( + !$declaration->id instanceof Identifier || $declaration->init === null + || isset($this->parameters[$declaration->id->name]) || isset($this->declarations[$declaration->id->name]) + ) { + return false; + } + $this->declarations[$declaration->id->name] = $node->kind; + $this->numericBindings[$declaration->id->name] = true; + } + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node && !$this->collectDeclarations($child)) { + return false; + } + } + } + return true; + } + + /** @param array $initialized */ + private function validateBlock(BlockStatement $block, array &$initialized, int $loopDepth, bool $functionBody = false): bool + { + $lexical = []; + foreach ($block->body as $statement) { + if (!$this->validateStatement($statement, $initialized, $loopDepth)) { + return false; + } + if ($statement instanceof VariableDeclaration && $statement->kind !== 'var') { + foreach ($statement->declarations as $declaration) { + if ($declaration->id instanceof Identifier) { + $lexical[$declaration->id->name] = true; + } + } + } + } + if (!$functionBody) { + $initialized = array_diff_key($initialized, $lexical); + } + return true; + } + + /** @param array $initialized */ + private function validateStatement(Node $statement, array &$initialized, int $loopDepth): bool + { + if ($statement instanceof EmptyStatement) { + return true; + } + if ($statement instanceof BlockStatement) { + return $this->validateBlock($statement, $initialized, $loopDepth); + } + if ($statement instanceof VariableDeclaration) { + if (!in_array($statement->kind, ['var', 'let', 'const'], true)) { + return false; + } + foreach ($statement->declarations as $declaration) { + if ( + !$declaration->id instanceof Identifier || $declaration->init === null + || $this->expressionType($declaration->init, $initialized) !== 'number' + ) { + return false; + } + $initialized[$declaration->id->name] = true; + } + return true; + } + if ($statement instanceof ExpressionStatement) { + $expression = $statement->expression; + if ($expression instanceof Literal && is_string($expression->value)) { + return true; + } + if ($expression instanceof UpdateExpression && $expression->argument instanceof Identifier) { + $name = $expression->argument->name; + return isset($initialized[$name]) && ($this->declarations[$name] ?? null) !== 'const'; + } + if ($expression instanceof AssignmentExpression && $expression->left instanceof Identifier) { + $name = $expression->left->name; + if ( + !isset($initialized[$name]) || ($this->declarations[$name] ?? null) === 'const' + || !in_array($expression->operator, ['=', '+=', '-=', '*='], true) + || $this->expressionType($expression->right, $initialized) !== 'number' + ) { + return false; + } + $initialized[$name] = true; + return true; + } + return false; + } + if ($statement instanceof ReturnStatement) { + return $statement->argument === null || $this->expressionType($statement->argument, $initialized) !== null; + } + if ($statement instanceof BreakStatement) { + return $statement->label === null && $loopDepth > 0; + } + if ($statement instanceof IfStatement) { + if ($this->expressionType($statement->test, $initialized) !== 'boolean') { + return false; + } + $yes = $no = $initialized; + if (!$this->validateStatement($statement->consequent, $yes, $loopDepth)) { + return false; + } + if ($statement->alternate !== null && !$this->validateStatement($statement->alternate, $no, $loopDepth)) { + return false; + } + $initialized = array_intersect_key($yes, $no); + return true; + } + if ($statement instanceof WhileStatement || $statement instanceof DoWhileStatement) { + ++$this->loops; + if ($this->expressionType($statement->test, $initialized) !== 'boolean') { + return false; + } + $body = $initialized; + return $this->validateStatement($statement->body, $body, $loopDepth + 1); + } + if ($statement instanceof ForStatement) { + ++$this->loops; + if ($statement->init !== null) { + $init = $statement->init instanceof VariableDeclaration ? $statement->init : new ExpressionStatement( + $statement->init->location, + $statement->init, + ); + if (!$this->validateStatement($init, $initialized, $loopDepth)) { + return false; + } + } + if ($statement->test !== null && $this->expressionType($statement->test, $initialized) !== 'boolean') { + return false; + } + $body = $initialized; + if (!$this->validateStatement($statement->body, $body, $loopDepth + 1)) { + return false; + } + if ( + $statement->update !== null && !$this->validateStatement( + new ExpressionStatement($statement->update->location, $statement->update), + $body, + $loopDepth + 1, + ) + ) { + return false; + } + if ($statement->init instanceof VariableDeclaration && $statement->init->kind !== 'var') { + foreach ($statement->init->declarations as $declaration) { + if ($declaration->id instanceof Identifier) { + unset($initialized[$declaration->id->name]); + } + } + } + return true; + } + return false; + } + + /** @param array $initialized */ + private function expressionType(Node $expression, array $initialized): ?string + { + if ($expression instanceof Identifier) { + return isset($initialized[$expression->name]) ? 'number' : null; + } + if ($expression instanceof Literal) { + return is_int($expression->value) || is_float($expression->value) + ? 'number' : (is_bool($expression->value) ? 'boolean' : null); + } + if ($expression instanceof MemberExpression) { + return $this->isStringMember($expression, 'length') ? 'number' : null; + } + if ($expression instanceof CallExpression && !$expression->optional) { + if ($expression->callee instanceof MemberExpression && $this->isStringMember($expression->callee, 'charCodeAt')) { + if (count($expression->arguments) !== 1 || $this->expressionType($expression->arguments[0], $initialized) !== 'number') { + return null; + } + $this->usesCharacterRead = true; + return 'number'; + } + if ($expression->callee instanceof Identifier && !isset($this->parameters[$expression->callee->name])) { + $name = $expression->callee->name; + $predicate = $this->predicate($name); + if ($predicate === null || count($predicate['parameters']) !== count($expression->arguments)) { + return null; + } + foreach ($expression->arguments as $argument) { + if ($this->expressionType($argument, $initialized) !== 'number') { + return null; + } + } + return 'boolean'; + } + } + return self::scalarExpressionType($expression, fn (Node $child): ?string => $this->expressionType($child, $initialized)); + } + + private function isStringMember(MemberExpression $expression, string $name): bool + { + return !$expression->computed && !$expression->optional && $expression->object instanceof Identifier + && isset($this->stringParameters[$expression->object->name]) + && $expression->property instanceof Identifier && $expression->property->name === $name; + } + + /** @return array{parameters: list, body: Node, reference: \WeakReference}|null */ + private function predicate(string $name): ?array + { + if (isset($this->numericBindings[$name])) { + return null; + } + if (isset($this->predicates[$name])) { + return $this->predicates[$name]; + } + $value = $this->function->getClosure()->findBindingDepth($name)[0] ?? null; + if ( + !$value instanceof JsFunction || $value->getNativeCallable() !== null || $value->getBoundTarget() !== null + || $value->isClassConstructor() || $value->isDerivedConstructor() || $value->isAsync() || $value->isGenerator() + ) { + return null; + } + $parameters = []; + foreach ($value->getParams() as $parameter) { + if (!$parameter instanceof Identifier || isset($parameters[$parameter->name])) { + return null; + } + $parameters[$parameter->name] = true; + } + $body = $value->getBody(); + if ($body instanceof BlockStatement) { + $statements = array_values(array_filter($body->body, static fn (Node $node): bool => !( + $node instanceof ExpressionStatement && $node->expression instanceof Literal + && is_string($node->expression->value) + ))); + if (count($statements) !== 1 || !$statements[0] instanceof ReturnStatement || $statements[0]->argument === null) { + return null; + } + $body = $statements[0]->argument; + } + if (!$body instanceof Node || self::predicateExpressionType($body, $parameters) !== 'boolean') { + return null; + } + return $this->predicates[$name] = [ + 'parameters' => array_keys($parameters), 'body' => $body, 'reference' => \WeakReference::create($value), + ]; + } + + /** @param array $parameters */ + private static function predicateExpressionType(Node $expression, array $parameters): ?string + { + if ($expression instanceof Identifier) { + return isset($parameters[$expression->name]) ? 'number' : null; + } + if ($expression instanceof Literal) { + return is_int($expression->value) || is_float($expression->value) + ? 'number' : (is_bool($expression->value) ? 'boolean' : null); + } + return self::scalarExpressionType($expression, static fn (Node $child): ?string => self::predicateExpressionType($child, $parameters)); + } + + /** @param \Closure(Node): ?string $type */ + private static function scalarExpressionType(Node $expression, \Closure $type): ?string + { + if ($expression instanceof UnaryExpression) { + $argument = $type($expression->argument); + return $expression->operator === '!' && $argument === 'boolean' ? 'boolean' + : (in_array($expression->operator, ['+', '-'], true) && $argument === 'number' ? 'number' : null); + } + if ($expression instanceof BinaryExpression) { + $left = $type($expression->left); + $right = $type($expression->right); + if ($left === 'number' && $right === 'number') { + if (in_array($expression->operator, ['+', '-', '*', '/', '%'], true)) { + return 'number'; + } + if (in_array($expression->operator, ['===', '!==', '==', '!=', '<', '>', '<=', '>='], true)) { + return 'boolean'; + } + } + return $left === 'boolean' && $right === 'boolean' && in_array($expression->operator, ['===', '!==', '==', '!='], true) + ? 'boolean' : null; + } + if ($expression instanceof LogicalExpression) { + return in_array($expression->operator, ['&&', '||'], true) + && $type($expression->left) === 'boolean' && $type($expression->right) === 'boolean' ? 'boolean' : null; + } + if ($expression instanceof ConditionalExpression && $type($expression->test) === 'boolean') { + $yes = $type($expression->consequent); + return $yes !== null && $yes === $type($expression->alternate) ? $yes : null; + } + return null; + } +} diff --git a/src/Runtime/CallStack.php b/src/Runtime/CallStack.php index e1f6362c..013b026c 100644 --- a/src/Runtime/CallStack.php +++ b/src/Runtime/CallStack.php @@ -69,6 +69,12 @@ public function depth(): int return $this->depth; } + /** Whether omitted effect-free frames would fit the configured stack limit. */ + public function hasCapacity(int $frames = 1): bool + { + return $frames <= $this->maxDepth - $this->depth; + } + /** @return list */ public function getFrames(): array { diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index a00fb3a8..e32f899c 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -5889,6 +5889,31 @@ public function vmLookupPrimitiveMember(JsValue $obj, string $name): JsValue return $this->getPropertyWithPrimitiveReceiver($boxed, $name, false, null, $obj); } + /** Check a pure inlined predicate before entering a body that cannot change call depth. */ + public function hasPureCallCapacity(int $frames): bool + { + return $this->callStack->hasCapacity($frames); + } + + /** Inspect an already realized primitive method without getters or cache initialization. */ + public function hasCachedStringIntrinsic(string $name, string $kind): bool + { + $realmInterpreter = \Phasis\Engine::getCurrentInterpreter() ?? $this; + $prototype = $realmInterpreter->cachedStringPrototype; + if ($prototype === null || get_class($prototype) !== JsObject::class) { + return false; + } + $value = $prototype->properties->dataSlots[$name] ?? null; + if ($value === null) { + $descriptor = $prototype->properties->descriptors[$name] ?? null; + if ($descriptor === null || !$descriptor->isDataDescriptor()) { + return false; + } + $value = $descriptor->value; + } + return $value instanceof JsFunction && $value->builtinKind === $kind && $value->getNativeCallable() !== null; + } + /** * VM helper: lower a nested ArrowFunction or FunctionExpression * AST node into a runtime JsFunction whose closure is the diff --git a/src/Value/JsString.php b/src/Value/JsString.php index 6cab1701..8bf08bfe 100644 --- a/src/Value/JsString.php +++ b/src/Value/JsString.php @@ -10,6 +10,7 @@ class JsString implements JsValue private ?string $utf16 = null; private ?int $codeUnitLength = null; + private ?bool $ascii = null; public static function setStringPrototype(JsObject $proto): void { @@ -69,11 +70,17 @@ public function display(): string /** JavaScript String.length (UTF-16 code unit count). */ public function length(): int { - return $this->codeUnitLength ??= mb_check_encoding($this->value, 'ASCII') + return $this->codeUnitLength ??= $this->isAscii() ? strlen($this->value) : (int) (strlen($this->utf16LE()) / 2); } + /** Whether byte offsets and UTF-16 offsets are interchangeable for this immutable value. */ + public function isAscii(): bool + { + return $this->ascii ??= mb_check_encoding($this->value, 'ASCII'); + } + /** UTF-16 code units cached for this immutable string value. */ public function utf16LE(): string { diff --git a/tests/Unit/Bytecode/StringScannerTest.php b/tests/Unit/Bytecode/StringScannerTest.php new file mode 100644 index 00000000..563dfe3a --- /dev/null +++ b/tests/Unit/Bytecode/StringScannerTest.php @@ -0,0 +1,408 @@ + code === 32 || code === 9 || code === 10 || code === 13; +function forward(text, offset) { + while (offset < text.length) { + if (!separator(text.charCodeAt(offset))) break; + offset++; + } + return offset; +} +function reverse(text, offset) { + while (offset > 0) { + if (!separator(text.charCodeAt(offset - 1))) break; + offset--; + } + return offset; +} +forward(' x ', 0); +reverse(' x ', 3); +JS; + + public function testForwardAndReverseScansUseCompiledBodies(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + $forward = $this->compiledFunction($engine, 'forward'); + $reverse = $this->compiledFunction($engine, 'reverse'); + self::assertNull($forward->phpCompiledNumeric); + foreach ([['x', 0.0, 0.0], [" \t\nx", 0.0, 3.0], ['', 0.0, 0.0], [' x', -0.5, 2.5]] as [$text, $offset, $expected]) { + self::assertSame($expected, $this->runCompiled($engine, $forward, [new JsString($text), JsNumber::of($offset)])->value); + } + self::assertSame(1.0, $this->runCompiled($engine, $reverse, [new JsString("x \t\n"), JsNumber::of(4)])->value); + self::assertTrue(is_nan($this->runCompiled($engine, $forward, [new JsString(' '), JsNumber::of(NAN)])->value)); + self::assertSame(INF, $this->runCompiled($engine, $forward, [new JsString(' '), JsNumber::of(INF)])->value); + self::assertSame(-INF, $this->runCompiled($engine, $forward, [new JsString(' '), JsNumber::of(-INF)])->value); + } + + public function testNumericLocalsAndPurePredicateArgumentsKeepEvaluationOrder(): void + { + $engine = new Engine(); + self::assertSame(9, $engine->eval(<<<'JS' +const pair = (left, right) => left === 97 && right === 98; +function count(text, offset) { + let total = 0; + for (let i = offset; i + 1 < text.length; i += 2) { + const code = text.charCodeAt(i); + if (pair(code, text.charCodeAt(i + 1))) total += i + 1; + } + return total; +} +count('ababab', 0); +JS)); + $function = $this->compiledFunction($engine, 'count'); + self::assertSame(9.0, $this->runCompiled($engine, $function, [new JsString('ababab'), JsNumber::of(0)])->value); + } + + public function testNonAsciiAndObjectArgumentsFallBackWithoutReplayingEffects(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + self::assertSame([1, 1, [0, 1]], $engine->eval(<<<'JS' +const calls = []; +const object = { length: 2, charCodeAt(index) { calls.push(index); return index === 0 ? 32 : 120; } }; +[forward(' é😀', 0), forward(object, 0), calls]; +JS)); + $this->expectException(Bailout::class); + $this->runCompiled($engine, $this->compiledFunction($engine, 'forward'), [new JsString('é'), JsNumber::of(0)]); + } + + public function testChangedPredicateAndMethodGettersAreObservedOnce(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + self::assertSame([1, 1, [32, 120], 2, true], $engine->eval(<<<'JS' +const calls = []; +separator = function (code) { calls.push(code); return code === 32; }; +const first = forward(' x', 0); +const original = String.prototype.charCodeAt; +let getters = 0; +Object.defineProperty(String.prototype, 'charCodeAt', { configurable: true, get() { getters++; return original; } }); +const empty = forward('', 0); +const second = forward(' x', 0); +Object.defineProperty(String.prototype, 'charCodeAt', { value: original, writable: true, configurable: true }); +[first, second, calls.slice(0, 2), getters, empty === 0]; +JS)); + } + + public function testGetterErrorsKeepIdentityAndEarlyReturnsDoNotReadTheMethod(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + self::assertSame([0, true, 1], $engine->eval(<<<'JS' +const original = String.prototype.charCodeAt; +const sentinel = {}; +let accesses = 0; +Object.defineProperty(String.prototype, 'charCodeAt', { configurable: true, get() { accesses++; throw sentinel; } }); +const empty = forward('', 0); +let same = false; +try { forward(' ', 0); } catch (error) { same = error === sentinel; } +Object.defineProperty(String.prototype, 'charCodeAt', { value: original, configurable: true, writable: true }); +[empty, same, accesses]; +JS)); + } + + public function testFactorySpecializationsDoNotSharePredicateOrEnvironmentState(): void + { + $engine = new Engine(); + self::assertSame([1, 1, 2], $engine->eval(<<<'JS' +function factory(test) { + return function scan(text, offset) { + while (offset < text.length) { + if (!test(text.charCodeAt(offset))) break; + offset++; + } + return offset; + }; +} +const first = factory(code => code === 32); +const second = factory(code => code === 9); +let effects = 0; +const rejected = factory(code => { effects++; return code === 32; }); +rejected(' x', 0); +[first(' x', 0), second('\tx', 0), effects]; +JS)); + $first = $this->compiledFunction($engine, 'first'); + $second = $this->compiledFunction($engine, 'second'); + self::assertSame(1.0, $this->runCompiled($engine, $first, [new JsString(' x'), JsNumber::of(0)])->value); + self::assertSame(0.0, $this->runCompiled($engine, $second, [new JsString(' x'), JsNumber::of(0)])->value); + self::assertSame(2, $engine->eval('effects')); + } + + public function testHostBindingReplacementInvalidatesAnAlreadyCompiledPredicate(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + $function = $this->compiledFunction($engine, 'forward'); + $engine->eval('const replacement = code => code === 120;'); + $replacement = $this->rawFunction($engine, 'replacement'); + $this->runCompiled($engine, $function, [new JsString(' x'), JsNumber::of(0)]); + $function->getClosure()->defineDeletable('separator', $replacement); + $this->expectException(Bailout::class); + $this->runCompiled($engine, $function, [new JsString(' x'), JsNumber::of(0)]); + } + + public function testForeignCompiledEntryBailsAndFreshEnginesKeepTheirOwnIntrinsics(): void + { + $first = new Engine(); + $first->eval(self::SOURCE); + $second = new Engine(); + $second->eval(self::SOURCE); + $foreign = $this->compiledFunction($first, 'forward'); + try { + $this->runCompiled($second, $foreign, [new JsString(' x'), JsNumber::of(0)]); + self::fail('A compiled scanner crossed an interpreter realm'); + } catch (Bailout) { + } + self::assertSame(0, $second->eval("String.prototype.charCodeAt = () => 120; forward(' x', 0)")); + self::assertSame(1.0, $this->runCompiled($first, $this->compiledFunction($first, 'forward'), [new JsString(' x'), JsNumber::of(0)])->value); + } + + public function testSharedSyntaxFactoriesKeepIndependentRealmGuards(): void + { + $first = new Engine(); + $first->eval(self::SOURCE); + $second = new Engine(); + $second->eval(self::SOURCE); + $program = (new Parser(<<<'JS' +function scan(text, offset) { + while (offset < text.length) { + if (text.charCodeAt(offset) !== 32) break; + offset++; + } + return offset; +} +JS))->parse(); + $declaration = $program->body[0]; + self::assertInstanceOf(\Phasis\Ast\Declaration\FunctionDeclaration::class, $declaration); + $functions = []; + foreach ([$first, $second] as $engine) { + $function = new JsFunction('scan', $declaration->params, $declaration->body, $engine->getGlobalEnv()->createChild()); + $function->realm = $engine; + $function->phpCompiled = JsToPhp::compile($function); + self::assertNotNull($function->phpCompiled); + self::assertSame(1.0, $this->runCompiled($engine, $function, [new JsString(' x'), JsNumber::of(0)])->value); + $functions[] = $function; + } + $this->expectException(Bailout::class); + $this->runCompiled($second, $functions[0], [new JsString(' x'), JsNumber::of(0)]); + } + + public function testSameRealmModuleInterpretersUseTheCurrentIntrinsicCacheOwner(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + $function = $this->compiledFunction($engine, 'forward'); + $module = new Interpreter($engine->getGlobalEnv()); + $module->setRealm($engine); + $previous = Engine::getCurrentInterpreter(); + try { + Engine::setCurrentInterpreter($module); + self::assertFalse($module->hasCachedStringIntrinsic('charCodeAt', 'string.charCodeAt')); + Engine::setCurrentInterpreter($engine->getInterpreter()); + self::assertTrue($module->hasCachedStringIntrinsic('charCodeAt', 'string.charCodeAt')); + $result = ($function->phpCompiled)( + [new JsString(' x'), JsNumber::of(0)], + JsUndefined::instance(), + $function->getClosure(), + $module, + [], + ); + self::assertInstanceOf(JsNumber::class, $result); + self::assertSame(1.0, $result->value); + } finally { + Engine::setCurrentInterpreter($previous); + } + } + + public function testLoopLimitAndActivatedBudgetRemainEffective(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + $engine->setLimit('maxLoopIterations', 2); + try { + $this->runCompiled($engine, $this->compiledFunction($engine, 'forward'), [new JsString(' x'), JsNumber::of(0)]); + self::fail('The scanner ignored the loop limit'); + } catch (InternalError $error) { + self::assertStringContainsString('Maximum loop iterations', $error->getMessage()); + } + $engine->setExecutionBudget(-1); + $this->expectException(BudgetExceeded::class); + $engine->eval("forward(' x', 0)"); + } + + public function testPurePredicateDoesNotBypassTheCallDepthLimit(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + $function = $this->compiledFunction($engine, 'forward'); + $property = new \ReflectionProperty($engine->getInterpreter(), 'callStack'); + $stack = new CallStack(0); + $property->setValue($engine->getInterpreter(), $stack); + $this->expectException(Bailout::class); + $this->runCompiled($engine, $function, [new JsString(' '), JsNumber::of(0)]); + } + + public function testColdAndCachedScannerCallsRespectThePredicateDepthBoundary(): void + { + $engine = new Engine(); + $engine->eval(<<<'JS' +const check = code => code === 32; +function scan(text, offset) { + while (offset < text.length) { + if (!check(text.charCodeAt(offset))) break; + offset++; + } + return offset; +} +JS); + $property = new \ReflectionProperty($engine->getInterpreter(), 'callStack'); + $property->setValue($engine->getInterpreter(), new CallStack(1)); + for ($attempt = 0; $attempt < 2; ++$attempt) { + try { + $engine->eval("scan(' ', 0)"); + self::fail('An inlined predicate bypassed the call depth boundary'); + } catch (InternalError $error) { + self::assertStringContainsString('Maximum call stack size', $error->getMessage()); + } + self::assertNull($this->rawFunction($engine, 'check')->phpCompiled); + self::assertNotNull($this->rawFunction($engine, 'scan')->phpCompiled); + } + } + + public function testCachedScannerCodeDoesNotRetainSyntaxOrLexicalEnvironments(): void + { + $engine = new Engine(); + $program = (new Parser(<<<'JS' +function check(value) { return value === 32; } +function scan(text, index) { + while (index < text.length) { + if (!check(text.charCodeAt(index))) break; + index++; + } + return index; +} +JS))->parse(); + $scope = $engine->getGlobalEnv()->createChild(); + $predicate = $program->body[0]; + $scanner = $program->body[1]; + self::assertInstanceOf(\Phasis\Ast\Declaration\FunctionDeclaration::class, $predicate); + self::assertInstanceOf(\Phasis\Ast\Declaration\FunctionDeclaration::class, $scanner); + $check = new JsFunction('check', $predicate->params, $predicate->body, $scope); + $check->realm = $engine; + $scope->defineVar('check', $check); + $function = new JsFunction('scan', $scanner->params, $scanner->body, $scope); + $function->realm = $engine; + $bodyReference = \WeakReference::create($scanner->body); + $scopeReference = \WeakReference::create($scope); + $predicateReference = \WeakReference::create($check); + $compiled = JsToPhp::compile($function); + self::assertNotNull($compiled); + unset($program, $predicate, $scanner, $scope, $check, $function); + gc_collect_cycles(); + self::assertNull($bodyReference->get()); + self::assertNull($scopeReference->get()); + self::assertNull($predicateReference->get()); + } + + public function testUnsupportedCompoundOperatorsKeepJavaScriptNumberSemantics(): void + { + $engine = new Engine(); + self::assertSame([1.5, 'Infinity'], $engine->eval(<<<'JS' +function remainder(text, offset) { + let result = 5.5; + while (offset < text.length) { result %= 2; offset++; } + return result; +} +function division(text, offset) { + let result = 1; + while (offset < text.length) { result /= 0; offset++; } + return result; +} +[remainder('x', 0), String(division('x', 0))]; +JS)); + self::assertNull($this->rawFunction($engine, 'remainder')->phpCompiled); + self::assertNull($this->rawFunction($engine, 'division')->phpCompiled); + } + + public function testEscapingLexicalWritesAreRejectedBeforeExecution(): void + { + $engine = new Engine(); + $engine->eval(<<<'JS' +function scan(text, offset) { + 'use strict'; + { let escaped = 1; } + escaped = 2; + while (offset < text.length) offset++; + return offset; +} +JS); + self::assertNull(JsToPhp::compile($this->rawFunction($engine, 'scan'))); + } + + public function testUnprovenReadsAndEffectsRemainOnTheVm(): void + { + $engine = new Engine(); + $engine->eval(<<<'JS' +let calls = 0; +let external = 0; +function effect(text, offset) { while (offset < text.length) { calls++; offset++; } return offset; } +function uninitialized(text, offset) { let n; while (offset < text.length) { offset++; } return n; } +function mutation(text, offset) { while (offset < text.length) { external = text.charCodeAt(offset); offset++; } return offset; } +JS); + foreach (['effect', 'uninitialized', 'mutation'] as $name) { + self::assertNull(JsToPhp::compile($this->rawFunction($engine, $name))); + } + self::assertSame([0, 0], $engine->eval('[calls, external]')); + } + + private function rawFunction(Engine $engine, string $name): JsFunction + { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + return $function; + } + + private function compiledFunction(Engine $engine, string $name): JsFunction + { + $function = $this->rawFunction($engine, $name); + self::assertNotNull($function->phpCompiled, $name . ' did not compile'); + return $function; + } + + /** @param list $arguments */ + private function runCompiled(Engine $engine, JsFunction $function, array $arguments): JsNumber + { + $previous = Engine::getCurrentInterpreter(); + Engine::setCurrentInterpreter($engine->getInterpreter()); + try { + $result = ($function->phpCompiled)($arguments, JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), []); + self::assertInstanceOf(JsNumber::class, $result); + return $result; + } finally { + Engine::setCurrentInterpreter($previous); + } + } +} From 08ba38260885d653accc22be7865854aeed9580b Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 01:11:40 +0200 Subject: [PATCH 48/99] Preserve lexical scope for exited block bindings --- src/Bytecode/Parts/CompilerBlockBindings.php | 7 +++ src/Bytecode/Parts/JsToPhpEligibility.php | 48 ++++++++++++++--- .../Unit/Bytecode/LexicalBlockEscapeTest.php | 48 +++++++++++++++++ .../Bytecode/fixtures/lexical-block-escape.js | 53 +++++++++++++++++++ .../fixtures/lexical-block-escape.json | 1 + 5 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 tests/Unit/Bytecode/LexicalBlockEscapeTest.php create mode 100644 tests/Unit/Bytecode/fixtures/lexical-block-escape.js create mode 100644 tests/Unit/Bytecode/fixtures/lexical-block-escape.json diff --git a/src/Bytecode/Parts/CompilerBlockBindings.php b/src/Bytecode/Parts/CompilerBlockBindings.php index 5286c708..6c2ed9ac 100644 --- a/src/Bytecode/Parts/CompilerBlockBindings.php +++ b/src/Bytecode/Parts/CompilerBlockBindings.php @@ -15,6 +15,7 @@ use Phasis\Ast\Expression\Property; use Phasis\Ast\Node; use Phasis\Ast\Statement\BlockStatement; +use Phasis\Bytecode\CompilerBailout; trait CompilerBlockBindings { @@ -31,6 +32,12 @@ private function collectReusableBlockBindings(BlockStatement $body): void $disallowed = array_fill_keys(array_keys($this->localSlots), true); $this->collectBlockBindingDeclarations($body, null, $body, $declarations, $declarationKinds, $disallowed); foreach ($declarations as $name => $blocks) { + if (count($blocks) === 1) { + $initialized = false; + if (!$this->blockBindingLifetimeIsIndependent($body, $name, array_fill_keys($blocks, true), null, $initialized)) { + throw new CompilerBailout('block binding needs a lexical environment'); + } + } if (isset($disallowed[$name]) || count($blocks) < 2 || count(array_unique($blocks)) !== count($blocks)) { continue; } diff --git a/src/Bytecode/Parts/JsToPhpEligibility.php b/src/Bytecode/Parts/JsToPhpEligibility.php index 2f06dd6c..cba14b8f 100644 --- a/src/Bytecode/Parts/JsToPhpEligibility.php +++ b/src/Bytecode/Parts/JsToPhpEligibility.php @@ -76,7 +76,36 @@ private static function bodyHasNestedLexical(Node $body): bool if (!$body instanceof BlockStatement) { return false; } - return self::blockHasUnsafeLexical($body->body); + return self::blockHasUnsafeLexical($body->body) || self::blockBindingEscapes($body, $body); + } + + private static function blockBindingEscapes(Node $node, BlockStatement $body): bool + { + if ( + $node instanceof FunctionDeclaration + || $node instanceof \Phasis\Ast\Expression\FunctionExpression + || $node instanceof \Phasis\Ast\Expression\ArrowFunction + ) { + return false; + } + if ($node instanceof BlockStatement && $node !== $body) { + foreach ($node->body as $statement) { + if ( + $statement instanceof VariableDeclaration && $statement->kind !== 'var' + && self::readsAnyName($body, self::collectDeclNames($statement), $node) + ) { + return true; + } + } + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node && self::blockBindingEscapes($child, $body)) { + return true; + } + } + } + return false; } /** @@ -178,8 +207,11 @@ private static function collectDeclNames(VariableDeclaration $node): array * * @param list $names */ - private static function readsAnyName(Node $node, array $names): bool + private static function readsAnyName(Node $node, array $names, ?Node $excludedScope = null): bool { + if ($node === $excludedScope) { + return false; + } if ($node instanceof Identifier) { return in_array($node->name, $names, true); } @@ -191,30 +223,30 @@ private static function readsAnyName(Node $node, array $names): bool return false; } if ($node instanceof \Phasis\Ast\Expression\MemberExpression) { - if (self::readsAnyName($node->object, $names)) { + if (self::readsAnyName($node->object, $names, $excludedScope)) { return true; } - if ($node->computed && self::readsAnyName($node->property, $names)) { + if ($node->computed && self::readsAnyName($node->property, $names, $excludedScope)) { return true; } return false; } if ($node instanceof \Phasis\Ast\Expression\Property) { - if ($node->computed && self::readsAnyName($node->key, $names)) { + if ($node->computed && self::readsAnyName($node->key, $names, $excludedScope)) { return true; } - return self::readsAnyName($node->value, $names); + return self::readsAnyName($node->value, $names, $excludedScope); } foreach ((array) $node as $value) { if ($value instanceof Node) { - if (self::readsAnyName($value, $names)) { + if (self::readsAnyName($value, $names, $excludedScope)) { return true; } continue; } if (is_array($value)) { foreach ($value as $item) { - if ($item instanceof Node && self::readsAnyName($item, $names)) { + if ($item instanceof Node && self::readsAnyName($item, $names, $excludedScope)) { return true; } } diff --git a/tests/Unit/Bytecode/LexicalBlockEscapeTest.php b/tests/Unit/Bytecode/LexicalBlockEscapeTest.php new file mode 100644 index 00000000..e081539e --- /dev/null +++ b/tests/Unit/Bytecode/LexicalBlockEscapeTest.php @@ -0,0 +1,48 @@ +checkOracle(false); + foreach (['escapedString', 'escapedNumeric', 'escapedRead', 'escapedCompound', 'escapedUpdate', 'escapedTypeof', 'escapedSloppy'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled, $name); + self::assertNull($function->phpCompiled, $name); + } + $valid = $engine->getGlobalEnv()->get('validBlock'); + self::assertInstanceOf(JsFunction::class, $valid); + self::assertInstanceOf(\Closure::class, JsToPhp::compile($valid)); + self::assertNotNull((new Compiler())->compile($valid)); + } + + public function testBudgetedInterpreterMatchesTheSameNodeOracle(): void + { + $this->checkOracle(true); + } + + private function checkOracle(bool $budgeted): Engine + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/lexical-block-escape.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/lexical-block-escape.json', + $engine->eval('JSON.stringify(lexicalBlockEscapeResult)'), + ); + return $engine; + } +} diff --git a/tests/Unit/Bytecode/fixtures/lexical-block-escape.js b/tests/Unit/Bytecode/fixtures/lexical-block-escape.js new file mode 100644 index 00000000..853c8b19 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/lexical-block-escape.js @@ -0,0 +1,53 @@ +function escapedString(text, offset) { + 'use strict'; + { let hidden = 1; } + hidden = 2; + while (offset < text.length) offset++; + return offset; +} +function escapedNumeric(offset) { + 'use strict'; + { let hidden = 1; } + hidden = 2; + while (offset < 1) offset++; + return offset; +} +function escapedRead() { + { const hidden = 1; } + return hidden; +} +function escapedCompound() { + 'use strict'; + { let hidden = 1; } + hidden += 1; + return 0; +} +function escapedUpdate() { + 'use strict'; + { let hidden = 1; } + hidden++; + return 0; +} +function escapedTypeof() { + { let hidden = 1; } + return typeof hidden; +} +function escapedSloppy() { + { let scopeLeak = 1; } + scopeLeak = 2; + return globalThis.scopeLeak; +} +function validBlock(offset) { + { let hidden = offset + 1; offset = hidden + 1; } + return offset; +} +globalThis.scopeLeak = 0; +const lexicalBlockEscapeResult = []; +for (const run of [ + () => escapedString('x', 0), () => escapedNumeric(0), () => escapedRead(), + () => escapedCompound(), () => escapedUpdate(), () => escapedTypeof(), () => escapedSloppy() +]) { + try { lexicalBlockEscapeResult.push(run()); } + catch (error) { lexicalBlockEscapeResult.push(error.name); } +} +lexicalBlockEscapeResult.push(validBlock(0), typeof hidden, globalThis.scopeLeak); diff --git a/tests/Unit/Bytecode/fixtures/lexical-block-escape.json b/tests/Unit/Bytecode/fixtures/lexical-block-escape.json new file mode 100644 index 00000000..06312131 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/lexical-block-escape.json @@ -0,0 +1 @@ +["ReferenceError","ReferenceError","ReferenceError","ReferenceError","ReferenceError","undefined",2,2,"undefined",2] From e78b8d6d652c5376227633096d46373ea4c3658a Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 01:19:34 +0200 Subject: [PATCH 49/99] Compile switch selection and fallthrough with scoped control flow --- src/Bytecode/Compiler.php | 1 + src/Bytecode/Parts/CompilerScope.php | 13 +++ src/Bytecode/Parts/CompilerStatement.php | 11 +- src/Bytecode/Parts/CompilerSwitch.php | 110 ++++++++++++++++++ tests/Unit/Bytecode/SwitchTest.php | 43 +++++++ tests/Unit/Bytecode/fixtures/switch.js | 139 +++++++++++++++++++++++ tests/Unit/Bytecode/fixtures/switch.json | 113 ++++++++++++++++++ 7 files changed, 428 insertions(+), 2 deletions(-) create mode 100644 src/Bytecode/Parts/CompilerSwitch.php create mode 100644 tests/Unit/Bytecode/SwitchTest.php create mode 100644 tests/Unit/Bytecode/fixtures/switch.js create mode 100644 tests/Unit/Bytecode/fixtures/switch.json diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index 7e654c78..8c37c9eb 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -62,6 +62,7 @@ final class Compiler { use Parts\CompilerBailoutAnalysis; use Parts\CompilerForOf; + use Parts\CompilerSwitch; use Parts\CompilerBlockBindings; use Parts\CompilerScope; use Parts\CompilerEmit; diff --git a/src/Bytecode/Parts/CompilerScope.php b/src/Bytecode/Parts/CompilerScope.php index f2409c56..726408c0 100644 --- a/src/Bytecode/Parts/CompilerScope.php +++ b/src/Bytecode/Parts/CompilerScope.php @@ -357,6 +357,13 @@ private function collectFunctionLocals(array $statements): void private function collectStatementLocals(Node $stmt): void { + if ($stmt instanceof \Phasis\Ast\Statement\SwitchStatement) { + $this->validateSwitchBindings($stmt); + foreach ($stmt->cases as $case) { + $this->collectFunctionLocals($case->consequent); + } + return; + } if ($stmt instanceof \Phasis\Ast\Statement\ForOfStatement) { if ($this->forOfBody === null || !$stmt->left instanceof VariableDeclaration) { throw new CompilerBailout('for-of assignment target'); @@ -653,6 +660,12 @@ private function collectInnerDeclaredNames(array $statements, array &$out): void */ private function collectInnerDeclaredNamesNode(Node $node, array &$out): void { + if ($node instanceof \Phasis\Ast\Statement\SwitchStatement) { + foreach ($node->cases as $case) { + $this->collectInnerDeclaredNames($case->consequent, $out); + } + return; + } if ($node instanceof \Phasis\Ast\Statement\ForOfStatement) { if ($node->left instanceof VariableDeclaration) { $this->collectInnerDeclaredNamesNode($node->left, $out); diff --git a/src/Bytecode/Parts/CompilerStatement.php b/src/Bytecode/Parts/CompilerStatement.php index 743e7a69..b4673b9c 100644 --- a/src/Bytecode/Parts/CompilerStatement.php +++ b/src/Bytecode/Parts/CompilerStatement.php @@ -99,6 +99,10 @@ private function compileStatement(Node $node): void $this->compileFor($node); return; } + if ($node instanceof \Phasis\Ast\Statement\SwitchStatement) { + $this->compileSwitch($node); + return; + } if ($node instanceof \Phasis\Ast\Statement\ForOfStatement) { $this->compileForOf($node); return; @@ -132,10 +136,13 @@ private function compileStatement(Node $node): void if ($node->label !== null) { throw new CompilerBailout('labeled continue'); } - if ($this->loopStack === []) { + $loopDepth = count($this->loopStack); + while ($loopDepth > 0 && $this->loopStack[$loopDepth - 1]['continue'] === -2) { + $loopDepth--; + } + if ($loopDepth === 0) { throw new CompilerBailout('continue outside loop'); } - $loopDepth = count($this->loopStack); foreach ($this->finallyLoopBoundaries as $boundary) { if ($boundary >= $loopDepth) { throw new CompilerBailout('continue escaping try-with-finally'); diff --git a/src/Bytecode/Parts/CompilerSwitch.php b/src/Bytecode/Parts/CompilerSwitch.php new file mode 100644 index 00000000..9f26f295 --- /dev/null +++ b/src/Bytecode/Parts/CompilerSwitch.php @@ -0,0 +1,110 @@ +forOfBody === null || $this->inGenerator) { + throw new CompilerBailout('switch requires an ordinary function body'); + } + if (!$this->switchScopesValidated) { + $this->validateForOfBlockScopes($this->forOfBody, $this->forOfBody); + $this->switchScopesValidated = true; + } + foreach ($node->cases as $case) { + foreach ($case->consequent as $statement) { + if ( + ($statement instanceof VariableDeclaration && $statement->kind !== 'var') + || $statement instanceof ClassDeclaration || $statement instanceof FunctionDeclaration + ) { + // Shared case-block lexical bindings exist before case + // expressions run. Flat local slots cannot model that TDZ. + throw new CompilerBailout('switch case-block lexical environment'); + } + $this->validateSwitchLocalInitialization($statement); + } + } + } + + private function validateSwitchLocalInitialization(Node $node): void + { + if ($node instanceof FunctionDeclaration || $node instanceof ClassDeclaration) { + throw new CompilerBailout('switch declaration needs a nested environment'); + } + if ($node instanceof FunctionExpression || $node instanceof ArrowFunction || $node instanceof ClassExpression) { + return; + } + if ($node instanceof VariableDeclaration && $node->kind === 'let') { + foreach ($node->declarations as $declaration) { + if ($declaration->init === null) { + throw new CompilerBailout('switch lexical initialization requires a fresh binding'); + } + } + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node) { + $this->validateSwitchLocalInitialization($child); + } + } + } + } + + private function compileSwitch(SwitchStatement $node): void + { + $this->validateSwitchBindings($node); + $valueSlot = count($this->localNames); + $this->localNames[] = '[[switchValue]]'; + $this->compileExpression($node->discriminant); + $this->emit(Op::STORE_LOCAL, $valueSlot); + + $caseJumps = []; + foreach ($node->cases as $index => $case) { + if ($case->test !== null) { + $this->emit(Op::LOAD_LOCAL, $valueSlot); + $this->compileExpression($case->test); + $this->emit(Op::SEQ); + $caseJumps[$index] = $this->emitJump(Op::JUMP_IF_TRUE); + } + } + $noMatch = $this->emitJump(Op::JUMP); + $hasDefault = false; + // A switch is a break target, but continue must find an outer loop. + $this->loopStack[] = ['continue' => -2, 'breaks' => [], 'continues' => []]; + foreach ($node->cases as $index => $case) { + if ($case->test === null) { + $this->patchJumpToHere($noMatch); + $hasDefault = true; + } else { + $this->patchJumpToHere($caseJumps[$index]); + } + foreach ($case->consequent as $statement) { + $this->compileStatement($statement); + } + } + if (!$hasDefault) { + $this->patchJumpToHere($noMatch); + } + $frame = array_pop($this->loopStack); + foreach ($frame['breaks'] as $jump) { + $this->patchJumpToHere($jump); + } + } +} diff --git a/tests/Unit/Bytecode/SwitchTest.php b/tests/Unit/Bytecode/SwitchTest.php new file mode 100644 index 00000000..3c751b1a --- /dev/null +++ b/tests/Unit/Bytecode/SwitchTest.php @@ -0,0 +1,43 @@ +checkOracle(false); + foreach (['selectedCase', 'strictCases', 'noDefault', 'nestedSwitches', 'forOfSwitch', 'finallySwitch'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name); + } + foreach (['caseBlockTdz', 'blockScopeEscape', 'resetSwitchLet', 'finallyContinue'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled, $name); + } + } + + public function testBudgetedInterpreterMatchesTheSameOracle(): void + { + $this->checkOracle(true); + } + + private function checkOracle(bool $budgeted): Engine + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/switch.js')); + self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/switch.json', $engine->eval('JSON.stringify(switchResults)')); + return $engine; + } +} diff --git a/tests/Unit/Bytecode/fixtures/switch.js b/tests/Unit/Bytecode/fixtures/switch.js new file mode 100644 index 00000000..4ff5ad30 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/switch.js @@ -0,0 +1,139 @@ +var switchResults = []; +function selectedCase(value, events) { + function probe(value, label) { events.push(label); return value; } + switch (probe(value, 'subject')) { + case probe(1, 'test1'): + events.push('one'); + break; + default: + events.push('default'); + case probe(2, 'test2'): + events.push('two'); + case probe(3, 'test3'): + events.push('three'); + } + events.push('end'); + return events; +} +for (const value of [1, 2, 3, 4, undefined, null]) switchResults.push(selectedCase(value, [])); + +var switchSymbol = Symbol('case'); +var switchObject = {}; +var switchBigInt = 1n; +function strictCases(value) { + switch (value) { + case 1: return 'number'; + case '1': return 'string'; + case switchBigInt: return 'bigint'; + case NaN: return 'nan'; + case -0: return 'zero'; + case switchSymbol: return 'symbol'; + case switchObject: return 'object'; + default: return 'default'; + } +} +for (const value of [1, '1', 1n, NaN, -0, 0, switchSymbol, Symbol('case'), switchObject, {}]) { + switchResults.push(strictCases(value)); +} +function noDefault(value) { + var output = 0; + switch (value) { case 1: output = 10; break; case 2: output = 20; } + return output; +} +switchResults.push(noDefault(0), noDefault(1), noDefault(2)); + +function nestedSwitches() { + const output = []; + for (var index = 0; index < 4; index++) { + switch (index) { + case 0: continue; + case 1: break; + case 2: { + const value = index + 10; + output.push(value); + switch (value) { case 12: output.push('inner'); break; default: return ['wrong']; } + } + default: output.push('body'); + } + output.push(index); + } + return output; +} +switchResults.push(nestedSwitches()); + +function forOfSwitch(input) { + const output = []; + for (const item of input) { + switch (item) { case 1: continue; case 2: break; case 3: return output; } + output.push(item); + } + return output; +} +const iteratorEvents = []; +const iterable = { + [Symbol.iterator]() { + let current = 0; + return { + next() { iteratorEvents.push('next'); return { value: ++current, done: current > 3 }; }, + return() { iteratorEvents.push('return'); return {}; } + }; + } +}; +switchResults.push(forOfSwitch(iterable), iteratorEvents); + +function finallySwitch(value, events) { + try { + switch (value) { case 1: return 10; case 2: throw 'case'; default: events.push('default'); } + return 20; + } finally { events.push('finally'); } +} +for (const value of [0, 1, 2]) { + const events = []; + try { events.push(finallySwitch(value, events)); } catch (error) { events.push(error); } + switchResults.push(events); +} + +function caseBlockTdz(value) { + switch (value) { + case hidden: return 'wrong'; + default: let hidden = 1; return hidden; + } +} +try { caseBlockTdz(0); } catch (error) { switchResults.push(error.name); } + +function blockScopeEscape(value) { + 'use strict'; + switch (value) { case 1: { let hidden = 1; } } + hidden = 2; +} +try { blockScopeEscape(1); } catch (error) { switchResults.push(error.name); } + +function resetSwitchLet() { + const output = []; + for (var index = 0; index < 2; index++) { + switch (index) { default: { let value; output.push(value === undefined); value = 1; } } + } + return output; +} +switchResults.push(resetSwitchLet()); + +function finallyContinue() { + const output = []; + for (var index = 0; index < 2; index++) { + switch (index) { + default: try { continue; } finally { output.push(index); } + } + } + return output; +} +switchResults.push(finallyContinue()); + +function argumentEffects(events) { + const sentinel = {}; + function fail() { events.push('case'); throw sentinel; } + try { + switch ((events.push('subject'), 1)) { case fail(): return 'wrong'; default: return 'wrong'; } + } catch (error) { return error === sentinel; } +} +const argumentEvents = []; +switchResults.push(argumentEffects(argumentEvents), argumentEvents); diff --git a/tests/Unit/Bytecode/fixtures/switch.json b/tests/Unit/Bytecode/fixtures/switch.json new file mode 100644 index 00000000..a0f70cdf --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/switch.json @@ -0,0 +1,113 @@ +[ + [ + "subject", + "test1", + "one", + "end" + ], + [ + "subject", + "test1", + "test2", + "two", + "three", + "end" + ], + [ + "subject", + "test1", + "test2", + "test3", + "three", + "end" + ], + [ + "subject", + "test1", + "test2", + "test3", + "default", + "two", + "three", + "end" + ], + [ + "subject", + "test1", + "test2", + "test3", + "default", + "two", + "three", + "end" + ], + [ + "subject", + "test1", + "test2", + "test3", + "default", + "two", + "three", + "end" + ], + "number", + "string", + "bigint", + "default", + "zero", + "zero", + "symbol", + "default", + "object", + "default", + 0, + 10, + 20, + [ + 1, + 12, + "inner", + "body", + 2, + "body", + 3 + ], + [ + 2 + ], + [ + "next", + "next", + "next", + "return" + ], + [ + "default", + "finally", + 20 + ], + [ + "finally", + 10 + ], + [ + "finally", + "case" + ], + "ReferenceError", + "ReferenceError", + [ + true, + true + ], + [ + 0, + 1 + ], + true, + [ + "subject", + "case" + ] +] From 1b4ddd05627a139525edcd04ab0035d0862ce87c Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 01:25:53 +0200 Subject: [PATCH 50/99] Compile simple rest parameters with existing binding semantics --- src/Bytecode/CompiledFunction.php | 2 +- src/Bytecode/Compiler.php | 16 +- src/Runtime/Parts/ExpressionEvaluation.php | 2 +- tests/Unit/Bytecode/RestParameterTest.php | 134 +++++++ .../Unit/Bytecode/fixtures/rest-parameters.js | 83 ++++ .../Bytecode/fixtures/rest-parameters.json | 358 ++++++++++++++++++ 6 files changed, 592 insertions(+), 3 deletions(-) create mode 100644 tests/Unit/Bytecode/RestParameterTest.php create mode 100644 tests/Unit/Bytecode/fixtures/rest-parameters.js create mode 100644 tests/Unit/Bytecode/fixtures/rest-parameters.json diff --git a/src/Bytecode/CompiledFunction.php b/src/Bytecode/CompiledFunction.php index 882b0e86..78c9846c 100644 --- a/src/Bytecode/CompiledFunction.php +++ b/src/Bytecode/CompiledFunction.php @@ -188,7 +188,7 @@ final class CompiledFunction * Frame directly and skip the per-call createChild * allocation. * @param bool $parametersFromEnvironment Read initialized parameter - * bindings after the interpreter applies defaults and parameter TDZ. + * bindings after the interpreter applies defaults, rest arrays and parameter TDZ. * @param array|null $capturedEnvironmentBindings Captured * body var/let/const declarations. Null retains interpreter hoisting; * parameters and function declarations have separate initialization. diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index 8c37c9eb..7ecec561 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -338,6 +338,10 @@ private function compileFunction(JsFunction $fn): CompiledFunction } foreach ($fn->getParams() as $param) { + if ($param instanceof RestElement && $param->argument instanceof Identifier && !$fn->isGenerator()) { + $this->parametersFromEnvironment = true; + $param = $param->argument; + } if ($param instanceof AssignmentPattern && $param->left instanceof Identifier && !$fn->isGenerator()) { if ($this->parameterInitializerCanCapture($param->right)) { throw new CompilerBailout('parameter initializer captures bindings'); @@ -450,11 +454,21 @@ private function compileFunction(JsFunction $fn): CompiledFunction private function capturedEnvironmentBindings(JsFunction $fn): ?array { if ( - $fn->isArrow() || $fn->isGenerator() || $this->parametersFromEnvironment + $fn->isArrow() || $fn->isGenerator() || $this->needsArguments || $this->classNodes !== [] || $this->arrayAssignmentReferences ) { return null; } + // Plain and rest parameters are already bound in the body environment. + // Parameter expressions need the interpreter's separate body scope. + foreach ($fn->getParams() as $parameter) { + if ( + !$parameter instanceof Identifier + && !($parameter instanceof RestElement && $parameter->argument instanceof Identifier) + ) { + return null; + } + } $bindings = []; foreach ($this->capturedLocals as $name => $kind) { if ($kind === 'var' || $kind === 'let' || $kind === 'const') { diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index e32f899c..bbe84629 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -4390,7 +4390,7 @@ private function executeFunction( $compiledBindings = $fn->compiled?->capturedEnvironmentBindings; if ( $compiledBindings !== null - && ($hasDefaultParams || $isNonSimpleParams || $argsObj !== null || !$this->vmOwnsFunctionHoists($fn)) + && ($hasDefaultParams || $argsObj !== null || !$this->vmOwnsFunctionHoists($fn)) ) { $compiledBindings = null; } diff --git a/tests/Unit/Bytecode/RestParameterTest.php b/tests/Unit/Bytecode/RestParameterTest.php new file mode 100644 index 00000000..50489d0c --- /dev/null +++ b/tests/Unit/Bytecode/RestParameterTest.php @@ -0,0 +1,134 @@ +checkOracle(false); + $compiledNames = [ + 'restOnly', 'restPrefix', 'restCaptured', 'restVarRedeclared', 'restHoisted', 'restDefaults', + 'strictRestArguments', 'restArrow', 'restMutation', 'restObjectIdentity', + 'restLegacy', + ]; + foreach ($compiledNames as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name); + self::assertTrue($function->compiled->parametersFromEnvironment, $name); + } + $captured = $engine->getGlobalEnv()->get('restCaptured'); + self::assertInstanceOf(JsFunction::class, $captured); + self::assertSame(['count' => 'let'], $captured->compiled?->capturedEnvironmentBindings); + foreach (['restDefaults', 'strictRestArguments'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled?->capturedEnvironmentBindings, $name); + } + foreach (['restArgumentSnapshot', 'restPattern', 'restEval', 'restWith'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled, $name); + } + } + + public function testBudgetedRestFunctionsMatchTheSameNodeOracle(): void + { + $this->checkOracle(true); + } + + public function testRestArraysUseTheCalleeRealmAcrossCalls(): void + { + $foreign = new Engine(); + $foreign->eval('function foreignRest(...values) { return values; }'); + $function = $foreign->getGlobalEnv()->get('foreignRest'); + $prototype = $foreign->getGlobalEnv()->getIntrinsic('ArrayPrototype'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertInstanceOf(JsObject::class, $prototype); + $caller = new Engine(); + $caller->getGlobalEnv()->defineVar('foreignRest', $function); + $caller->getGlobalEnv()->defineVar('foreignArrayPrototype', $prototype); + for ($pass = 0; $pass < 3; $pass++) { + self::assertSame([true, true, 2], $caller->eval(<<<'JS' +var result = foreignRest(1, 2); +[Object.getPrototypeOf(result) === foreignArrayPrototype, + Object.getPrototypeOf(result) !== Array.prototype, result.length]; +JS)); + } + self::assertNotNull($function->compiled); + } + + public function testBudgetTransitionsAndCallStackTrackingRemainActive(): void + { + $engine = new Engine(); + $engine->setLimit('maxLoopIterations', PHP_INT_MAX); + $engine->setGlobal('restDepth', fn (): int => $engine->getInterpreter()->getCallStack()->depth()); + self::assertGreaterThanOrEqual(9, $engine->eval(<<<'JS' +function restRecurse(depth, ...values) { + if (depth === 0) return restDepth(); + return restRecurse(depth - 1, values.length); +} +restRecurse(8, 1, 2); +JS)); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + self::assertSame(6, $engine->eval(<<<'JS' +function restLoop(limit, ...values) { + let total = 0; + for (let index = 0; index < limit; index++) total += values.length; + return total; +} +restLoop(3, 1, 2); +JS)); + $engine->setExecutionBudget(0.002); + $exceeded = false; + try { + $engine->eval('restLoop(100000000, 1, 2);'); + } catch (BudgetExceeded) { + $exceeded = true; + } + self::assertTrue($exceeded); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + $engine->setExecutionBudget(null); + self::assertSame(6, $engine->eval('restLoop(2, 1, 2, 3);')); + } + + public function testRetainedCapturesKeepTheirScopesAcrossBudgetTransitions(): void + { + $engine = new Engine(); + self::assertSame([1, 2], $engine->eval(<<<'JS' +function restScope(first, ...values) { + let value = first; + return () => [value, values.length]; +} +restScope(1, 2, 3)(); +JS)); + $engine->setExecutionBudget(5); + self::assertSame([4, 1], $engine->eval('var retainedRestScope = restScope(4, 5); retainedRestScope();')); + $engine->setExecutionBudget(null); + self::assertSame([6, 3], $engine->eval('restScope(6, 7, 8, 9)();')); + self::assertSame([4, 1], $engine->eval('retainedRestScope();')); + } + + private function checkOracle(bool $budgeted): Engine + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/rest-parameters.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/rest-parameters.json', + $engine->eval('JSON.stringify(restParameterResult)'), + ); + return $engine; + } +} diff --git a/tests/Unit/Bytecode/fixtures/rest-parameters.js b/tests/Unit/Bytecode/fixtures/rest-parameters.js new file mode 100644 index 00000000..b234117a --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/rest-parameters.js @@ -0,0 +1,83 @@ +const restParameterResult = []; +function restOnly(...values) { return values; } +function restPrefix(first, second, ...values) { return [first, second, values]; } +function restCaptured(first, ...values) { + let count = 0; + return function read() { + values.push(first + count++); + return values.slice(); + }; +} +function restVarRedeclared(...values) { + var values; + values.push('added'); + return () => values.slice(); +} +function restHoisted(...values) { + function values() { return 9; } + return () => values(); +} +function restDefaults(first = 3, ...values) { + var first; + first += 2; + return () => [first, values.slice()]; +} +function restArgumentSnapshot(first, ...values) { + const original = arguments; + first = 8; + values[0] = 9; + return [first, values, original[0], original[1]]; +} +const strictRestArguments = (function () { + 'use strict'; + return function strictRestArguments(first, ...values) { + const original = arguments; + first = 8; + values[0] = 9; + return [first, values, original[0], original[1]]; + }; +})(); +const restArrow = (...values) => values.slice(); +function restPattern(...[first, second]) { return [first, second]; } +function restMutation(first, ...values) { + first += 1; + values[0] = 'changed'; + return [first, values]; +} +function restObjectIdentity(...values) { + return [values.length, values[0] === restIdentityObject, values[1] === restIdentityArray, + Object.getPrototypeOf(values) === Array.prototype]; +} +function restLegacy(first, ...values) { + const snapshot = restLegacy['arguments']; + return [snapshot.length, snapshot[0], snapshot[1], first, values]; +} +function restEval(first, ...values) { return eval('first + values.length'); } +function restWith(...values) { with ({size: values.length}) { return size; } } +const restIdentityObject = {valueOf() { throw new Error('rest must not coerce arguments'); }}; +const restIdentityArray = [1, 2]; + +for (let pass = 0; pass < 3; pass++) { + restParameterResult.push(restOnly(), restOnly(1, 'two', null), restOnly(undefined)); + restParameterResult.push(restPrefix(), restPrefix(1), restPrefix(1, 2), restPrefix(1, 2, 3, 4)); + const left = restCaptured(10, 'left'); + const right = restCaptured(20, 'right'); + restParameterResult.push(left(), right(), left()); + restParameterResult.push(restVarRedeclared(1)(), restVarRedeclared(2)(), restHoisted(1)()); + restParameterResult.push(restDefaults()(), restDefaults(5, 6, 7)()); + restParameterResult.push(restArgumentSnapshot(1, 2, 3), strictRestArguments(1, 2, 3)); + restParameterResult.push(restArrow(), restArrow(1, 2), restPattern(1, 2, 3)); + restParameterResult.push(restMutation(1, 2, 3), restObjectIdentity(restIdentityObject, restIdentityArray)); + restParameterResult.push(restLegacy(1, 2, 3), restEval(3, 4, 5), restWith(1, 2)); +} + +for (const parameters of [ + ['first', '...first', 'return first;'], + ['first', 'first', '...tail', 'return tail;'], + ['...values', 'last', 'return values;'], + ['...values = []', 'return values;'], + ['...values', 'let values = 1; return values;'], +]) { + try { Function(...parameters); restParameterResult.push('accepted'); } + catch (error) { restParameterResult.push(error.name); } +} diff --git a/tests/Unit/Bytecode/fixtures/rest-parameters.json b/tests/Unit/Bytecode/fixtures/rest-parameters.json new file mode 100644 index 00000000..530c2526 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/rest-parameters.json @@ -0,0 +1,358 @@ +[ + [], + [ + 1, + "two", + null + ], + [ + null + ], + [ + null, + null, + [] + ], + [ + 1, + null, + [] + ], + [ + 1, + 2, + [] + ], + [ + 1, + 2, + [ + 3, + 4 + ] + ], + [ + "left", + 10 + ], + [ + "right", + 20 + ], + [ + "left", + 10, + 11 + ], + [ + 1, + "added" + ], + [ + 2, + "added" + ], + 9, + [ + 5, + [] + ], + [ + 7, + [ + 6, + 7 + ] + ], + [ + 8, + [ + 9, + 3 + ], + 1, + 2 + ], + [ + 8, + [ + 9, + 3 + ], + 1, + 2 + ], + [], + [ + 1, + 2 + ], + [ + 1, + 2 + ], + [ + 2, + [ + "changed", + 3 + ] + ], + [ + 2, + true, + true, + true + ], + [ + 3, + 1, + 2, + 1, + [ + 2, + 3 + ] + ], + 5, + 2, + [], + [ + 1, + "two", + null + ], + [ + null + ], + [ + null, + null, + [] + ], + [ + 1, + null, + [] + ], + [ + 1, + 2, + [] + ], + [ + 1, + 2, + [ + 3, + 4 + ] + ], + [ + "left", + 10 + ], + [ + "right", + 20 + ], + [ + "left", + 10, + 11 + ], + [ + 1, + "added" + ], + [ + 2, + "added" + ], + 9, + [ + 5, + [] + ], + [ + 7, + [ + 6, + 7 + ] + ], + [ + 8, + [ + 9, + 3 + ], + 1, + 2 + ], + [ + 8, + [ + 9, + 3 + ], + 1, + 2 + ], + [], + [ + 1, + 2 + ], + [ + 1, + 2 + ], + [ + 2, + [ + "changed", + 3 + ] + ], + [ + 2, + true, + true, + true + ], + [ + 3, + 1, + 2, + 1, + [ + 2, + 3 + ] + ], + 5, + 2, + [], + [ + 1, + "two", + null + ], + [ + null + ], + [ + null, + null, + [] + ], + [ + 1, + null, + [] + ], + [ + 1, + 2, + [] + ], + [ + 1, + 2, + [ + 3, + 4 + ] + ], + [ + "left", + 10 + ], + [ + "right", + 20 + ], + [ + "left", + 10, + 11 + ], + [ + 1, + "added" + ], + [ + 2, + "added" + ], + 9, + [ + 5, + [] + ], + [ + 7, + [ + 6, + 7 + ] + ], + [ + 8, + [ + 9, + 3 + ], + 1, + 2 + ], + [ + 8, + [ + 9, + 3 + ], + 1, + 2 + ], + [], + [ + 1, + 2 + ], + [ + 1, + 2 + ], + [ + 2, + [ + "changed", + 3 + ] + ], + [ + 2, + true, + true, + true + ], + [ + 3, + 1, + 2, + 1, + [ + 2, + 3 + ] + ], + 5, + 2, + "SyntaxError", + "SyntaxError", + "SyntaxError", + "SyntaxError", + "SyntaxError" +] From cf102e6d8292d09ad2b116429a7ee0079ca748f9 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 01:34:56 +0200 Subject: [PATCH 51/99] Align while checkpoints across interpreter and compiled tiers --- src/Bytecode/Parts/CompilerStatement.php | 2 +- src/Bytecode/Parts/JsToPhpEmitStatement.php | 33 ++-- src/Bytecode/VM.php | 16 ++ tests/Unit/Bytecode/WhileCheckpointTest.php | 175 ++++++++++++++++++++ 4 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 tests/Unit/Bytecode/WhileCheckpointTest.php diff --git a/src/Bytecode/Parts/CompilerStatement.php b/src/Bytecode/Parts/CompilerStatement.php index b4673b9c..eabff601 100644 --- a/src/Bytecode/Parts/CompilerStatement.php +++ b/src/Bytecode/Parts/CompilerStatement.php @@ -532,9 +532,9 @@ private function compileWhile(WhileStatement $node): void $loopId = $this->loopCount++; $this->emit(Op::LOOP_INIT, $loopId); $loopStart = count($this->code); + $this->emit(Op::LOOP_TICK, $loopId); $this->compileExpression($node->test); $jmpExit = $this->emitJump(Op::JUMP_IF_FALSE); - $this->emit(Op::LOOP_TICK, $loopId); $this->loopStack[] = ['continue' => -1, 'breaks' => [], 'continues' => []]; $this->compileStatement($node->body); $continueTarget = count($this->code); diff --git a/src/Bytecode/Parts/JsToPhpEmitStatement.php b/src/Bytecode/Parts/JsToPhpEmitStatement.php index 2dcd9536..60bd5de4 100644 --- a/src/Bytecode/Parts/JsToPhpEmitStatement.php +++ b/src/Bytecode/Parts/JsToPhpEmitStatement.php @@ -103,6 +103,7 @@ private function emitPrologue(array $params): void private function emitLoopTick(string $counter): void { + $this->emitLine('if ($interp->hasExecutionBudget()) { $interp->checkBudget(); }'); $this->emitLine('if (++' . $counter . ' > $interp->getMaxLoopIterations()) {'); $this->indentLevel++; $this->emitLine('throw new \\Phasis\\Exceptions\\InternalError("Maximum loop iterations exceeded");'); @@ -355,28 +356,18 @@ private function emitStatement(Node $node): void $test = $this->emitExpression($node->test); $testPending = $this->pendingStatements; $this->pendingStatements = $savedPending; - if ($testPending === []) { - $this->emitLine('while (' . $test . ') {'); - $this->indentLevel++; - $this->emitLoopTick($loopCounter); - $this->emitStatement($node->body); - $this->indentLevel--; - $this->emitLine('}'); - } else { - // Hoist test-pending statements into the loop body so - // free-var lookups and lifted calls inside the test - // condition no longer kick the function out of the JIT. - $this->emitLine('while (true) {'); - $this->indentLevel++; - foreach ($testPending as $line) { - $this->emitLine($line); - } - $this->emitLine('if (!(' . $test . ')) { break; }'); - $this->emitLoopTick($loopCounter); - $this->emitStatement($node->body); - $this->indentLevel--; - $this->emitLine('}'); + // The interpreter checks the checkpoint before every condition, + // including its lifted calls and its final false evaluation. + $this->emitLine('while (true) {'); + $this->indentLevel++; + $this->emitLoopTick($loopCounter); + foreach ($testPending as $line) { + $this->emitLine($line); } + $this->emitLine('if (!(' . $test . ')) { break; }'); + $this->emitStatement($node->body); + $this->indentLevel--; + $this->emitLine('}'); return; } if ($node instanceof DoWhileStatement) { diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 2984523c..ee74e34d 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -817,6 +817,9 @@ public function execute( $pc += 2; break; case Op::LOOP_TICK: + if ($this->interp->hasExecutionBudget()) { + $this->interp->checkBudget(); + } if (++$loopCounts[$code[$pc + 1]] > $this->interp->getMaxLoopIterations()) { throw new InternalError('Maximum loop iterations exceeded'); } @@ -2918,6 +2921,19 @@ public function execute( throw new InternalError('VM: unknown opcode ' . $op); } } // end inner while (dispatch loop) + } catch (\Phasis\Exceptions\BudgetExceeded $e) { + // A host deadline bypasses JS handlers, but still owns the + // same inline activations that an ordinary throw unwinds. + while ($savedFramesDepth > 0) { + $sf = $savedFrames[--$savedFramesDepth]; + if ($sf->isConstruct && $sf->newObject !== null) { + $sf->newObject->forceDelete('[[NewTarget]]'); + } + $this->interp->teardownInlineVmCall($sf->callee, $sf->restore); + $this->interp->releaseInlineVmFrame(); + $sf->release(); + } + throw $e; } catch (\Phasis\Exceptions\RuntimeError | \Phasis\Exceptions\SyntaxError $e) { // Handler search — first in the current frame, then // unwinding through `$savedFrames` if necessary (the diff --git a/tests/Unit/Bytecode/WhileCheckpointTest.php b/tests/Unit/Bytecode/WhileCheckpointTest.php new file mode 100644 index 00000000..5a1f73c5 --- /dev/null +++ b/tests/Unit/Bytecode/WhileCheckpointTest.php @@ -0,0 +1,175 @@ + */ + public static function loopModes(): iterable + { + foreach ([false, true] as $ast) { + foreach ([false, true] as $continue) { + yield ($ast ? 'ast' : 'bytecode') . ($continue ? '-continue' : '-backedge') => [$ast, $continue]; + } + } + } + + #[DataProvider('loopModes')] + public function testWhileLimitPrecedesTheFinalFalseCondition(bool $ast, bool $continue): void + { + $engine = new Engine(); + if ($ast) { + $engine->setExecutionBudget(10); + } + $body = 'n++;' . ($continue ? 'continue;' : ''); + $engine->eval('var conditions = 0; function probe() { let n = 0; while ((conditions++, n < 1)) {' . $body . '} return n; } probe();'); + $function = $engine->getGlobalEnv()->get('probe'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertSame(!$ast, $function->compiled !== null); + $engine->setLimit('maxLoopIterations', 1); + self::assertSame(['Maximum loop iterations exceeded', 1], $engine->eval(<<<'JS' +conditions = 0; +var result; +try { result = probe(); } catch (error) { result = error.message; } +[result, conditions]; +JS)); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } + + /** @return iterable */ + public static function budgetModes(): iterable + { + foreach ([false, true] as $ast) { + foreach (['while', 'do-while'] as $loop) { + foreach ([1, 1000] as $limit) { + yield ($ast ? 'ast-' : 'bytecode-') . $loop . '-' . $limit => [$ast, $loop, $limit]; + } + } + } + } + + #[DataProvider('budgetModes')] + public function testActivatedBudgetPrecedesLoopLimitsAndTheNextBody(bool $ast, string $loop, int $limit): void + { + $engine = new Engine(); + if ($ast) { + $engine->setExecutionBudget(10); + } + $expire = false; + $engine->setGlobal('expireBudget', static function () use ($engine, &$expire): void { + if ($expire) { + $engine->setExecutionBudget(-1); + } + }); + $body = '{ n++; iterations++; expireBudget(); }'; + $statement = $loop === 'while' ? 'while (n < 2) ' . $body : 'do ' . $body . ' while (n < 2);'; + $engine->eval('var iterations = 0; function probe() { let n = 0; ' . $statement . ' return n; } probe();'); + $function = $engine->getGlobalEnv()->get('probe'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertSame(!$ast, $function->compiled !== null); + $engine->eval('iterations = 0'); + $engine->setLimit('maxLoopIterations', $limit); + $expire = true; + $this->expectException(BudgetExceeded::class); + try { + $engine->eval('probe()'); + } finally { + self::assertSame(1.0, $engine->getGlobalEnv()->get('iterations')->value); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } + } + + /** @return iterable */ + public static function phpModes(): iterable + { + yield 'backedge' => [false]; + yield 'continue' => [true]; + } + + #[DataProvider('phpModes')] + public function testGeneratedPhpChecksBeforeConditionPreludes(bool $continue): void + { + $engine = new Engine(); + $body = 'n++;' . ($continue ? 'continue;' : ''); + $engine->eval(<<<'JS' +var conditions = 0; +function condition(n) { conditions++; return n < 1 ? 1 : 0; } +JS); + $engine->eval('function probe() { let n = 0; while (condition(n)) {' . $body . '} return n; } probe();'); + $function = $engine->getGlobalEnv()->get('probe'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + $engine->eval('conditions = 0'); + $engine->setLimit('maxLoopIterations', 1); + $this->expectException(InternalError::class); + try { + ($function->phpCompiled)([], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), []); + } finally { + self::assertSame(1.0, $engine->getGlobalEnv()->get('conditions')->value); + } + } + + public function testGeneratedPhpBudgetPrecedesTheIterationLimit(): void + { + $engine = new Engine(); + $expire = false; + $engine->setGlobal('expireBudget', static function () use ($engine, &$expire): void { + if ($expire) { + $engine->setExecutionBudget(-1); + } + }); + $engine->eval('function probe() { let n = 0; while (n < 2) { n++; expireBudget(); } return n; } probe();'); + $function = $engine->getGlobalEnv()->get('probe'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + $engine->setLimit('maxLoopIterations', 1); + $expire = true; + $this->expectException(BudgetExceeded::class); + ($function->phpCompiled)([], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), []); + } + + public function testBudgetAbortUnwindsInlineFramesAndBypassesJsCatch(): void + { + $engine = new Engine(); + $expire = false; + $engine->setGlobal('expireBudget', static function () use ($engine, &$expire): void { + if ($expire) { + $engine->setExecutionBudget(-1); + } + }); + self::assertSame(2, $engine->eval(<<<'JS' +var iterations = 0, caught = false; +function innerLoop() { let n = 0; while (n < 2) { n++; iterations++; expireBudget(); } return n; } +function middleLoop() { return innerLoop(); } +function outerLoop() { try { return middleLoop(); } catch (error) { caught = true; return -1; } } +outerLoop(); +JS)); + foreach (['innerLoop', 'middleLoop', 'outerLoop'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name); + } + $expire = true; + try { + $engine->eval('outerLoop()'); + self::fail('The expired host budget was ignored.'); + } catch (BudgetExceeded) { + self::assertFalse($engine->getGlobalEnv()->get('caught')->value); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } + $engine->setExecutionBudget(null); + $expire = false; + self::assertSame([2, false], $engine->eval('[outerLoop(), caught]')); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } +} From e73f22443ab72625c8299fe9f1c87ef9755fc653 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:02:00 +0200 Subject: [PATCH 52/99] Separate loop deadlines from successful iteration counts --- src/Bytecode/Op.php | 2 + src/Bytecode/Parts/CompilerStatement.php | 5 +- src/Bytecode/Parts/JsToPhpEmitStatement.php | 56 ++++----- src/Bytecode/VM.php | 5 +- src/Runtime/Parts/StatementExecution.php | 7 +- .../Bytecode/LoopCheckpointContractTest.php | 115 ++++++++++++++++++ tests/Unit/Bytecode/WhileCheckpointTest.php | 61 ++++++++-- 7 files changed, 206 insertions(+), 45 deletions(-) create mode 100644 tests/Unit/Bytecode/LoopCheckpointContractTest.php diff --git a/src/Bytecode/Op.php b/src/Bytecode/Op.php index f1084266..13008dbe 100644 --- a/src/Bytecode/Op.php +++ b/src/Bytecode/Op.php @@ -188,6 +188,7 @@ final class Op public const LOOP_INIT = 120; public const LOOP_TICK = 121; + public const CHECK_BUDGET = 126; // Host deadline checkpoint, independent of the body iteration count. public const ITERATOR_INIT = 122; // L: acquire an iterator and cached next in adjacent private slots. public const ITERATOR_NEXT = 123; // L I J: check loop limits, push the next value or branch when done. public const ITERATOR_CLOSE = 124; // L L L: close with the pending completion and value. @@ -200,6 +201,7 @@ public static function operandCount(int $op): int { switch ($op) { // 0-operand opcodes + case self::CHECK_BUDGET: case self::POP: case self::DUP: case self::LOAD_UNDEF: diff --git a/src/Bytecode/Parts/CompilerStatement.php b/src/Bytecode/Parts/CompilerStatement.php index eabff601..36e8dbba 100644 --- a/src/Bytecode/Parts/CompilerStatement.php +++ b/src/Bytecode/Parts/CompilerStatement.php @@ -470,6 +470,7 @@ private function compileFor(ForStatement $node): void $loopId = $this->loopCount++; $this->emit(Op::LOOP_INIT, $loopId); $loopStart = count($this->code); + $this->emit(Op::CHECK_BUDGET); // Test. Try the fused JUMP_IF_LOCAL_GE_CONST shortcut first // for the canonical `for (let i = 0; i < N; i++)` pattern. $jmpExit = -1; @@ -532,9 +533,10 @@ private function compileWhile(WhileStatement $node): void $loopId = $this->loopCount++; $this->emit(Op::LOOP_INIT, $loopId); $loopStart = count($this->code); - $this->emit(Op::LOOP_TICK, $loopId); + $this->emit(Op::CHECK_BUDGET); $this->compileExpression($node->test); $jmpExit = $this->emitJump(Op::JUMP_IF_FALSE); + $this->emit(Op::LOOP_TICK, $loopId); $this->loopStack[] = ['continue' => -1, 'breaks' => [], 'continues' => []]; $this->compileStatement($node->body); $continueTarget = count($this->code); @@ -559,6 +561,7 @@ private function compileDoWhile(DoWhileStatement $node): void $loopId = $this->loopCount++; $this->emit(Op::LOOP_INIT, $loopId); $loopStart = count($this->code); + $this->emit(Op::CHECK_BUDGET); $this->emit(Op::LOOP_TICK, $loopId); $this->loopStack[] = ['continue' => -1, 'breaks' => [], 'continues' => []]; $this->compileStatement($node->body); diff --git a/src/Bytecode/Parts/JsToPhpEmitStatement.php b/src/Bytecode/Parts/JsToPhpEmitStatement.php index 60bd5de4..14a51d61 100644 --- a/src/Bytecode/Parts/JsToPhpEmitStatement.php +++ b/src/Bytecode/Parts/JsToPhpEmitStatement.php @@ -101,9 +101,13 @@ private function emitPrologue(array $params): void } } - private function emitLoopTick(string $counter): void + private function emitLoopBudgetCheck(): void { $this->emitLine('if ($interp->hasExecutionBudget()) { $interp->checkBudget(); }'); + } + + private function emitLoopTick(string $counter): void + { $this->emitLine('if (++' . $counter . ' > $interp->getMaxLoopIterations()) {'); $this->indentLevel++; $this->emitLine('throw new \\Phasis\\Exceptions\\InternalError("Maximum loop iterations exceeded");'); @@ -315,37 +319,23 @@ private function emitStatement(Node $node): void $updatePending = $this->pendingStatements; } $this->pendingStatements = $savedPending; - if ($testPending === [] && $updatePending === []) { - // Cheap path: clean test + update, emit a plain `while`. - $this->emitLine('while (' . $test . ') {'); - $this->indentLevel++; - $this->emitLoopTick($loopCounter); - $this->emitStatement($node->body); - if ($update !== null) { - $this->emitLine($update . ';'); - } - $this->indentLevel--; - $this->emitLine('}'); - } else { - // Rewrite shape: while (true) { pending; if (!test) - // break; body; update_pending; update; }. - $this->emitLine('while (true) {'); - $this->indentLevel++; - foreach ($testPending as $line) { + $this->emitLine('while (true) {'); + $this->indentLevel++; + $this->emitLoopBudgetCheck(); + foreach ($testPending as $line) { + $this->emitLine($line); + } + $this->emitLine('if (!(' . $test . ')) { break; }'); + $this->emitLoopTick($loopCounter); + $this->emitStatement($node->body); + if ($update !== null) { + foreach ($updatePending as $line) { $this->emitLine($line); } - $this->emitLine('if (!(' . $test . ')) { break; }'); - $this->emitLoopTick($loopCounter); - $this->emitStatement($node->body); - if ($update !== null) { - foreach ($updatePending as $line) { - $this->emitLine($line); - } - $this->emitLine($update . ';'); - } - $this->indentLevel--; - $this->emitLine('}'); + $this->emitLine($update . ';'); } + $this->indentLevel--; + $this->emitLine('}'); return; } if ($node instanceof WhileStatement) { @@ -356,15 +346,16 @@ private function emitStatement(Node $node): void $test = $this->emitExpression($node->test); $testPending = $this->pendingStatements; $this->pendingStatements = $savedPending; - // The interpreter checks the checkpoint before every condition, - // including its lifted calls and its final false evaluation. + // A final false condition still checks the deadline, but consumes + // no body iteration from the configured loop limit. $this->emitLine('while (true) {'); $this->indentLevel++; - $this->emitLoopTick($loopCounter); + $this->emitLoopBudgetCheck(); foreach ($testPending as $line) { $this->emitLine($line); } $this->emitLine('if (!(' . $test . ')) { break; }'); + $this->emitLoopTick($loopCounter); $this->emitStatement($node->body); $this->indentLevel--; $this->emitLine('}'); @@ -380,6 +371,7 @@ private function emitStatement(Node $node): void $this->pendingStatements = $savedPending; $this->emitLine('do {'); $this->indentLevel++; + $this->emitLoopBudgetCheck(); $this->emitLoopTick($loopCounter); $this->emitStatement($node->body); if ($testPending !== []) { diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index ee74e34d..93b42199 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -816,10 +816,13 @@ public function execute( $loopCounts[$code[$pc + 1]] = 0; $pc += 2; break; - case Op::LOOP_TICK: + case Op::CHECK_BUDGET: if ($this->interp->hasExecutionBudget()) { $this->interp->checkBudget(); } + $pc++; + break; + case Op::LOOP_TICK: if (++$loopCounts[$code[$pc + 1]] > $this->interp->getMaxLoopIterations()) { throw new InternalError('Maximum loop iterations exceeded'); } diff --git a/src/Runtime/Parts/StatementExecution.php b/src/Runtime/Parts/StatementExecution.php index 5a21ee1f..56804128 100644 --- a/src/Runtime/Parts/StatementExecution.php +++ b/src/Runtime/Parts/StatementExecution.php @@ -2334,14 +2334,13 @@ private function execWhileStatement(WhileStatement $node, Environment $env, ?str if ($this->budget !== null) { $this->checkBudget(); } - if (++$iterations > $this->maxLoopIterations) { - throw new InternalError('Maximum loop iterations exceeded'); - } - $test = $this->evaluate($node->test, $env); if (!TypeConversion::toBoolean($test)) { break; } + if (++$iterations > $this->maxLoopIterations) { + throw new InternalError('Maximum loop iterations exceeded'); + } $completion = $this->executeStatement($node->body, $env); diff --git a/tests/Unit/Bytecode/LoopCheckpointContractTest.php b/tests/Unit/Bytecode/LoopCheckpointContractTest.php new file mode 100644 index 00000000..69225f36 --- /dev/null +++ b/tests/Unit/Bytecode/LoopCheckpointContractTest.php @@ -0,0 +1,115 @@ + */ + public static function tiersAndLoops(): iterable + { + foreach (['ast', 'bytecode', 'php'] as $tier) { + foreach (['for', 'while', 'do-while'] as $loop) { + yield $tier . '-' . $loop => [$tier, $loop]; + } + } + } + + #[DataProvider('tiersAndLoops')] + public function testExactAndZeroLimitsCountOnlyExecutedBodies(string $tier, string $loop): void + { + $engine = new Engine(); + $function = $this->prepare($engine, $tier, $loop, 'count++;'); + $engine->setLimit('maxLoopIterations', 5); + self::assertSame(5.0, $this->invoke($engine, $function, $tier, 5)); + $engine->setLimit('maxLoopIterations', 0); + if ($loop === 'do-while') { + $this->expectException(RuntimeError::class); + $this->invoke($engine, $function, $tier, 0); + } else { + self::assertSame(0.0, $this->invoke($engine, $function, $tier, 0)); + } + } + + #[DataProvider('tiersAndLoops')] + public function testBudgetCheckpointAroundTheFinalFalseCondition(string $tier, string $loop): void + { + $engine = new Engine(); + $expire = false; + $calls = 0; + $engine->setGlobal('expireBudget', static function () use ($engine, &$expire, &$calls): void { + if ($expire) { + $calls++; + $engine->setExecutionBudget(-1); + } + }); + $function = $this->prepare($engine, $tier, $loop, 'count++; expireBudget();'); + $engine->setLimit('maxLoopIterations', 1); + $expire = true; + $exceeded = false; + $result = null; + try { + $result = $this->invoke($engine, $function, $tier, 1); + } catch (BudgetExceeded) { + $exceeded = true; + } + self::assertSame($loop !== 'do-while', $exceeded); + if ($loop === 'do-while') { + self::assertSame(1.0, $result); + } + self::assertSame(1, $calls); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + $engine->setExecutionBudget(null); + } + + private function prepare(Engine $engine, string $tier, string $loop, string $body): JsFunction + { + if ($tier === 'ast') { + $engine->setExecutionBudget(10); + } + $statement = match ($loop) { + 'for' => 'for (; count < amount;) {' . $body . '}', + 'while' => 'while (count < amount) {' . $body . '}', + default => 'do {' . $body . '} while (count < amount);', + }; + if ($tier === 'bytecode') { + $statement = 'try {' . $statement . '} finally {}'; + } + $engine->eval('function probe(amount) { let count = 0; ' . $statement . ' return count; } probe(1);'); + $function = $engine->getGlobalEnv()->get('probe'); + self::assertInstanceOf(JsFunction::class, $function); + if ($tier === 'php') { + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + } else { + self::assertSame($tier === 'bytecode', $function->compiled !== null); + self::assertNull($function->phpCompiled); + } + return $function; + } + + private function invoke(Engine $engine, JsFunction $function, string $tier, int $amount): float + { + if ($tier === 'php') { + $result = ($function->phpCompiled)( + [JsNumber::of($amount)], + JsUndefined::instance(), + $function->getClosure(), + $engine->getInterpreter(), + $function->phpCompiledNodes, + ); + self::assertInstanceOf(JsNumber::class, $result); + return $result->value; + } + return (float) $engine->eval('probe(' . $amount . ')'); + } +} diff --git a/tests/Unit/Bytecode/WhileCheckpointTest.php b/tests/Unit/Bytecode/WhileCheckpointTest.php index 5a1f73c5..65e16e4e 100644 --- a/tests/Unit/Bytecode/WhileCheckpointTest.php +++ b/tests/Unit/Bytecode/WhileCheckpointTest.php @@ -8,6 +8,7 @@ use Phasis\Exceptions\BudgetExceeded; use Phasis\Exceptions\InternalError; use Phasis\Value\JsFunction; +use Phasis\Value\JsNumber; use Phasis\Value\JsUndefined; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -25,7 +26,7 @@ public static function loopModes(): iterable } #[DataProvider('loopModes')] - public function testWhileLimitPrecedesTheFinalFalseCondition(bool $ast, bool $continue): void + public function testWhileLimitCountsOnlySuccessfulIterations(bool $ast, bool $continue): void { $engine = new Engine(); if ($ast) { @@ -37,7 +38,7 @@ public function testWhileLimitPrecedesTheFinalFalseCondition(bool $ast, bool $co self::assertInstanceOf(JsFunction::class, $function); self::assertSame(!$ast, $function->compiled !== null); $engine->setLimit('maxLoopIterations', 1); - self::assertSame(['Maximum loop iterations exceeded', 1], $engine->eval(<<<'JS' + self::assertSame([1, 2], $engine->eval(<<<'JS' conditions = 0; var result; try { result = probe(); } catch (error) { result = error.message; } @@ -50,7 +51,7 @@ public function testWhileLimitPrecedesTheFinalFalseCondition(bool $ast, bool $co public static function budgetModes(): iterable { foreach ([false, true] as $ast) { - foreach (['while', 'do-while'] as $loop) { + foreach (['while', 'do-while', 'for'] as $loop) { foreach ([1, 1000] as $limit) { yield ($ast ? 'ast-' : 'bytecode-') . $loop . '-' . $limit => [$ast, $loop, $limit]; } @@ -72,12 +73,17 @@ public function testActivatedBudgetPrecedesLoopLimitsAndTheNextBody(bool $ast, s } }); $body = '{ n++; iterations++; expireBudget(); }'; - $statement = $loop === 'while' ? 'while (n < 2) ' . $body : 'do ' . $body . ' while (n < 2);'; - $engine->eval('var iterations = 0; function probe() { let n = 0; ' . $statement . ' return n; } probe();'); + $condition = '(conditions++, n < 2)'; + $statement = match ($loop) { + 'while' => 'while (' . $condition . ') ' . $body, + 'do-while' => 'do ' . $body . ' while (' . $condition . ');', + default => 'for (; ' . $condition . ';) ' . $body, + }; + $engine->eval('var iterations = 0, conditions = 0; function probe() { let n = 0; ' . $statement . ' return n; } probe();'); $function = $engine->getGlobalEnv()->get('probe'); self::assertInstanceOf(JsFunction::class, $function); self::assertSame(!$ast, $function->compiled !== null); - $engine->eval('iterations = 0'); + $engine->eval('iterations = 0; conditions = 0;'); $engine->setLimit('maxLoopIterations', $limit); $expire = true; $this->expectException(BudgetExceeded::class); @@ -85,6 +91,7 @@ public function testActivatedBudgetPrecedesLoopLimitsAndTheNextBody(bool $ast, s $engine->eval('probe()'); } finally { self::assertSame(1.0, $engine->getGlobalEnv()->get('iterations')->value); + self::assertSame(1.0, $engine->getGlobalEnv()->get('conditions')->value); self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); } } @@ -97,7 +104,7 @@ public static function phpModes(): iterable } #[DataProvider('phpModes')] - public function testGeneratedPhpChecksBeforeConditionPreludes(bool $continue): void + public function testGeneratedPhpCountsOnlySuccessfulIterations(bool $continue): void { $engine = new Engine(); $body = 'n++;' . ($continue ? 'continue;' : ''); @@ -111,6 +118,10 @@ function condition(n) { conditions++; return n < 1 ? 1 : 0; } self::assertInstanceOf(\Closure::class, $function->phpCompiled); $engine->eval('conditions = 0'); $engine->setLimit('maxLoopIterations', 1); + self::assertSame(1.0, ($function->phpCompiled)([], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), [])->value); + self::assertSame(2.0, $engine->getGlobalEnv()->get('conditions')->value); + $engine->eval('conditions = 0'); + $engine->setLimit('maxLoopIterations', 0); $this->expectException(InternalError::class); try { ($function->phpCompiled)([], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), []); @@ -119,6 +130,42 @@ function condition(n) { conditions++; return n < 1 ? 1 : 0; } } } + /** @return iterable */ + public static function emptyLoopTiers(): iterable + { + foreach (['ast', 'bytecode', 'php'] as $tier) { + yield $tier => [$tier]; + } + } + + #[DataProvider('emptyLoopTiers')] + public function testZeroLimitPermitsAnInitiallyFalseLoop(string $tier): void + { + $engine = new Engine(); + if ($tier === 'ast') { + $engine->setExecutionBudget(10); + } + $engine->eval('var conditions = 0; function condition(n) { conditions++; return n; }'); + $loop = 'while (condition(n)) { n--; }'; + if ($tier === 'bytecode') { + $loop = 'try {' . $loop . '} finally {}'; + } + $engine->eval('function probe(n) {' . $loop . ' return n; } probe(1);'); + $function = $engine->getGlobalEnv()->get('probe'); + self::assertInstanceOf(JsFunction::class, $function); + $engine->eval('conditions = 0'); + $engine->setLimit('maxLoopIterations', 0); + if ($tier === 'php') { + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + $result = ($function->phpCompiled)([JsNumber::of(0)], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), []); + self::assertSame(0.0, $result->value); + } else { + self::assertSame($tier === 'bytecode', $function->compiled !== null); + self::assertSame(0, $engine->eval('probe(0)')); + } + self::assertSame(1.0, $engine->getGlobalEnv()->get('conditions')->value); + } + public function testGeneratedPhpBudgetPrecedesTheIterationLimit(): void { $engine = new Engine(); From 71904167a1f730d461a5ad3205bc48582f0b5997 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:10:44 +0200 Subject: [PATCH 53/99] Preserve double precision in generated numeric literals --- src/Bytecode/Parts/JsToPhpEmitExpression.php | 13 +-- src/Bytecode/PhpNumericLiteral.php | 32 ++++++ tests/Unit/Bytecode/NumericLiteralTest.php | 106 +++++++++++++++++++ 3 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 src/Bytecode/PhpNumericLiteral.php create mode 100644 tests/Unit/Bytecode/NumericLiteralTest.php diff --git a/src/Bytecode/Parts/JsToPhpEmitExpression.php b/src/Bytecode/Parts/JsToPhpEmitExpression.php index 9bce7dc1..2d9566a7 100644 --- a/src/Bytecode/Parts/JsToPhpEmitExpression.php +++ b/src/Bytecode/Parts/JsToPhpEmitExpression.php @@ -28,6 +28,7 @@ use Phasis\Ast\Statement\WhileStatement; use Phasis\Value\JsFunction; use Phasis\Bytecode\Bailout; +use Phasis\Bytecode\PhpNumericLiteral; /** * JsToPhp trait part: JsToPhpEmitExpression. Composed into JsToPhp via @@ -170,17 +171,7 @@ private function emitExpression(Node $node): string { if ($node instanceof Literal) { if (is_int($node->value) || is_float($node->value)) { - // Emit numerical literals with a .0 suffix when they - // would otherwise look like ints to PHP. JS's `===` - // compares by value-only; PHP's `===` is type+value, - // so `(float)0 !== (int)0` in PHP. Forcing the literal - // through `(float)` keeps both sides float-typed and - // matches JS Number semantics exactly. - $f = (float) $node->value; - if (is_finite($f) && $f === (float) (int) $f) { - return $f >= 0 ? sprintf('%d.0', (int) $f) : sprintf('-%d.0', -(int) $f); - } - return (string) $f; + return PhpNumericLiteral::render((float) $node->value); } if (is_bool($node->value)) { return $node->value ? 'true' : 'false'; diff --git a/src/Bytecode/PhpNumericLiteral.php b/src/Bytecode/PhpNumericLiteral.php new file mode 100644 index 00000000..7350a3f2 --- /dev/null +++ b/src/Bytecode/PhpNumericLiteral.php @@ -0,0 +1,32 @@ + */ + public static function expressions(): array + { + return [ + '0', '-0', 'NaN', 'Infinity', '-Infinity', + '0.30000000000000004', '1.0000000000000002', '0.9999999999999999', + '5e-324', '-5e-324', '1.7976931348623157e308', '-1.7976931348623157e308', + '9007199254740991', '9007199254740992', '9007199254740994', + '9223372036854774784', '9223372036854775808', '9223372036854777856', + '-9223372036854774784', '-9223372036854775808', '-9223372036854777856', + ]; + } + + public function testCompiledNumbersMatchTheirOriginalLiteralBits(): void + { + foreach (self::expressions() as $expression) { + $engine = new Engine(); + self::assertTrue($engine->eval( + 'function literal() { return ' . $expression . '; } Object.is(literal(), (' . $expression . '));' + ), $expression); + $function = $engine->getGlobalEnv()->get('literal'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->phpCompiled, $expression . ' did not use the PHP backend'); + } + } + + public function testFormattingIgnoresPhpDisplayPrecision(): void + { + $previous = ini_get('precision'); + ini_set('precision', '3'); + try { + $engine = new Engine(); + self::assertTrue($engine->eval(<<<'JS' +function literal() { return 0.30000000000000004; } +Object.is(literal(), 0.30000000000000004); +JS)); + $function = $engine->getGlobalEnv()->get('literal'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->phpCompiled); + } finally { + ini_set('precision', $previous); + } + } + + public function testRoundTripExpressionsPreserveFiniteExtremesAndSignedZero(): void + { + foreach ( + [0.0, -0.0, 0.30000000000000004, PHP_FLOAT_MIN, PHP_FLOAT_MAX, + 5.0e-324, 9223372036854775808.0, -9223372036854775808.0, INF, -INF, NAN] as $value + ) { + $literal = PhpNumericLiteral::render($value); + $actual = eval('return ' . $literal . ';'); + self::assertIsFloat($actual, $literal); + self::assertSame(pack('E', $value), pack('E', $actual), $literal); + } + } + + public function testCompilationDoesNotRewriteOriginalAstSource(): void + { + $engine = new Engine(); + $program = (new Parser('function value() { return 0.30000000000000004; }'))->parse(); + $declaration = $program->body[0]; + self::assertInstanceOf(\Phasis\Ast\Declaration\FunctionDeclaration::class, $declaration); + $return = $declaration->body->body[0]; + self::assertInstanceOf(\Phasis\Ast\Statement\ReturnStatement::class, $return); + $literal = $return->argument; + self::assertInstanceOf(\Phasis\Ast\Expression\Literal::class, $literal); + $before = [$literal->raw, pack('E', $literal->value), $literal->cached]; + $function = new JsFunction('value', [], $declaration->body, $engine->getGlobalEnv()); + self::assertNotNull(JsToPhp::compile($function)); + self::assertSame($before, [$literal->raw, pack('E', $literal->value), $literal->cached]); + } + + public function testLocaleDecimalSeparatorsDoNotEnterGeneratedPhp(): void + { + $previous = setlocale(LC_NUMERIC, '0'); + try { + foreach (['C', 'de_DE.UTF-8', 'fr_FR.UTF-8', 'de_DE', 'fr_FR'] as $locale) { + if (setlocale(LC_NUMERIC, $locale) === false) { + continue; + } + $value = 0.30000000000000004; + $literal = PhpNumericLiteral::render($value); + self::assertStringNotContainsString(',', $literal); + self::assertSame(pack('E', $value), pack('E', eval('return ' . $literal . ';'))); + } + } finally { + setlocale(LC_NUMERIC, $previous); + } + } +} From 8ba4d1749e1cb9249d1632b493004b6e8b6d96d9 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:17:24 +0200 Subject: [PATCH 54/99] Exclude runtime JavaScript fixtures from PHP coding standards --- phpcs.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/phpcs.xml b/phpcs.xml index 2142ca65..9bf05881 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -21,6 +21,7 @@ tests/Unit/Formatter/fixtures/* tests/Unit/BuiltIn/fixtures/* tests/Unit/Bytecode/fixtures/* + tests/Unit/Runtime/fixtures/* tests/Wpt/fixtures/* tests/Wpt/testharness-shim.js tests/Wpt/upstream/* From e91c799c7e017c50570896fcbf3630d45e41e69b Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:17:46 +0200 Subject: [PATCH 55/99] Preserve object literal realms across generated calls --- src/Bytecode/Parts/JsToPhpEmitExpression.php | 11 +++ src/Bytecode/Parts/JsToPhpEmitStatement.php | 2 +- src/Runtime/Parts/ExpressionEvaluation.php | 20 ++--- tests/Unit/Runtime/ObjectLiteralRealmTest.php | 90 +++++++++++++++++++ 4 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 tests/Unit/Runtime/ObjectLiteralRealmTest.php diff --git a/src/Bytecode/Parts/JsToPhpEmitExpression.php b/src/Bytecode/Parts/JsToPhpEmitExpression.php index 2d9566a7..4e3fd8fd 100644 --- a/src/Bytecode/Parts/JsToPhpEmitExpression.php +++ b/src/Bytecode/Parts/JsToPhpEmitExpression.php @@ -724,6 +724,7 @@ private function emitNumericCallCore(CallExpression $node): ?string $boxedArgsArr = '[' . implode(', ', $boxedArgs) . ']'; $this->pendingStatements[] = $resultTemp . ' = ' . $calleeRef . '->phpCompiledNumeric !== null' + . ' && ' . $this->emitSameRealmGuard($calleeRef) . ' ? (' . $calleeRef . '->phpCompiledNumeric)(' . $argsArr . ', \\Phasis\\Value\\JsUndefined::instance(), ' . $calleeRef . '->closure, $interp, ' @@ -736,6 +737,7 @@ private function emitNumericCallCore(CallExpression $node): ?string $this->pendingStatements[] = 'if (' . $resultTemp . ' === null) {'; $this->pendingStatements[] = ' ' . $boxedResult . ' = ' . $calleeRef . '->phpCompiled !== null' + . ' && ' . $this->emitSameRealmGuard($calleeRef) . ' ? (' . $calleeRef . '->phpCompiled)(' . $boxedArgsArr . ', \\Phasis\\Value\\JsUndefined::instance(), ' . $calleeRef . '->closure, $interp, ' @@ -856,6 +858,7 @@ private function emitCallCore(CallExpression $node): string // method dispatch in this hot path. $this->pendingStatements[] = $resultTemp . ' = ' . $calleeRef . '->phpCompiled !== null' + . ' && ' . $this->emitSameRealmGuard($calleeRef) . ' ? (' . $calleeRef . '->phpCompiled)(' . $argsArr . ', \\Phasis\\Value\\JsUndefined::instance(), ' . $calleeRef . '->closure, $interp, ' @@ -865,6 +868,13 @@ private function emitCallCore(CallExpression $node): string return $resultTemp; } + /** Direct PHP dispatch cannot establish a foreign function's execution realm. */ + private function emitSameRealmGuard(string $callee): string + { + return '(' . $callee . '->realm === null || ' . $callee + . '->realm === (\\Phasis\\Engine::getCurrentInterpreter() ?? $interp)->getRealm())'; + } + /** * Lower `new Ctor(args)` where Ctor is an Identifier resolved * either as a function-typed local (from the same compile frame) @@ -987,6 +997,7 @@ private function emitMethodCallCore(CallExpression $node): string $resultTemp = $this->newTemp('mr'); $this->pendingStatements[] = $resultTemp . ' = ' . $methodTemp . '->phpCompiled !== null' + . ' && ' . $this->emitSameRealmGuard($methodTemp) . ' ? (' . $methodTemp . '->phpCompiled)(' . $argsArr . ', ' . $recv . ', ' . $methodTemp . '->closure, $interp, ' diff --git a/src/Bytecode/Parts/JsToPhpEmitStatement.php b/src/Bytecode/Parts/JsToPhpEmitStatement.php index 14a51d61..fdfc8198 100644 --- a/src/Bytecode/Parts/JsToPhpEmitStatement.php +++ b/src/Bytecode/Parts/JsToPhpEmitStatement.php @@ -524,7 +524,7 @@ private function flushPending(): void private function emitObjectLiteral(\Phasis\Ast\Expression\ObjectExpression $node): string { $temp = $this->newTemp('obj'); - $this->pendingStatements[] = $temp . ' = new \\Phasis\\Value\\JsObject();'; + $this->pendingStatements[] = $temp . ' = $interp->vmNewObject();'; foreach ($node->properties as $prop) { if (!$prop instanceof \Phasis\Ast\Expression\Property) { throw new Bailout('non-Property in object literal'); diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index bbe84629..d5573a6b 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -6072,15 +6072,10 @@ public function vmPrimitiveSetSymbol(JsValue $obj, JsSymbol $sym, JsValue $value */ public function vmNewObject(): JsObject { - if ($this->cachedObjectPrototype === null) { - if ($this->globalEnv->has('__ObjectPrototype__')) { - $p = $this->globalEnv->get('__ObjectPrototype__'); - if ($p instanceof JsObject) { - $this->cachedObjectPrototype = $p; - } - } - } - return new JsObject($this->cachedObjectPrototype); + $realmInterpreter = \Phasis\Engine::getCurrentInterpreter() ?? $this; + return new JsObject( + $realmInterpreter->cachedObjectPrototype ??= $realmInterpreter->resolveCachedPrototype('__ObjectPrototype__'), + ); } /** @@ -7281,12 +7276,7 @@ private function resolveCachedPrototype(string $name): ?JsObject private function evalObjectExpression(ObjectExpression $node, Environment $env): JsValue { - // Cache the global Object.prototype lookup. The binding is in - // globalEnv and doesn't change across an Engine instance, so - // looking it up via env-walk on every literal is wasted work. - $obj = new JsObject( - $this->cachedObjectPrototype ??= $this->resolveCachedPrototype('__ObjectPrototype__'), - ); + $obj = $this->vmNewObject(); foreach ($node->properties as $prop) { if ($prop instanceof SpreadElement) { diff --git a/tests/Unit/Runtime/ObjectLiteralRealmTest.php b/tests/Unit/Runtime/ObjectLiteralRealmTest.php new file mode 100644 index 00000000..32f1d96a --- /dev/null +++ b/tests/Unit/Runtime/ObjectLiteralRealmTest.php @@ -0,0 +1,90 @@ + */ + public static function modes(): iterable + { + yield 'compiled' => [false]; + yield 'budgeted-ast' => [true]; + } + + #[DataProvider('modes')] + public function testForeignFunctionsAndConstructorsUseTheirOwnPrototype(bool $budgeted): void + { + $foreign = new Engine(); + $foreign->eval(<<<'JS' +function foreignLiteral(callback) { return [{}, callback(), {}]; } +Object.prototype.markForeignLiteral = function () { this.observed = 31; }; +function foreignPhpLiteral(value) { + const object = {observed: 0, value: value}; + object.markForeignLiteral(); + return object.observed; +} +class ForeignRecord { constructor() { this.value = {}; } } +foreignLiteral(() => ({})); foreignPhpLiteral(1); new ForeignRecord(); +JS); + $prototype = $foreign->getGlobalEnv()->get('__ObjectPrototype__'); + self::assertInstanceOf(JsObject::class, $prototype); + $caller = new Engine(); + if ($budgeted) { + $caller->setExecutionBudget(10); + } + foreach (['foreignLiteral', 'foreignPhpLiteral', 'ForeignRecord'] as $name) { + $function = $foreign->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + $caller->getGlobalEnv()->defineVar($name, $function); + } + $caller->getGlobalEnv()->defineVar('foreignObjectPrototype', $prototype); + $caller->eval(<<<'JS' +var wrongRealmCalls = 0; +Object.prototype.markForeignLiteral = function () { this.observed = 73; wrongRealmCalls++; }; +Object.prototype.foreignMethod = foreignPhpLiteral; +function localLiteral() { return {}; } +function localStandard(value) { foreignPhpLiteral(value); return value; } +function localNumeric(value) { return foreignPhpLiteral(value) + 0; } +function localMethod(value) { + const receiver = {value: value}; + return receiver.foreignMethod(value) + 0; +} +localLiteral(); +JS); + for ($pass = 0; $pass < 3; $pass++) { + self::assertSame([true, true, true, true, true, true, 1, 31, 31, 0], $caller->eval(<<<'JS' +var values = foreignLiteral(localLiteral); +[Object.getPrototypeOf(values[0]) === foreignObjectPrototype, + Object.getPrototypeOf(values[1]) === Object.prototype, + Object.getPrototypeOf(values[2]) === foreignObjectPrototype, + Object.getPrototypeOf(new ForeignRecord().value) === foreignObjectPrototype, + foreignPhpLiteral(1) === 31, + Object.getPrototypeOf(localLiteral()) === Object.prototype, + localStandard(1), localNumeric(1), localMethod(1), wrongRealmCalls]; +JS)); + } + $phpFunction = $foreign->getGlobalEnv()->get('foreignPhpLiteral'); + self::assertInstanceOf(JsFunction::class, $phpFunction); + self::assertInstanceOf(\Closure::class, $phpFunction->phpCompiled); + self::assertInstanceOf(\Closure::class, $phpFunction->phpCompiledNumeric); + $phpFunction->phpCompiledNumeric = null; + self::assertSame([31, 0], $caller->eval('[localNumeric(1), wrongRealmCalls]')); + if (!$budgeted) { + foreach (['localStandard', 'localNumeric', 'localMethod'] as $name) { + $wrapper = $caller->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $wrapper); + self::assertInstanceOf(\Closure::class, $wrapper->phpCompiled, $name); + } + } + self::assertSame(0, $caller->getInterpreter()->getCallStack()->depth()); + self::assertSame(0, $foreign->getInterpreter()->getCallStack()->depth()); + } +} From de8262e1b4be3de095d9b66667cb11473770acb5 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:28:22 +0200 Subject: [PATCH 56/99] Compile guarded class constructor bodies with shared super semantics --- src/Bytecode/Compiler.php | 56 +++- src/Bytecode/Parts/CompilerExpression.php | 6 + tests/Unit/Bytecode/ClassConstructorTest.php | 153 ++++++++++ .../Bytecode/fixtures/class-constructors.js | 158 ++++++++++ .../Bytecode/fixtures/class-constructors.json | 275 ++++++++++++++++++ 5 files changed, 642 insertions(+), 6 deletions(-) create mode 100644 tests/Unit/Bytecode/ClassConstructorTest.php create mode 100644 tests/Unit/Bytecode/fixtures/class-constructors.js create mode 100644 tests/Unit/Bytecode/fixtures/class-constructors.json diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index 7ecec561..2adfac24 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -103,6 +103,8 @@ final class Compiler private bool $needsArguments = false; + private ?CallExpression $constructorSuperCall = null; + /** @var array Captured function-scope bindings and declaration kinds. */ private array $capturedLocals = []; @@ -174,7 +176,7 @@ final class Compiler */ private array $classNodes = []; - /** @var list Program expressions that need complete interpreter reference semantics. */ + /** @var list Expressions whose live bindings remain in the frame environment. */ private array $interpretedExpressions = []; /** @@ -295,10 +297,10 @@ public function compile(JsFunction $fn): CompiledFunction private function compileFunction(JsFunction $fn): CompiledFunction { - if ($fn->isAsync() || $fn->isNative() || $fn->isClassConstructor()) { + if ($fn->isAsync() || $fn->isNative()) { throw new CompilerBailout('non-ordinary function kind'); } - $this->thisFromFrame = !$fn->isArrow() && !$fn->isGenerator(); + $this->thisFromFrame = !$fn->isArrow() && !$fn->isGenerator() && !$fn->isDerivedConstructor(); // Generators get a stricter bailout: only "simple" bodies // (no yield* delegation, no try/catch/finally containing // yield, not an async generator) can be lowered to the @@ -315,7 +317,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction $body = $fn->getBody(); $functionStrict = $fn->isStrict() || ($body instanceof BlockStatement && self::programHasUseStrictDirective($body->body)); - $this->tailCallsEnabled = $functionStrict && !$fn->isGenerator(); + $this->tailCallsEnabled = $functionStrict && !$fn->isGenerator() && !$fn->isClassConstructor(); // Unmapped arguments and zero-parameter ordinary functions can use // the interpreter's existing arguments object without slot aliases. // Sloppy mapped parameter lists retain the interpreter path. @@ -356,6 +358,10 @@ private function compileFunction(JsFunction $fn): CompiledFunction $this->paramSlots[] = $slot; } + if ($fn->isDerivedConstructor()) { + $this->prepareConstructorSuperCall($body); + } + if ($isExpressionBody) { $this->collectCapturedLocals($body); // Arrow expression body: nothing to pre-walk (no var @@ -380,7 +386,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction nestedFns: $this->nestedFns, needsThis: $needsEnvThis, needsArgsBinding: $this->capturedLocals !== [] || $this->needsArguments, - canSkipEnvAlloc: !$needsEnvThis && !$this->parametersFromEnvironment + canSkipEnvAlloc: !$fn->isClassConstructor() && !$needsEnvThis && !$this->parametersFromEnvironment && $this->capturedLocals === [] && !$this->needsArguments, parametersFromEnvironment: $this->parametersFromEnvironment, hasTailCalls: $this->hasTailCalls, @@ -399,6 +405,11 @@ private function compileFunction(JsFunction $fn): CompiledFunction throw new CompilerBailout('local arguments binding'); } $this->collectCapturedLocals($body); + foreach ($this->constructorSuperCall->arguments ?? [] as $argument) { + if ($argument instanceof Identifier) { + $this->capturedLocals[$argument->name] ??= 'parameter'; + } + } // TDZ guard: bail if any let/const name appears in source // BEFORE its declaration. @@ -436,7 +447,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction nestedFns: $this->nestedFns, needsThis: $needsEnvThis, needsArgsBinding: $this->capturedLocals !== [] || $this->needsArguments, - canSkipEnvAlloc: !$needsEnvThis && !$this->parametersFromEnvironment + canSkipEnvAlloc: !$fn->isClassConstructor() && !$needsEnvThis && !$this->parametersFromEnvironment && $this->capturedLocals === [] && $this->nestedFns === [] && !$this->needsArguments, parametersFromEnvironment: $this->parametersFromEnvironment, @@ -445,11 +456,44 @@ private function compileFunction(JsFunction $fn): CompiledFunction ); $cf->handlers = $this->handlers; $cf->classNodes = $this->classNodes; + $cf->interpretedExpressions = $this->interpretedExpressions; $cf->arrayBindings = $this->arrayBindings; $cf->callMethodDisplays = $this->callMethodDisplays; return $cf; } + private function prepareConstructorSuperCall(Node $body): void + { + $statement = $body instanceof BlockStatement ? ($body->body[0] ?? null) : null; + $call = $statement instanceof ExpressionStatement ? $statement->expression : null; + if ( + !$call instanceof CallExpression || $call->optional + || !$call->callee instanceof Identifier || $call->callee->name !== 'super' + ) { + throw new CompilerBailout('derived constructor needs a leading super call'); + } + $parameters = []; + foreach ($this->paramSlots as $slot) { + $parameters[$this->localNames[$slot]] = true; + } + foreach ($call->arguments as $argument) { + if ($argument instanceof Identifier && isset($parameters[$argument->name])) { + continue; + } + if ( + $argument instanceof Literal + && ($argument->value === null || is_scalar($argument->value)) + ) { + continue; + } + throw new CompilerBailout('super argument needs additional environment bindings'); + } + // The unchanged interpreter owns super lookup, argument evaluation, + // field initialization and BindThisValue. Its parameter reads must + // share the same live bindings used by subsequent bytecode. + $this->constructorSuperCall = $call; + } + /** @return array|null */ private function capturedEnvironmentBindings(JsFunction $fn): ?array { diff --git a/src/Bytecode/Parts/CompilerExpression.php b/src/Bytecode/Parts/CompilerExpression.php index db811be0..b5592f77 100644 --- a/src/Bytecode/Parts/CompilerExpression.php +++ b/src/Bytecode/Parts/CompilerExpression.php @@ -641,6 +641,12 @@ private function compileCall(CallExpression $node): void throw new CompilerBailout('direct eval'); } if ($node->callee instanceof Identifier && $node->callee->name === 'super') { + if ($node === $this->constructorSuperCall) { + $index = count($this->interpretedExpressions); + $this->interpretedExpressions[] = $node; + $this->emit(Op::EVAL_EXPRESSION, $index); + return; + } throw new CompilerBailout('super call'); } diff --git a/tests/Unit/Bytecode/ClassConstructorTest.php b/tests/Unit/Bytecode/ClassConstructorTest.php new file mode 100644 index 00000000..7155c64d --- /dev/null +++ b/tests/Unit/Bytecode/ClassConstructorTest.php @@ -0,0 +1,153 @@ +checkOracle(false); + foreach ( + [ + 'ConstructorBase', 'ConstructorDerived', 'ConstructorGrandchild', 'ConstructorReplacementBase', + 'ConstructorReplacement', 'ConstructorCapture', 'ConstructorHoisted', 'ConstructorPrivateBase', + 'ConstructorRest', 'ConstructorUndefined', 'ConstructorPrimitive', 'ConstructorObject', + 'ConstructorReturnBase', 'ConstructorThrowBase', 'ConstructorThrow', 'ConstructorNull', + ] as $name + ) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name); + self::assertFalse($function->compiled->canSkipEnvAlloc, $name); + self::assertFalse($function->compiled->hasTailCalls, $name); + self::assertNull($function->phpCompiled, $name); + } + foreach ( + [ + 'ConstructorPrivateDerived', 'ConstructorBeforeThis', 'ConstructorDouble', + 'ConstructorNewTarget', 'ConstructorSpread', + ] as $name + ) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled, $name); + } + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } + + public function testBudgetedConstructorsMatchTheSameNodeOracle(): void + { + $this->checkOracle(true); + } + + public function testConstructorLiteralsUseTheCalleeRealm(): void + { + $foreign = new Engine(); + $foreign->eval(<<<'JS' +class ForeignBase { constructor(value) { this.array = [value]; this.object = {value}; } } +class ForeignDerived extends ForeignBase { constructor(value) { super(value); this.other = []; } } +new ForeignBase(0); new ForeignDerived(0); +JS); + $caller = new Engine(); + foreach (['ForeignBase', 'ForeignDerived'] as $name) { + $function = $foreign->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + $caller->getGlobalEnv()->defineVar($name, $function); + } + foreach (['ArrayPrototype', 'ObjectPrototype'] as $name) { + $prototype = $name === 'ObjectPrototype' + ? $foreign->getGlobalEnv()->get('__ObjectPrototype__') + : $foreign->getGlobalEnv()->getIntrinsic($name); + self::assertInstanceOf(JsObject::class, $prototype); + $caller->getGlobalEnv()->defineVar('foreign' . $name, $prototype); + } + for ($pass = 0; $pass < 3; $pass++) { + self::assertSame([true, true, true, true, true], $caller->eval(<<<'JS' +var base = new ForeignBase(1), derived = new ForeignDerived(2); +[Object.getPrototypeOf(base.array) === foreignArrayPrototype, + Object.getPrototypeOf(base.object) === foreignObjectPrototype, + Object.getPrototypeOf(derived.array) === foreignArrayPrototype, + Object.getPrototypeOf(derived.object) === foreignObjectPrototype, + Object.getPrototypeOf(derived.other) === foreignArrayPrototype]; +JS)); + } + foreach (['ForeignBase', 'ForeignDerived'] as $name) { + $function = $foreign->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + } + } + + public function testSuperTargetIsCapturedBeforeArgumentSideEffects(): void + { + // ECMA-262 13.3.7.1 captures GetSuperConstructor before ArgumentListEvaluation. + // Node 26.12.0 resolves this edge case later, so its result is not the oracle here. + foreach ([false, true] as $budgeted) { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + self::assertSame([true, true, ['argument', 'original']], $engine->eval(<<<'JS' +const events = []; +class OriginalBase { constructor(value) { events.push('original'); this.value = value; } } +class OtherBase { constructor(value) { events.push('other'); this.other = value; } } +class Derived extends OriginalBase { + constructor(value) { super((events.push('argument'), Object.setPrototypeOf(Derived, OtherBase), value)); } +} +const result = new Derived(2); +[result.value === 2, !('other' in result), events]; +JS)); + $function = $engine->getGlobalEnv()->get('Derived'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled); + } + } + + public function testConstructorLoopsRespectBudgetsAndUnwind(): void + { + $engine = new Engine(); + $engine->setLimit('maxLoopIterations', PHP_INT_MAX); + self::assertSame(3, $engine->eval(<<<'JS' +class LoopBase { constructor(limit) { this.limit = limit; } } +class LoopDerived extends LoopBase { + constructor(limit) { super(limit); let count = 0; while (count < limit) count++; this.count = count; } +} +new LoopDerived(3).count; +JS)); + $function = $engine->getGlobalEnv()->get('LoopDerived'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + $engine->setExecutionBudget(0.002); + try { + $engine->eval('new LoopDerived(100000000)'); + self::fail('The constructor loop ignored its host budget.'); + } catch (BudgetExceeded) { + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } + $engine->setExecutionBudget(null); + self::assertSame(4, $engine->eval('new LoopDerived(4).count')); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } + + private function checkOracle(bool $budgeted): Engine + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/class-constructors.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/class-constructors.json', + $engine->eval('JSON.stringify(constructorResults)'), + ); + return $engine; + } +} diff --git a/tests/Unit/Bytecode/fixtures/class-constructors.js b/tests/Unit/Bytecode/fixtures/class-constructors.js new file mode 100644 index 00000000..735adf4c --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/class-constructors.js @@ -0,0 +1,158 @@ +const constructorResults = []; +const constructorEvents = []; +function constructorOutcome(action) { + try { return action(); } catch (error) { return error.name; } +} +class ConstructorBase { + constructor(value) { this.value = value; this.array = [value]; this.object = {value}; } +} +class ConstructorDerived extends ConstructorBase { + field = constructorEvents.push('derived-field'); + constructor(value) { super(value); this.after = value + 1; } +} +class ConstructorGrandchild extends ConstructorDerived { + constructor(value) { super(value); this.last = value + 2; } +} +class ConstructorDefaultDerived extends ConstructorDerived { + last = constructorEvents.push('default-field'); +} +class ConstructorReplacementBase { + baseField = constructorEvents.push('base-field'); + constructor(value) { constructorEvents.push('base-body'); return {replacement: value}; } +} +class ConstructorReplacement extends ConstructorReplacementBase { + childField = constructorEvents.push('child-field'); + constructor(value) { super(value); this.saved = this.replacement; } +} +class ConstructorCapture extends ConstructorBase { + constructor(value) { + super(value); + value += 10; + this.after = value; + this.read = () => [value, this.value]; + } +} +class ConstructorHoisted extends ConstructorBase { + constructor(value) { + super(value); + function value() { return 'hoisted'; } + this.same = this.value === value; + } +} +class ConstructorPrivateBase { + #secret = 9; + constructor(value = this.#secret) { this.value = value; } + read() { return this.#secret; } +} +class ConstructorPrivateDerived extends ConstructorPrivateBase { + #secret = 11; + constructor(value) { super(value); this.child = this.#secret; } +} +class ConstructorRest { + constructor(first, ...values) { this.first = first; this.values = values; } +} +class ConstructorUndefined extends ConstructorBase { + constructor(value) { super(value); return; } +} +class ConstructorPrimitive extends ConstructorBase { + constructor(value) { super(value); return 7; } +} +class ConstructorObject extends ConstructorBase { + constructor(value) { super(value); return {other: value}; } +} +function constructorReturn(value) { return value; } +class ConstructorReturnBase { + constructor(value) { this.value = value; return constructorReturn(value); } +} +class ConstructorThrowBase { + constructor(value) { constructorEvents.push('throw-base'); throw value; } +} +class ConstructorThrow extends ConstructorThrowBase { + constructor(value) { super(value); constructorEvents.push('unreachable'); } +} +class ConstructorBeforeThis extends ConstructorBase { + constructor(value) { this.before = value; super(value); } +} +class ConstructorDouble extends ConstructorBase { + constructor(value) { super(value); super(value); } +} +class ConstructorOtherBase { + constructor(value) { this.other = value; } +} +class ConstructorNewTarget extends ConstructorBase { + constructor(value) { super(value); this.target = new.target; } +} +class ConstructorSpread extends ConstructorBase { + constructor(...values) { super(...values); } +} +class ConstructorNull extends null { + constructor() { super(); } +} +function ConstructorAlternateTarget() {} +function constructorFamily(parent, offset) { + return class ConstructorFamily extends parent { + constructor(value) { super(value); this.offset = offset; } + }; +} +class ConstructorSetter { + constructor(value) { this.value = value; } +} + +for (let pass = 0; pass < 3; pass++) { + constructorEvents.length = 0; + const base = new ConstructorBase(pass); + const derived = new ConstructorDerived(pass); + const grandchild = new ConstructorGrandchild(pass); + const implicit = new ConstructorDefaultDerived(pass); + constructorResults.push([base.value, base.array, base.object, derived.value, derived.after, + grandchild.value, grandchild.after, grandchild.last, implicit.value, constructorEvents.slice()]); + constructorEvents.length = 0; + const replacement = new ConstructorReplacement(pass); + constructorResults.push([replacement.saved, replacement.baseField, replacement.childField, + replacement instanceof ConstructorReplacement, constructorEvents.slice()]); + const captured = new ConstructorCapture(pass); + constructorResults.push([captured.after, captured.read()]); + const hoisted = new ConstructorHoisted(pass); + constructorResults.push([hoisted.same, hoisted.value()]); + const privateBase = new ConstructorPrivateBase(); + const privateDerived = new ConstructorPrivateDerived(); + constructorResults.push([privateBase.value, privateBase.read(), privateDerived.value, privateDerived.child]); + const rest = new ConstructorRest(pass, 1, 2, 3); + constructorResults.push([rest.first, rest.values]); + constructorResults.push(new ConstructorUndefined(pass).value, + constructorOutcome(() => new ConstructorPrimitive(pass)), new ConstructorObject(pass)); + constructorResults.push(new ConstructorReturnBase(pass).value, + new ConstructorReturnBase({returned: pass})); + const thrown = {name: 'sentinel'}; + constructorResults.push(constructorOutcome(() => new ConstructorThrow(thrown))); + constructorResults.push(constructorOutcome(() => new ConstructorBeforeThis(pass)), + constructorOutcome(() => new ConstructorDouble(pass)), constructorOutcome(() => new ConstructorNull())); + constructorResults.push(new ConstructorNewTarget(pass).target === ConstructorNewTarget, + new ConstructorSpread(pass).value); + const reflected = Reflect.construct(ConstructorDerived, [pass], ConstructorAlternateTarget); + constructorResults.push([Object.getPrototypeOf(reflected) === ConstructorAlternateTarget.prototype, + reflected.value, reflected.after]); + const proxied = new Proxy(ConstructorDerived, {}); + constructorResults.push(new proxied(pass).value); + const bound = ConstructorDerived.bind(null, pass); + constructorResults.push(new bound().value); + constructorResults.push(constructorOutcome(() => ConstructorBase(pass)), + constructorOutcome(() => ConstructorDerived(pass))); + const FamilyA = constructorFamily(ConstructorBase, 10 + pass); + const FamilyB = constructorFamily(ConstructorOtherBase, 20 + pass); + const familyA = new FamilyA(pass), familyB = new FamilyB(pass); + constructorResults.push([familyA.value, familyA.offset, familyB.other, familyB.offset]); + Object.defineProperty(ConstructorSetter.prototype, 'value', { + configurable: true, + set(value) { this.received = value + 1; }, + }); + const setter = new ConstructorSetter(pass); + Object.defineProperty(ConstructorSetter.prototype, 'value', { + configurable: true, value: 3, writable: false, + }); + constructorResults.push(setter.received, constructorOutcome(() => new ConstructorSetter(pass))); + delete ConstructorSetter.prototype.value; + constructorResults.push(new ConstructorSetter(pass).value); + try { new ConstructorThrow(thrown); } + catch (error) { constructorResults.push(error === thrown); } +} diff --git a/tests/Unit/Bytecode/fixtures/class-constructors.json b/tests/Unit/Bytecode/fixtures/class-constructors.json new file mode 100644 index 00000000..2640af6d --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/class-constructors.json @@ -0,0 +1,275 @@ +[ + [ + 0, + [ + 0 + ], + { + "value": 0 + }, + 0, + 1, + 0, + 1, + 2, + 0, + [ + "derived-field", + "derived-field", + "derived-field", + "default-field" + ] + ], + [ + 0, + null, + 3, + false, + [ + "base-field", + "base-body", + "child-field" + ] + ], + [ + 10, + [ + 10, + 0 + ] + ], + [ + true, + "hoisted" + ], + [ + 9, + 9, + 9, + 11 + ], + [ + 0, + [ + 1, + 2, + 3 + ] + ], + 0, + "TypeError", + { + "other": 0 + }, + 0, + { + "returned": 0 + }, + "sentinel", + "ReferenceError", + "ReferenceError", + "TypeError", + true, + 0, + [ + true, + 0, + 1 + ], + 0, + 0, + "TypeError", + "TypeError", + [ + 0, + 10, + 0, + 20 + ], + 1, + "TypeError", + 0, + true, + [ + 1, + [ + 1 + ], + { + "value": 1 + }, + 1, + 2, + 1, + 2, + 3, + 1, + [ + "derived-field", + "derived-field", + "derived-field", + "default-field" + ] + ], + [ + 1, + null, + 3, + false, + [ + "base-field", + "base-body", + "child-field" + ] + ], + [ + 11, + [ + 11, + 1 + ] + ], + [ + true, + "hoisted" + ], + [ + 9, + 9, + 9, + 11 + ], + [ + 1, + [ + 1, + 2, + 3 + ] + ], + 1, + "TypeError", + { + "other": 1 + }, + 1, + { + "returned": 1 + }, + "sentinel", + "ReferenceError", + "ReferenceError", + "TypeError", + true, + 1, + [ + true, + 1, + 2 + ], + 1, + 1, + "TypeError", + "TypeError", + [ + 1, + 11, + 1, + 21 + ], + 2, + "TypeError", + 1, + true, + [ + 2, + [ + 2 + ], + { + "value": 2 + }, + 2, + 3, + 2, + 3, + 4, + 2, + [ + "derived-field", + "derived-field", + "derived-field", + "default-field" + ] + ], + [ + 2, + null, + 3, + false, + [ + "base-field", + "base-body", + "child-field" + ] + ], + [ + 12, + [ + 12, + 2 + ] + ], + [ + true, + "hoisted" + ], + [ + 9, + 9, + 9, + 11 + ], + [ + 2, + [ + 1, + 2, + 3 + ] + ], + 2, + "TypeError", + { + "other": 2 + }, + 2, + { + "returned": 2 + }, + "sentinel", + "ReferenceError", + "ReferenceError", + "TypeError", + true, + 2, + [ + true, + 2, + 3 + ], + 2, + 2, + "TypeError", + "TypeError", + [ + 2, + 12, + 2, + 22 + ], + 3, + "TypeError", + 2, + true +] From 0124d7554898a1dc60f8725d640a259727de7e78 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:20:57 +0200 Subject: [PATCH 57/99] Avoid uncaptured hoisted function environment cycles --- src/Bytecode/CompiledFunction.php | 3 + src/Bytecode/Compiler.php | 30 ++++- src/Bytecode/Parts/CompilerScope.php | 1 + src/Bytecode/VM.php | 5 +- src/Runtime/Parts/ExpressionEvaluation.php | 9 ++ .../Bytecode/HoistedFunctionBindingTest.php | 118 ++++++++++++++++++ .../Unit/Bytecode/fixtures/hoist-bindings.js | 98 +++++++++++++++ .../Bytecode/fixtures/hoist-bindings.json | 98 +++++++++++++++ 8 files changed, 360 insertions(+), 2 deletions(-) create mode 100644 tests/Unit/Bytecode/HoistedFunctionBindingTest.php create mode 100644 tests/Unit/Bytecode/fixtures/hoist-bindings.js create mode 100644 tests/Unit/Bytecode/fixtures/hoist-bindings.json diff --git a/src/Bytecode/CompiledFunction.php b/src/Bytecode/CompiledFunction.php index 78c9846c..10520241 100644 --- a/src/Bytecode/CompiledFunction.php +++ b/src/Bytecode/CompiledFunction.php @@ -192,6 +192,8 @@ final class CompiledFunction * @param array|null $capturedEnvironmentBindings Captured * body var/let/const declarations. Null retains interpreter hoisting; * parameters and function declarations have separate initialization. + * @param array $omittedFunctionBindings DEFINE_NAME sites whose + * hoisted functions are observable only through frame slots. */ public function __construct( public readonly array $code, @@ -207,6 +209,7 @@ public function __construct( public readonly bool $parametersFromEnvironment = false, public readonly bool $hasTailCalls = false, public readonly ?array $capturedEnvironmentBindings = null, + public readonly array $omittedFunctionBindings = [], ) { } } diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index 2adfac24..c55b40e3 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -108,6 +108,9 @@ final class Compiler /** @var array Captured function-scope bindings and declaration kinds. */ private array $capturedLocals = []; + /** @var array Hoisted function definition sites and their frame slots. */ + private array $functionDefinitionSites = []; + /** @var array Uncaptured lexical bindings with proven disjoint block lifetimes. */ private array $reusableBlockLocals = []; @@ -437,6 +440,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction // canSkipEnvAlloc semantics under frame-based this. $needsEnvThis = $this->arrayAssignmentReferences || $this->hasLoadThis || $this->nestedFnsLexicallyReferenceThis(); + $capturedBindings = $this->capturedEnvironmentBindings($fn); $cf = new CompiledFunction( code: $this->code, consts: $this->consts, @@ -452,7 +456,8 @@ private function compileFunction(JsFunction $fn): CompiledFunction && !$this->needsArguments, parametersFromEnvironment: $this->parametersFromEnvironment, hasTailCalls: $this->hasTailCalls, - capturedEnvironmentBindings: $this->capturedEnvironmentBindings($fn), + capturedEnvironmentBindings: $capturedBindings, + omittedFunctionBindings: $this->omittedFunctionBindings($fn, $capturedBindings), ); $cf->handlers = $this->handlers; $cf->classNodes = $this->classNodes; @@ -524,6 +529,29 @@ private function capturedEnvironmentBindings(JsFunction $fn): ?array return $bindings; } + /** + * @param array|null $capturedBindings + * @return array + */ + private function omittedFunctionBindings(JsFunction $fn, ?array $capturedBindings): array + { + if ( + $capturedBindings === null || $fn->isClassConstructor() || $fn->isDerivedConstructor() + || $this->interpretedExpressions !== [] + ) { + return []; + } + $omitted = []; + foreach ($this->functionDefinitionSites as $pc => [$name, $slot]) { + // Parameter bindings can remain observable through arguments even + // when nested functions do not capture their declaration name. + if (!isset($this->capturedLocals[$name]) && !in_array($slot, $this->paramSlots, true)) { + $omitted[$pc] = true; + } + } + return $omitted; + } + private function parameterInitializerCanCapture(Node $node): bool { if ( diff --git a/src/Bytecode/Parts/CompilerScope.php b/src/Bytecode/Parts/CompilerScope.php index 726408c0..0a1e990b 100644 --- a/src/Bytecode/Parts/CompilerScope.php +++ b/src/Bytecode/Parts/CompilerScope.php @@ -573,6 +573,7 @@ private function hoistFunctionDeclarations(array $statements): void // up — which can happen when ramda-style libraries declare // many top-level `function r(t,n){...}` shapes whose tree- // walker hoist binding got eclipsed or never created. + $this->functionDefinitionSites[count($this->code)] = [$name, $slot]; $this->emit(Op::DEFINE_NAME, $this->internName($name)); } } diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 93b42199..45850cee 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -1020,7 +1020,10 @@ public function execute( $pc += 3; break; case Op::DEFINE_NAME: - $env->defineVar($names[$code[$pc + 1]], $stack[--$sp]); + --$sp; + if (!isset($cf->omittedFunctionBindings[$pc])) { + $env->defineVar($names[$code[$pc + 1]], $stack[$sp]); + } $pc += 2; break; case Op::INITIALIZE_NAME: diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index d5573a6b..5cbb62e1 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -4112,6 +4112,15 @@ private function executeFunction( && !$fn->getClosure()->isUnderWithScope() ) { $fn->compiled = \Phasis\Bytecode\CompilationTemplates::get($fn); + // A cached syntax failure lets fresh closures use the VM prologue + // without constructing interpreter hoists it would discard. + if ( + $fn->compiled !== null && $fn->compiled->omittedFunctionBindings !== [] + && $fn->phpCompiled === null && !$fn->phpCompileFailed + && \Phasis\Bytecode\CompilationFailures::get($fn, 'php') !== null + ) { + $fn->phpCompileFailed = true; + } } // Hot path for VM-compiled bodies with no env-binding needs: diff --git a/tests/Unit/Bytecode/HoistedFunctionBindingTest.php b/tests/Unit/Bytecode/HoistedFunctionBindingTest.php new file mode 100644 index 00000000..340bce12 --- /dev/null +++ b/tests/Unit/Bytecode/HoistedFunctionBindingTest.php @@ -0,0 +1,118 @@ +checkOracle(false); + foreach (['localOnly', 'siblings', 'duplicateDeclarations', 'varRedeclaration', 'varReplacement', 'strictBindings'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotEmpty($function->compiled?->omittedFunctionBindings, $name); + } + foreach (['recursive', 'parameterCollision', 'restCollision', 'defaultCollision', 'classEval'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertSame([], $function->compiled?->omittedFunctionBindings ?? [], $name); + } + } + + public function testBudgetedHoistsMatchTheSameNodeOracle(): void + { + $this->checkOracle(true); + } + + public function testUnobservedFunctionBindingsDoNotKeepTheirActivationsAlive(): void + { + foreach ([false, true] as $freshClosure) { + $engine = new Engine(); + $engine->eval(<<<'JS' +function makeCycleFactory() { + return function cycleFactory() { + const token = {}; + function helper() { return token; } + return token; + }; +} +var cycleFactory = makeCycleFactory(); +cycleFactory(); +cycleFactory(); +JS); + if ($freshClosure) { + $engine->eval('cycleFactory = makeCycleFactory();'); + } + $enabled = gc_enabled(); + gc_collect_cycles(); + gc_disable(); + try { + $engine->eval('var cycleProbe = cycleFactory();'); + $token = $engine->getGlobalEnv()->get('cycleProbe'); + $reference = \WeakReference::create($token); + unset($token); + $engine->eval('cycleProbe = null;'); + self::assertNull($reference->get(), 'An unobserved helper must not retain its activation.'); + } finally { + $engine->reset(); + if ($enabled) { + gc_enable(); + } + gc_collect_cycles(); + } + } + } + + public function testEscapingFunctionsKeepTheirCalleeRealmAndSeparateCaptures(): void + { + $foreign = new Engine(); + $foreign->eval(<<<'JS' +function createHelper(value) { + function helper() { return value; } + return helper; +} +createHelper(0); +JS); + $function = $foreign->getGlobalEnv()->get('createHelper'); + self::assertInstanceOf(JsFunction::class, $function); + $caller = new Engine(); + $caller->getGlobalEnv()->defineVar('createHelper', $function); + $prototype = $function->getPrototype(); + self::assertNotNull($prototype); + $caller->getGlobalEnv()->defineVar('foreignFunctionPrototype', $prototype); + for ($pass = 0; $pass < 3; $pass++) { + self::assertSame([3, 7, false, true, true], $caller->eval(<<<'JS' +var firstHelper = createHelper(3); +var secondHelper = createHelper(7); +[firstHelper(), secondHelper(), firstHelper === secondHelper, + Object.getPrototypeOf(firstHelper) === foreignFunctionPrototype, + Object.getPrototypeOf(firstHelper) !== Function.prototype]; +JS)); + } + self::assertNotEmpty($function->compiled?->omittedFunctionBindings); + $caller->setExecutionBudget(5); + self::assertSame(11, $caller->eval('createHelper(11)();')); + $caller->setExecutionBudget(null); + self::assertSame(13, $caller->eval('createHelper(13)();')); + } + + private function checkOracle(bool $budgeted): Engine + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/hoist-bindings.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/hoist-bindings.json', + $engine->eval('JSON.stringify(hoistBindingResult)'), + ); + return $engine; + } +} diff --git a/tests/Unit/Bytecode/fixtures/hoist-bindings.js b/tests/Unit/Bytecode/fixtures/hoist-bindings.js new file mode 100644 index 00000000..c74d0b97 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/hoist-bindings.js @@ -0,0 +1,98 @@ +const hoistBindingResult = []; +function localOnly() { + const token = 3; + function helper() { return token; } + return helper(); +} +function recursive() { + function helper(depth) { return depth ? helper(depth - 1) : 5; } + return helper(3); +} +function siblings() { + function first() { return second(); } + function second() { return 7; } + return first(); +} +function replaceCaptured() { + function read() { return helper; } + function helper() { return 1; } + helper = 'changed'; + return read(); +} +function duplicateDeclarations() { + function helper() { return 1; } + function helper() { return 2; } + return helper(); +} +function varRedeclaration() { + function helper() { return 4; } + var helper; + return helper(); +} +function varReplacement() { + function helper() { return 4; } + var helper = 8; + return helper; +} +function parameterCollision(helper) { + function helper() { return 9; } + const snapshot = parameterCollision['arguments']; + return [helper(), snapshot[0] === helper]; +} +function restCollision(...helper) { + function helper() { return 11; } + return helper(); +} +function defaultCollision(helper = 1) { + function helper() { return 13; } + return helper(); +} +function retainedRest(...values) { + function read() { return values.slice(); } + return read; +} +function directEval() { + function helper() { return 15; } + return eval('helper()'); +} +function nestedEval() { + function helper() { return 17; } + function read() { return eval('helper()'); } + return read(); +} +function classEval() { + function helper() { return 19; } + return new class { read() { return eval('helper()'); } }().read(); +} +function withBinding() { + function helper() { return 21; } + with ({}) { return helper(); } +} +function strictBindings() { + 'use strict'; + function helper() { return 23; } + return helper(); +} +for (let pass = 0; pass < 3; pass++) { + hoistBindingResult.push(localOnly(), recursive(), siblings(), replaceCaptured(), duplicateDeclarations(), + varRedeclaration(), varReplacement(), parameterCollision(1), restCollision(1), defaultCollision(), + directEval(), nestedEval(), classEval(), withBinding(), strictBindings()); + const first = retainedRest(1, 2); + const second = retainedRest(3); + hoistBindingResult.push(first(), second(), first()); +} +let escapedHelper; +function keepCaller() { escapedHelper = keepCaller.caller; } +function escapeThroughCaller(hook) { + let value = 1; + function helper() { hook(); value++; } + helper(); + return () => value; +} +for (let pass = 0; pass < 3; pass++) { + const read = escapeThroughCaller(keepCaller); + hoistBindingResult.push(read(), escapedHelper.name); + escapedHelper(); + hoistBindingResult.push(read()); + escapedHelper = null; +} diff --git a/tests/Unit/Bytecode/fixtures/hoist-bindings.json b/tests/Unit/Bytecode/fixtures/hoist-bindings.json new file mode 100644 index 00000000..bf097702 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/hoist-bindings.json @@ -0,0 +1,98 @@ +[ + 3, + 5, + 7, + "changed", + 2, + 4, + 8, + [ + 9, + true + ], + 11, + 13, + 15, + 17, + 19, + 21, + 23, + [ + 1, + 2 + ], + [ + 3 + ], + [ + 1, + 2 + ], + 3, + 5, + 7, + "changed", + 2, + 4, + 8, + [ + 9, + true + ], + 11, + 13, + 15, + 17, + 19, + 21, + 23, + [ + 1, + 2 + ], + [ + 3 + ], + [ + 1, + 2 + ], + 3, + 5, + 7, + "changed", + 2, + 4, + 8, + [ + 9, + true + ], + 11, + 13, + 15, + 17, + 19, + 21, + 23, + [ + 1, + 2 + ], + [ + 3 + ], + [ + 1, + 2 + ], + 2, + "helper", + 3, + 2, + "helper", + 3, + 2, + "helper", + 3 +] From e66b18bf65e5b9077d8f8ca1ff26bbd394135060 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:30:21 +0200 Subject: [PATCH 58/99] Check numeric bridge bounds before integer casts --- src/Engine.php | 2 +- tests/Unit/InteropRegressionTest.php | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Engine.php b/src/Engine.php index 48c5ba5e..5d349353 100644 --- a/src/Engine.php +++ b/src/Engine.php @@ -2437,7 +2437,7 @@ private function toPhp(JsValue $value, array $seen = []): mixed if ($num === -INF) { return -INF; } - if ($num == (int) $num && abs($num) < PHP_INT_MAX) { + if (abs($num) < PHP_INT_MAX && $num == (int) $num) { return (int) $num; } return $num; diff --git a/tests/Unit/InteropRegressionTest.php b/tests/Unit/InteropRegressionTest.php index 17dd5e05..02ad7b9e 100644 --- a/tests/Unit/InteropRegressionTest.php +++ b/tests/Unit/InteropRegressionTest.php @@ -10,6 +10,23 @@ final class InteropRegressionTest extends TestCase { + public function testLargeNumericResultsDoNotAttemptOutOfRangeIntegerCasts(): void + { + $numbers = [PHP_FLOAT_MAX, -PHP_FLOAT_MAX, (float) PHP_INT_MAX, -(float) PHP_INT_MAX, 42.0, 0.5]; + $engine = new Engine(); + $engine->setGlobal('numbers', $numbers); + set_error_handler(static function (int $severity, string $message): never { + throw new \ErrorException($message, 0, $severity); + }); + try { + self::assertSame([ + PHP_FLOAT_MAX, -PHP_FLOAT_MAX, (float) PHP_INT_MAX, -(float) PHP_INT_MAX, 42, 0.5, + ], $engine->eval('numbers')); + } finally { + restore_error_handler(); + } + } + public function testPublicPropertiesAndMethodsReferToTheOriginalObject(): void { $engine = new Engine(); From 0ed62f0fe8b2fa2c67f5ada4e84deea882ac07d2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 24 Oct 2026 00:43:47 +0000 Subject: [PATCH 59/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 44 +++++++++++------------ compat.json | 100 ++++++++++++++++++++++++++-------------------------- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index d1edb983..70d72132 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,13 +3,13 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-23T22:42:14+00:00` +- Snapshot time: `2026-10-24T00:43:45+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `bcced36a` (dirty) +- Git: `feat/express-hono-compatibility` @ `e66b18bf` (dirty) ## Summary @@ -198,26 +198,26 @@ Generated from a completed `test262` pass. Do not edit by hand. | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| staging/sm | NORMAL | 178.113s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 177.236s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 174.932s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 173.783s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 172.134s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 161.071s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| built-ins/decodeURIComponent | NORMAL | 160.213s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| staging/sm | NORMAL | 151.531s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| staging/sm | NORMAL | 145.027s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| built-ins/decodeURI | NORMAL | 142.401s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| staging/sm | NORMAL | 140.809s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| staging/sm | NORMAL | 99.334s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| intl402 | NORMAL | 89.761s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | -| language/literals | NORMAL | 86.762s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | -| built-ins/TypedArray | NORMAL | 72.654s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | -| built-ins/decodeURIComponent | NORMAL | 72.198s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | -| built-ins/decodeURI | NORMAL | 71.191s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | -| intl402/DateTimeFormat | NORMAL | 67.042s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | -| annexB/built-ins/RegExp | NORMAL | 64.604s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.430s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Linear_A.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Linear_B.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Lisu.js` | +| staging/sm | NORMAL | 184.605s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 183.902s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 183.576s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 182.867s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 181.268s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 175.681s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| staging/sm | NORMAL | 170.852s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| built-ins/decodeURIComponent | NORMAL | 163.763s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| staging/sm | NORMAL | 146.772s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 145.879s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| built-ins/decodeURI | NORMAL | 143.023s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| staging/sm | NORMAL | 115.169s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| language/literals | NORMAL | 85.324s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | +| intl402 | NORMAL | 83.484s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | +| built-ins/TypedArray | NORMAL | 74.003s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | +| built-ins/decodeURIComponent | NORMAL | 73.143s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | +| built-ins/decodeURI | NORMAL | 72.719s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | +| intl402/DateTimeFormat | NORMAL | 67.267s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | +| annexB/built-ins/RegExp | NORMAL | 64.783s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.699s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Malayalam.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Mandaic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Manichaean.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 22e7fa47..3ea4daa7 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-23T22:42:14+00:00", - "updatedAt": "2026-10-23T22:42:14+00:00", + "generatedAt": "2026-10-24T00:43:45+00:00", + "updatedAt": "2026-10-24T00:43:45+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "bcced36a", + "commit": "e66b18bf", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "334feb69abfcc6f625451b033c0456e0e9e4b5cf", - "runIdentity": "5b2a1450979babf9804570e09487114d3a631c0ae316d415bfdd99472deca6e4" + "fingerprint": "b0f8635c7820ddf7811126d4c1e2b008c868e4e6", + "runIdentity": "e3eae8ee0b2d698781e287c43b4788c980b9079186afb589eb43188f33170fbd" }, "discovery": { "groupCount": 161, @@ -2719,16 +2719,16 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 178.113, + "durationSec": 184.605, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 177.236, + "durationSec": 183.902, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" @@ -2737,43 +2737,52 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 174.932, + "durationSec": 183.576, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 173.783, + "durationSec": 182.867, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 172.134, + "durationSec": 181.268, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 161.071, + "durationSec": 175.681, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" ] }, + { + "group": "staging/sm", + "kind": "normal", + "durationSec": 170.852, + "filesCount": 1, + "sampleFiles": [ + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + ] + }, { "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 160.213, + "durationSec": 163.763, "filesCount": 1, "sampleFiles": [ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" @@ -2782,25 +2791,25 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 151.531, + "durationSec": 146.772, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 145.027, + "durationSec": 145.879, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 142.401, + "durationSec": 143.023, "filesCount": 1, "sampleFiles": [ "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" @@ -2809,25 +2818,29 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 140.809, + "durationSec": 115.169, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { - "group": "staging/sm", + "group": "language/literals", "kind": "normal", - "durationSec": 99.334, - "filesCount": 1, + "durationSec": 85.324, + "filesCount": 25, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" + "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", + "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", + "...", + "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", + "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" ] }, { "group": "intl402", "kind": "normal", - "durationSec": 89.761, + "durationSec": 83.484, "filesCount": 22, "sampleFiles": [ "test262/test/intl402/constructors-string-and-single-element-array.js", @@ -2837,23 +2850,10 @@ "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" ] }, - { - "group": "language/literals", - "kind": "normal", - "durationSec": 86.762, - "filesCount": 25, - "sampleFiles": [ - "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", - "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", - "...", - "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", - "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" - ] - }, { "group": "built-ins/TypedArray", "kind": "normal", - "durationSec": 72.654, + "durationSec": 74.003, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", @@ -2866,7 +2866,7 @@ { "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 72.198, + "durationSec": 73.143, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", @@ -2879,7 +2879,7 @@ { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 71.191, + "durationSec": 72.719, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", @@ -2892,7 +2892,7 @@ { "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 67.042, + "durationSec": 67.267, "filesCount": 12, "sampleFiles": [ "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", @@ -2905,7 +2905,7 @@ { "group": "annexB/built-ins/RegExp", "kind": "normal", - "durationSec": 64.604, + "durationSec": 64.783, "filesCount": 25, "sampleFiles": [ "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", @@ -2918,12 +2918,12 @@ { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.43, + "durationSec": 59.699, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Linear_A.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Linear_B.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Lisu.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Malayalam.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Mandaic.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Manichaean.js" ] } ] From f014c2d34d35f69f6ba14e0da5560fd7c72a7b9f Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:41:23 +0200 Subject: [PATCH 60/99] Compile guarded pure segments of string while loops --- src/Bytecode/CompiledFunction.php | 3 + src/Bytecode/Compiler.php | 3 + src/Bytecode/JsToPhp.php | 1 + src/Bytecode/Op.php | 2 + src/Bytecode/Parts/CompilerStatement.php | 3 + .../Parts/CompilerStringLoopRegions.php | 120 ++++++ src/Bytecode/Parts/JsToPhpEmitExpression.php | 4 +- src/Bytecode/Parts/JsToPhpEmitStatement.php | 4 +- src/Bytecode/Parts/JsToPhpLoopRegions.php | 127 ++++++ src/Bytecode/Parts/JsToPhpStringScanners.php | 13 +- src/Bytecode/StringLoopRegion.php | 14 + src/Bytecode/StringLoopRegionAnalysis.php | 385 ++++++++++++++++++ src/Bytecode/StringLoopRegionPlan.php | 41 ++ src/Bytecode/StringLoopRegionVerifier.php | 209 ++++++++++ src/Bytecode/StringScannerPlan.php | 2 +- src/Bytecode/VM.php | 15 + tests/Unit/Bytecode/StringLoopRegionTest.php | 323 +++++++++++++++ 17 files changed, 1263 insertions(+), 6 deletions(-) create mode 100644 src/Bytecode/Parts/CompilerStringLoopRegions.php create mode 100644 src/Bytecode/Parts/JsToPhpLoopRegions.php create mode 100644 src/Bytecode/StringLoopRegion.php create mode 100644 src/Bytecode/StringLoopRegionAnalysis.php create mode 100644 src/Bytecode/StringLoopRegionPlan.php create mode 100644 src/Bytecode/StringLoopRegionVerifier.php create mode 100644 tests/Unit/Bytecode/StringLoopRegionTest.php diff --git a/src/Bytecode/CompiledFunction.php b/src/Bytecode/CompiledFunction.php index 10520241..df889a71 100644 --- a/src/Bytecode/CompiledFunction.php +++ b/src/Bytecode/CompiledFunction.php @@ -21,6 +21,9 @@ */ final class CompiledFunction { + /** @var list Immutable native code with exact ordinary-bytecode exits. */ + public array $loopRegions = []; + /** * Ordered flat array bindings reuse the interpreter's iterator protocol. * Captured identifiers retain their live Environment binding. diff --git a/src/Bytecode/Compiler.php b/src/Bytecode/Compiler.php index c55b40e3..482ed577 100644 --- a/src/Bytecode/Compiler.php +++ b/src/Bytecode/Compiler.php @@ -68,6 +68,7 @@ final class Compiler use Parts\CompilerEmit; use Parts\CompilerStatement; use Parts\CompilerExpression; + use Parts\CompilerStringLoopRegions; /** @var list */ private array $code = []; @@ -290,6 +291,7 @@ public function compile(JsFunction $fn): CompiledFunction } try { $compiled = $this->compileFunction($fn); + $this->finalizeStringLoopRegions($compiled); CompilationTemplates::remember($fn, $compiled); return $compiled; } catch (CompilerBailout $error) { @@ -303,6 +305,7 @@ private function compileFunction(JsFunction $fn): CompiledFunction if ($fn->isAsync() || $fn->isNative()) { throw new CompilerBailout('non-ordinary function kind'); } + $this->regionFunction = $this->ordinaryRegionFunction($fn); $this->thisFromFrame = !$fn->isArrow() && !$fn->isGenerator() && !$fn->isDerivedConstructor(); // Generators get a stricter bailout: only "simple" bodies // (no yield* delegation, no try/catch/finally containing diff --git a/src/Bytecode/JsToPhp.php b/src/Bytecode/JsToPhp.php index d76549f8..21e738f8 100644 --- a/src/Bytecode/JsToPhp.php +++ b/src/Bytecode/JsToPhp.php @@ -63,6 +63,7 @@ final class JsToPhp use Parts\JsToPhpEmitStatement; use Parts\JsToPhpEmitExpression; use Parts\JsToPhpStringScanners; + use Parts\JsToPhpLoopRegions; /** @var array */ private array $declaredLocals = []; diff --git a/src/Bytecode/Op.php b/src/Bytecode/Op.php index 13008dbe..27cc769b 100644 --- a/src/Bytecode/Op.php +++ b/src/Bytecode/Op.php @@ -189,6 +189,7 @@ final class Op public const LOOP_INIT = 120; public const LOOP_TICK = 121; public const CHECK_BUDGET = 126; // Host deadline checkpoint, independent of the body iteration count. + public const STRING_LOOP_REGION = 125; // I: one-shot pure first segment; ordinary VM backedges bypass it. public const ITERATOR_INIT = 122; // L: acquire an iterator and cached next in adjacent private slots. public const ITERATOR_NEXT = 123; // L I J: check loop limits, push the next value or branch when done. public const ITERATOR_CLOSE = 124; // L L L: close with the pending completion and value. @@ -285,6 +286,7 @@ public static function operandCount(int $op): int case self::MAKE_CLASS: case self::LOOP_INIT: case self::LOOP_TICK: + case self::STRING_LOOP_REGION: case self::ITERATOR_INIT: return 1; // 2-operand opcodes diff --git a/src/Bytecode/Parts/CompilerStatement.php b/src/Bytecode/Parts/CompilerStatement.php index 36e8dbba..1da95049 100644 --- a/src/Bytecode/Parts/CompilerStatement.php +++ b/src/Bytecode/Parts/CompilerStatement.php @@ -62,6 +62,7 @@ trait CompilerStatement { private function compileStatement(Node $node): void { + $this->recordRegionStatement($node); if ($node instanceof ReturnStatement) { if ($this->inGenerator && $this->finallyLoopBoundaries !== []) { throw new CompilerBailout('generator return inside try-with-finally'); @@ -532,6 +533,7 @@ private function compileWhile(WhileStatement $node): void { $loopId = $this->loopCount++; $this->emit(Op::LOOP_INIT, $loopId); + $region = $this->beginStringLoopRegion($node, $loopId); $loopStart = count($this->code); $this->emit(Op::CHECK_BUDGET); $this->compileExpression($node->test); @@ -544,6 +546,7 @@ private function compileWhile(WhileStatement $node): void $jumpOpcodePc = count($this->code) - 2; $this->code[$jumpOpcodePc + 1] = $loopStart - $jumpOpcodePc; $loopExit = count($this->code); + $this->finishStringLoopRegion($region, $loopStart, $loopExit); $this->patchJumpToHere($jmpExit); $frame = array_pop($this->loopStack); foreach ($frame['continues'] as $idx) { diff --git a/src/Bytecode/Parts/CompilerStringLoopRegions.php b/src/Bytecode/Parts/CompilerStringLoopRegions.php new file mode 100644 index 00000000..5aac521d --- /dev/null +++ b/src/Bytecode/Parts/CompilerStringLoopRegions.php @@ -0,0 +1,120 @@ + */ + private array $pendingLoopRegions = []; + + /** @var array Statement identity to its first-effect PC; -1 rejects ambiguous reuse. */ + private array $regionStatementPcs = []; + + private function ordinaryRegionFunction(JsFunction $function): bool + { + return !$function->isClassConstructor() && !$function->isDerivedConstructor() && $function->getBoundTarget() === null; + } + + private function recordRegionStatement(Node $node): void + { + if ($this->pendingLoopRegions === []) { + return; + } + $identity = spl_object_id($node); + $pc = count($this->code); + $previous = $this->regionStatementPcs[$identity] ?? $pc; + $this->regionStatementPcs[$identity] = $previous === $pc ? $pc : -1; + } + + private function beginStringLoopRegion(WhileStatement $node, int $loopId): ?int + { + if ( + !$this->regionFunction || $this->inGenerator || $this->parametersFromEnvironment + || $this->needsArguments || $this->capturedLocals !== [] + ) { + return null; + } + $plan = StringLoopRegionPlan::analyze($node, $this->localSlots, $this->capturedLocals, $this->constSlots); + if ($plan === null) { + return null; + } + $index = count($this->pendingLoopRegions); + $this->pendingLoopRegions[] = [ + 'plan' => $plan, 'opcode' => count($this->code), 'loopId' => $loopId, + 'entry' => -1, 'normalExit' => -1, + ]; + $this->emit(Op::STRING_LOOP_REGION, $index); + return $index; + } + + private function finishStringLoopRegion(?int $index, int $entry, int $normalExit): void + { + if ($index === null) { + return; + } + $this->pendingLoopRegions[$index]['entry'] = $entry; + $this->pendingLoopRegions[$index]['normalExit'] = $normalExit; + } + + /** Verify complete handler tables and bytecode before generating any executable region. */ + private function finalizeStringLoopRegions(CompiledFunction $function): void + { + $function->loopRegions = array_fill(0, count($this->pendingLoopRegions), null); + if ( + $this->parametersFromEnvironment || $this->needsArguments || $this->capturedLocals !== [] + || $this->arrayAssignmentReferences || $this->interpretedExpressions !== [] || $this->classNodes !== [] + ) { + return; + } + foreach ($this->pendingLoopRegions as $index => $pending) { + $entry = $pending['entry']; + $loopId = $pending['loopId']; + if ($entry < 0 || ($function->code[$entry] ?? null) !== Op::CHECK_BUDGET) { + continue; + } + $plan = $pending['plan']; + $exits = []; + foreach ($plan->exits as $node) { + $pc = $this->regionStatementPcs[spl_object_id($node)] ?? -1; + if ($pc < 0) { + continue 2; + } + $exits[] = $pc; + } + if ( + !StringLoopRegionVerifier::verify( + $function, + $plan, + $entry, + $pending['normalExit'], + $pending['opcode'], + $loopId, + $exits, + ) + ) { + continue; + } + $executor = JsToPhp::compileLoopRegion($plan, $loopId); + if ($executor === null) { + continue; + } + $exits[] = $pending['normalExit']; + $function->loopRegions[$index] = new StringLoopRegion($executor, $exits); + } + } +} diff --git a/src/Bytecode/Parts/JsToPhpEmitExpression.php b/src/Bytecode/Parts/JsToPhpEmitExpression.php index 4e3fd8fd..6699f90a 100644 --- a/src/Bytecode/Parts/JsToPhpEmitExpression.php +++ b/src/Bytecode/Parts/JsToPhpEmitExpression.php @@ -130,7 +130,7 @@ private function inferExpressionType(Node $node): string } if (isset($this->declaredLocals[$node->name])) { $kind = $this->localTypes[$node->name] ?? 'numeric'; - return $kind === 'numeric' ? 'numeric' : 'unknown'; + return $kind === 'numeric' ? 'numeric' : ($kind === 'boolean' ? 'boolean' : 'unknown'); } // Free var: emitExpression unboxes to numeric (with a // runtime JsNumber assertion). @@ -192,7 +192,7 @@ private function emitExpression(Node $node): string // means the local is being read in a context our // numeric pipeline can't lower. Bail. $kind = $this->localTypes[$node->name] ?? 'numeric'; - if ($kind !== 'numeric') { + if ($kind !== 'numeric' && $kind !== 'boolean') { throw new Bailout('non-numeric local in expression: ' . $node->name); } return $this->slotVar($node->name); diff --git a/src/Bytecode/Parts/JsToPhpEmitStatement.php b/src/Bytecode/Parts/JsToPhpEmitStatement.php index fdfc8198..09e7a487 100644 --- a/src/Bytecode/Parts/JsToPhpEmitStatement.php +++ b/src/Bytecode/Parts/JsToPhpEmitStatement.php @@ -166,6 +166,7 @@ private function emitStatement(Node $node): void $expr = $this->emitExpression($node->expression); $this->flushPending(); $this->emitLine($expr . ';'); + $this->emitRegionExpressionWrite($node->expression); return; } if ($node instanceof VariableDeclaration) { @@ -247,7 +248,7 @@ private function emitStatement(Node $node): void $callRaw = $this->emitFunctionValuedCall($decl->init); $this->flushPending(); $this->emitLine($this->slotVar($name) . ' = ' . $callRaw . ';'); - } elseif ($kind === 'numeric' && $decl->init instanceof CallExpression && $this->scannerPlan === null) { + } elseif ($kind === 'numeric' && $decl->init instanceof CallExpression && $this->scannerPlan === null && $this->loopRegion === null) { // `let r = callExpr()` where r's static type defaults // to numeric. emitExpression would emit the call THEN // a runtime `instanceof JsNumber` check that throws @@ -268,6 +269,7 @@ private function emitStatement(Node $node): void $this->flushPending(); $this->emitLine($this->slotVar($name) . ' = ' . $val . ';'); } + $this->emitRegionWrite($name); } return; } diff --git a/src/Bytecode/Parts/JsToPhpLoopRegions.php b/src/Bytecode/Parts/JsToPhpLoopRegions.php new file mode 100644 index 00000000..138cea70 --- /dev/null +++ b/src/Bytecode/Parts/JsToPhpLoopRegions.php @@ -0,0 +1,127 @@ +numericMode = true; + $compiler->loopRegion = $plan; + foreach ($plan->bindingTypes as $name => $type) { + $compiler->declaredLocals[$name] = true; + $compiler->localTypes[$name] = $type === 'number' ? 'numeric' : $type; + } + try { + $compiler->emitRegionGuards(); + foreach ($plan->inputs as $name => $binding) { + $compiler->emitRegionInput($name, $binding['slot'], $binding['type']); + } + foreach ($plan->outputs as $name => $_) { + $compiler->emitLine($compiler->regionWrittenFlag($name) . ' = false;'); + } + $compiler->emitLine('$_region_iterations = $loopCounts[' . $loopId . '] ?? 0;'); + $compiler->emitLine('try {'); + ++$compiler->indentLevel; + $compiler->emitLine('while (true) {'); + ++$compiler->indentLevel; + $compiler->emitLoopBudgetCheck(); + $condition = $compiler->emitExpression($plan->loop->test); + $compiler->flushPending(); + $compiler->emitLine('if (!(' . $condition . ')) { return ' . count($plan->exits) . '.0; }'); + $compiler->emitLoopTick('$_region_iterations'); + $compiler->emitStatement($plan->body); + --$compiler->indentLevel; + $compiler->emitLine('}'); + --$compiler->indentLevel; + $compiler->emitLine('} finally {'); + ++$compiler->indentLevel; + $compiler->emitLine('$loopCounts[' . $loopId . '] = $_region_iterations;'); + foreach ($plan->outputs as $name => $binding) { + $class = $binding['type'] === 'boolean' ? 'JsBoolean' : 'JsNumber'; + $compiler->emitLine('if (' . $compiler->regionWrittenFlag($name) . ') {'); + ++$compiler->indentLevel; + $compiler->emitLine('$locals[' . $binding['slot'] . '] = \\Phasis\\Value\\' . $class + . '::of(' . $compiler->slotVar($name) . ');'); + --$compiler->indentLevel; + $compiler->emitLine('}'); + } + --$compiler->indentLevel; + $compiler->emitLine('}'); + } catch (Bailout) { + return null; + } + $source = 'return static function (array &$locals, $interp, array &$loopCounts): ?float {' + . "\n" . $compiler->out . '};'; + $factory = self::scannerClosureFactory($plan->loop, $source); + if ($factory === null) { + return null; + } + $closure = $factory([], null); + return $closure instanceof \Closure ? $closure : null; + } + + private function emitRegionGuards(): void + { + $this->emitLine('$_region_context = \\Phasis\\Engine::getCurrentInterpreter();'); + $this->emitLine('if ($interp->hasExecutionBudget() || $_region_context?->hasExecutionBudget()' + . ' || $_region_context?->getRealm() !== $interp->getRealm() || $interp->getRealm() === null) { return null; }'); + $this->emitLine('if (!$interp->hasCachedStringIntrinsic("charCodeAt", "string.charCodeAt")) { return null; }'); + } + + private function emitRegionInput(string $name, int $slot, string $type): void + { + $variable = $this->slotVar($name); + $class = match ($type) { + 'number' => 'JsNumber', + 'boolean' => 'JsBoolean', + 'string' => 'JsString', + default => throw new Bailout('unknown region input type'), + }; + $this->emitLine($variable . ' = $locals[' . $slot . '] ?? null;'); + $this->emitLine('if (!(' . $variable . ' instanceof \\Phasis\\Value\\' . $class . ')) { return null; }'); + if ($type === 'string') { + $this->emitLine('if (get_class(' . $variable . ') !== \\Phasis\\Value\\JsString::class' + . ' || !' . $variable . '->isAscii()) { return null; }'); + } + $this->emitLine($variable . ' = ' . $variable . '->value;'); + } + + private function regionWrittenFlag(string $name): string + { + return '$_region_written_' . preg_replace('/[^A-Za-z0-9_]/', '_', $name); + } + + private function emitRegionWrite(string $name): void + { + if ($this->loopRegion !== null && isset($this->loopRegion->outputs[$name])) { + $this->emitLine($this->regionWrittenFlag($name) . ' = true;'); + } + } + + private function emitRegionExpressionWrite(Node $expression): void + { + if ($expression instanceof AssignmentExpression && $expression->left instanceof Identifier) { + $this->emitRegionWrite($expression->left->name); + } elseif ($expression instanceof UpdateExpression && $expression->argument instanceof Identifier) { + $this->emitRegionWrite($expression->argument->name); + } + } +} diff --git a/src/Bytecode/Parts/JsToPhpStringScanners.php b/src/Bytecode/Parts/JsToPhpStringScanners.php index d7d1f96f..551a319e 100644 --- a/src/Bytecode/Parts/JsToPhpStringScanners.php +++ b/src/Bytecode/Parts/JsToPhpStringScanners.php @@ -62,6 +62,15 @@ private function emitScannerStringParameter(string $name, int $index): void private function scannerCallType(CallExpression $expression): ?string { + if ( + $this->loopRegion !== null && $expression->callee instanceof MemberExpression + && !$expression->callee->computed && !$expression->callee->optional + && $expression->callee->object instanceof Identifier && $expression->callee->property instanceof Identifier + && ($this->loopRegion->bindingTypes[$expression->callee->object->name] ?? null) === 'string' + && $expression->callee->property->name === 'charCodeAt' + ) { + return 'numeric'; + } if ($this->scannerPlan === null) { return null; } @@ -81,7 +90,7 @@ private function scannerCallType(CallExpression $expression): ?string private function emitScannerCall(CallExpression $expression): ?string { $type = $this->scannerCallType($expression); - if ($type === null || $this->scannerPlan === null) { + if ($type === null || ($this->scannerPlan === null && $this->loopRegion === null)) { return null; } if ($type === 'numeric' && $expression->callee instanceof MemberExpression) { @@ -100,7 +109,7 @@ private function emitScannerCall(CallExpression $expression): ?string . ' ? NAN : (float) ord(' . $string . '[(int) ' . $position . ']);'; return $value; } - if (!$expression->callee instanceof Identifier) { + if (!$expression->callee instanceof Identifier || $this->scannerPlan === null) { throw new Bailout('scanner predicate is not a named binding'); } $predicate = $this->scannerPlan->predicates[$expression->callee->name]; diff --git a/src/Bytecode/StringLoopRegion.php b/src/Bytecode/StringLoopRegion.php new file mode 100644 index 00000000..ba1fc7e2 --- /dev/null +++ b/src/Bytecode/StringLoopRegion.php @@ -0,0 +1,14 @@ + $exitPcs */ + public function __construct(public \Closure $execute, public array $exitPcs) + { + } +} diff --git a/src/Bytecode/StringLoopRegionAnalysis.php b/src/Bytecode/StringLoopRegionAnalysis.php new file mode 100644 index 00000000..58b0ea57 --- /dev/null +++ b/src/Bytecode/StringLoopRegionAnalysis.php @@ -0,0 +1,385 @@ + */ + private array $types = []; + + /** @var array */ + private array $inputNames = []; + + /** @var array */ + private array $writtenNames = []; + + /** @var array */ + private array $declarations = []; + + /** @var list */ + private array $opaqueStatements = []; + + private bool $characterRead = false; + + /** + * @param array $slots + * @param array $captured + * @param array $constants + */ + private function __construct( + public readonly WhileStatement $loop, + private readonly array $slots, + private readonly array $captured, + private readonly array $constants, + ) { + } + + /** + * No partial effects are permitted when a proof or entry guard fails. + * + * @param array $slots + * @param array $captured + * @param array $constants + */ + public static function analyze(WhileStatement $loop, array $slots, array $captured, array $constants): ?StringLoopRegionPlan + { + if (!$loop->body instanceof BlockStatement) { + return null; + } + $plan = new self($loop, $slots, $captured, $constants); + if (!$plan->collectDeclarations($loop->body)) { + return null; + } + $initialized = []; + if ($plan->expressionType($loop->test, 'boolean', $initialized) !== 'boolean') { + return null; + } + [$body, $backedge] = $plan->rewrite($loop->body, $initialized); + if ( + !$body instanceof BlockStatement || !$backedge || !$plan->characterRead + || $plan->knownExpressionType($loop->test) !== 'boolean' || !$plan->recheckExpressions($body) + ) { + return null; + } + $safeNames = []; + foreach ($plan->types as $name => $_) { + $safe = preg_replace('/[^A-Za-z0-9_]/', '_', $name); + if (isset($safeNames[$safe])) { + return null; + } + $safeNames[$safe] = true; + } + $inputs = $outputs = []; + foreach ($plan->inputNames as $name => $_) { + $inputs[$name] = ['slot' => $slots[$name], 'type' => $plan->types[$name]]; + } + foreach ($plan->writtenNames as $name => $_) { + $outputs[$name] = ['slot' => $slots[$name], 'type' => $plan->types[$name]]; + } + return new StringLoopRegionPlan($loop, $body, $inputs, $outputs, $plan->types, $plan->opaqueStatements); + } + + private function collectDeclarations(Node $node): bool + { + if ( + $node instanceof WhileStatement || $node instanceof \Phasis\Ast\Statement\ForStatement + || $node instanceof \Phasis\Ast\Statement\ForOfStatement || $node instanceof \Phasis\Ast\Statement\ForInStatement + || $node instanceof \Phasis\Ast\Statement\DoWhileStatement + ) { + return false; + } + if ( + $node instanceof \Phasis\Ast\Declaration\FunctionDeclaration + || $node instanceof \Phasis\Ast\Expression\FunctionExpression || $node instanceof \Phasis\Ast\Expression\ArrowFunction + ) { + return true; + } + if ($node instanceof VariableDeclaration) { + foreach ($node->declarations as $declaration) { + if (!$declaration->id instanceof Identifier || isset($this->declarations[$declaration->id->name])) { + return false; + } + $this->declarations[$declaration->id->name] = $node->kind; + } + } + foreach (get_object_vars($node) as $value) { + foreach (is_array($value) ? $value : [$value] as $child) { + if ($child instanceof Node && !$this->collectDeclarations($child)) { + return false; + } + } + } + return true; + } + + /** + * @param array $initialized + * @return array{Node, bool} + */ + private function rewrite(Node $node, array &$initialized): array + { + if ($node instanceof EmptyStatement) { + return [$node, true]; + } + if ($node instanceof BlockStatement) { + $statements = []; + $fallsThrough = true; + $lexical = []; + foreach ($node->body as $statement) { + if (!$fallsThrough) { + break; + } + [$rewritten, $fallsThrough] = $this->rewrite($statement, $initialized); + $statements[] = $rewritten; + if ($statement instanceof VariableDeclaration && $statement->kind !== 'var') { + foreach ($statement->declarations as $declaration) { + if ($declaration->id instanceof Identifier) { + $lexical[$declaration->id->name] = true; + } + } + } + } + $initialized = array_diff_key($initialized, $lexical); + return [new BlockStatement($node->location, $statements), $fallsThrough]; + } + $saved = [$this->types, $this->inputNames, $this->writtenNames, $this->characterRead, $initialized]; + if ($node instanceof IfStatement && $this->expressionType($node->test, 'boolean', $initialized) === 'boolean') { + $yes = $no = $initialized; + [$consequent, $yesFallsThrough] = $this->rewrite($node->consequent, $yes); + [$alternate, $noFallsThrough] = $node->alternate !== null + ? $this->rewrite($node->alternate, $no) : [null, true]; + $initialized = $yesFallsThrough && $noFallsThrough ? array_intersect_key($yes, $no) + : ($yesFallsThrough ? $yes : $no); + return [new IfStatement($node->location, $node->test, $consequent, $alternate), $yesFallsThrough || $noFallsThrough]; + } + if ($node instanceof VariableDeclaration && in_array($node->kind, ['var', 'let', 'const'], true)) { + $valid = true; + foreach ($node->declarations as $declaration) { + if (!$declaration->id instanceof Identifier || $declaration->init === null) { + $valid = false; + break; + } + $name = $declaration->id->name; + $type = $this->expressionType($declaration->init, null, $initialized); + if (!in_array($type, ['number', 'boolean'], true) || !$this->binding($name, $type)) { + $valid = false; + break; + } + $initialized[$name] = true; + $this->writtenNames[$name] = true; + } + if ($valid) { + return [$node, true]; + } + } + if ($node instanceof ExpressionStatement) { + $expression = $node->expression; + if ($expression instanceof Literal && is_string($expression->value)) { + return [new EmptyStatement($node->location), true]; + } + if ($expression instanceof UpdateExpression && $expression->argument instanceof Identifier) { + $name = $expression->argument->name; + if (!$this->isConst($name) && $this->identifierType($name, 'number', $initialized) === 'number') { + $this->writtenNames[$name] = true; + return [$node, true]; + } + } + if ($expression instanceof AssignmentExpression && $expression->left instanceof Identifier) { + $name = $expression->left->name; + $type = $this->expressionType($expression->right, null, $initialized); + if ( + !$this->isConst($name) && in_array($type, ['number', 'boolean'], true) + && ($expression->operator === '=' || ($type === 'number' && in_array($expression->operator, ['+=', '-=', '*='], true))) + && $this->identifierType($name, $type, $initialized) === $type + ) { + $this->writtenNames[$name] = true; + return [$node, true]; + } + } + } + [$this->types, $this->inputNames, $this->writtenNames, $this->characterRead, $initialized] = $saved; + $exit = count($this->opaqueStatements); + $this->opaqueStatements[] = $node; + return [new ReturnStatement($node->location, new Literal($node->location, $exit, (string) $exit)), false]; + } + + private function isConst(string $name): bool + { + return ($this->declarations[$name] ?? null) === 'const' + || isset($this->slots[$name], $this->constants[$this->slots[$name]]); + } + + private function binding(string $name, string $type): bool + { + if (!isset($this->slots[$name]) || isset($this->captured[$name])) { + return false; + } + if (isset($this->types[$name]) && $this->types[$name] !== $type) { + return false; + } + $this->types[$name] = $type; + return true; + } + + /** @param array $initialized */ + private function identifierType(string $name, ?string $expected, array $initialized): ?string + { + if (isset($this->declarations[$name]) && !isset($initialized[$name])) { + return null; + } + $type = $expected ?? $this->types[$name] ?? 'number'; + if (!$this->binding($name, $type)) { + return null; + } + if (!isset($this->declarations[$name])) { + $this->inputNames[$name] = true; + } + return $type; + } + + /** @param array $initialized */ + private function expressionType(Node $node, ?string $expected, array $initialized): ?string + { + $type = null; + if ($node instanceof Identifier) { + $type = $this->identifierType($node->name, $expected, $initialized); + } elseif ($node instanceof Literal) { + $type = is_bool($node->value) ? 'boolean' : (is_int($node->value) || is_float($node->value) ? 'number' : null); + } elseif ($node instanceof MemberExpression && $this->stringMember($node, 'length', $initialized)) { + $type = 'number'; + } elseif ( + $node instanceof CallExpression && !$node->optional && $node->callee instanceof MemberExpression + && $this->stringMember($node->callee, 'charCodeAt', $initialized) && count($node->arguments) === 1 + && $this->expressionType($node->arguments[0], 'number', $initialized) === 'number' + ) { + $this->characterRead = true; + $type = 'number'; + } elseif ($node instanceof UnaryExpression && $node->prefix) { + $argumentType = $node->operator === '!' ? 'boolean' : (in_array($node->operator, ['+', '-'], true) ? 'number' : null); + if ($argumentType !== null && $this->expressionType($node->argument, $argumentType, $initialized) === $argumentType) { + $type = $argumentType; + } + } elseif ($node instanceof BinaryExpression) { + $equality = in_array($node->operator, ['===', '!==', '==', '!='], true); + $operandType = $equality && ($this->knownBoolean($node->left) || $this->knownBoolean($node->right)) ? 'boolean' : 'number'; + if ( + ($equality || in_array($node->operator, ['+', '-', '*', '/', '%', '<', '>', '<=', '>='], true)) + && $this->expressionType($node->left, $operandType, $initialized) === $operandType + && $this->expressionType($node->right, $operandType, $initialized) === $operandType + ) { + $type = in_array($node->operator, ['+', '-', '*', '/', '%'], true) ? 'number' : 'boolean'; + } + } elseif ( + $node instanceof LogicalExpression && in_array($node->operator, ['&&', '||'], true) + && $this->expressionType($node->left, 'boolean', $initialized) === 'boolean' + && $this->expressionType($node->right, 'boolean', $initialized) === 'boolean' + ) { + $type = 'boolean'; + } elseif ($node instanceof ConditionalExpression && $this->expressionType($node->test, 'boolean', $initialized) === 'boolean') { + $yes = $this->expressionType($node->consequent, $expected, $initialized); + if ($yes !== null && $this->expressionType($node->alternate, $yes, $initialized) === $yes) { + $type = $yes; + } + } + return $expected === null || $type === $expected ? $type : null; + } + + private function recheckExpressions(Node $node): bool + { + if ($node instanceof BlockStatement) { + foreach ($node->body as $statement) { + if (!$this->recheckExpressions($statement)) { + return false; + } + } + return true; + } + if ($node instanceof IfStatement) { + return $this->knownExpressionType($node->test) === 'boolean' + && $this->recheckExpressions($node->consequent) + && ($node->alternate === null || $this->recheckExpressions($node->alternate)); + } + if ($node instanceof VariableDeclaration) { + foreach ($node->declarations as $declaration) { + if ($declaration->init === null || $this->knownExpressionType($declaration->init) === null) { + return false; + } + } + return true; + } + if ($node instanceof ExpressionStatement) { + return $node->expression instanceof UpdateExpression + || ($node->expression instanceof AssignmentExpression && $this->knownExpressionType($node->expression->right) !== null); + } + return $node instanceof EmptyStatement || ($node instanceof ReturnStatement && $node->argument instanceof Literal); + } + + private function knownExpressionType(Node $node): ?string + { + if ($node instanceof Identifier) { + $type = $this->types[$node->name] ?? null; + return $type === 'number' || $type === 'boolean' ? $type : null; + } + if ($node instanceof Literal) { + return is_bool($node->value) ? 'boolean' : (is_int($node->value) || is_float($node->value) ? 'number' : null); + } + if ($node instanceof MemberExpression) { + return $this->knownStringMember($node, 'length') ? 'number' : null; + } + if ( + $node instanceof CallExpression && !$node->optional && $node->callee instanceof MemberExpression + && $this->knownStringMember($node->callee, 'charCodeAt') && count($node->arguments) === 1 + && $this->knownExpressionType($node->arguments[0]) === 'number' + ) { + return 'number'; + } + return StringScannerPlan::scalarExpressionType($node, fn (Node $child): ?string => $this->knownExpressionType($child)); + } + + private function knownStringMember(MemberExpression $node, string $name): bool + { + return !$node->computed && !$node->optional && $node->object instanceof Identifier + && ($this->types[$node->object->name] ?? null) === 'string' + && $node->property instanceof Identifier && $node->property->name === $name; + } + + private function knownBoolean(Node $node): bool + { + return ($node instanceof Literal && is_bool($node->value)) + || ($node instanceof Identifier && ($this->types[$node->name] ?? null) === 'boolean'); + } + + /** @param array $initialized */ + private function stringMember(MemberExpression $node, string $name, array $initialized): bool + { + if ( + $node->computed || $node->optional || !$node->object instanceof Identifier + || !$node->property instanceof Identifier || $node->property->name !== $name + ) { + return false; + } + return $this->identifierType($node->object->name, 'string', $initialized) === 'string'; + } +} diff --git a/src/Bytecode/StringLoopRegionPlan.php b/src/Bytecode/StringLoopRegionPlan.php new file mode 100644 index 00000000..8448c124 --- /dev/null +++ b/src/Bytecode/StringLoopRegionPlan.php @@ -0,0 +1,41 @@ + $inputs + * @param array $outputs + * @param array $bindingTypes + * @param list $exits Original statements at which execution must return to the VM. + */ + public function __construct( + public WhileStatement $loop, + public BlockStatement $body, + public array $inputs, + public array $outputs, + public array $bindingTypes, + public array $exits, + ) { + } + + /** + * No partial effects are permitted when a proof or entry guard fails. + * + * @param array $slots + * @param array $captured + * @param array $constants + */ + public static function analyze(WhileStatement $loop, array $slots, array $captured, array $constants): ?self + { + return StringLoopRegionAnalysis::analyze($loop, $slots, $captured, $constants); + } +} diff --git a/src/Bytecode/StringLoopRegionVerifier.php b/src/Bytecode/StringLoopRegionVerifier.php new file mode 100644 index 00000000..2a834b32 --- /dev/null +++ b/src/Bytecode/StringLoopRegionVerifier.php @@ -0,0 +1,209 @@ + $exits */ + public static function verify( + CompiledFunction $function, + StringLoopRegionPlan $plan, + int $entry, + int $normalExit, + int $opcodePc, + int $loopId, + array $exits, + ): bool { + $code = $function->code; + if (($code[$entry] ?? null) !== Op::CHECK_BUDGET) { + return false; + } + $boundaries = []; + try { + for ($pc = 0, $count = count($code); $pc < $count;) { + $boundaries[$pc] = true; + $width = 1 + Op::operandCount($code[$pc]); + if ($pc + $width > $count) { + return false; + } + $pc += $width; + } + } catch (\LogicException) { + return false; + } + $stops = array_fill_keys([...$exits, $normalExit], true); + foreach ($stops as $pc => $_) { + if (!isset($boundaries[$pc]) || $pc < $entry || $pc > $normalExit) { + return false; + } + } + $slotTypes = $written = $initial = []; + foreach ($plan->bindingTypes as $name => $type) { + $binding = $plan->inputs[$name] ?? $plan->outputs[$name] ?? null; + if ($binding === null || isset($slotTypes[$binding['slot']])) { + return false; + } + $slotTypes[$binding['slot']] = $type; + } + foreach ($plan->inputs as $binding) { + $initial[$binding['slot']] = true; + } + foreach ($plan->outputs as $binding) { + $written[$binding['slot']] = true; + } + $queue = [[$entry, 0, $initial, false]]; + $seen = []; + $backedge = false; + $tickSeen = false; + $steps = 0; + while ($queue !== []) { + if (++$steps > 100000) { + return false; + } + [$pc, $height, $initialized, $ticked] = array_pop($queue); + if ($height < 0 || !isset($boundaries[$pc])) { + return false; + } + if (isset($stops[$pc])) { + if ($height !== 0 || ($pc !== $normalExit && !$ticked)) { + return false; + } + continue; + } + if ($pc < $entry || $pc >= $normalExit) { + return false; + } + if (isset($seen[$pc])) { + if ($seen[$pc][0] !== $height || $seen[$pc][2] !== $ticked) { + return false; + } + $merged = array_intersect_key($initialized, $seen[$pc][1]); + if (count($merged) === count($seen[$pc][1])) { + continue; + } + $initialized = $merged; + } + $seen[$pc] = [$height, $initialized, $ticked]; + $op = $code[$pc]; + $next = $pc + 1 + Op::operandCount($op); + $edges = []; + if ($op === Op::LOAD_LOCAL) { + $slot = $code[$pc + 1]; + if (!isset($slotTypes[$slot], $initialized[$slot])) { + return false; + } + ++$height; + } elseif ($op === Op::STORE_LOCAL) { + $slot = $code[$pc + 1]; + if ($height < 1 || !isset($written[$slot])) { + return false; + } + $initialized[$slot] = true; + --$height; + } elseif ($op === Op::INC_LOCAL || $op === Op::DEC_LOCAL) { + $slot = $code[$pc + 1]; + if (!isset($written[$slot], $initialized[$slot]) || $slotTypes[$slot] !== 'number') { + return false; + } + } elseif ($op === Op::LOAD_CONST) { + $constant = $function->consts[$code[$pc + 1]] ?? null; + if (!$constant instanceof JsNumber && !$constant instanceof JsBoolean) { + return false; + } + ++$height; + } elseif ($op === Op::LOAD_TRUE || $op === Op::LOAD_FALSE) { + ++$height; + } elseif ($op === Op::DUP) { + if ($height < 1) { + return false; + } + ++$height; + } elseif ($op === Op::POP) { + if ($height < 1) { + return false; + } + --$height; + } elseif ($op === Op::LOAD_MEMBER) { + if ($height < 1 || !in_array($function->names[$code[$pc + 1]] ?? null, ['length', 'charCodeAt'], true)) { + return false; + } + } elseif ($op === Op::CALL_METHOD) { + if ($height < 3 || $code[$pc + 1] !== 1) { + return false; + } + $height -= 2; + } elseif ( + in_array($op, [Op::ADD, Op::SUB, Op::MUL, Op::DIV, Op::MOD, Op::LT, Op::GT, Op::LE, + Op::GE, Op::EQ, Op::NEQ, Op::SEQ, Op::SNEQ], true) + ) { + if ($height < 2) { + return false; + } + --$height; + } elseif (in_array($op, [Op::NEG, Op::POS, Op::NOT], true)) { + if ($height < 1) { + return false; + } + } elseif ($op === Op::CHECK_BUDGET) { + if (!self::sameHandlers($function, $opcodePc, $pc)) { + return false; + } + } elseif ($op === Op::LOOP_TICK) { + if ($ticked || $code[$pc + 1] !== $loopId || !self::sameHandlers($function, $opcodePc, $pc)) { + return false; + } + $tickSeen = true; + $ticked = true; + } elseif ($op === Op::JUMP) { + $edges[] = [$pc + $code[$pc + 1], $height]; + } elseif ($op === Op::JUMP_IF_FALSE || $op === Op::JUMP_IF_TRUE) { + if ($height < 1) { + return false; + } + --$height; + $edges = [[$next, $height], [$pc + $code[$pc + 1], $height]]; + } elseif ($op === Op::JUMP_IF_TRUTHY_KEEP || $op === Op::JUMP_IF_FALSY_KEEP) { + if ($height < 1) { + return false; + } + $edges = [[$next, $height - 1], [$pc + $code[$pc + 1], $height]]; + } else { + return false; + } + if ($edges === []) { + $edges[] = [$next, $height]; + } + foreach ($edges as [$target, $targetHeight]) { + $edgeTicked = $ticked; + if ($target === $entry && $target <= $pc) { + if (!$ticked) { + return false; + } + $backedge = true; + $edgeTicked = false; + } + $queue[] = [$target, $targetHeight, $initialized, $edgeTicked]; + } + } + return $backedge && $tickSeen; + } + + private static function sameHandlers(CompiledFunction $function, int $first, int $second): bool + { + foreach ($function->handlers as $handler) { + if ( + ($first >= $handler->tryStart && $first < $handler->tryEnd) + !== ($second >= $handler->tryStart && $second < $handler->tryEnd) + ) { + return false; + } + } + return true; + } +} diff --git a/src/Bytecode/StringScannerPlan.php b/src/Bytecode/StringScannerPlan.php index 9285f788..9661f208 100644 --- a/src/Bytecode/StringScannerPlan.php +++ b/src/Bytecode/StringScannerPlan.php @@ -383,7 +383,7 @@ private static function predicateExpressionType(Node $expression, array $paramet } /** @param \Closure(Node): ?string $type */ - private static function scalarExpressionType(Node $expression, \Closure $type): ?string + public static function scalarExpressionType(Node $expression, \Closure $type): ?string { if ($expression instanceof UnaryExpression) { $argument = $type($expression->argument); diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 45850cee..2921340e 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -816,6 +816,21 @@ public function execute( $loopCounts[$code[$pc + 1]] = 0; $pc += 2; break; + case Op::STRING_LOOP_REGION: + $region = $cf->loopRegions[$code[$pc + 1]] ?? null; + if ($sp === 0 && $region !== null) { + $exit = ($region->execute)($locals, $this->interp, $loopCounts); + if ($exit !== null) { + $token = (int) $exit; + if (!isset($region->exitPcs[$token])) { + throw new \LogicException('Pure loop returned an invalid exit'); + } + $pc = $region->exitPcs[$token]; + break; + } + } + $pc += 2; + break; case Op::CHECK_BUDGET: if ($this->interp->hasExecutionBudget()) { $this->interp->checkBudget(); diff --git a/tests/Unit/Bytecode/StringLoopRegionTest.php b/tests/Unit/Bytecode/StringLoopRegionTest.php new file mode 100644 index 00000000..d279b9f8 --- /dev/null +++ b/tests/Unit/Bytecode/StringLoopRegionTest.php @@ -0,0 +1,323 @@ +eval(self::SOURCE); + self::assertSame([[1, 4], [2, 3], [3], 2], $engine->eval("[scan('abc,def', 0), scan('abc', 0), events, creations]")); + $compiled = $this->compiled($engine); + self::assertCount(1, array_filter($compiled->loopRegions)); + $regionPc = $this->regionPc($compiled); + $entry = $regionPc + 2; + self::assertSame(Op::CHECK_BUDGET, $compiled->code[$entry]); + for ($pc = 0; $pc < count($compiled->code); $pc += 1 + Op::operandCount($compiled->code[$pc])) { + if ($compiled->code[$pc] === Op::JUMP && $compiled->code[$pc + 1] < 0) { + self::assertSame($entry, $pc + $compiled->code[$pc + 1]); + } + } + } + + public function testNativeExitRestoresActiveSlotsAndCounterExactlyOnce(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + $engine->eval("scan('a,b', 0)"); + $compiled = $this->compiled($engine); + [$region, $locals, $counts, $loopId] = $this->prepare($compiled, 'abc,def'); + $exit = $this->execute($engine, $region, $locals, $counts); + self::assertNotNull($exit); + self::assertSame(3.0, $locals[array_search('index', $compiled->localNames, true)]->value); + self::assertSame(44.0, $locals[array_search('code', $compiled->localNames, true)]->value); + self::assertSame(4, $counts[$loopId]); + self::assertSame([1], $engine->eval('events')); + self::assertSame(1, $engine->eval('creations')); + } + + public function testFinalFalseDoesNotCountAndLimitThrowsCommitTheSameState(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + $engine->eval("scan('ab', 0)"); + $compiled = $this->compiled($engine); + [$region, $locals, $counts, $loopId] = $this->prepare($compiled, 'ab'); + self::assertNotNull($this->execute($engine, $region, $locals, $counts)); + self::assertSame(2, $counts[$loopId]); + self::assertSame(2.0, $locals[array_search('index', $compiled->localNames, true)]->value); + $engine->setLimit('maxLoopIterations', 2); + [$region, $locals, $counts, $loopId] = $this->prepare($compiled, 'abcd'); + try { + $this->execute($engine, $region, $locals, $counts); + self::fail('The region skipped its precondition checkpoint'); + } catch (InternalError) { + } + self::assertSame(3, $counts[$loopId]); + self::assertSame(2.0, $locals[array_search('index', $compiled->localNames, true)]->value); + self::assertSame(98.0, $locals[array_search('code', $compiled->localNames, true)]->value); + } + + public function testAHandlerObservesUpdatesCommittedBeforeTheLimitThrows(): void + { + $engine = new Engine(); + $engine->eval(<<<'JS' +function prime(text) { return [text.charCodeAt(0)]; } +prime('x'); +function observed(text) { + const state = {}; + let index = 0; + try { + while (index < text.length) { + const code = text.charCodeAt(index); + if (code === 44) break; + index++; + } + } catch (error) { return [index, String(error).includes('Maximum loop iterations')]; } + return [index, false]; +} +JS); + $engine->setLimit('maxLoopIterations', 2); + self::assertSame([2, true], $engine->eval("observed('abcd')")); + } + + public function testGuardFailureDoesNotReadGettersOrWriteAnySlot(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + $engine->eval("scan('ab', 0)"); + $compiled = $this->compiled($engine); + [$region, $locals, $counts] = $this->prepare($compiled, 'é'); + $original = $locals; + self::assertNull($this->execute($engine, $region, $locals, $counts)); + self::assertSame($original, $locals); + self::assertSame([], $counts); + $engine->eval(<<<'JS' +let accesses = 0; +const original = String.prototype.charCodeAt; +Object.defineProperty(String.prototype, 'charCodeAt', { configurable: true, get() { accesses++; return original; } }); +JS); + [$region, $locals, $counts] = $this->prepare($compiled, 'ab'); + self::assertNull($this->execute($engine, $region, $locals, $counts)); + self::assertSame(0, $engine->eval('accesses')); + self::assertSame([2, 2], $engine->eval("[scan('ab', 0)[1], accesses]")); + } + + public function testOpaqueContinueReturnsToOrdinaryBytecodeAfterMethodMutation(): void + { + $engine = new Engine(); + self::assertSame([4, [2, 3]], $engine->eval(<<<'JS' +const native = String.prototype.charCodeAt; +const reads = []; +function prime(text) { return [text.charCodeAt(0)]; } +prime('x'); +function scan(text) { + const state = {}; + let index = 0; + while (index < text.length) { + const code = text.charCodeAt(index); + if (code === 44) { + String.prototype.charCodeAt = function (position) { reads.push(position); return native.call(this, position); }; + index++; + continue; + } + index++; + } + return index; +} +const result = scan('a,bc'); +String.prototype.charCodeAt = native; +[result, reads]; +JS)); + self::assertNotEmpty(array_filter($this->compiled($engine)->loopRegions)); + } + + public function testBooleanStateAndNumericUpdatesStayTypedAcrossIterations(): void + { + $engine = new Engine(); + self::assertSame([4, false], $engine->eval(<<<'JS' +function prime(text) { return [text.charCodeAt(0)]; } +prime('x'); +function scan(text) { + const state = {}; + let index = 0; + let alternate = false; + while (index < text.length) { + const code = text.charCodeAt(index); + if (alternate && code === 92) index++; + if (code === 44) break; + alternate = !alternate; + index++; + } + return [index, alternate]; +} +scan('abcd'); +JS)); + self::assertNotEmpty(array_filter($this->compiled($engine)->loopRegions)); + } + + public function testNumericObjectCoercionAndPrefixEffectsAreNotReplayed(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + self::assertSame([[1, 3], 3, 1], $engine->eval(<<<'JS' +let coercions = 0; +const offset = { valueOf() { coercions++; return 0; } }; +[scan('abc', offset), coercions, creations]; +JS)); + self::assertNotEmpty(array_filter($this->compiled($engine)->loopRegions)); + } + + public function testSharedTemplateExecutorsUseTheInvocationRealm(): void + { + $first = new Engine(); + $first->eval(self::SOURCE); + $first->eval("scan('ab', 0)"); + $source = $first->getGlobalEnv()->get('scan'); + self::assertInstanceOf(\Phasis\Value\JsFunction::class, $source); + $second = new Engine(); + $second->eval(self::SOURCE); + $shared = new \Phasis\Value\JsFunction('shared', $source->getParams(), $source->getBody(), $second->getGlobalEnv()); + $shared->realm = $second; + $second->setGlobalJsValue('shared', $shared); + self::assertSame([1, 2], $second->eval("shared('ab', 0)")); + self::assertInstanceOf(CompiledFunction::class, $shared->compiled); + self::assertNotSame($source->compiled, $shared->compiled); + self::assertSame($source->compiled->loopRegions[0], $shared->compiled->loopRegions[0]); + $second->eval(<<<'JS' +let reads = 0; +const method = String.prototype.charCodeAt; +Object.defineProperty(String.prototype, 'charCodeAt', { configurable: true, get() { reads++; return method; } }); +JS); + [$region, $locals, $counts] = $this->prepare($this->compiled($first), 'ab'); + self::assertNull($this->execute($second, $region, $locals, $counts)); + self::assertSame(0, $second->eval('reads')); + self::assertNotNull($this->execute($first, $region, $locals, $counts)); + } + + public function testABudgetActivatedBeforeEntryUsesTheOriginalCheckpoint(): void + { + $engine = new Engine(); + $expire = false; + $hooks = 0; + $engine->setGlobal('activateBudget', static function () use ($engine, &$expire, &$hooks): void { + ++$hooks; + if ($expire) { + $engine->setExecutionBudget(-1); + } + }); + $engine->eval(<<<'JS' +let prefixes = 0; +let swallowed = 0; +function prime(text) { return [text.charCodeAt(0)]; } +prime('x'); +function scan(text) { + const state = { count: ++prefixes }; + let index = 0; + activateBudget(); + try { + while (index < text.length) { + const code = text.charCodeAt(index); + if (code === 44) break; + index++; + } + } catch (error) { swallowed++; } + return index; +} +scan('ab'); +JS); + self::assertNotEmpty(array_filter($this->compiled($engine)->loopRegions)); + $expire = true; + try { + $engine->eval("scan('ab')"); + self::fail('An expired budget entered a pure region'); + } catch (BudgetExceeded) { + } + $engine->setExecutionBudget(null); + self::assertSame([2, 0], $engine->eval('[prefixes, swallowed]')); + self::assertSame(2, $hooks); + } + + private function compiled(Engine $engine): CompiledFunction + { + $function = $engine->getGlobalEnv()->get('scan'); + self::assertInstanceOf(\Phasis\Value\JsFunction::class, $function); + self::assertNull($function->phpCompiled); + self::assertInstanceOf(CompiledFunction::class, $function->compiled); + return $function->compiled; + } + + private function regionPc(CompiledFunction $compiled): int + { + for ($pc = 0; $pc < count($compiled->code); $pc += 1 + Op::operandCount($compiled->code[$pc])) { + if ($compiled->code[$pc] === Op::STRING_LOOP_REGION) { + return $pc; + } + } + self::fail('The function did not emit a region entry'); + } + + /** @return array{StringLoopRegion, list<\Phasis\Value\JsValue>, array, int} */ + private function prepare(CompiledFunction $compiled, string $text): array + { + $pc = $this->regionPc($compiled); + $region = $compiled->loopRegions[$compiled->code[$pc + 1]]; + self::assertInstanceOf(StringLoopRegion::class, $region); + $locals = array_fill(0, $compiled->slotCount, JsUndefined::instance()); + $locals[array_search('text', $compiled->localNames, true)] = new JsString($text); + $locals[array_search('index', $compiled->localNames, true)] = JsNumber::of(0); + for ($tick = $pc + 2; $tick < count($compiled->code); $tick += 1 + Op::operandCount($compiled->code[$tick])) { + if ($compiled->code[$tick] === Op::LOOP_TICK) { + return [$region, $locals, [], $compiled->code[$tick + 1]]; + } + } + self::fail('The region has no iteration checkpoint'); + } + + /** @param list<\Phasis\Value\JsValue> $locals @param array $counts */ + private function execute(Engine $engine, StringLoopRegion $region, array &$locals, array &$counts): ?float + { + $previous = Engine::getCurrentInterpreter(); + Engine::setCurrentInterpreter($engine->getInterpreter()); + try { + return ($region->execute)($locals, $engine->getInterpreter(), $counts); + } finally { + Engine::setCurrentInterpreter($previous); + } + } +} From 430f54b5dfb5c03121100d561848e2e157e74f3e Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:44:06 +0200 Subject: [PATCH 61/99] Respect nested lexical shadows in block binding proofs --- src/Bytecode/Parts/CompilerBlockBindings.php | 34 +++- .../Bytecode/ShadowedBlockBindingTest.php | 50 ++++++ .../fixtures/shadowed-block-bindings.js | 145 ++++++++++++++++++ .../fixtures/shadowed-block-bindings.json | 47 ++++++ 4 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 tests/Unit/Bytecode/ShadowedBlockBindingTest.php create mode 100644 tests/Unit/Bytecode/fixtures/shadowed-block-bindings.js create mode 100644 tests/Unit/Bytecode/fixtures/shadowed-block-bindings.json diff --git a/src/Bytecode/Parts/CompilerBlockBindings.php b/src/Bytecode/Parts/CompilerBlockBindings.php index 6c2ed9ac..7581a58e 100644 --- a/src/Bytecode/Parts/CompilerBlockBindings.php +++ b/src/Bytecode/Parts/CompilerBlockBindings.php @@ -149,9 +149,10 @@ private function blockBindingLifetimeIsIndependent( $node instanceof FunctionDeclaration || $node instanceof FunctionExpression || $node instanceof ArrowFunction || $node instanceof ClassDeclaration || $node instanceof ClassExpression ) { - // Even a shadowed use is conservatively excluded here. A fresh - // environment remains necessary for any possible closure capture. - return !$this->blockBindingNameOccurs($node, $name); + // Ordinary nested bodies may shadow this name in their own block. + // Class evaluation keeps the conservative scope proof. + $resolveFunctionScopes = !$node instanceof ClassDeclaration && !$node instanceof ClassExpression; + return !$this->blockBindingNameOccurs($node, $name, $resolveFunctionScopes); } if ($node instanceof VariableDeclaration) { foreach ($node->declarations as $declaration) { @@ -193,14 +194,37 @@ private function blockBindingLifetimeIsIndependent( return true; } - private function blockBindingNameOccurs(Node $node, string $name): bool + private function blockBindingNameOccurs(Node $node, string $name, bool $resolveFunctionScopes = false): bool { if ($node instanceof Identifier && $node->name === $name) { return true; } + if ($node instanceof ClassDeclaration || $node instanceof ClassExpression) { + $resolveFunctionScopes = false; + } + if ($resolveFunctionScopes && $node instanceof BlockStatement) { + foreach ($node->body as $statement) { + if (!$statement instanceof VariableDeclaration || ($statement->kind !== 'let' && $statement->kind !== 'const')) { + continue; + } + foreach ($statement->declarations as $declaration) { + if ($declaration->id instanceof Identifier && $declaration->id->name === $name) { + // The binding shadows the outer name throughout this + // exact block, including its initializer and TDZ. + return false; + } + } + } + } + if ($resolveFunctionScopes && $node instanceof MemberExpression && !$node->computed) { + return $this->blockBindingNameOccurs($node->object, $name, $resolveFunctionScopes); + } + if ($resolveFunctionScopes && $node instanceof Property && !$node->computed) { + return $this->blockBindingNameOccurs($node->value, $name, $resolveFunctionScopes); + } foreach (get_object_vars($node) as $value) { foreach (is_array($value) ? $value : [$value] as $child) { - if ($child instanceof Node && $this->blockBindingNameOccurs($child, $name)) { + if ($child instanceof Node && $this->blockBindingNameOccurs($child, $name, $resolveFunctionScopes)) { return true; } } diff --git a/tests/Unit/Bytecode/ShadowedBlockBindingTest.php b/tests/Unit/Bytecode/ShadowedBlockBindingTest.php new file mode 100644 index 00000000..0dea457e --- /dev/null +++ b/tests/Unit/Bytecode/ShadowedBlockBindingTest.php @@ -0,0 +1,50 @@ +checkOracle(false); + foreach (['literalKeys', 'innerLexical', 'innerDeadZone', 'innerThrow'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled, $name); + } + $fallbacks = [ + 'mixedCapture', 'defaultCapture', 'computedCapture', 'shorthandCapture', 'nestedClassEval', + 'nestedClassKeyEval', 'nestedEval', 'nestedWith', 'siblingBlocks', + ]; + foreach ($fallbacks as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->compiled, $name); + } + } + + public function testBudgetedExecutionMatchesTheSameNodeOracle(): void + { + $this->checkOracle(true); + } + + private function checkOracle(bool $budgeted): Engine + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/shadowed-block-bindings.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/shadowed-block-bindings.json', + $engine->eval('JSON.stringify(shadowedBlockResult)'), + ); + return $engine; + } +} diff --git a/tests/Unit/Bytecode/fixtures/shadowed-block-bindings.js b/tests/Unit/Bytecode/fixtures/shadowed-block-bindings.js new file mode 100644 index 00000000..7834570a --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/shadowed-block-bindings.js @@ -0,0 +1,145 @@ +const shadowedBlockResult = []; +function literalKeys() { + function read(record) { return {value: record.value}.value; } + let result = 0; + for (var index = 0; index < 3; index++) { + const value = index; + result += read({value}); + } + return result; +} +function innerLexical() { + function read(values) { + let result = 0; + while (values.length) { + const token = values.pop(); + result += token; + } + return result; + } + let result = 0; + for (var index = 0; index < 3; index++) { + const token = index; + result += token + read([3, 5]); + } + return result; +} +function innerDeadZone() { + function read() { + try { return token; } catch (error) { return error.name; } + const token = 9; + } + let result = ''; + for (var index = 0; index < 2; index++) { + const token = index; + result += token + ':' + read() + ';'; + } + return result; +} +function mixedCapture() { + var saved; + for (var index = 0; index < 3; index++) { + const token = index; + saved = () => { + if (false) { const token = 99; return token; } + return token; + }; + } + return saved(); +} +function defaultCapture() { + var saved; + for (var index = 0; index < 3; index++) { + const token = index; + saved = function read(value = token) { const token = 99; return value; }; + } + return saved(); +} +function computedCapture() { + var saved; + for (var index = 0; index < 3; index++) { + const token = index; + saved = () => ({[token]: 7}); + } + return Object.keys(saved()); +} +function shorthandCapture() { + var saved; + for (var index = 0; index < 3; index++) { + const token = index; + saved = () => ({token}); + } + return saved().token; +} +function nestedClassEval() { + var Saved; + for (var index = 0; index < 3; index++) { + const token = index; + Saved = class { + read() { + if (false) { const token = 8; } + return eval('token'); + } + }; + } + return new Saved().read(); +} +function nestedClassKeyEval() { + var Saved; + for (var index = 0; index < 3; index++) { + const token = index; + Saved = class { token() { return eval('token'); } }; + } + return new Saved().token(); +} +function nestedEval() { + var saved; + for (var index = 0; index < 3; index++) { + const token = index; + saved = function read() { + if (false) { const token = 8; } + return eval('token'); + }; + } + return saved(); +} +function nestedWith() { + var saved; + for (var index = 0; index < 3; index++) { + const token = index; + saved = function read() { + if (false) { const token = 8; } + with ({}) { return token; } + }; + } + return saved(); +} +function throwShadowValue() { throw 'inner'; } +function innerThrow() { + function read() { const token = throwShadowValue(); return token; } + let result = ''; + for (var index = 0; index < 2; index++) { + const token = index; + try { read(); } catch (error) { result += token + ':' + error + ';'; } + } + return result; +} +function siblingBlocks() { + function read(enabled) { + if (enabled) { const token = 3; return () => token; } + { let token = 7; return () => ++token; } + } + let result = 0; + for (var index = 0; index < 2; index++) { + const token = index; + const first = read(true); + const second = read(false); + result += token + first() + second() + second(); + } + return result; +} +for (let pass = 0; pass < 3; pass++) { + shadowedBlockResult.push(literalKeys(), innerLexical(), innerDeadZone(), mixedCapture(), defaultCapture(), + computedCapture(), shorthandCapture(), nestedClassEval(), nestedClassKeyEval(), nestedEval(), nestedWith(), + innerThrow(), siblingBlocks()); +} diff --git a/tests/Unit/Bytecode/fixtures/shadowed-block-bindings.json b/tests/Unit/Bytecode/fixtures/shadowed-block-bindings.json new file mode 100644 index 00000000..783e4b29 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/shadowed-block-bindings.json @@ -0,0 +1,47 @@ +[ + 3, + 27, + "0:ReferenceError;1:ReferenceError;", + 2, + 2, + [ + "2" + ], + 2, + 2, + 2, + 2, + 2, + "0:inner;1:inner;", + 41, + 3, + 27, + "0:ReferenceError;1:ReferenceError;", + 2, + 2, + [ + "2" + ], + 2, + 2, + 2, + 2, + 2, + "0:inner;1:inner;", + 41, + 3, + 27, + "0:ReferenceError;1:ReferenceError;", + 2, + 2, + [ + "2" + ], + 2, + 2, + 2, + 2, + 2, + "0:inner;1:inner;", + 41 +] From ba525bc2c32f8fd20bc692dcdcc0b6d9548d680a Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 02:45:20 +0200 Subject: [PATCH 62/99] Speed numeric Uint8Array indexed writes --- src/Value/JsTypedArray.php | 12 +++ tests/Unit/Bytecode/TypedArrayWriteTest.php | 27 ++++++ .../Bytecode/fixtures/typed-array-writes.js | 18 ++++ .../Bytecode/fixtures/typed-array-writes.json | 88 +++++++++++++++++++ 4 files changed, 145 insertions(+) diff --git a/src/Value/JsTypedArray.php b/src/Value/JsTypedArray.php index e860a5d5..fcffa610 100644 --- a/src/Value/JsTypedArray.php +++ b/src/Value/JsTypedArray.php @@ -593,6 +593,18 @@ public function setIntegerIndex(int $index, JsValue $value): bool if ($this->buffer->isImmutable()) { return false; } + // Primitive numbers cannot run user conversion between the validity check and write. + if ( + $this->typeName === 'Uint8Array' && $value instanceof JsNumber + && get_class($this) === self::class && get_class($this->buffer) === JsArrayBuffer::class + ) { + if ($index >= 0 && $index < $this->getLength()) { + $number = $value->value; + $integer = is_nan($number) || is_infinite($number) ? 0 : (int) $number; + $this->buffer->writeBytes($this->byteOffset + $index, pack('C', $integer)); + } + return true; + } $coerced = $this->coerceTypedArrayValue($value); if ($index >= 0 && $index < $this->getLength()) { $this->setIndex($index, $coerced); diff --git a/tests/Unit/Bytecode/TypedArrayWriteTest.php b/tests/Unit/Bytecode/TypedArrayWriteTest.php index 539e994f..cf614656 100644 --- a/tests/Unit/Bytecode/TypedArrayWriteTest.php +++ b/tests/Unit/Bytecode/TypedArrayWriteTest.php @@ -6,6 +6,10 @@ use Phasis\Engine; use Phasis\Value\JsFunction; +use Phasis\Value\JsArrayBuffer; +use Phasis\Value\JsNumber; +use Phasis\Value\JsTypedArray; +use Phasis\Value\JsValue; use PHPUnit\Framework\TestCase; final class TypedArrayWriteTest extends TestCase @@ -51,4 +55,27 @@ function strict(view, key, value) { 'use strict'; view[key] = value; } result; JS)); } + + public function testNumericStoresRetainHostTypedArrayOverrides(): void + { + $buffer = new JsArrayBuffer(2); + $view = new class ('Uint8Array', $buffer, 0, 2) extends JsTypedArray { + public function setIndex(int $index, JsValue $value): void + { + parent::setIndex($index + 1, $value); + } + }; + self::assertTrue($view->setIntegerIndex(0, JsNumber::of(31))); + self::assertSame('001f', bin2hex($buffer->getData())); + } + + public function testPrimitiveNumericStoresStillRejectImmutableBuffers(): void + { + $buffer = new JsArrayBuffer(1); + $view = new JsTypedArray('Uint8Array', $buffer, 0, 1); + $view->setIntegerIndex(0, JsNumber::of(7)); + $buffer->makeImmutable(); + self::assertFalse($view->setIntegerIndex(0, JsNumber::of(31))); + self::assertSame('07', bin2hex($buffer->getData())); + } } diff --git a/tests/Unit/Bytecode/fixtures/typed-array-writes.js b/tests/Unit/Bytecode/fixtures/typed-array-writes.js index 4ae7732d..8201c07d 100644 --- a/tests/Unit/Bytecode/fixtures/typed-array-writes.js +++ b/tests/Unit/Bytecode/fixtures/typed-array-writes.js @@ -53,3 +53,21 @@ for (const store of [strictStore, sloppyStore]) { store(tracking, 5, {valueOf() { resizable.resize(8); return 29; }}); typedArrayWriteResult.push(['grow', tracking.length, tracking[5]]); } +for (const store of [strictStore, sloppyStore]) { + const buffer = new ArrayBuffer(8, {maxByteLength: 12}); + const offset = new Uint8Array(buffer, 2, 3); + store(offset, 0, 257.75); + store(offset, 2, -257.75); + typedArrayWriteResult.push(['offset-numbers', store.name, Array.from(new Uint8Array(buffer))]); + buffer.resize(1); + store(offset, 0, 31); + typedArrayWriteResult.push(['number-oob', store.name, Array.from(new Uint8Array(buffer))]); + buffer.resize(12); + store(offset, 1, 511); + const tracking = new Uint8Array(buffer); + store(tracking, 11, -1); + typedArrayWriteResult.push(['number-regrown', store.name, Array.from(tracking)]); + structuredClone(buffer, {transfer: [buffer]}); + store(offset, 0, 73); + typedArrayWriteResult.push(['number-detached', store.name, offset.length]); +} diff --git a/tests/Unit/Bytecode/fixtures/typed-array-writes.json b/tests/Unit/Bytecode/fixtures/typed-array-writes.json index e5e9345f..6720c663 100644 --- a/tests/Unit/Bytecode/fixtures/typed-array-writes.json +++ b/tests/Unit/Bytecode/fixtures/typed-array-writes.json @@ -896,5 +896,93 @@ "grow", 8, 29 + ], + [ + "offset-numbers", + "strictStore", + [ + 0, + 0, + 1, + 0, + 255, + 0, + 0, + 0 + ] + ], + [ + "number-oob", + "strictStore", + [ + 0 + ] + ], + [ + "number-regrown", + "strictStore", + [ + 0, + 0, + 0, + 255, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 255 + ] + ], + [ + "number-detached", + "strictStore", + 0 + ], + [ + "offset-numbers", + "sloppyStore", + [ + 0, + 0, + 1, + 0, + 255, + 0, + 0, + 0 + ] + ], + [ + "number-oob", + "sloppyStore", + [ + 0 + ] + ], + [ + "number-regrown", + "sloppyStore", + [ + 0, + 0, + 0, + 255, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 255 + ] + ], + [ + "number-detached", + "sloppyStore", + 0 ] ] From cb6029a7ee4c3c51b8cbf437ee09a66fec3c6289 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 24 Oct 2026 01:11:35 +0000 Subject: [PATCH 63/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 44 ++++++------- compat.json | 178 +++++++++++++++++++++++++--------------------------- 2 files changed, 109 insertions(+), 113 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 70d72132..d733588f 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,13 +3,13 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-24T00:43:45+00:00` +- Snapshot time: `2026-10-24T01:11:33+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `e66b18bf` (dirty) +- Git: `feat/express-hono-compatibility` @ `ba525bc2` (dirty) ## Summary @@ -198,26 +198,26 @@ Generated from a completed `test262` pass. Do not edit by hand. | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| staging/sm | NORMAL | 184.605s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 183.902s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 183.576s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 182.867s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 181.268s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 175.681s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| staging/sm | NORMAL | 170.852s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| built-ins/decodeURIComponent | NORMAL | 163.763s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| staging/sm | NORMAL | 146.772s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| staging/sm | NORMAL | 145.879s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| built-ins/decodeURI | NORMAL | 143.023s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| staging/sm | NORMAL | 115.169s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| language/literals | NORMAL | 85.324s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | -| intl402 | NORMAL | 83.484s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | -| built-ins/TypedArray | NORMAL | 74.003s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | -| built-ins/decodeURIComponent | NORMAL | 73.143s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | -| built-ins/decodeURI | NORMAL | 72.719s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | -| intl402/DateTimeFormat | NORMAL | 67.267s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | -| annexB/built-ins/RegExp | NORMAL | 64.783s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.699s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Malayalam.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Mandaic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Manichaean.js` | +| built-ins/decodeURIComponent | NORMAL | 163.507s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| built-ins/decodeURI | NORMAL | 139.454s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| staging/sm | NORMAL | 100.949s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 100.291s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 99.715s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 98.440s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 95.367s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 91.046s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| staging/sm | NORMAL | 86.932s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| intl402 | NORMAL | 85.029s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | +| staging/sm | NORMAL | 82.003s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 80.993s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| built-ins/decodeURI | NORMAL | 73.746s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | +| built-ins/decodeURIComponent | NORMAL | 73.328s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | +| intl402/DateTimeFormat | NORMAL | 67.982s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | +| staging/sm | NORMAL | 65.928s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.856s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Avestan.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Balinese.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Bamum.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Bassa_Vah.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Batak.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.807s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Malayalam.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Mandaic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Manichaean.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.680s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Rejang.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Runic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Samaritan.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.629s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 3ea4daa7..10b00432 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-24T00:43:45+00:00", - "updatedAt": "2026-10-24T00:43:45+00:00", + "generatedAt": "2026-10-24T01:11:33+00:00", + "updatedAt": "2026-10-24T01:11:33+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "e66b18bf", + "commit": "ba525bc2", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "b0f8635c7820ddf7811126d4c1e2b008c868e4e6", - "runIdentity": "e3eae8ee0b2d698781e287c43b4788c980b9079186afb589eb43188f33170fbd" + "fingerprint": "76af713f1a4edd72cf26a470b82737afcce2eb66", + "runIdentity": "9b5c8c3956e480f6dac517554c75d5fd5bec26fa5cebf408961b9c7cf1106a0c" }, "discovery": { "groupCount": 161, @@ -2717,36 +2717,27 @@ "blockedChunks": [], "slowChunks": [ { - "group": "staging/sm", - "kind": "normal", - "durationSec": 184.605, - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" - ] - }, - { - "group": "staging/sm", + "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 183.902, + "durationSec": 163.507, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" ] }, { - "group": "staging/sm", + "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 183.576, + "durationSec": 139.454, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 182.867, + "durationSec": 100.949, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" @@ -2755,118 +2746,105 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 181.268, + "durationSec": 100.291, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 175.681, + "durationSec": 99.715, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 170.852, + "durationSec": 98.44, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" ] }, { - "group": "built-ins/decodeURIComponent", + "group": "staging/sm", "kind": "normal", - "durationSec": 163.763, + "durationSec": 95.367, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 146.772, + "durationSec": 91.046, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 145.879, + "durationSec": 86.932, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" ] }, { - "group": "built-ins/decodeURI", + "group": "intl402", "kind": "normal", - "durationSec": 143.023, - "filesCount": 1, + "durationSec": 85.029, + "filesCount": 22, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" + "test262/test/intl402/constructors-string-and-single-element-array.js", + "test262/test/intl402/constructors-taint-Object-prototype-2.js", + "...", + "test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js", + "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 115.169, + "durationSec": 82.003, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" - ] - }, - { - "group": "language/literals", - "kind": "normal", - "durationSec": 85.324, - "filesCount": 25, - "sampleFiles": [ - "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", - "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", - "...", - "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", - "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" ] }, { - "group": "intl402", + "group": "staging/sm", "kind": "normal", - "durationSec": 83.484, - "filesCount": 22, + "durationSec": 80.993, + "filesCount": 1, "sampleFiles": [ - "test262/test/intl402/constructors-string-and-single-element-array.js", - "test262/test/intl402/constructors-taint-Object-prototype-2.js", - "...", - "test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js", - "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { - "group": "built-ins/TypedArray", + "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 74.003, + "durationSec": 73.746, "filesCount": 25, "sampleFiles": [ - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", "...", - "test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js", - "test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" ] }, { "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 73.143, + "durationSec": 73.328, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", @@ -2876,23 +2854,10 @@ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" ] }, - { - "group": "built-ins/decodeURI", - "kind": "normal", - "durationSec": 72.719, - "filesCount": 25, - "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", - "...", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" - ] - }, { "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 67.267, + "durationSec": 67.982, "filesCount": 12, "sampleFiles": [ "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", @@ -2903,28 +2868,59 @@ ] }, { - "group": "annexB/built-ins/RegExp", + "group": "staging/sm", "kind": "normal", - "durationSec": 64.783, - "filesCount": 25, + "durationSec": 65.928, + "filesCount": 1, "sampleFiles": [ - "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", - "test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js", - "...", - "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js", - "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js" + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.699, + "durationSec": 59.856, + "filesCount": 5, + "sampleFiles": [ + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Avestan.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Balinese.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Bamum.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Bassa_Vah.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Batak.js" + ] + }, + { + "group": "built-ins/RegExp/property-escapes/generated", + "kind": "normal", + "durationSec": 59.807, "filesCount": 3, "sampleFiles": [ "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Malayalam.js", "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Mandaic.js", "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Manichaean.js" ] + }, + { + "group": "built-ins/RegExp/property-escapes/generated", + "kind": "normal", + "durationSec": 59.68, + "filesCount": 3, + "sampleFiles": [ + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Rejang.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Runic.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Samaritan.js" + ] + }, + { + "group": "built-ins/RegExp/property-escapes/generated", + "kind": "normal", + "durationSec": 59.629, + "filesCount": 3, + "sampleFiles": [ + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js" + ] } ] } From 6b895cccea012e122960f63fee3bc140559b4594 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 03:37:51 +0200 Subject: [PATCH 64/99] Fix realm prototypes for Node host byte views --- src/BuiltIn/TypedArray/BufferTypes.php | 1 + src/BuiltIn/TypedArray/TypedArrayHelpers.php | 1 + src/Node/HostBindings.php | 6 +- src/Node/IoBindings.php | 5 +- src/Node/NodeRuntime.php | 17 +++ tests/Unit/Node/ByteViewPrototypeTest.php | 136 +++++++++++++++++++ tests/Unit/Node/fixtures/byte-view-stdio.php | 35 +++++ 7 files changed, 193 insertions(+), 8 deletions(-) create mode 100644 tests/Unit/Node/ByteViewPrototypeTest.php create mode 100644 tests/Unit/Node/fixtures/byte-view-stdio.php diff --git a/src/BuiltIn/TypedArray/BufferTypes.php b/src/BuiltIn/TypedArray/BufferTypes.php index ac530ec5..7767efd2 100644 --- a/src/BuiltIn/TypedArray/BufferTypes.php +++ b/src/BuiltIn/TypedArray/BufferTypes.php @@ -430,6 +430,7 @@ function (JsValue $this_): JsValue { PropertyDescriptor::accessor($speciesGetter, null, false, true), ); + $env->setIntrinsic('ArrayBuffer.prototype', $proto); $env->defineVar('ArrayBuffer', $constructor); } diff --git a/src/BuiltIn/TypedArray/TypedArrayHelpers.php b/src/BuiltIn/TypedArray/TypedArrayHelpers.php index a4f88489..4371e492 100644 --- a/src/BuiltIn/TypedArray/TypedArrayHelpers.php +++ b/src/BuiltIn/TypedArray/TypedArrayHelpers.php @@ -372,6 +372,7 @@ function (JsValue $this_, array $args) use ($typeName, $bpe, $proto, $ctorBox): PropertyDescriptor::data($proto, false, false, false), ); + $env->setIntrinsic($typeName . '.prototype', $proto); $env->defineVar($typeName, $constructor); } diff --git a/src/Node/HostBindings.php b/src/Node/HostBindings.php index f7875d1f..261d7665 100644 --- a/src/Node/HostBindings.php +++ b/src/Node/HostBindings.php @@ -52,7 +52,7 @@ public static function create(Engine $engine, NodeRuntime $runtime): JsObject } return JsNumber::of($written); }); - self::method($host, 'stdioRead', static function (array $args): JsValue { + self::method($host, 'stdioRead', static function (array $args) use ($runtime): JsValue { if ((int) ($args[0] ?? JsUndefined::instance())->toNumber() !== 0) { throw new TypeError('Invalid standard input descriptor'); } @@ -68,9 +68,7 @@ public static function create(Engine $engine, NodeRuntime $runtime): JsObject if ($bytes === '' && feof(STDIN)) { return \Phasis\Value\JsNull::instance(); } - $buffer = new \Phasis\Value\JsArrayBuffer(strlen($bytes)); - $buffer->setData($bytes); - return new \Phasis\Value\JsTypedArray('Uint8Array', $buffer, 0, strlen($bytes)); + return $runtime->byteArray($bytes); }); self::method($host, 'timer', static function (array $args) use ($engine): JsValue { $operation = ($args[0] ?? JsUndefined::instance())->toJsString(); diff --git a/src/Node/IoBindings.php b/src/Node/IoBindings.php index 2089e8da..c761eaa8 100644 --- a/src/Node/IoBindings.php +++ b/src/Node/IoBindings.php @@ -8,7 +8,6 @@ use Phasis\Exceptions\TypeError; use Phasis\Interop\PhpToJs; use Phasis\Runtime\AsyncContextStorage; -use Phasis\Value\JsArrayBuffer; use Phasis\Value\JsBoolean; use Phasis\Value\JsFunction; use Phasis\Value\JsNumber; @@ -342,9 +341,7 @@ private function readSocket(SocketState $socket): void } $data = @fread($stream, 65536); if ($data !== false && $data !== '') { - $buffer = new JsArrayBuffer(strlen($data)); - $buffer->setData($data); - $this->emit($socket, 'data', new JsTypedArray('Uint8Array', $buffer, 0, strlen($data))); + $this->emit($socket, 'data', $this->runtime->byteArray($data)); } if (is_resource($stream) && isset($this->sockets[$socket->id]) && feof($stream)) { $socket->readEnded = true; diff --git a/src/Node/NodeRuntime.php b/src/Node/NodeRuntime.php index fda1c6cd..03d212ef 100644 --- a/src/Node/NodeRuntime.php +++ b/src/Node/NodeRuntime.php @@ -8,10 +8,12 @@ use Phasis\Exceptions\TypeError; use Phasis\Interop\PhpToJs; use Phasis\Runtime\AsyncContextStorage; +use Phasis\Value\JsArrayBuffer; use Phasis\Value\JsFunction; use Phasis\Value\JsObject; use Phasis\Value\JsPromise; use Phasis\Value\JsString; +use Phasis\Value\JsTypedArray; use Phasis\Value\JsUndefined; use Phasis\Value\JsValue; @@ -172,6 +174,21 @@ public function module(string $name): JsValue return $this->engine->getInterpreter()->getModuleLoader()->requireModule($name, __FILE__); } + /** Create fresh bytes with the owning realm's view and backing-buffer intrinsics. */ + public function byteArray(string $bytes): JsTypedArray + { + $env = $this->engine->getGlobalEnv(); + $viewPrototype = $env->getIntrinsic('Uint8Array.prototype'); + $bufferPrototype = $env->getIntrinsic('ArrayBuffer.prototype'); + if (!$viewPrototype instanceof JsObject || !$bufferPrototype instanceof JsObject) { + throw new \LogicException('Node byte arrays require installed TypedArray intrinsics.'); + } + $length = strlen($bytes); + $buffer = new JsArrayBuffer($length, $bufferPrototype); + $buffer->setData($bytes); + return new JsTypedArray('Uint8Array', $buffer, 0, $length, $viewPrototype); + } + /** Run the asynchronous Fetch transport on this realm's HTTP sockets. */ public function fetch( JsObject $request, diff --git a/tests/Unit/Node/ByteViewPrototypeTest.php b/tests/Unit/Node/ByteViewPrototypeTest.php new file mode 100644 index 00000000..a875ad8d --- /dev/null +++ b/tests/Unit/Node/ByteViewPrototypeTest.php @@ -0,0 +1,136 @@ + */ + public static function globalModes(): iterable + { + yield 'ordinary globals' => [false]; + yield 'replaced globals' => [true]; + } + + public function testNormalNodeInstallationHasByteArrayIntrinsicsReady(): void + { + $engine = new Engine(node: true); + try { + $runtime = $engine->getNodeRuntime(); + self::assertNotNull($runtime); + $bytes = $runtime->byteArray("\x00\xffa"); + self::assertSame($engine->getGlobalEnv()->getIntrinsic('Uint8Array.prototype'), $bytes->getPrototype()); + self::assertSame($engine->getGlobalEnv()->getIntrinsic('ArrayBuffer.prototype'), $bytes->getBuffer()->getPrototype()); + self::assertSame('00ff61', bin2hex($bytes->getBuffer()->getData())); + } finally { + $engine->getNodeRuntime()?->close(); + } + } + + #[DataProvider('globalModes')] + public function testSocketBytesUseTheOwningRealmForTheViewAndBuffer(bool $replaceGlobals): void + { + $owner = new Engine(node: true); + $sibling = null; + try { + $owner->eval(<<<'JS' +const ByteConstructor = Uint8Array; +const BufferConstructor = ArrayBuffer; +const bytePrototype = ByteConstructor.prototype; +const bufferPrototype = BufferConstructor.prototype; +const payload = new ByteConstructor([0, 255, 97]); +let constructorReads = 0; +const observations = []; +JS); + $sibling = new Engine(node: true); + $sibling->eval('new Uint8Array(1);'); + $owner->setExecutionBudget(3); + if ($replaceGlobals) { + $owner->eval(<<<'JS' +for (const name of ['Uint8Array', 'ArrayBuffer']) { + Object.defineProperty(globalThis, name, {configurable: true, get() { + constructorReads++; + throw new Error('Host bytes must use their intrinsic prototypes'); + }}); +} +JS); + } + $owner->eval(<<<'JS' +const host = __phasisNodeHost.net; +let listener, client, accepted; +listener = host.call('listen', {host: '127.0.0.1', port: 0}, (event, value) => { + if (event !== 'connection') return; + accepted = value; + host.call('callback', accepted, (kind, bytes) => { + if (kind !== 'data') return; + observations.push(Object.getPrototypeOf(bytes) === bytePrototype, + Object.getPrototypeOf(bytes.buffer) === bufferPrototype, + BufferConstructor.isView(bytes), bytes instanceof ByteConstructor, + Array.from(bytes), constructorReads); + host.call('close', accepted); + host.call('close', client.value); + host.call('close', listener.value); + }); +}); +const address = host.call('address', listener.value).value; +client = host.call('connect', {host: '127.0.0.1', port: address.port}, event => { + if (event === 'connect') host.call('write', client.value, payload, () => {}); +}); +JS); + self::assertSame([true, true, true, true, [0, 255, 97], 0], $owner->eval('observations')); + } finally { + $owner->getNodeRuntime()?->close(); + $sibling?->getNodeRuntime()?->close(); + } + } + + public function testStdinBytesUseTheOwningRealmAfterSiblingAndGlobalChanges(): void + { + $process = proc_open( + [PHP_BINARY, __DIR__ . '/fixtures/byte-view-stdio.php'], + [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']], + $pipes, + dirname(__DIR__, 3), + ['XDEBUG_MODE' => 'off'], + ); + self::assertIsResource($process); + $output = $errors = ''; + try { + fwrite($pipes[0], "\x00\xffa"); + fclose($pipes[0]); + stream_set_blocking($pipes[1], false); + stream_set_blocking($pipes[2], false); + $deadline = microtime(true) + 5; + do { + $output .= stream_get_contents($pipes[1]); + $errors .= stream_get_contents($pipes[2]); + $status = proc_get_status($process); + if (!$status['running']) { + break; + } + if (microtime(true) >= $deadline) { + self::fail('The bounded stdin prototype probe did not finish.'); + } + usleep(1000); + } while (true); + $output .= stream_get_contents($pipes[1]); + $errors .= stream_get_contents($pipes[2]); + self::assertSame(0, $status['exitcode'], $errors); + self::assertSame('', $errors); + self::assertSame([true, true, true, true, [0, 255, 97], 0], json_decode($output, true, flags: JSON_THROW_ON_ERROR)); + } finally { + foreach ($pipes as $pipe) { + if (is_resource($pipe)) { + fclose($pipe); + } + } + proc_terminate($process); + proc_close($process); + } + } +} diff --git a/tests/Unit/Node/fixtures/byte-view-stdio.php b/tests/Unit/Node/fixtures/byte-view-stdio.php new file mode 100644 index 00000000..f4f3581d --- /dev/null +++ b/tests/Unit/Node/fixtures/byte-view-stdio.php @@ -0,0 +1,35 @@ +eval(<<<'JS' +const ByteConstructor = Uint8Array; +const BufferConstructor = ArrayBuffer; +const bytePrototype = ByteConstructor.prototype; +const bufferPrototype = BufferConstructor.prototype; +let constructorReads = 0; +JS); + $sibling = new Phasis\Engine(node: true); + $sibling->eval('new Uint8Array(1);'); + echo json_encode($owner->eval(<<<'JS' +for (const name of ['Uint8Array', 'ArrayBuffer']) { + Object.defineProperty(globalThis, name, {configurable: true, get() { + constructorReads++; + throw new Error('Host bytes must use their intrinsic prototypes'); + }}); +} +const bytes = __phasisNodeHost.stdioRead(0); +[Object.getPrototypeOf(bytes) === bytePrototype, + Object.getPrototypeOf(bytes.buffer) === bufferPrototype, + BufferConstructor.isView(bytes), bytes instanceof ByteConstructor, + Array.from(bytes), constructorReads]; +JS), JSON_THROW_ON_ERROR), "\n"; +} finally { + $owner->getNodeRuntime()?->close(); + $sibling?->getNodeRuntime()?->close(); +} From b7089d7990d8868381b1da75048580f898c1499b Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 03:55:27 +0200 Subject: [PATCH 65/99] Preserve foreign realms in inline Array callbacks --- src/Bytecode/VM.php | 8 ++ .../Unit/Bytecode/ArrayCallbackRealmTest.php | 77 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 tests/Unit/Bytecode/ArrayCallbackRealmTest.php diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 2921340e..1a5e42dc 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -415,6 +415,8 @@ private function inlineDenseArrayMethod( $callback->isClassConstructor() || $callback->isDerivedConstructor() || $callback->getHomeObject() !== null + || ($callback->realm !== null + && $callback->realm !== (\Phasis\Engine::getCurrentInterpreter() ?? $this->interp)->getRealm()) ) { return null; } @@ -483,6 +485,8 @@ private function inlineDenseArrayMethod( $callback->isClassConstructor() || $callback->isDerivedConstructor() || $callback->getHomeObject() !== null + || ($callback->realm !== null + && $callback->realm !== (\Phasis\Engine::getCurrentInterpreter() ?? $this->interp)->getRealm()) ) { return null; } @@ -561,6 +565,8 @@ private function inlineDenseArrayMethod( $callback->isClassConstructor() || $callback->isDerivedConstructor() || $callback->getHomeObject() !== null + || ($callback->realm !== null + && $callback->realm !== (\Phasis\Engine::getCurrentInterpreter() ?? $this->interp)->getRealm()) ) { return null; } @@ -607,6 +613,8 @@ private function inlineDenseArrayMethod( $callback->isClassConstructor() || $callback->isDerivedConstructor() || $callback->getHomeObject() !== null + || ($callback->realm !== null + && $callback->realm !== (\Phasis\Engine::getCurrentInterpreter() ?? $this->interp)->getRealm()) ) { return null; } diff --git a/tests/Unit/Bytecode/ArrayCallbackRealmTest.php b/tests/Unit/Bytecode/ArrayCallbackRealmTest.php new file mode 100644 index 00000000..a20a4f6a --- /dev/null +++ b/tests/Unit/Bytecode/ArrayCallbackRealmTest.php @@ -0,0 +1,77 @@ + */ + public static function executionModes(): iterable + { + yield 'VM with numeric entry' => [false, true]; + yield 'VM with standard entry' => [false, false]; + yield 'AST with numeric entry' => [true, true]; + yield 'AST with standard entry' => [true, false]; + } + + #[DataProvider('executionModes')] + public function testDenseCallbacksEnterTheirOwnRealmOnce(bool $budgeted, bool $numeric): void + { + $foreign = new Engine(); + $foreign->eval(<<<'JS' +var foreignCalls = 0; +Object.prototype.markForeign = function () { foreignCalls++; }; +function foreignCallback(value) { + const object = {value: value}; + const result = object.value; + object.markForeign(); + return result; +} +foreignCallback(1); +foreignCalls = 0; +JS); + $callback = $foreign->getGlobalEnv()->get('foreignCallback'); + self::assertInstanceOf(JsFunction::class, $callback); + self::assertInstanceOf(\Closure::class, $callback->phpCompiled); + self::assertInstanceOf(\Closure::class, $callback->phpCompiledNumeric); + if (!$numeric) { + $callback->phpCompiledNumeric = null; + } + $caller = new Engine(); + $caller->getGlobalEnv()->defineVar('foreignCallback', $callback); + if ($budgeted) { + $caller->setExecutionBudget(10); + } + $caller->eval(<<<'JS' +var wrongRealmCalls = 0; +Object.prototype.markForeign = function () { wrongRealmCalls++; }; +function localMap() { const values = [1, 2]; return values.map(foreignCallback); } +function localReduce() { const values = [1, 2]; return values.reduce(foreignCallback, 0); } +function localEach() { const values = [1, 2]; values.forEach(foreignCallback); return wrongRealmCalls; } +function localFilter() { const values = [1, 2]; return values.filter(foreignCallback); } +JS); + for ($pass = 0; $pass < 3; $pass++) { + self::assertSame([[1, 2], 0, 0, [1, 2], 0], $caller->eval(<<<'JS' +[localMap(), localReduce(), localEach(), localFilter(), wrongRealmCalls]; +JS)); + self::assertSame(8 * ($pass + 1), $foreign->eval('foreignCalls')); + } + if (!$budgeted) { + foreach (['localMap', 'localReduce', 'localEach', 'localFilter'] as $name) { + $wrapper = $caller->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $wrapper); + self::assertNotNull($wrapper->compiled, $name . ' must exercise the VM callback path.'); + } + } + self::assertSame($numeric, $callback->phpCompiledNumeric !== null); + self::assertInstanceOf(\Closure::class, $callback->phpCompiled); + self::assertSame(0, $caller->getInterpreter()->getCallStack()->depth()); + self::assertSame(0, $foreign->getInterpreter()->getCallStack()->depth()); + } +} From b45ceb7b449d2181faae7a6594284f38484ef429 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 04:02:15 +0200 Subject: [PATCH 66/99] Reuse immutable custom regular expression syntax trees --- src/Runtime/Parts/Helpers/RegExpHelpers.php | 94 +++++++++----------- tests/Unit/Runtime/RegExpPreparationTest.php | 61 +++++++++++++ 2 files changed, 105 insertions(+), 50 deletions(-) diff --git a/src/Runtime/Parts/Helpers/RegExpHelpers.php b/src/Runtime/Parts/Helpers/RegExpHelpers.php index f7f44b94..2bbaaa17 100644 --- a/src/Runtime/Parts/Helpers/RegExpHelpers.php +++ b/src/Runtime/Parts/Helpers/RegExpHelpers.php @@ -159,14 +159,13 @@ public function callNew(JsValue $callee, array $args): JsValue return $newObj; } - /** @var array, names: list, custom: bool}> */ + /** @var array, names: list, custom: bool, ast: ?\Phasis\Regex\Ast\Pattern}> */ private array $preparedRegExpPatterns = []; private function createRegExpObject(string $pattern, string $flags): JsObject { $originalPattern = $pattern; $prepared = $this->prepareRegExpPattern($pattern, $flags); - $pattern = $prepared['pattern']; $sortedFlags = $prepared['flags']; $pcrePattern = $prepared['pcre']; $groupNameMap = $prepared['groups']; @@ -229,33 +228,25 @@ private function createRegExpObject(string $pattern, string $flags): JsObject // points; ES non-unicode mode requires UTF-16 code units, // so `.` must NOT match an astral character). // exec() routes through the in-engine matcher in those cases. - if ($prepared['custom']) { - try { - // The AST parser consumes ordinary alternatives after Unicode string sets are lowered. - $customPattern = str_contains($flags, 'v') ? $this->transformVFlagPattern($pattern) : $pattern; - $regexAst = (new \Phasis\Regex\Parser($customPattern, $flags))->parse(); - $obj->defineOwnProperty( - '[[CustomRegexAst]]', - PropertyDescriptor::data( - new \Phasis\Value\JsHostValue($regexAst), - false, - false, - false, - ), - ); - $obj->defineOwnProperty( - '[[CustomRegexFlags]]', - PropertyDescriptor::data( - new JsString($flags), - false, - false, - false, - ), - ); - } catch (\Throwable) { - // If our parser bails on something it doesn't model - // yet, fall back to PCRE2. - } + if ($prepared['ast'] !== null) { + $obj->defineOwnProperty( + '[[CustomRegexAst]]', + PropertyDescriptor::data( + new \Phasis\Value\JsHostValue($prepared['ast']), + false, + false, + false, + ), + ); + $obj->defineOwnProperty( + '[[CustomRegexFlags]]', + PropertyDescriptor::data( + new JsString($flags), + false, + false, + false, + ), + ); } // [[NamedGroupNames]] preserves every distinct named group in the @@ -284,9 +275,12 @@ private function createRegExpObject(string $pattern, string $flags): JsObject } /** - * Reuse immutable preprocessing only; every instance keeps fresh lastIndex, - * prototype, named-group objects and custom matcher state. - * @return array{pattern: string, flags: string, pcre: string, groups: array, names: list, custom: bool} + * Reuse immutable preprocessing and syntax nodes. Every instance keeps + * fresh lastIndex, prototype, named-group objects and matcher state. + * @return array{ + * pattern: string, flags: string, pcre: string, groups: array, + * names: list, custom: bool, ast: ?\Phasis\Regex\Ast\Pattern, + * } */ private function prepareRegExpPattern(string $pattern, string $flags): array { @@ -422,24 +416,23 @@ private function prepareRegExpPattern(string $pattern, string $flags): array // as an ECMAScript SyntaxError, since accepting silently // would let invalid patterns pass. $pcreCompiles = @preg_match($pcrePattern, '') !== false; - if (!$pcreCompiles) { - $customNeeded = self::patternNeedsCustomMatcher($pattern, $flags); - $customParseOk = false; - if ($customNeeded) { - try { - $customPattern = str_contains($flags, 'v') ? $this->transformVFlagPattern($pattern) : $pattern; - (new \Phasis\Regex\Parser($customPattern, $flags))->parse(); - $customParseOk = true; - } catch (\Throwable) { - $customParseOk = false; - } - } - if (!$customParseOk) { - throw new \Phasis\Exceptions\SyntaxError( - 'Invalid regular expression: /' . $pattern . '/: ' . preg_last_error_msg(), - ); + $customNeeded = self::patternNeedsCustomMatcher($pattern, $flags); + $customAst = null; + if ($customNeeded) { + try { + // Syntax nodes contain only readonly syntax data. Captures, + // cursors and memoization belong to each fresh Matcher. + $customPattern = str_contains($flags, 'v') ? $this->transformVFlagPattern($pattern) : $pattern; + $customAst = (new \Phasis\Regex\Parser($customPattern, $flags))->parse(); + } catch (\Throwable) { + // Keep the existing PCRE fallback for unmodeled custom syntax. } } + if (!$pcreCompiles && $customAst === null) { + throw new \Phasis\Exceptions\SyntaxError( + 'Invalid regular expression: /' . $pattern . '/: ' . preg_last_error_msg(), + ); + } $prepared = [ 'pattern' => $pattern, @@ -447,9 +440,10 @@ private function prepareRegExpPattern(string $pattern, string $flags): array 'pcre' => $pcrePattern, 'groups' => $groupNameMap, 'names' => self::extractNamedGroupNames($pattern), - 'custom' => self::patternNeedsCustomMatcher($pattern, $flags), + 'custom' => $customNeeded, + 'ast' => $customAst, ]; - if ($key !== null && !$prepared['custom'] && strlen($pcrePattern) <= 16384) { + if ($key !== null && (!$customNeeded || $customAst !== null) && strlen($pcrePattern) <= 16384) { if (count($this->preparedRegExpPatterns) >= 128) { array_shift($this->preparedRegExpPatterns); } diff --git a/tests/Unit/Runtime/RegExpPreparationTest.php b/tests/Unit/Runtime/RegExpPreparationTest.php index 53a99862..f5d27a10 100644 --- a/tests/Unit/Runtime/RegExpPreparationTest.php +++ b/tests/Unit/Runtime/RegExpPreparationTest.php @@ -49,4 +49,65 @@ public function testCachedNullCharactersCannotBypassInvalidFlagValidation(): voi [seeded.test('a\0x'), rejected]; JS)); } + + public function testRepeatedCustomPatternsKeepCapturesAndCompileChangesIndependent(): void + { + $engine = new Engine(); + self::assertSame([true, 'ab', 'b', 2, 0, 'a', 'a', 1, 'b', 2, true, 'b'], $engine->eval(<<<'JS' +const first = new RegExp('(?a|b)+', 'dg'); +const second = new RegExp('(?a|b)+', 'dg'); +const match = first.exec('ab'); +const saved = match.groups.letter; +match.groups.letter = 'changed'; +match.indices.groups.letter[0] = 99; +const secondBefore = second.lastIndex; +const next = second.exec('a'); +first.compile('(?b)+', 'g'); +const third = new RegExp('(?a|b)+', 'dg'); +third.lastIndex = 1; +const last = third.exec('ab'); +[first !== second, match[0], saved, match.indices[0][1], secondBefore, + next[0], next.groups.letter, second.lastIndex, last.groups.letter, third.lastIndex, + first.test('b'), RegExp.$1]; +JS)); + } + + public function testCustomPatternFlagsAndUnicodeModesStayIndependent(): void + { + $engine = new Engine(); + self::assertSame([true, true, false, true, false, true, true, false, true, true], $engine->eval(<<<'JS' +const checks = []; +for (let repeat = 0; repeat < 2; repeat++) { + checks.push(new RegExp('^[\\u{10000}-\\u{10ffff}]+$', 'u').test('\ud83d\ude00')); + checks.push(new RegExp('^[\\u{10000}-\\u{10ffff}]+$', 'u').test('\ud83d')); + checks.push(new RegExp('^(?a)+$', 'i').test('AA')); + checks.push(new RegExp('^(?a)+$', '').test('AA')); +} +const unicodeSet = new RegExp('[\\p{ASCII}&&[^A-Z]]+', 'v'); +const repeatedSet = new RegExp('[\\p{ASCII}&&[^A-Z]]+', 'v'); +[checks[0], checks[2], checks[1], checks[4], checks[5], checks[6], + unicodeSet.test('abc'), repeatedSet.test('ABC'), unicodeSet !== repeatedSet, + new RegExp('(?<=a)(b)', 'd').exec('ab').indices[1][0] === 1]; +JS)); + } + + public function testPreparedCustomPatternsDoNotRetainInstancesOrShareRealmPrototypes(): void + { + $first = new Engine(); + $first->eval('var temporary = new RegExp("(?a)+", "g"); RegExp.prototype.realm = 1;'); + $regexp = $first->getGlobalEnv()->get('temporary'); + self::assertInstanceOf(JsObject::class, $regexp); + $reference = \WeakReference::create($regexp); + unset($regexp); + $second = new Engine(); + $second->eval('new RegExp("(?a)+", "g"); RegExp.prototype.realm = 2;'); + self::assertSame([1, true, 'a'], $first->eval(<<<'JS' +temporary = null; +const next = new RegExp('(?a)+', 'g'); +[next.realm, Object.getPrototypeOf(next) === RegExp.prototype, next.exec('aa').groups.x]; +JS)); + gc_collect_cycles(); + self::assertNull($reference->get()); + self::assertSame(2, $second->eval('new RegExp("(?a)+", "g").realm')); + } } From 20f02717957fd026c1cede9231e944b58756590e Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 04:15:46 +0200 Subject: [PATCH 67/99] Resolve TypedArray copy prototype before source validation --- src/BuiltIn/TypedArray/TypedArrayHelpers.php | 13 +++--- .../Unit/Runtime/TypedArrayCopyOrderTest.php | 39 +++++++++++++++++ .../fixtures/typed-array-copy-order.cjs | 43 +++++++++++++++++++ .../fixtures/typed-array-copy-order.json | 21 +++++++++ 4 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 tests/Unit/Runtime/TypedArrayCopyOrderTest.php create mode 100644 tests/Unit/Runtime/fixtures/typed-array-copy-order.cjs create mode 100644 tests/Unit/Runtime/fixtures/typed-array-copy-order.json diff --git a/src/BuiltIn/TypedArray/TypedArrayHelpers.php b/src/BuiltIn/TypedArray/TypedArrayHelpers.php index 4371e492..e51fc6bf 100644 --- a/src/BuiltIn/TypedArray/TypedArrayHelpers.php +++ b/src/BuiltIn/TypedArray/TypedArrayHelpers.php @@ -310,11 +310,9 @@ function (JsValue $this_, array $args) use ($typeName, $bpe, $proto, $ctorBox): "Constructor {$typeName} requires 'new'" ); } - // Per §23.2.5.1 TypedArray ( ...args ): the argument validation - // (e.g. Symbol/BigInt argument TypeError for `new T(sym)`) must - // happen BEFORE GetPrototypeFromConstructor is called. Pass a - // deferred proto resolver so constructTypedArray performs proto - // access only after args are validated. + // Primitive lengths are coerced before prototype lookup. Buffer + // and TypedArray sources resolve it before source validation. + // Defer the lookup so constructTypedArray preserves that order. $ntDesc = $this_->getOwnPropertyDescriptor('[[NewTarget]]'); $nt = ($ntDesc->value instanceof JsFunction) ? $ntDesc->value @@ -689,6 +687,9 @@ private static function constructTypedArray( // new TypedArray(typedArray): copy elements. if ($arg0 instanceof JsTypedArray) { + // AllocateTypedArray reads newTarget.prototype before source validation. + // The getter may detach, resize or repair the source view. + $resolvedProto = $getProto(); // Per spec InitializeTypedArrayFromTypedArray, validate the // source: throw TypeError if its buffer is detached or the // view is now out of bounds. @@ -703,7 +704,7 @@ private static function constructTypedArray( ); } $srcLen = $arg0->getLength(); - $result = JsTypedArray::fromLength($typeName, $srcLen, $getProto()); + $result = JsTypedArray::fromLength($typeName, $srcLen, $resolvedProto); for ($i = 0; $i < $srcLen; $i++) { $result->setIndex($i, $arg0->getIndex($i)); } diff --git a/tests/Unit/Runtime/TypedArrayCopyOrderTest.php b/tests/Unit/Runtime/TypedArrayCopyOrderTest.php new file mode 100644 index 00000000..a7006fdf --- /dev/null +++ b/tests/Unit/Runtime/TypedArrayCopyOrderTest.php @@ -0,0 +1,39 @@ + */ + public static function executionModes(): iterable + { + yield 'VM' => [false]; + yield 'AST' => [true]; + } + + #[DataProvider('executionModes')] + public function testPrototypeLookupPrecedesSourceValidation(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->execFile(__DIR__ . '/fixtures/typed-array-copy-order.cjs'); + $observations = $engine->eval('JSON.stringify(copyOrderObservations)'); + self::assertIsString($observations); + self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/typed-array-copy-order.json', $observations); + if (!$budgeted) { + $copy = $engine->getGlobalEnv()->get('constructCopy'); + self::assertInstanceOf(JsFunction::class, $copy); + self::assertNotNull($copy->compiled); + } + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } +} diff --git a/tests/Unit/Runtime/fixtures/typed-array-copy-order.cjs b/tests/Unit/Runtime/fixtures/typed-array-copy-order.cjs new file mode 100644 index 00000000..5f4387c0 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/typed-array-copy-order.cjs @@ -0,0 +1,43 @@ +var copyOrderObservations = []; +function constructCopy(Type, source, NewTarget) { + return Reflect.construct(Type, [source], NewTarget); +} +function copyOrderCase(label, Type, source, action) { + const effects = []; + const prototype = Object.create(Type.prototype); + const target = (function Target() {}).bind(null); + Object.defineProperty(target, 'prototype', {get() { + effects.push('prototype'); + action(source); + return prototype; + }}); + try { + const result = constructCopy(Type, source, target); + copyOrderObservations.push([label, effects, 'copy', result.length, + Array.from(result, value => String(value)), Object.getPrototypeOf(result) === prototype, + result.buffer !== source.buffer]); + } catch (error) { + copyOrderObservations.push([label, effects, error === copyOrderSentinel ? 'sentinel' : error.name]); + } +} +const copyOrderSentinel = {}; +for (const Type of [Uint8Array, Float64Array, BigInt64Array]) { + const input = Type === BigInt64Array ? [1n, 2n] : [1, 2]; + const live = new Type(input); + const normal = constructCopy(Type, live, Type); + copyOrderObservations.push([Type.name + ' intrinsic copy', normal.length, + Array.from(normal, value => String(value)), normal.buffer !== live.buffer]); + const detached = new Type(input); + detached.buffer.transfer(); + copyOrderCase(Type.name + ' detached throw', Type, detached, () => {throw copyOrderSentinel;}); + copyOrderCase(Type.name + ' detached read', Type, detached, () => {}); + copyOrderCase(Type.name + ' detach in getter', Type, new Type(input), source => {source.buffer.transfer();}); + const size = Type.BYTES_PER_ELEMENT; + const outOfBounds = new Type(new ArrayBuffer(4 * size, {maxByteLength: 8 * size}), 0, 4); + outOfBounds.buffer.resize(2 * size); + copyOrderCase(Type.name + ' out of bounds throw', Type, outOfBounds, () => {throw copyOrderSentinel;}); + copyOrderCase(Type.name + ' out of bounds read', Type, outOfBounds, () => {}); +} +const fixed = new Uint8Array(new ArrayBuffer(4, {maxByteLength: 8}), 0, 4); +fixed.set([1, 2, 3, 4]); +copyOrderCase('fixed shrink', Uint8Array, fixed, source => {source.buffer.resize(2);}); diff --git a/tests/Unit/Runtime/fixtures/typed-array-copy-order.json b/tests/Unit/Runtime/fixtures/typed-array-copy-order.json new file mode 100644 index 00000000..400c2fef --- /dev/null +++ b/tests/Unit/Runtime/fixtures/typed-array-copy-order.json @@ -0,0 +1,21 @@ +[ + ["Uint8Array intrinsic copy", 2, ["1", "2"], true], + ["Uint8Array detached throw", ["prototype"], "sentinel"], + ["Uint8Array detached read", ["prototype"], "TypeError"], + ["Uint8Array detach in getter", ["prototype"], "TypeError"], + ["Uint8Array out of bounds throw", ["prototype"], "sentinel"], + ["Uint8Array out of bounds read", ["prototype"], "TypeError"], + ["Float64Array intrinsic copy", 2, ["1", "2"], true], + ["Float64Array detached throw", ["prototype"], "sentinel"], + ["Float64Array detached read", ["prototype"], "TypeError"], + ["Float64Array detach in getter", ["prototype"], "TypeError"], + ["Float64Array out of bounds throw", ["prototype"], "sentinel"], + ["Float64Array out of bounds read", ["prototype"], "TypeError"], + ["BigInt64Array intrinsic copy", 2, ["1", "2"], true], + ["BigInt64Array detached throw", ["prototype"], "sentinel"], + ["BigInt64Array detached read", ["prototype"], "TypeError"], + ["BigInt64Array detach in getter", ["prototype"], "TypeError"], + ["BigInt64Array out of bounds throw", ["prototype"], "sentinel"], + ["BigInt64Array out of bounds read", ["prototype"], "TypeError"], + ["fixed shrink", ["prototype"], "TypeError"] +] From e0395d2087241a2e2facdbf5f5399e5f86f784ff Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 04:37:54 +0200 Subject: [PATCH 68/99] Clone same-type TypedArray bytes without element boxing --- src/BuiltIn/TypedArray/TypedArrayHelpers.php | 30 +- src/Value/JsTypedArray.php | 3 + tests/Unit/Runtime/TypedArrayByteCopyTest.php | 106 +++++++ .../fixtures/typed-array-byte-copy.cjs | 44 +++ .../fixtures/typed-array-byte-copy.json | 265 ++++++++++++++++++ 5 files changed, 447 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/Runtime/TypedArrayByteCopyTest.php create mode 100644 tests/Unit/Runtime/fixtures/typed-array-byte-copy.cjs create mode 100644 tests/Unit/Runtime/fixtures/typed-array-byte-copy.json diff --git a/src/BuiltIn/TypedArray/TypedArrayHelpers.php b/src/BuiltIn/TypedArray/TypedArrayHelpers.php index e51fc6bf..bc88b7cc 100644 --- a/src/BuiltIn/TypedArray/TypedArrayHelpers.php +++ b/src/BuiltIn/TypedArray/TypedArrayHelpers.php @@ -328,7 +328,13 @@ function (JsValue $this_, array $args) use ($typeName, $bpe, $proto, $ctorBox): } return $defaultProto; }; - return self::constructTypedArray($typeName, $bpe, $protoResolver, $args); + return self::constructTypedArray( + $typeName, + $bpe, + $protoResolver, + $args, + $nt !== null && $nt === $ctorBox->ref, + ); }, 3, ); @@ -582,6 +588,7 @@ private static function constructTypedArray( int $bpe, JsObject|\Closure $protoOrResolver, array $args, + bool $intrinsicNewTarget, ): JsTypedArray { $getProto = static function () use (&$protoOrResolver): JsObject { if ($protoOrResolver instanceof \Closure) { @@ -705,6 +712,27 @@ private static function constructTypedArray( } $srcLen = $arg0->getLength(); $result = JsTypedArray::fromLength($typeName, $srcLen, $resolvedProto); + // Same-type copies preserve the stored bits, including NaN payloads. + if ( + $intrinsicNewTarget && get_class($arg0) === JsTypedArray::class + && $arg0->getTypeName() === $typeName + ) { + $sourceBuffer = $arg0->getBuffer(); + $resultBuffer = $result->getBuffer(); + if ( + get_class($sourceBuffer) === JsArrayBuffer::class + && get_class($resultBuffer) === JsArrayBuffer::class + && !$sourceBuffer->isResizable() && !$sourceBuffer->isDetached() + && !$arg0->isOutOfBounds() && $arg0->getLength() === $srcLen + ) { + $byteLength = $srcLen * $bpe; + $bytes = substr($sourceBuffer->getData(), $arg0->getByteOffset(), $byteLength); + if (strlen($bytes) === $byteLength) { + $resultBuffer->setData($bytes); + return $result; + } + } + } for ($i = 0; $i < $srcLen; $i++) { $result->setIndex($i, $arg0->getIndex($i)); } diff --git a/src/Value/JsTypedArray.php b/src/Value/JsTypedArray.php index fcffa610..3fac8bed 100644 --- a/src/Value/JsTypedArray.php +++ b/src/Value/JsTypedArray.php @@ -138,6 +138,9 @@ public function preventExtensions(): bool /** * Whether this TypedArray's view is out of bounds for its buffer. * Only relevant for fixed-length views on resizable buffers. + * Buffer resize or detachment through an alias can change this between reads. + * + * @phpstan-impure */ public function isOutOfBounds(): bool { diff --git a/tests/Unit/Runtime/TypedArrayByteCopyTest.php b/tests/Unit/Runtime/TypedArrayByteCopyTest.php new file mode 100644 index 00000000..36d442d1 --- /dev/null +++ b/tests/Unit/Runtime/TypedArrayByteCopyTest.php @@ -0,0 +1,106 @@ + */ + public static function executionModes(): iterable + { + yield 'VM' => [false]; + yield 'AST' => [true]; + } + + #[DataProvider('executionModes')] + public function testCopiesPreserveWindowsBitsAndFallbackSemantics(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->execFile(__DIR__ . '/fixtures/typed-array-byte-copy.cjs'); + $observations = $engine->eval('JSON.stringify(typedArrayCopyObservations)'); + self::assertIsString($observations); + self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/typed-array-byte-copy.json', $observations); + } + + public function testHostViewAndBufferSubclassesKeepTheirElementReads(): void + { + $engine = new Engine(); + $constructor = $engine->getGlobalEnv()->get('Uint8Array'); + self::assertInstanceOf(JsFunction::class, $constructor); + $viewPrototype = $constructor->get('prototype'); + self::assertInstanceOf(JsObject::class, $viewPrototype); + $bufferPrototype = $engine->getGlobalEnv()->getIntrinsic('ArrayBuffer.prototype'); + self::assertInstanceOf(JsObject::class, $bufferPrototype); + $buffer = new JsArrayBuffer(2, $bufferPrototype); + $buffer->setData("\x01\x02"); + $view = new class ('Uint8Array', $buffer, 0, 2, $viewPrototype) extends JsTypedArray { + public int $reads = 0; + + public function getIndex(int $index): JsValue + { + ++$this->reads; + return parent::getIndex($index); + } + }; + $engine->getGlobalEnv()->defineVar('source', $view); + self::assertSame([1, 2], $engine->eval('Array.from(new Uint8Array(source))')); + self::assertSame(2, $view->reads); + + $hostBuffer = new class (2, $bufferPrototype) extends JsArrayBuffer { + public int $reads = 0; + + public function readBytes(int $offset, int $length): string + { + ++$this->reads; + return parent::readBytes($offset, $length); + } + }; + $hostBuffer->setData("\x03\x04"); + $engine->getGlobalEnv()->defineVar('source', new JsTypedArray('Uint8Array', $hostBuffer, 0, 2, $viewPrototype)); + self::assertSame([3, 4], $engine->eval('Array.from(new Uint8Array(source))')); + self::assertSame(2, $hostBuffer->reads); + } + + public function testForeignConstructorKeepsItsViewAndBufferRealm(): void + { + $foreign = new Engine(); + $foreign->eval('function foreignCopy(source) { return new Uint8Array(source); } foreignCopy(new Uint8Array(0));'); + $caller = new Engine(); + $foreignValues = [ + 'foreignCopy' => $foreign->getGlobalEnv()->get('foreignCopy'), + 'foreignViewPrototype' => $foreign->getGlobalEnv()->getIntrinsic('Uint8Array.prototype'), + 'foreignBufferPrototype' => $foreign->getGlobalEnv()->getIntrinsic('ArrayBuffer.prototype'), + ]; + foreach ($foreignValues as $name => $value) { + self::assertInstanceOf(JsValue::class, $value); + $caller->getGlobalEnv()->defineVar($name, $value); + } + $sibling = new Engine(); + $sibling->eval('new Uint8Array(1);'); + for ($pass = 0; $pass < 3; $pass++) { + self::assertSame([true, true, true, [1, 2]], $caller->eval(<<<'JS' +var source = new Uint8Array([1, 2]); +var result = foreignCopy(source); +[Object.getPrototypeOf(result) === foreignViewPrototype, + Object.getPrototypeOf(result.buffer) === foreignBufferPrototype, + result.buffer !== source.buffer, Array.from(result)]; +JS)); + } + $function = $foreign->getGlobalEnv()->get('foreignCopy'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + } +} diff --git a/tests/Unit/Runtime/fixtures/typed-array-byte-copy.cjs b/tests/Unit/Runtime/fixtures/typed-array-byte-copy.cjs new file mode 100644 index 00000000..0f434e94 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/typed-array-byte-copy.cjs @@ -0,0 +1,44 @@ +var typedArrayCopyObservations = []; +for (const Type of [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, + Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array]) { + const big = Type === BigInt64Array || Type === BigUint64Array; + const input = big ? [8n, 9n, 1n, 2n, 3n, 7n] : [8, 9, 1, 2, 3, 7]; + const backing = new Type(input); + const source = new Type(backing.buffer, 2 * Type.BYTES_PER_ELEMENT, 3); + const copy = new Type(source); + source[0] = big ? 9n : 9; + copy[1] = big ? 8n : 8; + typedArrayCopyObservations.push([Type.name, Array.from(copy, value => String(value)), + Array.from(source, value => String(value)), copy.byteLength, + copy.buffer !== source.buffer, Object.getPrototypeOf(copy) === Type.prototype]); +} +const publicSource = new Uint8Array([4, 5, 6]); +let publicReads = 0; +for (const key of ['length', 'byteLength', 'byteOffset', 'buffer', 'constructor', Symbol.iterator]) { + Object.defineProperty(publicSource, key, {get() {publicReads++; throw new Error('public source read');}}); +} +typedArrayCopyObservations.push(['public properties', Array.from(new Uint8Array(publicSource)), publicReads]); +typedArrayCopyObservations.push(['different element types', Array.from(new Uint8Array(new Int16Array([-1, 257])))]); +const payload = new Uint32Array([0x7fc01234, 0x7fa12345, 0x80000000]); +const floats = new Float32Array(payload.buffer); +typedArrayCopyObservations.push(['float32 bits', Array.from(new Uint32Array(new Float32Array(floats).buffer))]); +const negativeZero = new Float64Array(new Float64Array([-0, Infinity, -Infinity, NaN])); +typedArrayCopyObservations.push(['float64 values', Object.is(negativeZero[0], -0), + negativeZero[1] === Infinity, negativeZero[2] === -Infinity, Number.isNaN(negativeZero[3])]); +const shared = new Uint8Array(new SharedArrayBuffer(3)); +shared.set([3, 4, 5]); +const sharedCopy = new Uint8Array(shared); +typedArrayCopyObservations.push(['shared source', Array.from(sharedCopy), + sharedCopy.buffer instanceof ArrayBuffer, !(sharedCopy.buffer instanceof SharedArrayBuffer)]); +const resizable = new Uint8Array(new ArrayBuffer(4, {maxByteLength: 8})); +resizable.set([1, 2, 3, 4]); +resizable.buffer.resize(2); +const resizedCopy = new Uint8Array(resizable); +resizable[0] = 9; +typedArrayCopyObservations.push(['resizable source', Array.from(resizedCopy), resizedCopy.buffer.resizable]); +function CustomTarget() {} +CustomTarget.prototype = Object.create(Uint8Array.prototype); +const custom = Reflect.construct(Uint8Array, [new Uint8Array([6, 7])], CustomTarget); +typedArrayCopyObservations.push(['custom newTarget', Array.from(custom), Object.getPrototypeOf(custom) === CustomTarget.prototype]); +typedArrayCopyObservations.push(['bigint signed', Array.from(new BigInt64Array(new BigInt64Array([-1n, -9223372036854775808n])), value => String(value))]); +typedArrayCopyObservations.push(['bigint unsigned', Array.from(new BigUint64Array(new BigUint64Array([18446744073709551615n, 0n])), value => String(value))]); diff --git a/tests/Unit/Runtime/fixtures/typed-array-byte-copy.json b/tests/Unit/Runtime/fixtures/typed-array-byte-copy.json new file mode 100644 index 00000000..b00163f3 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/typed-array-byte-copy.json @@ -0,0 +1,265 @@ +[ + [ + "Int8Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 3, + true, + true + ], + [ + "Uint8Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 3, + true, + true + ], + [ + "Uint8ClampedArray", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 3, + true, + true + ], + [ + "Int16Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 6, + true, + true + ], + [ + "Uint16Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 6, + true, + true + ], + [ + "Int32Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 12, + true, + true + ], + [ + "Uint32Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 12, + true, + true + ], + [ + "Float16Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 6, + true, + true + ], + [ + "Float32Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 12, + true, + true + ], + [ + "Float64Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 24, + true, + true + ], + [ + "BigInt64Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 24, + true, + true + ], + [ + "BigUint64Array", + [ + "1", + "8", + "3" + ], + [ + "9", + "2", + "3" + ], + 24, + true, + true + ], + [ + "public properties", + [ + 4, + 5, + 6 + ], + 0 + ], + [ + "different element types", + [ + 255, + 1 + ] + ], + [ + "float32 bits", + [ + 2143294004, + 2141266757, + 2147483648 + ] + ], + [ + "float64 values", + true, + true, + true, + true + ], + [ + "shared source", + [ + 3, + 4, + 5 + ], + true, + true + ], + [ + "resizable source", + [ + 1, + 2 + ], + false + ], + [ + "custom newTarget", + [ + 6, + 7 + ], + true + ], + [ + "bigint signed", + [ + "-1", + "-9223372036854775808" + ] + ], + [ + "bigint unsigned", + [ + "18446744073709551615", + "0" + ] + ] +] From a208f3c21c3b3a0dd531c977f448ec3d1fea317d Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 04:54:04 +0200 Subject: [PATCH 69/99] Guard VM array index casts with numeric bounds --- src/Bytecode/VM.php | 2 + tests/Unit/Bytecode/NumericArrayIndexTest.php | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/Unit/Bytecode/NumericArrayIndexTest.php diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 1a5e42dc..8f3f1b5e 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -2573,6 +2573,7 @@ public function execute( if ( $obj instanceof \Phasis\Value\JsArray && $key instanceof JsNumber + && $key->value >= 0 && $key->value < PHP_INT_MAX && $obj->isDenseMode() ) { $kv = $key->value; @@ -2755,6 +2756,7 @@ public function execute( if ( $obj instanceof \Phasis\Value\JsArray && $key instanceof JsNumber + && $key->value >= 0 && $key->value < PHP_INT_MAX ) { $kv = $key->value; $kvi = (int) $kv; diff --git a/tests/Unit/Bytecode/NumericArrayIndexTest.php b/tests/Unit/Bytecode/NumericArrayIndexTest.php new file mode 100644 index 00000000..49df4450 --- /dev/null +++ b/tests/Unit/Bytecode/NumericArrayIndexTest.php @@ -0,0 +1,45 @@ + */ + public static function keys(): iterable + { + foreach ( + ['NaN', 'Infinity', '-Infinity', '1e100', '-1e100', + '9223372036854775808', '-9223372036854775808', '4294967295', '0.5', '-1'] as $key + ) { + yield $key => [$key, 0]; + } + yield 'zero' => ['0', 1]; + yield 'negative-zero' => ['-0', 1]; + yield 'one' => ['1', 2]; + } + + #[DataProvider('keys')] + public function testVmNumericKeysRespectArrayIndexBoundsWithoutPhpWarnings(string $key, int $length): void + { + $engine = new Engine(); + self::assertSame('[7,' . $length . ',true,1]', $engine->eval(<<<'JS' +function access(array, key, value) { array[key] = value; return array[key]; } +JS + . 'var array = [], key = ' . $key . '; var value = access(array, key, 7);' + . 'JSON.stringify([value, array.length, Object.hasOwn(array, String(key)), Object.keys(array).length]);')); + $function = $engine->getGlobalEnv()->get('access'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + self::assertContains(Op::LOAD_COMPUTED, $function->compiled->code); + self::assertContains(Op::STORE_COMPUTED, $function->compiled->code); + self::assertNull($function->phpCompiled); + } +} From 1786bdb3cf434b22d41e9f5ed165fe39585e1776 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 04:54:20 +0200 Subject: [PATCH 70/99] Preserve double precision in compiled literal properties --- src/Bytecode/Parts/JsToPhpEmitStatement.php | 3 +- .../Bytecode/NumericPropertyLiteralTest.php | 55 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/Bytecode/NumericPropertyLiteralTest.php diff --git a/src/Bytecode/Parts/JsToPhpEmitStatement.php b/src/Bytecode/Parts/JsToPhpEmitStatement.php index 09e7a487..d17895e8 100644 --- a/src/Bytecode/Parts/JsToPhpEmitStatement.php +++ b/src/Bytecode/Parts/JsToPhpEmitStatement.php @@ -28,6 +28,7 @@ use Phasis\Ast\Statement\WhileStatement; use Phasis\Value\JsFunction; use Phasis\Bytecode\Bailout; +use Phasis\Bytecode\PhpNumericLiteral; /** * JsToPhp trait part: JsToPhpEmitStatement. Composed into JsToPhp via @@ -570,7 +571,7 @@ private function emitJsValueExpression(Node $node): string return '\\Phasis\\Value\\JsBoolean::of(' . ($node->value ? 'true' : 'false') . ')'; } if (is_int($node->value) || is_float($node->value)) { - return '\\Phasis\\Value\\JsNumber::of((float) ' . (string) (float) $node->value . ')'; + return '\\Phasis\\Value\\JsNumber::of(' . PhpNumericLiteral::render((float) $node->value) . ')'; } if (is_string($node->value)) { return 'new \\Phasis\\Value\\JsString(' . var_export($node->value, true) . ')'; diff --git a/tests/Unit/Bytecode/NumericPropertyLiteralTest.php b/tests/Unit/Bytecode/NumericPropertyLiteralTest.php new file mode 100644 index 00000000..80fdbdc3 --- /dev/null +++ b/tests/Unit/Bytecode/NumericPropertyLiteralTest.php @@ -0,0 +1,55 @@ + */ + public static function literals(): iterable + { + foreach ( + ['0', '-0', '0.30000000000000004', '1.0000000000000002', '0.9999999999999999', + '5e-324', '1.7976931348623157e308', '9007199254740991', '9007199254740992', + '9223372036854775808', '9223372036854777856', '-9223372036854777856', + 'NaN', 'Infinity', '-Infinity'] as $literal + ) { + yield 'object-' . $literal => [$literal, false]; + yield 'nested-array-' . $literal => [$literal, true]; + } + } + + #[DataProvider('literals')] + public function testCompiledPropertiesPreserveOriginalNumberBits(string $literal, bool $array): void + { + $engine = new Engine(); + $source = $array + ? 'var saved; Object.prototype.captureLiteral = function () { saved = this.items[0]; };' + . 'function literal() { const object = {items: [' . $literal . ']}; object.captureLiteral(); return 0; }' + . 'literal(); Object.is(saved, (' . $literal . '));' + : 'function literal() { const object = {value: ' . $literal . '}; return object.value; }' + . 'Object.is(literal(), (' . $literal . '));'; + self::assertTrue($engine->eval($source), $literal); + $function = $engine->getGlobalEnv()->get('literal'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + } + + public function testPropertyLiteralsIgnorePhpDisplayPrecision(): void + { + $before = ini_get('precision'); + ini_set('precision', '3'); + try { + $this->testCompiledPropertiesPreserveOriginalNumberBits('0.30000000000000004', false); + $this->testCompiledPropertiesPreserveOriginalNumberBits('0.30000000000000004', true); + } finally { + ini_set('precision', $before); + } + } +} From 75915d0c86ba9c7798c9fac1d57f67e86e29a9a3 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 04:54:32 +0200 Subject: [PATCH 71/99] Prevent compiled functions from replaying effects on bailout --- src/Bytecode/JsToPhp.php | 56 +- src/Bytecode/Parts/JsToPhpBailoutSafety.php | 67 +++ src/Bytecode/Parts/JsToPhpEmitExpression.php | 480 +++++++----------- src/Bytecode/Parts/JsToPhpEmitStatement.php | 101 +++- src/Bytecode/Parts/JsToPhpScope.php | 8 +- src/Runtime/Environment.php | 43 ++ src/Runtime/Parts/ExpressionEvaluation.php | 12 + .../CachedBindingInvalidationTest.php | 31 +- .../Bytecode/JsToPhpBailoutSafetyTest.php | 272 ++++++++++ .../Bytecode/LoopCheckpointContractTest.php | 7 +- tests/Unit/Bytecode/WhileCheckpointTest.php | 38 +- tests/Unit/Runtime/ObjectLiteralRealmTest.php | 17 +- 12 files changed, 757 insertions(+), 375 deletions(-) create mode 100644 src/Bytecode/Parts/JsToPhpBailoutSafety.php create mode 100644 tests/Unit/Bytecode/JsToPhpBailoutSafetyTest.php diff --git a/src/Bytecode/JsToPhp.php b/src/Bytecode/JsToPhp.php index 21e738f8..8c0b53d8 100644 --- a/src/Bytecode/JsToPhp.php +++ b/src/Bytecode/JsToPhp.php @@ -64,6 +64,7 @@ final class JsToPhp use Parts\JsToPhpEmitExpression; use Parts\JsToPhpStringScanners; use Parts\JsToPhpLoopRegions; + use Parts\JsToPhpBailoutSafety; /** @var array */ private array $declaredLocals = []; @@ -132,29 +133,6 @@ final class JsToPhp /** @var array Free variables referenced by the body. */ private array $freeVars = []; - /** - * Per-safe-name set of free vars whose `static $_fvenv_…, $_fvver_…, - * $_fv_… = ...;` declaration has already been hoisted into the - * closure prologue. Survives captureBranch (which intentionally - * resets `freeVars` so each conditional arm re-emits the lazy - * init check), so the same `static` declaration isn't emitted - * twice and tripped by PHP's "Duplicate declaration of static - * variable" compile-time error. - * - * @var array - */ - private array $freeVarStatics = []; - - /** - * `static $_fvenv_$safe = null, $_fvver_$safe = -1, $_fv_$safe = 0.0;` - * lines hoisted to the top of the closure. Each safe-name appears - * at most once, regardless of how many branches resolve the same - * free var. - * - * @var list - */ - private array $freeVarStaticDecls = []; - /** * AST nodes the eval'd closure references at run time, indexed * positionally. Currently only nested FunctionDeclaration nodes @@ -206,6 +184,9 @@ final class JsToPhp public static function compile(JsFunction $fn): ?\Closure { + if ($fn->getBoundTarget() !== null) { + return null; + } if (CompilationFailures::get($fn, 'php') !== null) { return null; } @@ -227,7 +208,9 @@ private static function compileFunction(JsFunction $fn): ?\Closure // derived ctor was leaking through as `$env->get("super")` // which then ReferenceError-ed at runtime. if ( - $fn->isClassConstructor() + $fn->isAsync() + || $fn->isGenerator() + || $fn->isClassConstructor() || $fn->isDerivedConstructor() || $fn->getHomeObject() !== null ) { @@ -299,6 +282,10 @@ private static function compileWith(JsFunction $fn, bool $numeric, ?StringScanne if ($isExpressionBody && !$body instanceof Node) { return null; } + // A raw entry must have an explicit final return before any body can run. + if ($numeric && !$isExpressionBody && !self::numericModeEligible($fn)) { + return null; + } $compiler = new self(); $compiler->numericMode = $numeric; $compiler->scannerPlan = $scanner; @@ -335,6 +322,7 @@ private static function compileWith(JsFunction $fn, bool $numeric, ?StringScanne return null; } } else { + $compiler->prepareLocalFunctionDeclarations($body); $compiler->collectLocals($body->body); $compiler->checkNestedCaptures($body->body); // Bail if any declared local has no init AND no @@ -377,18 +365,7 @@ private static function compileWith(JsFunction $fn, bool $numeric, ?StringScanne foreach ($body->body as $stmt) { $compiler->emitStatement($stmt); } - if ($numeric) { - // Numeric-mode bodies must end with an explicit - // ReturnStatement (handled by emitStatement). A - // function that falls through has no numeric value - // to surface — bail at runtime so the standard - // entry's undefined return takes over. NAN serves - // as a "fell off body" sentinel here, but better - // is to emit a Bailout so the caller falls back. - $compiler->emitLine( - 'throw new \\Phasis\\Bytecode\\Bailout("numeric body fall-off");' - ); - } else { + if (!$numeric) { $compiler->emitLine('return \\Phasis\\Value\\JsUndefined::instance();'); } } @@ -418,12 +395,7 @@ private static function compileWith(JsFunction $fn, bool $numeric, ?StringScanne // overflow thresholds while leaving headroom below // typical PHP defaults. Use a static counter local to the // closure so we don't depend on private CallStack APIs. - $freeVarStatics = ''; - foreach ($compiler->freeVarStaticDecls as $decl) { - $freeVarStatics .= $decl . "\n"; - } - $bodyPrologue = $freeVarStatics - . "static \$_jstophp_depth = 0;\n" + $bodyPrologue = "static \$_jstophp_depth = 0;\n" . "if (\$_jstophp_depth >= 8192) { throw new \\Phasis\\Exceptions\\InternalError('Maximum call stack size exceeded'); }\n" . "\$_jstophp_depth++;\n" . "try {\n"; diff --git a/src/Bytecode/Parts/JsToPhpBailoutSafety.php b/src/Bytecode/Parts/JsToPhpBailoutSafety.php new file mode 100644 index 00000000..629d1cb3 --- /dev/null +++ b/src/Bytecode/Parts/JsToPhpBailoutSafety.php @@ -0,0 +1,67 @@ + */ + private array $topLevelFunctionDeclarations = []; + + /** @var array */ + private array $initializedLocalFunctions = []; + + private function prepareLocalFunctionDeclarations(\Phasis\Ast\Statement\BlockStatement $body): void + { + $counts = []; + foreach ($body->body as $statement) { + if ($statement instanceof \Phasis\Ast\Declaration\FunctionDeclaration && $statement->id !== null) { + $name = $statement->id->name; + $counts[$name] = ($counts[$name] ?? 0) + 1; + } + } + foreach ($body->body as $statement) { + if ( + $statement instanceof \Phasis\Ast\Declaration\FunctionDeclaration && $statement->id !== null + && $counts[$statement->id->name] === 1 + ) { + $this->topLevelFunctionDeclarations[spl_object_id($statement)] = true; + } + } + } + + private function recordRuntimeGuard(): void + { + if ($this->observableEffectCount !== 0) { + throw new Bailout('speculative guard after observable effect'); + } + ++$this->runtimeGuardCount; + } + + private function recordObservableEffect(): void + { + ++$this->observableEffectCount; + } + + /** @return array{int, int} */ + private function beginLoopSafety(): array + { + return [$this->runtimeGuardCount, $this->observableEffectCount]; + } + + /** @param array{int, int} $before */ + private function finishLoopSafety(array $before): void + { + if ($this->runtimeGuardCount > $before[0] && $this->observableEffectCount > $before[1]) { + throw new Bailout('loop backedge can replay an observable effect'); + } + } +} diff --git a/src/Bytecode/Parts/JsToPhpEmitExpression.php b/src/Bytecode/Parts/JsToPhpEmitExpression.php index 6699f90a..6a2ba609 100644 --- a/src/Bytecode/Parts/JsToPhpEmitExpression.php +++ b/src/Bytecode/Parts/JsToPhpEmitExpression.php @@ -154,8 +154,9 @@ private function inferExpressionType(Node $node): string return 'unknown'; } if ($node instanceof AssignmentExpression) { - // Result of an assignment is the assigned value; most - // assignments in our profile deal with numeric slots. + if ($node->operator === '=') { + return $node->right instanceof CallExpression ? 'numeric' : $this->inferExpressionType($node->right); + } return 'numeric'; } if ($node instanceof \Phasis\Ast\Expression\MemberExpression) { @@ -197,64 +198,32 @@ private function emitExpression(Node $node): string } return $this->slotVar($node->name); } - // Free variable: read from env, unbox to raw double on - // first reference; subsequent uses pull the raw $_fv_* - // PHP local. Bail if the free var is not a JsNumber so - // the VM falls back gracefully. - // - // Cache strategy: gate the env lookup on Environment:: - // $globalBindingsVersion. The static persists across - // closure invocations; if no binding has been written - // since the previous call (closure / fib hot path), we - // skip env->get entirely and reuse the cached raw value. - // The env identity check guards against the same compiled - // closure being reused on a different env; if so, the - // cache invalidates and we re-resolve. + $this->recordRuntimeGuard(); $name = $node->name; if (!isset($this->freeVars[$name])) { $this->freeVars[$name] = true; $safe = preg_replace('/[^A-Za-z0-9_]/', '_', $name); $box = '$_fvbox_' . $safe; - $php = $this->freeVar($name); - $envCacheVar = '$_fvenv_' . $safe; - $verCacheVar = '$_fvver_' . $safe; - // Hoist the `static …` declaration to the closure - // prologue exactly once per safe-name. Emitting it - // inline here would duplicate when the same free var - // is read from both arms of a conditional — captureBranch - // resets $freeVars so each arm re-enters this block, - // but PHP forbids redeclaring the same static variable - // in one function body. - if (!isset($this->freeVarStatics[$safe])) { - $this->freeVarStatics[$safe] = true; - $this->freeVarStaticDecls[] = 'static ' . $envCacheVar - . ' = null, ' . $verCacheVar . ' = -1, ' . $php . ' = 0.0;'; - } - $this->pendingStatements[] = '$_curVer = \\Phasis\\Runtime\\Environment::' - . '$globalBindingsVersion;'; - $this->pendingStatements[] = 'if ($env !== ' . $envCacheVar - . ' || $_curVer !== ' . $verCacheVar . ') {'; - $this->pendingStatements[] = ' ' . $box - . ' = $env->get(' . var_export($name, true) . ');'; - $this->pendingStatements[] = ' if (!(' . $box + $this->pendingStatements[] = $box . ' = $env->getDataBinding(' . var_export($name, true) . ');'; + $this->pendingStatements[] = 'if (!(' . $box . ' instanceof \\Phasis\\Value\\JsNumber)) { throw new \\Phasis\\Bytecode\\Bailout("non-numeric freevar"); }'; - // Update the cache only AFTER the JsNumber check - // succeeds. If the value is not numeric we throw - // Bailout, and the cache must stay unchanged so the - // next call re-enters the if-block and re-throws, - // routing again to the VM fallback. Mutating env / - // version before the throw makes the cache appear - // valid on retry and returns the stale default. - $this->pendingStatements[] = ' ' . $envCacheVar . ' = $env;'; - $this->pendingStatements[] = ' ' . $verCacheVar . ' = $_curVer;'; - $this->pendingStatements[] = ' ' . $php . ' = ' . $box . '->value;'; - $this->pendingStatements[] = '}'; + $this->pendingStatements[] = $this->freeVar($name) . ' = ' . $box . '->value;'; } return $this->freeVar($name); } if ($node instanceof BinaryExpression) { $l = $this->emitExpression($node->left); + if ($this->scannerPlan === null && $this->loopRegion === null) { + $left = $this->newTemp('binary_left'); + $this->pendingStatements[] = $left . ' = ' . $l . ';'; + $l = $left; + } $r = $this->emitExpression($node->right); + if ($this->scannerPlan === null && $this->loopRegion === null) { + $right = $this->newTemp('binary_right'); + $this->pendingStatements[] = $right . ' = ' . $r . ';'; + $r = $right; + } switch ($node->operator) { case '+': case '-': @@ -329,15 +298,7 @@ private function emitExpression(Node $node): string } } if ($node instanceof UpdateExpression) { - if (!$node->argument instanceof Identifier) { - throw new Bailout('update on non-identifier'); - } - if (!isset($this->declaredLocals[$node->argument->name])) { - throw new Bailout('update on non-local'); - } - $slot = $this->slotVar($node->argument->name); - $op = $node->operator === '++' ? '+= 1' : '-= 1'; - return '(' . $slot . ' ' . $op . ')'; + return $this->emitLocalUpdate($node, false); } if ($node instanceof AssignmentExpression) { // obj.prop = value: lower to a direct dataSlots write on @@ -359,16 +320,21 @@ private function emitExpression(Node $node): string } $recv = $this->slotVar($recvName); $key = $node->left->property->name; + if ($this->inferExpressionType($node->right) !== 'numeric') { + throw new Bailout('non-numeric private write'); + } $val = $this->emitExpression($node->right); $temp = $this->newTemp('mw'); + $this->recordRuntimeGuard(); + $this->pendingStatements[] = 'if (!(' . $recv . ' instanceof \\Phasis\\Value\\JsObject)' + . ' || get_class(' . $recv . ') !== \\Phasis\\Value\\JsObject::class' + . ' || !isset(' . $recv . '->properties->dataSlots[' . var_export($key, true) . '])) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("member write requires an own data slot"); }'; $this->pendingStatements[] = $temp . ' = \\Phasis\\Value\\JsNumber::of((float)(' . $val . '));'; - $this->pendingStatements[] = $recv . '->properties->dataSlots[' - . var_export($key, true) . '] = ' . $temp . ';'; - // Expression value of assignment is the assigned RHS; - // most callers (ExpressionStatement) discard it, but - // return the boxed JsValue so chained assignment works. - return $temp; + $this->pendingStatements[] = $recv . '->properties->setDataSlot(' + . var_export($key, true) . ', ' . $temp . ');'; + return $temp . '->value'; } // Computed bracket-write: arr[i] = numericExpr on an array- // typed local. Lowers to a denseElements write via @@ -389,23 +355,28 @@ private function emitExpression(Node $node): string } $recv = $this->slotVar($recvName); $idxExpr = $this->emitExpression($node->left->property); + $index = $this->newTemp('array_index'); + $this->pendingStatements[] = $index . ' = ' . $idxExpr . ';'; + if ($this->inferExpressionType($node->right) !== 'numeric') { + throw new Bailout('non-numeric private write'); + } $val = $this->emitExpression($node->right); $idxLocal = $this->newTemp('ai'); $valTemp = $this->newTemp('av'); - $this->pendingStatements[] = $idxLocal . ' = (int) ' . $idxExpr . ';'; $this->pendingStatements[] = $valTemp . ' = \\Phasis\\Value\\JsNumber::of((float)(' . $val . '));'; - $this->pendingStatements[] = 'if (!' . $recv - . '->isDenseMode()) { throw new \\Phasis\\Bytecode\\Bailout("array write on non-dense receiver"); }'; + $this->recordRuntimeGuard(); + $this->pendingStatements[] = 'if (!(' . $recv . ' instanceof \\Phasis\\Value\\JsArray)' + . ' || get_class(' . $recv . ') !== \\Phasis\\Value\\JsArray::class || !' . $recv . '->isDenseMode()' + . ' || !is_float(' . $index . ') || !is_finite(' . $index . ') || ' . $index . ' < 0 || floor(' . $index . ') !== ' . $index + . ' || ' . $index . ' >= ' . $recv . '->getLength()) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("array write requires an own dense index"); }'; + $this->pendingStatements[] = $idxLocal . ' = (int) ' . $index . ';'; + $this->pendingStatements[] = 'if ((' . $recv . '->getDenseElements()[' . $idxLocal . '] ?? null) === null) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("array write requires a present index"); }'; $this->pendingStatements[] = $recv . '->setDenseElement(' . $idxLocal . ', ' . $valTemp . ');'; - // Maintain length invariant: extending past current - // length needs setLength to keep getLength() correct - // for downstream reads (e.g. .length / dense iter). - $this->pendingStatements[] = 'if (' . $idxLocal . ' >= ' . $recv - . '->getLength()) { ' . $recv . '->setLength(' - . $idxLocal . ' + 1); }'; - return $valTemp; + return $valTemp . '->value'; } if (!$node->left instanceof Identifier) { throw new Bailout('assign to non-identifier'); @@ -438,9 +409,6 @@ private function emitExpression(Node $node): string && ($this->localTypes[$name] ?? null) === 'object' ) { $newTemp = $this->emitNewExpression($node->right); - $this->pendingStatements[] = 'if (!(' . $newTemp - . ' instanceof \\Phasis\\Value\\JsObject)) { ' - . 'throw new \\Phasis\\Bytecode\\Bailout("new returned non-object"); }'; $this->pendingStatements[] = $this->slotVar($name) . ' = ' . $newTemp . ';'; return $newTemp; } @@ -466,8 +434,18 @@ private function emitExpression(Node $node): string } throw new Bailout('string assignment ' . $node->operator); } + if (!in_array($kind ?? 'numeric', ['numeric', 'boolean'], true)) { + throw new Bailout('assignment changes a non-scalar local type'); + } $slot = $this->slotVar($name); $val = $this->emitExpression($node->right); + $expected = ($this->localTypes[$name] ?? 'numeric') === 'boolean' ? 'boolean' : 'numeric'; + if ( + $this->inferExpressionType($node->right) !== $expected + && !($expected === 'numeric' && $node->right instanceof CallExpression) + ) { + throw new Bailout('assignment changes a scalar local type'); + } $op = $node->operator; if ($op === '=') { return '(' . $slot . ' = ' . $val . ')'; @@ -541,6 +519,7 @@ private function emitExpression(Node $node): string ) { $key = $node->property->name; $temp = $this->newTemp('tmr'); + $this->recordRuntimeGuard(); $this->pendingStatements[] = 'if (!($thisValue instanceof \\Phasis\\Value\\JsObject)) { ' . 'throw new \\Phasis\\Bytecode\\Bailout("this not object"); }'; $this->pendingStatements[] = $temp . ' = $thisValue' @@ -566,9 +545,15 @@ private function emitExpression(Node $node): string $recv = $this->slotVar($recvName); $idxLocal = $this->newTemp('ai'); $valLocal = $this->newTemp('av'); - $this->pendingStatements[] = $idxLocal . ' = (int) ' . $idxExpr . ';'; - $this->pendingStatements[] = 'if (!' . $recv - . '->isDenseMode()) { throw new \\Phasis\\Bytecode\\Bailout("array read on non-dense receiver"); }'; + $index = $this->newTemp('array_index'); + $this->pendingStatements[] = $index . ' = ' . $idxExpr . ';'; + $this->recordRuntimeGuard(); + $this->pendingStatements[] = 'if (!(' . $recv . ' instanceof \\Phasis\\Value\\JsArray)' + . ' || get_class(' . $recv . ') !== \\Phasis\\Value\\JsArray::class || !' . $recv . '->isDenseMode()' + . ' || !is_float(' . $index . ') || !is_finite(' . $index . ') || ' . $index . ' < 0 || floor(' . $index . ') !== ' . $index + . ' || ' . $index . ' >= ' . $recv . '->getLength()) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("array read requires an own dense index"); }'; + $this->pendingStatements[] = $idxLocal . ' = (int) ' . $index . ';'; $this->pendingStatements[] = $valLocal . ' = ' . $recv . '->getDenseElements()[' . $idxLocal . '] ?? null;'; $this->pendingStatements[] = 'if (!(' . $valLocal @@ -597,6 +582,9 @@ private function emitExpression(Node $node): string } $recv = $this->slotVar($recvName); $temp = $this->newTemp('mr'); + $this->recordRuntimeGuard(); + $this->pendingStatements[] = 'if (!(' . $recv . ' instanceof \\Phasis\\Value\\JsObject)) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("member receiver unavailable"); }'; $this->pendingStatements[] = $temp . ' = ' . $recv . '->properties->dataSlots[' . var_export($key, true) . '] ?? null;'; $this->pendingStatements[] = 'if (!(' . $temp @@ -621,33 +609,6 @@ private function emitCallExpression(CallExpression $node): string if ($scannerCall !== null) { return $scannerCall; } - // Method call shortcut: `arr.push(val)` on an array-typed - // local goes straight to JsArray::push without resolving the - // method through the prototype chain. Returns the new length - // as a numeric raw double, matching the VM inline path. - if ( - $node->callee instanceof \Phasis\Ast\Expression\MemberExpression - && !$node->callee->computed - && $node->callee->object instanceof Identifier - && $node->callee->property instanceof Identifier - ) { - $recvName = $node->callee->object->name; - if ( - isset($this->declaredLocals[$recvName]) - && ($this->localTypes[$recvName] ?? 'numeric') === 'array' - && $node->callee->property->name === 'push' - && count($node->arguments) === 1 - && !($node->arguments[0] instanceof \Phasis\Ast\Expression\SpreadElement) - ) { - $argExpr = $this->emitExpression($node->arguments[0]); - $recv = $this->slotVar($recvName); - $valTemp = $this->newTemp('av'); - $this->pendingStatements[] = $valTemp - . ' = \\Phasis\\Value\\JsNumber::of(' . $argExpr . ');'; - $this->pendingStatements[] = $recv . '->push(' . $valTemp . ');'; - return '((float) ' . $recv . '->getLength())'; - } - } // Always prefer the callee's numeric entry when it exists, // regardless of caller mode. The result is a raw float that // can be plugged into either pipeline directly: numeric mode @@ -658,6 +619,7 @@ private function emitCallExpression(CallExpression $node): string return $rawTemp; } $resultTemp = $this->emitCallCore($node); + $this->recordRuntimeGuard(); // The numeric pipeline expects a raw double. The callee's // contract is `JsNumber` — anything else triggers a Bailout // so the VM / tree-walker fallback handles non-numeric cases. @@ -682,73 +644,35 @@ private function emitNumericCallCore(CallExpression $node): ?string if (!$node->callee instanceof Identifier) { return null; } - // Same arg / callee resolution as emitCallCore but emitting - // directly to numeric entry. Bail back (return null) if the - // shape doesn't fit so the caller falls back to spec dispatch. - $argRawExprs = []; - foreach ($node->arguments as $arg) { - if ($arg instanceof \Phasis\Ast\Expression\SpreadElement) { + $this->recordRuntimeGuard(); + $name = $node->callee->name; + if (isset($this->declaredLocals[$name])) { + if (($this->localTypes[$name] ?? null) !== 'function') { return null; } - $argRawExprs[] = $this->emitExpression($arg); - } - $calleeName = $node->callee->name; - $isLocalFnCallee = false; - if (isset($this->declaredLocals[$calleeName])) { - if (($this->localTypes[$calleeName] ?? null) !== 'function') { - return null; - } - $calleeRef = $this->slotVar($calleeName); - $isLocalFnCallee = true; + $callee = $this->slotVar($name); } else { - $calleeRef = '$_fnc_' . preg_replace('/[^A-Za-z0-9_]/', '_', $calleeName); - if (!isset($this->freeVars['__fnc_' . $calleeName])) { - $this->freeVars['__fnc_' . $calleeName] = true; - $this->pendingStatements[] = $calleeRef - . ' = $env->get(' . var_export($calleeName, true) . ');'; - } - } - $argsArr = '[' . implode(', ', $argRawExprs) . ']'; - $resultTemp = $this->newTemp('cn'); - if (!$isLocalFnCallee) { - $this->pendingStatements[] = 'if (!(' . $calleeRef - . ' instanceof \\Phasis\\Value\\JsFunction)) { throw new \\Phasis\\Bytecode\\Bailout("non-function callee"); }'; - } - // Prefer phpCompiledNumeric. Fall back to phpCompiled with - // JsNumber boxing of args + unboxing of result. If neither - // exists, fall back to callFunction (and unbox). - $boxedArgs = []; - foreach ($argRawExprs as $expr) { - $boxedArgs[] = '\\Phasis\\Value\\JsNumber::of(' . $expr . ')'; - } - $boxedArgsArr = '[' . implode(', ', $boxedArgs) . ']'; - $this->pendingStatements[] = $resultTemp . ' = ' - . $calleeRef . '->phpCompiledNumeric !== null' - . ' && ' . $this->emitSameRealmGuard($calleeRef) - . ' ? (' . $calleeRef . '->phpCompiledNumeric)(' - . $argsArr . ', \\Phasis\\Value\\JsUndefined::instance(), ' - . $calleeRef . '->closure, $interp, ' - . $calleeRef . '->phpCompiledNodes)' - . ' : null;'; - // null sentinel triggers spec-entry fallback. Use the same - // pattern as the standard call core: phpCompiled or callFunction, - // then unbox. - $boxedResult = $this->newTemp('cnb'); - $this->pendingStatements[] = 'if (' . $resultTemp . ' === null) {'; - $this->pendingStatements[] = ' ' . $boxedResult . ' = ' - . $calleeRef . '->phpCompiled !== null' - . ' && ' . $this->emitSameRealmGuard($calleeRef) - . ' ? (' . $calleeRef . '->phpCompiled)(' - . $boxedArgsArr . ', \\Phasis\\Value\\JsUndefined::instance(), ' - . $calleeRef . '->closure, $interp, ' - . $calleeRef . '->phpCompiledNodes)' - . ' : $interp->callFunction(' . $calleeRef . ', ' - . '\\Phasis\\Value\\JsUndefined::instance(), ' . $boxedArgsArr . ');'; - $this->pendingStatements[] = ' if (!(' . $boxedResult - . ' instanceof \\Phasis\\Value\\JsNumber)) { throw new \\Phasis\\Bytecode\\Bailout("non-numeric call result"); }'; - $this->pendingStatements[] = ' ' . $resultTemp . ' = ' . $boxedResult . '->value;'; - $this->pendingStatements[] = '}'; - return $resultTemp; + $callee = $this->newTemp('numeric_callee'); + $this->pendingStatements[] = $callee . ' = $env->getDataBinding(' . var_export($name, true) . ');'; + } + $this->pendingStatements[] = 'if (!(' . $callee . ' instanceof \\Phasis\\Value\\JsFunction)' + . ' || ' . $callee . '->phpCompiledNumeric === null || !' . $this->emitSameRealmGuard($callee) + . ' || $interp->hasExecutionBudget() || (\\Phasis\\Engine::getCurrentInterpreter()?->hasExecutionBudget() ?? false)) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("numeric callee unavailable"); }'; + $arguments = []; + foreach ($node->arguments as $argument) { + if ($argument instanceof \Phasis\Ast\Expression\SpreadElement) { + throw new Bailout('spread numeric argument'); + } + $arguments[] = $this->emitNumericArgument($argument); + } + $this->recordRuntimeGuard(); + $result = $this->newTemp('numeric_result'); + $this->pendingStatements[] = $result . ' = (' . $callee . '->phpCompiledNumeric)([' . implode(', ', $arguments) + . '], \\Phasis\\Value\\JsUndefined::instance(), ' . $callee . '->closure, $interp, ' + . $callee . '->phpCompiledNodes);'; + $this->recordObservableEffect(); + return $result; } /** @@ -760,6 +684,7 @@ private function emitNumericCallCore(CallExpression $node): ?string private function emitFunctionValuedCall(CallExpression $node): string { $resultTemp = $this->emitCallCore($node); + $this->recordRuntimeGuard(); $this->pendingStatements[] = 'if (!(' . $resultTemp . ' instanceof \\Phasis\\Value\\JsFunction)) { throw new \\Phasis\\Bytecode\\Bailout("non-function call result"); }'; return $resultTemp; @@ -774,98 +699,96 @@ private function emitFunctionValuedCall(CallExpression $node): string */ private function emitCallCore(CallExpression $node): string { - // MemberExpression callee — `obj.method(args)`. Receiver - // must be a known object-typed local; method name must be - // an identifier (non-computed). Emits a runtime lookup + - // JsFunction guard + dispatch with the receiver passed as - // `$thisValue`. Falls back to bailout if the resolved - // method isn't BC- or JsToPhp-compiled (callFunction - // handles the spec-correct path). if ( - $node->callee instanceof \Phasis\Ast\Expression\MemberExpression - && !$node->callee->computed - && $node->callee->object instanceof Identifier - && $node->callee->property instanceof Identifier + $node->callee instanceof \Phasis\Ast\Expression\MemberExpression && !$node->callee->computed + && $node->callee->object instanceof Identifier && $node->callee->property instanceof Identifier ) { return $this->emitMethodCallCore($node); } if (!$node->callee instanceof Identifier) { throw new Bailout('non-identifier callee'); } - // Emit each arg as a numeric raw expression and box on the way - // in. Calls within args produce their own pending statements, - // which run before this call's; emit order matches JS spec - // left-to-right argument evaluation. - $argRawExprs = []; - foreach ($node->arguments as $arg) { - if ($arg instanceof \Phasis\Ast\Expression\SpreadElement) { - throw new Bailout('spread arg'); - } - $argRawExprs[] = $this->emitExpression($arg); - } - $calleeName = $node->callee->name; - // Resolve the callee. Function-typed local? Use the slot var - // directly (FunctionDeclaration-bound or assigned earlier from - // a function-valued call). Otherwise free-variable lookup - // cached in a $_fnc_ local on first reference. - $isLocalFnCallee = false; - if (isset($this->declaredLocals[$calleeName])) { - if (($this->localTypes[$calleeName] ?? null) !== 'function') { + $name = $node->callee->name; + if (isset($this->declaredLocals[$name])) { + if (($this->localTypes[$name] ?? null) !== 'function') { throw new Bailout('non-function-typed local callee'); } - $calleeRef = $this->slotVar($calleeName); - $isLocalFnCallee = true; + if (!isset($this->initializedLocalFunctions[$name])) { + throw new Bailout('local call requires interpreter function hoists'); + } + $callee = $this->slotVar($name); } else { - $calleeRef = '$_fnc_' . preg_replace('/[^A-Za-z0-9_]/', '_', $calleeName); - if (!isset($this->freeVars['__fnc_' . $calleeName])) { - $this->freeVars['__fnc_' . $calleeName] = true; - $this->pendingStatements[] = $calleeRef - . ' = $env->get(' . var_export($calleeName, true) . ');'; + $this->recordRuntimeGuard(); + $callee = $this->newTemp('callee'); + $this->pendingStatements[] = $callee . ' = $env->getDataBinding(' . var_export($name, true) . ');'; + $this->pendingStatements[] = 'if (' . $callee . ' === null) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("observable callee lookup"); }'; + } + $arguments = []; + foreach ($node->arguments as $argument) { + if ($argument instanceof \Phasis\Ast\Expression\SpreadElement) { + throw new Bailout('spread arg'); } + $arguments[] = '\\Phasis\\Value\\JsNumber::of(' . $this->emitNumericArgument($argument) . ')'; } - // Box args, build the args array, dispatch. - $boxedArgs = []; - foreach ($argRawExprs as $expr) { - $boxedArgs[] = '\\Phasis\\Value\\JsNumber::of(' . $expr . ')'; + return $this->emitBoxedDispatch( + $callee, + '\\Phasis\\Value\\JsUndefined::instance()', + '[' . implode(', ', $arguments) . ']', + $name, + ); + } + + private function emitLocalUpdate(UpdateExpression $node, bool $discard): string + { + if (!$node->argument instanceof Identifier || !isset($this->declaredLocals[$node->argument->name])) { + throw new Bailout('update on non-local identifier'); } - $argsArr = '[' . implode(', ', $boxedArgs) . ']'; - $resultTemp = $this->newTemp('cr'); - // Direct closure-to-closure dispatch when both this body and - // the callee are JsToPhp-compiled. Skips executeFunction's - // setup (callStack push, sloppy this coerce, frame setup, - // teardown) entirely. Falls back to callFunction for natives, - // generators, and any uncompiled callee — those still need - // the standard prologue / kind dispatch. - // Guard: if the callee isn't a JsFunction we can't dispatch - // numerically. Bail to VM so the spec-correct TypeError / - // Proxy / etc. handling fires. - // The instanceof JsFunction guard is only needed for free-var - // callees, where env->get could return any JsValue. For - // function-typed locals, the assignment site (FunctionDeclaration - // emit / function-valued call init) already asserted JsFunction - // and the slot type stays invariant — the per-call check is - // pure overhead. Free-var callees still need the guard since - // global / outer-scope bindings can change shape between calls. - if (!$isLocalFnCallee) { - $this->pendingStatements[] = 'if (!(' . $calleeRef - . ' instanceof \\Phasis\\Value\\JsFunction)) { throw new \\Phasis\\Bytecode\\Bailout("non-function callee"); }'; - } - // Direct closure dispatch when phpCompiled is set. The compile - // path only runs for non-native callees (callFunctionInner - // routes natives to their callable before reaching tryRunOnVm), - // so phpCompiled !== null implies non-native. Direct property - // access on $closure / phpCompiledNodes skips the getter - // method dispatch in this hot path. - $this->pendingStatements[] = $resultTemp . ' = ' - . $calleeRef . '->phpCompiled !== null' - . ' && ' . $this->emitSameRealmGuard($calleeRef) - . ' ? (' . $calleeRef . '->phpCompiled)(' - . $argsArr . ', \\Phasis\\Value\\JsUndefined::instance(), ' - . $calleeRef . '->closure, $interp, ' - . $calleeRef . '->phpCompiledNodes)' - . ' : $interp->callFunction(' . $calleeRef . ', ' - . '\\Phasis\\Value\\JsUndefined::instance(), ' . $argsArr . ');'; - return $resultTemp; + if (($this->localTypes[$node->argument->name] ?? 'numeric') !== 'numeric') { + throw new Bailout('update on a non-numeric local'); + } + $slot = $this->slotVar($node->argument->name); + $operation = $slot . ($node->operator === '++' ? ' += 1.0' : ' -= 1.0'); + if ($node->prefix || $discard) { + return '(' . $operation . ')'; + } + $previous = $this->newTemp('postfix'); + $this->pendingStatements[] = $previous . ' = ' . $slot . ';'; + $this->pendingStatements[] = $operation . ';'; + return $previous; + } + + private function emitNumericArgument(Node $argument): string + { + if ($this->inferExpressionType($argument) !== 'numeric') { + throw new Bailout('non-numeric call argument'); + } + $value = $this->emitExpression($argument); + $temporary = $this->newTemp('argument'); + $this->pendingStatements[] = $temporary . ' = ' . $value . ';'; + return $temporary; + } + + private function emitBoxedDispatch(string $callee, string $receiver, string $arguments, string $display): string + { + $result = $this->newTemp('call_result'); + $packed = $this->newTemp('call_arguments'); + $this->pendingStatements[] = $packed . ' = ' . $arguments . ';'; + $arguments = $packed; + $fallback = '$interp->vmCallValue(' . $callee . ', ' . $receiver . ', ' . $arguments + . ', ' . var_export($display, true) . ')'; + $this->pendingStatements[] = 'try {'; + $this->pendingStatements[] = ' ' . $result . ' = ' . $callee . ' instanceof \\Phasis\\Value\\JsFunction' + . ' && ' . $callee . '->phpCompiled !== null && ' . $this->emitSameRealmGuard($callee) + . ' && !$interp->hasExecutionBudget()' + . ' && !(\\Phasis\\Engine::getCurrentInterpreter()?->hasExecutionBudget() ?? false)' + . ' ? (' . $callee . '->phpCompiled)(' . $arguments . ', ' . $receiver . ', ' + . $callee . '->closure, $interp, ' . $callee . '->phpCompiledNodes) : ' . $fallback . ';'; + $this->pendingStatements[] = '} catch (\\Phasis\\Bytecode\\Bailout) {'; + $this->pendingStatements[] = ' ' . $result . ' = ' . $fallback . ';'; + $this->pendingStatements[] = '}'; + $this->recordObservableEffect(); + return $result; } /** Direct PHP dispatch cannot establish a foreign function's execution realm. */ @@ -885,16 +808,10 @@ private function emitSameRealmGuard(string $callee): string */ private function emitNewExpression(\Phasis\Ast\Expression\NewExpression $node): string { + $this->recordObservableEffect(); if (!$node->callee instanceof Identifier) { throw new Bailout('new with non-identifier callee'); } - $argRawExprs = []; - foreach ($node->arguments as $arg) { - if ($arg instanceof \Phasis\Ast\Expression\SpreadElement) { - throw new Bailout('spread arg in new'); - } - $argRawExprs[] = $this->emitExpression($arg); - } $ctorName = $node->callee->name; // Prefer the function-typed local slot when the constructor was // declared in this compile frame (e.g. a nested @@ -904,14 +821,21 @@ private function emitNewExpression(\Phasis\Ast\Expression\NewExpression $node): isset($this->declaredLocals[$ctorName]) && ($this->localTypes[$ctorName] ?? null) === 'function' ) { + if (!isset($this->initializedLocalFunctions[$ctorName])) { + throw new Bailout('local constructor requires interpreter function hoists'); + } $ctorRef = $this->slotVar($ctorName); } else { $ctorRef = '$_ctor_' . preg_replace('/[^A-Za-z0-9_]/', '_', $ctorName); - if (!isset($this->freeVars['__ctor_' . $ctorName])) { - $this->freeVars['__ctor_' . $ctorName] = true; - $this->pendingStatements[] = $ctorRef - . ' = $env->get(' . var_export($ctorName, true) . ');'; + $this->pendingStatements[] = $ctorRef + . ' = $env->get(' . var_export($ctorName, true) . ');'; + } + $argRawExprs = []; + foreach ($node->arguments as $arg) { + if ($arg instanceof \Phasis\Ast\Expression\SpreadElement) { + throw new Bailout('spread arg in new'); } + $argRawExprs[] = $this->emitNumericArgument($arg); } $boxedArgs = []; foreach ($argRawExprs as $expr) { @@ -965,45 +889,23 @@ private function emitMethodCallCore(CallExpression $node): string $recv = $this->slotVar($recvName); $methodTemp = $this->newTemp('mc'); $propLit = var_export($propId->name, true); - // Inline the common own-data-slot and prototype-data-slot - // resolutions; only fall back to `->get()` when we miss both. - // This mirrors the VM's LOAD_MEMBER fast paths but inside the - // JsToPhp-compiled closure so proto-method hot loops never - // pay the method-dispatch tax. The receiver was already - // proven to be an object-typed local upstream, so the - // ->properties / ->prototype field accesses are safe. - $this->pendingStatements[] = $methodTemp . ' = ' - . $recv . '->properties->dataSlots[' . $propLit . ']' - . ' ?? (' - . $recv . '->prototype !== null' - . ' ? (' . $recv . '->prototype->properties->dataSlots[' . $propLit . ']' - . ' ?? ' . $recv . '->get(' . $propLit . '))' - . ' : ' . $recv . '->get(' . $propLit . '));'; - $this->pendingStatements[] = 'if (!(' . $methodTemp - . ' instanceof \\Phasis\\Value\\JsFunction)) { ' - . 'throw new \\Phasis\\Bytecode\\Bailout("non-function method"); }'; + $this->recordRuntimeGuard(); + $this->pendingStatements[] = 'if (!(' . $recv . ' instanceof \\Phasis\\Value\\JsObject)) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("method receiver unavailable"); }'; + $this->recordObservableEffect(); + $this->pendingStatements[] = $methodTemp . ' = ' . $recv . '->get(' . $propLit . ');'; $argRawExprs = []; foreach ($node->arguments as $arg) { if ($arg instanceof \Phasis\Ast\Expression\SpreadElement) { throw new Bailout('spread arg in method call'); } - $argRawExprs[] = $this->emitExpression($arg); + $argRawExprs[] = $this->emitNumericArgument($arg); } $boxedArgs = []; foreach ($argRawExprs as $expr) { $boxedArgs[] = '\\Phasis\\Value\\JsNumber::of(' . $expr . ')'; } $argsArr = '[' . implode(', ', $boxedArgs) . ']'; - $resultTemp = $this->newTemp('mr'); - $this->pendingStatements[] = $resultTemp . ' = ' - . $methodTemp . '->phpCompiled !== null' - . ' && ' . $this->emitSameRealmGuard($methodTemp) - . ' ? (' . $methodTemp . '->phpCompiled)(' - . $argsArr . ', ' . $recv . ', ' - . $methodTemp . '->closure, $interp, ' - . $methodTemp . '->phpCompiledNodes)' - . ' : $interp->callFunction(' . $methodTemp . ', ' - . $recv . ', ' . $argsArr . ');'; - return $resultTemp; + return $this->emitBoxedDispatch($methodTemp, $recv, $argsArr, $recvName . '.' . $propId->name); } } diff --git a/src/Bytecode/Parts/JsToPhpEmitStatement.php b/src/Bytecode/Parts/JsToPhpEmitStatement.php index d17895e8..2b433e1f 100644 --- a/src/Bytecode/Parts/JsToPhpEmitStatement.php +++ b/src/Bytecode/Parts/JsToPhpEmitStatement.php @@ -60,13 +60,9 @@ private function emitPrologue(array $params): void } $php = $this->slotVar($name); if ($this->numericMode) { - // Numeric entry: caller (another JsToPhp closure) has - // already validated the arg shape and passes raw - // float values via $rawArgs. Default missing args to - // NAN — JS spec says ToNumber(undefined) is NaN, and - // a numeric body computing on a missing param should - // propagate NaN rather than silently treat as 0. - $this->emitLine($php . ' = $rawArgs[' . $idx . '] ?? NAN;'); + $this->emitLine($php . ' = $rawArgs[' . $idx . '] ?? null;'); + $this->emitLine('if (!is_float(' . $php . ')) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("non-numeric raw argument"); }'); } else { $this->emitLine( $php . ' = isset($args[' . $idx . ']) && $args[' . $idx . '] ' @@ -140,6 +136,9 @@ private function emitStatement(Node $node): void $this->slotVar($name) . ' = $interp->vmMakeFunction($nestedFns[' . $idx . '], $env);' ); + if (isset($this->topLevelFunctionDeclarations[spl_object_id($node)])) { + $this->initializedLocalFunctions[$name] = true; + } return; } if ($node instanceof BlockStatement) { @@ -164,7 +163,8 @@ private function emitStatement(Node $node): void $this->emitLine($resultTemp . ';'); return; } - $expr = $this->emitExpression($node->expression); + $expr = $node->expression instanceof UpdateExpression + ? $this->emitLocalUpdate($node->expression, true) : $this->emitExpression($node->expression); $this->flushPending(); $this->emitLine($expr . ';'); $this->emitRegionExpressionWrite($node->expression); @@ -237,9 +237,6 @@ private function emitStatement(Node $node): void // the construct-returns-primitive corner case. $newTemp = $this->emitNewExpression($decl->init); $this->flushPending(); - $this->emitLine('if (!(' . $newTemp - . ' instanceof \\Phasis\\Value\\JsObject)) { ' - . 'throw new \\Phasis\\Bytecode\\Bailout("new returned non-object"); }'); $this->emitLine($this->slotVar($name) . ' = ' . $newTemp . ';'); } elseif ($kind === 'function' && $decl->init instanceof CallExpression) { // Call returning a JsFunction (e.g. `const add5 = @@ -266,6 +263,13 @@ private function emitStatement(Node $node): void // callee returns a JsNumber. throw new Bailout('let X = callExpr() with default numeric type'); } else { + if (!in_array($kind, ['numeric', 'boolean'], true)) { + throw new Bailout('initializer changes a non-scalar local type'); + } + $expected = $kind === 'boolean' ? 'boolean' : 'numeric'; + if ($this->inferExpressionType($decl->init) !== $expected) { + throw new Bailout('non-numeric scalar initializer'); + } $val = $this->emitExpression($decl->init); $this->flushPending(); $this->emitLine($this->slotVar($name) . ' = ' . $val . ';'); @@ -302,6 +306,7 @@ private function emitStatement(Node $node): void $this->emitLine($expr . ';'); } } + $loopSafety = $this->beginLoopSafety(); // The test / update are emitted at every iteration boundary. // When the test or update needs deferred statements (free- // variable resolution caches, lifted call results), rewrite @@ -312,13 +317,14 @@ private function emitStatement(Node $node): void // loop that references a closed-over local in its test. $savedPending = $this->pendingStatements; $this->pendingStatements = []; - $test = $node->test !== null ? $this->emitExpression($node->test) : 'true'; + $test = $node->test !== null ? $this->emitLoopCondition($node->test) : 'true'; $testPending = $this->pendingStatements; $this->pendingStatements = []; $update = null; $updatePending = []; if ($node->update !== null) { - $update = $this->emitExpression($node->update); + $update = $node->update instanceof UpdateExpression + ? $this->emitLocalUpdate($node->update, true) : $this->emitExpression($node->update); $updatePending = $this->pendingStatements; } $this->pendingStatements = $savedPending; @@ -339,14 +345,16 @@ private function emitStatement(Node $node): void } $this->indentLevel--; $this->emitLine('}'); + $this->finishLoopSafety($loopSafety); return; } if ($node instanceof WhileStatement) { + $loopSafety = $this->beginLoopSafety(); $loopCounter = $this->newTemp('loop'); $this->emitLine($loopCounter . ' = 0;'); $savedPending = $this->pendingStatements; $this->pendingStatements = []; - $test = $this->emitExpression($node->test); + $test = $this->emitLoopCondition($node->test); $testPending = $this->pendingStatements; $this->pendingStatements = $savedPending; // A final false condition still checks the deadline, but consumes @@ -362,14 +370,16 @@ private function emitStatement(Node $node): void $this->emitStatement($node->body); $this->indentLevel--; $this->emitLine('}'); + $this->finishLoopSafety($loopSafety); return; } if ($node instanceof DoWhileStatement) { + $loopSafety = $this->beginLoopSafety(); $loopCounter = $this->newTemp('loop'); $this->emitLine($loopCounter . ' = 0;'); $savedPending = $this->pendingStatements; $this->pendingStatements = []; - $test = $this->emitExpression($node->test); + $test = $this->emitLoopCondition($node->test); $testPending = $this->pendingStatements; $this->pendingStatements = $savedPending; $this->emitLine('do {'); @@ -391,6 +401,7 @@ private function emitStatement(Node $node): void // a flag so the pending lines run before the test. $this->emitLine('} while (' . $test . ');'); } + $this->finishLoopSafety($loopSafety); return; } if ($node instanceof BreakStatement) { @@ -408,6 +419,36 @@ private function emitStatement(Node $node): void return; } if ($node instanceof ReturnStatement) { + if (!$this->numericMode && $node->argument instanceof CallExpression) { + if (in_array('function', $this->localTypes, true)) { + throw new Bailout('boxed return call requires interpreter function hoists'); + } + $value = $this->emitCallCore($node->argument); + $this->flushPending(); + $this->emitLine('return ' . $value . ';'); + return; + } + if ( + !$this->numericMode && $node->argument instanceof Identifier + && !isset($this->declaredLocals[$node->argument->name]) + ) { + $this->recordObservableEffect(); + $this->emitLine('return $env->get(' . var_export($node->argument->name, true) . ');'); + return; + } + if ( + !$this->numericMode && $node->argument instanceof \Phasis\Ast\Expression\MemberExpression + && !$node->argument->computed && !$node->argument->optional + && $node->argument->object instanceof Identifier && $node->argument->property instanceof Identifier + && ($this->localTypes[$node->argument->object->name] ?? null) === 'object' + ) { + $this->recordObservableEffect(); + $receiver = $this->slotVar($node->argument->object->name); + $this->emitLine('return $interp->vmLookupPrimitiveMember(' . $receiver + . ' ?? \\Phasis\\Value\\JsUndefined::instance(), ' + . var_export($node->argument->property->name, true) . ');'); + return; + } if ($node->argument === null) { if ($this->numericMode) { // No numeric value to surface; bail so the caller @@ -459,8 +500,7 @@ private function emitDestructureFromLiteral( \Phasis\Ast\Pattern\ObjectPattern $pattern, \Phasis\Ast\Expression\ObjectExpression $literal, ): void { - // Build a key → AST value map from the literal so pattern - // targets can fetch their values without a runtime lookup. + // Every initializer runs before binding targets, including unused and overwritten properties. $keyMap = []; foreach ($literal->properties as $prop) { if (!$prop instanceof \Phasis\Ast\Expression\Property) { @@ -477,7 +517,13 @@ private function emitDestructureFromLiteral( } else { throw new Bailout('weird destructure source key'); } - $keyMap[$key] = $prop->value; + if ($key === '__proto__' || $this->inferExpressionType($prop->value) !== 'numeric') { + throw new Bailout('non-numeric destructuring value'); + } + $value = $this->emitExpression($prop->value); + $temporary = $this->newTemp('destructure_value'); + $this->pendingStatements[] = $temporary . ' = ' . $value . ';'; + $keyMap[$key] = $temporary; } foreach ($pattern->properties as $prop) { if (!$prop instanceof \Phasis\Ast\Pattern\AssignmentProperty) { @@ -500,7 +546,7 @@ private function emitDestructureFromLiteral( if (!isset($keyMap[$patKey])) { throw new Bailout('pattern key missing in source'); } - $valueExpr = $this->emitExpression($keyMap[$patKey]); + $valueExpr = $keyMap[$patKey]; $this->flushPending(); $this->emitLine( $this->slotVar($prop->value->name) . ' = ' . $valueExpr . ';' @@ -508,6 +554,16 @@ private function emitDestructureFromLiteral( } } + /** @phpstan-impure */ + private function emitLoopCondition(Node $condition): string + { + if ($condition instanceof CallExpression && $this->scannerPlan === null && $this->loopRegion === null) { + $value = $this->emitCallCore($condition); + return '\\Phasis\\Spec\\TypeConversion::toBoolean(' . $value . ')'; + } + return $this->emitExpression($condition); + } + private function flushPending(): void { foreach ($this->pendingStatements as $line) { @@ -546,9 +602,12 @@ private function emitObjectLiteral(\Phasis\Ast\Expression\ObjectExpression $node } else { throw new Bailout('object literal weird key'); } + if ($key === '__proto__') { + throw new Bailout('object literal prototype setter'); + } $valueRef = $this->emitJsValueExpression($prop->value); - $this->pendingStatements[] = $temp . '->properties->dataSlots[' - . var_export($key, true) . '] = ' . $valueRef . ';'; + $this->pendingStatements[] = $temp . '->properties->setDataSlot(' + . var_export($key, true) . ', ' . $valueRef . ');'; } return $temp; } diff --git a/src/Bytecode/Parts/JsToPhpScope.php b/src/Bytecode/Parts/JsToPhpScope.php index de5f4e93..ed6c235c 100644 --- a/src/Bytecode/Parts/JsToPhpScope.php +++ b/src/Bytecode/Parts/JsToPhpScope.php @@ -232,8 +232,9 @@ private function checkNestedCapturesIn(Node $node): void /** * Build the initial set of names defined in a nested function's - * own scope: its parameters, plus its own name (FunctionExpression - * / FunctionDeclaration). Names in this set shadow outer locals + * own scope: its parameters, plus a named FunctionExpression's name. + * A FunctionDeclaration's name resolves through its enclosing scope. + * Names in this set shadow outer locals * and are NOT considered captures. * * @return array @@ -241,9 +242,6 @@ private function checkNestedCapturesIn(Node $node): void private function initialNestedScope(Node $fnNode): array { $blocked = []; - if ($fnNode instanceof FunctionDeclaration && $fnNode->id !== null) { - $blocked[$fnNode->id->name] = true; - } if ( $fnNode instanceof \Phasis\Ast\Expression\FunctionExpression && $fnNode->name !== null diff --git a/src/Runtime/Environment.php b/src/Runtime/Environment.php index 30ff67fe..d37a590c 100644 --- a/src/Runtime/Environment.php +++ b/src/Runtime/Environment.php @@ -517,6 +517,49 @@ public function findBindingDepth(string $name): ?array return null; } + /** + * Read an ordinary data binding without invoking getters, imports or with traps. + * Null declines speculation and leaves errors and observable reads to the interpreter. + */ + public function getDataBinding(string $name): ?JsValue + { + $current = $this; + while ($current !== null) { + if ( + $current->withObject !== null || isset($current->tdz[$name]) + || array_key_exists($name, $current->importBindings) + ) { + return null; + } + if (isset($current->bindings[$name])) { + if (!$current->isGlobalObjectBinding($name)) { + return $current->bindings[$name]; + } + $object = $current->linkedObject; + return $object !== null ? self::ordinaryDataValue($object, $name) : null; + } + if ($current->parent === null && $current->linkedObject !== null) { + $object = $current->linkedObject; + return self::ordinaryDataValue($object, $name); + } + $current = $current->parent; + } + return null; + } + + private static function ordinaryDataValue(\Phasis\Value\JsObject $object, string $name): ?JsValue + { + if (get_class($object) !== \Phasis\Value\JsObject::class) { + return null; + } + $value = $object->properties->dataSlots[$name] ?? null; + if ($value !== null) { + return $value; + } + $descriptor = $object->properties->descriptors[$name] ?? null; + return $descriptor !== null && $descriptor->isDataDescriptor() ? $descriptor->value : null; + } + public function get( string $name, bool $strict = false, diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index 5cbb62e1..743918f0 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -3795,6 +3795,18 @@ private function spreadInto(JsValue $iterable, array &$target): void } } + /** @param list $args */ + public function vmCallValue(JsValue $callee, JsValue $thisValue, array $args, string $display = 'value'): JsValue + { + if ($callee instanceof JsFunction) { + return $this->callFunction($callee, $thisValue, $args); + } + if ($callee instanceof \Phasis\Value\JsProxy && $callee->isCallable()) { + return $callee->apply($thisValue, $args); + } + throw new TypeError($display . ' is not a function'); + } + /** @param JsValue[] $args */ public function callFunction( JsFunction $fn, diff --git a/tests/Unit/Bytecode/CachedBindingInvalidationTest.php b/tests/Unit/Bytecode/CachedBindingInvalidationTest.php index 1e63a86c..831b8943 100644 --- a/tests/Unit/Bytecode/CachedBindingInvalidationTest.php +++ b/tests/Unit/Bytecode/CachedBindingInvalidationTest.php @@ -6,6 +6,7 @@ use Phasis\Ast\Declaration\FunctionDeclaration; use Phasis\Bytecode\Compiler; +use Phasis\Bytecode\Bailout; use Phasis\Bytecode\Frame; use Phasis\Bytecode\JsToPhp; use Phasis\Bytecode\Op; @@ -21,6 +22,20 @@ final class CachedBindingInvalidationTest extends TestCase { + public function testImportFallbackDoesNotRepeatTheResolver(): void + { + $engine = new Engine(); + $scope = $engine->getGlobalEnv()->createChild(); + $calls = 0; + $scope->defineImportBinding('current', static function () use (&$calls): JsNumber { + return JsNumber::of(++$calls); + }); + $read = $this->reader($engine, $scope, 'php', true); + self::assertSame(1.0, $read()); + self::assertSame(2.0, $read()); + self::assertSame(2, $calls); + } + /** @return iterable */ public static function mutations(): iterable { @@ -47,7 +62,7 @@ public function testCachedReadsObserveHostBindingMutations(string $tier, string } else { $parent->set('current', JsNumber::of(1)); } - $read = $this->reader($engine, $scope, $tier); + $read = $this->reader($engine, $scope, $tier, $mutation === 'shadow-import'); self::assertSame(1.0, $read()); switch ($mutation) { case 'replace-deletable': @@ -72,7 +87,7 @@ public function testCachedReadsObserveHostBindingMutations(string $tier, string } /** @return \Closure(): float */ - private function reader(Engine $engine, Environment $scope, string $tier): \Closure + private function reader(Engine $engine, Environment $scope, string $tier, bool $importFallback = false): \Closure { // Activation setup must not incidentally invalidate the warmed binding cache. $declaration = (new Parser('function read() { return current + 0; }'))->parse()->body[0]; @@ -82,7 +97,17 @@ private function reader(Engine $engine, Environment $scope, string $tier): \Clos if ($tier === 'php') { $compiled = JsToPhp::compile($function); self::assertInstanceOf(\Closure::class, $compiled); - return static fn (): float => $compiled([], $undefined, $scope, $engine->getInterpreter(), [])->value; + return static function () use ($compiled, $undefined, $scope, $engine, $function, $importFallback): float { + try { + return $compiled([], $undefined, $scope, $engine->getInterpreter(), [])->value; + } catch (Bailout $error) { + if (!$importFallback) { + throw $error; + } + self::assertNull($scope->getDataBinding('current')); + return $engine->getInterpreter()->callFunction($function, $undefined, [])->value; + } + }; } $compiled = (new Compiler())->compile($function); self::assertContains(Op::LOAD_NAME, $compiled->code); diff --git a/tests/Unit/Bytecode/JsToPhpBailoutSafetyTest.php b/tests/Unit/Bytecode/JsToPhpBailoutSafetyTest.php new file mode 100644 index 00000000..e806277e --- /dev/null +++ b/tests/Unit/Bytecode/JsToPhpBailoutSafetyTest.php @@ -0,0 +1,272 @@ + */ + public static function cases(): iterable + { + yield 'boxed-free-return' => [ + 'var n=0,value=\'x\'; function touch(){n++} function checked(){touch();return value' + . '} var a=checked(),b=n,c=checked(); JSON.stringify([a,b,c,n]);', + '["x",1,"x",2]', + true, + true, + ]; + yield 'arithmetic-free-return' => [ + 'var n=0,value=\'x\'; function touch(){n++} function checked(){touch();return value' + . '+0} var a=checked(),b=n,c=checked(); JSON.stringify([a,b,c,n]);', + '["x0",1,"x0",2]', + false, + true, + ]; + yield 'boxed-call-return' => [ + 'var n=0;function produce(){n++;return \'x\'}function checked(){return produce()}va' + . 'r a=checked(),b=n,c=checked();JSON.stringify([a,b,c,n]);', + '["x",1,"x",2]', + true, + true, + ]; + yield 'nonnumeric-call-result' => [ + 'var n=0;function produce(){n++;return \'x\'}function checked(){return produce()+0}' + . 'var a=checked(),b=n,c=checked();JSON.stringify([a,b,c,n]);', + '["x0",1,"x0",2]', + true, + true, + ]; + yield 'member-after-effect' => [ + 'var n=0;Object.prototype.change=function(){n++;delete this.value};Object.defineP' + . 'roperty(Object.prototype,\'value\',{get(){n++;return \'x\'}});function checked(){con' + . 'st object={value:0};object.change();return object.value}var a=checked(),b=n,c=ch' + . 'ecked();JSON.stringify([a,b,c,n]);', + '["x",2,"x",4]', + true, + true, + ]; + yield 'branch-merge' => [ + 'var n=0,value=\'x\';function touch(){n++}function checked(x){if(x>0)touch();return' + . ' value+0}var a=checked(1),b=n,c=checked(0);JSON.stringify([a,b,c,n]);', + '["x0",1,"x0",1]', + false, + true, + ]; + yield 'conditional-pending-statements' => [ + 'var n=0,value=\'x\';function produce(){n++;return \'x\'}function checked(x){return x' + . '>0?produce()+0:value+0}var a=checked(1),b=n,c=checked(0);JSON.stringify([a,b,c,n' + . ']);', + '["x0",1,"x0",1]', + false, + true, + ]; + yield 'while-backedge' => [ + 'let limit=2;var n=0;function touch(){n++;limit=\'x\'}function checked(){let i=0;wh' + . 'ile(i [ + 'let limit=2;var n=0;function touch(){n++;limit=\'x\'}function checked(){let i=0;fo' + . 'r(;i [ + 'let limit=2;var n=0;function touch(){n++;limit=\'x\'}function checked(){let i=0;do' + . '{touch();i++}while(i [ + 'var n=0;function second(){n++;return \'x\'}function first(){n++;target=second;retu' + . 'rn 0}var target=first;function checked(){target(0);return target(0)}JSON.stringi' + . 'fy([checked(),n]);', + '["x",2]', + false, + true, + ]; + yield 'noncallable-no-coercion' => [ + 'var n=0;var target={[Symbol.toPrimitive](){n++;return \'object\'}};function checke' + . 'd(x){return target(x)}var error;try{checked(1)}catch(e){error=e instanceof TypeE' + . 'rror}JSON.stringify([error,n]);', + '[true,0]', + true, + true, + ]; + yield 'global-getter-before-fallback' => [ + 'var n=0;Object.defineProperty(globalThis,\'input\',{get(){n++;return \'x\'}});functi' + . 'on checked(){return input+0}var a=checked(),b=n,c=checked();JSON.stringify([a,b,' + . 'c,n]);', + '["x0",1,"x0",2]', + true, + true, + ]; + yield 'missing-raw-argument' => [ + 'function identity(x){return x}identity(1);function checked(){let value=1;value=i' + . 'dentity();return value}JSON.stringify([typeof checked(),typeof checked()]);', + '["undefined","undefined"]', + true, + true, + ]; + yield 'local-callee-fallback-and-arguments' => [ + 'var events=[],lookups=0;function event(value){events.push(value)}function target' + . '(value,required){event(value);return value}target(1,1);Object.defineProperty(Obj' + . 'ect.prototype,\'method\',{get(){lookups++;return target}});function checked(value)' + . '{const object={};object.method(value+=1);return value}var a=checked(7),b=checked' + . '(8);JSON.stringify([a,b,lookups,events]);', + '[8,9,2,[1,8,9]]', + true, + true, + ]; + yield 'argument-source-order' => [ + 'function identity(n){return n}function combine(a,b){return a*100+b}identity(1);c' + . 'ombine(1,1);function checked(n){return combine((n=n+1),identity(n)+0)}JSON.strin' + . 'gify([checked(1),checked(2)]);', + '[202,303]', + true, + true, + ]; + yield 'postfix-arguments' => [ + 'function combine(a,b){return a*100+b}combine(1,1);function checked(n){return com' + . 'bine(n++,n)}JSON.stringify([checked(1),checked(2)]);', + '[102,203]', + true, + true, + ]; + yield 'postfix-subtraction-left' => [ + 'function identity(n){return n}identity(1);function checked(n){return n--*100-ide' + . 'ntity(n)}JSON.stringify([checked(1),checked(3)]);', + '[100,298]', + true, + true, + ]; + yield 'own-object-write' => [ + 'var hits=0;Object.defineProperty(Object.prototype,\'x\',{set(v){hits++}});function' + . ' checked(n){const object={x:n};object.x=n+1;return object.x}JSON.stringify([chec' + . 'ked(1),checked(2),hits]);', + '[2,3,0]', + true, + true, + ]; + yield 'new-object-key-setter' => [ + 'var hits=0,value=\'x\';Object.defineProperty(Object.prototype,\'newKey\',{set(v){hit' + . 's++}});function checked(n){const object={};object.newKey=n;return value+0}var a=' + . 'checked(1),b=hits,c=checked(2);JSON.stringify([a,b,c,hits]);', + '["x0",1,"x0",2]', + true, + true, + ]; + yield 'array-write-fractional' => [ + 'var hits=0,value=\'x\';Object.defineProperty(Array.prototype,\'0.5\',{set(v){hits++}' + . '});function checked(n){const array=[];array[n]=1;return value+0}var a=checked(0.' + . '5),b=hits,c=checked(0.5);JSON.stringify([a,b,c,hits]);', + '["x0",1,"x0",2]', + true, + true, + ]; + yield 'array-write-nan' => [ + 'var hits=0,value=\'x\';Object.defineProperty(Array.prototype,\'NaN\',{set(v){hits++}' + . '});function checked(n){const array=[];array[n]=1;return value+0}var a=checked(Na' + . 'N),b=hits,c=checked(NaN);JSON.stringify([a,b,c,hits]);', + '["x0",1,"x0",2]', + true, + true, + ]; + yield 'array-write-missing-integer' => [ + 'var hits=0,value=\'x\';Object.defineProperty(Array.prototype,\'0\',{set(v){hits++}})' + . ';function checked(n){const array=[];array[n]=1;return value+0}var a=checked(0),b' + . '=hits,c=checked(0);JSON.stringify([a,b,c,hits]);', + '["x0",1,"x0",2]', + true, + true, + ]; + yield 'array-read-fractional-getter' => [ + 'var hits=0;Object.defineProperty(Array.prototype,\'0.5\',{get(){hits++;return 4}})' + . ';function checked(n){const array=[];return array[n]+0}var a=checked(0.5),b=hits,' + . 'c=checked(0.5);JSON.stringify([a,b,c,hits]);', + '[4,1,4,2]', + true, + true, + ]; + yield 'unused-literal-initializer' => [ + 'var events=0;function touch(){events++;return 7}function checked(n){const {a}={u' + . 'nused:touch(),a:n};return a}var a=checked(1),b=events,c=checked(2);JSON.stringif' + . 'y([a,b,c,events]);', + '[1,1,2,2]', + false, + true, + ]; + yield 'overwritten-literal-initializer' => [ + 'var events=0;function touch(){events++;return 7}function checked(n){const {a}={a' + . ':touch(),a:n};return a}var a=checked(1),b=events,c=checked(2);JSON.stringify([a,' + . 'b,c,events]);', + '[1,1,2,2]', + false, + true, + ]; + yield 'object-literal-property-order' => [ + 'Object.prototype.inspect=function(){return Object.keys(this).join(\',\')};function' + . ' checked(n){const object={first:n,second:n};return object.inspect()}JSON.stringi' + . 'fy([checked(1),checked(2)]);', + '["first,second","first,second"]', + true, + true, + ]; + yield 'escaped-object-mutation' => [ + 'var hits=0,value=\'x\';Object.prototype.escape=function(){Object.defineProperty(th' + . 'is,\'x\',{set(v){hits++},configurable:true})};function checked(n){const object={x:' + . '0};object.escape();object.x=n;return value+0}var a=checked(1),b=hits,c=checked(2' + . ');JSON.stringify([a,b,c,hits]);', + '["x0",1,"x0",2]', + false, + true, + ]; + yield 'late-local-loop-function' => [ + 'function checked(){let count=0;while(condition(count)){count++}function conditio' + . 'n(value){return value<1}return count}JSON.stringify([checked(),checked()]);', + '[1,1]', + false, + true, + ]; + yield 'conditional-local-loop-function' => [ + 'function checked(n){if(n>0){function condition(value){return value<1}}let count=' + . '0;while(condition(count)){count++}return count}JSON.stringify([checked(1),checke' + . 'd(1)]);', + '[1,1]', + false, + false, + ]; + yield 'recursive-local-function' => [ + 'function checked(){function helper(n){return n>0?helper(n-1):5}return helper(3)}' + . 'JSON.stringify([checked(),checked()]);', + '[5,5]', + false, + true, + ]; + } + + #[DataProvider('cases')] + public function testSpeculativeFallbackDoesNotReplayEffects(string $source, string $expected, bool $php, bool $vm): void + { + $engine = new Engine(); + self::assertSame($expected, $engine->eval($source)); + $function = $engine->getGlobalEnv()->get('checked'); + self::assertInstanceOf(JsFunction::class, $function); + if ($php) { + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + } else { + self::assertNull($function->phpCompiled); + self::assertSame($vm, $function->compiled !== null); + } + } +} diff --git a/tests/Unit/Bytecode/LoopCheckpointContractTest.php b/tests/Unit/Bytecode/LoopCheckpointContractTest.php index 69225f36..9a4b79e8 100644 --- a/tests/Unit/Bytecode/LoopCheckpointContractTest.php +++ b/tests/Unit/Bytecode/LoopCheckpointContractTest.php @@ -77,6 +77,11 @@ private function prepare(Engine $engine, string $tier, string $loop, string $bod if ($tier === 'ast') { $engine->setExecutionBudget(10); } + $helper = ''; + if (str_contains($body, 'expireBudget();')) { + $helper = 'function expireLocal() { expireBudget(); } '; + $body = str_replace('expireBudget();', 'expireLocal();', $body); + } $statement = match ($loop) { 'for' => 'for (; count < amount;) {' . $body . '}', 'while' => 'while (count < amount) {' . $body . '}', @@ -85,7 +90,7 @@ private function prepare(Engine $engine, string $tier, string $loop, string $bod if ($tier === 'bytecode') { $statement = 'try {' . $statement . '} finally {}'; } - $engine->eval('function probe(amount) { let count = 0; ' . $statement . ' return count; } probe(1);'); + $engine->eval('function probe(amount) { ' . $helper . 'let count = 0; ' . $statement . ' return count; } probe(1);'); $function = $engine->getGlobalEnv()->get('probe'); self::assertInstanceOf(JsFunction::class, $function); if ($tier === 'php') { diff --git a/tests/Unit/Bytecode/WhileCheckpointTest.php b/tests/Unit/Bytecode/WhileCheckpointTest.php index 65e16e4e..5ba7117a 100644 --- a/tests/Unit/Bytecode/WhileCheckpointTest.php +++ b/tests/Unit/Bytecode/WhileCheckpointTest.php @@ -112,19 +112,33 @@ public function testGeneratedPhpCountsOnlySuccessfulIterations(bool $continue): var conditions = 0; function condition(n) { conditions++; return n < 1 ? 1 : 0; } JS); - $engine->eval('function probe() { let n = 0; while (condition(n)) {' . $body . '} return n; } probe();'); + $engine->eval('function probe() { function condition(value) { conditions++; return value < 1 ? 1 : 0; } ' + . 'let n = 0; while (condition(n)) {' . $body . '} return n; } probe();'); $function = $engine->getGlobalEnv()->get('probe'); self::assertInstanceOf(JsFunction::class, $function); self::assertInstanceOf(\Closure::class, $function->phpCompiled); $engine->eval('conditions = 0'); $engine->setLimit('maxLoopIterations', 1); - self::assertSame(1.0, ($function->phpCompiled)([], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), [])->value); + $result = ($function->phpCompiled)( + [], + JsUndefined::instance(), + $function->getClosure(), + $engine->getInterpreter(), + $function->phpCompiledNodes, + ); + self::assertSame(1.0, $result->value); self::assertSame(2.0, $engine->getGlobalEnv()->get('conditions')->value); $engine->eval('conditions = 0'); $engine->setLimit('maxLoopIterations', 0); $this->expectException(InternalError::class); try { - ($function->phpCompiled)([], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), []); + ($function->phpCompiled)( + [], + JsUndefined::instance(), + $function->getClosure(), + $engine->getInterpreter(), + $function->phpCompiledNodes, + ); } finally { self::assertSame(1.0, $engine->getGlobalEnv()->get('conditions')->value); } @@ -150,14 +164,21 @@ public function testZeroLimitPermitsAnInitiallyFalseLoop(string $tier): void if ($tier === 'bytecode') { $loop = 'try {' . $loop . '} finally {}'; } - $engine->eval('function probe(n) {' . $loop . ' return n; } probe(1);'); + $engine->eval('function probe(n) { function condition(value) { conditions++; return value; } ' + . $loop . ' return n; } probe(1);'); $function = $engine->getGlobalEnv()->get('probe'); self::assertInstanceOf(JsFunction::class, $function); $engine->eval('conditions = 0'); $engine->setLimit('maxLoopIterations', 0); if ($tier === 'php') { self::assertInstanceOf(\Closure::class, $function->phpCompiled); - $result = ($function->phpCompiled)([JsNumber::of(0)], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), []); + $result = ($function->phpCompiled)( + [JsNumber::of(0)], + JsUndefined::instance(), + $function->getClosure(), + $engine->getInterpreter(), + $function->phpCompiledNodes, + ); self::assertSame(0.0, $result->value); } else { self::assertSame($tier === 'bytecode', $function->compiled !== null); @@ -175,14 +196,15 @@ public function testGeneratedPhpBudgetPrecedesTheIterationLimit(): void $engine->setExecutionBudget(-1); } }); - $engine->eval('function probe() { let n = 0; while (n < 2) { n++; expireBudget(); } return n; } probe();'); + $engine->eval('function probe() { function expireLocal() { expireBudget(); } ' + . 'let n = 0; while (n < 2) { n++; expireLocal(); } return n; } probe();'); $function = $engine->getGlobalEnv()->get('probe'); self::assertInstanceOf(JsFunction::class, $function); self::assertInstanceOf(\Closure::class, $function->phpCompiled); $engine->setLimit('maxLoopIterations', 1); $expire = true; $this->expectException(BudgetExceeded::class); - ($function->phpCompiled)([], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), []); + ($function->phpCompiled)([], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), $function->phpCompiledNodes); } public function testBudgetAbortUnwindsInlineFramesAndBypassesJsCatch(): void @@ -197,7 +219,7 @@ public function testBudgetAbortUnwindsInlineFramesAndBypassesJsCatch(): void self::assertSame(2, $engine->eval(<<<'JS' var iterations = 0, caught = false; function innerLoop() { let n = 0; while (n < 2) { n++; iterations++; expireBudget(); } return n; } -function middleLoop() { return innerLoop(); } +function middleLoop() { try { return innerLoop(); } finally {} } function outerLoop() { try { return middleLoop(); } catch (error) { caught = true; return -1; } } outerLoop(); JS)); diff --git a/tests/Unit/Runtime/ObjectLiteralRealmTest.php b/tests/Unit/Runtime/ObjectLiteralRealmTest.php index 32f1d96a..d3df0966 100644 --- a/tests/Unit/Runtime/ObjectLiteralRealmTest.php +++ b/tests/Unit/Runtime/ObjectLiteralRealmTest.php @@ -25,11 +25,13 @@ public function testForeignFunctionsAndConstructorsUseTheirOwnPrototype(bool $bu $foreign = new Engine(); $foreign->eval(<<<'JS' function foreignLiteral(callback) { return [{}, callback(), {}]; } -Object.prototype.markForeignLiteral = function () { this.observed = 31; }; +var foreignMarkCalls = 0; +Object.prototype.markForeignLiteral = function () { this.observed = 31; foreignMarkCalls++; }; function foreignPhpLiteral(value) { const object = {observed: 0, value: value}; + const result = object.value; object.markForeignLiteral(); - return object.observed; + return result; } class ForeignRecord { constructor() { this.value = {}; } } foreignLiteral(() => ({})); foreignPhpLiteral(1); new ForeignRecord(); @@ -55,28 +57,31 @@ function localStandard(value) { foreignPhpLiteral(value); return value; } function localNumeric(value) { return foreignPhpLiteral(value) + 0; } function localMethod(value) { const receiver = {value: value}; - return receiver.foreignMethod(value) + 0; + receiver.foreignMethod(value); + return value; } localLiteral(); JS); + $foreign->eval('foreignMarkCalls = 0'); for ($pass = 0; $pass < 3; $pass++) { - self::assertSame([true, true, true, true, true, true, 1, 31, 31, 0], $caller->eval(<<<'JS' + self::assertSame([true, true, true, true, true, true, 1, 1, 1, 0], $caller->eval(<<<'JS' var values = foreignLiteral(localLiteral); [Object.getPrototypeOf(values[0]) === foreignObjectPrototype, Object.getPrototypeOf(values[1]) === Object.prototype, Object.getPrototypeOf(values[2]) === foreignObjectPrototype, Object.getPrototypeOf(new ForeignRecord().value) === foreignObjectPrototype, - foreignPhpLiteral(1) === 31, + foreignPhpLiteral(1) === 1, Object.getPrototypeOf(localLiteral()) === Object.prototype, localStandard(1), localNumeric(1), localMethod(1), wrongRealmCalls]; JS)); + self::assertSame(($pass + 1) * 4, $foreign->eval('foreignMarkCalls')); } $phpFunction = $foreign->getGlobalEnv()->get('foreignPhpLiteral'); self::assertInstanceOf(JsFunction::class, $phpFunction); self::assertInstanceOf(\Closure::class, $phpFunction->phpCompiled); self::assertInstanceOf(\Closure::class, $phpFunction->phpCompiledNumeric); $phpFunction->phpCompiledNumeric = null; - self::assertSame([31, 0], $caller->eval('[localNumeric(1), wrongRealmCalls]')); + self::assertSame([1, 0], $caller->eval('[localNumeric(1), wrongRealmCalls]')); if (!$budgeted) { foreach (['localStandard', 'localNumeric', 'localMethod'] as $name) { $wrapper = $caller->getGlobalEnv()->get($name); From 3e3cda74016b309e8c2c55321118566b8a5928c9 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 05:00:38 +0200 Subject: [PATCH 72/99] Store string iterator state in private slots --- src/BuiltIn/String/StringIteration.php | 87 ++---- src/BuiltIn/StringPrototype.php | 7 +- .../Parts/Helpers/IteratorProtocol.php | 6 +- src/Value/JsStringIterator.php | 60 ++++ .../BuiltIn/StringIteratorStorageTest.php | 124 ++++++++ .../fixtures/string-iterator-storage.js | 73 +++++ .../fixtures/string-iterator-storage.json | 268 ++++++++++++++++++ 7 files changed, 550 insertions(+), 75 deletions(-) create mode 100644 src/Value/JsStringIterator.php create mode 100644 tests/Unit/BuiltIn/StringIteratorStorageTest.php create mode 100644 tests/Unit/BuiltIn/fixtures/string-iterator-storage.js create mode 100644 tests/Unit/BuiltIn/fixtures/string-iterator-storage.json diff --git a/src/BuiltIn/String/StringIteration.php b/src/BuiltIn/String/StringIteration.php index c307c553..ab96db1c 100644 --- a/src/BuiltIn/String/StringIteration.php +++ b/src/BuiltIn/String/StringIteration.php @@ -46,48 +46,21 @@ public static function getStringIteratorPrototype(?JsObject $iteratorPrototype = $proto = new JsObject($iteratorPrototype); $nextFn = JsFunction::fromCallable('next', function (JsValue $this_, array $args): JsValue { - if (!$this_ instanceof JsObject) { + if (!$this_ instanceof \Phasis\Value\JsStringIterator) { throw new \Phasis\Exceptions\TypeError( 'Method String Iterator.prototype.next called on incompatible receiver', ); } - $slotDesc = $this_->getOwnPropertyDescriptor('[[StringIteratorData]]'); - if ($slotDesc === null) { - throw new \Phasis\Exceptions\TypeError( - 'Method String Iterator.prototype.next called on incompatible receiver', - ); - } - $data = $slotDesc->value; - if (!$data instanceof JsObject) { - $result = new JsObject(); - $result->set('value', JsUndefined::instance()); - $result->set('done', new JsBoolean(true)); - return $result; - } - $charsVal = $data->get('chars'); - $indexVal = $data->get('index'); - $totalVal = $data->get('total'); - $index = ($indexVal instanceof JsNumber) ? (int) $indexVal->value : 0; - $total = ($totalVal instanceof JsNumber) ? (int) $totalVal->value : 0; - - $result = new JsObject(); - if ($index < $total) { - $char = $charsVal instanceof JsObject ? $charsVal->get((string) $index) : JsUndefined::instance(); - $data->set('index', JsNumber::of((float) ($index + 1))); - $result->set('value', $char); - $result->set('done', new JsBoolean(false)); - } else { - $this_->defineOwnProperty( - '[[StringIteratorData]]', - PropertyDescriptor::data(JsUndefined::instance(), false, false, false), - ); - $result->set('value', JsUndefined::instance()); - $result->set('done', new JsBoolean(true)); - } + $done = false; + $value = $this_->nextValue($done); + $result = \Phasis\Engine::getCurrentInterpreter()?->vmNewObject() ?? new JsObject(); + $result->defineOwnDataPropertyFast('value', $value); + $result->defineOwnDataPropertyFast('done', JsBoolean::of($done)); return $result; }, 0); $nextFn->setNonConstructable(); $proto->defineOwnProperty('next', PropertyDescriptor::data($nextFn, true, false, true)); + $proto->setInternalProperty('StringIteratorNext', $nextFn); // Symbol.toStringTag = "String Iterator". $proto->definePropertyBySymbol( @@ -105,45 +78,17 @@ public static function getStringIteratorPrototype(?JsObject $iteratorPrototype = * Per spec 22.1.5.2.1: iteration yields code points (combining surrogate * pairs), but lone surrogates are yielded individually. */ - public static function createStringIterator(JsString $str): JsObject + public static function createStringIterator(JsString $str, ?JsObject $prototype = null): JsObject { - $proto = self::$stringIteratorPrototype; - $iterator = new JsObject($proto); - - // Build character list using UTF-16 code units, combining valid - // surrogate pairs into single code points. - $chars = []; - $u16 = $str->utf16LE(); - $u16Len = (int) (strlen($u16) / 2); - $i = 0; - while ($i < $u16Len) { - $cu = ord($u16[$i * 2]) | (ord($u16[$i * 2 + 1]) << 8); - if ($cu >= 0xD800 && $cu <= 0xDBFF && $i + 1 < $u16Len) { - $next = ord($u16[($i + 1) * 2]) | (ord($u16[($i + 1) * 2 + 1]) << 8); - if ($next >= 0xDC00 && $next <= 0xDFFF) { - // Valid surrogate pair: combine into a single code point. - $cp = ($cu - 0xD800) * 0x400 + ($next - 0xDC00) + 0x10000; - $chars[] = new JsString(mb_chr($cp, 'UTF-8')); - $i += 2; - continue; - } - } - // Lone surrogate or BMP character. - $chars[] = new JsString(JsString::utf16CodeUnitToUtf8($cu)); - $i++; + if ($prototype === null) { + $intrinsic = \Phasis\Engine::getCurrentInterpreter()?->getGlobalEnv()->getIntrinsic('StringIteratorPrototype'); + $prototype = $intrinsic instanceof JsObject ? $intrinsic : self::$stringIteratorPrototype; } - $charsArr = JsArray::fromArray($chars); - - $data = new JsObject(); - $data->set('chars', $charsArr); - $data->set('index', JsNumber::of(0.0)); - $data->set('total', JsNumber::of((float) count($chars))); - $iterator->defineOwnProperty( - '[[StringIteratorData]]', - PropertyDescriptor::data($data, false, false, false), - ); - - return $iterator; + $next = $prototype?->getInternalProperty('StringIteratorNext'); + if (!$prototype instanceof JsObject || !$next instanceof JsFunction) { + throw new \LogicException('String iterator intrinsic is missing'); + } + return new \Phasis\Value\JsStringIterator($str, $next, $prototype); } private static function charAt(): \Closure diff --git a/src/BuiltIn/StringPrototype.php b/src/BuiltIn/StringPrototype.php index 24a67d16..3659a05f 100644 --- a/src/BuiltIn/StringPrototype.php +++ b/src/BuiltIn/StringPrototype.php @@ -38,9 +38,10 @@ public static function install(Environment $env): void $iteratorPrototype = $env->has('__IteratorPrototype__') ? $env->get('__IteratorPrototype__') : null; - self::getStringIteratorPrototype( + $stringIteratorPrototype = self::getStringIteratorPrototype( $iteratorPrototype instanceof JsObject ? $iteratorPrototype : null, ); + $env->setIntrinsic('StringIteratorPrototype', $stringIteratorPrototype); $proto = new JsObject(); @@ -222,7 +223,7 @@ public static function install(Environment $env): void // String.prototype[Symbol.iterator] per spec 22.1.3.34. $iterSym = SymbolConstructor::iterator(); - $iterFn = JsFunction::fromCallable('[Symbol.iterator]', function (JsValue $this_): JsValue { + $iterFn = JsFunction::fromCallable('[Symbol.iterator]', function (JsValue $this_) use ($stringIteratorPrototype): JsValue { // RequireObjectCoercible(this value), then ToString. if ($this_ instanceof JsNull || $this_ instanceof JsUndefined) { throw new \Phasis\Exceptions\TypeError( @@ -230,7 +231,7 @@ public static function install(Environment $env): void ); } $str = $this_ instanceof JsString ? $this_ : new JsString(TypeConversion::toString($this_)); - return self::createStringIterator($str); + return self::createStringIterator($str, $stringIteratorPrototype); }, 0); $proto->definePropertyBySymbol( $iterSym, diff --git a/src/Runtime/Parts/Helpers/IteratorProtocol.php b/src/Runtime/Parts/Helpers/IteratorProtocol.php index c3dd9f29..273540eb 100644 --- a/src/Runtime/Parts/Helpers/IteratorProtocol.php +++ b/src/Runtime/Parts/Helpers/IteratorProtocol.php @@ -210,7 +210,11 @@ private function iteratorNext(JsObject $iterator, JsValue $nextMethod, bool &$do if ($done) { return JsUndefined::instance(); } - if ($iterator instanceof \Phasis\Value\JsArrayIterator && $iterator->hasIntrinsicNext($nextMethod)) { + if ( + ($iterator instanceof \Phasis\Value\JsArrayIterator + || ($iterator instanceof \Phasis\Value\JsStringIterator && $this->budget === null)) + && $iterator->hasIntrinsicNext($nextMethod) + ) { try { $value = $iterator->nextValue($done); return $readValue ? $value : JsUndefined::instance(); diff --git a/src/Value/JsStringIterator.php b/src/Value/JsStringIterator.php new file mode 100644 index 00000000..dc6beed2 --- /dev/null +++ b/src/Value/JsStringIterator.php @@ -0,0 +1,60 @@ +units = $string?->utf16LE(); + } + + /** Whether the cached method can advance without creating a result object. */ + public function hasIntrinsicNext(JsValue $method): bool + { + return $method === $this->intrinsicNext + && ($this->intrinsicNext->realm === null || $this->intrinsicNext->realm === \Phasis\Engine::getCurrentRealm()); + } + + /** Advance by one code point, retaining individual unpaired surrogates. */ + public function nextValue(bool &$done): JsValue + { + $string = $this->string; + if ($string === null) { + $done = true; + return JsUndefined::instance(); + } + $units = $this->units ?? ''; + $offset = $this->nextIndex * 2; + $length = strlen($units); + if ($offset >= $length) { + $this->string = null; + $this->units = null; + $done = true; + return JsUndefined::instance(); + } + $first = ord($units[$offset]) | (ord($units[$offset + 1]) << 8); + if ($first >= 0xD800 && $first <= 0xDBFF && $offset + 3 < $length) { + $second = ord($units[$offset + 2]) | (ord($units[$offset + 3]) << 8); + if ($second >= 0xDC00 && $second <= 0xDFFF) { + $this->nextIndex += 2; + $done = false; + return new JsString(mb_chr(($first - 0xD800) * 0x400 + ($second - 0xDC00) + 0x10000, 'UTF-8')); + } + } + $this->nextIndex++; + $done = false; + return new JsString(JsString::utf16CodeUnitToUtf8($first)); + } +} diff --git a/tests/Unit/BuiltIn/StringIteratorStorageTest.php b/tests/Unit/BuiltIn/StringIteratorStorageTest.php new file mode 100644 index 00000000..f6d633a1 --- /dev/null +++ b/tests/Unit/BuiltIn/StringIteratorStorageTest.php @@ -0,0 +1,124 @@ +setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/string-iterator-storage.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/string-iterator-storage.json', + $engine->eval('JSON.stringify(stringIteratorStorage)'), + ); + } + } + + public function testResultPropertiesBypassInheritedSetters(): void + { + $engine = new Engine(); + self::assertSame('["x",false,0,["value","done"]]', $engine->eval(<<<'JS' +(() => { + let calls = 0; + Object.defineProperty(Object.prototype, 'value', { __proto__: null, configurable: true, set() { calls++; } }); + Object.defineProperty(Object.prototype, 'done', { __proto__: null, configurable: true, set() { calls++; } }); + const result = 'x'[Symbol.iterator]().next(); + delete Object.prototype.value; + delete Object.prototype.done; + return JSON.stringify([result.value, result.done, calls, Object.keys(result)]); +})() +JS)); + } + + public function testForeignFactoriesAndNextMethodsKeepTheirRealm(): void + { + $foreign = new Engine(); + $foreign->eval(<<<'JS' +var foreignFactory = String.prototype[Symbol.iterator]; +var foreignIteratorPrototype = Object.getPrototypeOf(''[Symbol.iterator]()); +var foreignNext = foreignIteratorPrototype.next; +var foreignObjectPrototype = Object.prototype; +JS); + $caller = new Engine(); + self::assertTrue($foreign->eval("Object.getPrototypeOf('x'[Symbol.iterator]().next()) === Object.prototype")); + foreach (['foreignFactory', 'foreignIteratorPrototype', 'foreignNext', 'foreignObjectPrototype'] as $name) { + $caller->getGlobalEnv()->defineVar($name, $foreign->getGlobalEnv()->get($name)); + } + for ($pass = 0; $pass < 3; $pass++) { + self::assertSame('[true,true,true,"x","y"]', $caller->eval(<<<'JS' +(() => { + const iterator = foreignFactory.call('xy'); + const first = iterator.next(); + const second = foreignNext.call(iterator); + const local = foreignNext.call('z'[Symbol.iterator]()); + return JSON.stringify([Object.getPrototypeOf(iterator) === foreignIteratorPrototype, + Object.getPrototypeOf(first) === foreignObjectPrototype, + Object.getPrototypeOf(local) === foreignObjectPrototype, first.value, second.value]); +})() +JS)); + } + } + + public function testExhaustedIteratorReleasesItsSource(): void + { + $engine = new Engine(); + $prototype = $engine->getGlobalEnv()->getIntrinsic('StringIteratorPrototype'); + self::assertInstanceOf(JsObject::class, $prototype); + $next = $prototype->getInternalProperty('StringIteratorNext'); + self::assertInstanceOf(JsFunction::class, $next); + $string = new JsString('x'); + $reference = \WeakReference::create($string); + $iterator = StringPrototype::createStringIterator($string, $prototype); + self::assertInstanceOf(JsStringIterator::class, $iterator); + unset($string); + $done = false; + self::assertSame('x', $iterator->nextValue($done)->value); + self::assertFalse($done); + self::assertNotNull($reference->get()); + $iterator->nextValue($done); + self::assertTrue($done); + self::assertNull($reference->get()); + $iterator->nextValue($done); + self::assertTrue($done); + } + + public function testHostStringConversionRunsOnceWhenTheIteratorIsCreated(): void + { + $engine = new Engine(); + $prototype = $engine->getGlobalEnv()->getIntrinsic('StringIteratorPrototype'); + self::assertInstanceOf(JsObject::class, $prototype); + $string = new class ('ab') extends JsString { + public int $calls = 0; + + public function utf16LE(): string + { + $this->calls++; + return parent::utf16LE(); + } + }; + $iterator = StringPrototype::createStringIterator($string, $prototype); + self::assertInstanceOf(JsStringIterator::class, $iterator); + self::assertSame(1, $string->calls); + $done = false; + self::assertSame('a', $iterator->nextValue($done)->value); + self::assertSame('b', $iterator->nextValue($done)->value); + $iterator->nextValue($done); + self::assertTrue($done); + self::assertSame(1, $string->calls); + } +} diff --git a/tests/Unit/BuiltIn/fixtures/string-iterator-storage.js b/tests/Unit/BuiltIn/fixtures/string-iterator-storage.js new file mode 100644 index 00000000..5e637fa9 --- /dev/null +++ b/tests/Unit/BuiltIn/fixtures/string-iterator-storage.js @@ -0,0 +1,73 @@ +var stringIteratorStorage = (() => { + const units = value => { + const result = []; + for (let i = 0; i < value.length; i++) result.push(value.charCodeAt(i)); + return result; + }; + function spread(value) { return [...value].map(units); } + function astSpread(value) { with ({}) {} return [...value].map(units); } + function collect(value) { const result = []; for (const item of value) result.push(units(item)); return result; } + const result = []; + for (const value of ['', 'a', 'A\u{1F600}B', '\uD800', '\uDC00', '\uD800x\uDC00', '\uDBFF\uDFFF', '\uD800\uD800\uDC00']) { + result.push([spread(value), astSpread(value), collect(value)]); + } + const iterator = 'ab'[Symbol.iterator](); + const first = iterator.next(); + const second = iterator.next(); + const third = iterator.next(); + result.push([first.value, first.done, second.value, second.done, third.value === undefined, third.done, + iterator.next().done, first !== second, Object.keys(first), Object.getOwnPropertyDescriptor(first, 'value')]); + const prototype = Object.getPrototypeOf(iterator); + const next = prototype.next; + result.push([Object.getOwnPropertyNames(iterator), Object.prototype.toString.call(iterator)]); + for (const receiver of [null, undefined, {}, Object.create(prototype), new Proxy('x'[Symbol.iterator](), {})]) { + try { next.call(receiver); result.push('no error'); } catch (error) { result.push(error instanceof TypeError); } + } + const log = []; + const source = 'abcd'[Symbol.iterator](); + Object.defineProperty(source, 'next', { get() { log.push('next getter'); return next; }}); + source.return = function () { log.push('return'); return {}; }; + const iterable = { [Symbol.iterator]() { log.push('iterator'); return source; }}; + const target = { set value(value) { log.push(value); prototype.next = function () { throw new Error('new next'); }; }}; + function pair(value, target) { [target.value, target.value] = value; } + try { pair(iterable, target); } finally { prototype.next = next; } + result.push(log); + const originalIterator = String.prototype[Symbol.iterator]; + Object.defineProperty(String.prototype, Symbol.iterator, { configurable: true, get() { + log.push(typeof this + ':' + String(this)); + return new Proxy(function () { log.push('factory:' + typeof this); return originalIterator.call(this); }, { + apply(target, receiver, args) { log.push('apply'); return Reflect.apply(target, receiver, args); } + }); + }}); + try { result.push(spread('xy')); } finally { + Object.defineProperty(String.prototype, Symbol.iterator, { value: originalIterator, writable: true, configurable: true }); + } + result.push(log.slice()); + prototype.next = function () { log.push('custom next'); return { value: 'replacement', done: false }; }; + try { const [value] = 'x'; result.push(value); } finally { prototype.next = next; } + const proxyIterator = 'pq'[Symbol.iterator](); + const proxyLog = []; + proxyIterator.next = new Proxy(next, { apply(target, receiver, args) { + proxyLog.push(receiver === proxyIterator); + return Reflect.apply(target, receiver, args); + }}); + proxyIterator.return = function () { proxyLog.push('return'); return {}; }; + const [proxyValue] = { [Symbol.iterator]() { return proxyIterator; }}; + result.push([proxyValue, proxyLog]); + const failureLog = []; + const failing = 'x'[Symbol.iterator](); + failing.next = function () { failureLog.push('next'); throw new Error('step'); }; + failing.return = function () { failureLog.push('return'); return {}; }; + try { spread({ [Symbol.iterator]() { return failing; }}); } catch (error) { failureLog.push(error.message); } + result.push(failureLog); + const coercionLog = []; + const sourceObject = { [Symbol.toPrimitive](hint) { coercionLog.push(hint); return 'A\u{1F600}'; }}; + const coerced = originalIterator.call(sourceObject); + sourceObject[Symbol.toPrimitive] = () => { throw new Error('coercion repeated'); }; + result.push([units(coerced.next().value), units(coerced.next().value), coerced.next().done, coercionLog]); + const frozen = Object.freeze('rs'[Symbol.iterator]()); + Object.setPrototypeOf(frozen, Object.getPrototypeOf(frozen)); + result.push([next.call(frozen).value, next.call(frozen).value, next.call(frozen).done]); + return result; +})(); +if (typeof process !== 'undefined') process.stdout.write(JSON.stringify(stringIteratorStorage)); diff --git a/tests/Unit/BuiltIn/fixtures/string-iterator-storage.json b/tests/Unit/BuiltIn/fixtures/string-iterator-storage.json new file mode 100644 index 00000000..f8970077 --- /dev/null +++ b/tests/Unit/BuiltIn/fixtures/string-iterator-storage.json @@ -0,0 +1,268 @@ +[ + [ + [], + [], + [] + ], + [ + [ + [ + 97 + ] + ], + [ + [ + 97 + ] + ], + [ + [ + 97 + ] + ] + ], + [ + [ + [ + 65 + ], + [ + 55357, + 56832 + ], + [ + 66 + ] + ], + [ + [ + 65 + ], + [ + 55357, + 56832 + ], + [ + 66 + ] + ], + [ + [ + 65 + ], + [ + 55357, + 56832 + ], + [ + 66 + ] + ] + ], + [ + [ + [ + 55296 + ] + ], + [ + [ + 55296 + ] + ], + [ + [ + 55296 + ] + ] + ], + [ + [ + [ + 56320 + ] + ], + [ + [ + 56320 + ] + ], + [ + [ + 56320 + ] + ] + ], + [ + [ + [ + 55296 + ], + [ + 120 + ], + [ + 56320 + ] + ], + [ + [ + 55296 + ], + [ + 120 + ], + [ + 56320 + ] + ], + [ + [ + 55296 + ], + [ + 120 + ], + [ + 56320 + ] + ] + ], + [ + [ + [ + 56319, + 57343 + ] + ], + [ + [ + 56319, + 57343 + ] + ], + [ + [ + 56319, + 57343 + ] + ] + ], + [ + [ + [ + 55296 + ], + [ + 55296, + 56320 + ] + ], + [ + [ + 55296 + ], + [ + 55296, + 56320 + ] + ], + [ + [ + 55296 + ], + [ + 55296, + 56320 + ] + ] + ], + [ + "a", + false, + "b", + false, + true, + true, + true, + true, + [ + "value", + "done" + ], + { + "value": "a", + "writable": true, + "enumerable": true, + "configurable": true + } + ], + [ + [], + "[object String Iterator]" + ], + true, + true, + true, + true, + true, + [ + "iterator", + "next getter", + "a", + "b", + "return", + "object:xy", + "apply", + "factory:object", + "custom next" + ], + [ + [ + 120 + ], + [ + 121 + ] + ], + [ + "iterator", + "next getter", + "a", + "b", + "return", + "object:xy", + "apply", + "factory:object" + ], + "replacement", + [ + "p", + [ + true, + "return" + ] + ], + [ + "next", + "step" + ], + [ + [ + 65 + ], + [ + 55357, + 56832 + ], + true, + [ + "string" + ] + ], + [ + "r", + "s", + true + ] +] From d8c51626b214e6c47a4e8d8ed64cb563f9055869 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 05:02:57 +0200 Subject: [PATCH 73/99] Match JavaScript number truthiness in generated PHP --- src/Bytecode/Parts/JsToPhpEmitExpression.php | 34 +++++- src/Bytecode/Parts/JsToPhpEmitStatement.php | 4 +- src/Bytecode/Parts/JsToPhpLoopRegions.php | 2 +- tests/Unit/Bytecode/NumericTruthinessTest.php | 112 ++++++++++++++++++ 4 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 tests/Unit/Bytecode/NumericTruthinessTest.php diff --git a/src/Bytecode/Parts/JsToPhpEmitExpression.php b/src/Bytecode/Parts/JsToPhpEmitExpression.php index 6a2ba609..8ace0960 100644 --- a/src/Bytecode/Parts/JsToPhpEmitExpression.php +++ b/src/Bytecode/Parts/JsToPhpEmitExpression.php @@ -167,6 +167,28 @@ private function inferExpressionType(Node $node): string return 'unknown'; } + private function scalarTruthiness(string $value, string $type): string + { + return match ($type) { + 'numeric' => '(' . $value . ' != 0.0 && !is_nan(' . $value . '))', + 'boolean' => $value, + default => throw new Bailout('unknown scalar truthiness'), + }; + } + + /** @phpstan-impure */ + private function emitScalarCondition(Node $node): string + { + $value = $this->emitExpression($node); + $type = $this->inferExpressionType($node); + if ($type === 'numeric') { + $temporary = $this->newTemp('truthy'); + $this->pendingStatements[] = $temporary . ' = ' . $value . ';'; + $value = $temporary; + } + return $this->scalarTruthiness($value, $type); + } + /** @phpstan-impure */ private function emitExpression(Node $node): string { @@ -267,10 +289,11 @@ private function emitExpression(Node $node): string $rightBranch = $this->captureBranch($node->right); $temp = $this->newTemp('lv'); $this->pendingStatements[] = $temp . ' = ' . $l . ';'; + $truthy = $this->scalarTruthiness($temp, $this->inferExpressionType($node->left)); if ($node->operator === '&&') { - $this->pendingStatements[] = 'if (' . $temp . ') {'; + $this->pendingStatements[] = 'if (' . $truthy . ') {'; } elseif ($node->operator === '||') { - $this->pendingStatements[] = 'if (!(' . $temp . ')) {'; + $this->pendingStatements[] = 'if (!(' . $truthy . ')) {'; } else { throw new Bailout('logical ' . $node->operator); } @@ -285,14 +308,15 @@ private function emitExpression(Node $node): string throw new Bailout('postfix unary'); } if ($node instanceof UnaryExpression) { + if ($node->operator === '!') { + return '(!' . $this->emitScalarCondition($node->argument) . ')'; + } $arg = $this->emitExpression($node->argument); switch ($node->operator) { case '-': return '(-' . $arg . ')'; case '+': return '(+' . $arg . ')'; - case '!': - return '(!' . $arg . ')'; default: throw new Bailout('unary ' . $node->operator); } @@ -462,7 +486,7 @@ private function emitExpression(Node $node): string // pendings unconditionally — fatal for recursion shapes // like `n < 2 ? n : fib(n-1)+fib(n-2)`. Lower to a temp + // if/else so each branch's pendings run only on its arm. - $test = $this->emitExpression($node->test); + $test = $this->emitScalarCondition($node->test); $consBranch = $this->captureBranch($node->consequent); $altBranch = $this->captureBranch($node->alternate); // Fast path: when neither branch lifted any statements diff --git a/src/Bytecode/Parts/JsToPhpEmitStatement.php b/src/Bytecode/Parts/JsToPhpEmitStatement.php index 2b433e1f..5ca09ed1 100644 --- a/src/Bytecode/Parts/JsToPhpEmitStatement.php +++ b/src/Bytecode/Parts/JsToPhpEmitStatement.php @@ -279,7 +279,7 @@ private function emitStatement(Node $node): void return; } if ($node instanceof IfStatement) { - $cond = $this->emitExpression($node->test); + $cond = $this->emitScalarCondition($node->test); $this->flushPending(); $this->emitLine('if (' . $cond . ') {'); $this->indentLevel++; @@ -561,7 +561,7 @@ private function emitLoopCondition(Node $condition): string $value = $this->emitCallCore($condition); return '\\Phasis\\Spec\\TypeConversion::toBoolean(' . $value . ')'; } - return $this->emitExpression($condition); + return $this->emitScalarCondition($condition); } private function flushPending(): void diff --git a/src/Bytecode/Parts/JsToPhpLoopRegions.php b/src/Bytecode/Parts/JsToPhpLoopRegions.php index 138cea70..a13e6aa7 100644 --- a/src/Bytecode/Parts/JsToPhpLoopRegions.php +++ b/src/Bytecode/Parts/JsToPhpLoopRegions.php @@ -43,7 +43,7 @@ public static function compileLoopRegion(StringLoopRegionPlan $plan, int $loopId $compiler->emitLine('while (true) {'); ++$compiler->indentLevel; $compiler->emitLoopBudgetCheck(); - $condition = $compiler->emitExpression($plan->loop->test); + $condition = $compiler->emitScalarCondition($plan->loop->test); $compiler->flushPending(); $compiler->emitLine('if (!(' . $condition . ')) { return ' . count($plan->exits) . '.0; }'); $compiler->emitLoopTick('$_region_iterations'); diff --git a/tests/Unit/Bytecode/NumericTruthinessTest.php b/tests/Unit/Bytecode/NumericTruthinessTest.php new file mode 100644 index 00000000..60bc352e --- /dev/null +++ b/tests/Unit/Bytecode/NumericTruthinessTest.php @@ -0,0 +1,112 @@ + */ + public static function numbers(): iterable + { + foreach (['NaN', '0', '-0'] as $value) { + yield $value => [$value, false]; + } + foreach (['1', '-1', 'Infinity', '-Infinity', '5e-324', '-5e-324', '1e100'] as $value) { + yield $value => [$value, true]; + } + } + + #[DataProvider('numbers')] + public function testCompiledConditionsUseNumberToBooleanExactlyOnce(string $value, bool $truth): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE); + $boolean = $truth ? 'true' : 'false'; + $number = $truth ? '1' : '0'; + $onceAnd = $truth ? 22 : ($value === 'NaN' ? 101 : 1); + $checks = 'var value = ' . $value . '; [' + . 'scalarNot(value) === !' . $boolean . ',' + . 'scalarDoubleNot(value) === ' . $boolean . ',' + . 'scalarIf(value) === ' . $number . ',' + . 'scalarConditional(value) === ' . $number . ',' + . 'Object.is(scalarAnd(value), ' . ($truth ? '7' : 'value') . '),' + . 'Object.is(scalarOr(value), ' . ($truth ? 'value' : '7') . '),' + . 'scalarWhile(value) === ' . $number . ',' + . 'scalarFor(value) === ' . $number . ',' + . 'scalarDoWhile(value) === ' . ($truth ? '2' : '1') . ',' + . 'scalarOnceConditional(value) === ' . ($truth ? '11' : '10') . ',' + . 'scalarOnceNot(value) === ' . ($truth ? '10' : '11') . ',' + . 'scalarOnceAnd(value) === ' . $onceAnd . ',' + . 'scalarOnceOr(value) === ' . ($truth ? '1' : '2') . ']'; + for ($pass = 0; $pass < 2; $pass++) { + self::assertSame(array_fill(0, 13, true), $engine->eval($checks)); + } + foreach ($engine->getGlobalEnv()->allBindings() as $name => $function) { + if (str_starts_with($name, 'scalar')) { + self::assertInstanceOf(JsFunction::class, $function); + self::assertInstanceOf(\Closure::class, $function->phpCompiled, $name); + } + } + } + + public function testProvenBooleanScannerAndRegionConditionsRemainCompiled(): void + { + $engine = new Engine(); + self::assertSame([1, [0, 1]], $engine->eval(<<<'JS' +function prime(text) { return [text.charCodeAt(0)]; } +prime('x'); +function scanner(text, start) { + let count = 0; + while (start > 0) { count++; start = 0; } + return count + text.length; +} +function region(text, start) { + let count = 0; + while (start > 0) { + const code = text.charCodeAt(0); + count++; + start = 0; + } + return [count, text.length]; +} +[scanner('x', NaN), region('x', NaN)]; +JS)); + $scanner = $engine->getGlobalEnv()->get('scanner'); + self::assertInstanceOf(JsFunction::class, $scanner); + self::assertInstanceOf(\Closure::class, $scanner->phpCompiled); + $region = $engine->getGlobalEnv()->get('region'); + self::assertInstanceOf(JsFunction::class, $region); + self::assertNotNull($region->compiled); + self::assertCount(1, array_filter($region->compiled->loopRegions)); + } +} From 737dfe33e05a3d153216332a95b3e1174f72805a Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 05:07:28 +0200 Subject: [PATCH 74/99] Read ordinary computed data properties without coercion dispatch --- src/Bytecode/VM.php | 19 ++++ tests/Unit/Bytecode/ComputedDataReadTest.php | 40 +++++++++ .../Bytecode/fixtures/computed-data-reads.js | 51 +++++++++++ .../fixtures/computed-data-reads.json | 86 +++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 tests/Unit/Bytecode/ComputedDataReadTest.php create mode 100644 tests/Unit/Bytecode/fixtures/computed-data-reads.js create mode 100644 tests/Unit/Bytecode/fixtures/computed-data-reads.json diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index 8f3f1b5e..caa50e41 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -2604,6 +2604,25 @@ public function execute( break; } } + // Primitive keys require no coercion. Read live own + // data only; accessors, prototypes and exotic receivers + // retain the ordinary computed-property path. + if (get_class($obj) === JsObject::class) { + $value = null; + if (get_class($key) === JsString::class) { + $value = $obj->properties->dataSlots[$key->value] ?? null; + } elseif (get_class($key) === \Phasis\Value\JsSymbol::class) { + $descriptor = $obj->getSymbolPropertyDescriptor($key); + if ($descriptor !== null && $descriptor->isDataDescriptor()) { + $value = $descriptor->value; + } + } + if ($value !== null) { + $stack[$sp++] = $value; + $pc++; + break; + } + } $stack[$sp++] = $this->lookupComputed($obj, $key); $pc++; break; diff --git a/tests/Unit/Bytecode/ComputedDataReadTest.php b/tests/Unit/Bytecode/ComputedDataReadTest.php new file mode 100644 index 00000000..76b749a5 --- /dev/null +++ b/tests/Unit/Bytecode/ComputedDataReadTest.php @@ -0,0 +1,40 @@ + */ + public static function executionModes(): iterable + { + yield 'VM' => [false]; + yield 'AST' => [true]; + } + + #[DataProvider('executionModes')] + public function testLiveDataAndFallbackEffectsMatchNode(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->eval((string) file_get_contents(__DIR__ . '/fixtures/computed-data-reads.js')); + self::assertJsonStringEqualsJsonFile( + __DIR__ . '/fixtures/computed-data-reads.json', + $engine->eval('JSON.stringify(computedDataReads)'), + ); + if (!$budgeted) { + $function = $engine->getGlobalEnv()->get('readComputed'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + } + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } +} diff --git a/tests/Unit/Bytecode/fixtures/computed-data-reads.js b/tests/Unit/Bytecode/fixtures/computed-data-reads.js new file mode 100644 index 00000000..9d7b3214 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/computed-data-reads.js @@ -0,0 +1,51 @@ +var computedDataReads = []; +var readEvents = []; +function readComputed(object, key) { return object[key]; } +const key = Symbol('key'); +const object = {field: 1, [key]: 2}; +computedDataReads.push(['data', readComputed(object, 'field'), readComputed(object, key)]); +object.field = 3; +object[key] = 4; +computedDataReads.push(['writes', readComputed(object, 'field'), readComputed(object, key)]); +Object.defineProperty(object, 'field', {value: 5, writable: false}); +Object.defineProperty(object, key, {value: 6, writable: false}); +computedDataReads.push(['descriptors', readComputed(object, 'field'), readComputed(object, key)]); +Object.defineProperty(object, 'field', {get() {readEvents.push('own-string'); return 7;}}); +Object.defineProperty(object, key, {get() {readEvents.push('own-symbol'); return 8;}}); +computedDataReads.push(['accessors', readComputed(object, 'field'), readComputed(object, key)]); +delete object.field; +delete object[key]; +const prototype = { + get field() {readEvents.push('prototype-string'); return this.marker;}, + get [key]() {readEvents.push('prototype-symbol'); return this.marker + 1;}, +}; +object.marker = 9; +Object.setPrototypeOf(object, prototype); +computedDataReads.push(['prototype', readComputed(object, 'field'), readComputed(object, key)]); +const proxy = new Proxy({field: 11, [key]: 12}, { + get(target, property, receiver) { + readEvents.push(typeof property === 'symbol' ? 'proxy-symbol' : 'proxy-string'); + return Reflect.get(target, property, receiver); + }, +}); +computedDataReads.push(['proxy', readComputed(proxy, 'field'), readComputed(proxy, key)]); +const stringKey = {[Symbol.toPrimitive]() {readEvents.push('coerce-string'); return 'field';}}; +const symbolKey = {[Symbol.toPrimitive]() {readEvents.push('coerce-symbol'); return key;}}; +computedDataReads.push(['coercion', readComputed(proxy, stringKey), readComputed(proxy, symbolKey)]); +const inheritedProxy = Object.create(new Proxy({field: 18, [key]: 19}, { + get(target, property, receiver) { + readEvents.push(typeof property === 'symbol' ? 'inherited-proxy-symbol' : 'inherited-proxy-string'); + return Reflect.get(target, property, receiver); + }, +})); +computedDataReads.push(['inherited-proxy', readComputed(inheritedProxy, 'field'), readComputed(inheritedProxy, key)]); +let nullCoercions = 0, nullError = false; +try { readComputed(null, {[Symbol.toPrimitive]() {nullCoercions++; return 'field';}}); } +catch (error) { nullError = error instanceof TypeError; } +computedDataReads.push(['nullish-order', nullError, nullCoercions]); +const unusual = {length: 13, ['0']: 14, ['']: 15}; +computedDataReads.push(['keys', readComputed(unusual, 'length'), readComputed(unusual, 0), readComputed(unusual, '')]); +computedDataReads.push(['exotic', readComputed([16], 0), readComputed([16], 'length'), readComputed(new Uint8Array([17]), '0')]); +computedDataReads.push(['primitive', readComputed('abc', 'length'), readComputed('abc', '1')]); +computedDataReads.push(['missing', readComputed({}, key) === undefined, readComputed({}, 'missing') === undefined]); +computedDataReads.push(['events', readEvents]); diff --git a/tests/Unit/Bytecode/fixtures/computed-data-reads.json b/tests/Unit/Bytecode/fixtures/computed-data-reads.json new file mode 100644 index 00000000..18bf82d3 --- /dev/null +++ b/tests/Unit/Bytecode/fixtures/computed-data-reads.json @@ -0,0 +1,86 @@ +[ + [ + "data", + 1, + 2 + ], + [ + "writes", + 3, + 4 + ], + [ + "descriptors", + 5, + 6 + ], + [ + "accessors", + 7, + 8 + ], + [ + "prototype", + 9, + 10 + ], + [ + "proxy", + 11, + 12 + ], + [ + "coercion", + 11, + 12 + ], + [ + "inherited-proxy", + 18, + 19 + ], + [ + "nullish-order", + true, + 0 + ], + [ + "keys", + 13, + 14, + 15 + ], + [ + "exotic", + 16, + 1, + 17 + ], + [ + "primitive", + 3, + "b" + ], + [ + "missing", + true, + true + ], + [ + "events", + [ + "own-string", + "own-symbol", + "prototype-string", + "prototype-symbol", + "proxy-string", + "proxy-symbol", + "coerce-string", + "proxy-string", + "coerce-symbol", + "proxy-symbol", + "inherited-proxy-string", + "inherited-proxy-symbol" + ] + ] +] From 8d1d20a427fda62e958c549acdc023049194e6a7 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 05:10:49 +0200 Subject: [PATCH 75/99] Use byte offsets for native ASCII string operations --- src/BuiltIn/String/StringIteration.php | 8 +- src/BuiltIn/String/StringSearch.php | 13 +- tests/Unit/Runtime/NativeAsciiStringTest.php | 85 ++++ .../Runtime/fixtures/native-ascii-strings.cjs | 49 +++ .../fixtures/native-ascii-strings.json | 414 ++++++++++++++++++ 5 files changed, 564 insertions(+), 5 deletions(-) create mode 100644 tests/Unit/Runtime/NativeAsciiStringTest.php create mode 100644 tests/Unit/Runtime/fixtures/native-ascii-strings.cjs create mode 100644 tests/Unit/Runtime/fixtures/native-ascii-strings.json diff --git a/src/BuiltIn/String/StringIteration.php b/src/BuiltIn/String/StringIteration.php index ab96db1c..037651a2 100644 --- a/src/BuiltIn/String/StringIteration.php +++ b/src/BuiltIn/String/StringIteration.php @@ -131,8 +131,9 @@ private static function slice(): \Closure $str = self::extractString($this_); // Per spec, String.prototype.slice indices are UTF-16 code unit // offsets, not code point offsets, so work on the UTF-16LE form. - $u16 = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); - $len = (int) (strlen($u16) / 2); + $ascii = $this_ instanceof JsString && get_class($this_) === JsString::class && $this_->isAscii(); + $u16 = $ascii ? '' : ($this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str)); + $len = $ascii ? strlen($str) : (int) (strlen($u16) / 2); // Per spec 22.1.3.22: intStart = ToIntegerOrInfinity(start). $startArg = $args[0] ?? JsUndefined::instance(); @@ -165,6 +166,9 @@ private static function slice(): \Closure if ($from >= $to) { return new JsString(''); } + if ($ascii) { + return new JsString(substr($str, $from, $to - $from)); + } $sliceBytes = substr($u16, $from * 2, ($to - $from) * 2); return new JsString(JsString::utf16LEToUtf8($sliceBytes)); diff --git a/src/BuiltIn/String/StringSearch.php b/src/BuiltIn/String/StringSearch.php index f9e7cab4..b001c223 100644 --- a/src/BuiltIn/String/StringSearch.php +++ b/src/BuiltIn/String/StringSearch.php @@ -93,16 +93,19 @@ private static function indexOf(): \Closure return function (JsValue $this_, array $args): JsValue { $str = self::extractString($this_); $search = isset($args[0]) ? TypeConversion::toString($args[0]) : 'undefined'; + $ascii = $this_ instanceof JsString && get_class($this_) === JsString::class + && isset($args[0]) && $args[0] instanceof JsString && get_class($args[0]) === JsString::class + && $this_->isAscii() && $args[0]->isAscii(); // Per §22.1.3.9 String.prototype.indexOf: positions are UTF-16 // code unit offsets. Convert both haystack and needle to UTF-16LE // byte strings and search by byte, then divide by 2. Using // mb_strpos with UTF-8 counts codepoints which misaligns for // strings that contain surrogate pairs (chars above U+FFFF). - $hayU16 = $this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str); + $hayU16 = $ascii ? '' : ($this_ instanceof JsString ? $this_->utf16LE() : JsString::utf8ToUtf16LE($str)); $needle = $args[0] ?? null; - $needleU16 = $needle instanceof JsString ? $needle->utf16LE() : JsString::utf8ToUtf16LE($search); - $hayLen = strlen($hayU16) / 2; + $needleU16 = $ascii ? '' : ($needle instanceof JsString ? $needle->utf16LE() : JsString::utf8ToUtf16LE($search)); + $hayLen = $ascii ? strlen($str) : strlen($hayU16) / 2; $posFloat = isset($args[1]) ? TypeConversion::toIntegerOrInfinity($args[1]) @@ -118,6 +121,10 @@ private static function indexOf(): \Closure } return JsNumber::of(-1.0); } + if ($ascii) { + $offset = strpos($str, $search, $fromIndex); + return JsNumber::of($offset === false ? -1.0 : (float) $offset); + } // strpos over UTF-16LE bytes could in principle match at an // odd byte offset (misaligned with the code-unit grid) when a diff --git a/tests/Unit/Runtime/NativeAsciiStringTest.php b/tests/Unit/Runtime/NativeAsciiStringTest.php new file mode 100644 index 00000000..35358e70 --- /dev/null +++ b/tests/Unit/Runtime/NativeAsciiStringTest.php @@ -0,0 +1,85 @@ + */ + public static function executionModes(): iterable + { + yield 'VM' => [false]; + yield 'AST' => [true]; + } + + #[DataProvider('executionModes')] + public function testAsciiAndUtf16BoundariesAndCoercionsMatchNode(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->execFile(__DIR__ . '/fixtures/native-ascii-strings.cjs'); + $observations = $engine->eval('JSON.stringify(nativeAsciiObservations)'); + self::assertIsString($observations); + self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/native-ascii-strings.json', $observations); + if (!$budgeted) { + foreach (['nativeAsciiIndex', 'nativeAsciiSlice'] as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNotNull($function->compiled); + } + } + } + + public function testHostStringsKeepTheirUtf16HooksBeforeArgumentCoercions(): void + { + $engine = new Engine(); + $events = new \ArrayObject(); + $make = static fn (string $value, string $name): JsString => new class ($value, $name, $events) extends JsString { + public function __construct(string $value, private readonly string $name, private readonly \ArrayObject $events) + { + parent::__construct($value); + } + + public function isAscii(): bool + { + throw new \LogicException('Host string ASCII hooks must stay on the existing fallback.'); + } + + public function utf16LE(): string + { + $this->events->append($this->name . ':utf16'); + return parent::utf16LE(); + } + }; + $engine->getGlobalEnv()->defineVar('hostReceiver', $make('abc', 'receiver')); + $engine->getGlobalEnv()->defineVar('hostSearch', $make('b', 'search')); + $engine->setGlobal('recordCoercion', static function (string $name) use ($events): void { + $events->append($name); + }); + self::assertSame(1, $engine->eval(<<<'JS' +String.prototype.indexOf.call(hostReceiver, hostSearch, {valueOf() {recordCoercion('position'); return 1;}}); +JS)); + self::assertSame(['receiver:utf16', 'search:utf16', 'position'], $events->getArrayCopy()); + $events->exchangeArray([]); + self::assertSame(1, $engine->eval(<<<'JS' +'abc'.indexOf(hostSearch, {valueOf() {recordCoercion('position'); return 1;}}); +JS)); + self::assertSame(['search:utf16', 'position'], $events->getArrayCopy()); + $events->exchangeArray([]); + self::assertSame('b', $engine->eval(<<<'JS' +String.prototype.slice.call(hostReceiver, + {valueOf() {recordCoercion('start'); return 1;}}, + {valueOf() {recordCoercion('end'); return 2;}}); +JS)); + self::assertSame(['receiver:utf16', 'start', 'end'], $events->getArrayCopy()); + } +} diff --git a/tests/Unit/Runtime/fixtures/native-ascii-strings.cjs b/tests/Unit/Runtime/fixtures/native-ascii-strings.cjs new file mode 100644 index 00000000..cba89d8a --- /dev/null +++ b/tests/Unit/Runtime/fixtures/native-ascii-strings.cjs @@ -0,0 +1,49 @@ +var nativeAsciiObservations = []; +function nativeAsciiIndex(value, search, position) { return value.indexOf(search, position); } +function nativeAsciiSlice(value, start, end) { return value.slice(start, end); } +function nativeAsciiUnits(value) { + const units = []; + for (let i = 0; i < value.length; i++) units.push(value.charCodeAt(i)); + return units; +} +const positions = [-Infinity, -2.8, -0, 0, 1.9, 2, 99, Infinity, NaN, undefined]; +for (const pair of [['', ''], ['abcabc', 'bc'], ['abcabc', ''], ['a\0b', '\0'], + ['A\uD83D\uDE00B', '\uDE00'], ['A\uD83D\uDE00B', 'B'], ['\uD800x\uDC00', '\uD800'], ['éa', 'a']]) { + for (const position of positions) nativeAsciiObservations.push(nativeAsciiIndex(pair[0], pair[1], position)); +} +nativeAsciiObservations.push('undefined'.indexOf(), ''.indexOf()); +for (const value of ['', 'ab\0cd\x7f', 'A\uD83D\uDE00B', '\uD800x\uDC00', 'éa']) { + for (const start of [-Infinity, -2.8, -0, 1.2, 99, Infinity, NaN, undefined]) { + for (const end of [undefined, -Infinity, -1.2, 0, 2.8, 99, Infinity, NaN]) { + nativeAsciiObservations.push(nativeAsciiUnits(nativeAsciiSlice(value, start, end))); + } + } +} +let effects = []; +function coerced(label, value) { + return {[Symbol.toPrimitive](hint) {effects.push(label + ':' + hint); return value;}}; +} +let result = String.prototype.indexOf.call(coerced('receiver', 'abc'), coerced('search', 'b'), coerced('position', 1)); +nativeAsciiObservations.push(['index coercions', result, effects]); +effects = []; +result = nativeAsciiIndex('abc', 'b', coerced('position', 1)); +nativeAsciiObservations.push(['ASCII index coercion', result, effects]); +effects = []; +result = String.prototype.slice.call(coerced('receiver', 'abc'), coerced('start', 1), coerced('end', 2)); +nativeAsciiObservations.push(['slice coercions', nativeAsciiUnits(result), effects]); +effects = []; +result = nativeAsciiSlice('abc', coerced('start', 1), coerced('end', 2)); +nativeAsciiObservations.push(['ASCII slice coercions', nativeAsciiUnits(result), effects]); +for (const kind of ['index null', 'index symbol', 'index bigint', 'slice null', 'slice symbol', 'slice bigint']) { + effects = []; + let errorName = null; + try { + if (kind === 'index null') String.prototype.indexOf.call(null, coerced('search', 'a'), coerced('position', 0)); + if (kind === 'index symbol') nativeAsciiIndex('abc', Symbol(), coerced('position', 0)); + if (kind === 'index bigint') nativeAsciiIndex('abc', coerced('search', 'a'), 1n); + if (kind === 'slice null') String.prototype.slice.call(null, coerced('start', 0), coerced('end', 1)); + if (kind === 'slice symbol') nativeAsciiSlice('abc', Symbol(), coerced('end', 1)); + if (kind === 'slice bigint') nativeAsciiSlice('abc', coerced('start', 0), 1n); + } catch (error) {errorName = error.name;} + nativeAsciiObservations.push([kind, errorName, effects]); +} diff --git a/tests/Unit/Runtime/fixtures/native-ascii-strings.json b/tests/Unit/Runtime/fixtures/native-ascii-strings.json new file mode 100644 index 00000000..5016d9b1 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/native-ascii-strings.json @@ -0,0 +1,414 @@ +[ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 4, + -1, + -1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 6, + 6, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + -1, + -1, + -1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + -1, + -1, + 3, + 3, + 0, + 0, + 0, + 0, + -1, + -1, + -1, + -1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + -1, + -1, + -1, + 1, + 1, + 0, + -1, + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [97,98,0,99,100,127], + [], + [97,98,0,99,100], + [], + [97,98], + [97,98,0,99,100,127], + [97,98,0,99,100,127], + [], + [100,127], + [], + [100], + [], + [], + [100,127], + [100,127], + [], + [97,98,0,99,100,127], + [], + [97,98,0,99,100], + [], + [97,98], + [97,98,0,99,100,127], + [97,98,0,99,100,127], + [], + [98,0,99,100,127], + [], + [98,0,99,100], + [], + [98], + [98,0,99,100,127], + [98,0,99,100,127], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [97,98,0,99,100,127], + [], + [97,98,0,99,100], + [], + [97,98], + [97,98,0,99,100,127], + [97,98,0,99,100,127], + [], + [97,98,0,99,100,127], + [], + [97,98,0,99,100], + [], + [97,98], + [97,98,0,99,100,127], + [97,98,0,99,100,127], + [], + [65,55357,56832,66], + [], + [65,55357,56832], + [], + [65,55357], + [65,55357,56832,66], + [65,55357,56832,66], + [], + [56832,66], + [], + [56832], + [], + [], + [56832,66], + [56832,66], + [], + [65,55357,56832,66], + [], + [65,55357,56832], + [], + [65,55357], + [65,55357,56832,66], + [65,55357,56832,66], + [], + [55357,56832,66], + [], + [55357,56832], + [], + [55357], + [55357,56832,66], + [55357,56832,66], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [65,55357,56832,66], + [], + [65,55357,56832], + [], + [65,55357], + [65,55357,56832,66], + [65,55357,56832,66], + [], + [65,55357,56832,66], + [], + [65,55357,56832], + [], + [65,55357], + [65,55357,56832,66], + [65,55357,56832,66], + [], + [55296,120,56320], + [], + [55296,120], + [], + [55296,120], + [55296,120,56320], + [55296,120,56320], + [], + [120,56320], + [], + [120], + [], + [120], + [120,56320], + [120,56320], + [], + [55296,120,56320], + [], + [55296,120], + [], + [55296,120], + [55296,120,56320], + [55296,120,56320], + [], + [120,56320], + [], + [120], + [], + [120], + [120,56320], + [120,56320], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [55296,120,56320], + [], + [55296,120], + [], + [55296,120], + [55296,120,56320], + [55296,120,56320], + [], + [55296,120,56320], + [], + [55296,120], + [], + [55296,120], + [55296,120,56320], + [55296,120,56320], + [], + [233,97], + [], + [233], + [], + [233,97], + [233,97], + [233,97], + [], + [233,97], + [], + [233], + [], + [233,97], + [233,97], + [233,97], + [], + [233,97], + [], + [233], + [], + [233,97], + [233,97], + [233,97], + [], + [97], + [], + [], + [], + [97], + [97], + [97], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [], + [233,97], + [], + [233], + [], + [233,97], + [233,97], + [233,97], + [], + [233,97], + [], + [233], + [], + [233,97], + [233,97], + [233,97], + [], + ["index coercions",1,["receiver:string","search:string","position:number"]], + ["ASCII index coercion",1,["position:number"]], + ["slice coercions",[98],["receiver:string","start:number","end:number"]], + ["ASCII slice coercions",[98],["start:number","end:number"]], + ["index null","TypeError",[]], + ["index symbol","TypeError",[]], + ["index bigint","TypeError",["search:string"]], + ["slice null","TypeError",[]], + ["slice symbol","TypeError",[]], + ["slice bigint","TypeError",["start:number"]] +] From aec1e4fcb43a9478846a21a044c594f575e355a0 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 05:11:02 +0200 Subject: [PATCH 76/99] Document generated execution and byte-copy correctness fixes --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 764eed62..3e051498 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ - Symbol property writes preserve Proxy traps and receivers; typed-array copies clamp array-like lengths before checking destination bounds. - Array literals and built-in array results retain their realm's intrinsic prototype when the global Array constructor is replaced. - Compiled identifier updates and strict program assignments retain their original references through coercion and right-hand-side effects. +- Generated PHP preserves numeric truthiness and literal precision, evaluates operands once, and falls back before observable effects. +- Same-type typed-array copies preserve byte payloads and prototype-validation order; host byte views and inlined callbacks retain their defining realms. - Stream controllers, readers and writers retain their originating realm after VM context creation; pending Promise finalizers retain their registered async context. - Temporal calendar fields, arithmetic, rounding, parsing, timezone boundaries, and Intl formatting use consistent calendar data and option validation. - Module evaluation, source and typed imports, resource disposal, cross-realm intrinsics, numeric serialization, and compiled global bindings follow current language semantics. From b326f0d678eac1071d4db370d0b4fe4689966ee4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 24 Oct 2026 03:35:28 +0000 Subject: [PATCH 77/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 54 ++++++++-------- compat.json | 179 ++++++++++++++++++++++++++-------------------------- 2 files changed, 120 insertions(+), 113 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index d733588f..f68d86ad 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,19 +3,19 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-24T01:11:33+00:00` +- Snapshot time: `2026-10-24T03:35:26+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `ba525bc2` (dirty) +- Git: `feat/express-hono-compatibility` @ `aec1e4fc` (dirty) ## Summary | Pass | Fail | Skip | Blocked | Pending | Running | Attempted | Known | Total | Pass Rate | |---:|---:|---:|---:|---:|---:|---:|---:|---:|---:| -| 53616 | 0 | 0 | 0 | 0 | 0 | 53616 | 53616 | 53616 | 100.0% | +| 53615 | 1 | 0 | 0 | 0 | 0 | 53616 | 53616 | 53616 | 99.9% | ## Top-Level Areas @@ -26,7 +26,7 @@ Generated from a completed `test262` pass. Do not edit by hand. | harness | PASS | 116 | 0 | 0 | 0 | 0 | 0 | 100.0% | | intl402 | PASS | 3382 | 0 | 0 | 0 | 0 | 0 | 100.0% | | language | PASS | 23726 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| staging | PASS | 1483 | 0 | 0 | 0 | 0 | 0 | 100.0% | +| staging | PARTIAL | 1482 | 1 | 0 | 0 | 0 | 0 | 99.9% | ## Group Coverage @@ -190,34 +190,38 @@ Generated from a completed `test262` pass. Do not edit by hand. | staging/decorators | PASS | 3 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/explicit-resource-management | PASS | 53 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/set-methods | PASS | 3 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| staging/sm | PASS | 1406 | 0 | 0 | 0 | 0 | 0 | 100.0% | +| staging/sm | PARTIAL | 1405 | 1 | 0 | 0 | 0 | 0 | 99.9% | | staging/source-phase-imports | PASS | 2 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/top-level-await | PASS | 1 | 0 | 0 | 0 | 0 | 0 | 100.0% | +## Failing Tests + +1 individual failure paths and messages are recorded in [compat.json](compat.json) under `test262.failures`. + ## Slowest Chunks | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| built-ins/decodeURIComponent | NORMAL | 163.507s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| built-ins/decodeURI | NORMAL | 139.454s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| staging/sm | NORMAL | 100.949s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 100.291s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 99.715s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 98.440s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 95.367s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 91.046s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| staging/sm | NORMAL | 86.932s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| intl402 | NORMAL | 85.029s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | -| staging/sm | NORMAL | 82.003s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| staging/sm | NORMAL | 80.993s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| built-ins/decodeURI | NORMAL | 73.746s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | -| built-ins/decodeURIComponent | NORMAL | 73.328s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | -| intl402/DateTimeFormat | NORMAL | 67.982s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | -| staging/sm | NORMAL | 65.928s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.856s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Avestan.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Balinese.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Bamum.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Bassa_Vah.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Batak.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.807s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Malayalam.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Mandaic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Manichaean.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.680s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Rejang.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Runic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Samaritan.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.629s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js` | +| staging/sm | NORMAL | 179.254s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 178.090s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 176.536s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 176.085s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 173.926s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 171.558s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| staging/sm | NORMAL | 168.036s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| staging/sm | NORMAL | 142.027s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| staging/sm | NORMAL | 134.787s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 116.164s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| built-ins/decodeURIComponent | NORMAL | 90.181s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| intl402 | NORMAL | 85.375s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | +| built-ins/decodeURI | NORMAL | 81.845s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| built-ins/TypedArray | NORMAL | 71.484s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | +| intl402/DateTimeFormat | NORMAL | 66.465s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | +| annexB/built-ins/RegExp | NORMAL | 65.097s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 57.998s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Newa.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nko.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nushu.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 57.442s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Grapheme_Extend.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Hex_Digit.js`
`test262/test/built-ins/RegExp/property-escapes/generated/IDS_Binary_Operator.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 56.915s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Myanmar.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nabataean.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nag_Mundari.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 56.881s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Math.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Noncharacter_Code_Point.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Pattern_Syntax.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 10b00432..94635e8e 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-24T01:11:33+00:00", - "updatedAt": "2026-10-24T01:11:33+00:00", + "generatedAt": "2026-10-24T03:35:26+00:00", + "updatedAt": "2026-10-24T03:35:26+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "ba525bc2", + "commit": "aec1e4fc", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "76af713f1a4edd72cf26a470b82737afcce2eb66", - "runIdentity": "9b5c8c3956e480f6dac517554c75d5fd5bec26fa5cebf408961b9c7cf1106a0c" + "fingerprint": "49c5bdc6a14925b427e8b6b520056b235fec8b9f", + "runIdentity": "263ce79594262b0119bfbc48ce283698aac3faad57f84ce8d3a2d2d0a1522562" }, "discovery": { "groupCount": 161, @@ -199,8 +199,8 @@ "test262": { "skippedFeatures": [], "totals": { - "pass": 53616, - "fail": 0, + "pass": 53615, + "fail": 1, "skip": 0, "blocked": 0, "pending": 0, @@ -208,7 +208,7 @@ "attempted": 53616, "known": 53616, "total": 53616, - "passRate": 100 + "passRate": 99.9 }, "areas": [ { @@ -283,9 +283,9 @@ }, { "name": "staging", - "status": "pass", - "pass": 1483, - "fail": 0, + "status": "partial", + "pass": 1482, + "fail": 1, "skip": 0, "blocked": 0, "pending": 0, @@ -293,7 +293,7 @@ "attempted": 1483, "known": 1483, "total": 1483, - "passRate": 100 + "passRate": 99.9 } ], "groups": [ @@ -2670,9 +2670,9 @@ { "name": "staging/sm", "area": "staging", - "status": "pass", - "pass": 1406, - "fail": 0, + "status": "partial", + "pass": 1405, + "fail": 1, "skip": 0, "blocked": 0, "pending": 0, @@ -2680,7 +2680,7 @@ "attempted": 1406, "known": 1406, "total": 1406, - "passRate": 100 + "passRate": 99.9 }, { "name": "staging/source-phase-imports", @@ -2713,40 +2713,45 @@ "passRate": 100 } ], - "failures": [], + "failures": [ + { + "path": "test262/test/staging/sm/extensions/function-caller-skips-eval-frames.js", + "message": "runtime: Phasis\\Exceptions\\JsThrowable: Expected SameValue(\u00abnull\u00bb, \u00abfunction nest2() { return nest(); }\u00bb) to be true" + } + ], "blockedChunks": [], "slowChunks": [ { - "group": "built-ins/decodeURIComponent", + "group": "staging/sm", "kind": "normal", - "durationSec": 163.507, + "durationSec": 179.254, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { - "group": "built-ins/decodeURI", + "group": "staging/sm", "kind": "normal", - "durationSec": 139.454, + "durationSec": 178.09, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 100.949, + "durationSec": 176.536, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 100.291, + "durationSec": 176.085, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" @@ -2755,109 +2760,105 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 99.715, + "durationSec": 173.926, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 98.44, + "durationSec": 171.558, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 95.367, + "durationSec": 168.036, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 91.046, + "durationSec": 142.027, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 86.932, + "durationSec": 134.787, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" ] }, { - "group": "intl402", + "group": "staging/sm", "kind": "normal", - "durationSec": 85.029, - "filesCount": 22, + "durationSec": 116.164, + "filesCount": 1, "sampleFiles": [ - "test262/test/intl402/constructors-string-and-single-element-array.js", - "test262/test/intl402/constructors-taint-Object-prototype-2.js", - "...", - "test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js", - "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { - "group": "staging/sm", + "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 82.003, + "durationSec": 90.181, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" ] }, { - "group": "staging/sm", + "group": "intl402", "kind": "normal", - "durationSec": 80.993, - "filesCount": 1, + "durationSec": 85.375, + "filesCount": 22, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" + "test262/test/intl402/constructors-string-and-single-element-array.js", + "test262/test/intl402/constructors-taint-Object-prototype-2.js", + "...", + "test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js", + "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" ] }, { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 73.746, - "filesCount": 25, + "durationSec": 81.845, + "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", - "...", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" ] }, { - "group": "built-ins/decodeURIComponent", + "group": "built-ins/TypedArray", "kind": "normal", - "durationSec": 73.328, + "durationSec": 71.484, "filesCount": 25, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", + "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", + "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js", "...", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" + "test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js", + "test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js" ] }, { "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 67.982, + "durationSec": 66.465, "filesCount": 12, "sampleFiles": [ "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", @@ -2868,58 +2869,60 @@ ] }, { - "group": "staging/sm", + "group": "annexB/built-ins/RegExp", "kind": "normal", - "durationSec": 65.928, - "filesCount": 1, + "durationSec": 65.097, + "filesCount": 25, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" + "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", + "test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js", + "...", + "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js", + "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.856, - "filesCount": 5, + "durationSec": 57.998, + "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Avestan.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Balinese.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Bamum.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Bassa_Vah.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Batak.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Newa.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nko.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nushu.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.807, + "durationSec": 57.442, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Malayalam.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Mandaic.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Manichaean.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Grapheme_Extend.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Hex_Digit.js", + "test262/test/built-ins/RegExp/property-escapes/generated/IDS_Binary_Operator.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.68, + "durationSec": 56.915, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Rejang.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Runic.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Samaritan.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Myanmar.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nabataean.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nag_Mundari.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.629, + "durationSec": 56.881, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Math.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Noncharacter_Code_Point.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Pattern_Syntax.js" ] } ] From 58f50e6964be2628bc1e98e00396a1b7f74ddc4c Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 05:57:13 +0200 Subject: [PATCH 78/99] Fail canonical CI when the completed report contains failures --- .github/workflows/compat-matrix.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/compat-matrix.yml b/.github/workflows/compat-matrix.yml index 1a3da071..6511b7c5 100644 --- a/.github/workflows/compat-matrix.yml +++ b/.github/workflows/compat-matrix.yml @@ -400,3 +400,26 @@ jobs: echo "Push failed; snapshot is in the compat-report artifact." exit 0 fi + + # Preserve and publish the full failure report before failing the gate. + # A complete run may still contain failing tests. + - name: Require a complete passing canonical snapshot + run: | + php <<'PHP' + 0 + && ($snapshot['test262']['skippedFeatures'] ?? null) === []; + foreach (['pass', 'attempted', 'known', 'total'] as $key) { + $passed = $passed && ($totals[$key] ?? null) === $total; + } + foreach (['fail', 'skip', 'blocked', 'pending', 'running'] as $key) { + $passed = $passed && ($totals[$key] ?? null) === 0; + } + if (!$passed) { + fwrite(STDERR, "Canonical test262 did not pass every discovered file. See compat.json and COMPAT.md.\n"); + exit(1); + } + PHP From 76bac88f5087ba803eeb0db9c0682a9fc3ce034b Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 06:33:39 +0200 Subject: [PATCH 79/99] Keep observable PHP-generated calls on tracked activations --- src/Bytecode/JsToPhp.php | 39 +- src/Bytecode/Parts/JsToPhpEligibility.php | 27 ++ src/Bytecode/Parts/JsToPhpEmitStatement.php | 25 +- src/Bytecode/Parts/JsToPhpLoopRegions.php | 3 + src/Bytecode/Parts/JsToPhpStringScanners.php | 3 +- src/Bytecode/StringScannerPlan.php | 10 +- src/Bytecode/VM.php | 15 +- src/Runtime/Environment.php | 13 + src/Runtime/Parts/ExpressionEvaluation.php | 13 +- .../Unit/Bytecode/ArrayCallbackRealmTest.php | 41 +- tests/Unit/Bytecode/CallerActivationTest.php | 349 ++++++++++++++++++ .../Bytecode/JsToPhpBailoutSafetyTest.php | 22 +- .../Bytecode/LoopCheckpointContractTest.php | 6 +- .../Bytecode/NonCallableFormattingTest.php | 101 +++++ .../Bytecode/NumericPropertyLiteralTest.php | 15 +- .../Unit/Bytecode/PurePhpLoopContractTest.php | 60 +++ tests/Unit/Bytecode/StringScannerTest.php | 98 +++++ tests/Unit/Bytecode/WhileCheckpointTest.php | 41 +- tests/Unit/Runtime/ObjectLiteralRealmTest.php | 6 +- 19 files changed, 790 insertions(+), 97 deletions(-) create mode 100644 tests/Unit/Bytecode/CallerActivationTest.php create mode 100644 tests/Unit/Bytecode/NonCallableFormattingTest.php create mode 100644 tests/Unit/Bytecode/PurePhpLoopContractTest.php diff --git a/src/Bytecode/JsToPhp.php b/src/Bytecode/JsToPhp.php index 8c0b53d8..6b0a440b 100644 --- a/src/Bytecode/JsToPhp.php +++ b/src/Bytecode/JsToPhp.php @@ -32,29 +32,19 @@ * JS-to-PHP source compiler. Emits a PHP closure that runs the JS * function body directly, bypassing the VM dispatch loop entirely. * - * Phase 2 scope: tight numeric subset where every value flow can be - * statically proven to use raw PHP doubles for numbers and bools for - * booleans. The compiler now supports: - * - Free-variable reads (resolved via $env->get + unbox-on-entry). - * - Function calls with Identifier callee, when args / return are - * numeric. Recursive call into another phpCompiled closure goes - * direct, skipping executeFunction's setup; otherwise we route - * through Interpreter::callFunction so the spec-y bookkeeping - * still runs. - * - All Phase 1 features: arithmetic, comparisons, locals, simple - * control flow. + * Frameless specialization admits call-free scalar arithmetic, locals, + * control flow and guarded ordinary data reads. Fresh private object and + * array operations can share that tier without exposing their allocations. + * Reads that could invoke getters or host overrides decline before effects. * - * Bails (returns null) on: - * - Member access (would need shape-aware property reads). - * - String / object / array operations. - * - Closures that write to free variables. - * - Any node not enumerated in emitStatement / emitExpression. + * Ordinary calls and construction remain on the tracked VM/AST paths. + * Their transitive callbacks can observe caller/arguments even when a callee + * has a numeric return entry. Only complete scanner/region proofs may inline + * closed scalar predicates and guarded primitive intrinsics without a frame. * - * Calls inside expressions are lifted to temporary statements by a - * pendingStatements buffer so each call result lands in its own - * named PHP variable; the enclosing expression then references that - * variable. Avoids closure-per-expression patterns that would blow - * up PHP JIT traces. + * A pendingStatements buffer preserves evaluation order where scalar + * expressions need temporaries. Unsupported syntax and writes to free + * variables decline compilation rather than weakening these contracts. */ final class JsToPhp { @@ -184,7 +174,10 @@ final class JsToPhp public static function compile(JsFunction $fn): ?\Closure { - if ($fn->getBoundTarget() !== null) { + if ( + get_class($fn) !== JsFunction::class || !$fn->getClosure()->hasPlainChain() + || $fn->getBoundTarget() !== null + ) { return null; } if (CompilationFailures::get($fn, 'php') !== null) { @@ -251,7 +244,7 @@ private static function compileFunction(JsFunction $fn): ?\Closure if (self::bodyHasNestedLexical($body)) { return null; } - $standard = self::compileWith($fn, false); + $standard = self::bodyHasUntrackedCall($body) ? null : self::compileWith($fn, false); if ($standard === null) { $scanner = StringScannerPlan::analyze($fn); return $scanner !== null ? self::compileWith($fn, false, $scanner) : null; diff --git a/src/Bytecode/Parts/JsToPhpEligibility.php b/src/Bytecode/Parts/JsToPhpEligibility.php index cba14b8f..f25b1cd9 100644 --- a/src/Bytecode/Parts/JsToPhpEligibility.php +++ b/src/Bytecode/Parts/JsToPhpEligibility.php @@ -439,6 +439,33 @@ private static function bodyHasReturnCall(Node $body): bool return false; } + /** Ordinary calls can expose caller/arguments through any transitive callback or getter. */ + private static function bodyHasUntrackedCall(Node $node): bool + { + if ($node instanceof CallExpression || $node instanceof \Phasis\Ast\Expression\NewExpression) { + return true; + } + if ( + $node instanceof FunctionDeclaration || $node instanceof \Phasis\Ast\Expression\FunctionExpression + || $node instanceof \Phasis\Ast\Expression\ArrowFunction + ) { + return false; + } + foreach ((array) $node as $value) { + if ($value instanceof Node && self::bodyHasUntrackedCall($value)) { + return true; + } + if (is_array($value)) { + foreach ($value as $child) { + if ($child instanceof Node && self::bodyHasUntrackedCall($child)) { + return true; + } + } + } + } + return false; + } + private static function exprHasTailCall(Node $node): bool { if ($node instanceof CallExpression) { diff --git a/src/Bytecode/Parts/JsToPhpEmitStatement.php b/src/Bytecode/Parts/JsToPhpEmitStatement.php index 5ca09ed1..22136ef6 100644 --- a/src/Bytecode/Parts/JsToPhpEmitStatement.php +++ b/src/Bytecode/Parts/JsToPhpEmitStatement.php @@ -41,6 +41,11 @@ trait JsToPhpEmitStatement */ private function emitPrologue(array $params): void { + $this->emitLine('$_php_context = \\Phasis\\Engine::getCurrentInterpreter();'); + $this->emitLine('if (!$env->hasPlainChain()' + . ' || get_class($interp) !== \\Phasis\\Runtime\\Interpreter::class' + . ' || ($_php_context !== null && get_class($_php_context) !== \\Phasis\\Runtime\\Interpreter::class)) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("untracked host override"); }'); $this->emitScannerGuards(); foreach ($params as $idx => $param) { if (!$param instanceof Identifier) { @@ -432,8 +437,11 @@ private function emitStatement(Node $node): void !$this->numericMode && $node->argument instanceof Identifier && !isset($this->declaredLocals[$node->argument->name]) ) { - $this->recordObservableEffect(); - $this->emitLine('return $env->get(' . var_export($node->argument->name, true) . ');'); + $this->recordRuntimeGuard(); + $value = $this->newTemp('return_binding'); + $this->emitLine($value . ' = $env->getDataBinding(' . var_export($node->argument->name, true) . ');'); + $this->emitLine('if (' . $value . ' === null) { throw new \\Phasis\\Bytecode\\Bailout("observable return binding"); }'); + $this->emitLine('return ' . $value . ';'); return; } if ( @@ -442,11 +450,16 @@ private function emitStatement(Node $node): void && $node->argument->object instanceof Identifier && $node->argument->property instanceof Identifier && ($this->localTypes[$node->argument->object->name] ?? null) === 'object' ) { - $this->recordObservableEffect(); + $this->recordRuntimeGuard(); $receiver = $this->slotVar($node->argument->object->name); - $this->emitLine('return $interp->vmLookupPrimitiveMember(' . $receiver - . ' ?? \\Phasis\\Value\\JsUndefined::instance(), ' - . var_export($node->argument->property->name, true) . ');'); + $value = $this->newTemp('return_member'); + $this->emitLine('if (!(' . $receiver . ' instanceof \\Phasis\\Value\\JsObject)' + . ' || get_class(' . $receiver . ') !== \\Phasis\\Value\\JsObject::class) {' + . ' throw new \\Phasis\\Bytecode\\Bailout("observable return receiver"); }'); + $this->emitLine($value . ' = ' . $receiver . '->properties->dataSlots[' + . var_export($node->argument->property->name, true) . '] ?? null;'); + $this->emitLine('if (' . $value . ' === null) { throw new \\Phasis\\Bytecode\\Bailout("observable return member"); }'); + $this->emitLine('return ' . $value . ';'); return; } if ($node->argument === null) { diff --git a/src/Bytecode/Parts/JsToPhpLoopRegions.php b/src/Bytecode/Parts/JsToPhpLoopRegions.php index a13e6aa7..5fa1ea1c 100644 --- a/src/Bytecode/Parts/JsToPhpLoopRegions.php +++ b/src/Bytecode/Parts/JsToPhpLoopRegions.php @@ -81,6 +81,9 @@ public static function compileLoopRegion(StringLoopRegionPlan $plan, int $loopId private function emitRegionGuards(): void { $this->emitLine('$_region_context = \\Phasis\\Engine::getCurrentInterpreter();'); + $this->emitLine('if (get_class($interp) !== \\Phasis\\Runtime\\Interpreter::class' + . ' || $_region_context === null || get_class($_region_context) !== \\Phasis\\Runtime\\Interpreter::class)' + . ' { return null; }'); $this->emitLine('if ($interp->hasExecutionBudget() || $_region_context?->hasExecutionBudget()' . ' || $_region_context?->getRealm() !== $interp->getRealm() || $interp->getRealm() === null) { return null; }'); $this->emitLine('if (!$interp->hasCachedStringIntrinsic("charCodeAt", "string.charCodeAt")) { return null; }'); diff --git a/src/Bytecode/Parts/JsToPhpStringScanners.php b/src/Bytecode/Parts/JsToPhpStringScanners.php index 551a319e..ff6d70f7 100644 --- a/src/Bytecode/Parts/JsToPhpStringScanners.php +++ b/src/Bytecode/Parts/JsToPhpStringScanners.php @@ -44,7 +44,8 @@ private function emitScannerGuards(): void $index = 0; foreach ($this->scannerPlan->predicates as $name => $_) { $this->emitLine('$_scanner_binding = $env->findBindingDepth(' . var_export($name, true) . ');'); - $this->emitLine('if ($_scanner_binding === null || $_scanner_binding[0] !== $scannerGuards[' . $index . ']->get()) {' + $this->emitLine('if ($_scanner_binding === null || $_scanner_binding[0] !== $scannerGuards[' . $index . ']->get()' + . ' || !$_scanner_binding[0]->getClosure()->hasPlainChain()) {' . ' throw new \\Phasis\\Bytecode\\Bailout("scanner predicate changed"); }'); ++$index; } diff --git a/src/Bytecode/StringScannerPlan.php b/src/Bytecode/StringScannerPlan.php index 9661f208..f908729e 100644 --- a/src/Bytecode/StringScannerPlan.php +++ b/src/Bytecode/StringScannerPlan.php @@ -336,9 +336,15 @@ private function predicate(string $name): ?array if (isset($this->predicates[$name])) { return $this->predicates[$name]; } - $value = $this->function->getClosure()->findBindingDepth($name)[0] ?? null; + $scope = $this->function->getClosure(); + if (!$scope->hasPlainChain()) { + return null; + } + $value = $scope->findBindingDepth($name)[0] ?? null; if ( - !$value instanceof JsFunction || $value->getNativeCallable() !== null || $value->getBoundTarget() !== null + !$value instanceof JsFunction || get_class($value) !== JsFunction::class + || !$value->getClosure()->hasPlainChain() + || $value->getNativeCallable() !== null || $value->getBoundTarget() !== null || $value->isClassConstructor() || $value->isDerivedConstructor() || $value->isAsync() || $value->isGenerator() ) { return null; diff --git a/src/Bytecode/VM.php b/src/Bytecode/VM.php index caa50e41..b05c7269 100644 --- a/src/Bytecode/VM.php +++ b/src/Bytecode/VM.php @@ -1607,7 +1607,8 @@ public function execute( } elseif ($callee instanceof \Phasis\Value\JsProxy && $callee->isCallable()) { $stack[$sp++] = $callee->apply($receiver, $args); } else { - $display = $cf->callMethodDisplays[$pc] ?? (TypeConversion::toString($callee) ?: 'value'); + $display = $cf->callMethodDisplays[$pc] + ?? ($callee instanceof JsObject ? 'value' : (TypeConversion::toString($callee) ?: 'value')); throw new TypeError($display . ' is not a function'); } $pc += 2; @@ -1654,9 +1655,8 @@ public function execute( $pc += 2; break; } - throw new TypeError( - (TypeConversion::toString($callee) ?: 'value') . ' is not a function' - ); + $display = $callee instanceof JsObject ? 'value' : (TypeConversion::toString($callee) ?: 'value'); + throw new TypeError($display . ' is not a function'); } // Cross-realm calls need the ordinary realm switch; // cached eligibility describes only function shape. @@ -2168,12 +2168,11 @@ public function execute( // Prefer the compiler-rendered call-site // source (e.g. `[].__proto__`) so the // TypeError matches V8 / SpiderMonkey - // wording. Fall back to the value's - // toString and finally a generic 'value' - // when no display was recorded. + // wording. Object coercion while formatting + // an error must not invoke user code. $display = $cf->callMethodDisplays[$pc] ?? null; if ($display === null) { - $display = TypeConversion::toString($method) ?: 'value'; + $display = $method instanceof JsObject ? 'value' : (TypeConversion::toString($method) ?: 'value'); } throw new TypeError($display . ' is not a function'); } diff --git a/src/Runtime/Environment.php b/src/Runtime/Environment.php index d37a590c..c548c792 100644 --- a/src/Runtime/Environment.php +++ b/src/Runtime/Environment.php @@ -517,6 +517,19 @@ public function findBindingDepth(string $name): ?array return null; } + /** Internal: generated reads must not bypass host overrides on any scope in the chain. */ + final public function hasPlainChain(): bool + { + $current = $this; + while ($current !== null) { + if (get_class($current) !== self::class) { + return false; + } + $current = $current->parent; + } + return true; + } + /** * Read an ordinary data binding without invoking getters, imports or with traps. * Null declines speculation and leaves errors and observable reads to the interpreter. diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index 743918f0..db074b96 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -1509,7 +1509,7 @@ private function evalCallExpression(CallExpression $node, Environment $env, bool $args = $this->evaluateArguments($node->arguments, $env); if (!($callee instanceof JsFunction)) { throw new TypeError( - TypeConversion::toString($callee) . ' is not a function', + ($callee instanceof JsObject ? 'value' : TypeConversion::toString($callee)) . ' is not a function', ); } return $this->callFunction($callee, $rawObj, $args); @@ -3312,7 +3312,7 @@ private function evalNewExpression(NewExpression $node, Environment $env): JsVal } if (!$callee instanceof JsFunction || !$callee->isConstructable()) { - throw new TypeError(TypeConversion::toString($callee) . ' is not a constructor'); + throw new TypeError(($callee instanceof JsObject ? 'value' : TypeConversion::toString($callee)) . ' is not a constructor'); } // Create a new object with the constructor's prototype @@ -3699,7 +3699,7 @@ public function initializeInstanceFields(JsFunction $ctor, JsObject $instance, E * Format the call expression's callee for "X is not a function" errors. * Mirrors V8/SpiderMonkey error messages by serialising MemberExpression * and Identifier callees rather than using the value's toString. Falls - * back to the value's stringification for opaque/computed callees. + * back to primitive formatting or a generic object label without invoking hooks. */ private function formatCalleeForError(Node $node, JsValue $value): string { @@ -3707,7 +3707,7 @@ private function formatCalleeForError(Node $node, JsValue $value): string if ($text !== null) { return $text; } - return TypeConversion::toString($value); + return $value instanceof JsObject ? 'value' : TypeConversion::toString($value); } /** Recursively render a MemberExpression / Identifier / ArrayExpression @@ -5932,7 +5932,8 @@ public function hasCachedStringIntrinsic(string $name, string $kind): bool } $value = $descriptor->value; } - return $value instanceof JsFunction && $value->builtinKind === $kind && $value->getNativeCallable() !== null; + return $value instanceof JsFunction && get_class($value) === JsFunction::class + && $value->builtinKind === $kind && $value->getNativeCallable() !== null; } /** @@ -6108,7 +6109,7 @@ public function vmNewExpression(JsValue $callee, array $args, Environment $env): return $callee->construct($args, $callee); } if (!$callee instanceof JsFunction || !$callee->isConstructable()) { - throw new TypeError(TypeConversion::toString($callee) . ' is not a constructor'); + throw new TypeError(($callee instanceof JsObject ? 'value' : TypeConversion::toString($callee)) . ' is not a constructor'); } // Mirror evalNewExpression's full setup so class field // initializers, derived-constructor checks, and the diff --git a/tests/Unit/Bytecode/ArrayCallbackRealmTest.php b/tests/Unit/Bytecode/ArrayCallbackRealmTest.php index a20a4f6a..c00b81d7 100644 --- a/tests/Unit/Bytecode/ArrayCallbackRealmTest.php +++ b/tests/Unit/Bytecode/ArrayCallbackRealmTest.php @@ -38,8 +38,8 @@ function foreignCallback(value) { JS); $callback = $foreign->getGlobalEnv()->get('foreignCallback'); self::assertInstanceOf(JsFunction::class, $callback); - self::assertInstanceOf(\Closure::class, $callback->phpCompiled); - self::assertInstanceOf(\Closure::class, $callback->phpCompiledNumeric); + self::assertNull($callback->phpCompiled); + self::assertNull($callback->phpCompiledNumeric); if (!$numeric) { $callback->phpCompiledNumeric = null; } @@ -69,6 +69,43 @@ function localFilter() { const values = [1, 2]; return values.filter(foreignCall self::assertNotNull($wrapper->compiled, $name . ' must exercise the VM callback path.'); } } + self::assertNull($callback->phpCompiledNumeric); + self::assertNull($callback->phpCompiled); + self::assertSame(0, $caller->getInterpreter()->getCallStack()->depth()); + self::assertSame(0, $foreign->getInterpreter()->getCallStack()->depth()); + } + + #[DataProvider('executionModes')] + public function testPureCompiledCallbackErrorsUseTheirOwnRealm(bool $budgeted, bool $numeric): void + { + $foreign = new Engine(); + $foreign->eval('function pureCallback(value) { let count = 0; while (count < value) { count++; } return count; }' + . 'pureCallback(1);'); + $callback = $foreign->getGlobalEnv()->get('pureCallback'); + self::assertInstanceOf(JsFunction::class, $callback); + self::assertInstanceOf(\Closure::class, $callback->phpCompiled); + self::assertInstanceOf(\Closure::class, $callback->phpCompiledNumeric); + if (!$numeric) { + $callback->phpCompiledNumeric = null; + } + $caller = new Engine(); + $caller->setGlobalJsValue('pureCallback', $callback); + $caller->setGlobalJsValue('ForeignError', $foreign->getGlobalEnv()->get('Error')); + $caller->setLimit('maxLoopIterations', 1); + if ($budgeted) { + $caller->setExecutionBudget(10); + } + self::assertSame([true, true, true, true], $caller->eval(<<<'JS' +function map() { return [2].map(pureCallback); } +function reduce() { return [2].reduce(pureCallback, 2); } +function each() { return [2].forEach(pureCallback); } +function filter() { return [2].filter(pureCallback); } +function exceeds(action) { + try { action(); return false; } + catch (error) { return error instanceof ForeignError && !(error instanceof Error); } +} +[exceeds(map), exceeds(reduce), exceeds(each), exceeds(filter)]; +JS)); self::assertSame($numeric, $callback->phpCompiledNumeric !== null); self::assertInstanceOf(\Closure::class, $callback->phpCompiled); self::assertSame(0, $caller->getInterpreter()->getCallStack()->depth()); diff --git a/tests/Unit/Bytecode/CallerActivationTest.php b/tests/Unit/Bytecode/CallerActivationTest.php new file mode 100644 index 00000000..b15fca27 --- /dev/null +++ b/tests/Unit/Bytecode/CallerActivationTest.php @@ -0,0 +1,349 @@ +, list}> */ + public static function observers(): iterable + { + yield 'terminal-caller' => [ + <<<'JS' +function observe() { + return observe.caller === outer; +} +function outer() { + return observe(); +} +JS, + 'outer()', 'true', ['outer'], [], + ]; + yield 'terminal-arguments' => [ + <<<'JS' +function observe() { + return outer.arguments[0]; +} +function outer(value) { + return observe(); +} +JS, + 'outer(7)', '7', ['outer'], [], + ]; + yield 'discarded-call' => [ + <<<'JS' +var seen = false; +function observe() { + seen = observe.caller === outer && outer.arguments[0] === 7; +} +function outer(value) { + observe(); + return value; +} +function output() { + seen = false; + return [outer(7), seen]; +} +JS, + 'output()', '[7,true]', ['outer'], [], + ]; + yield 'strict-barrier' => [ + <<<'JS' +var seen = false; +function observe() { + seen = observe.caller === null; +} +function outer(value) { + 'use strict'; + observe(); + return value; +} +function output() { + seen = false; + outer(7); + return seen; +} +JS, + 'output()', 'true', ['outer'], [], + ]; + yield 'method-getter' => [ + <<<'JS' +var getters = 0, methods = 0, seen = false; +function getter() { + getters++; + seen = getter.caller === outer && outer.arguments[0] === 7; + return method; +} +function method(value) { + methods++; + return seen && method.caller === outer ? value : 0; +} +Object.defineProperty(Object.prototype, 'observe', { get: getter, configurable: true }); +function outer(value) { + const object = { value: value }; + return object.observe(value); +} +function output() { + getters = methods = 0; + seen = false; + return [outer(7), getters, methods]; +} +JS, + 'output()', '[7,1,1]', ['outer'], [], + ]; + yield 'constructor' => [ + <<<'JS' +var seen = false, calls = 0; +function Ctor() { + calls++; + seen = Ctor.caller === outer && outer.arguments[0] === 7; +} +function outer(value) { + const ignored = new Ctor(); + return value; +} +function output() { + seen = false; + calls = 0; + return [outer(7), seen, calls]; +} +JS, + 'output()', '[7,true,1]', ['outer'], [], + ]; + yield 'numeric-constructor-chain' => [ + <<<'JS' +var seen = false; +function Ctor() { + seen = Ctor.caller === bridge && bridge.caller === outer && bridge.arguments[0] === 7; +} +function bridge(value) { + const ignored = new Ctor(); + return value; +} +function outer(value) { + return bridge(value) + 1; +} +function output() { + seen = false; + return [outer(7), seen]; +} +JS, + 'output()', '[8,true]', ['outer', 'bridge'], [], + ]; + yield 'numeric-callback-chain' => [ + <<<'JS' +var seen = false; +function observe() { + seen = observe.caller === bridge && bridge.caller === outer && bridge.arguments[0] === 7; +} +function bridge(value) { + observe(); + return value; +} +function outer(value) { + return bridge(value) + 1; +} +function output() { + seen = false; + return [outer(7), seen]; +} +JS, + 'output()', '[8,true]', ['outer', 'bridge'], [], + ]; + yield 'free-binding-getter' => [ + <<<'JS' +var seen = false, reads = 0; +function getter() { + reads++; + seen = getter.caller === outer && outer.arguments[0] === 7; + return 3; +} +Object.defineProperty(globalThis, 'observed', { get: getter, configurable: true }); +function outer(value) { + return observed; +} +function output() { + seen = false; + reads = 0; + return [outer(7), seen, reads]; +} +JS, + 'output()', '[3,true,1]', [], ['outer'], + ]; + yield 'member-getter' => [ + <<<'JS' +var seen = false, reads = 0; +function getter() { + reads++; + seen = getter.caller === outer && outer.arguments[0] === 7; + return 3; +} +Object.defineProperty(Object.prototype, 'observed', { get: getter, configurable: true }); +function outer(value) { + const object = {}; + return object.observed; +} +function output() { + seen = false; + reads = 0; + return [outer(7), seen, reads]; +} +JS, + 'output()', '[3,true,1]', [], ['outer'], + ]; + yield 'while-condition' => [ + <<<'JS' +var seen = false; +function condition() { + seen = condition.caller === outer && outer.arguments[0] === 7; + return false; +} +function outer(value) { + while (condition()) { + break; + } + return seen; +} +JS, + 'outer(7)', 'true', ['outer'], [], + ]; + yield 'for-condition' => [ + <<<'JS' +var seen = false; +function condition() { + seen = condition.caller === outer && outer.arguments[0] === 7; + return false; +} +function outer(value) { + for (; condition();) { + break; + } + return seen; +} +JS, + 'outer(7)', 'true', ['outer'], [], + ]; + yield 'do-condition' => [ + <<<'JS' +var seen = false; +function condition() { + seen = condition.caller === outer && outer.arguments[0] === 7; + return false; +} +function outer(value) { + do { + } while (condition()); + return seen; +} +JS, + 'outer(7)', 'true', ['outer'], [], + ]; + yield 'eval-frame-chain' => [ + <<<'JS' +function observe() { + return observe.caller.caller === outer; +} +function bridge() { + return eval('observe()'); +} +function outer() { + return bridge(); +} +JS, + 'outer()', 'true', ['outer'], [], + ]; + } + + #[DataProvider('observers')] + public function testObservableBoundariesKeepCallerAndArgumentRecords( + string $definitions, + string $expression, + string $expected, + array $declined, + array $guarded, + ): void { + $engine = new Engine(); + $engine->eval($definitions); + for ($pass = 0; $pass < 2; $pass++) { + self::assertSame($expected, $engine->eval('JSON.stringify(' . $expression . ')')); + } + foreach ($declined as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->phpCompiled, $name); + self::assertNull($function->phpCompiledNumeric, $name); + } + foreach ($guarded as $name) { + $function = $engine->getGlobalEnv()->get($name); + self::assertInstanceOf(JsFunction::class, $function); + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + $before = $engine->getGlobalEnv()->get('reads')->value; + $previous = Engine::getCurrentInterpreter(); + Engine::setCurrentInterpreter($engine->getInterpreter()); + try { + ($function->phpCompiled)( + [JsNumber::of(7)], + JsUndefined::instance(), + $function->getClosure(), + $engine->getInterpreter(), + $function->phpCompiledNodes, + ); + self::fail('A getter must run through a tracked activation.'); + } catch (Bailout) { + self::assertSame($before, $engine->getGlobalEnv()->get('reads')->value); + } finally { + Engine::setCurrentInterpreter($previous); + } + } + } + + public function testCachedEntriesRejectHostEnvironmentReceiversAndAncestorsBeforeVirtualReads(): void + { + $engine = new Engine(); + $engine->eval('var captured = 7; function read() { return captured; } read();'); + $function = $engine->getGlobalEnv()->get('read'); + self::assertInstanceOf(JsFunction::class, $function); + $host = new class ($engine->getGlobalEnv()) extends Environment { + public int $reads = 0; + + public function getDataBinding(string $name): ?JsValue + { + ++$this->reads; + return parent::getDataBinding($name); + } + }; + $host->defineVar('captured', JsNumber::of(7)); + $previous = Engine::getCurrentInterpreter(); + Engine::setCurrentInterpreter($engine->getInterpreter()); + try { + foreach ([$host, $host->createChild()] as $scope) { + self::assertFalse($scope->hasPlainChain()); + $function->closure = $scope; + self::assertNull(JsToPhp::compile($function)); + foreach ([$function->phpCompiled, $function->phpCompiledNumeric] as $entry) { + self::assertInstanceOf(\Closure::class, $entry); + try { + $entry([], JsUndefined::instance(), $scope, $engine->getInterpreter(), []); + self::fail('A cached entry must reject a host environment chain.'); + } catch (Bailout) { + self::assertSame(0, $host->reads); + } + } + } + } finally { + Engine::setCurrentInterpreter($previous); + } + } +} diff --git a/tests/Unit/Bytecode/JsToPhpBailoutSafetyTest.php b/tests/Unit/Bytecode/JsToPhpBailoutSafetyTest.php index e806277e..6197cbbe 100644 --- a/tests/Unit/Bytecode/JsToPhpBailoutSafetyTest.php +++ b/tests/Unit/Bytecode/JsToPhpBailoutSafetyTest.php @@ -18,7 +18,7 @@ public static function cases(): iterable 'var n=0,value=\'x\'; function touch(){n++} function checked(){touch();return value' . '} var a=checked(),b=n,c=checked(); JSON.stringify([a,b,c,n]);', '["x",1,"x",2]', - true, + false, true, ]; yield 'arithmetic-free-return' => [ @@ -32,14 +32,14 @@ public static function cases(): iterable 'var n=0;function produce(){n++;return \'x\'}function checked(){return produce()}va' . 'r a=checked(),b=n,c=checked();JSON.stringify([a,b,c,n]);', '["x",1,"x",2]', - true, + false, true, ]; yield 'nonnumeric-call-result' => [ 'var n=0;function produce(){n++;return \'x\'}function checked(){return produce()+0}' . 'var a=checked(),b=n,c=checked();JSON.stringify([a,b,c,n]);', '["x0",1,"x0",2]', - true, + false, true, ]; yield 'member-after-effect' => [ @@ -48,7 +48,7 @@ public static function cases(): iterable . 'st object={value:0};object.change();return object.value}var a=checked(),b=n,c=ch' . 'ecked();JSON.stringify([a,b,c,n]);', '["x",2,"x",4]', - true, + false, true, ]; yield 'branch-merge' => [ @@ -100,7 +100,7 @@ public static function cases(): iterable . 'd(x){return target(x)}var error;try{checked(1)}catch(e){error=e instanceof TypeE' . 'rror}JSON.stringify([error,n]);', '[true,0]', - true, + false, true, ]; yield 'global-getter-before-fallback' => [ @@ -115,7 +115,7 @@ public static function cases(): iterable 'function identity(x){return x}identity(1);function checked(){let value=1;value=i' . 'dentity();return value}JSON.stringify([typeof checked(),typeof checked()]);', '["undefined","undefined"]', - true, + false, true, ]; yield 'local-callee-fallback-and-arguments' => [ @@ -125,7 +125,7 @@ public static function cases(): iterable . '{const object={};object.method(value+=1);return value}var a=checked(7),b=checked' . '(8);JSON.stringify([a,b,lookups,events]);', '[8,9,2,[1,8,9]]', - true, + false, true, ]; yield 'argument-source-order' => [ @@ -133,21 +133,21 @@ public static function cases(): iterable . 'ombine(1,1);function checked(n){return combine((n=n+1),identity(n)+0)}JSON.strin' . 'gify([checked(1),checked(2)]);', '[202,303]', - true, + false, true, ]; yield 'postfix-arguments' => [ 'function combine(a,b){return a*100+b}combine(1,1);function checked(n){return com' . 'bine(n++,n)}JSON.stringify([checked(1),checked(2)]);', '[102,203]', - true, + false, true, ]; yield 'postfix-subtraction-left' => [ 'function identity(n){return n}identity(1);function checked(n){return n--*100-ide' . 'ntity(n)}JSON.stringify([checked(1),checked(3)]);', '[100,298]', - true, + false, true, ]; yield 'own-object-write' => [ @@ -219,7 +219,7 @@ public static function cases(): iterable . ' checked(n){const object={first:n,second:n};return object.inspect()}JSON.stringi' . 'fy([checked(1),checked(2)]);', '["first,second","first,second"]', - true, + false, true, ]; yield 'escaped-object-mutation' => [ diff --git a/tests/Unit/Bytecode/LoopCheckpointContractTest.php b/tests/Unit/Bytecode/LoopCheckpointContractTest.php index 9a4b79e8..7fbabbdf 100644 --- a/tests/Unit/Bytecode/LoopCheckpointContractTest.php +++ b/tests/Unit/Bytecode/LoopCheckpointContractTest.php @@ -93,10 +93,10 @@ private function prepare(Engine $engine, string $tier, string $loop, string $bod $engine->eval('function probe(amount) { ' . $helper . 'let count = 0; ' . $statement . ' return count; } probe(1);'); $function = $engine->getGlobalEnv()->get('probe'); self::assertInstanceOf(JsFunction::class, $function); - if ($tier === 'php') { + if ($tier === 'php' && $helper === '') { self::assertInstanceOf(\Closure::class, $function->phpCompiled); } else { - self::assertSame($tier === 'bytecode', $function->compiled !== null); + self::assertSame($tier !== 'ast', $function->compiled !== null); self::assertNull($function->phpCompiled); } return $function; @@ -104,7 +104,7 @@ private function prepare(Engine $engine, string $tier, string $loop, string $bod private function invoke(Engine $engine, JsFunction $function, string $tier, int $amount): float { - if ($tier === 'php') { + if ($tier === 'php' && $function->phpCompiled !== null) { $result = ($function->phpCompiled)( [JsNumber::of($amount)], JsUndefined::instance(), diff --git a/tests/Unit/Bytecode/NonCallableFormattingTest.php b/tests/Unit/Bytecode/NonCallableFormattingTest.php new file mode 100644 index 00000000..056eb567 --- /dev/null +++ b/tests/Unit/Bytecode/NonCallableFormattingTest.php @@ -0,0 +1,101 @@ + */ + public static function calls(): iterable + { + foreach ([false, true] as $ast) { + foreach ( + [ + 'call' => ['return target(0);', Op::CALL, false], + 'tail-call' => ["'use strict'; return target(0);", Op::TAIL_CALL, false], + 'method' => ['return holder["method"](0);', Op::CALL_METHOD, false], + 'tail-method' => ["'use strict'; return holder[\"method\"](0);", Op::TAIL_CALL_METHOD, false], + 'constructor' => ['const ignored = new target(); return 0;', Op::NEW_CALL, false], + 'arrow-constructor' => ['const ignored = new target(); return 0;', Op::NEW_CALL, true], + ] as $name => [$body, $opcode, $arrow] + ) { + yield ($ast ? 'ast-' : 'vm-') . $name => [$body, $opcode, $arrow, $ast]; + } + } + } + + #[DataProvider('calls')] + public function testRejectionDoesNotInvokePrimitiveConversionHooks(string $body, int $opcode, bool $arrow, bool $ast): void + { + $engine = new Engine(); + if ($ast) { + $engine->setExecutionBudget(10); + } + $target = $arrow ? '() => {}' : '{}'; + self::assertSame([[true, 0, 0], [true, 0, 0]], $engine->eval('const target = ' . $target . ';' . <<<'JS' +let reads = 0, conversions = 0; +Object.defineProperty(target, Symbol.toPrimitive, { + get() { + reads++; + return function () { conversions++; return 'target'; }; + } +}); +const holder = { method: target }; +JS + . 'function invoke() {' . $body . '}' . <<<'JS' +const results = []; +for (let pass = 0; pass < 2; pass++) { + let typeError = false; + try { invoke(); } catch (error) { typeError = error instanceof TypeError; } + results.push([typeError, reads, conversions]); +} +results; +JS)); + $function = $engine->getGlobalEnv()->get('invoke'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertNull($function->phpCompiled); + if (!$ast) { + self::assertNotNull($function->compiled); + $opcodes = []; + $code = $function->compiled->code; + for ($pc = 0; $pc < count($code); $pc += Op::operandCount($code[$pc]) + 1) { + $opcodes[] = $code[$pc]; + } + self::assertContains($opcode, $opcodes); + } + } + + public function testPrivateMethodRejectionDoesNotInvokeConversionHooks(): void + { + foreach ([false, true] as $ast) { + $engine = new Engine(); + if ($ast) { + $engine->setExecutionBudget(10); + } + self::assertSame([true, 0, 0], $engine->eval(<<<'JS' +let reads = 0, conversions = 0; +const target = {}; +Object.defineProperty(target, Symbol.toPrimitive, { + get() { + reads++; + return function () { conversions++; return 'target'; }; + } +}); +class Record { + #method = target; + invoke() { return this.#method(); } +} +let typeError = false; +try { new Record().invoke(); } catch (error) { typeError = error instanceof TypeError; } +[typeError, reads, conversions]; +JS)); + } + } +} diff --git a/tests/Unit/Bytecode/NumericPropertyLiteralTest.php b/tests/Unit/Bytecode/NumericPropertyLiteralTest.php index 80fdbdc3..0c793692 100644 --- a/tests/Unit/Bytecode/NumericPropertyLiteralTest.php +++ b/tests/Unit/Bytecode/NumericPropertyLiteralTest.php @@ -6,6 +6,8 @@ use Phasis\Engine; use Phasis\Value\JsFunction; +use Phasis\Value\JsArray; +use Phasis\Value\JsUndefined; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -38,7 +40,18 @@ public function testCompiledPropertiesPreserveOriginalNumberBits(string $literal self::assertTrue($engine->eval($source), $literal); $function = $engine->getGlobalEnv()->get('literal'); self::assertInstanceOf(JsFunction::class, $function); - self::assertInstanceOf(\Closure::class, $function->phpCompiled); + if (!$array) { + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + return; + } + self::assertNull($function->phpCompiled); + self::assertTrue($engine->eval('function pureLiteral() { const object = {items: [' . $literal . ']};' + . 'return object.items; } Object.is(pureLiteral()[0], (' . $literal . '));'), $literal); + $pure = $engine->getGlobalEnv()->get('pureLiteral'); + self::assertInstanceOf(JsFunction::class, $pure); + self::assertInstanceOf(\Closure::class, $pure->phpCompiled); + $result = ($pure->phpCompiled)([], JsUndefined::instance(), $pure->getClosure(), $engine->getInterpreter(), []); + self::assertInstanceOf(JsArray::class, $result); } public function testPropertyLiteralsIgnorePhpDisplayPrecision(): void diff --git a/tests/Unit/Bytecode/PurePhpLoopContractTest.php b/tests/Unit/Bytecode/PurePhpLoopContractTest.php new file mode 100644 index 00000000..a6b9a36e --- /dev/null +++ b/tests/Unit/Bytecode/PurePhpLoopContractTest.php @@ -0,0 +1,60 @@ + */ + public static function loops(): iterable + { + yield 'for' => ['for (; count < amount;) { count++; }', 0]; + yield 'while' => ['while (count < amount) { count++; }', 0]; + yield 'do-while' => ['do { count++; } while (count < amount);', 1]; + } + + #[DataProvider('loops')] + public function testDirectCompiledLoopsRetainCountsAndDeadlineChecks(string $loop, int $empty): void + { + $engine = new Engine(); + $engine->eval('function pure(amount) { let count = 0; ' . $loop . ' return count; } pure(1);'); + $function = $engine->getGlobalEnv()->get('pure'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + $engine->setLimit('maxLoopIterations', 1); + self::assertSame((float) $empty, $this->invoke($engine, $function, 0)); + self::assertSame(1.0, $this->invoke($engine, $function, 1)); + try { + $this->invoke($engine, $function, 2); + self::fail('The compiled loop ignored its iteration limit.'); + } catch (InternalError $error) { + self::assertStringContainsString('Maximum loop iterations', $error->getMessage()); + } + $engine->setExecutionBudget(-1); + $this->expectException(BudgetExceeded::class); + $this->invoke($engine, $function, 0); + } + + private function invoke(Engine $engine, JsFunction $function, int $amount): float + { + $result = ($function->phpCompiled)( + [JsNumber::of($amount)], + JsUndefined::instance(), + $function->getClosure(), + $engine->getInterpreter(), + $function->phpCompiledNodes, + ); + self::assertInstanceOf(JsNumber::class, $result); + return $result->value; + } +} diff --git a/tests/Unit/Bytecode/StringScannerTest.php b/tests/Unit/Bytecode/StringScannerTest.php index 563dfe3a..385a46e6 100644 --- a/tests/Unit/Bytecode/StringScannerTest.php +++ b/tests/Unit/Bytecode/StringScannerTest.php @@ -392,6 +392,104 @@ private function compiledFunction(Engine $engine, string $name): JsFunction return $function; } + public function testReplacedIntrinsicGettersAndCallbacksObserveTheTrackedScanner(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE . "forward(' ', 0);"); + self::assertSame([1, true, true, 1], $engine->eval(<<<'JS' +const originalMethod = String.prototype.charCodeAt; +let getterCaller = false, callbackCaller = false, reads = 0; +function replacement(index) { + callbackCaller = replacement.caller === forward; + return originalMethod.call(this, index); +} +function methodGetter() { + reads++; + getterCaller = methodGetter.caller === forward; + return replacement; +} +Object.defineProperty(String.prototype, 'charCodeAt', { get: methodGetter, configurable: true }); +const result = forward(' ', 0); +Object.defineProperty(String.prototype, 'charCodeAt', { + value: originalMethod, writable: true, configurable: true +}); +[result, getterCaller, callbackCaller, reads]; +JS)); + } + + public function testHostStringOverridesAreNotInvokedByCompiledGuards(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE . "forward(' ', 0);"); + $value = new class (' ') extends JsString { + public int $reads = 0; + + public function isAscii(): bool + { + ++$this->reads; + return true; + } + }; + try { + $this->runCompiled($engine, $this->compiledFunction($engine, 'forward'), [$value, JsNumber::of(0)]); + self::fail('A host string subclass must stay outside the scanner.'); + } catch (Bailout) { + self::assertSame(0, $value->reads); + } + } + + public function testCachedPredicateClosureReplacementDeclinesBeforeHostMetadata(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE . "forward(' ', 0);"); + $predicate = $engine->getGlobalEnv()->get('separator'); + self::assertInstanceOf(JsFunction::class, $predicate); + $scope = new class ($engine->getGlobalEnv()) extends \Phasis\Runtime\Environment { + public int $lookups = 0; + + public function findBindingDepth(string $name): ?array + { + ++$this->lookups; + return parent::findBindingDepth($name); + } + }; + $predicate->closure = $scope->createChild(); + try { + $this->runCompiled($engine, $this->compiledFunction($engine, 'forward'), [new JsString(' '), JsNumber::of(0)]); + self::fail('A changed predicate host scope must not be inlined.'); + } catch (Bailout) { + self::assertSame(0, $scope->lookups); + } + } + + public function testHostIntrinsicFunctionOverridesAreNotInvokedByPreflight(): void + { + $engine = new Engine(); + $engine->eval(self::SOURCE . "forward(' ', 0);"); + $prototype = $engine->getGlobalEnv()->get('String')->get('prototype'); + $original = $prototype->get('charCodeAt'); + $host = new class ('charCodeAt', [], null, $engine->getGlobalEnv()) extends JsFunction { + public int $reads = 0; + + public function getNativeCallable(): ?\Closure + { + ++$this->reads; + return static fn (): JsNumber => JsNumber::of(32); + } + }; + $host->builtinKind = 'string.charCodeAt'; + $previous = Engine::getCurrentInterpreter(); + Engine::setCurrentInterpreter($engine->getInterpreter()); + try { + $prototype->defineOwnProperty('charCodeAt', \Phasis\Object\PropertyDescriptor::data($host, true, false, true)); + self::assertFalse($engine->getInterpreter()->hasCachedStringIntrinsic('charCodeAt', 'string.charCodeAt')); + self::assertSame(0, $host->reads); + } finally { + $prototype->defineOwnProperty('charCodeAt', \Phasis\Object\PropertyDescriptor::data($original, true, false, true)); + Engine::setCurrentInterpreter($previous); + } + } + /** @param list $arguments */ private function runCompiled(Engine $engine, JsFunction $function, array $arguments): JsNumber { diff --git a/tests/Unit/Bytecode/WhileCheckpointTest.php b/tests/Unit/Bytecode/WhileCheckpointTest.php index 5ba7117a..b91cb5c9 100644 --- a/tests/Unit/Bytecode/WhileCheckpointTest.php +++ b/tests/Unit/Bytecode/WhileCheckpointTest.php @@ -8,8 +8,6 @@ use Phasis\Exceptions\BudgetExceeded; use Phasis\Exceptions\InternalError; use Phasis\Value\JsFunction; -use Phasis\Value\JsNumber; -use Phasis\Value\JsUndefined; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -104,7 +102,7 @@ public static function phpModes(): iterable } #[DataProvider('phpModes')] - public function testGeneratedPhpCountsOnlySuccessfulIterations(bool $continue): void + public function testEffectfulConditionsFallBackAndCountOnlySuccessfulIterations(bool $continue): void { $engine = new Engine(); $body = 'n++;' . ($continue ? 'continue;' : ''); @@ -116,29 +114,16 @@ function condition(n) { conditions++; return n < 1 ? 1 : 0; } . 'let n = 0; while (condition(n)) {' . $body . '} return n; } probe();'); $function = $engine->getGlobalEnv()->get('probe'); self::assertInstanceOf(JsFunction::class, $function); - self::assertInstanceOf(\Closure::class, $function->phpCompiled); + self::assertNull($function->phpCompiled); $engine->eval('conditions = 0'); $engine->setLimit('maxLoopIterations', 1); - $result = ($function->phpCompiled)( - [], - JsUndefined::instance(), - $function->getClosure(), - $engine->getInterpreter(), - $function->phpCompiledNodes, - ); - self::assertSame(1.0, $result->value); + self::assertSame(1, $engine->eval('probe()')); self::assertSame(2.0, $engine->getGlobalEnv()->get('conditions')->value); $engine->eval('conditions = 0'); $engine->setLimit('maxLoopIterations', 0); $this->expectException(InternalError::class); try { - ($function->phpCompiled)( - [], - JsUndefined::instance(), - $function->getClosure(), - $engine->getInterpreter(), - $function->phpCompiledNodes, - ); + $engine->eval('probe()'); } finally { self::assertSame(1.0, $engine->getGlobalEnv()->get('conditions')->value); } @@ -171,15 +156,9 @@ public function testZeroLimitPermitsAnInitiallyFalseLoop(string $tier): void $engine->eval('conditions = 0'); $engine->setLimit('maxLoopIterations', 0); if ($tier === 'php') { - self::assertInstanceOf(\Closure::class, $function->phpCompiled); - $result = ($function->phpCompiled)( - [JsNumber::of(0)], - JsUndefined::instance(), - $function->getClosure(), - $engine->getInterpreter(), - $function->phpCompiledNodes, - ); - self::assertSame(0.0, $result->value); + self::assertNull($function->phpCompiled); + self::assertNotNull($function->compiled); + self::assertSame(0, $engine->eval('probe(0)')); } else { self::assertSame($tier === 'bytecode', $function->compiled !== null); self::assertSame(0, $engine->eval('probe(0)')); @@ -187,7 +166,7 @@ public function testZeroLimitPermitsAnInitiallyFalseLoop(string $tier): void self::assertSame(1.0, $engine->getGlobalEnv()->get('conditions')->value); } - public function testGeneratedPhpBudgetPrecedesTheIterationLimit(): void + public function testEffectfulBudgetActivationFallsBackBeforeTheIterationLimit(): void { $engine = new Engine(); $expire = false; @@ -200,11 +179,11 @@ public function testGeneratedPhpBudgetPrecedesTheIterationLimit(): void . 'let n = 0; while (n < 2) { n++; expireLocal(); } return n; } probe();'); $function = $engine->getGlobalEnv()->get('probe'); self::assertInstanceOf(JsFunction::class, $function); - self::assertInstanceOf(\Closure::class, $function->phpCompiled); + self::assertNull($function->phpCompiled); $engine->setLimit('maxLoopIterations', 1); $expire = true; $this->expectException(BudgetExceeded::class); - ($function->phpCompiled)([], JsUndefined::instance(), $function->getClosure(), $engine->getInterpreter(), $function->phpCompiledNodes); + $engine->eval('probe()'); } public function testBudgetAbortUnwindsInlineFramesAndBypassesJsCatch(): void diff --git a/tests/Unit/Runtime/ObjectLiteralRealmTest.php b/tests/Unit/Runtime/ObjectLiteralRealmTest.php index d3df0966..aeb75810 100644 --- a/tests/Unit/Runtime/ObjectLiteralRealmTest.php +++ b/tests/Unit/Runtime/ObjectLiteralRealmTest.php @@ -78,15 +78,15 @@ function localMethod(value) { } $phpFunction = $foreign->getGlobalEnv()->get('foreignPhpLiteral'); self::assertInstanceOf(JsFunction::class, $phpFunction); - self::assertInstanceOf(\Closure::class, $phpFunction->phpCompiled); - self::assertInstanceOf(\Closure::class, $phpFunction->phpCompiledNumeric); + self::assertNull($phpFunction->phpCompiled); + self::assertNull($phpFunction->phpCompiledNumeric); $phpFunction->phpCompiledNumeric = null; self::assertSame([1, 0], $caller->eval('[localNumeric(1), wrongRealmCalls]')); if (!$budgeted) { foreach (['localStandard', 'localNumeric', 'localMethod'] as $name) { $wrapper = $caller->getGlobalEnv()->get($name); self::assertInstanceOf(JsFunction::class, $wrapper); - self::assertInstanceOf(\Closure::class, $wrapper->phpCompiled, $name); + self::assertNull($wrapper->phpCompiled, $name); } } self::assertSame(0, $caller->getInterpreter()->getCallStack()->depth()); From 1a09c05877c840f442167e6b44a7b768f02a1861 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 06:34:12 +0200 Subject: [PATCH 80/99] Validate TypedArray set bounds before content type --- src/BuiltIn/TypedArray/PrototypeMethods.php | 10 +- tests/Unit/Runtime/TypedArraySetOrderTest.php | 33 +++++ .../fixtures/typed-array-set-order.cjs | 34 ++++++ .../fixtures/typed-array-set-order.json | 114 ++++++++++++++++++ 4 files changed, 186 insertions(+), 5 deletions(-) create mode 100644 tests/Unit/Runtime/TypedArraySetOrderTest.php create mode 100644 tests/Unit/Runtime/fixtures/typed-array-set-order.cjs create mode 100644 tests/Unit/Runtime/fixtures/typed-array-set-order.json diff --git a/src/BuiltIn/TypedArray/PrototypeMethods.php b/src/BuiltIn/TypedArray/PrototypeMethods.php index 8923496b..37c6f31a 100644 --- a/src/BuiltIn/TypedArray/PrototypeMethods.php +++ b/src/BuiltIn/TypedArray/PrototypeMethods.php @@ -76,17 +76,17 @@ function (JsValue $this_, array $args) use ($typeName): JsValue { $source->validateNotDetached(); $srcLen = $source->getLength(); $targetLen = $this_->getLength(); - // Per spec: if one is BigInt and the other is not, throw TypeError. $isBigSrc = $source->isBigIntArray(); + // Per spec: if srcLength + targetOffset > targetLength, throw RangeError. + if ($srcLen + $offset > $targetLen) { + throw new RangeError('Source is too large'); + } + // Bounds errors precede a Number/BigInt content-type mismatch. if ($isBigSrc !== $isBigTarget) { throw new \Phasis\Exceptions\TypeError( 'Cannot mix BigInt and other types, use explicit conversions' ); } - // Per spec: if srcLength + targetOffset > targetLength, throw RangeError. - if ($srcLen + $offset > $targetLen) { - throw new RangeError('Source is too large'); - } // Per spec: if same buffer, clone srcBuffer first. if ($source->getBuffer() === $this_->getBuffer()) { $cached = []; diff --git a/tests/Unit/Runtime/TypedArraySetOrderTest.php b/tests/Unit/Runtime/TypedArraySetOrderTest.php new file mode 100644 index 00000000..e4a6ddda --- /dev/null +++ b/tests/Unit/Runtime/TypedArraySetOrderTest.php @@ -0,0 +1,33 @@ + */ + public static function executionModes(): iterable + { + yield 'VM' => [false]; + yield 'AST' => [true]; + } + + #[DataProvider('executionModes')] + public function testBoundsErrorsPrecedeContentMismatchAfterSourceValidation(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->execFile(__DIR__ . '/fixtures/typed-array-set-order.cjs'); + $observations = $engine->eval('JSON.stringify(typedArraySetOrderObservations)'); + self::assertIsString($observations); + self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/typed-array-set-order.json', $observations); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } +} diff --git a/tests/Unit/Runtime/fixtures/typed-array-set-order.cjs b/tests/Unit/Runtime/fixtures/typed-array-set-order.cjs new file mode 100644 index 00000000..87cd3212 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/typed-array-set-order.cjs @@ -0,0 +1,34 @@ +var typedArraySetOrderObservations = []; +const orderSentinel = {}; +function orderedSet(target, source, offset) { + return target.set(source, offset); +} +function observeSetOrder(label, Target, Source, targetLength, sourceLength, offsetValue, detachSource, throws) { + const target = new Target(targetLength); + const source = new Source(sourceLength); + if (detachSource) source.buffer.transfer(); + const trace = []; + try { + orderedSet(target, source, {valueOf() { + trace.push('offset'); + if (throws) throw orderSentinel; + return offsetValue; + }}); + typedArraySetOrderObservations.push([label, trace, 'returned']); + } catch (error) { + typedArraySetOrderObservations.push([label, trace, + error === orderSentinel ? 'sentinel' : error.name]); + } +} +for (const pair of [[BigInt64Array, Uint8Array], [Uint8Array, BigInt64Array]]) { + const [Target, Source] = pair; + const label = Target.name + ' from ' + Source.name; + observeSetOrder(label + ' oversized', Target, Source, 1, 2, 0, false, false); + observeSetOrder(label + ' offset exceeds range', Target, Source, 1, 1, 1, false, false); + observeSetOrder(label + ' infinite offset', Target, Source, 1, 0, Infinity, false, false); + observeSetOrder(label + ' content mismatch', Target, Source, 1, 1, 0, false, false); + observeSetOrder(label + ' detached oversized source', Target, Source, 1, 2, 0, true, false); + observeSetOrder(label + ' detached source infinite offset', Target, Source, 1, 0, Infinity, true, false); + observeSetOrder(label + ' detached source negative offset', Target, Source, 1, 2, -1, true, false); + observeSetOrder(label + ' throw before detached source', Target, Source, 1, 2, 0, true, true); +} diff --git a/tests/Unit/Runtime/fixtures/typed-array-set-order.json b/tests/Unit/Runtime/fixtures/typed-array-set-order.json new file mode 100644 index 00000000..6b4bb0c1 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/typed-array-set-order.json @@ -0,0 +1,114 @@ +[ + [ + "BigInt64Array from Uint8Array oversized", + [ + "offset" + ], + "RangeError" + ], + [ + "BigInt64Array from Uint8Array offset exceeds range", + [ + "offset" + ], + "RangeError" + ], + [ + "BigInt64Array from Uint8Array infinite offset", + [ + "offset" + ], + "RangeError" + ], + [ + "BigInt64Array from Uint8Array content mismatch", + [ + "offset" + ], + "TypeError" + ], + [ + "BigInt64Array from Uint8Array detached oversized source", + [ + "offset" + ], + "TypeError" + ], + [ + "BigInt64Array from Uint8Array detached source infinite offset", + [ + "offset" + ], + "TypeError" + ], + [ + "BigInt64Array from Uint8Array detached source negative offset", + [ + "offset" + ], + "RangeError" + ], + [ + "BigInt64Array from Uint8Array throw before detached source", + [ + "offset" + ], + "sentinel" + ], + [ + "Uint8Array from BigInt64Array oversized", + [ + "offset" + ], + "RangeError" + ], + [ + "Uint8Array from BigInt64Array offset exceeds range", + [ + "offset" + ], + "RangeError" + ], + [ + "Uint8Array from BigInt64Array infinite offset", + [ + "offset" + ], + "RangeError" + ], + [ + "Uint8Array from BigInt64Array content mismatch", + [ + "offset" + ], + "TypeError" + ], + [ + "Uint8Array from BigInt64Array detached oversized source", + [ + "offset" + ], + "TypeError" + ], + [ + "Uint8Array from BigInt64Array detached source infinite offset", + [ + "offset" + ], + "TypeError" + ], + [ + "Uint8Array from BigInt64Array detached source negative offset", + [ + "offset" + ], + "RangeError" + ], + [ + "Uint8Array from BigInt64Array throw before detached source", + [ + "offset" + ], + "sentinel" + ] +] From 2d9b2f95abf02fd6943de1ea782d0774df104874 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 06:39:42 +0200 Subject: [PATCH 81/99] Copy matching TypedArray set elements as raw bytes --- src/BuiltIn/TypedArray/PrototypeMethods.php | 24 + .../Runtime/TypedArraySetByteCopyTest.php | 148 +++++ .../fixtures/typed-array-set-byte-copy.cjs | 103 +++ .../fixtures/typed-array-set-byte-copy.json | 607 ++++++++++++++++++ 4 files changed, 882 insertions(+) create mode 100644 tests/Unit/Runtime/TypedArraySetByteCopyTest.php create mode 100644 tests/Unit/Runtime/fixtures/typed-array-set-byte-copy.cjs create mode 100644 tests/Unit/Runtime/fixtures/typed-array-set-byte-copy.json diff --git a/src/BuiltIn/TypedArray/PrototypeMethods.php b/src/BuiltIn/TypedArray/PrototypeMethods.php index 37c6f31a..6495424f 100644 --- a/src/BuiltIn/TypedArray/PrototypeMethods.php +++ b/src/BuiltIn/TypedArray/PrototypeMethods.php @@ -87,6 +87,30 @@ function (JsValue $this_, array $args) use ($typeName): JsValue { 'Cannot mix BigInt and other types, use explicit conversions' ); } + // Matching element types preserve stored bits, including NaN payloads. + if ( + get_class($this_) === JsTypedArray::class && get_class($source) === JsTypedArray::class + && $source->getTypeName() === $this_->getTypeName() + ) { + $sourceBuffer = $source->getBuffer(); + $targetBuffer = $this_->getBuffer(); + if ( + get_class($sourceBuffer) === JsArrayBuffer::class + && get_class($targetBuffer) === JsArrayBuffer::class + && !$sourceBuffer->isResizable() && !$targetBuffer->isResizable() + && !$sourceBuffer->isDetached() && !$targetBuffer->isDetached() + && !$source->isOutOfBounds() && !$this_->isOutOfBounds() + ) { + $width = $source->getBytesPerElement(); + $byteLength = $srcLen * $width; + // Snapshot first so overlapping views preserve set's source bytes. + $bytes = $sourceBuffer->readBytes($source->getByteOffset(), $byteLength); + if (strlen($bytes) === $byteLength) { + $targetBuffer->writeBytes($this_->getByteOffset() + $offset * $width, $bytes); + return JsUndefined::instance(); + } + } + } // Per spec: if same buffer, clone srcBuffer first. if ($source->getBuffer() === $this_->getBuffer()) { $cached = []; diff --git a/tests/Unit/Runtime/TypedArraySetByteCopyTest.php b/tests/Unit/Runtime/TypedArraySetByteCopyTest.php new file mode 100644 index 00000000..b7bd135d --- /dev/null +++ b/tests/Unit/Runtime/TypedArraySetByteCopyTest.php @@ -0,0 +1,148 @@ + */ + public static function executionModes(): iterable + { + yield 'VM' => [false]; + yield 'AST' => [true]; + } + + #[DataProvider('executionModes')] + public function testByteCopiesAndFallbacksMatchNode(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $engine->execFile(__DIR__ . '/fixtures/typed-array-set-byte-copy.cjs'); + $observations = $engine->eval('JSON.stringify(typedArraySetObservations)'); + self::assertIsString($observations); + self::assertJsonStringEqualsJsonFile(__DIR__ . '/fixtures/typed-array-set-byte-copy.json', $observations); + self::assertSame(0, $engine->getInterpreter()->getCallStack()->depth()); + } + + public function testHostViewsAndBuffersKeepTheirElementHooks(): void + { + $engine = new Engine(); + $constructor = $engine->getGlobalEnv()->get('Uint8Array'); + self::assertInstanceOf(JsFunction::class, $constructor); + $viewPrototype = $constructor->get('prototype'); + self::assertInstanceOf(JsObject::class, $viewPrototype); + $bufferPrototype = $engine->getGlobalEnv()->getIntrinsic('ArrayBuffer.prototype'); + self::assertInstanceOf(JsObject::class, $bufferPrototype); + $sourceBuffer = new JsArrayBuffer(2, $bufferPrototype); + $sourceBuffer->setData("\x01\x02"); + $hostSource = new class ('Uint8Array', $sourceBuffer, 0, 2, $viewPrototype) extends JsTypedArray { + public int $reads = 0; + + public function getIndex(int $index): JsValue + { + ++$this->reads; + return parent::getIndex($index); + } + }; + $targetBuffer = new JsArrayBuffer(2, $bufferPrototype); + $target = new JsTypedArray('Uint8Array', $targetBuffer, 0, 2, $viewPrototype); + $engine->getGlobalEnv()->defineVar('source', $hostSource); + $engine->getGlobalEnv()->defineVar('target', $target); + $engine->eval('target.set(source);'); + self::assertSame("\x01\x02", $targetBuffer->getData()); + self::assertSame(2, $hostSource->reads); + + $hostTarget = new class ('Uint8Array', $targetBuffer, 0, 2, $viewPrototype) extends JsTypedArray { + public int $writes = 0; + + public function setIndex(int $index, JsValue $value): void + { + ++$this->writes; + parent::setIndex($index, $value); + } + }; + $engine->getGlobalEnv()->defineVar('source', new JsTypedArray('Uint8Array', $sourceBuffer, 0, 2, $viewPrototype)); + $engine->getGlobalEnv()->defineVar('target', $hostTarget); + $engine->eval('target.set(source);'); + self::assertSame(2, $hostTarget->writes); + + $hostSourceBuffer = new class (2, $bufferPrototype) extends JsArrayBuffer { + public int $reads = 0; + + public function readBytes(int $offset, int $length): string + { + ++$this->reads; + return parent::readBytes($offset, $length); + } + }; + $hostSourceBuffer->setData("\x03\x04"); + $engine->getGlobalEnv()->defineVar('source', new JsTypedArray('Uint8Array', $hostSourceBuffer, 0, 2, $viewPrototype)); + $engine->getGlobalEnv()->defineVar('target', $target); + $engine->eval('target.set(source);'); + self::assertSame("\x03\x04", $targetBuffer->getData()); + self::assertSame(2, $hostSourceBuffer->reads); + + $hostTargetBuffer = new class (2, $bufferPrototype) extends JsArrayBuffer { + public int $writes = 0; + + public function writeBytes(int $offset, string $bytes): void + { + ++$this->writes; + parent::writeBytes($offset, $bytes); + } + }; + $engine->getGlobalEnv()->defineVar('source', new JsTypedArray('Uint8Array', $sourceBuffer, 0, 2, $viewPrototype)); + $engine->getGlobalEnv()->defineVar('target', new JsTypedArray('Uint8Array', $hostTargetBuffer, 0, 2, $viewPrototype)); + $engine->eval('target.set(source);'); + self::assertSame("\x01\x02", $hostTargetBuffer->getData()); + self::assertSame(2, $hostTargetBuffer->writes); + } + + public function testImmutableTargetRejectsBeforeOffsetCoercionAndImmutableSourceCanBeRead(): void + { + $engine = new Engine(); + self::assertSame([true, 0, [1, 2], [0, 1, 2, 0]], $engine->eval(<<<'JS' +const immutable = new Uint8Array([1, 2]).buffer.sliceToImmutable(0); +const source = new Uint8Array(immutable); +const target = new Uint8Array(4); +let calls = 0, threw = false; +try { source.set(new Uint8Array([9]), {valueOf() {calls++; return 0;}}); } +catch (error) {threw = error instanceof TypeError;} +target.set(source, 1); +[threw, calls, Array.from(source), Array.from(target)]; +JS)); + } + + public function testForeignNativeMethodAndViewsKeepTheirRealms(): void + { + $foreign = new Engine(); + $foreign->eval('var source = new Uint8Array([1, 2]); var setter = Uint8Array.prototype.set;'); + $caller = new Engine(); + foreach (['source', 'setter'] as $name) { + $caller->getGlobalEnv()->defineVar($name, $foreign->getGlobalEnv()->get($name)); + } + $sourcePrototype = $foreign->getGlobalEnv()->getIntrinsic('Uint8Array.prototype'); + self::assertInstanceOf(JsObject::class, $sourcePrototype); + $caller->getGlobalEnv()->defineVar('sourcePrototype', $sourcePrototype); + $sibling = new Engine(); + $sibling->eval('new Uint8Array(1);'); + self::assertSame([true, [0, 1, 2, 0], true, true], $caller->eval(<<<'JS' +const target = new Uint8Array(4); +const result = setter.call(target, source, 1); +[result === undefined, Array.from(target), Object.getPrototypeOf(source) === sourcePrototype, + Object.getPrototypeOf(target) === Uint8Array.prototype]; +JS)); + } +} diff --git a/tests/Unit/Runtime/fixtures/typed-array-set-byte-copy.cjs b/tests/Unit/Runtime/fixtures/typed-array-set-byte-copy.cjs new file mode 100644 index 00000000..0b465a86 --- /dev/null +++ b/tests/Unit/Runtime/fixtures/typed-array-set-byte-copy.cjs @@ -0,0 +1,103 @@ +var typedArraySetObservations = []; +function setArrayValues(target, source, offset) { + return target.set(source, offset); +} +for (const Type of [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, + Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array]) { + const big = Type === BigInt64Array || Type === BigUint64Array; + const convert = value => big ? BigInt(value) : value; + const sourceBacking = new Type([8, 9, 1, 2, 3, 7].map(convert)); + const source = new Type(sourceBacking.buffer, 2 * Type.BYTES_PER_ELEMENT, 3); + const targetBacking = new Type([6, 6, 6, 6, 6, 6, 6].map(convert)); + const target = new Type(targetBacking.buffer, Type.BYTES_PER_ELEMENT, 5); + const result = setArrayValues(target, source, 1); + typedArraySetObservations.push([Type.name + ' windows', Array.from(targetBacking, String), + Array.from(source, String), result === undefined]); + + const forward = new Type([1, 2, 3, 4, 5, 6].map(convert)); + setArrayValues(forward, new Type(forward.buffer, 0, 4), 1); + const backward = new Type([1, 2, 3, 4, 5, 6].map(convert)); + setArrayValues(backward, new Type(backward.buffer, Type.BYTES_PER_ELEMENT, 4), 0); + setArrayValues(backward, backward, 0); + typedArraySetObservations.push([Type.name + ' overlap', Array.from(forward, String), Array.from(backward, String)]); +} +const sourceWithProperties = new Uint8Array([4, 5, 6]); +const targetWithProperties = new Uint8Array(5); +let publicReads = 0; +for (const key of ['length', 'byteLength', 'byteOffset', 'buffer', 'constructor', Symbol.iterator]) { + for (const view of [sourceWithProperties, targetWithProperties]) { + Object.defineProperty(view, key, {get() {publicReads++; throw new Error('public property read');}}); + } +} +setArrayValues(targetWithProperties, sourceWithProperties, 1); +typedArraySetObservations.push(['public properties', targetWithProperties[1], targetWithProperties[2], + targetWithProperties[3], publicReads]); +const payload = new Uint32Array([0x7fc01234, 0x7fa12345, 0x80000000]); +const floatTarget = new Float32Array(3); +setArrayValues(floatTarget, new Float32Array(payload.buffer), 0); +typedArraySetObservations.push(['float32 bits', Array.from(new Uint32Array(floatTarget.buffer))]); +const overlapPayload = new Uint32Array([0x7fa12345, 0x7fc01234, 0x80000000, 0]); +const overlapFloats = new Float32Array(overlapPayload.buffer); +setArrayValues(overlapFloats, new Float32Array(overlapPayload.buffer, 0, 3), 1); +typedArraySetObservations.push(['overlap float32 bits', Array.from(overlapPayload)]); +const converted = new Uint8Array(3); +setArrayValues(converted, new Int16Array([-1, 257, 300]), 0); +typedArraySetObservations.push(['different types', Array.from(converted)]); +for (const sharedSource of [false, true]) { + const source = new Uint8Array(sharedSource ? new SharedArrayBuffer(3) : new ArrayBuffer(3)); + const target = new Uint8Array(sharedSource ? new ArrayBuffer(5) : new SharedArrayBuffer(5)); + source.set([3, 4, 5]); + setArrayValues(target, source, 1); + typedArraySetObservations.push(['shared ' + (sharedSource ? 'source' : 'target'), Array.from(target)]); +} +const resizableSource = new Uint8Array(new ArrayBuffer(4, {maxByteLength: 8})); +resizableSource.set([1, 2, 3, 4]); +const resizedTarget = new Uint8Array([9, 9, 9, 9, 9, 9]); +setArrayValues(resizedTarget, resizableSource, {valueOf() {resizableSource.buffer.resize(2); return 1;}}); +typedArraySetObservations.push(['resizable source', Array.from(resizedTarget)]); +const resizableTarget = new Uint8Array(new ArrayBuffer(5, {maxByteLength: 8})); +setArrayValues(resizableTarget, new Uint8Array([7, 8]), {valueOf() {resizableTarget.buffer.resize(3); return 1;}}); +typedArraySetObservations.push(['resizable target', Array.from(resizableTarget)]); +const sentinel = {}; +function setFailure(label, target, source, action, offsetValue) { + const trace = []; + const offset = {valueOf() {trace.push('offset'); action(); return offsetValue;}}; + try { + setArrayValues(target, source, offset); + typedArraySetObservations.push([label, trace, 'returned']); + } catch (error) { + typedArraySetObservations.push([label, trace, error === sentinel ? 'sentinel' : error.name]); + } +} +const detachedSource = new Uint8Array(2); +detachedSource.buffer.transfer(); +setFailure('negative before detached source', new Uint8Array(1), detachedSource, () => {}, -1); +setFailure('throw before detached source', new Uint8Array(1), detachedSource, () => {throw sentinel;}, 0); +const detachTarget = new Uint8Array(2); +setFailure('detach target in offset', detachTarget, new Uint8Array([1]), () => {detachTarget.buffer.transfer();}, 0); +const detachSource = new Uint8Array(2); +setFailure('detach source in offset', new Uint8Array(2), detachSource, () => {detachSource.buffer.transfer();}, 0); +const shrinkSource = new Uint8Array(new ArrayBuffer(4, {maxByteLength: 8}), 0, 4); +setFailure('source out of bounds after offset', new Uint8Array(4), shrinkSource, + () => {shrinkSource.buffer.resize(2);}, 0); +setFailure('mixed content before size', new BigInt64Array(1), new Uint8Array(2), () => {}, 0); +setFailure('range', new Uint8Array(1), new Uint8Array(2), () => {}, 0); +setFailure('infinite offset', new Uint8Array(2), new Uint8Array(0), () => {}, Infinity); +const fractional = new Uint8Array(4); +setArrayValues(fractional, new Uint8Array([7, 8]), 1.9); +setArrayValues(fractional, new Uint8Array([6]), -0); +typedArraySetObservations.push(['fractional and negative zero', Array.from(fractional), + setArrayValues(fractional, new Uint8Array(0), 4) === undefined]); +const changedSource = new Uint8Array([1, 2]); +const changedTarget = new Uint8Array(4); +let offsetCalls = 0; +setArrayValues(changedTarget, changedSource, {valueOf() {offsetCalls++; changedSource[0] = 7; return 1;}}); +typedArraySetObservations.push(['offset mutation', offsetCalls, Array.from(changedTarget)]); +const arrayLikeTrace = []; +const arrayLikeTarget = new Uint8Array(3); +setArrayValues(arrayLikeTarget, { + get length() {arrayLikeTrace.push('length'); return 2;}, + get 0() {arrayLikeTrace.push('0'); return 257;}, + get 1() {arrayLikeTrace.push('1'); return -1;} +}, {valueOf() {arrayLikeTrace.push('offset'); return 1;}}); +typedArraySetObservations.push(['array-like fallback', arrayLikeTrace, Array.from(arrayLikeTarget)]); diff --git a/tests/Unit/Runtime/fixtures/typed-array-set-byte-copy.json b/tests/Unit/Runtime/fixtures/typed-array-set-byte-copy.json new file mode 100644 index 00000000..f44a008e --- /dev/null +++ b/tests/Unit/Runtime/fixtures/typed-array-set-byte-copy.json @@ -0,0 +1,607 @@ +[ + [ + "Int8Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Int8Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "Uint8Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Uint8Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "Uint8ClampedArray windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Uint8ClampedArray overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "Int16Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Int16Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "Uint16Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Uint16Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "Int32Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Int32Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "Uint32Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Uint32Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "Float16Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Float16Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "Float32Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Float32Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "Float64Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "Float64Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "BigInt64Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "BigInt64Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "BigUint64Array windows", + [ + "6", + "6", + "1", + "2", + "3", + "6", + "6" + ], + [ + "1", + "2", + "3" + ], + true + ], + [ + "BigUint64Array overlap", + [ + "1", + "1", + "2", + "3", + "4", + "6" + ], + [ + "2", + "3", + "4", + "5", + "5", + "6" + ] + ], + [ + "public properties", + 4, + 5, + 6, + 0 + ], + [ + "float32 bits", + [ + 2143294004, + 2141266757, + 2147483648 + ] + ], + [ + "overlap float32 bits", + [ + 2141266757, + 2141266757, + 2143294004, + 2147483648 + ] + ], + [ + "different types", + [ + 255, + 1, + 44 + ] + ], + [ + "shared target", + [ + 0, + 3, + 4, + 5, + 0 + ] + ], + [ + "shared source", + [ + 0, + 3, + 4, + 5, + 0 + ] + ], + [ + "resizable source", + [ + 9, + 1, + 2, + 9, + 9, + 9 + ] + ], + [ + "resizable target", + [ + 0, + 7, + 8 + ] + ], + [ + "negative before detached source", + [ + "offset" + ], + "RangeError" + ], + [ + "throw before detached source", + [ + "offset" + ], + "sentinel" + ], + [ + "detach target in offset", + [ + "offset" + ], + "TypeError" + ], + [ + "detach source in offset", + [ + "offset" + ], + "TypeError" + ], + [ + "source out of bounds after offset", + [ + "offset" + ], + "TypeError" + ], + [ + "mixed content before size", + [ + "offset" + ], + "RangeError" + ], + [ + "range", + [ + "offset" + ], + "RangeError" + ], + [ + "infinite offset", + [ + "offset" + ], + "RangeError" + ], + [ + "fractional and negative zero", + [ + 6, + 7, + 8, + 0 + ], + true + ], + [ + "offset mutation", + 1, + [ + 0, + 7, + 2, + 0 + ] + ], + [ + "array-like fallback", + [ + "offset", + "length", + "0", + "1" + ], + [ + 0, + 1, + 255 + ] + ] +] From c5863729a73950c2e6c7e5caee06cc04c26ae4ad Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 06:46:40 +0200 Subject: [PATCH 82/99] Clear completed frame slots with a bulk allocation --- src/Bytecode/Frame.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Bytecode/Frame.php b/src/Bytecode/Frame.php index b0258fd0..455a3946 100644 --- a/src/Bytecode/Frame.php +++ b/src/Bytecode/Frame.php @@ -89,10 +89,7 @@ public function release(JsValue $undefined): void { unset($this->env); $this->thisValue = $undefined; - $count = count($this->locals); - for ($i = 0; $i < $count; $i++) { - $this->locals[$i] = $undefined; - } + $this->locals = array_fill(0, count($this->locals), $undefined); $this->stack = []; $this->sp = 0; } From 397242146644d4705824cfccbbd8a975a5f1db20 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 06:46:59 +0200 Subject: [PATCH 83/99] Document caller tracking and typed-array copy fixes --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e051498..5456f619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,9 @@ - Array literals and built-in array results retain their realm's intrinsic prototype when the global Array constructor is replaced. - Compiled identifier updates and strict program assignments retain their original references through coercion and right-hand-side effects. - Generated PHP preserves numeric truthiness and literal precision, evaluates operands once, and falls back before observable effects. +- Calls, getters and constructors retain caller and argument records; non-callable errors do not invoke object conversion hooks. - Same-type typed-array copies preserve byte payloads and prototype-validation order; host byte views and inlined callbacks retain their defining realms. +- Typed-array `set` checks bounds before content-type mismatches and copies matching native element types without changing stored bits. - Stream controllers, readers and writers retain their originating realm after VM context creation; pending Promise finalizers retain their registered async context. - Temporal calendar fields, arithmetic, rounding, parsing, timezone boundaries, and Intl formatting use consistent calendar data and option validation. - Module evaluation, source and typed imports, resource disposal, cross-realm intrinsics, numeric serialization, and compiled global bindings follow current language semantics. @@ -30,10 +32,11 @@ ### Changed - Bytecode compilation handles captured bindings, default initializers, array bindings and assignments, optional chains, spread calls, computed methods, object prototypes, regular-expression literals and strict tail calls; reusable syntax templates keep closure state separate. - Proven disjoint lexical scopes reuse frame slots, ordinary function prototypes materialize when observed, and numeric typed-array writes avoid redundant conversions while retaining buffer-resize and detachment behavior. +- Completed frames clear their local slots in one allocation while releasing activation references. - Protected returns preserve finalizer completion order in bytecode, and logical assignments and object relational operators use the shared JavaScript semantics. - Bounded regular-expression preparation and cached UTF-16 searches reduce repeated work while preserving fresh objects and observable coercions. - The test262 runner executes both variants of unflagged scripts, preserves raw sources and module parse goals, requires async completion, and checks negative-test error types and phases. -- Compatibility shards retain full file manifests; merging rejects overlapping or stale results and keeps missing coverage visible. Incomplete or failing coverage cannot round up to 100%. +- Compatibility shards retain full file manifests; merging rejects overlapping or stale results and keeps missing coverage visible. Incomplete or failing coverage cannot round up to 100%; the canonical workflow fails on nonpassing results after preserving the report. ## [0.8.0] - 2026-10-16 From eae33b52dfb2b46dfea57d24777005275d96d023 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 24 Oct 2026 05:12:15 +0000 Subject: [PATCH 84/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 54 ++++++++-------- compat.json | 175 ++++++++++++++++++++++++++-------------------------- 2 files changed, 113 insertions(+), 116 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index f68d86ad..696a27cb 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,19 +3,19 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-24T03:35:26+00:00` +- Snapshot time: `2026-10-24T05:12:14+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `aec1e4fc` (dirty) +- Git: `feat/express-hono-compatibility` @ `39724214` (dirty) ## Summary | Pass | Fail | Skip | Blocked | Pending | Running | Attempted | Known | Total | Pass Rate | |---:|---:|---:|---:|---:|---:|---:|---:|---:|---:| -| 53615 | 1 | 0 | 0 | 0 | 0 | 53616 | 53616 | 53616 | 99.9% | +| 53616 | 0 | 0 | 0 | 0 | 0 | 53616 | 53616 | 53616 | 100.0% | ## Top-Level Areas @@ -26,7 +26,7 @@ Generated from a completed `test262` pass. Do not edit by hand. | harness | PASS | 116 | 0 | 0 | 0 | 0 | 0 | 100.0% | | intl402 | PASS | 3382 | 0 | 0 | 0 | 0 | 0 | 100.0% | | language | PASS | 23726 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| staging | PARTIAL | 1482 | 1 | 0 | 0 | 0 | 0 | 99.9% | +| staging | PASS | 1483 | 0 | 0 | 0 | 0 | 0 | 100.0% | ## Group Coverage @@ -190,38 +190,34 @@ Generated from a completed `test262` pass. Do not edit by hand. | staging/decorators | PASS | 3 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/explicit-resource-management | PASS | 53 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/set-methods | PASS | 3 | 0 | 0 | 0 | 0 | 0 | 100.0% | -| staging/sm | PARTIAL | 1405 | 1 | 0 | 0 | 0 | 0 | 99.9% | +| staging/sm | PASS | 1406 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/source-phase-imports | PASS | 2 | 0 | 0 | 0 | 0 | 0 | 100.0% | | staging/top-level-await | PASS | 1 | 0 | 0 | 0 | 0 | 0 | 100.0% | -## Failing Tests - -1 individual failure paths and messages are recorded in [compat.json](compat.json) under `test262.failures`. - ## Slowest Chunks | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| staging/sm | NORMAL | 179.254s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 178.090s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 176.536s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 176.085s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 173.926s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 171.558s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| staging/sm | NORMAL | 168.036s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| staging/sm | NORMAL | 142.027s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| staging/sm | NORMAL | 134.787s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| staging/sm | NORMAL | 116.164s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| built-ins/decodeURIComponent | NORMAL | 90.181s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| intl402 | NORMAL | 85.375s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | -| built-ins/decodeURI | NORMAL | 81.845s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| built-ins/TypedArray | NORMAL | 71.484s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | -| intl402/DateTimeFormat | NORMAL | 66.465s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | -| annexB/built-ins/RegExp | NORMAL | 65.097s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 57.998s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Newa.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nko.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nushu.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 57.442s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Grapheme_Extend.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Hex_Digit.js`
`test262/test/built-ins/RegExp/property-escapes/generated/IDS_Binary_Operator.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 56.915s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Myanmar.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nabataean.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nag_Mundari.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 56.881s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Math.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Noncharacter_Code_Point.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Pattern_Syntax.js` | +| staging/sm | NORMAL | 187.136s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 182.278s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 179.007s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 178.499s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 178.458s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 171.051s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| staging/sm | NORMAL | 169.255s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| built-ins/decodeURIComponent | NORMAL | 166.512s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| staging/sm | NORMAL | 148.758s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| built-ins/decodeURI | NORMAL | 143.603s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| staging/sm | NORMAL | 138.609s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 122.550s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| intl402 | NORMAL | 87.509s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | +| language/literals | NORMAL | 80.139s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | +| built-ins/decodeURI | NORMAL | 74.946s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | +| built-ins/decodeURIComponent | NORMAL | 74.730s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | +| built-ins/TypedArray | NORMAL | 71.508s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | +| intl402/DateTimeFormat | NORMAL | 68.375s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | +| annexB/built-ins/RegExp | NORMAL | 63.498s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.922s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 94635e8e..ba9ab4a0 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-24T03:35:26+00:00", - "updatedAt": "2026-10-24T03:35:26+00:00", + "generatedAt": "2026-10-24T05:12:14+00:00", + "updatedAt": "2026-10-24T05:12:14+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "aec1e4fc", + "commit": "39724214", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "49c5bdc6a14925b427e8b6b520056b235fec8b9f", - "runIdentity": "263ce79594262b0119bfbc48ce283698aac3faad57f84ce8d3a2d2d0a1522562" + "fingerprint": "854fe5d604c4e4242d6895d002c533834ad815d7", + "runIdentity": "94e3b04d57ecbc5f3d5d44387f054fad3f92fffd8a2979bc45632c4bd6b7f90c" }, "discovery": { "groupCount": 161, @@ -199,8 +199,8 @@ "test262": { "skippedFeatures": [], "totals": { - "pass": 53615, - "fail": 1, + "pass": 53616, + "fail": 0, "skip": 0, "blocked": 0, "pending": 0, @@ -208,7 +208,7 @@ "attempted": 53616, "known": 53616, "total": 53616, - "passRate": 99.9 + "passRate": 100 }, "areas": [ { @@ -283,9 +283,9 @@ }, { "name": "staging", - "status": "partial", - "pass": 1482, - "fail": 1, + "status": "pass", + "pass": 1483, + "fail": 0, "skip": 0, "blocked": 0, "pending": 0, @@ -293,7 +293,7 @@ "attempted": 1483, "known": 1483, "total": 1483, - "passRate": 99.9 + "passRate": 100 } ], "groups": [ @@ -2670,9 +2670,9 @@ { "name": "staging/sm", "area": "staging", - "status": "partial", - "pass": 1405, - "fail": 1, + "status": "pass", + "pass": 1406, + "fail": 0, "skip": 0, "blocked": 0, "pending": 0, @@ -2680,7 +2680,7 @@ "attempted": 1406, "known": 1406, "total": 1406, - "passRate": 99.9 + "passRate": 100 }, { "name": "staging/source-phase-imports", @@ -2713,27 +2713,22 @@ "passRate": 100 } ], - "failures": [ - { - "path": "test262/test/staging/sm/extensions/function-caller-skips-eval-frames.js", - "message": "runtime: Phasis\\Exceptions\\JsThrowable: Expected SameValue(\u00abnull\u00bb, \u00abfunction nest2() { return nest(); }\u00bb) to be true" - } - ], + "failures": [], "blockedChunks": [], "slowChunks": [ { "group": "staging/sm", "kind": "normal", - "durationSec": 179.254, + "durationSec": 187.136, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 178.09, + "durationSec": 182.278, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" @@ -2742,25 +2737,25 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 176.536, + "durationSec": 179.007, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 176.085, + "durationSec": 178.499, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 173.926, + "durationSec": 178.458, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" @@ -2769,61 +2764,70 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 171.558, + "durationSec": 171.051, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 168.036, + "durationSec": 169.255, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + ] + }, + { + "group": "built-ins/decodeURIComponent", + "kind": "normal", + "durationSec": 166.512, + "filesCount": 1, + "sampleFiles": [ + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 142.027, + "durationSec": 148.758, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { - "group": "staging/sm", + "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 134.787, + "durationSec": 143.603, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 116.164, + "durationSec": 138.609, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" ] }, { - "group": "built-ins/decodeURIComponent", + "group": "staging/sm", "kind": "normal", - "durationSec": 90.181, + "durationSec": 122.55, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { "group": "intl402", "kind": "normal", - "durationSec": 85.375, + "durationSec": 87.509, "filesCount": 22, "sampleFiles": [ "test262/test/intl402/constructors-string-and-single-element-array.js", @@ -2833,19 +2837,49 @@ "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" ] }, + { + "group": "language/literals", + "kind": "normal", + "durationSec": 80.139, + "filesCount": 25, + "sampleFiles": [ + "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", + "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", + "...", + "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", + "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" + ] + }, { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 81.845, - "filesCount": 1, + "durationSec": 74.946, + "filesCount": 25, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", + "...", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" + ] + }, + { + "group": "built-ins/decodeURIComponent", + "kind": "normal", + "durationSec": 74.73, + "filesCount": 25, + "sampleFiles": [ + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", + "...", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" ] }, { "group": "built-ins/TypedArray", "kind": "normal", - "durationSec": 71.484, + "durationSec": 71.508, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", @@ -2858,7 +2892,7 @@ { "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 66.465, + "durationSec": 68.375, "filesCount": 12, "sampleFiles": [ "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", @@ -2871,7 +2905,7 @@ { "group": "annexB/built-ins/RegExp", "kind": "normal", - "durationSec": 65.097, + "durationSec": 63.498, "filesCount": 25, "sampleFiles": [ "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", @@ -2884,45 +2918,12 @@ { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 57.998, - "filesCount": 3, - "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Newa.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nko.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nushu.js" - ] - }, - { - "group": "built-ins/RegExp/property-escapes/generated", - "kind": "normal", - "durationSec": 57.442, - "filesCount": 3, - "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Grapheme_Extend.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Hex_Digit.js", - "test262/test/built-ins/RegExp/property-escapes/generated/IDS_Binary_Operator.js" - ] - }, - { - "group": "built-ins/RegExp/property-escapes/generated", - "kind": "normal", - "durationSec": 56.915, - "filesCount": 3, - "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Myanmar.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nabataean.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Nag_Mundari.js" - ] - }, - { - "group": "built-ins/RegExp/property-escapes/generated", - "kind": "normal", - "durationSec": 56.881, + "durationSec": 59.922, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Math.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Noncharacter_Code_Point.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Pattern_Syntax.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js" ] } ] From 0222e6c6b8553f8c893320f73a2c263640998085 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 07:10:41 +0200 Subject: [PATCH 85/99] Keep host descriptor callbacks outside generated preflight --- src/Runtime/Environment.php | 9 +++- .../Bytecode/GeneratedDataBindingTest.php | 52 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/Unit/Bytecode/GeneratedDataBindingTest.php diff --git a/src/Runtime/Environment.php b/src/Runtime/Environment.php index c548c792..83e0a789 100644 --- a/src/Runtime/Environment.php +++ b/src/Runtime/Environment.php @@ -562,7 +562,10 @@ public function getDataBinding(string $name): ?JsValue private static function ordinaryDataValue(\Phasis\Value\JsObject $object, string $name): ?JsValue { - if (get_class($object) !== \Phasis\Value\JsObject::class) { + if ( + get_class($object) !== \Phasis\Value\JsObject::class + || get_class($object->properties) !== \Phasis\Object\PropertyMap::class + ) { return null; } $value = $object->properties->dataSlots[$name] ?? null; @@ -570,7 +573,9 @@ private static function ordinaryDataValue(\Phasis\Value\JsObject $object, string return $value; } $descriptor = $object->properties->descriptors[$name] ?? null; - return $descriptor !== null && $descriptor->isDataDescriptor() ? $descriptor->value : null; + return $descriptor !== null + && get_class($descriptor) === \Phasis\Object\PropertyDescriptor::class + && $descriptor->isDataDescriptor() ? $descriptor->value : null; } public function get( diff --git a/tests/Unit/Bytecode/GeneratedDataBindingTest.php b/tests/Unit/Bytecode/GeneratedDataBindingTest.php new file mode 100644 index 00000000..80cf1984 --- /dev/null +++ b/tests/Unit/Bytecode/GeneratedDataBindingTest.php @@ -0,0 +1,52 @@ + */ + public static function entries(): iterable + { + yield 'cold' => [false]; + yield 'cached' => [true]; + } + + #[DataProvider('entries')] + public function testGlobalReadsDoNotInvokeHostDescriptorMetadata(bool $warm): void + { + $engine = new Engine(); + $engine->eval('var captured = 7; function readCaptured() { return captured; }'); + if ($warm) { + self::assertSame(7, $engine->eval('readCaptured();')); + } + + $descriptor = new class (value: JsNumber::of(19), writable: false) extends PropertyDescriptor { + public int $metadataReads = 0; + + public function isDataDescriptor(): bool + { + ++$this->metadataReads; + return parent::isDataDescriptor(); + } + }; + $global = $engine->getGlobalEnv()->getLinkedObject(); + self::assertNotNull($global); + $global->properties->set('captured', $descriptor); + + self::assertSame(19, $engine->eval('readCaptured();')); + self::assertSame(19, $engine->eval('readCaptured();')); + self::assertSame(0, $descriptor->metadataReads); + $function = $engine->getGlobalEnv()->get('readCaptured'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + } +} From dbd441a449830d5ba17dd06836d61a9bce218f65 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 07:49:30 +0200 Subject: [PATCH 86/99] Avoid redundant initial function descriptor allocation --- src/Value/JsFunction.php | 20 +- .../Runtime/FreshFunctionDescriptorsTest.php | 153 ++++ .../fresh-function-descriptors.expected.json | 693 ++++++++++++++++++ .../fixtures/fresh-function-descriptors.js | 65 ++ 4 files changed, 927 insertions(+), 4 deletions(-) create mode 100644 tests/Unit/Runtime/FreshFunctionDescriptorsTest.php create mode 100644 tests/Unit/Runtime/fixtures/fresh-function-descriptors.expected.json create mode 100644 tests/Unit/Runtime/fixtures/fresh-function-descriptors.js diff --git a/src/Value/JsFunction.php b/src/Value/JsFunction.php index 87cfef8d..fdc0bd59 100644 --- a/src/Value/JsFunction.php +++ b/src/Value/JsFunction.php @@ -291,21 +291,33 @@ public function __construct( $length++; } } - $this->defineOwnProperty('length', new \Phasis\Object\PropertyDescriptor( + $lengthDescriptor = new \Phasis\Object\PropertyDescriptor( value: JsNumber::of((float) $length), writable: false, enumerable: false, configurable: true, - )); + ); + // The base constructor just created this map. Host subclasses retain + // their virtual definition hooks, including mutations between fields. + if (get_class($this) === self::class) { + $this->properties->set('length', $lengthDescriptor); + } else { + $this->defineOwnProperty('length', $lengthDescriptor); + } // Per spec, the exposed .name is "" for anonymous functions. // Internally we keep '(anonymous)' as a sentinel for name inference. $exposedName = $name === '(anonymous)' ? '' : $name; - $this->defineOwnProperty('name', new \Phasis\Object\PropertyDescriptor( + $nameDescriptor = new \Phasis\Object\PropertyDescriptor( value: new JsString($exposedName), writable: false, enumerable: false, configurable: true, - )); + ); + if (get_class($this) === self::class) { + $this->properties->set('name', $nameDescriptor); + } else { + $this->defineOwnProperty('name', $nameDescriptor); + } } /** diff --git a/tests/Unit/Runtime/FreshFunctionDescriptorsTest.php b/tests/Unit/Runtime/FreshFunctionDescriptorsTest.php new file mode 100644 index 00000000..5623331d --- /dev/null +++ b/tests/Unit/Runtime/FreshFunctionDescriptorsTest.php @@ -0,0 +1,153 @@ + */ + public static function modes(): iterable + { + yield 'ordinary' => [false]; + yield 'budgeted' => [true]; + } + + #[DataProvider('modes')] + public function testFunctionMetadataMatchesNode(bool $budgeted): void + { + $engine = new Engine(); + if ($budgeted) { + $engine->setExecutionBudget(10); + } + $source = file_get_contents(__DIR__ . '/fixtures/fresh-function-descriptors.js'); + $oracle = file_get_contents(__DIR__ . '/fixtures/fresh-function-descriptors.expected.json'); + self::assertIsString($source); + self::assertIsString($oracle); + $engine->eval($source); + $actual = $engine->eval('JSON.stringify(freshFunctionDescriptors)'); + self::assertIsString($actual); + self::assertSame( + self::comparableMetadata(json_decode($oracle, true, flags: JSON_THROW_ON_ERROR)), + self::comparableMetadata(json_decode($actual, true, flags: JSON_THROW_ON_ERROR)), + ); + } + + /** + * Full Annex B own-key differences remain in the raw Node and baseline + * snapshots. This oracle assertion covers metadata and its relative order. + */ + private static function comparableMetadata(mixed $value): mixed + { + if (!is_array($value)) { + return $value; + } + unset($value['keys']); + foreach ($value as $key => $item) { + $value[$key] = self::comparableMetadata($item); + } + return $value; + } + + public function testInitialDescriptorsHaveIndependentState(): void + { + $first = new JsFunction('first', [null, null], null, new Environment()); + $second = new JsFunction('second', [null, null], null, new Environment()); + self::assertSame(['length', 'name'], $first->getOwnPropertyNames()); + $firstLength = $first->getOwnPropertyDescriptor('length'); + $secondLength = $second->getOwnPropertyDescriptor('length'); + $firstName = $first->getOwnPropertyDescriptor('name'); + $secondName = $second->getOwnPropertyDescriptor('name'); + self::assertNotNull($firstLength); + self::assertNotNull($secondLength); + self::assertNotNull($firstName); + self::assertNotNull($secondName); + self::assertNotSame($firstLength, $secondLength); + self::assertNotSame($firstName, $secondName); + self::assertFalse($firstLength->writable); + self::assertFalse($firstLength->enumerable); + self::assertTrue($firstLength->configurable); + $firstLength->value = JsNumber::of(19); + $firstName->configurable = false; + self::assertSame(19.0, $first->get('length')->toNumber()); + self::assertFalse($first->getOwnPropertyDescriptor('name')?->configurable); + self::assertSame(2.0, $second->get('length')->toNumber()); + self::assertTrue($secondName->configurable); + self::assertSame('second', TypeConversion::toString($second->get('name'))); + } + + public function testHostSubclassDefinitionHooksKeepTheirOrderAndEffects(): void + { + $function = new class ('provided', [null, null], null, new Environment()) extends JsFunction { + /** @var list}> */ + public array $observations = []; + + public function defineOwnProperty(string $name, PropertyDescriptor $descriptor): bool + { + $this->observations[] = [$name, $this->getOwnPropertyNames()]; + if ($name === 'length') { + $descriptor->value = JsNumber::of(7); + parent::defineOwnProperty('name', PropertyDescriptor::data( + new JsString('host'), + false, + false, + false, + )); + } + return parent::defineOwnProperty($name, $descriptor); + } + }; + self::assertSame([['length', []], ['name', ['name', 'length']]], $function->observations); + self::assertSame(['name', 'length'], $function->getOwnPropertyNames()); + self::assertSame(7.0, $function->get('length')->toNumber()); + self::assertSame('host', TypeConversion::toString($function->get('name'))); + self::assertFalse($function->getOwnPropertyDescriptor('name')?->configurable); + } + + #[DataProvider('modes')] + public function testSiblingAndForeignConstructorsKeepTheirRealm(bool $budgeted): void + { + $foreign = new Engine(); + if ($budgeted) { + $foreign->setExecutionBudget(10); + } + $foreign->eval(<<<'JS' +var foreignFunctionConstructor = Function; +var foreignFunctionPrototype = Function.prototype; +var foreignObjectPrototype = Object.prototype; +JS); + $caller = new Engine(); + if ($budgeted) { + $caller->setExecutionBudget(10); + } + self::assertSame([true, true, true, 2, 1, 1, 'named', 'arrow', 'anonymous'], $foreign->eval(<<<'JS' +function named(a, b) {} +var arrow = a => a; +var dynamic = Function('a', 'b = 1', 'return a + b'); +[Object.getPrototypeOf(named) === foreignFunctionPrototype, + Object.getPrototypeOf(arrow) === foreignFunctionPrototype, + Object.getPrototypeOf(dynamic.prototype) === foreignObjectPrototype, + named.length, arrow.length, dynamic.length, named.name, arrow.name, dynamic.name]; +JS)); + foreach (['foreignFunctionConstructor', 'foreignFunctionPrototype', 'foreignObjectPrototype'] as $name) { + $caller->getGlobalEnv()->defineVar($name, $foreign->getGlobalEnv()->get($name)); + } + self::assertSame([true, true, 1, 'anonymous', ['length', 'name']], $caller->eval(<<<'JS' +var foreignCreated = foreignFunctionConstructor('a', 'b = 1', 'return a + b'); +[Object.getPrototypeOf(foreignCreated) === foreignFunctionPrototype, + Object.getPrototypeOf(foreignCreated.prototype) === foreignObjectPrototype, + foreignCreated.length, foreignCreated.name, + Object.getOwnPropertyNames(foreignCreated).filter(key => key === 'length' || key === 'name')]; +JS)); + } +} diff --git a/tests/Unit/Runtime/fixtures/fresh-function-descriptors.expected.json b/tests/Unit/Runtime/fixtures/fresh-function-descriptors.expected.json new file mode 100644 index 00000000..177c305d --- /dev/null +++ b/tests/Unit/Runtime/fixtures/fresh-function-descriptors.expected.json @@ -0,0 +1,693 @@ +{ + "initial": { + "ordinary": { + "name": [ + "ordinary", + false, + false, + true, + false, + false + ], + "length": [ + 2, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "strict": { + "name": [ + "strict", + false, + false, + true, + false, + false + ], + "length": [ + 1, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "defaulted": { + "name": [ + "defaulted", + false, + false, + true, + false, + false + ], + "length": [ + 1, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "restOnly": { + "name": [ + "restOnly", + false, + false, + true, + false, + false + ], + "length": [ + 0, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "destructured": { + "name": [ + "destructured", + false, + false, + true, + false, + false + ], + "length": [ + 2, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "arrow": { + "name": [ + "arrow", + false, + false, + true, + false, + false + ], + "length": [ + 2, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": null, + "extensible": true + }, + "method": { + "name": [ + "method", + false, + false, + true, + false, + false + ], + "length": [ + 2, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": null, + "extensible": true + }, + "getter": { + "name": [ + "get value", + false, + false, + true, + false, + false + ], + "length": [ + 0, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": null, + "extensible": true + }, + "setter": { + "name": [ + "set value", + false, + false, + true, + false, + false + ], + "length": [ + 1, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": null, + "extensible": true + }, + "asyncFunction": { + "name": [ + "asyncFunction", + false, + false, + true, + false, + false + ], + "length": [ + 2, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "async", + "ownPrototype": null, + "extensible": true + }, + "generator": { + "name": [ + "generator", + false, + false, + true, + false, + false + ], + "length": [ + 1, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "generator", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "asyncGenerator": { + "name": [ + "asyncGenerator", + false, + false, + true, + false, + false + ], + "length": [ + 1, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "asyncGenerator", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "Constructor": { + "name": [ + "Constructor", + false, + false, + true, + false, + false + ], + "length": [ + 1, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": [ + "object", + false, + false, + false + ], + "extensible": true + }, + "anonymous": { + "name": [ + "", + false, + false, + true, + false, + false + ], + "length": [ + 1, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "bound": { + "name": [ + "bound ordinary", + false, + false, + true, + false, + false + ], + "length": [ + 1, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": null, + "extensible": true + }, + "native": { + "name": [ + "max", + false, + false, + true, + false, + false + ], + "length": [ + 2, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": null, + "extensible": true + }, + "dynamic": { + "name": [ + "anonymous", + false, + false, + true, + false, + false + ], + "length": [ + 1, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "proxy": { + "name": [ + "ordinary", + false, + false, + true, + false, + false + ], + "length": [ + 2, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "name", + "prototype" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [], + "prototypeKind": "function", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + } + }, + "sloppyWritePreserved": true, + "strictWriteRejected": true, + "changed": { + "name": [ + "renamed", + true, + true, + true, + false, + false + ], + "length": [ + 8, + false, + false, + true, + false, + false + ], + "keys": [ + "length", + "prototype", + "name" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [ + "name" + ], + "prototypeKind": "function", + "ownPrototype": [ + "object", + true, + false, + false + ], + "extensible": true + }, + "frozen": { + "name": [ + "renamed", + false, + true, + false, + false, + false + ], + "length": [ + 8, + false, + false, + false, + false, + false + ], + "keys": [ + "length", + "prototype", + "name" + ], + "initialMetadataOrder": [ + "length", + "name" + ], + "enumerable": [ + "name" + ], + "prototypeKind": "function", + "ownPrototype": [ + "object", + false, + false, + false + ], + "extensible": false + }, + "prototypeIdentity": [ + true, + true, + true + ] +} diff --git a/tests/Unit/Runtime/fixtures/fresh-function-descriptors.js b/tests/Unit/Runtime/fixtures/fresh-function-descriptors.js new file mode 100644 index 00000000..d6ec5d3a --- /dev/null +++ b/tests/Unit/Runtime/fixtures/fresh-function-descriptors.js @@ -0,0 +1,65 @@ +var freshFunctionDescriptors = (() => { + const generatorPrototype = Object.getPrototypeOf(function* () {}); + const asyncPrototype = Object.getPrototypeOf(async function () {}); + const asyncGeneratorPrototype = Object.getPrototypeOf(async function* () {}); + function dataDescriptor(fn, name) { + const descriptor = Object.getOwnPropertyDescriptor(fn, name); + if (!descriptor) return null; + return [descriptor.value, descriptor.writable, descriptor.enumerable, descriptor.configurable, + 'get' in descriptor, 'set' in descriptor]; + } + function snapshot(fn) { + const prototype = Object.getPrototypeOf(fn); + const ownPrototype = Object.getOwnPropertyDescriptor(fn, 'prototype'); + return { + name: dataDescriptor(fn, 'name'), length: dataDescriptor(fn, 'length'), + keys: Reflect.ownKeys(fn).map(key => typeof key === 'symbol' ? String(key) : key), + initialMetadataOrder: Object.getOwnPropertyNames(fn).filter(key => key === 'name' || key === 'length'), + enumerable: Object.keys(fn), + prototypeKind: prototype === Function.prototype ? 'function' + : prototype === generatorPrototype ? 'generator' + : prototype === asyncPrototype ? 'async' + : prototype === asyncGeneratorPrototype ? 'asyncGenerator' : 'other', + ownPrototype: ownPrototype ? [typeof ownPrototype.value, + ownPrototype.writable, ownPrototype.enumerable, ownPrototype.configurable] : null, + extensible: Object.isExtensible(fn) + }; + } + function ordinary(a, b) { return a + b; } + function strict(a) { 'use strict'; return a; } + function defaulted(a, b = 1, ...rest) { return [a, b, rest]; } + function restOnly(...rest) { return rest; } + function destructured({a}, [b]) { return a + b; } + const arrow = (a, b) => a + b; + const object = { method(a, b) {}, get value() { return 1; }, set value(value) {} }; + const getter = Object.getOwnPropertyDescriptor(object, 'value').get; + const setter = Object.getOwnPropertyDescriptor(object, 'value').set; + async function asyncFunction(a, b) { return a + b; } + function* generator(a) { yield a; } + async function* asyncGenerator(a) { yield a; } + class Constructor { constructor(a, b = 0) {} } + const anonymous = (0, function (a) {}); + const cases = { ordinary, strict, defaulted, restOnly, destructured, arrow, + method: object.method, getter, setter, asyncFunction, generator, asyncGenerator, + Constructor, anonymous, bound: ordinary.bind(null, 1), native: Math.max, + dynamic: Function('a', 'b = 1', 'return a + b'), proxy: new Proxy(ordinary, {}) }; + const initial = {}; + for (const key of Object.keys(cases)) initial[key] = snapshot(cases[key]); + const originalLength = ordinary.length; + ordinary.length = 99; + const sloppyWritePreserved = ordinary.length === originalLength; + let strictWriteRejected = false; + try { (function () { 'use strict'; ordinary.name = 'wrong'; })(); } + catch (error) { strictWriteRejected = error instanceof TypeError; } + Object.defineProperty(ordinary, 'length', { value: 8 }); + delete ordinary.name; + Object.defineProperty(ordinary, 'name', { value: 'renamed', writable: true, enumerable: true, configurable: true }); + const changed = snapshot(ordinary); + Object.freeze(ordinary); + const frozen = snapshot(ordinary); + function first() {} function second() {} + const prototypeIdentity = [first.prototype !== second.prototype, + first.prototype.constructor === first, second.prototype.constructor === second]; + return { initial, sloppyWritePreserved, strictWriteRejected, changed, frozen, prototypeIdentity }; +})(); +if (typeof process !== 'undefined') process.stdout.write(JSON.stringify(freshFunctionDescriptors)); From ab864d4cac474a00460689439436551151f044f5 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 07:50:08 +0200 Subject: [PATCH 87/99] Document host preflight and function allocation fixes --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5456f619..170ae750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Array literals and built-in array results retain their realm's intrinsic prototype when the global Array constructor is replaced. - Compiled identifier updates and strict program assignments retain their original references through coercion and right-hand-side effects. - Generated PHP preserves numeric truthiness and literal precision, evaluates operands once, and falls back before observable effects. +- Generated binding preflight does not invoke host property-map or descriptor overrides. - Calls, getters and constructors retain caller and argument records; non-callable errors do not invoke object conversion hooks. - Same-type typed-array copies preserve byte payloads and prototype-validation order; host byte views and inlined callbacks retain their defining realms. - Typed-array `set` checks bounds before content-type mismatches and copies matching native element types without changing stored bits. @@ -33,6 +34,7 @@ - Bytecode compilation handles captured bindings, default initializers, array bindings and assignments, optional chains, spread calls, computed methods, object prototypes, regular-expression literals and strict tail calls; reusable syntax templates keep closure state separate. - Proven disjoint lexical scopes reuse frame slots, ordinary function prototypes materialize when observed, and numeric typed-array writes avoid redundant conversions while retaining buffer-resize and detachment behavior. - Completed frames clear their local slots in one allocation while releasing activation references. +- Fresh functions initialize their name and length descriptors without redundant allocation while preserving host subclass hooks. - Protected returns preserve finalizer completion order in bytecode, and logical assignments and object relational operators use the shared JavaScript semantics. - Bounded regular-expression preparation and cached UTF-16 searches reduce repeated work while preserving fresh objects and observable coercions. - The test262 runner executes both variants of unflagged scripts, preserves raw sources and module parse goals, requires async completion, and checks negative-test error types and phases. From 4c3cf399cc4288896393852f2f7e10644a39a5ff Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 08:02:38 +0200 Subject: [PATCH 88/99] Clarify generated execution and runtime guards in docs --- docs/advanced/architecture.md | 4 ++-- docs/advanced/benchmarks.md | 9 ++++----- docs/advanced/bytecode-vm.md | 2 +- docs/compatibility/limitations.md | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/advanced/architecture.md b/docs/advanced/architecture.md index babb0e4a..64ebe7ee 100644 --- a/docs/advanced/architecture.md +++ b/docs/advanced/architecture.md @@ -120,10 +120,10 @@ Value conversion across the boundary lives in two places: An uncaught JS `throw` becomes a PHP `Phasis\Exceptions\JsThrowable`; engine errors extend `Phasis\Exceptions\RuntimeError`. JavaScript handlers catch those values and parse errors. PHP host-function throwables are converted at the interop boundary into catchable JS errors, preserving the PHP class name and message; callback throws retain their original JS value. -Two limits exist: the fixed call-stack ceiling (`CallStack::maxDepth`, 4,096 frames, plus an 8,192-frame guard for transpiled closures), and `maxLoopIterations`, set through `Engine::setLimit()` and enforced across the tree-walker, bytecode VM and transpiled closures. Loop counters are local to each loop entry and survive generator suspension. There are no string-length, output-size or execution-time limits. +The runtime enforces a call-stack ceiling (`CallStack::maxDepth`, 4,096 frames, plus an 8,192-frame guard for transpiled closures) and `maxLoopIterations`, configured through `Engine::setLimit()`. Loop counters are local to each loop entry and survive generator suspension. Hosts can also set an execution-time budget with `Engine::setExecutionBudget()`; expiry throws a PHP `BudgetExceeded` exception that JavaScript cannot catch. There are no built-in string-length or output-size limits. ## Bytecode VM -Hot functions get lowered two ways. `JsToPhp` (in `src/Bytecode/`) emits a PHP closure for numeric / locals-heavy bodies that PHP's tracing JIT can compile to native; the pipeline lowers `new Ctor(args)`, `obj.method(args)`, and `this.member` reads, which is enough to make the canonical class-method-in-a-loop pattern bypass the VM entirely. Everything else compiles to flat bytecode consumed by `VM::execute`, with a custom callstack that keeps every JS call inside a single PHP frame and a per-PC inline cache for prototype-method reads. Simple generator bodies compile to bytecode too, with `Op::YIELD` capturing a heap frame snapshot instead of crossing PHP Fiber. +Hot functions get lowered two ways. `JsToPhp` (in `src/Bytecode/`) emits PHP closures for proven numeric bodies and string-scanning loops, which PHP's tracing JIT can optimize. Guards validate assumptions before observable effects; calls, getters and constructors that can expose caller state retain tracked activations. Other supported bodies compile to flat bytecode consumed by `VM::execute`, whose custom callstack keeps eligible bytecode calls inside one PHP frame. Property inline caches retain up to four prototype shapes and check mutation versions. Simple generator bodies compile to bytecode too, with `Op::YIELD` capturing a heap frame snapshot instead of crossing PHP Fiber. Any shape the compiler doesn't lower (e.g. `with`, `try` with a re-binding catch, `yield*`, async generators) falls back to the tree-walker. See [Bytecode VM](/docs/advanced/bytecode-vm) for the full mechanism. diff --git a/docs/advanced/benchmarks.md b/docs/advanced/benchmarks.md index 8ebd632f..6046ea6e 100644 --- a/docs/advanced/benchmarks.md +++ b/docs/advanced/benchmarks.md @@ -30,10 +30,10 @@ The right mental model: Phasis is a **glue layer** for JS-shaped logic embedded ## What makes the engine fast (relative to a naïve tree-walker) - **Bytecode VM** — most hot dispatch runs through `VM::execute`'s opcode switch, not the AST. -- **Custom callstack** — every JS call keeps state inside `VM::execute` and saves the caller's frame onto a pool; no new PHP frame per JS call. See [Bytecode VM § Custom callstack](/docs/advanced/bytecode-vm). -- **Inline caches** — a per-PC monomorphic cache makes prototype-method-on-instance reads (the `c.method()` shape) skip the prototype-chain walk. +- **Custom callstack** — eligible bytecode calls keep state inside `VM::execute` and save the caller's frame in a pool, without another PHP call frame. See [Bytecode VM § Custom callstack](/docs/advanced/bytecode-vm). +- **Inline caches** — a per-PC cache retains up to four prototype shapes, allowing repeated method reads (the `c.method()` shape) to skip the prototype-chain walk while checking for mutations. - **Frame-snapshot generators** — simple generator bodies suspend by capturing the dispatch state into a heap object instead of crossing a PHP Fiber. -- **JsToPhp transpiler** — numeric / locals-heavy bodies (including `obj.method()`, `new Ctor()`, and `this.member` reads) compile to PHP closures that PHP 8.5's tracing JIT lowers to native machine code. +- **JsToPhp transpiler** — proven numeric bodies and string-scanning loops compile to PHP closures that PHP's tracing JIT can optimize. Entry checks validate assumptions before observable effects; calls that can expose their caller remain on tracked execution paths. - **JSON.stringify cache** — `JSON.stringify(o)` caches its output on the input object with transitive version invalidation, accelerating the deep-clone idiom `JSON.parse(JSON.stringify(o))`. ## Measuring your own workload @@ -83,10 +83,9 @@ opcache.preload_user=www-data What would close more of the V8 gap, in rough order of tractability: -- **Polymorphic inline caches** — let a single `LOAD_MEMBER` call site hold 2-4 cached shapes before falling back to slow dispatch. Helps code that processes heterogeneous receivers. - **`yield*` and try-with-yield on the frame-snapshot generator path** — these shapes currently route to the Fiber-backed tree-walker. Each needs explicit state-machine handling (delegate-iterator forwarding, handler stack preserved across suspend) before they're snapshot-safe. - **Async generators and `await` on snapshots** — the spec composes generator suspension with the microtask queue. Once the bytecode body supports both `yield` and `await`, async generators become snapshot-friendly too. -- **Parameter type inference in JsToPhp** — function parameters default to numeric type, so `function (obj) { obj.method() }` bails the compiler. Inferring object-typed parameters from how they're used in the body would unlock method calls on function arguments without requiring the receiver to be locally constructed via `new`. +- **Broader JsToPhp lowering** — support additional parameter types and calls while preserving observable caller records, coercion order and fallback before effects. Object-typed parameters alone are not sufficient to make `function (obj) { obj.method() }` safe to lower. - **Direct opcache emission** — skip JsToPhp's `eval()` step by writing opcache-format opcodes directly. Deepest item; the others can be done within the existing architecture. None of these are necessary for the embedding workloads Phasis targets. diff --git a/docs/advanced/bytecode-vm.md b/docs/advanced/bytecode-vm.md index f81b3d41..475ec7b6 100644 --- a/docs/advanced/bytecode-vm.md +++ b/docs/advanced/bytecode-vm.md @@ -101,7 +101,7 @@ Each fast path is gated by a "shape check" — if the receiver doesn't match the ## What this doesn't do -The bytecode VM is **not a JIT** in the V8 sense. It doesn't generate native machine code per-function and doesn't speculate based on observed types beyond the IC's monomorphic prototype-identity check. Function-boundary inlining is approximated by the custom callstack (no extra PHP frame per JS call) rather than by lowering the callee's body into the caller's bytecode. +The bytecode VM is **not a JIT** in the V8 sense. It doesn't generate native machine code per-function. Its property inline cache checks up to four prototype identities and their mutation versions. Eligible bytecode calls share the VM dispatch loop through the custom callstack, without lowering the callee's body into the caller's bytecode. The JsToPhp transpiler is the closest the engine has to a JIT: it generates PHP source for hot function bodies that PHP 8.5's tracing JIT then compiles to native. JsToPhp goes through `eval()`, so it pays a one-time compile tax and the tracing JIT has to discover the function as if it were user code. Skipping the `eval()` step by emitting opcache opcodes directly would close more of the gap — see [Benchmarks § Roadmap](/docs/advanced/benchmarks#roadmap). diff --git a/docs/compatibility/limitations.md b/docs/compatibility/limitations.md index 4e8be36b..eb5a97b2 100644 --- a/docs/compatibility/limitations.md +++ b/docs/compatibility/limitations.md @@ -14,7 +14,7 @@ Phasis aims to behave identically to V8 on every observable spec test. This page ## Performance ceiling -The engine is a tree-walker with an opportunistic bytecode VM and a JsToPhp transpiler that lowers numeric / locals-heavy bodies (including `obj.method()`, `new Ctor()`, and `this.member` shapes) to native PHP closures that PHP 8.5's tracing JIT can compile to machine code. Most hot dispatch happens inside the VM's switch loop or directly in JIT-compiled PHP — not by walking the AST — but each VM opcode still pays a PHP dispatch tax, and any shape JsToPhp doesn't yet handle falls back to the slower VM. The ceiling on dispatch-bound workloads is roughly **~100× slower than V8**. +The engine combines a tree-walker, a bytecode VM and a JsToPhp transpiler. Proven numeric bodies and string-scanning loops can become PHP closures that PHP's tracing JIT optimizes. Calls that can expose their caller retain tracked activations, and unsupported shapes use the VM or tree-walker. Each VM opcode still pays a PHP dispatch cost. Dispatch-bound workloads can be roughly **~100× slower than V8**. For embedding workloads — running user-supplied logic on PHP data, content-transformation pipelines, validation rules — the ceiling rarely matters. V8 is 100 ms; Phasis is 10 s; both are well below the request timeout. Closing more of the gap would require teaching JsToPhp more shapes (parameter type inference, `await` / `yield*` lowering) or emitting opcache opcodes directly rather than through `eval()`. See [Benchmarks § Roadmap](/docs/advanced/benchmarks#roadmap). From ae6a57217118eac714e19c66dc797367896d1fb9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 24 Oct 2026 06:14:08 +0000 Subject: [PATCH 89/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 44 +++++++------- compat.json | 172 +++++++++++++++++++++++++--------------------------- 2 files changed, 106 insertions(+), 110 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 696a27cb..798d79ab 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,13 +3,13 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-24T05:12:14+00:00` +- Snapshot time: `2026-10-24T06:14:06+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `39724214` (dirty) +- Git: `feat/express-hono-compatibility` @ `4c3cf399` (dirty) ## Summary @@ -198,26 +198,26 @@ Generated from a completed `test262` pass. Do not edit by hand. | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| staging/sm | NORMAL | 187.136s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 182.278s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 179.007s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 178.499s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 178.458s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 171.051s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| staging/sm | NORMAL | 169.255s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| built-ins/decodeURIComponent | NORMAL | 166.512s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| staging/sm | NORMAL | 148.758s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| built-ins/decodeURI | NORMAL | 143.603s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| staging/sm | NORMAL | 138.609s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| staging/sm | NORMAL | 122.550s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| intl402 | NORMAL | 87.509s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | -| language/literals | NORMAL | 80.139s | 25 | `test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js`
`test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js`
...
`test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js`
`test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js` | -| built-ins/decodeURI | NORMAL | 74.946s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | -| built-ins/decodeURIComponent | NORMAL | 74.730s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | -| built-ins/TypedArray | NORMAL | 71.508s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | -| intl402/DateTimeFormat | NORMAL | 68.375s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | -| annexB/built-ins/RegExp | NORMAL | 63.498s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.922s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js` | +| staging/sm | NORMAL | 185.003s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 184.441s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 184.159s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 181.971s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 177.410s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 169.918s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| staging/sm | NORMAL | 156.581s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 155.460s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| staging/sm | NORMAL | 149.212s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| staging/sm | NORMAL | 125.007s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| intl402 | NORMAL | 83.986s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | +| built-ins/decodeURIComponent | NORMAL | 81.827s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| built-ins/TypedArray | NORMAL | 71.720s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | +| built-ins/decodeURI | NORMAL | 70.619s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| intl402/DateTimeFormat | NORMAL | 67.318s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.600s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bengali.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Beria_Erfe.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bhaiksuki.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bopomofo.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Brahmi.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.985s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Old_Uyghur.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Oriya.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Osage.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.976s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Adlam.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Ahom.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Anatolian_Hieroglyphs.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Arabic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Armenian.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.932s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Tham.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Viet.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Yo.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.032s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Syloti_Nagri.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Syriac.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tagalog.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index ba9ab4a0..f707997a 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-24T05:12:14+00:00", - "updatedAt": "2026-10-24T05:12:14+00:00", + "generatedAt": "2026-10-24T06:14:06+00:00", + "updatedAt": "2026-10-24T06:14:06+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "39724214", + "commit": "4c3cf399", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "854fe5d604c4e4242d6895d002c533834ad815d7", - "runIdentity": "94e3b04d57ecbc5f3d5d44387f054fad3f92fffd8a2979bc45632c4bd6b7f90c" + "fingerprint": "bb54c91d6d6c114b8b91b39b47bdf15064054854", + "runIdentity": "03a46d1c626e11de932edfba29a2e4b57cf32559b9c91abb5c8177585a22588c" }, "discovery": { "groupCount": 161, @@ -2719,43 +2719,43 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 187.136, + "durationSec": 185.003, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 182.278, + "durationSec": 184.441, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 179.007, + "durationSec": 184.159, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 178.499, + "durationSec": 181.971, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 178.458, + "durationSec": 177.41, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" @@ -2764,7 +2764,7 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 171.051, + "durationSec": 169.918, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" @@ -2773,52 +2773,34 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 169.255, - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" - ] - }, - { - "group": "built-ins/decodeURIComponent", - "kind": "normal", - "durationSec": 166.512, + "durationSec": 156.581, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 148.758, - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" - ] - }, - { - "group": "built-ins/decodeURI", - "kind": "normal", - "durationSec": 143.603, + "durationSec": 155.46, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 138.609, + "durationSec": 149.212, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 122.55, + "durationSec": 125.007, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" @@ -2827,7 +2809,7 @@ { "group": "intl402", "kind": "normal", - "durationSec": 87.509, + "durationSec": 83.986, "filesCount": 22, "sampleFiles": [ "test262/test/intl402/constructors-string-and-single-element-array.js", @@ -2837,49 +2819,19 @@ "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" ] }, - { - "group": "language/literals", - "kind": "normal", - "durationSec": 80.139, - "filesCount": 25, - "sampleFiles": [ - "test262/test/language/literals/regexp/S7.8.5_A1.1_T1.js", - "test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js", - "...", - "test262/test/language/literals/regexp/S7.8.5_A2.2_T2.js", - "test262/test/language/literals/regexp/S7.8.5_A2.3_T1.js" - ] - }, - { - "group": "built-ins/decodeURI", - "kind": "normal", - "durationSec": 74.946, - "filesCount": 25, - "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", - "...", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", - "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" - ] - }, { "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 74.73, - "filesCount": 25, + "durationSec": 81.827, + "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", - "...", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" ] }, { "group": "built-ins/TypedArray", "kind": "normal", - "durationSec": 71.508, + "durationSec": 71.72, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", @@ -2889,10 +2841,19 @@ "test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js" ] }, + { + "group": "built-ins/decodeURI", + "kind": "normal", + "durationSec": 70.619, + "filesCount": 1, + "sampleFiles": [ + "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" + ] + }, { "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 68.375, + "durationSec": 67.318, "filesCount": 12, "sampleFiles": [ "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", @@ -2903,27 +2864,62 @@ ] }, { - "group": "annexB/built-ins/RegExp", + "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 63.498, - "filesCount": 25, + "durationSec": 59.6, + "filesCount": 5, "sampleFiles": [ - "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", - "test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js", - "...", - "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js", - "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bengali.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Beria_Erfe.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bhaiksuki.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bopomofo.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Brahmi.js" + ] + }, + { + "group": "built-ins/RegExp/property-escapes/generated", + "kind": "normal", + "durationSec": 58.985, + "filesCount": 3, + "sampleFiles": [ + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Old_Uyghur.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Oriya.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Osage.js" + ] + }, + { + "group": "built-ins/RegExp/property-escapes/generated", + "kind": "normal", + "durationSec": 58.976, + "filesCount": 5, + "sampleFiles": [ + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Adlam.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Ahom.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Anatolian_Hieroglyphs.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Arabic.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Armenian.js" + ] + }, + { + "group": "built-ins/RegExp/property-escapes/generated", + "kind": "normal", + "durationSec": 58.932, + "filesCount": 3, + "sampleFiles": [ + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Tham.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Viet.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Yo.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.922, + "durationSec": 58.032, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kirat_Rai.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Lao.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Latin.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Syloti_Nagri.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Syriac.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tagalog.js" ] } ] From 232ec2cc649c8cfb7ae8372b8df7f7621f98eac2 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 08:14:30 +0200 Subject: [PATCH 90/99] Fix operand decoding for template string coercion --- src/Bytecode/Op.php | 1 + tests/Unit/Bytecode/StringLoopRegionTest.php | 28 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/Bytecode/Op.php b/src/Bytecode/Op.php index 27cc769b..ac48ffaa 100644 --- a/src/Bytecode/Op.php +++ b/src/Bytecode/Op.php @@ -231,6 +231,7 @@ public static function operandCount(int $op): int case self::INSTANCEOF: case self::NOT: case self::TYPEOF: + case self::TO_STRING: case self::BAND: case self::BOR: case self::BXOR: diff --git a/tests/Unit/Bytecode/StringLoopRegionTest.php b/tests/Unit/Bytecode/StringLoopRegionTest.php index d279b9f8..eae839dc 100644 --- a/tests/Unit/Bytecode/StringLoopRegionTest.php +++ b/tests/Unit/Bytecode/StringLoopRegionTest.php @@ -55,6 +55,34 @@ public function testOpaqueExitsDoNotReplayPrefixOrBranchEffects(): void } } + public function testTemplateAfterTheLoopDoesNotDisableItsVerifiedRegion(): void + { + $engine = new Engine(); + $source = str_replace( + 'return [state.creation, index];', + 'return `${state.creation}:${index}:${tail}`;', + self::SOURCE, + ); + $engine->eval($source . <<<'JS' +const tail = { toString() { events.push('toString'); return 'tail'; } }; +JS); + self::assertSame( + ['1:4:tail', '2:3:tail', [3, 'toString', 'toString'], 2], + $engine->eval("[scan('abc,def', 0), scan('abc', 0), events, creations]"), + ); + $compiled = $this->compiled($engine); + self::assertCount(1, array_filter($compiled->loopRegions)); + $conversions = []; + for ($pc = 0; $pc < count($compiled->code); $pc += 1 + Op::operandCount($compiled->code[$pc])) { + if ($compiled->code[$pc] === Op::TO_STRING) { + $conversions[] = $pc; + } + } + self::assertSame(count($compiled->code), $pc); + self::assertCount(3, $conversions); + self::assertGreaterThan($this->regionPc($compiled), min($conversions)); + } + public function testNativeExitRestoresActiveSlotsAndCounterExactlyOnce(): void { $engine = new Engine(); From 4d349cfa8c749af32ccb224995e23c9c23de8046 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 08:17:40 +0200 Subject: [PATCH 91/99] Reject host metadata overrides before string scanner execution --- src/Runtime/Parts/ExpressionEvaluation.php | 10 +- .../Bytecode/StringIntrinsicGuardTest.php | 117 ++++++++++++++++++ 2 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 tests/Unit/Bytecode/StringIntrinsicGuardTest.php diff --git a/src/Runtime/Parts/ExpressionEvaluation.php b/src/Runtime/Parts/ExpressionEvaluation.php index db074b96..43472d60 100644 --- a/src/Runtime/Parts/ExpressionEvaluation.php +++ b/src/Runtime/Parts/ExpressionEvaluation.php @@ -5921,13 +5921,19 @@ public function hasCachedStringIntrinsic(string $name, string $kind): bool { $realmInterpreter = \Phasis\Engine::getCurrentInterpreter() ?? $this; $prototype = $realmInterpreter->cachedStringPrototype; - if ($prototype === null || get_class($prototype) !== JsObject::class) { + if ( + $prototype === null || get_class($prototype) !== JsObject::class + || get_class($prototype->properties) !== \Phasis\Object\PropertyMap::class + ) { return false; } $value = $prototype->properties->dataSlots[$name] ?? null; if ($value === null) { $descriptor = $prototype->properties->descriptors[$name] ?? null; - if ($descriptor === null || !$descriptor->isDataDescriptor()) { + if ( + $descriptor === null || get_class($descriptor) !== PropertyDescriptor::class + || !$descriptor->isDataDescriptor() + ) { return false; } $value = $descriptor->value; diff --git a/tests/Unit/Bytecode/StringIntrinsicGuardTest.php b/tests/Unit/Bytecode/StringIntrinsicGuardTest.php new file mode 100644 index 00000000..7960af9f --- /dev/null +++ b/tests/Unit/Bytecode/StringIntrinsicGuardTest.php @@ -0,0 +1,117 @@ + */ + public static function entries(): iterable + { + yield 'cold descriptor' => [false, false]; + yield 'cached descriptor' => [true, false]; + yield 'cold property map' => [false, true]; + yield 'cached property map' => [true, true]; + } + + #[DataProvider('entries')] + public function testUnusedStringMethodsDoNotReadHostMetadata(bool $warm, bool $mapOverride): void + { + $engine = new Engine(); + $engine->eval(<<<'JS' +function prime(text) { return text.charCodeAt(0); } +function scan(text, offset) { + while (offset < text.length) { + const code = text.charCodeAt(offset); + if (code === 120) break; + offset++; + } + return offset; +} +prime('x'); +JS); + if ($warm) { + self::assertSame(2, $engine->eval("scan(' ax', 0)")); + } + $prototype = $engine->getGlobalEnv()->get('String')->get('prototype'); + self::assertInstanceOf(JsObject::class, $prototype); + $originalMap = $prototype->properties; + $originalDescriptor = $originalMap->descriptors['charCodeAt']; + $descriptor = new class ( + value: $originalDescriptor->value, + writable: true, + enumerable: false, + configurable: true, + ) extends PropertyDescriptor { + public int $reads = 0; + + public function isDataDescriptor(): bool + { + ++$this->reads; + return parent::isDataDescriptor(); + } + }; + $map = new class ($originalMap) extends PropertyMap { + public int $reads = 0; + + public function __construct(private readonly PropertyMap $original) + { + $this->order = $original->order; + $this->version = $original->version; + $this->mutationVersion = $original->mutationVersion; + $this->isUsedAsProto = $original->isUsedAsProto; + unset($this->dataSlots, $this->descriptors); + } + + public function __isset(string $name): bool + { + ++$this->reads; + return $name === 'dataSlots' || $name === 'descriptors'; + } + + public function __get(string $name): mixed + { + ++$this->reads; + return match ($name) { + 'dataSlots' => $this->original->dataSlots, + 'descriptors' => $this->original->descriptors, + default => throw new \LogicException('Unexpected metadata read: ' . $name), + }; + } + }; + $previous = Engine::getCurrentInterpreter(); + Engine::setCurrentInterpreter($engine->getInterpreter()); + try { + self::assertTrue($engine->getInterpreter()->hasCachedStringIntrinsic('charCodeAt', 'string.charCodeAt')); + if ($mapOverride) { + $prototype->properties = $map; + } else { + $originalMap->descriptors['charCodeAt'] = $descriptor; + } + self::assertSame(0, $engine->eval("scan('', 0)")); + self::assertSame(0, $descriptor->reads); + self::assertSame(0, $map->reads); + self::assertSame(2, $engine->eval("scan(' ax', 0)")); + self::assertSame(0, $descriptor->reads); + if ($mapOverride) { + self::assertGreaterThan(0, $map->reads); + } + $function = $engine->getGlobalEnv()->get('scan'); + self::assertInstanceOf(JsFunction::class, $function); + self::assertInstanceOf(\Closure::class, $function->phpCompiled); + } finally { + $prototype->properties = $originalMap; + $originalMap->descriptors['charCodeAt'] = $originalDescriptor; + Engine::setCurrentInterpreter($previous); + } + } +} From 094a3e46349e6e09fa73d23484d54a9cb87e52a6 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 08:21:54 +0200 Subject: [PATCH 92/99] Document scanner guard and opcode decoding fixes --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 170ae750..f0475a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,8 @@ - Array literals and built-in array results retain their realm's intrinsic prototype when the global Array constructor is replaced. - Compiled identifier updates and strict program assignments retain their original references through coercion and right-hand-side effects. - Generated PHP preserves numeric truthiness and literal precision, evaluates operands once, and falls back before observable effects. -- Generated binding preflight does not invoke host property-map or descriptor overrides. +- Generated binding and string-method preflight checks do not invoke host property-map or descriptor overrides. +- Template strings outside pure loops no longer prevent those loops from using verified compiled code. - Calls, getters and constructors retain caller and argument records; non-callable errors do not invoke object conversion hooks. - Same-type typed-array copies preserve byte payloads and prototype-validation order; host byte views and inlined callbacks retain their defining realms. - Typed-array `set` checks bounds before content-type mismatches and copies matching native element types without changing stored bits. From b56afe5dcb7436784766bc8e2cffa58396103fd8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 24 Oct 2026 06:52:53 +0000 Subject: [PATCH 93/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 44 ++++++++-------- compat.json | 142 +++++++++++++++++++++++++--------------------------- 2 files changed, 91 insertions(+), 95 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 798d79ab..c0f4dcb8 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,13 +3,13 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-24T06:14:06+00:00` +- Snapshot time: `2026-10-24T06:52:52+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `4c3cf399` (dirty) +- Git: `feat/express-hono-compatibility` @ `094a3e46` (dirty) ## Summary @@ -198,26 +198,26 @@ Generated from a completed `test262` pass. Do not edit by hand. | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| staging/sm | NORMAL | 185.003s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 184.441s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 184.159s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 181.971s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 177.410s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 169.918s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| staging/sm | NORMAL | 156.581s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| staging/sm | NORMAL | 155.460s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| staging/sm | NORMAL | 149.212s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| staging/sm | NORMAL | 125.007s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| intl402 | NORMAL | 83.986s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | -| built-ins/decodeURIComponent | NORMAL | 81.827s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| built-ins/TypedArray | NORMAL | 71.720s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | -| built-ins/decodeURI | NORMAL | 70.619s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| intl402/DateTimeFormat | NORMAL | 67.318s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 59.600s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bengali.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Beria_Erfe.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bhaiksuki.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bopomofo.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Brahmi.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 58.985s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Old_Uyghur.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Oriya.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Osage.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 58.976s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Adlam.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Ahom.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Anatolian_Hieroglyphs.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Arabic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Armenian.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 58.932s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Tham.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Viet.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Yo.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 58.032s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Syloti_Nagri.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Syriac.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tagalog.js` | +| staging/sm | NORMAL | 104.628s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 102.486s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 99.716s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 96.997s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 93.628s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 92.071s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| built-ins/decodeURIComponent | NORMAL | 86.778s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| staging/sm | NORMAL | 84.784s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| intl402 | NORMAL | 82.707s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | +| staging/sm | NORMAL | 82.691s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| built-ins/decodeURI | NORMAL | 74.053s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| built-ins/TypedArray | NORMAL | 71.932s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | +| staging/sm | NORMAL | 71.156s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| intl402/DateTimeFormat | NORMAL | 66.141s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | +| staging/sm | NORMAL | 61.245s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.922s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Math.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Noncharacter_Code_Point.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Pattern_Syntax.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.892s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Toto.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tulu_Tigalari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Ugaritic.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.834s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.569s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Glagolitic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Gothic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Grantha.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.052s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index f707997a..6c7657c0 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-24T06:14:06+00:00", - "updatedAt": "2026-10-24T06:14:06+00:00", + "generatedAt": "2026-10-24T06:52:52+00:00", + "updatedAt": "2026-10-24T06:52:52+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "4c3cf399", + "commit": "094a3e46", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "bb54c91d6d6c114b8b91b39b47bdf15064054854", - "runIdentity": "03a46d1c626e11de932edfba29a2e4b57cf32559b9c91abb5c8177585a22588c" + "fingerprint": "e163187c171ee7421a46f7fceb96d62f8d4956e2", + "runIdentity": "313297c88a51d44a20f45aa2772ec07e4a625fab0cc942ba368956af4cf3303e" }, "discovery": { "groupCount": 161, @@ -2719,16 +2719,7 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 185.003, - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" - ] - }, - { - "group": "staging/sm", - "kind": "normal", - "durationSec": 184.441, + "durationSec": 104.628, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" @@ -2737,16 +2728,7 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 184.159, - "filesCount": 1, - "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" - ] - }, - { - "group": "staging/sm", - "kind": "normal", - "durationSec": 181.971, + "durationSec": 102.486, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" @@ -2755,61 +2737,61 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 177.41, + "durationSec": 99.716, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 169.918, + "durationSec": 96.997, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 156.581, + "durationSec": 93.628, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 155.46, + "durationSec": 92.071, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { - "group": "staging/sm", + "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 149.212, + "durationSec": 86.778, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 125.007, + "durationSec": 84.784, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" + "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" ] }, { "group": "intl402", "kind": "normal", - "durationSec": 83.986, + "durationSec": 82.707, "filesCount": 22, "sampleFiles": [ "test262/test/intl402/constructors-string-and-single-element-array.js", @@ -2820,18 +2802,27 @@ ] }, { - "group": "built-ins/decodeURIComponent", + "group": "staging/sm", "kind": "normal", - "durationSec": 81.827, + "durationSec": 82.691, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + ] + }, + { + "group": "built-ins/decodeURI", + "kind": "normal", + "durationSec": 74.053, + "filesCount": 1, + "sampleFiles": [ + "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" ] }, { "group": "built-ins/TypedArray", "kind": "normal", - "durationSec": 71.72, + "durationSec": 71.932, "filesCount": 25, "sampleFiles": [ "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", @@ -2842,18 +2833,18 @@ ] }, { - "group": "built-ins/decodeURI", + "group": "staging/sm", "kind": "normal", - "durationSec": 70.619, + "durationSec": 71.156, "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" ] }, { "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 67.318, + "durationSec": 66.141, "filesCount": 12, "sampleFiles": [ "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", @@ -2863,63 +2854,68 @@ "test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js" ] }, + { + "group": "staging/sm", + "kind": "normal", + "durationSec": 61.245, + "filesCount": 1, + "sampleFiles": [ + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" + ] + }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 59.6, - "filesCount": 5, + "durationSec": 58.922, + "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bengali.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Beria_Erfe.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bhaiksuki.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Bopomofo.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Brahmi.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Math.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Noncharacter_Code_Point.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Pattern_Syntax.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 58.985, + "durationSec": 58.892, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Old_Uyghur.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Oriya.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Osage.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Toto.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tulu_Tigalari.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Ugaritic.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 58.976, - "filesCount": 5, + "durationSec": 58.834, + "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Adlam.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Ahom.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Anatolian_Hieroglyphs.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Arabic.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Armenian.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 58.932, + "durationSec": 58.569, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Tham.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Viet.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tai_Yo.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Glagolitic.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Gothic.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Grantha.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 58.032, + "durationSec": 58.052, "filesCount": 3, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Syloti_Nagri.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Syriac.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tagalog.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js" ] } ] From e08f2f2ded77d04f7b2246a3eb3d9e289640d5ff Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 09:14:34 +0200 Subject: [PATCH 94/99] Document experimental framework support and relaxed CI timeouts --- .github/workflows/frameworks.yml | 4 ++-- AGENTS.md | 9 +++++++-- CHANGELOG.md | 3 ++- README.md | 8 +++++--- docs/modules.md | 9 ++++++++- tests/Frameworks/hono/README.md | 19 +++++++++++++++---- 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/.github/workflows/frameworks.yml b/.github/workflows/frameworks.yml index 8a111652..c75771a1 100644 --- a/.github/workflows/frameworks.yml +++ b/.github/workflows/frameworks.yml @@ -78,7 +78,7 @@ jobs: if: matrix.suite == 'express' run: | python3 -B tests/Frameworks/express/test_runner.py - python3 -B tests/Frameworks/express/run.py --runtime both --jobs 1 --output framework-results/express + python3 -B tests/Frameworks/express/run.py --runtime both --jobs 1 --timeout-scale 10 --output framework-results/express - name: Hono harness deadline differential if: startsWith(matrix.suite, 'hono-') @@ -90,7 +90,7 @@ jobs: if: startsWith(matrix.suite, 'hono-') env: FRAMEWORK_SUITE: ${{ matrix.suite }} - run: python3 -B tests/Frameworks/hono/run.py --project "${FRAMEWORK_SUITE#hono-}" --timeout 1800 + run: python3 -B tests/Frameworks/hono/run.py --project "${FRAMEWORK_SUITE#hono-}" --timeout 1800 --timeout-scale 10 - name: Hono independent native Vitest baseline if: startsWith(matrix.suite, 'hono-') && !cancelled() diff --git a/AGENTS.md b/AGENTS.md index aeddcd99..31c31838 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,8 +14,13 @@ run test oracles, but must never become an execution backend. Explicit `child_process` operations use PHP host processes; a JavaScript child launched through `process.execPath` runs the Phasis PHP entry point. New host resources must register cleanup with their owning NodeRuntime. Keep original framework -assertions and timeouts, report all discovered cases and upstream skips, and -retain source identity for complete-run claims. Close and reap owned test +assertions, report all discovered cases and upstream skips, and retain source +identity for complete-run claims. Express and Hono support is experimental; +their CI runners explicitly use `--timeout-scale 10` while performance work is +deferred. Preserve original timeout values and record effective limits in the +results; a scaled run is a functional compatibility result, not a claim to meet +upstream performance deadlines. Never relax test262 assertions, coverage or +timeouts to accommodate framework workloads. Close and reap owned test processes and listeners after every run. ## Releases diff --git a/CHANGELOG.md b/CHANGELOG.md index f0475a2b..951997d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Added - Opt-in Node-compatible realms and `phasis --node`, with CommonJS package loading, Buffer and streams, filesystem and process I/O, HTTP/HTTPS/HTTP2, TLS, compression, timers, async context, and isolated VM realms. -- Pinned Express and Hono upstream runners with original assertions, case inventories, source hashes, bounded workers and real network interoperability checks. +- Experimental Express and Hono support with pinned upstream runners, original assertions, case inventories, source hashes, bounded workers and real network interoperability checks. - Ed25519 WebCrypto keys, MessageEvent and in-process BroadcastChannel support. - Keyed Promise combinators, iterator chunk/window/zip helpers, and immutable ArrayBuffers with protected typed-array, DataView, and Atomics writes. - Locale variants and locale-specific calendar, collation, hour-cycle, text-direction, and week information. @@ -32,6 +32,7 @@ - Intl option precedence, legacy constructors, plural notation, numbering systems, and plain date/time formatting. ### Changed +- Framework runners accept an explicit timeout scale and record original and effective limits. Experimental Express/Hono CI uses a scale of 10 while performance work is deferred; test262 limits and engine budgets are unchanged. - Bytecode compilation handles captured bindings, default initializers, array bindings and assignments, optional chains, spread calls, computed methods, object prototypes, regular-expression literals and strict tail calls; reusable syntax templates keep closure state separate. - Proven disjoint lexical scopes reuse frame slots, ordinary function prototypes materialize when observed, and numeric typed-array writes avoid redundant conversions while retaining buffer-resize and detachment behavior. - Completed frames clear their local slots in one allocation while releasing activation references. diff --git a/README.md b/README.md index 61b547e9..e64ae5cf 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Phasis lexes, parses, and executes ECMAScript in pure PHP. No `exec('node …')` - **Fetch Pack**: `fetch`, `Request`, `Response`, `Headers`, `Body`, `AbortController`/`AbortSignal`, `Blob`/`File`, `FormData`, `EventTarget`/`Event`, full WHATWG Streams, `navigator` - **Crypto**: `crypto.getRandomValues`, `crypto.randomUUID`, full `SubtleCrypto` (SHA family, HMAC, AES-GCM/CBC/CTR, RSA-OAEP/PSS/PKCS1, ECDSA, ECDH, HKDF, PBKDF2) - **WebSocket** (RFC 6455 + replaceable transport), **XMLHttpRequest** (layered over fetch), and a real **event loop** (`setTimeout` / `setInterval` / `queueMicrotask`, plus Stage-3 `AsyncContext`) -- **Opt-in Node compatibility** for Express and Hono: CommonJS packages, Buffer, streams, filesystem access, HTTP/HTTPS/HTTP2 servers and clients, TLS, crypto, timers, and async context, executed inside PHP. See the [module coverage and host limits](./docs/modules.md#node-compatibility). +- **Experimental Express and Hono support** through opt-in Node compatibility: CommonJS packages, Buffer, streams, filesystem access, HTTP/HTTPS/HTTP2 servers and clients, TLS, crypto, timers, and async context, executed inside PHP. See the [module coverage and host limits](./docs/modules.md#node-compatibility). - **JSX Pack**: render JSX components to HTML from PHP with `Engine::render()`, no build step - **Native React 19.3 server renderer** in PHP: `react`, `react-dom/server` and `react-dom/static` are built in, with HTML byte-identical to `react-dom@19.3.1` and hydratable by React on the client (hooks, context, Suspense, `useId`, async components, resource hints) - **General HTML renderer** (`phasis`, `phasis/jsx-runtime`) for emails, feeds and static pages, byte-identical to preact-render-to-string 6.8.1, plus `raw()` @@ -120,13 +120,15 @@ composer cs npm ci --prefix tests/Frameworks python3 tests/Frameworks/express/setup.py python3 tests/Frameworks/hono/setup.py -python3 tests/Frameworks/express/run.py --output /tmp/phasis-express-report -python3 tests/Frameworks/hono/run.py +python3 tests/Frameworks/express/run.py --timeout-scale 10 --output /tmp/phasis-express-report +python3 tests/Frameworks/hono/run.py --timeout-scale 10 # test262 conformance sample (needs: git submodule update --init test262) ./bin/test262 --category built-ins/Array --jobs 4 ``` +Express and Hono support is experimental. Framework CI uses ten times the upstream test timeouts while retaining the original assertions and recording both timeout values. Omit `--timeout-scale 10` to check the original deadlines. This setting does not change test262 limits or engine execution budgets. + CI runs PHPStan, PHPCS, the unit suite and the oracle regression on every push to `main` and every pull request; the Web Platform Tests and popular-package suites run when `src/` or their fixtures change. The full test262 matrix (`compat-matrix.yml`) is started by hand, not on every push; it runs against the test262 revision pinned by the submodule and commits the result to `COMPAT.md`, which records the snapshot time. ## Compatibility diff --git a/docs/modules.md b/docs/modules.md index 0b875373..8d4e2950 100644 --- a/docs/modules.md +++ b/docs/modules.md @@ -65,7 +65,8 @@ In ES modules, `process.env.NODE_ENV` is replaced with the configured value at p ## Node compatibility -Enable Node mode explicitly for packages that use Node APIs: +Express and Hono support is **experimental**. Enable Node mode explicitly for +packages that use Node APIs: ```php use Phasis\Engine; @@ -141,6 +142,12 @@ failures, blocked tests, source hashes and process timeouts. Framework versions and suite revisions are recorded there; passing a framework suite does not imply that the complete Node test suite or Hono's Bun/Deno/Fastly/workerd hosts pass. +Framework CI passes `--timeout-scale 10` to the Express and Hono runners so slow +PHP workloads can complete their original assertions. Reports retain the +original and effective timeouts; scaled results do not establish upstream +performance parity. The default scale is 1 for checking the original deadlines. +This configuration does not affect test262 or engine execution budgets. + ## Styles and assets - **Style imports** (`import './Card.css'`) load as empty modules on the server. diff --git a/tests/Frameworks/hono/README.md b/tests/Frameworks/hono/README.md index 4d3399f0..40ff46ac 100644 --- a/tests/Frameworks/hono/README.md +++ b/tests/Frameworks/hono/README.md @@ -1,4 +1,7 @@ -# Hono upstream compatibility +# Experimental Hono compatibility + +Hono support is experimental. CI checks functional compatibility with an explicit +timeout scale of 10; meeting the original performance deadlines is deferred. The ignored source tree in `upstream/hono-4.13.13` is the unchanged Hono v4.13.13 archive at commit `08a023cbfde55b434fb0fb30fae35d42e4bf20aa`. The repository, @@ -31,7 +34,14 @@ python3 tests/Frameworks/hono/run.py src/context.test.ts src/request.test.ts runs both and compares every discovered case's identity and outcome. Each file runs in a separate process, sequentially, with a 1,800 second outer wall limit (`--timeout` overrides it). This lets large files finish hundreds of -cases while retaining the original per-test and per-hook deadlines. +cases while retaining the original per-test and per-hook deadlines by default. +Pass `--timeout-scale 10` to match CI, or set +`PHASIS_FRAMEWORK_TIMEOUT_SCALE=10`; an explicit CLI value takes precedence. +The scale applies equally to the Node harness and Phasis, and reports record +the scale plus each case's original and effective timeout. The outer worker +limit, engine budgets and test262 timeouts are unchanged. Disabled upstream +deadlines remain disabled. The independent native Vitest oracle retains its +original deadlines. The PHP worker uses `XDEBUG_MODE=off`, a 4 GiB memory limit and a one million iteration limit so the unchanged 100,000-entry parser and large-body stress cases fit. Override memory with `--php-memory-limit 2G`; positive byte counts @@ -59,8 +69,9 @@ Unsupported harness operations throw and are reported separately. Upstream skip declarations remain skips, never passes. The test environment clears `NO_COLOR` for both engines, matching the color tests' unstubbed assumption. The Node runtime project sets `NAME=Node`, as its upstream configuration does. -Test and hook deadlines preserve Vitest 5's defaults of 5,000 ms and 10,000 ms, -explicit numeric/options values, suite inheritance and disabled deadlines. +At scale 1, test and hook deadlines preserve Vitest 5's defaults of 5,000 ms and +10,000 ms, explicit numeric/options values, suite inheritance and disabled +deadlines. At scale 10, those defaults become 50,000 ms and 100,000 ms. Captured real timers and monotonic time keep deadlines effective under fake timers and synchronous or microtask starvation. Failed suite setup is recorded as a suite failure with blocked cases, separately from upstream skip declarations. From 314fe49e23d36983ccf73b5d808b2ee83f32d9d3 Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 09:21:44 +0200 Subject: [PATCH 95/99] Add explicit Hono framework timeout scaling --- tests/Frameworks/hono/build-selftest.mjs | 2 +- tests/Frameworks/hono/compare-native.py | 2 ++ tests/Frameworks/hono/deadline.mjs | 36 ++++++++++++++++++- .../hono/fixtures/timeout-scaling-entry.mjs | 7 ++++ .../hono/fixtures/timeout-scaling.test.mjs | 35 ++++++++++++++++++ tests/Frameworks/hono/harness.mjs | 12 ++++--- tests/Frameworks/hono/run.py | 32 ++++++++++++++--- tests/Frameworks/hono/selftest.py | 32 +++++++++++++++++ tests/Frameworks/hono/test_runner.py | 35 ++++++++++++++++++ 9 files changed, 182 insertions(+), 11 deletions(-) create mode 100644 tests/Frameworks/hono/fixtures/timeout-scaling-entry.mjs create mode 100644 tests/Frameworks/hono/fixtures/timeout-scaling.test.mjs diff --git a/tests/Frameworks/hono/build-selftest.mjs b/tests/Frameworks/hono/build-selftest.mjs index 4b6703b5..011fd282 100644 --- a/tests/Frameworks/hono/build-selftest.mjs +++ b/tests/Frameworks/hono/build-selftest.mjs @@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url'; const directory = dirname(fileURLToPath(import.meta.url)); const output = resolve(directory, '.generated/selftest'); await mkdir(output, { recursive: true }); -for (const name of ['timeouts', 'scheduling']) { +for (const name of ['timeouts', 'scheduling', 'timeout-scaling']) { await build({ entryPoints: [resolve(directory, 'fixtures/' + name + '-entry.mjs')], outfile: resolve(output, name + '.cjs'), bundle: true, platform: 'node', diff --git a/tests/Frameworks/hono/compare-native.py b/tests/Frameworks/hono/compare-native.py index 5b95b390..a1b0fff1 100644 --- a/tests/Frameworks/hono/compare-native.py +++ b/tests/Frameworks/hono/compare-native.py @@ -42,6 +42,8 @@ row['missing'] = list((expected - actual).elements()) row['unexpected'] = list((actual - expected).elements()) result = {'run': manifest['id'], 'runtime': args.runtime, 'files': comparison, + 'timeoutScale': manifest.get('timeoutScale', 1), + 'nativeVitestTimeouts': 'original Vitest configuration; framework timeout scaling is not applied', 'counts': dict(Counter(row['status'] for row in comparison))} output = args.manifest.parent / ('native-comparison-' + args.runtime + '.json') output.write_text(json.dumps(result, indent=2)) diff --git a/tests/Frameworks/hono/deadline.mjs b/tests/Frameworks/hono/deadline.mjs index 68cbb568..17cb0973 100644 --- a/tests/Frameworks/hono/deadline.mjs +++ b/tests/Frameworks/hono/deadline.mjs @@ -5,8 +5,40 @@ export const monotonicNow = globalThis.performance ? globalThis.performance.now. export const defaultTestTimeout = 5_000; export const defaultHookTimeout = 10_000; +export function parseTimeoutScale(value) { + const source = String(value).trim(); + if (!/^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/.test(source)) { + throw new Error('The timeout scale must be a finite positive number'); + } + const scale = Number(source); + if (!Number.isFinite(scale) || scale <= 0 || scale > 100) { + throw new Error('The timeout scale must be finite, greater than 0 and at most 100'); + } + return scale; +} + +export const timeoutScale = parseTimeoutScale(globalThis.process?.env?.PHASIS_FRAMEWORK_TIMEOUT_SCALE ?? '1'); + +export function scaledTimeout(originalTimeout, scale = timeoutScale) { + if (originalTimeout <= 0 || originalTimeout === Infinity) return originalTimeout; + const effectiveTimeout = originalTimeout * scale; + if (!Number.isFinite(effectiveTimeout) || effectiveTimeout <= 0 || effectiveTimeout > 2_147_483_647) { + throw new Error('The effective timeout must be finite, positive and at most 2147483647ms'); + } + return effectiveTimeout; +} + +export function timeoutSettings(originalTimeout) { + const effectiveTimeout = scaledTimeout(originalTimeout); + return { + originalTimeout: originalTimeout === Infinity ? 'Infinity' : originalTimeout, + effectiveTimeout: effectiveTimeout === Infinity ? 'Infinity' : effectiveTimeout, + }; +} + // Vitest 5 checks elapsed time even when synchronous work or microtasks starve timers. -export function withDeadline(action, timeout, isHook = false, abort) { +export function withDeadline(action, originalTimeout, isHook = false, abort) { + const timeout = scaledTimeout(originalTimeout); if (timeout <= 0 || timeout === Infinity) return action(); return new Promise((resolve, reject) => { const end = monotonicNow() + timeout; @@ -18,6 +50,8 @@ export function withDeadline(action, timeout, isHook = false, abort) { realClearTimeout(timer); const kind = isHook ? 'Hook' : 'Test'; const error = new Error(`${kind} timed out in ${timeout}ms.\nIf this is a long-running ${kind.toLowerCase()}, pass a timeout value as the last argument or configure it globally with "${isHook ? 'hookTimeout' : 'testTimeout'}".`); + error.originalTimeout = originalTimeout; + error.effectiveTimeout = timeout; try { abort?.(error); } catch (cause) { diff --git a/tests/Frameworks/hono/fixtures/timeout-scaling-entry.mjs b/tests/Frameworks/hono/fixtures/timeout-scaling-entry.mjs new file mode 100644 index 00000000..c64ba454 --- /dev/null +++ b/tests/Frameworks/hono/fixtures/timeout-scaling-entry.mjs @@ -0,0 +1,7 @@ +import { run } from '../harness.mjs'; +import './timeout-scaling.test.mjs'; +run().then(report => { + globalThis.__honoReport = report; + if (globalThis.__honoComplete) globalThis.__honoComplete(); + else process.stdout.write('__PHASIS_HONO_REPORT__' + JSON.stringify(report) + '\n', () => process.exit(0)); +}); diff --git a/tests/Frameworks/hono/fixtures/timeout-scaling.test.mjs b/tests/Frameworks/hono/fixtures/timeout-scaling.test.mjs new file mode 100644 index 00000000..af112049 --- /dev/null +++ b/tests/Frameworks/hono/fixtures/timeout-scaling.test.mjs @@ -0,0 +1,35 @@ +import { setTimeout as nativeTimeout } from 'node:timers'; +import { parseTimeoutScale, scaledTimeout } from '../deadline.mjs'; +const realNow = performance.now.bind(performance); +const delay = duration => new Promise(resolve => nativeTimeout(resolve, duration)); +const busy = duration => { + const end = realNow() + duration; + while (realNow() < end) {} +}; + +test('scale validation and timer bounds', () => { + expect(parseTimeoutScale('2.5')).toBe(2.5); + for (const value of ['', '0', '-1', 'NaN', 'Infinity', '1e500', '1e-500', '1_0', '0x10', '101', '1e6']) { + expect(() => parseTimeoutScale(value)).toThrow(); + } + expect(() => scaledTimeout(1e9, 10)).toThrow(); + expect(() => scaledTimeout(Number.MIN_VALUE, .5)).toThrow(); + expect(scaledTimeout(0, 10)).toBe(0); + expect(scaledTimeout(Infinity, 10)).toBe(Infinity); +}); +test('explicit awaited deadline', () => delay(60), 20); +test('explicit elapsed deadline', { timeout: 20 }, () => busy(60)); +test('disabled deadline stays disabled', () => delay(30), 0); +test('infinite deadline stays disabled', { timeout: Infinity }, () => delay(30)); +describe('scaled beforeEach', () => { + beforeEach(() => busy(60), 20); + test('hook completes within effective deadline', () => expect(true).toBe(true)); +}); +describe('scaled beforeAll', () => { + beforeAll(() => delay(60), 20); + test('setup completes within effective deadline', () => expect(true).toBe(true)); +}); +describe('scaled cleanup', () => { + beforeEach(() => () => delay(60), 20); + test('cleanup completes within effective deadline', () => expect(true).toBe(true)); +}); diff --git a/tests/Frameworks/hono/harness.mjs b/tests/Frameworks/hono/harness.mjs index d320743e..e1bb5bf5 100644 --- a/tests/Frameworks/hono/harness.mjs +++ b/tests/Frameworks/hono/harness.mjs @@ -8,7 +8,7 @@ import { fn, spyOn, clearAllMocks, resetAllMocks, restoreAllMocks } from '@vites import { expectTypeOf } from 'expect-type'; import fakeTimers from '@sinonjs/fake-timers'; import { format } from '@vitest/pretty-format'; -import { defaultTestTimeout, defaultHookTimeout, withDeadline, monotonicNow } from './deadline.mjs'; +import { defaultTestTimeout, defaultHookTimeout, withDeadline, monotonicNow, timeoutScale, timeoutSettings } from './deadline.mjs'; chai.use(JestExtend); chai.use(JestChaiExpect); @@ -192,6 +192,7 @@ function fullName(entry) { } function failure(error, depth = 0) { return { name: error?.name || 'Error', message: String(error?.message ?? error), stack: String(error?.stack || ''), + ...(error?.originalTimeout !== undefined ? { originalTimeout: error.originalTimeout, effectiveTimeout: error.effectiveTimeout } : {}), ...(error?.cause !== undefined && depth < 3 ? { cause: failure(error.cause, depth + 1) } : {}) }; } async function invoke(hook, context) { @@ -200,8 +201,10 @@ async function invoke(hook, context) { } async function runCase(entry, ancestors, results, inheritedError) { const started = monotonicNow(); - const record = { id: entry.id, name: fullName(entry), status: 'pass', assertions: 0 }; - globalThis.__honoCase?.(JSON.stringify({ id: record.id, name: record.name })); + const record = { id: entry.id, name: fullName(entry), status: 'pass', assertions: 0, + ...timeoutSettings(entry.options.timeout ?? defaultTestTimeout) }; + globalThis.__honoCase?.(JSON.stringify({ id: record.id, name: record.name, + originalTimeout: record.originalTimeout, effectiveTimeout: record.effectiveTimeout })); if (entry.skipped) { record.status = 'upstream-skip'; results.push(record); @@ -296,5 +299,6 @@ export async function run() { await runSuite(root, [], results); const counts = { pass: 0, fail: 0, 'upstream-skip': 0, 'harness-blocked': 0, 'suite-blocked': 0 }; for (const result of results) counts[result.status]++; - return { counts, results, suiteErrors }; + return { counts, results, suiteErrors, timeoutScale, + timeouts: { test: timeoutSettings(defaultTestTimeout), hook: timeoutSettings(defaultHookTimeout) } }; } diff --git a/tests/Frameworks/hono/run.py b/tests/Frameworks/hono/run.py index 82fbbcf2..6671e5c2 100644 --- a/tests/Frameworks/hono/run.py +++ b/tests/Frameworks/hono/run.py @@ -3,6 +3,7 @@ import argparse import json import hashlib +import math from datetime import datetime, timezone from uuid import uuid4 from inventory import inventory as upstream_inventory @@ -48,9 +49,10 @@ def terminate_group(process): process.wait() -def execute(command, timeout, project="main", log_file=None): +def execute(command, timeout, project="main", log_file=None, timeout_scale=1): try: - environment = dict(os.environ, XDEBUG_MODE='off', PHASIS_HONO_PROJECT=project) + environment = dict(os.environ, XDEBUG_MODE='off', PHASIS_HONO_PROJECT=project, + PHASIS_FRAMEWORK_TIMEOUT_SCALE=str(timeout_scale)) if project == 'node': environment['NAME'] = 'Node' environment.pop('NO_COLOR', None) @@ -104,10 +106,23 @@ def php_memory_limit(value): return match[1] + suffix +def timeout_scale(value): + source = str(value).strip() + if re.fullmatch(r'[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?', source) is None: + raise argparse.ArgumentTypeError('The timeout scale must be a finite positive number') + scale = float(source) + if not math.isfinite(scale) or scale <= 0 or scale > 100: + raise argparse.ArgumentTypeError('The timeout scale must be finite, greater than 0 and at most 100') + return scale + + def parse_arguments(arguments=None): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('files', nargs='*') parser.add_argument('--timeout', type=float, default=1800) + parser.add_argument('--timeout-scale', type=timeout_scale, + default=os.environ.get('PHASIS_FRAMEWORK_TIMEOUT_SCALE', '1'), + help='Multiply framework test/hook deadlines by >0 and <=100 (default: environment or 1); not the process watchdog') parser.add_argument('--project', choices=['main', 'jsx-runtime-default', 'jsx-runtime-dom', 'node'], default='main') parser.add_argument('--runtime', choices=['node', 'phasis', 'both'], default='both') parser.add_argument('--no-build', action='store_true') @@ -138,6 +153,10 @@ def main(): 'inventory': inventory, 'upstreamProjects': all_projects, 'selected': files, 'runtimes': args.runtime, 'timeoutSeconds': args.timeout, 'phpMemoryLimit': args.php_memory_limit, + 'timeoutScale': args.timeout_scale, + 'timeouts': {'test': {'originalTimeout': 5000, 'effectiveTimeout': 5000 * args.timeout_scale}, + 'hook': {'originalTimeout': 10000, 'effectiveTimeout': 10000 * args.timeout_scale}}, + 'nativeVitestTimeouts': 'unchanged; configure the independent native runner separately', 'runtimeSourceAtStart': source_hash(REPOSITORY / 'src'), 'harnessSourceAtStart': harness_hash(), 'dependenciesAtStart': dependency_hash(), 'complete': False, 'files': manifest} @@ -156,7 +175,8 @@ def save_manifest(): manifest.append(row) save_manifest() if not args.no_build: - status, output = execute(['node', str(DIRECTORY / 'build.mjs'), name], args.timeout, args.project) + status, output = execute(['node', str(DIRECTORY / 'build.mjs'), name], args.timeout, args.project, + timeout_scale=args.timeout_scale) save(identifier + '-build.log', output) if status: row['build'] = {'status': 'build-blocked', 'exitCode': status} @@ -174,7 +194,7 @@ def save_manifest(): 'php', '-d', 'memory_limit=' + args.php_memory_limit, str(DIRECTORY / 'run-php.php'), script] started = time.monotonic() status, output = execute(command, args.timeout, args.project, - archive / (identifier + '-' + runtime + '.log')) + archive / (identifier + '-' + runtime + '.log'), timeout_scale=args.timeout_scale) row.setdefault('elapsedSeconds', {})[runtime] = round(time.monotonic() - started, 3) save(identifier + '-' + runtime + '.log', output) reports = [line[len(PREFIX):] for line in output.splitlines() if line.startswith(PREFIX)] @@ -182,7 +202,9 @@ def save_manifest(): row['runtimes'][runtime] = {'status': 'process-blocked', 'exitCode': status} else: report = json.loads(reports[0]) - if not report['results']: + if report.get('timeoutScale') != args.timeout_scale: + row['runtimes'][runtime] = {'status': 'timeout-configuration-mismatch', 'exitCode': status} + elif not report['results']: row['runtimes'][runtime] = {'status': 'empty-discovery', 'exitCode': status} else: save(identifier + '-' + runtime + '.json', json.dumps(report, indent=2)) diff --git a/tests/Frameworks/hono/selftest.py b/tests/Frameworks/hono/selftest.py index 9d81401d..47f1a2ab 100644 --- a/tests/Frameworks/hono/selftest.py +++ b/tests/Frameworks/hono/selftest.py @@ -24,6 +24,7 @@ def main(): 'phasis': ['php', '-d', 'memory_limit=1G', str(DIRECTORY / 'run-php.php'), str(script)], } manifest = {'id': run_id, 'kind': 'harness-deadline-selftest', 'results': {}, + 'timeoutScale': 1, 'nativeVitestTimeouts': 'original Vitest configuration', 'runtimeSource': source_hash(REPOSITORY / 'src'), 'harnessSource': harness_hash()} for runtime, command in commands.items(): status, output = execute(command, 60, log_file=archive / (runtime + '.log')) @@ -87,6 +88,37 @@ def main(): if schedules[runtime] != schedules['native']: manifest['results'][runtime]['differences'].append('lifecycle job scheduling differs') manifest['scheduling'] = schedules + scaling = {} + for scale in [1, 10]: + for runtime in ['node', 'phasis']: + script = DIRECTORY / '.generated/selftest/timeout-scaling.mjs' + command = ['node', str(script)] if runtime == 'node' else [ + 'php', '-d', 'memory_limit=1G', str(DIRECTORY / 'run-php.php'), str(script)] + label = 'timeout-scaling-' + runtime + '-' + str(scale) + status, output = execute(command, 60, log_file=archive / (label + '.log'), timeout_scale=scale) + reports = [json.loads(line[len(PREFIX):]) for line in output.splitlines() if line.startswith(PREFIX)] + if status != 0 or len(reports) != 1: + raise RuntimeError(label + ' did not finish') + report = reports[0] + (archive / (label + '.json')).write_text(json.dumps(report, indent=2)) + expected = {'pass': 8, 'fail': 0, 'upstream-skip': 0, 'harness-blocked': 0, 'suite-blocked': 0} if scale == 10 else { + 'pass': 3, 'fail': 4, 'upstream-skip': 0, 'harness-blocked': 0, 'suite-blocked': 1} + if report['timeoutScale'] != scale or report['counts'] != expected: + raise RuntimeError(label + ' produced incorrect deadline outcomes') + for case in report['results']: + original = 20 if case['name'].startswith('explicit ') else 0 if case['name'].startswith('disabled ') else ( + 'Infinity' if case['name'].startswith('infinite ') else 5000) + effective = original * scale if isinstance(original, int) else original + if (case['originalTimeout'], case['effectiveTimeout']) != (original, effective): + raise RuntimeError(label + ': incorrect recorded limit for ' + case['name']) + if scale == 1 and case['status'] in ['fail', 'suite-blocked']: + if (case['error'].get('originalTimeout'), case['error'].get('effectiveTimeout')) != (20, 20): + raise RuntimeError(label + ': missing original hook/test deadline evidence') + scaling[label] = [(case['id'], case['name'], case['status'], case['assertions'], + case['originalTimeout'], case['effectiveTimeout']) for case in report['results']] + if scaling['timeout-scaling-node-' + str(scale)] != scaling['timeout-scaling-phasis-' + str(scale)]: + raise RuntimeError('Node/Phasis timeout scaling case identities, assertions or outcomes differ') + manifest['timeoutScaling'] = scaling (archive / 'manifest.json').write_text(json.dumps(manifest, indent=2)) print(json.dumps(manifest['results'])) print('Run manifest:', archive / 'manifest.json') diff --git a/tests/Frameworks/hono/test_runner.py b/tests/Frameworks/hono/test_runner.py index dd56d276..1392072b 100644 --- a/tests/Frameworks/hono/test_runner.py +++ b/tests/Frameworks/hono/test_runner.py @@ -5,10 +5,45 @@ import sys import time import unittest +from unittest.mock import patch from run import execute, parse_arguments +class TimeoutScaleTest(unittest.TestCase): + def test_default_environment_and_cli_precedence(self): + with patch.dict(os.environ, {}, clear=True): + self.assertEqual(parse_arguments([])[1].timeout_scale, 1) + with patch.dict(os.environ, {'PHASIS_FRAMEWORK_TIMEOUT_SCALE': '2.5'}): + self.assertEqual(parse_arguments([])[1].timeout_scale, 2.5) + self.assertEqual(parse_arguments(['--timeout-scale', '10'])[1].timeout_scale, 10) + with patch.dict(os.environ, {'PHASIS_FRAMEWORK_TIMEOUT_SCALE': 'invalid'}): + self.assertEqual(parse_arguments(['--timeout-scale', '3'])[1].timeout_scale, 3) + with contextlib.redirect_stderr(io.StringIO()), self.assertRaises(SystemExit): + parse_arguments([]) + + def test_valid_scales(self): + for source, expected in [('1', 1), ('10', 10), ('100', 100), ('0.5', .5), ('2e1', 20), ('.25', .25)]: + with self.subTest(source=source): + self.assertEqual(parse_arguments(['--timeout-scale', source])[1].timeout_scale, expected) + + def test_invalid_and_overflowing_scales_are_rejected(self): + for value in ['', '0', '-1', 'NaN', 'Infinity', '1e500', '1e-500', '1_0', '0x10', '101', '1e6']: + with self.subTest(value=value), contextlib.redirect_stderr(io.StringIO()): + with self.assertRaises(SystemExit) as error: + parse_arguments(['--timeout-scale', value]) + self.assertEqual(error.exception.code, 2) + + def test_worker_scale_is_explicit_and_does_not_change_watchdog(self): + program = "import os; print(os.environ['PHASIS_FRAMEWORK_TIMEOUT_SCALE'])" + with patch.dict(os.environ, {'PHASIS_FRAMEWORK_TIMEOUT_SCALE': '99'}): + self.assertEqual(execute([sys.executable, '-c', program], 5)[1].strip(), '1') + self.assertEqual(execute([sys.executable, '-c', program], 5, timeout_scale=10)[1].strip(), '10') + status, output = execute([sys.executable, '-c', 'import time; time.sleep(60)'], .05, timeout_scale=10) + self.assertEqual(status, 124) + self.assertIn('PROCESS TIMEOUT', output) + + class WorkerMemoryTest(unittest.TestCase): def test_default_and_explicit_memory_limits(self): _, default = parse_arguments([]) From af483e2d8ff9341b2a517b9e282f147ba474843e Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 09:23:23 +0200 Subject: [PATCH 96/99] Verify scaled Hono deadlines still reject late work --- .../Frameworks/hono/fixtures/timeout-scaling.test.mjs | 10 +++++++++- tests/Frameworks/hono/selftest.py | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/Frameworks/hono/fixtures/timeout-scaling.test.mjs b/tests/Frameworks/hono/fixtures/timeout-scaling.test.mjs index af112049..882a6c21 100644 --- a/tests/Frameworks/hono/fixtures/timeout-scaling.test.mjs +++ b/tests/Frameworks/hono/fixtures/timeout-scaling.test.mjs @@ -1,5 +1,5 @@ import { setTimeout as nativeTimeout } from 'node:timers'; -import { parseTimeoutScale, scaledTimeout } from '../deadline.mjs'; +import { parseTimeoutScale, scaledTimeout, timeoutScale, withDeadline } from '../deadline.mjs'; const realNow = performance.now.bind(performance); const delay = duration => new Promise(resolve => nativeTimeout(resolve, duration)); const busy = duration => { @@ -17,6 +17,14 @@ test('scale validation and timer bounds', () => { expect(scaledTimeout(0, 10)).toBe(0); expect(scaledTimeout(Infinity, 10)).toBe(Infinity); }); +test('scaled deadlines remain enforced', async () => { + for (const action of [() => delay(60), () => busy(60)]) { + await expect(withDeadline(action, 1)).rejects.toMatchObject({ + originalTimeout: 1, + effectiveTimeout: timeoutScale, + }); + } +}); test('explicit awaited deadline', () => delay(60), 20); test('explicit elapsed deadline', { timeout: 20 }, () => busy(60)); test('disabled deadline stays disabled', () => delay(30), 0); diff --git a/tests/Frameworks/hono/selftest.py b/tests/Frameworks/hono/selftest.py index 47f1a2ab..aaff1db1 100644 --- a/tests/Frameworks/hono/selftest.py +++ b/tests/Frameworks/hono/selftest.py @@ -101,8 +101,8 @@ def main(): raise RuntimeError(label + ' did not finish') report = reports[0] (archive / (label + '.json')).write_text(json.dumps(report, indent=2)) - expected = {'pass': 8, 'fail': 0, 'upstream-skip': 0, 'harness-blocked': 0, 'suite-blocked': 0} if scale == 10 else { - 'pass': 3, 'fail': 4, 'upstream-skip': 0, 'harness-blocked': 0, 'suite-blocked': 1} + expected = {'pass': 9, 'fail': 0, 'upstream-skip': 0, 'harness-blocked': 0, 'suite-blocked': 0} if scale == 10 else { + 'pass': 4, 'fail': 4, 'upstream-skip': 0, 'harness-blocked': 0, 'suite-blocked': 1} if report['timeoutScale'] != scale or report['counts'] != expected: raise RuntimeError(label + ' produced incorrect deadline outcomes') for case in report['results']: From ba89283bf85109812740580ecf7faf028f99713f Mon Sep 17 00:00:00 2001 From: dnnsjsk Date: Sat, 24 Oct 2026 09:23:54 +0200 Subject: [PATCH 97/99] Allow bounded timeout scaling for Express framework checks --- tests/Frameworks/express/run-node.cjs | 9 ++ tests/Frameworks/express/run-phasis.php | 13 +- tests/Frameworks/express/run.py | 27 +++- tests/Frameworks/express/runner.cjs | 62 ++++++++- tests/Frameworks/express/test_runner.py | 162 +++++++++++++++++++++++- 5 files changed, 261 insertions(+), 12 deletions(-) diff --git a/tests/Frameworks/express/run-node.cjs b/tests/Frameworks/express/run-node.cjs index 3e861583..218ecc2b 100644 --- a/tests/Frameworks/express/run-node.cjs +++ b/tests/Frameworks/express/run-node.cjs @@ -8,6 +8,14 @@ const args = process.argv.slice(2); const selectedFile = args.find((arg) => arg.startsWith('--file='))?.slice(7); const selectedGrep = args.find((arg) => arg.startsWith('--grep='))?.slice(7); const output = args.find((arg) => arg.startsWith('--output='))?.slice(9); +const scaleIndex = args.findIndex(arg => arg === '--timeout-scale' || arg.startsWith('--timeout-scale=')); +const rawScale = scaleIndex < 0 ? (process.env.PHASIS_FRAMEWORK_TIMEOUT_SCALE ?? '1') + : args[scaleIndex] === '--timeout-scale' ? args[scaleIndex + 1] : args[scaleIndex].slice(16); +if (typeof rawScale !== 'string' || !/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(rawScale.trim()) + || !Number.isFinite(Number(rawScale)) || Number(rawScale) <= 0 || Number(rawScale) > 100) { + throw new Error('--timeout-scale must be a finite positive number at most 100.'); +} +const timeoutScale = Number(rawScale); const pinned = JSON.parse(fs.readFileSync(path.join(__dirname, 'manifest.json'), 'utf8')); const manifest = pinned.files.filter(file => !selectedFile || file.path === selectedFile); if (!manifest.length) throw new Error('The requested file is not part of the pinned Express suite.'); @@ -26,6 +34,7 @@ globalThis.__expressFinished = function finished(serialized) { process.exitCode = result.fail || result.pending || result.loadErrors.length || result.asynchronousErrors.length ? 1 : 0; }; require('./runner.cjs')(files, { + timeoutScale, grep: selectedGrep, expectedTests: manifest.reduce((sum, file) => sum + file.tests, 0), expectedCases: manifest.flatMap(file => file.cases), diff --git a/tests/Frameworks/express/run-phasis.php b/tests/Frameworks/express/run-phasis.php index fd926545..9409d934 100644 --- a/tests/Frameworks/express/run-phasis.php +++ b/tests/Frameworks/express/run-phasis.php @@ -7,7 +7,16 @@ use Phasis\Engine; use Phasis\Node\NodeOptions; -$options = getopt('', ['file:', 'grep:', 'output:', 'budget:']); +$options = getopt('', ['file:', 'grep:', 'output:', 'budget:', 'timeout-scale:']); +if (in_array('--timeout-scale', $argv, true) && !array_key_exists('timeout-scale', $options)) { + throw new InvalidArgumentException('--timeout-scale requires a numeric value.'); +} +$scaleEnvironment = getenv('PHASIS_FRAMEWORK_TIMEOUT_SCALE'); +$rawScale = $options['timeout-scale'] ?? ($scaleEnvironment === false ? '1' : $scaleEnvironment); +if (!is_string($rawScale) || !is_numeric($rawScale) || !is_finite((float) $rawScale) || (float) $rawScale <= 0 || (float) $rawScale > 100) { + throw new InvalidArgumentException('--timeout-scale must be a finite positive number at most 100.'); +} +$timeoutScale = (float) $rawScale; $root = __DIR__ . '/upstream'; $pinned = json_decode((string) file_get_contents(__DIR__ . '/manifest.json'), true, 512, JSON_THROW_ON_ERROR); $files = []; @@ -64,6 +73,7 @@ $engine->setGlobal('__expressFiles', $files); $engine->setGlobal('__expressRunner', __DIR__ . '/runner.cjs'); $engine->setGlobal('__expressOptions', [ + 'timeoutScale' => $timeoutScale, 'grep' => $options['grep'] ?? null, 'expectedTests' => array_sum(array_column($manifest, 'tests')), 'expectedCases' => array_merge(...array_column($manifest, 'cases')), @@ -97,6 +107,7 @@ 'source' => $metadata, 'filtered' => isset($options['file']) || isset($options['grep']), 'manifest' => $manifest, + 'timeoutScale' => $timeoutScale, ] + $result; $serialized = json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE | JSON_THROW_ON_ERROR) . "\n"; if (isset($options['output'])) { diff --git a/tests/Frameworks/express/run.py b/tests/Frameworks/express/run.py index 0e5ffdfa..a1b4e9c4 100644 --- a/tests/Frameworks/express/run.py +++ b/tests/Frameworks/express/run.py @@ -6,7 +6,9 @@ import datetime import hashlib import json +import math import os +import re from pathlib import Path import signal import subprocess @@ -28,11 +30,21 @@ def tree_hash(directory): return digest.hexdigest() -def source_identity(): +def timeout_scale(value): + if not re.fullmatch(r"[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?", str(value).strip()): + raise argparse.ArgumentTypeError("timeout scale must be a finite positive number") + number = float(value) + if not math.isfinite(number) or number <= 0 or number > 100: + raise argparse.ArgumentTypeError("timeout scale must be a finite positive number at most 100") + return number + + +def source_identity(scale=1): harness = hashlib.sha256() for name in ("run.py", "runner.cjs", "run-node.cjs", "run-phasis.php", "setup.py", "upstream.json"): harness.update(name.encode() + b"\0" + (HERE / name).read_bytes()) return { + "timeoutScale": scale, "runtimeSha256": tree_hash(REPOSITORY / "src"), "upstreamSha256": tree_hash(HERE / "upstream"), "manifestSha256": hashlib.sha256((HERE / "manifest.json").read_bytes()).hexdigest(), @@ -65,6 +77,8 @@ def main(): parser.add_argument("--runtime", choices=("node", "phasis", "both"), default="both") parser.add_argument("--jobs", type=int, choices=(1, 2), default=1) parser.add_argument("--timeout", type=float, default=1800) + parser.add_argument("--timeout-scale", type=timeout_scale, + default=os.environ.get("PHASIS_FRAMEWORK_TIMEOUT_SCALE", "1")) parser.add_argument("--output", type=Path, required=True) args = parser.parse_args() if args.timeout <= 0: @@ -75,7 +89,7 @@ def main(): args.output.mkdir(parents=True) manifest = json.loads((HERE / "manifest.json").read_text()) source = json.loads((HERE / "upstream.json").read_text()) - identity_before = source_identity() + identity_before = source_identity(args.timeout_scale) runtimes = ["node", "phasis"] if args.runtime == "both" else [args.runtime] tasks = [(runtime, entry) for runtime in runtimes for entry in manifest["files"]] stopped = threading.Event() @@ -97,7 +111,7 @@ def execute(task): log = output.with_suffix(".log") command = (["node", str(HERE / "run-node.cjs")] if runtime == "node" else ["php", "-d", "memory_limit=1G", str(HERE / "run-phasis.php")]) - command += ["--file=" + entry["path"], "--output=" + str(output)] + command += ["--file=" + entry["path"], "--output=" + str(output), "--timeout-scale=" + str(args.timeout_scale)] timed_out = False start = time.monotonic() with log.open("w") as handle: @@ -135,6 +149,7 @@ def execute(task): "exitCode": exit_code, "timedOut": timed_out, "log": log.name, "elapsedSeconds": time.monotonic() - start, "caseIdentityMatches": case_identity_matches, "unaccountedCases": missing, + "timeoutScaleMatches": report.get("timeoutScale") == args.timeout_scale, "report": report, } print(json.dumps({key: value for key, value in result.items() if key not in ("report", "unaccountedCases")} @@ -171,14 +186,15 @@ def execute(task): results.append(result) for name, handler in previous_handlers.items(): signal.signal(name, handler) - identity_after = source_identity() + identity_after = source_identity(args.timeout_scale) stable_source = identity_before == identity_after summary = { "generatedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(), "source": source, "manifest": manifest, "filtered": False, "identityBefore": identity_before, "identityAfter": identity_after, "stableSource": stable_source, "interrupted": stopped.is_set(), - "execution": {"isolation": "file", "workers": args.jobs, "timeoutSeconds": args.timeout}, + "execution": {"isolation": "file", "workers": args.jobs, "timeoutSeconds": args.timeout, + "timeoutScale": args.timeout_scale}, "runtimes": {}, "files": results, } successful = stable_source and not stopped.is_set() @@ -206,6 +222,7 @@ def execute(task): and not unaccounted and values["pass"] == values["expectedTests"] and values["fail"] == values["pending"] == values["loadErrors"] == values["asynchronousErrors"] == 0 and all(result["exitCode"] == 0 for result in selected.values())) + values["success"] = values["success"] and all(result["timeoutScaleMatches"] for result in selected.values()) successful = successful and values["success"] summary["runtimes"][runtime] = values (args.output / "summary.json").write_text(json.dumps(summary, indent=2) + "\n") diff --git a/tests/Frameworks/express/runner.cjs b/tests/Frameworks/express/runner.cjs index b132507d..baeee67f 100644 --- a/tests/Frameworks/express/runner.cjs +++ b/tests/Frameworks/express/runner.cjs @@ -13,8 +13,61 @@ function serializeError(error) { } module.exports = function runExpressTests(files, options = {}) { - const output = { complete: false, discovered: 0, pass: 0, fail: 0, pending: 0, tests: [], loadErrors: [], asynchronousErrors: [] }; + const rawScale = options.timeoutScale === undefined ? 1 : options.timeoutScale; + if ((typeof rawScale !== 'number' && typeof rawScale !== 'string') || String(rawScale).trim() === '' + || !/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(String(rawScale).trim()) + || !Number.isFinite(Number(rawScale)) || Number(rawScale) <= 0 || Number(rawScale) > 100) { + throw new TypeError('timeoutScale must be a finite positive number at most 100.'); + } + const timeoutScale = Number(rawScale); + const output = { timeoutScale, complete: false, discovered: 0, pass: 0, fail: 0, pending: 0, tests: [], loadErrors: [], asynchronousErrors: [] }; const caseIds = new WeakMap(); + const timeouts = new WeakMap(); + const runnable = Mocha.Runnable.prototype; + const originalRun = runnable.run; + const originalTimeout = runnable.timeout; + function effectiveTimeout(original) { + if (original === 0) return 0; + const effective = original * timeoutScale; + if (!Number.isFinite(effective) || effective <= 0 || effective > 2147483647) { + throw new RangeError('The scaled timeout must fit a positive 32-bit timer.'); + } + return effective; + } + function timeoutDetails(test) { + return timeouts.get(test) || { originalTimeout: test.timeout(), effectiveTimeout: effectiveTimeout(test.timeout()) }; + } + // Keep declarations raw so inherited hooks and retry clones are scaled once. + runnable.run = function (callback) { + const test = this; + const ownTimeout = Object.prototype.hasOwnProperty.call(test, 'timeout'); + const previousTimeout = test.timeout; + const state = { originalTimeout: originalTimeout.call(test), effectiveTimeout: null }; + timeouts.set(test, state); + function restore() { + test._timeout = state.originalTimeout; + if (ownTimeout) test.timeout = previousTimeout; + else delete test.timeout; + } + test.timeout = function (value) { + if (arguments.length === 0) return originalTimeout.call(test); + const timer = test.timer; + test.timer = null; + try { originalTimeout.call(test, value); } + finally { test.timer = timer; } + state.originalTimeout = originalTimeout.call(test); + state.effectiveTimeout = null; + state.effectiveTimeout = effectiveTimeout(state.originalTimeout); + test._timeout = state.effectiveTimeout; + if (timer) test.resetTimeout(); + return test; + }; + try { test.timeout(state.originalTimeout); } + catch (error) { restore(); callback(error); return; } + try { + return originalRun.call(test, error => { restore(); callback(error); }); + } catch (error) { restore(); throw error; } + }; let responses = []; const ClientRequest = require('http').ClientRequest; const originalEmit = ClientRequest.prototype.emit; @@ -38,17 +91,17 @@ module.exports = function runExpressTests(files, options = {}) { }); runner.on('pass', (test) => { output.pass++; - output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'pass', duration: test.duration }); + output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'pass', duration: test.duration, ...timeoutDetails(test) }); if (output.tests.length % 100 === 0) checkpoint(); }); runner.on('fail', (test, error) => { output.fail++; - output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'fail', duration: test.duration, error: serializeError(error), responses }); + output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'fail', duration: test.duration, ...timeoutDetails(test), error: serializeError(error), responses }); checkpoint(); }); runner.on('pending', (test) => { output.pending++; - output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'pending' }); + output.tests.push({ id: caseIds.get(test), title: test.fullTitle(), file: test.file, status: 'pending', ...timeoutDetails(test) }); }); } }); const onUncaught = (error) => { @@ -87,6 +140,7 @@ module.exports = function runExpressTests(files, options = {}) { checkpoint(); if (options.grep) mocha.grep(new RegExp(options.grep)); mocha.run(() => { + runnable.run = originalRun; ClientRequest.prototype.emit = originalEmit; process.removeListener('uncaughtException', onUncaught); process.removeListener('unhandledRejection', onUncaught); diff --git a/tests/Frameworks/express/test_runner.py b/tests/Frameworks/express/test_runner.py index 0ded569c..99cba89f 100644 --- a/tests/Frameworks/express/test_runner.py +++ b/tests/Frameworks/express/test_runner.py @@ -1,14 +1,172 @@ -"""Regression checks for owned worker-process cleanup.""" +"""Regression checks for timeout settings and owned worker-process cleanup.""" +import argparse +import json import os from pathlib import Path +import re import selectors +import shutil import subprocess import sys +import tempfile import unittest +from unittest import mock sys.path.insert(0, str(Path(__file__).resolve().parent)) -from run import terminate_group +from run import source_identity, terminate_group, timeout_scale + +HERE = Path(__file__).resolve().parent + + +class TimeoutScaleParsingTest(unittest.TestCase): + def test_finite_positive_bounded_decimal_scales(self): + for value in ("1", "10", "100", ".5", "1e1"): + self.assertGreater(timeout_scale(value), 0) + for value in ("", "NaN", "Infinity", "-Infinity", "0", "-1", "101", "1e400", "0x10", "1_0"): + with self.subTest(value=value), self.assertRaises(argparse.ArgumentTypeError): + timeout_scale(value) + + def test_source_identity_records_the_timeout_setting(self): + with mock.patch("run.tree_hash", return_value="unchanged"): + first = source_identity(1) + scaled = source_identity(10) + self.assertEqual(first["runtimeSha256"], scaled["runtimeSha256"]) + self.assertEqual(first["timeoutScale"], 1) + self.assertEqual(scaled["timeoutScale"], 10) + + +@unittest.skipUnless(shutil.which("node") and (HERE.parent / "node_modules/mocha/mocha.js").is_file(), + "requires the prepared Mocha dependency") +class TimeoutRunnerTest(unittest.TestCase): + def run_control(self, body, titles, *, scale=1, timeout=30): + with tempfile.TemporaryDirectory(prefix="phasis-timeout-control-") as temporary: + directory = Path(temporary) + source = directory / "control.cjs" + output = directory / "result.json" + source.write_text(body) + options = {"timeout": timeout, "expectedTests": len(titles), + "expectedCases": [{"id": f"control.js:{index + 1}", "title": title} + for index, title in enumerate(titles)], + "fileNames": {str(source): "control.js"}} + if scale is not None: + options["timeoutScale"] = scale + program = ("globalThis.__expressFinished=s=>require('node:fs').writeFileSync(" + + json.dumps(str(output)) + ",s);require(" + json.dumps(str(HERE / "runner.cjs")) + + ")(" + json.dumps([str(source)]) + "," + json.dumps(options) + ");") + result = subprocess.run(["node", "-e", program], cwd=HERE, + capture_output=True, text=True, timeout=5) + self.assertEqual(result.returncode, 0, result.stderr) + report = json.loads(output.read_text()) + self.assertTrue(report["complete"]) + self.assertEqual(report["caseManifest"], options["expectedCases"]) + self.assertEqual(report["loadErrors"], []) + self.assertEqual(report["asynchronousErrors"], []) + return report + + def test_default_one_and_scaled_async_deadline(self): + body = "it('async', function(done) { setTimeout(done, 60); });" + normal = self.run_control(body, ["async"], scale=None, timeout=30) + scaled = self.run_control(body, ["async"], scale=4, timeout=30) + self.assertEqual((normal["timeoutScale"], normal["fail"]), (1, 1)) + self.assertEqual((scaled["timeoutScale"], scaled["pass"]), (4, 1)) + self.assertEqual(scaled["tests"][0]["id"], "control.js:1") + self.assertEqual(scaled["tests"][0]["originalTimeout"], 30) + self.assertEqual(scaled["tests"][0]["effectiveTimeout"], 120) + + def test_dynamic_explicit_async_and_synchronous_timeouts_still_fail(self): + for body in ( + "it('deadline', function(done) { this.timeout(10); setTimeout(done, 45); });", + "it('deadline', function() { this.timeout('10ms'); const end=Date.now()+35; while(Date.now() Date: Sat, 24 Oct 2026 10:11:09 +0200 Subject: [PATCH 98/99] Prepare v0.9.0 release --- CHANGELOG.md | 2 ++ src/Node/NodeRuntime.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 951997d6..a7b348dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [0.9.0] - 2026-10-24 + ### Added - Opt-in Node-compatible realms and `phasis --node`, with CommonJS package loading, Buffer and streams, filesystem and process I/O, HTTP/HTTPS/HTTP2, TLS, compression, timers, async context, and isolated VM realms. - Experimental Express and Hono support with pinned upstream runners, original assertions, case inventories, source hashes, bounded workers and real network interoperability checks. diff --git a/src/Node/NodeRuntime.php b/src/Node/NodeRuntime.php index 03d212ef..d54265b3 100644 --- a/src/Node/NodeRuntime.php +++ b/src/Node/NodeRuntime.php @@ -310,7 +310,7 @@ private function initializeProcess(): void $this->process->set('execPath', new JsString(PHP_BINARY)); $this->process->set('version', new JsString('v26.12.0')); $this->process->set('release', PhpToJs::convert(['name' => 'node'])); - $this->process->set('versions', PhpToJs::convert(['node' => '26.12.0', 'phasis' => '0.8.0', 'php' => PHP_VERSION])); + $this->process->set('versions', PhpToJs::convert(['node' => '26.12.0', 'phasis' => '0.9.0', 'php' => PHP_VERSION])); $this->process->set('platform', new JsString(match (PHP_OS_FAMILY) { 'Darwin' => 'darwin', 'Windows' => 'win32', default => strtolower(PHP_OS_FAMILY), })); From a60d51be185cb5a522b4e7462a63fe75cbf208ca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 24 Oct 2026 08:22:26 +0000 Subject: [PATCH 99/99] Update COMPAT.md from CI [skip ci] --- COMPAT.md | 44 +++++++------- compat.json | 168 ++++++++++++++++++++++++++++------------------------ 2 files changed, 111 insertions(+), 101 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index c0f4dcb8..1503a4f5 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -3,13 +3,13 @@ Generated from a completed `test262` pass. Do not edit by hand. - Refresh: `./bin/compat-report` -- Snapshot time: `2026-10-24T06:52:52+00:00` +- Snapshot time: `2026-10-24T08:22:25+00:00` - Chunk size: `25` - Timeout: `300s` - Jobs: `4` - Groups: `161` - Test files: `53616` -- Git: `feat/express-hono-compatibility` @ `094a3e46` (dirty) +- Git: `feat/express-hono-compatibility` @ `b4624b71` (dirty) ## Summary @@ -198,26 +198,26 @@ Generated from a completed `test262` pass. Do not edit by hand. | Group | Kind | Duration | Files | Sample | |---|---|---:|---:|---| -| staging/sm | NORMAL | 104.628s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | -| staging/sm | NORMAL | 102.486s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | -| staging/sm | NORMAL | 99.716s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | -| staging/sm | NORMAL | 96.997s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | -| staging/sm | NORMAL | 93.628s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | -| staging/sm | NORMAL | 92.071s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | -| built-ins/decodeURIComponent | NORMAL | 86.778s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | -| staging/sm | NORMAL | 84.784s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | -| intl402 | NORMAL | 82.707s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | -| staging/sm | NORMAL | 82.691s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | -| built-ins/decodeURI | NORMAL | 74.053s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | -| built-ins/TypedArray | NORMAL | 71.932s | 25 | `test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js`
...
`test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js`
`test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js` | -| staging/sm | NORMAL | 71.156s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | -| intl402/DateTimeFormat | NORMAL | 66.141s | 12 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js` | -| staging/sm | NORMAL | 61.245s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 58.922s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Math.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Noncharacter_Code_Point.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Pattern_Syntax.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 58.892s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Toto.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tulu_Tigalari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Ugaritic.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 58.834s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 58.569s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Glagolitic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Gothic.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Grantha.js` | -| built-ins/RegExp/property-escapes/generated | NORMAL | 58.052s | 3 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js` | +| staging/sm | NORMAL | 187.532s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js` | +| staging/sm | NORMAL | 185.335s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js` | +| staging/sm | NORMAL | 183.376s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js` | +| staging/sm | NORMAL | 181.430s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js` | +| staging/sm | NORMAL | 176.894s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js` | +| staging/sm | NORMAL | 167.859s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js` | +| built-ins/decodeURIComponent | NORMAL | 164.085s | 1 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js` | +| staging/sm | NORMAL | 156.742s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js` | +| staging/sm | NORMAL | 152.821s | 1 | `test262/test/staging/sm/TypedArray/sort_large_countingsort.js` | +| staging/sm | NORMAL | 149.594s | 1 | `test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js` | +| built-ins/decodeURI | NORMAL | 144.082s | 1 | `test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js` | +| staging/sm | NORMAL | 125.528s | 1 | `test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js` | +| built-ins/decodeURIComponent | NORMAL | 74.418s | 25 | `test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js`
...
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js`
`test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js` | +| built-ins/decodeURI | NORMAL | 73.594s | 25 | `test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js`
...
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js`
`test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js` | +| annexB/built-ins/RegExp | NORMAL | 64.136s | 25 | `test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js`
`test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js`
...
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js`
`test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js` | +| intl402/DateTimeFormat | NORMAL | 60.635s | 25 | `test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js`
`test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js`
...
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/name.js`
`test262/test/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js` | +| intl402 | NORMAL | 59.788s | 22 | `test262/test/intl402/constructors-string-and-single-element-array.js`
`test262/test/intl402/constructors-taint-Object-prototype-2.js`
...
`test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js`
`test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.566s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Nandinagari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_New_Tai_Lue.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Newa.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Nko.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Nushu.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 59.490s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Inscriptional_Parthian.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Javanese.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kaithi.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kannada.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Katakana.js` | +| built-ins/RegExp/property-escapes/generated | NORMAL | 58.496s | 5 | `test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Todhri.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Tolong_Siki.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Toto.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Tulu_Tigalari.js`
`test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Ugaritic.js` | ## Runner Caveats diff --git a/compat.json b/compat.json index 6c7657c0..b9fd4630 100644 --- a/compat.json +++ b/compat.json @@ -1,10 +1,10 @@ { - "generatedAt": "2026-10-24T06:52:52+00:00", - "updatedAt": "2026-10-24T06:52:52+00:00", + "generatedAt": "2026-10-24T08:22:25+00:00", + "updatedAt": "2026-10-24T08:22:25+00:00", "complete": true, "git": { "branch": "feat/express-hono-compatibility", - "commit": "094a3e46", + "commit": "b4624b71", "isDirty": true }, "environment": { @@ -19,8 +19,8 @@ }, "state": { "directory": ".compat-state", - "fingerprint": "e163187c171ee7421a46f7fceb96d62f8d4956e2", - "runIdentity": "313297c88a51d44a20f45aa2772ec07e4a625fab0cc942ba368956af4cf3303e" + "fingerprint": "6dae375cd029fff559e6f2252d22bcbacb3f0284", + "runIdentity": "0730fc2d37920605e99fb17b1b6f28fff808f5d951dec70f65acd883210dd4b3" }, "discovery": { "groupCount": 161, @@ -2719,34 +2719,34 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 104.628, + "durationSec": 187.532, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 102.486, + "durationSec": 185.335, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-4-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 99.716, + "durationSec": 183.376, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-7-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-8-of-8.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 96.997, + "durationSec": 181.43, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-3-of-8.js" @@ -2755,7 +2755,7 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 93.628, + "durationSec": 176.894, "filesCount": 1, "sampleFiles": [ "test262/test/staging/sm/Date/dst-offset-caching-2-of-8.js" @@ -2764,16 +2764,16 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 92.071, + "durationSec": 167.859, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" ] }, { "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 86.778, + "durationSec": 164.085, "filesCount": 1, "sampleFiles": [ "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js" @@ -2782,140 +2782,150 @@ { "group": "staging/sm", "kind": "normal", - "durationSec": 84.784, + "durationSec": 156.742, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-5-of-8.js" + "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" ] }, { - "group": "intl402", + "group": "staging/sm", "kind": "normal", - "durationSec": 82.707, - "filesCount": 22, + "durationSec": 152.821, + "filesCount": 1, "sampleFiles": [ - "test262/test/intl402/constructors-string-and-single-element-array.js", - "test262/test/intl402/constructors-taint-Object-prototype-2.js", - "...", - "test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js", - "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" + "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" ] }, { "group": "staging/sm", "kind": "normal", - "durationSec": 82.691, + "durationSec": 149.594, "filesCount": 1, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/sort_large_countingsort.js" + "test262/test/staging/sm/Date/dst-offset-caching-1-of-8.js" ] }, { "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 74.053, + "durationSec": 144.082, "filesCount": 1, "sampleFiles": [ "test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js" ] }, { - "group": "built-ins/TypedArray", + "group": "staging/sm", "kind": "normal", - "durationSec": 71.932, - "filesCount": 25, + "durationSec": 125.528, + "filesCount": 1, "sampleFiles": [ - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js", - "test262/test/built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js", - "...", - "test262/test/built-ins/TypedArray/prototype/copyWithin/not-a-constructor.js", - "test262/test/built-ins/TypedArray/prototype/copyWithin/prop-desc.js" + "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" ] }, { - "group": "staging/sm", + "group": "built-ins/decodeURIComponent", "kind": "normal", - "durationSec": 71.156, - "filesCount": 1, + "durationSec": 74.418, + "filesCount": 25, "sampleFiles": [ - "test262/test/staging/sm/Date/dst-offset-caching-6-of-8.js" + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js", + "...", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T1.js", + "test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.8_T2.js" ] }, { - "group": "intl402/DateTimeFormat", + "group": "built-ins/decodeURI", "kind": "normal", - "durationSec": 66.141, - "filesCount": 12, + "durationSec": 73.594, + "filesCount": 25, "sampleFiles": [ - "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", - "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js", "...", - "test262/test/intl402/DateTimeFormat/prototype/formatToParts/dangi-calendar-dates.js", - "test262/test/intl402/DateTimeFormat/prototype/formatToParts/date-constructor-not-called.js" + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T1.js", + "test262/test/built-ins/decodeURI/S15.1.3.1_A1.8_T2.js" ] }, { - "group": "staging/sm", + "group": "annexB/built-ins/RegExp", "kind": "normal", - "durationSec": 61.245, - "filesCount": 1, + "durationSec": 64.136, + "filesCount": 25, "sampleFiles": [ - "test262/test/staging/sm/TypedArray/element-setting-converts-using-ToNumber.js" + "test262/test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js", + "test262/test/annexB/built-ins/RegExp/RegExp-decimal-escape-class-range.js", + "...", + "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-cross-realm-constructor.js", + "test262/test/annexB/built-ins/RegExp/legacy-accessors/lastParen/this-not-regexp-constructor.js" ] }, { - "group": "built-ins/RegExp/property-escapes/generated", + "group": "intl402/DateTimeFormat", "kind": "normal", - "durationSec": 58.922, - "filesCount": 3, + "durationSec": 60.635, + "filesCount": 25, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Math.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Noncharacter_Code_Point.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Pattern_Syntax.js" + "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plainmonthday-formatting-timezonename.js", + "test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-plaintime-formatting-timezonename.js", + "...", + "test262/test/intl402/DateTimeFormat/prototype/formatToParts/name.js", + "test262/test/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js" ] }, { - "group": "built-ins/RegExp/property-escapes/generated", + "group": "intl402", "kind": "normal", - "durationSec": 58.892, - "filesCount": 3, + "durationSec": 59.788, + "filesCount": 22, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Toto.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Tulu_Tigalari.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Ugaritic.js" + "test262/test/intl402/constructors-string-and-single-element-array.js", + "test262/test/intl402/constructors-taint-Object-prototype-2.js", + "...", + "test262/test/intl402/supportedLocalesOf-throws-if-element-not-string-or-object.js", + "test262/test/intl402/supportedLocalesOf-unicode-extensions-ignored.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 58.834, - "filesCount": 3, + "durationSec": 59.566, + "filesCount": 5, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Devanagari.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dives_Akuru.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Dogra.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Nandinagari.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_New_Tai_Lue.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Newa.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Nko.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Nushu.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 58.569, - "filesCount": 3, + "durationSec": 59.49, + "filesCount": 5, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Glagolitic.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Gothic.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Grantha.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Inscriptional_Parthian.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Javanese.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kaithi.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Kannada.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Katakana.js" ] }, { "group": "built-ins/RegExp/property-escapes/generated", "kind": "normal", - "durationSec": 58.052, - "filesCount": 3, + "durationSec": 58.496, + "filesCount": 5, "sampleFiles": [ - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Palmyrene.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Pau_Cin_Hau.js", - "test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Phags_Pa.js" + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Todhri.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Tolong_Siki.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Toto.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Tulu_Tigalari.js", + "test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Ugaritic.js" ] } ]