From 18f72b6c17bb83bb0e9dde3b0b4c1d3db5309b0d Mon Sep 17 00:00:00 2001 From: Joey Pender Date: Tue, 9 Apr 2024 09:42:23 -0500 Subject: [PATCH] fix(android): JS Engine Reliability Fixes (#69) --- .changeset/rotten-items-beam.md | 8 + .github/workflows/reusable_unit-tests.yml | 2 +- README.md | 2 +- apps/example-app/android/app/build.gradle | 1 + apps/example-app/android/variables.gradle | 2 +- apps/example-app/ios/App/Podfile.lock | 2 +- packages/android-engine/.editorconfig | 4 - packages/android-engine/.idea/.name | 1 - .../androidTestResultsUserPreferences.xml | 336 - .../android-engine/.idea/jarRepositories.xml | 25 - packages/android-engine/.prettierignore | 3 - packages/android-engine/CHANGELOG.md | 53 - .../src/main/AndroidManifest.xml | 7 - .../src/main/cpp/CMakeLists.txt | 34 - .../src/main/cpp/api/api_crypto.cpp | 67 - .../src/main/cpp/api/api_fetch.cpp | 114 - .../src/main/cpp/cap_api/api_cap_device.cpp | 60 - .../main/cpp/cap_api/api_cap_geolocation.cpp | 32 - .../src/main/cpp/cap_api/api_cap_kv.cpp | 84 - .../cpp/cap_api/api_cap_notifications.cpp | 31 - .../android-js-engine/src/main/cpp/context.h | 70 - .../android-js-engine/src/main/cpp/errors.cpp | 65 - .../android-js-engine/src/main/cpp/errors.h | 12 - .../src/main/cpp/native_context.cpp | 67 - .../src/main/cpp/quickjs/VERSION | 1 - .../src/main/cpp/quickjs/doc/jsbignum.html | 1005 --- .../src/main/cpp/quickjs/doc/quickjs.html | 1797 ------ .../src/main/cpp/quickjs/libunicode-table.h | 4368 ------------- .../src/main/cpp/quickjs/qjscalc.js | 2591 -------- .../src/main/cpp/quickjs/repl.js | 1579 ----- .../src/main/cpp/quickjs/test262_errors.txt | 35 - .../android-js-engine/src/main/cpp/runner.cpp | 106 - .../android-js-engine/src/main/cpp/runner.h | 37 - .../io/ionic/android_js_engine/Context.kt | 52 - .../ionic/android_js_engine/JSFetchOptions.kt | 26 - .../io/ionic/android_js_engine/JSFunction.kt | 15 - .../android_js_engine/api/CapacitorAPI.kt | 34 - .../io/ionic/android_js_engine/api/KVAPI.kt | 7 - .../android_js_engine/ExampleUnitTest.kt | 16 - .../app/src/main/res/values/strings.xml | 3 - .../gradle/wrapper/gradle-wrapper.jar | Bin 61608 -> 0 bytes packages/android-engine/gradlew | 244 - packages/android-engine/package.json | 21 - packages/android-engine/settings.gradle | 11 - .../.clang-format | 0 .../.clang-tidy | 0 packages/android-js-engine/.editorconfig | 2 + .../.gitignore | 0 packages/android-js-engine/.idea/.gitignore | 3 + packages/android-js-engine/.idea/.name | 1 + .../androidTestResultsUserPreferences.xml | 182 + .../.idea/compiler.xml | 0 .../.idea/deploymentTargetDropDown.xml | 49 + .../.idea/gradle.xml | 7 +- .../.idea/kotlinc.xml | 0 .../android-js-engine/.idea/migrations.xml | 10 + .../.idea/misc.xml | 0 .../.idea/vcs.xml | 0 .../AndroidJSEngine}/.gitignore | 0 .../AndroidJSEngine}/build.gradle | 14 +- .../AndroidJSEngine}/consumer-rules.pro | 0 .../AndroidJSEngine}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 4 + .../src/main/cpp/CMakeLists.txt | 18 + .../src/main/cpp/android_js_engine.cpp | 11 + .../AndroidJSEngine}/src/main/cpp/java.cpp | 99 +- .../AndroidJSEngine}/src/main/cpp/java.h | 27 +- .../src/main/cpp/java_errors.cpp | 40 + .../src/main/cpp/java_errors.h | 11 + .../src/main/cpp/js-engine/.clang-format | 169 + .../src/main/cpp/js-engine/.clang-tidy | 1 + .../src/main/cpp/js-engine/.gitignore | 18 + .../src/main/cpp/js-engine/.idea/.gitignore | 8 + .../src/main/cpp/js-engine/.idea/.name | 1 + .../js-engine/.idea/codeStyles/Project.xml | 7 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + .../src/main/cpp/js-engine/.idea/misc.xml | 4 + .../src/main/cpp/js-engine/.idea/modules.xml | 8 + .../src/main/cpp/js-engine/.idea/vcs.xml | 8 + .../main/cpp/js-engine/.vscode/launch.json | 34 + .../main/cpp/js-engine/.vscode/settings.json | 89 + .../src/main/cpp/js-engine/CMakeLists.txt | 33 + .../src/main/cpp/js-engine/CMakePresets.json | 15 + .../main/cpp/js-engine/src}/api/api_blob.cpp | 33 +- .../main/cpp/js-engine/src}/api/api_blob.h | 0 .../cpp/js-engine/src}/api/api_console.cpp | 25 +- .../main/cpp/js-engine/src}/api/api_console.h | 4 +- .../main/cpp/js-engine/src/api/api_crypto.cpp | 59 + .../main/cpp/js-engine/src}/api/api_crypto.h | 0 .../cpp/js-engine/src}/api/api_events.cpp | 7 +- .../main/cpp/js-engine/src}/api/api_events.h | 0 .../main/cpp/js-engine/src/api/api_fetch.cpp | 159 + .../main/cpp/js-engine/src}/api/api_fetch.h | 0 .../js-engine/src}/api/api_js_response.cpp | 184 +- .../cpp/js-engine/src}/api/api_js_response.h | 6 +- .../main/cpp/js-engine/src}/api/api_text.cpp | 94 +- .../main/cpp/js-engine/src}/api/api_text.h | 0 .../cpp/js-engine/src}/api/api_timeout.cpp | 41 +- .../main/cpp/js-engine/src}/api/api_timeout.h | 0 .../src/capacitor-api/api_device.cpp | 43 + .../js-engine/src/capacitor-api/api_device.h} | 6 +- .../src/capacitor-api/api_geolocation.cpp | 23 + .../src/capacitor-api/api_geolocation.h} | 6 +- .../js-engine/src/capacitor-api/api_kv.cpp | 87 + .../cpp/js-engine/src/capacitor-api/api_kv.h} | 6 +- .../src/capacitor-api/api_notifications.cpp | 27 + .../src/capacitor-api/api_notifications.h} | 6 +- .../src/main/cpp/js-engine/src/capacitor.hpp | 28 + .../src/main/cpp/js-engine/src}/context.cpp | 210 +- .../src/main/cpp/js-engine/src/context.hpp | 60 + .../src/main/cpp/js-engine/src/errors.cpp | 29 + .../src/main/cpp/js-engine/src/errors.hpp | 22 + .../src/main/cpp/js-engine/src/native.hpp | 51 + .../cpp/js-engine/src}/quickjs/CMakeLists.txt | 0 .../main/cpp/js-engine/src}/quickjs/Changelog | 27 + .../main/cpp/js-engine/src}/quickjs/LICENSE | 0 .../main/cpp/js-engine/src}/quickjs/Makefile | 93 +- .../src/main/cpp/js-engine/src}/quickjs/TODO | 7 +- .../main/cpp/js-engine/src/quickjs/VERSION | 1 + .../main/cpp/js-engine/src}/quickjs/cutils.c | 0 .../main/cpp/js-engine/src}/quickjs/cutils.h | 3 + .../js-engine/src/quickjs/doc/jsbignum.html | 734 +++ .../js-engine/src}/quickjs/doc/jsbignum.pdf | Bin .../js-engine/src}/quickjs/doc/jsbignum.texi | 0 .../js-engine/src/quickjs/doc/quickjs.html | 1410 ++++ .../js-engine/src}/quickjs/doc/quickjs.pdf | Bin 166097 -> 167595 bytes .../js-engine/src}/quickjs/doc/quickjs.texi | 53 +- .../main/cpp/js-engine/src}/quickjs/libbf.c | 41 +- .../main/cpp/js-engine/src}/quickjs/libbf.h | 2 +- .../js-engine/src}/quickjs/libregexp-opcode.h | 3 +- .../cpp/js-engine/src}/quickjs/libregexp.c | 193 +- .../cpp/js-engine/src}/quickjs/libregexp.h | 1 + .../js-engine/src/quickjs/libunicode-table.h | 4486 +++++++++++++ .../cpp/js-engine/src}/quickjs/libunicode.c | 386 +- .../cpp/js-engine/src}/quickjs/libunicode.h | 3 + .../main/cpp/js-engine/src}/quickjs/list.h | 3 +- .../src/main/cpp/js-engine/src}/quickjs/qjs.c | 23 +- .../main/cpp/js-engine/src}/quickjs/qjsc.c | 7 +- .../main/cpp/js-engine/src/quickjs/qjscalc.js | 2657 ++++++++ .../cpp/js-engine/src}/quickjs/quickjs-atom.h | 12 +- .../cpp/js-engine/src}/quickjs/quickjs-libc.c | 74 +- .../cpp/js-engine/src}/quickjs/quickjs-libc.h | 0 .../js-engine/src}/quickjs/quickjs-opcode.h | 13 +- .../main/cpp/js-engine/src}/quickjs/quickjs.c | 5644 +++++++++++------ .../main/cpp/js-engine/src}/quickjs/quickjs.h | 27 +- .../cpp/js-engine/src}/quickjs/readme.txt | 0 .../cpp/js-engine/src}/quickjs/release.sh | 26 +- .../main/cpp/js-engine/src/quickjs/repl.js | 1590 +++++ .../cpp/js-engine/src}/quickjs/run-test262.c | 64 +- .../cpp/js-engine/src}/quickjs/test262.conf | 48 +- .../js-engine/src/quickjs/test262_errors.txt | 8 + .../cpp/js-engine/src}/quickjs/test262o.conf | 0 .../src}/quickjs/test262o_errors.txt | 0 .../src}/quickjs/unicode_download.sh | 10 +- .../cpp/js-engine/src}/quickjs/unicode_gen.c | 204 +- .../js-engine/src}/quickjs/unicode_gen_def.h | 7 + .../src/main/cpp/js-engine/src/runner.cpp | 112 + .../src/main/cpp/js-engine/src/runner.hpp | 35 + .../main/cpp/js-engine/tests/CMakeLists.txt | 61 + .../cpp/js-engine/tests/src/context_tests.cpp | 487 ++ .../cpp/js-engine/tests/src/engine_tests.cpp | 64 + .../tests/src/native_engine/engine.cpp | 84 + .../tests/src/native_engine/engine.hpp | 27 + .../tests/src/native_engine/errors.cpp | 14 + .../tests/src/native_engine/errors.hpp | 27 + .../src/native_engine/native_interface.cpp | 152 + .../src/native_engine/native_interface.hpp | 33 + .../tests/src/native_engine/value.cpp | 68 + .../tests/src/native_engine/value.hpp | 31 + .../cpp/js-engine/vcpkg-configuration.json | 14 + .../src/main/cpp/js-engine/vcpkg.json | 10 + .../src/main/cpp/native_android_interface.cpp | 342 + .../src/main/cpp/native_android_interface.h | 33 + .../main/cpp/native_capacitor_interface.cpp | 199 + .../src/main/cpp/native_capacitor_interface.h | 29 + .../src/main/cpp/native_context.cpp | 74 + .../src/main/cpp/native_runner.cpp | 17 +- .../io/ionic/android_js_engine/Context.kt | 77 + .../ionic/android_js_engine/EngineErrors.kt | 2 + .../android_js_engine/NativeCapacitorAPI.kt | 29 + .../android_js_engine/NativeJSFetchOptions.kt | 13 + .../android_js_engine/NativeJSFunction.kt | 15 + .../android_js_engine/NativeJSResponse.kt} | 2 +- .../ionic/android_js_engine/NativeJSValue.kt} | 20 +- .../io/ionic/android_js_engine/NativeLib.kt | 16 + .../ionic/android_js_engine/NativeWebAPI.kt} | 19 +- .../java/io/ionic/android_js_engine/Runner.kt | 60 +- .../capacitor_api}/DeviceAPI.kt | 3 +- .../capacitor_api}/GeolocationAPI.kt | 2 +- .../android_js_engine/capacitor_api/KVAPI.kt | 12 + .../capacitor_api}/NotificationsAPI.kt | 2 +- .../app/.gitignore | 0 .../app/build.gradle | 30 +- .../app/proguard-rules.pro | 0 .../ContextTest.kt} | 106 +- .../RunnerTest.kt} | 20 +- .../app/src/main/AndroidManifest.xml | 4 +- .../res/drawable/ic_launcher_background.xml | 0 .../res/drawable}/ic_launcher_foreground.xml | 0 .../res/mipmap-anydpi-v26/ic_launcher.xml | 0 .../mipmap-anydpi-v26/ic_launcher_round.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin .../res/mipmap-hdpi/ic_launcher_round.webp | Bin .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin .../res/mipmap-mdpi/ic_launcher_round.webp | Bin .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin .../app/src/main/res/values-night/themes.xml | 2 +- .../app/src/main/res/values/colors.xml | 0 .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/themes.xml | 2 +- .../app/src/main/res/xml/backup_rules.xml | 0 .../main/res/xml/data_extraction_rules.xml | 0 .../ExampleUnitTest.kt | 2 +- .../build.gradle | 0 .../gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 4 +- packages/android-js-engine/gradlew | 185 + .../gradlew.bat | 15 +- packages/android-js-engine/package.json | 22 + packages/android-js-engine/settings.gradle | 18 + packages/capacitor-plugin/README.md | 2 +- .../capacitor-plugin/android/build.gradle | 5 +- .../android/src/main/AndroidManifest.xml | 1 + .../plugin/BackgroundRunner.kt | 89 +- .../plugin/BackgroundRunnerPlugin.kt | 28 +- .../backgroundrunner/plugin/RunnerConfig.kt | 51 +- .../backgroundrunner/plugin/RunnerWorker.kt | 7 +- .../backgroundrunner/plugin/api/Device.kt | 3 +- .../plugin/api/Geolocation.kt | 2 +- .../ionic/backgroundrunner/plugin/api/KV.kt | 2 +- .../plugin/api/Notifications.kt | 6 +- .../main/libs/android-js-engine-release.aar | Bin 2288840 -> 2504137 bytes .../scripts/build-native-sdks.sh | 4 +- .../scripts/copy-native-sdks.sh | 2 +- .../capacitor-plugin/scripts/install_libs.js | 44 +- packages/capacitor-plugin/src/definitions.ts | 2 +- packages/capacitor-plugin/src/web.ts | 8 +- pnpm-lock.yaml | 32 +- 244 files changed, 19652 insertions(+), 16218 deletions(-) create mode 100644 .changeset/rotten-items-beam.md delete mode 100644 packages/android-engine/.editorconfig delete mode 100644 packages/android-engine/.idea/.name delete mode 100644 packages/android-engine/.idea/androidTestResultsUserPreferences.xml delete mode 100644 packages/android-engine/.idea/jarRepositories.xml delete mode 100644 packages/android-engine/.prettierignore delete mode 100644 packages/android-engine/CHANGELOG.md delete mode 100644 packages/android-engine/android-js-engine/src/main/AndroidManifest.xml delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/CMakeLists.txt delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/api/api_crypto.cpp delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/api/api_fetch.cpp delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_device.cpp delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_geolocation.cpp delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_kv.cpp delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_notifications.cpp delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/context.h delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/errors.cpp delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/errors.h delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/native_context.cpp delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/quickjs/VERSION delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/jsbignum.html delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/quickjs.html delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode-table.h delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjscalc.js delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/quickjs/repl.js delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262_errors.txt delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/runner.cpp delete mode 100644 packages/android-engine/android-js-engine/src/main/cpp/runner.h delete mode 100644 packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/Context.kt delete mode 100644 packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSFetchOptions.kt delete mode 100644 packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSFunction.kt delete mode 100644 packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/CapacitorAPI.kt delete mode 100644 packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/KVAPI.kt delete mode 100644 packages/android-engine/android-js-engine/src/test/java/io/ionic/android_js_engine/ExampleUnitTest.kt delete mode 100644 packages/android-engine/app/src/main/res/values/strings.xml delete mode 100644 packages/android-engine/gradle/wrapper/gradle-wrapper.jar delete mode 100755 packages/android-engine/gradlew delete mode 100644 packages/android-engine/package.json delete mode 100644 packages/android-engine/settings.gradle rename packages/{android-engine => android-js-engine}/.clang-format (100%) rename packages/{android-engine => android-js-engine}/.clang-tidy (100%) create mode 100644 packages/android-js-engine/.editorconfig rename packages/{android-engine => android-js-engine}/.gitignore (100%) create mode 100644 packages/android-js-engine/.idea/.gitignore create mode 100644 packages/android-js-engine/.idea/.name create mode 100644 packages/android-js-engine/.idea/androidTestResultsUserPreferences.xml rename packages/{android-engine => android-js-engine}/.idea/compiler.xml (100%) create mode 100644 packages/android-js-engine/.idea/deploymentTargetDropDown.xml rename packages/{android-engine => android-js-engine}/.idea/gradle.xml (71%) rename packages/{android-engine => android-js-engine}/.idea/kotlinc.xml (100%) create mode 100644 packages/android-js-engine/.idea/migrations.xml rename packages/{android-engine => android-js-engine}/.idea/misc.xml (100%) rename packages/{android-engine => android-js-engine}/.idea/vcs.xml (100%) rename packages/{android-engine/android-js-engine => android-js-engine/AndroidJSEngine}/.gitignore (100%) rename packages/{android-engine/android-js-engine => android-js-engine/AndroidJSEngine}/build.gradle (90%) rename packages/{android-engine/android-js-engine => android-js-engine/AndroidJSEngine}/consumer-rules.pro (100%) rename packages/{android-engine/android-js-engine => android-js-engine/AndroidJSEngine}/proguard-rules.pro (100%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/AndroidManifest.xml create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/CMakeLists.txt create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/android_js_engine.cpp rename packages/{android-engine/android-js-engine => android-js-engine/AndroidJSEngine}/src/main/cpp/java.cpp (74%) rename packages/{android-engine/android-js-engine => android-js-engine/AndroidJSEngine}/src/main/cpp/java.h (72%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/java_errors.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/java_errors.h create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.clang-format create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.clang-tidy create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.gitignore create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/.gitignore create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/.name create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/codeStyles/Project.xml create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/codeStyles/codeStyleConfig.xml create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/misc.xml create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/modules.xml create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/vcs.xml create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.vscode/launch.json create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.vscode/settings.json create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/CMakeLists.txt create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/CMakePresets.json rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_blob.cpp (77%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_blob.h (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_console.cpp (70%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_console.h (83%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_crypto.cpp rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_crypto.h (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_events.cpp (81%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_events.h (100%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_fetch.cpp rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_fetch.h (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_js_response.cpp (54%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_js_response.h (57%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_text.cpp (64%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_text.h (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_timeout.cpp (59%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/api/api_timeout.h (100%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_device.cpp rename packages/{android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_device.h => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_device.h} (65%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_geolocation.cpp rename packages/{android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_geolocation.h => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_geolocation.h} (52%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_kv.cpp rename packages/{android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_kv.h => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_kv.h} (67%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_notifications.cpp rename packages/{android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_notifications.h => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_notifications.h} (50%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor.hpp rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/context.cpp (69%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/context.hpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/errors.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/errors.hpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/native.hpp rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/CMakeLists.txt (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/Changelog (81%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/LICENSE (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/Makefile (87%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/TODO (94%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/VERSION rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/cutils.c (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/cutils.h (97%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/jsbignum.html rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/doc/jsbignum.pdf (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/doc/jsbignum.texi (100%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/quickjs.html rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/doc/quickjs.pdf (58%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/doc/quickjs.texi (95%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/libbf.c (99%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/libbf.h (99%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/libregexp-opcode.h (95%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/libregexp.c (94%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/libregexp.h (97%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode-table.h rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/libunicode.c (82%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/libunicode.h (97%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/list.h (96%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/qjs.c (97%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/qjsc.c (99%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjscalc.js rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/quickjs-atom.h (98%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/quickjs-libc.c (98%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/quickjs-libc.h (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/quickjs-opcode.h (95%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/quickjs.c (94%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/quickjs.h (98%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/readme.txt (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/release.sh (85%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/repl.js rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/run-test262.c (96%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/test262.conf (84%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262_errors.txt rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/test262o.conf (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/test262o_errors.txt (100%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/unicode_download.sh (75%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/unicode_gen.c (93%) rename packages/{android-engine/android-js-engine/src/main/cpp => android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src}/quickjs/unicode_gen_def.h (97%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/runner.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/runner.hpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/CMakeLists.txt create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/context_tests.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/engine_tests.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/engine.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/engine.hpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/errors.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/errors.hpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/native_interface.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/native_interface.hpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/value.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/value.hpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/vcpkg-configuration.json create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/vcpkg.json create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_android_interface.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_android_interface.h create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_capacitor_interface.cpp create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_capacitor_interface.h create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_context.cpp rename packages/{android-engine/android-js-engine => android-js-engine/AndroidJSEngine}/src/main/cpp/native_runner.cpp (52%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/Context.kt rename packages/{android-engine/android-js-engine => android-js-engine/AndroidJSEngine}/src/main/java/io/ionic/android_js_engine/EngineErrors.kt (99%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeCapacitorAPI.kt create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSFetchOptions.kt create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSFunction.kt rename packages/{android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSResponse.kt => android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSResponse.kt} (79%) rename packages/{android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSValue.kt => android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSValue.kt} (75%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeLib.kt rename packages/{android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/WebAPI.kt => android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeWebAPI.kt} (82%) rename packages/{android-engine/android-js-engine => android-js-engine/AndroidJSEngine}/src/main/java/io/ionic/android_js_engine/Runner.kt (61%) rename packages/{android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api => android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api}/DeviceAPI.kt (65%) rename packages/{android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api => android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api}/GeolocationAPI.kt (58%) create mode 100644 packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/KVAPI.kt rename packages/{android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api => android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api}/NotificationsAPI.kt (58%) rename packages/{android-engine => android-js-engine}/app/.gitignore (100%) rename packages/{android-engine => android-js-engine}/app/build.gradle (61%) rename packages/{android-engine => android-js-engine}/app/proguard-rules.pro (100%) rename packages/{android-engine/app/src/androidTest/java/io/ionic/backgroundrunner/ContextTests.kt => android-js-engine/app/src/androidTest/java/io/ionic/android_js_engine_testproject/ContextTest.kt} (83%) rename packages/{android-engine/app/src/androidTest/java/io/ionic/backgroundrunner/RunnerTests.kt => android-js-engine/app/src/androidTest/java/io/ionic/android_js_engine_testproject/RunnerTest.kt} (82%) rename packages/{android-engine => android-js-engine}/app/src/main/AndroidManifest.xml (90%) rename packages/{android-engine => android-js-engine}/app/src/main/res/drawable/ic_launcher_background.xml (100%) rename packages/{android-engine/app/src/main/res/drawable-v24 => android-js-engine/app/src/main/res/drawable}/ic_launcher_foreground.xml (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-hdpi/ic_launcher.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-mdpi/ic_launcher.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-xhdpi/ic_launcher.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/values-night/themes.xml (86%) rename packages/{android-engine => android-js-engine}/app/src/main/res/values/colors.xml (100%) create mode 100644 packages/android-js-engine/app/src/main/res/values/strings.xml rename packages/{android-engine => android-js-engine}/app/src/main/res/values/themes.xml (86%) rename packages/{android-engine => android-js-engine}/app/src/main/res/xml/backup_rules.xml (100%) rename packages/{android-engine => android-js-engine}/app/src/main/res/xml/data_extraction_rules.xml (100%) rename packages/{android-engine/app/src/test/java/io/ionic/backgroundrunner => android-js-engine/app/src/test/java/io/ionic/android_js_engine_testproject}/ExampleUnitTest.kt (87%) rename packages/{android-engine => android-js-engine}/build.gradle (100%) rename packages/{android-engine => android-js-engine}/gradle.properties (100%) create mode 100644 packages/android-js-engine/gradle/wrapper/gradle-wrapper.jar rename packages/{android-engine => android-js-engine}/gradle/wrapper/gradle-wrapper.properties (80%) create mode 100755 packages/android-js-engine/gradlew rename packages/{android-engine => android-js-engine}/gradlew.bat (86%) create mode 100644 packages/android-js-engine/package.json create mode 100644 packages/android-js-engine/settings.gradle diff --git a/.changeset/rotten-items-beam.md b/.changeset/rotten-items-beam.md new file mode 100644 index 00000000..59262234 --- /dev/null +++ b/.changeset/rotten-items-beam.md @@ -0,0 +1,8 @@ +--- +"android-js-engine": minor +"@capacitor/background-runner": minor +--- + +More reliability fixes for the JS Engine used in the Background Runner: +- (Android) Fixes in runtime during background execution +- (Android) Improvements in native lib handling for testing diff --git a/.github/workflows/reusable_unit-tests.yml b/.github/workflows/reusable_unit-tests.yml index 7eb9ce93..ebf2492e 100644 --- a/.github/workflows/reusable_unit-tests.yml +++ b/.github/workflows/reusable_unit-tests.yml @@ -34,7 +34,7 @@ jobs: uses: reactivecircus/android-emulator-runner@v2 with: api-level: 29 - working-directory: ./packages/android-engine + working-directory: ./packages/android-js-engine emulator-options: -no-window -no-audio -no-boot-anim -accel on -no-snapshot-save profile: pixel_6 script: ./gradlew connectedCheck diff --git a/README.md b/README.md index 315e57b7..f2e31fd3 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ Request permission to display local notifications. ### dispatchEvent(...) ```typescript -dispatchEvent(options: DispatchEventOptions) => any +dispatchEvent(options: DispatchEventOptions) => any ``` Dispatches an event to the configured runner. diff --git a/apps/example-app/android/app/build.gradle b/apps/example-app/android/app/build.gradle index 8e2f21fc..e0c850ca 100644 --- a/apps/example-app/android/app/build.gradle +++ b/apps/example-app/android/app/build.gradle @@ -27,6 +27,7 @@ android { repositories { flatDir{ dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' + dirs '../../node_modules/@capacitor/background-runner/android/src/main/libs', 'libs' } } diff --git a/apps/example-app/android/variables.gradle b/apps/example-app/android/variables.gradle index 5946adab..5f27ad56 100644 --- a/apps/example-app/android/variables.gradle +++ b/apps/example-app/android/variables.gradle @@ -1,6 +1,6 @@ ext { minSdkVersion = 22 - compileSdkVersion = 33 + compileSdkVersion = 34 targetSdkVersion = 33 androidxActivityVersion = '1.7.0' androidxAppCompatVersion = '1.6.1' diff --git a/apps/example-app/ios/App/Podfile.lock b/apps/example-app/ios/App/Podfile.lock index 14512790..b4451684 100644 --- a/apps/example-app/ios/App/Podfile.lock +++ b/apps/example-app/ios/App/Podfile.lock @@ -49,4 +49,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 023978344a0d202e5020371cd007ff62c16044ac -COCOAPODS: 1.11.3 +COCOAPODS: 1.13.0 diff --git a/packages/android-engine/.editorconfig b/packages/android-engine/.editorconfig deleted file mode 100644 index bd049e0a..00000000 --- a/packages/android-engine/.editorconfig +++ /dev/null @@ -1,4 +0,0 @@ -[*.{kt,kts}] -ktlint_standard_no-wildcard-imports = disabled -ktlint_standard_package-name = disabled - diff --git a/packages/android-engine/.idea/.name b/packages/android-engine/.idea/.name deleted file mode 100644 index 0630b2c2..00000000 --- a/packages/android-engine/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -Capacitor Background Runner \ No newline at end of file diff --git a/packages/android-engine/.idea/androidTestResultsUserPreferences.xml b/packages/android-engine/.idea/androidTestResultsUserPreferences.xml deleted file mode 100644 index ce815748..00000000 --- a/packages/android-engine/.idea/androidTestResultsUserPreferences.xml +++ /dev/null @@ -1,336 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/packages/android-engine/.idea/jarRepositories.xml b/packages/android-engine/.idea/jarRepositories.xml deleted file mode 100644 index d2ce72d1..00000000 --- a/packages/android-engine/.idea/jarRepositories.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/packages/android-engine/.prettierignore b/packages/android-engine/.prettierignore deleted file mode 100644 index d096b65c..00000000 --- a/packages/android-engine/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -build -dist -src/main/cpp \ No newline at end of file diff --git a/packages/android-engine/CHANGELOG.md b/packages/android-engine/CHANGELOG.md deleted file mode 100644 index f388cb72..00000000 --- a/packages/android-engine/CHANGELOG.md +++ /dev/null @@ -1,53 +0,0 @@ -# Change Log - -## [1.0.5](https://github.com/ionic-team/capacitor-background-runner/compare/1.0.4...1.0.5) (2023-08-17) - -**Note:** Version bump only for package android-engine - - - - - -## [1.0.4](https://github.com/ionic-team/capacitor-background-runner/compare/1.0.3...1.0.4) (2023-08-10) - -**Note:** Version bump only for package android-engine - - - - - -## [1.0.3](https://github.com/ionic-team/capacitor-background-runner/compare/1.0.2...1.0.3) (2023-08-10) - -**Note:** Version bump only for package android-engine - - - - - -## [1.0.2](https://github.com/ionic-team/capacitor-background-runner/compare/1.0.1...1.0.2) (2023-08-10) - -**Note:** Version bump only for package android-engine - - - - - -## [1.0.1](https://github.com/ionic-team/capacitor-background-runner/compare/1.0.0...1.0.1) (2023-08-09) - - -### Bug Fixes - -* Updating to Gradle 8 ([#17](https://github.com/ionic-team/capacitor-background-runner/issues/17)) ([353dbe3](https://github.com/ionic-team/capacitor-background-runner/commit/353dbe331f5ed2344ded407041e001e440b9d0ee)) - - - - - -# 1.0.0 (2023-07-18) - - -### Features - -* Android JS Engine / Plugin ([#6](https://github.com/ionic-team/enterprise-background-runner/issues/6)) ([1f52918](https://github.com/ionic-team/enterprise-background-runner/commit/1f52918784d91558a3e7798d5449887d7fb5cd32)) -* Capacitor Plugin ([#3](https://github.com/ionic-team/enterprise-background-runner/issues/3)) ([ffac505](https://github.com/ionic-team/enterprise-background-runner/commit/ffac505560c144d2478ed6de49dc7d0c5130b15c)) -* **iOS:** Adding Capacitor Web APIs ([#4](https://github.com/ionic-team/enterprise-background-runner/issues/4)) ([7daa335](https://github.com/ionic-team/enterprise-background-runner/commit/7daa3350335989e8caf20c7258074a6dfa5d2cfe)) diff --git a/packages/android-engine/android-js-engine/src/main/AndroidManifest.xml b/packages/android-engine/android-js-engine/src/main/AndroidManifest.xml deleted file mode 100644 index 8a9a80f7..00000000 --- a/packages/android-engine/android-js-engine/src/main/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/CMakeLists.txt b/packages/android-engine/android-js-engine/src/main/cpp/CMakeLists.txt deleted file mode 100644 index 5eb89fae..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -cmake_minimum_required(VERSION 3.22.1) - -project("android_js_engine") - -add_library( - ${PROJECT_NAME} - SHARED - native_runner.cpp native_context.cpp - - runner.cpp context.cpp errors.cpp java.cpp - - api/api_console.cpp - api/api_events.cpp - api/api_timeout.cpp - api/api_crypto.cpp - api/api_text.cpp - api/api_fetch.cpp - api/api_js_response.cpp - api/api_blob.cpp - - cap_api/api_cap_kv.cpp - cap_api/api_cap_device.cpp - cap_api/api_cap_geolocation.cpp - cap_api/api_cap_notifications.cpp -) - -find_library( - log-lib - log) - -add_subdirectory("quickjs") - -target_link_libraries(${PROJECT_NAME} ${log-lib}) -target_link_libraries(${PROJECT_NAME} quickjs) \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_crypto.cpp b/packages/android-engine/android-js-engine/src/main/cpp/api/api_crypto.cpp deleted file mode 100644 index 9af7a35b..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_crypto.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "api_crypto.h" - -#include "../context.h" -#include "../errors.h" - -JSValue api_crypto_get_random_values(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - uint8_t *buf; - size_t elem, len, offset, buf_size; - int size; - - auto t_arr_buf = JS_GetTypedArrayBuffer(ctx, argv[0], &offset, &len, &elem); - buf = JS_GetArrayBuffer(ctx, &buf_size, t_arr_buf); - - if (!buf) { - return JS_EXCEPTION; - } - - size = buf_size; - - auto *context = (Context *)JS_GetContextOpaque(ctx); - - auto *env = context->java->getEnv(); - if (env == nullptr) { - return throw_js_exception(ctx, "JVM Environment is null"); - } - - auto random_bytes = static_cast(env->CallStaticObjectMethod(context->java->web_api_class, context->java->web_api_cryptoGetRandom_method, size)); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - auto random = env->GetByteArrayElements(random_bytes, nullptr); - - for (int i = 0; i < size; i++) { - buf[i] = random[i]; - } - - env->ReleaseByteArrayElements(random_bytes, random, 0); - - JS_FreeValue(ctx, t_arr_buf); - - return JS_DupValue(ctx, argv[0]); -} - -JSValue api_crypto_random_uuid(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - auto *context = (Context *)JS_GetContextOpaque(ctx); - - auto *env = context->java->getEnv(); - if (env == nullptr) { - return throw_js_exception(ctx, "JVM Environment is null"); - } - - auto *str = (jstring)env->CallStaticObjectMethod(context->java->web_api_class, context->java->web_api_cryptoRandomUUID_method); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - const auto *c_str = env->GetStringUTFChars(str, nullptr); - - auto ret_value = JS_NewString(ctx, c_str); - - env->ReleaseStringUTFChars(str, c_str); - - return ret_value; -} \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_fetch.cpp b/packages/android-engine/android-js-engine/src/main/cpp/api/api_fetch.cpp deleted file mode 100644 index 01f2c108..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_fetch.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "api_fetch.h" - -#include "../context.h" -#include "../errors.h" - -JSValue js_fetch_job(JSContext *ctx, int argc, JSValueConst *argv) { - JSValue resolve, reject, request, options; - - resolve = argv[0]; - reject = argv[1]; - request = argv[2]; - options = argv[3]; - - auto *context = (Context *)JS_GetContextOpaque(ctx); - if (context == nullptr) { - auto exception = throw_js_exception(ctx, "parent context is null"); - reject_promise(ctx, reject, exception); - return JS_UNDEFINED; - } - - auto *env = context->java->getEnv(); - if (env == nullptr) { - auto exception = throw_js_exception(ctx, "JVM Environment is null"); - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); - return JS_UNDEFINED; - } - - if (JS_IsNull(request) || !JS_IsString(request)) { - auto exception = throw_js_exception(ctx, "invalid url"); - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); - return JS_UNDEFINED; - } - - const auto *c_url_str = JS_ToCString(ctx, request); - auto *j_url_str = env->NewStringUTF(c_url_str); - - jobject j_options = nullptr; - - if (!JS_IsNull(options) && !JS_IsUndefined(options)) { - auto options_json_value = JS_JSONStringify(ctx, options, JS_UNDEFINED, JS_UNDEFINED); - const auto *options_json_c_str = JS_ToCString(ctx, options_json_value); - auto *options_json_j_str = env->NewStringUTF(options_json_c_str); - - j_options = env->NewObject(context->java->js_fetch_options_class, context->java->js_fetch_options_constructor, options_json_j_str); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); - return JS_UNDEFINED; - } - - JS_FreeCString(ctx, options_json_c_str); - JS_FreeValue(ctx, options_json_value); - } - - auto response = env->CallStaticObjectMethod(context->java->web_api_class, context->java->web_api_fetch_method, j_url_str, j_options); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); - return JS_UNDEFINED; - } - - auto js_response = new_js_response(ctx, response); - - auto ok = JS_GetPropertyStr(ctx, js_response, "ok"); - if (!JS_ToBool(ctx, ok)) { - auto err = JS_GetPropertyStr(ctx, js_response, "error"); - reject_promise(ctx, reject, err); - - JS_FreeValue(ctx, ok); - JS_FreeValue(ctx, err); - JS_FreeValue(ctx, js_response); - return JS_UNDEFINED; - } - - auto global_obj = JS_GetGlobalObject(ctx); - JSValueConst resolve_args[1]; - resolve_args[0] = js_response; - - JS_Call(ctx, resolve, global_obj, 1, resolve_args); - - JS_FreeValue(ctx, ok); - JS_FreeValue(ctx, global_obj); - JS_FreeValue(ctx, js_response); - - return JS_UNDEFINED; -} - -JSValue api_fetch(JSContext *ctx, JSValueConst this_val, int argc, JSValue *argv) { - JSValue promise, resolving_funcs[2]; - JSValueConst args[4]; - - promise = JS_NewPromiseCapability(ctx, resolving_funcs); - if (JS_IsException(promise)) { - return promise; - } - - args[0] = resolving_funcs[0]; - args[1] = resolving_funcs[1]; - args[2] = JS_DupValue(ctx, argv[0]); - args[3] = JS_DupValue(ctx, argv[1]); - - JS_EnqueueJob(ctx, js_fetch_job, 4, args); - - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - JS_FreeValue(ctx, argv[0]); - JS_FreeValue(ctx, argv[1]); - - return promise; -} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_device.cpp b/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_device.cpp deleted file mode 100644 index 29c2cb2f..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_device.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "api_cap_device.h" - -#include "../context.h" -#include "../errors.h" - -JSValue api_device_battery(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - - auto *device = env->GetObjectField(context->cap_api, context->java->capacitor_api_device_field); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - auto *j_json_str = (jstring)env->CallObjectMethod(device, context->java->capacitor_api_device_getBatteryStatus_method); - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - if (j_json_str == nullptr) { - return JS_NULL; - } - - const auto *c_json_str = env->GetStringUTFChars(j_json_str, nullptr); - - auto ret_value = JS_ParseJSON(ctx, c_json_str, strlen(c_json_str), ""); - env->ReleaseStringUTFChars(j_json_str, c_json_str); - - return ret_value; -} - -JSValue api_device_network(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - - auto *device = env->GetObjectField(context->cap_api, context->java->capacitor_api_device_field); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - auto *j_json_str = (jstring)env->CallObjectMethod(device, context->java->capacitor_api_device_getNetworkStatus_method); - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - if (j_json_str == nullptr) { - return JS_NULL; - } - - const auto *c_json_str = env->GetStringUTFChars(j_json_str, nullptr); - - auto ret_value = JS_ParseJSON(ctx, c_json_str, strlen(c_json_str), ""); - env->ReleaseStringUTFChars(j_json_str, c_json_str); - - return ret_value; -} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_geolocation.cpp b/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_geolocation.cpp deleted file mode 100644 index aea10172..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_geolocation.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "api_cap_geolocation.h" - -#include "../context.h" -#include "../errors.h" - -JSValue api_geolocation_current_location(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - - auto *geolocation = env->GetObjectField(context->cap_api, context->java->capacitor_api_geolocation_field); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - auto value_j_str = (jstring)env->CallObjectMethod(geolocation, context->java->capacitor_api_geolocation_getCurrentPosition_method); - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - if (value_j_str == nullptr) { - return JS_NULL; - } - - const auto *c_json_str = env->GetStringUTFChars(value_j_str, nullptr); - - auto ret_value = JS_ParseJSON(ctx, c_json_str, strlen(c_json_str), ""); - env->ReleaseStringUTFChars(value_j_str, c_json_str); - - return ret_value; -} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_kv.cpp b/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_kv.cpp deleted file mode 100644 index 71d5890f..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_kv.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "api_cap_kv.h" - -#include "../context.h" -#include "../errors.h" - -JSValue api_kv_set(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - const auto *key_c_str = JS_ToCString(ctx, argv[0]); - const auto *value_c_str = JS_ToCString(ctx, argv[1]); - - auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - - auto *kv = env->GetObjectField(context->cap_api, context->java->capacitor_api_kv_field); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - JS_FreeCString(ctx, key_c_str); - return exception; - } - - jstring key_j_str = env->NewStringUTF(key_c_str); - jstring value_j_str = env->NewStringUTF(value_c_str); - - env->CallVoidMethod(kv, context->java->capacitor_api_kv_set_method, key_j_str, value_j_str); - - JS_FreeCString(ctx, key_c_str); - JS_FreeCString(ctx, value_c_str); - - return JS_UNDEFINED; -} - -JSValue api_kv_get(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - const auto *key_c_str = JS_ToCString(ctx, argv[0]); - - auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - - auto *kv = env->GetObjectField(context->cap_api, context->java->capacitor_api_kv_field); - - jstring key_j_str = env->NewStringUTF(key_c_str); - - auto *value_j_str = (jstring)env->CallObjectMethod(kv, context->java->capacitor_api_kv_get_method, key_j_str); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - JS_FreeCString(ctx, key_c_str); - return exception; - } - - if (value_j_str == nullptr) { - JS_FreeCString(ctx, key_c_str); - return JS_NULL; - } - - const auto *value_c_str = env->GetStringUTFChars(value_j_str, nullptr); - auto value_str_obj = JS_NewString(ctx, value_c_str); - - auto ret_value = JS_NewObject(ctx); - JS_SetPropertyStr(ctx, ret_value, "value", value_str_obj); - - env->ReleaseStringUTFChars(value_j_str, value_c_str); - JS_FreeCString(ctx, key_c_str); - - return ret_value; -} - -JSValue api_kv_remove(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - const auto *key_c_str = JS_ToCString(ctx, argv[0]); - - auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - - auto *kv = env->GetObjectField(context->cap_api, context->java->capacitor_api_kv_field); - - jstring key_j_str = env->NewStringUTF(key_c_str); - - env->CallVoidMethod(kv, context->java->capacitor_api_kv_remove_method, key_j_str); - JS_FreeCString(ctx, key_c_str); - - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - return JS_UNDEFINED; -} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_notifications.cpp b/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_notifications.cpp deleted file mode 100644 index 94f16e57..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_notifications.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "api_cap_notifications.h" - -#include "../context.h" -#include "../errors.h" - -JSValue api_notifications_schedule(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - - auto *notification = env->GetObjectField(context->cap_api, context->java->capacitor_api_notification_field); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - auto options_str = JS_JSONStringify(ctx, argv[0], JS_UNDEFINED, JS_UNDEFINED); - const auto *options_c_str = JS_ToCString(ctx, options_str); - auto *options_j_str = env->NewStringUTF(options_c_str); - - env->CallVoidMethod(notification, context->java->capacitor_api_notifications_schedule_method, options_j_str); - - JS_FreeCString(ctx, options_c_str); - JS_FreeValue(ctx, options_str); - - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - return JS_UNDEFINED; -} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/context.h b/packages/android-engine/android-js-engine/src/main/cpp/context.h deleted file mode 100644 index 2d9aecd6..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/context.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef CAPACITOR_BACKGROUND_RUNNER_CONTEXT_H -#define CAPACITOR_BACKGROUND_RUNNER_CONTEXT_H -#include -#include - -#include - -#include "./quickjs/quickjs.h" - -#include "java.h" -#include "api/api_console.h" -#include "api/api_timeout.h" -#include "api/api_events.h" -#include "api/api_crypto.h" -#include "api/api_text.h" -#include "api/api_fetch.h" -#include "api/api_js_response.h" -#include "api/api_blob.h" - -#include "cap_api/api_cap_kv.h" -#include "cap_api/api_cap_device.h" -#include "cap_api/api_cap_geolocation.h" -#include "cap_api/api_cap_notifications.h" - -class Context { -public: - std::string name; - - JSContext *qjs_context; - Java *java; - jobject cap_api; - - std::unordered_map event_listeners; - std::unordered_map registered_functions; - std::unordered_map timers; - - Context(const std::string& name, JSRuntime *parent_rt, JNIEnv *env); - ~Context(); - - void run_loop(); - - void register_function(const std::string& func_name, jobject func); - JSValue evaluate(const std::string& code, bool ret_val) const; - JSValue dispatch_event(const std::string& event, JSValue details); - - void init_capacitor_api(jobject cap_api_obj); - -private: - void init_callbacks(JSValue callbacks) const; - void log_debug(const std::string& msg) const; - - void execute_timer(JSValue timerFunc) const; - - void init_api_console() const; - void init_api_event_listeners() const; - void init_api_timeout() const; - void init_api_crypto() const; - void init_api_text() const; - void init_api_fetch() const; - void init_api_blob() const; - - void init_capacitor_kv_api() const; - void init_capacitor_device_api() const; - void init_capacitor_notifications_api() const; - void init_capacitor_geolocation_api() const; -}; - - - -#endif //CAPACITOR_BACKGROUND_RUNNER_CONTEXT_H diff --git a/packages/android-engine/android-js-engine/src/main/cpp/errors.cpp b/packages/android-engine/android-js-engine/src/main/cpp/errors.cpp deleted file mode 100644 index 42e7cf9a..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/errors.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "errors.h" - -bool throw_js_exception_in_jvm(JNIEnv *env, JSContext *ctx, JSValue value) { - if (JS_IsException(value)) { - JS_FreeValue(ctx, value); - - jclass error_class = env->FindClass("io/ionic/android_js_engine/EngineErrors$JavaScriptException"); - - JSValue const exception = JS_GetException(ctx); - - JSValue const err_message = JS_GetPropertyStr(ctx, exception, "message"); - const char *err_message_c_str = JS_ToCString(ctx, err_message); - - env->ThrowNew(error_class, err_message_c_str); - - JS_FreeCString(ctx, err_message_c_str); - - JS_FreeValue(ctx, err_message); - JS_FreeValue(ctx, exception); - - return true; - } - - return false; -} - -JSValue throw_jvm_exception_in_js(JNIEnv *env, JSContext *ctx) { - if (!env->ExceptionCheck()) { - return JS_NULL; - } - - auto *throwable = env->ExceptionOccurred(); - env->ExceptionClear(); - - jclass exception_class = env->FindClass("java/lang/Exception"); - jmethodID exception_constructor = env->GetMethodID(exception_class, "", "(Ljava/lang/Throwable;)V"); - jmethodID get_message_method = env->GetMethodID(exception_class, "getMessage", "()Ljava/lang/String;"); - - auto *err_obj = env->NewObject(exception_class, exception_constructor, throwable); - auto *err_msg = (jstring)env->CallObjectMethod(err_obj, get_message_method); - - const auto *c_err_msg = env->GetStringUTFChars(err_msg, nullptr); - - auto exception = throw_js_exception(ctx, c_err_msg); - - env->ReleaseStringUTFChars(err_msg, c_err_msg); - - return exception; -} - -JSValue throw_js_exception(JSContext *ctx, const char *message) { - auto exception = JS_NewError(ctx); - JS_SetPropertyStr(ctx, exception, "message", JS_NewString(ctx, message)); - - return JS_Throw(ctx, exception); -} - -void reject_promise(JSContext *ctx, JSValue reject_func, JSValue reject_obj) { - auto global_obj = JS_GetGlobalObject(ctx); - JSValueConst reject_args[1]; - reject_args[0] = reject_obj; - - JS_Call(ctx, reject_func, global_obj, 1, reject_args); - JS_FreeValue(ctx, global_obj); -} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/errors.h b/packages/android-engine/android-js-engine/src/main/cpp/errors.h deleted file mode 100644 index af05c407..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/errors.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CAPACITOR_BACKGROUND_RUNNER_ERRORS_H -#define CAPACITOR_BACKGROUND_RUNNER_ERRORS_H - -#include -#include "quickjs/quickjs.h" - -bool throw_js_exception_in_jvm(JNIEnv *env, JSContext *ctx, JSValue value); -JSValue throw_jvm_exception_in_js(JNIEnv *env, JSContext *ctx); -JSValue throw_js_exception(JSContext *ctx, const char * message); -void reject_promise(JSContext *ctx, JSValue reject_func, JSValue reject_obj); - -#endif //CAPACITOR_BACKGROUND_RUNNER_ERRORS_H diff --git a/packages/android-engine/android-js-engine/src/main/cpp/native_context.cpp b/packages/android-engine/android-js-engine/src/main/cpp/native_context.cpp deleted file mode 100644 index f35de364..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/native_context.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include - -#include "context.h" -#include "errors.h" -#include "runner.h" - -extern "C" JNIEXPORT jlong JNICALL Java_io_ionic_android_1js_1engine_Context_createRunnerContext(JNIEnv *env, jobject thiz, jlong runner_ptr, jstring name) { - auto *runner = (Runner *)runner_ptr; - return (jlong)runner->create_context(env->GetStringUTFChars(name, nullptr), env); -} -extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Context_destroyRunnerContext(JNIEnv *env, jobject thiz, jlong runner_ptr, jlong ptr) { - auto *runner = (Runner *)runner_ptr; - auto *ctx = (Context *)ptr; - - runner->destroy_context(ctx->name); -} -extern "C" JNIEXPORT jstring JNICALL Java_io_ionic_android_1js_1engine_Context_evaluate(JNIEnv *env, jobject thiz, jlong ptr, jstring code, jboolean ret_value) { - auto *ctx = (Context *)ptr; - - const char *c_code = env->GetStringUTFChars(code, nullptr); - auto value = ctx->evaluate(c_code, (bool)ret_value); - - if (throw_js_exception_in_jvm(env, ctx->qjs_context, value)) { - JS_FreeValue(ctx->qjs_context, value); - return nullptr; - } - - const char *json_string = JS_ToCString(ctx->qjs_context, value); - auto *j_json_string = env->NewStringUTF(json_string); - - JS_FreeCString(ctx->qjs_context, json_string); - JS_FreeValue(ctx->qjs_context, value); - - return j_json_string; -} -extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Context_registerGlobalFunction(JNIEnv *env, jobject thiz, jlong ptr, jstring function_name, jobject function) { - auto *context = (Context *)ptr; - - const auto *c_function_name = env->GetStringUTFChars(function_name, nullptr); - context->register_function(c_function_name, env->NewGlobalRef(function)); - - env->ReleaseStringUTFChars(function_name, c_function_name); -} -extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Context_dispatchEvent(JNIEnv *env, jobject thiz, jlong ptr, jstring event, jstring details) { - auto *context = (Context *)ptr; - - const char *c_event = env->GetStringUTFChars(event, nullptr); - const char *c_details_json = env->GetStringUTFChars(details, nullptr); - - auto details_obj = JS_ParseJSON(context->qjs_context, c_details_json, strlen(c_details_json), "
"); - - auto value = context->dispatch_event(c_event, details_obj); - JS_FreeValue(context->qjs_context, details_obj); - - env->ReleaseStringUTFChars(event, c_event); - env->ReleaseStringUTFChars(details, c_details_json); - - throw_js_exception_in_jvm(env, context->qjs_context, value); - - JS_FreeValue(context->qjs_context, value); -} -extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Context_setCapacitorAPI(JNIEnv *env, jobject thiz, jlong ptr, jobject api) { - auto *ctx = (Context *)ptr; - auto *api_instance = env->NewGlobalRef(api); - - ctx->init_capacitor_api(api_instance); -} \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/VERSION b/packages/android-engine/android-js-engine/src/main/cpp/quickjs/VERSION deleted file mode 100644 index 22ffec18..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/VERSION +++ /dev/null @@ -1 +0,0 @@ -2021-03-27 diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/jsbignum.html b/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/jsbignum.html deleted file mode 100644 index b07f7c14..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/jsbignum.html +++ /dev/null @@ -1,1005 +0,0 @@ - - - - - Javascript Bignum Extensions - - - - - - - - - - - - - -

Javascript Bignum Extensions

- - -

Table of Contents

- - - - -

1 Introduction

- -

- The Bignum extensions add the following features to the Javascript - language while being 100% backward compatible: -

-
    -
  • - Operator overloading with a dispatch logic inspired from the proposal - available at - https://github.com/tc39/proposal-operator-overloading/. -
  • -
  • - Arbitrarily large floating point numbers (BigFloat) in base - 2 using the IEEE 754 semantics. -
  • -
  • - Arbitrarily large floating point numbers (BigDecimal) in - base 10 based on the proposal available at - https://github.com/littledan/proposal-bigdecimal. -
  • -
  • - math mode: arbitrarily large integers and floating point - numbers are available by default. The integer division and power can be - overloaded for example to return a fraction. The modulo operator - (%) is defined as the Euclidian remainder. - ^ is an alias to the power operator (**). - ^^ is used as the exclusive or operator. -
  • -
- -

- The extensions are independent from each other except the - math - mode which relies on BigFloat and operator overloading. -

- -

2 Operator overloading

- -

- Operator overloading is inspired from the proposal available at - https://github.com/tc39/proposal-operator-overloading/. It implements the same dispatch logic but finds the operator sets by - looking at the Symbol.operatorSet property in the objects. - The changes were done in order to simplify the implementation. -

-

More precisely, the following modifications were made:

-
    -
  • - with operators from is not supported. Operator overloading - is always enabled. -
  • -
  • - The dispatch is not based on a static [[OperatorSet]] field - in all instances. Instead, a dynamic lookup of the - Symbol.operatorSet property is done. This property is - typically added in the prototype of each object. -
  • -
  • - Operators.create(...dictionaries) is used to create a new - OperatorSet object. The Operators function is supported as - an helper to be closer to the TC39 proposal. -
  • -
  • [] cannot be overloaded.
  • -
  • - In math mode, the BigInt division and power operators can be overloaded - with Operators.updateBigIntOperators(dictionary). -
  • -
- - -

3 BigInt extensions

- -

A few properties are added to the BigInt object:

-
-
tdiv(a, b)
-
-

- Return trunc(a/b). b = 0 raises a RangeError - exception. -

-
-
fdiv(a, b)
-
-

- Return \lfloor a/b \rfloor. b = 0 raises a - RangeError exception. -

-
-
cdiv(a, b)
-
-

- Return \lceil a/b \rceil. b = 0 raises a - RangeError exception. -

-
-
ediv(a, b)
-
-

- Return sgn(b) \lfloor a/{|b|} \rfloor (Euclidian division). - b = 0 raises a RangeError exception. -

-
-
tdivrem(a, b)
-
fdivrem(a, b)
-
cdivrem(a, b)
-
edivrem(a, b)
-
-

- Return an array of two elements. The first element is the quotient, - the second is the remainder. The same rounding is done as the - corresponding division operation. -

-
-
sqrt(a)
-
-

- Return \lfloor \sqrt(a) \rfloor. A RangeError exception is - raised if a < 0. -

-
-
sqrtrem(a)
-
-

- Return an array of two elements. The first element is - \lfloor \sqrt{a} \rfloor. The second element is - a-\lfloor \sqrt{a} \rfloor^2. A RangeError exception is - raised if a < 0. -

-
-
floorLog2(a)
-
-

- Return -1 if a \leq 0 otherwise return - \lfloor \log2(a) \rfloor. -

-
-
ctz(a)
-
-

- Return the number of trailing zeros in the two’s complement - binary representation of a. Return -1 if a=0. -

-
-
- - -

4 BigFloat

- - -

4.1 Introduction

- -

- This extension adds the BigFloat primitive type. The - BigFloat type represents floating point numbers in base 2 - with the IEEE 754 semantics. A floating point number is represented as a - sign, mantissa and exponent. The special values NaN, - +/-Infinity, +0 and -0 - are supported. The mantissa and exponent can have any bit length with an - implementation specific minimum and maximum. -

- -

4.2 Floating point rounding

- -

- Each floating point operation operates with infinite precision and then - rounds the result according to the specified floating point environment - (BigFloatEnv object). The status flags of the environment are - also set according to the result of the operation. -

-

- If no floating point environment is provided, the global floating point - environment is used. -

-

- The rounding mode of the global floating point environment is always - RNDN (“round to nearest with ties to even”)1. The status flags of the global environment cannot be read2. The precision of the global environment is - BigFloatEnv.prec. The number of exponent bits of the global - environment is BigFloatEnv.expBits. The global environment - subnormal flag is set to true. -

-

- For example, prec = 53 and expBits = 11 exactly - give the same precision as the IEEE 754 64 bit floating point format. The - default precision is prec = 113 and - expBits = 15 (IEEE 754 128 bit floating point format). -

-

- The global floating point environment can only be modified temporarily - when calling a function (see BigFloatEnv.setPrec). Hence a - function can change the global floating point environment for its callees - but not for its caller. -

- -

4.3 Operators

- -

- The builtin operators are extended so that a BigFloat is returned if at - least one operand is a BigFloat. The computations are always done with - infinite precision and rounded according to the global floating point - environment. -

-

- typeof applied on a BigFloat returns - bigfloat. -

-

- BigFloat can be compared with all the other numeric types and the result - follows the expected mathematical relations. -

-

- However, since BigFloat and Number are different types they are never - equal when using the strict comparison operators (e.g. - 0.0 === 0.0l is false). -

- -

4.4 BigFloat literals

- -

- BigFloat literals are floating point numbers with a trailing - l suffix. BigFloat literals have an infinite precision. They - are rounded according to the global floating point environment when they - are evaluated.3 -

- -

4.5 Builtin Object changes

- - -

4.5.1 BigFloat function

- -

- The BigFloat function cannot be invoked as a constructor. - When invoked as a function: the parameter is converted to a primitive - type. If the result is a numeric type, it is converted to BigFloat without - rounding. If the result is a string, it is converted to BigFloat using the - precision of the global floating point environment. -

-

BigFloat properties:

-
-
LN2
-
PI
-
-

- Getter. Return the value of the corresponding mathematical constant - rounded to nearest, ties to even with the current global precision. - The constant values are cached for small precisions. -

-
-
MIN_VALUE
-
MAX_VALUE
-
EPSILON
-
-

- Getter. Return the minimum, maximum and epsilon - BigFloat values (same definition as the corresponding - Number constants). -

-
-
fpRound(a[, e])
-
-

- Round the floating point number a according to the - floating point environment e or the global environment if - e is undefined. -

-
-
parseFloat(a[, radix[, e]])
-
-

- Parse the string a as a floating point number in radix - radix. The radix is 0 (default) or from 2 to 36. The - radix 0 means radix 10 unless there is a hexadecimal or binary prefix. - The result is rounded according to the floating point environment - e or the global environment if e is - undefined. -

-
-
isFinite(a)
-
-

Return true if a is a finite bigfloat.

-
-
isNaN(a)
-
-

Return true if a is a NaN bigfloat.

-
-
add(a, b[, e])
-
sub(a, b[, e])
-
mul(a, b[, e])
-
div(a, b[, e])
-
-

- Perform the specified floating point operation and round the floating - point number a according to the floating point - environment e or the global environment if - e is undefined. If e is specified, the - floating point status flags are updated. -

-
-
floor(x)
-
ceil(x)
-
round(x)
-
trunc(x)
-

Round to an integer. No additional rounding is performed.

-
abs(x)
-
-

- Return the absolute value of x. No additional rounding is performed. -

-
-
fmod(x, y[, e])
-
remainder(x, y[, e])
-
-

- Floating point remainder. The quotient is truncated to zero (fmod) or - to the nearest integer with ties to even (remainder). - e is an optional floating point environment. -

-
-
sqrt(x[, e])
-
-

- Square root. Return a rounded floating point number. e is - an optional floating point environment. -

-
-
sin(x[, e])
-
cos(x[, e])
-
tan(x[, e])
-
asin(x[, e])
-
acos(x[, e])
-
atan(x[, e])
-
atan2(x, y[, e])
-
exp(x[, e])
-
log(x[, e])
-
pow(x, y[, e])
-
-

- Transcendental operations. Return a rounded floating point number. - e is an optional floating point environment. -

-
-
- - -

4.5.2 BigFloat.prototype

- -

The following properties are modified:

-
-
valueOf()
-
-

- Return the bigfloat primitive value corresponding to - this. -

-
-
toString(radix)
-
-

For floating point numbers:

-
    -
  • - If the radix is a power of two, the conversion is done with infinite - precision. -
  • -
  • - Otherwise, the number is rounded to nearest with ties to even using - the global precision. It is then converted to string using the - minimum number of digits so that its conversion back to a floating - point using the global precision and round to nearest gives the same - number. -
  • -
- -

- The exponent letter is e for base 10, p for - bases 2, 8, 16 with a binary exponent and @ for the other - bases. -

-
-
- toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10) -
-
toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
-
- toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10) -
-
-

- Same semantics as the corresponding Number functions with - BigFloats. There is no limit on the accepted precision p. - The rounding mode and radix can be optionally specified. The radix - must be between 2 and 36. -

-
-
- - -

4.5.3 BigFloatEnv constructor

- -

- The BigFloatEnv([p, [,rndMode]] constructor cannot be invoked - as a function. The floating point environment contains: -

-
    -
  • the mantissa precision in bits
  • -
  • the exponent size in bits assuming an IEEE 754 representation;
  • -
  • - the subnormal flag (if true, subnormal floating point numbers can be - generated by the floating point operations). -
  • -
  • the rounding mode
  • -
  • - the floating point status. The status flags can only be set by the - floating point operations. They can be reset with - BigFloatEnv.prototype.clearStatus() or with the various - status flag setters. -
  • -
- -

- new BigFloatEnv([p, [,rndMode]] creates a new floating point - environment. The status flags are reset. If no parameter is given the - precision, exponent bits and subnormal flags are copied from the global - floating point environment. Otherwise, the precision is set to - p, the number of exponent bits is set to - expBitsMax and the subnormal flags is set to - false. If rndMode is undefined, the - rounding mode is set to RNDN. -

-

BigFloatEnv properties:

-
-
prec
-
-

- Getter. Return the precision in bits of the global floating point - environment. The initial value is 113. -

-
-
expBits
-
-

- Getter. Return the exponent size in bits of the global floating point - environment assuming an IEEE 754 representation. The initial value is - 15. -

-
-
setPrec(f, p[, e])
-
-

- Set the precision of the global floating point environment to - p and the exponent size to e then call the - function f. Then the Float precision and exponent size - are reset to their precious value and the return value of - f is returned (or an exception is raised if - f raised an exception). If e is - undefined it is set to - BigFloatEnv.expBitsMax. -

-
-
precMin
-
-

- Read-only integer. Return the minimum allowed precision. Must be at - least 2. -

-
-
precMax
-
-

- Read-only integer. Return the maximum allowed precision. Must be at - least 113. -

-
-
expBitsMin
-
-

- Read-only integer. Return the minimum allowed exponent size in bits. - Must be at least 3. -

-
-
expBitsMax
-
-

- Read-only integer. Return the maximum allowed exponent size in bits. - Must be at least 15. -

-
-
RNDN
-
-

- Read-only integer. Round to nearest, with ties to even rounding mode. -

-
-
RNDZ
-

Read-only integer. Round to zero rounding mode.

-
RNDD
-

Read-only integer. Round to -Infinity rounding mode.

-
RNDU
-

Read-only integer. Round to +Infinity rounding mode.

-
RNDNA
-
-

- Read-only integer. Round to nearest, with ties away from zero rounding - mode. -

-
-
RNDA
-

Read-only integer. Round away from zero rounding mode.

-
- RNDF4 -
-
-

- Read-only integer. Faithful rounding mode. The result is - non-deterministically rounded to -Infinity or +Infinity. This rounding - mode usually gives a faster and deterministic running time for the - floating point operations. -

-
-
- -

BigFloatEnv.prototype properties:

-
-
prec
-
-

Getter and setter (Integer). Return or set the precision in bits.

-
-
expBits
-
-

- Getter and setter (Integer). Return or set the exponent size in bits - assuming an IEEE 754 representation. -

-
-
rndMode
-
-

Getter and setter (Integer). Return or set the rounding mode.

-
-
subnormal
-
-

- Getter and setter (Boolean). subnormal flag. It is false when - expBits = expBitsMax. -

-
-
clearStatus()
-

Clear the status flags.

-
invalidOperation
-
divideByZero
-
overflow
-
underflow
-
inexact
-

Getter and setter (Boolean). Status flags.

-
- - -

5 BigDecimal

- -

- This extension adds the BigDecimal primitive type. The - BigDecimal type represents floating point numbers in base 10. - It is inspired from the proposal available at - https://github.com/littledan/proposal-bigdecimal. -

-

- The BigDecimal floating point numbers are always normalized - and finite. There is no concept of -0, - Infinity or NaN. By default, all the - computations are done with infinite precision. -

- -

5.1 Operators

- -

The following builtin operators support BigDecimal:

-
-
+
-
-
-
*
-
-

- Both operands must be BigDecimal. The result is computed with infinite - precision. -

-
-
%
-
-

- Both operands must be BigDecimal. The result is computed with infinite - precision. A range error is throws in case of division by zero. -

-
-
/
-
-

- Both operands must be BigDecimal. A range error is throws in case of - division by zero or if the result cannot be represented with infinite - precision (use BigDecimal.div to specify the rounding). -

-
-
**
-
-

- Both operands must be BigDecimal. The exponent must be a positive - integer. The result is computed with infinite precision. -

-
-
===
-
-

- When one of the operand is a BigDecimal, return true if both operands - are a BigDecimal and if they are equal. -

-
-
==
-
!=
-
<=
-
>=
-
<
-
>
-
-

- Numerical comparison. When one of the operand is not a BigDecimal, it - is converted to BigDecimal by using ToString(). Hence comparisons - between Number and BigDecimal do not use the exact mathematical value - of the Number value. -

-
-
- - -

5.2 BigDecimal literals

- -

- BigDecimal literals are decimal floating point numbers with a trailing - m suffix. -

- -

5.3 Builtin Object changes

- - -

5.3.1 The BigDecimal function.

- -

- It returns 0m if no parameter is provided. Otherwise the - first parameter is converted to a bigdecimal by using ToString(). Hence - Number values are not converted to their exact numerical value as - BigDecimal. -

- -

- 5.3.2 Properties of the BigDecimal object -

- -
-
add(a, b[, e])
-
sub(a, b[, e])
-
mul(a, b[, e])
-
div(a, b[, e])
-
mod(a, b[, e])
-
sqrt(a, e)
-
round(a, e)
-
-

- Perform the specified floating point operation and round the floating - point result according to the rounding object e. If the - rounding object is not present, the operation is executed with - infinite precision. -

-

- For div, a RangeError exception is thrown in - case of division by zero or if the result cannot be represented with - infinite precision if no rounding object is present. -

-

- For sqrt, a range error is thrown if a is - less than zero. -

-

- The rounding object must contain the following properties: - roundingMode is a string specifying the rounding mode - ("floor", "ceiling", - "down", "up", - "half-even", "half-up"). - Either maximumSignificantDigits or - maximumFractionDigits must be present to specify - respectively the number of significant digits (must be >= 1) or the - number of digits after the decimal point (must be >= 0). -

-
-
- - -

- 5.3.3 Properties of the BigDecimal.prototype object -

- -
-
valueOf()
-
-

- Return the bigdecimal primitive value corresponding to - this. -

-
-
toString()
-
-

- Convert this to a string with infinite precision in base - 10. -

-
-
toPrecision(p, rnd_mode = "half-up")
-
toFixed(p, rnd_mode = "half-up")
-
toExponential(p, rnd_mode = "half-up")
-
-

- Convert the BigDecimal this to string with the specified - precision p. There is no limit on the accepted precision - p. The rounding mode can be optionally specified. - toPrecision outputs either in decimal fixed notation or - in decimal exponential notation with a p digits of - precision. toExponential outputs in decimal exponential - notation with p digits after the decimal point. - toFixed outputs in decimal notation with - p digits after the decimal point. -

-
-
- - -

6 Math mode

- -

- A new math mode is enabled with the - "use math" directive. It propagates the same way as - the strict mode. It is designed so that arbitrarily large - integers and floating point numbers are available by default. In order to - minimize the number of changes in the Javascript semantics, integers are - represented either as Number or BigInt depending on their magnitude. - Floating point numbers are always represented as BigFloat. -

-

The following changes are made to the Javascript semantics:

-
    -
  • - Floating point literals (i.e. number with a decimal point or an - exponent) are BigFloat by default (i.e. a - l suffix is implied). Hence - typeof 1.0 === "bigfloat". -
  • -
  • - Integer literals (i.e. numbers without a decimal point or an exponent) - with or without the n suffix are BigInt if - their value cannot be represented as a safe integer. A safe integer is - defined as a integer whose absolute value is smaller or equal to - 2**53-1. Hence - typeof 1 === "number ", - typeof 1n === "number" but - typeof 9007199254740992 === "bigint" . -
  • -
  • - All the bigint builtin operators and functions are modified so that - their result is returned as a Number if it is a safe integer. Otherwise - the result stays a BigInt. -
  • -
  • - The builtin operators are modified so that they return an exact result - (which can be a BigInt) if their operands are safe integers. Operands - between Number and BigInt are accepted provided the Number operand is a - safe integer. The integer power with a negative exponent returns a - BigFloat as result. The integer division returns a BigFloat as result. -
  • -
  • - The ^ operator is an alias to the power operator - (**). -
  • -
  • - The power operator (both ^ and **) grammar is - modified so that -2^2 is allowed and yields - -4. -
  • -
  • - The logical xor operator is still available with the - ^^ operator. -
  • -
  • - The modulo operator (%) returns the Euclidian remainder - (always positive) instead of the truncated remainder. -
  • -
  • - The integer division operator can be overloaded with - Operators.updateBigIntOperators(dictionary). -
  • -
  • - The integer power operator with a non zero negative exponent can be - overloaded with - Operators.updateBigIntOperators(dictionary). -
  • -
- -
-
-

Footnotes

- -

(1)

-

- The rationale is that the rounding mode changes must always be explicit. -

-

(2)

-

The rationale is to avoid side effects for the built-in operators.

-

(3)

-

- Base 10 floating point literals cannot usually be exactly represented as - base 2 floating point number. In order to ensure that the literal is - represented accurately with the current precision, it must be evaluated - at runtime. -

-

(4)

-

- Could be removed in case a deterministic behavior for floating point - operations is required. -

-
-
- - diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/quickjs.html b/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/quickjs.html deleted file mode 100644 index f317fe7e..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/quickjs.html +++ /dev/null @@ -1,1797 +0,0 @@ - - - - - QuickJS Javascript Engine - - - - - - - - - - - - - -

QuickJS Javascript Engine

- - -

Table of Contents

- - - - -

1 Introduction

- -

- QuickJS is a small and embeddable Javascript engine. It supports the - ES2020 specification - 1 - including modules, asynchronous generators, proxies and BigInt. -

-

- It supports mathematical extensions such as big decimal float float - numbers (BigDecimal), big binary floating point numbers (BigFloat), and - operator overloading. -

- -

1.1 Main Features

- -
    -
  • - Small and easily embeddable: just a few C files, no external dependency, - 210 KiB of x86 code for a simple “hello world” program. -
  • -
  • - Fast interpreter with very low startup time: runs the 69000 tests of the - ECMAScript Test Suite2 in - about 95 seconds on a single core of a desktop PC. The complete life - cycle of a runtime instance completes in less than 300 microseconds. -
  • -
  • - Almost complete ES2020 support including modules, asynchronous - generators and full Annex B support (legacy web compatibility). Many - features from the upcoming ES2021 specification - 3 are also supported. -
  • -
  • - Passes nearly 100% of the ECMAScript Test Suite tests when selecting the - ES2020 features. -
  • -
  • - Compile Javascript sources to executables with no external dependency. -
  • -
  • - Garbage collection using reference counting (to reduce memory usage and - have deterministic behavior) with cycle removal. -
  • -
  • - Mathematical extensions: BigDecimal, BigFloat, operator overloading, - bigint mode, math mode. -
  • -
  • - Command line interpreter with contextual colorization and completion - implemented in Javascript. -
  • -
  • Small built-in standard library with C library wrappers.
  • -
- - -

2 Usage

- - -

2.1 Installation

- -

- A Makefile is provided to compile the engine on Linux or MacOS/X. A - preliminary Windows support is available thru cross compilation on a Linux - host with the MingGW tools. -

-

- Edit the top of the Makefile if you wish to select specific - options then run make. -

-

- You can type make install as root if you wish to install the - binaries and support files to /usr/local (this is not - necessary to use QuickJS). -

- -

2.2 Quick start

- -

- qjs is the command line interpreter (Read-Eval-Print Loop). - You can pass Javascript files and/or expressions as arguments to execute - them: -

-
-
-./qjs examples/hello.js
-
-
- -

qjsc is the command line compiler:

-
-
-./qjsc -o hello examples/hello.js
-./hello
-
-
- -

- generates a hello executable with no external dependency. -

- -

2.3 Command line options

- - -

2.3.1 qjs interpreter

- -
-usage: qjs [options] [file [args]]
-
-

Options are:

-
-
-h
-
--help
-

List options.

-
- -e EXPR -
-
- --eval EXPR -
-

Evaluate EXPR.

-
-i
-
--interactive
-
-

- Go to interactive mode (it is not the default when files are provided - on the command line). -

-
-
-m
-
--module
-
-

- Load as ES6 module (default=autodetect). A module is autodetected if - the filename extension is .mjs or if the first keyword of - the source is import. -

-
-
--script
-

Load as ES6 script (default=autodetect).

-
--bignum
-
-

- Enable the bignum extensions: BigDecimal object, BigFloat object and - the "use math" directive. -

-
-
-I file
-
--include file
-

Include an additional file.

-
- -

Advanced options are:

-
-
--std
-
-

- Make the std and os modules available to the - loaded script even if it is not a module. -

-
-
-d
-
--dump
-

Dump the memory usage stats.

-
-q
-
--quit
-

just instantiate the interpreter and quit.

-
- - -

2.3.2 qjsc compiler

- -
-usage: qjsc [options] [files]
-
-

Options are:

-
-
-c
-
-

- Only output bytecode in a C file. The default is to output an - executable file. -

-
-
-e
-
-

- Output main() and bytecode in a C file. The default is to - output an executable file. -

-
-
-o output
-
-

- Set the output filename (default = out.c or - a.out). -

-
-
-N cname
-

Set the C name of the generated data.

-
-m
-

Compile as Javascript module (default=autodetect).

-
-D module_name
-
-

- Compile a dynamically loaded module and its dependencies. This option - is needed when your code uses the import keyword or the - os.Worker constructor because the compiler cannot - statically find the name of the dynamically loaded modules. -

-
-
-M module_name[,cname]
-
-

- Add initialization code for an external C module. See the - c_module example. -

-
-
-x
-

Byte swapped output (only used for cross compilation).

-
-flto
-
-

- Use link time optimization. The compilation is slower but the - executable is smaller and faster. This option is automatically set - when the -fno-x options are used. -

-
-
- -fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint] -
-
-

- Disable selected language features to produce a smaller executable - file. -

-
-
-fbignum
-
-

- Enable the bignum extensions: BigDecimal object, BigFloat object and - the "use math" directive. -

-
-
- - -

2.4 qjscalc application

- -

- The qjscalc application is a superset of the qjs - command line interpreter implementing a Javascript calculator with - arbitrarily large integer and floating point numbers, fractions, complex - numbers, polynomials and matrices. The source code is in - qjscalc.js. More documentation and a web version are - available at http://numcalc.com. -

- -

2.5 Built-in tests

- -

- Run make test to run the few built-in tests included in the - QuickJS archive. -

- -

2.6 Test262 (ECMAScript Test Suite)

- -

- A test262 runner is included in the QuickJS archive. The test262 tests can - be installed in the QuickJS source directory with: -

-
-
-git clone https://github.com/tc39/test262.git test262
-cd test262
-patch -p1 < ../tests/test262.patch
-cd ..
-
-
- -

- The patch adds the implementation specific harness functions - and optimizes the inefficient RegExp character classes and Unicode - property escapes tests (the tests themselves are not modified, only a slow - string initialization function is optimized). -

-

The tests can be run with

-
-
-make test2
-
-
- -

- The configuration files test262.conf (resp. - test262o.conf for the old ES5.1 tests4)) contain the options to run the various tests. Tests can be excluded - based on features or filename. -

-

- The file test262_errors.txt contains the current list of - errors. The runner displays a message when a new error appears or when an - existing error is corrected or modified. Use the -u option to - update the current list of errors (or make test2-update). -

-

- The file test262_report.txt contains the logs of all the - tests. It is useful to have a clearer analysis of a particular error. In - case of crash, the last line corresponds to the failing test. -

-

- Use the syntax - ./run-test262 -c test262.conf -f filename.js to run a single - test. Use the syntax ./run-test262 -c test262.conf N to start - testing at test number N. -

-

- For more information, run ./run-test262 to see the command - line options of the test262 runner. -

-

- run-test262 accepts the -N option to be invoked - from test262-harness5 thru eshost. - Unless you want to compare QuickJS with other engines under the same - conditions, we do not recommend to run the tests this way as it is much - slower (typically half an hour instead of about 100 seconds). -

- -

3 Specifications

- - -

3.1 Language support

- - -

3.1.1 ES2020 support

- -

- The ES2020 specification is almost fully supported including the Annex B - (legacy web compatibility) and the Unicode related features. -

-

The following features are not supported yet:

-
    -
  • - Tail calls6 -
  • -
- - -

3.1.2 ECMA402

- -

ECMA402 (Internationalization API) is not supported.

- -

3.1.3 Extensions

- -
    -
  • - The directive "use strip" indicates that the - debug information (including the source code of the functions) should - not be retained to save memory. As "use strict", - the directive can be global to a script or local to a function. -
  • -
  • - The first line of a script beginning with #! is ignored. -
  • -
- - -

3.1.4 Mathematical extensions

- -

- The mathematical extensions are fully backward compatible with standard - Javascript. See jsbignum.pdf for more information. -

-
    -
  • - BigDecimal support: arbitrary large floating point numbers - in base 10. -
  • -
  • - BigFloat support: arbitrary large floating point numbers in - base 2. -
  • -
  • Operator overloading.
  • -
  • - The directive "use bigint" enables the bigint - mode where integers are BigInt by default. -
  • -
  • - The directive "use math" enables the math mode - where the division and power operators on integers produce fractions. - Floating point literals are BigFloat by default and - integers are BigInt by default. -
  • -
- - -

3.2 Modules

- -

- ES6 modules are fully supported. The default name resolution is the - following: -

-
    -
  • - Module names with a leading . or .. are - relative to the current module path. -
  • -
  • - Module names without a leading . or .. are - system modules, such as std or os. -
  • -
  • - Module names ending with .so are native modules using the - QuickJS C API. -
  • -
- - -

3.3 Standard library

- -

- The standard library is included by default in the command line - interpreter. It contains the two modules std and - os and a few global objects. -

- -

3.3.1 Global objects

- -
-
scriptArgs
-
-

- Provides the command line arguments. The first argument is the script - name. -

-
-
print(...args)
-
-

Print the arguments separated by spaces and a trailing newline.

-
-
console.log(...args)
-

Same as print().

-
- - -

3.3.2 std module

- -

- The std module provides wrappers to the libc - stdlib.h and stdio.h and a few other utilities. -

-

Available exports:

-
-
exit(n)
-

Exit the process.

-
evalScript(str, options = undefined)
-
-

- Evaluate the string str as a script (global eval). - options is an optional object containing the following - optional properties: -

-
-
backtrace_barrier
-
-

- Boolean (default = false). If true, error backtraces do not list - the stack frames below the evalScript. -

-
-
-
-
loadScript(filename)
-
-

- Evaluate the file filename as a script (global eval). -

-
-
loadFile(filename)
-
-

- Load the file filename and return it as a string assuming - UTF-8 encoding. Return null in case of I/O error. -

-
-
open(filename, flags, errorObj = undefined)
-
-

- Open a file (wrapper to the libc fopen()). Return the - FILE object or null in case of I/O error. If - errorObj is not undefined, set its - errno property to the error code or to 0 if no error - occured. -

-
-
popen(command, flags, errorObj = undefined)
-
-

- Open a process by creating a pipe (wrapper to the libc - popen()). Return the FILE object or null in - case of I/O error. If errorObj is not undefined, set its - errno property to the error code or to 0 if no error - occured. -

-
-
fdopen(fd, flags, errorObj = undefined)
-
-

- Open a file from a file handle (wrapper to the libc - fdopen()). Return the FILE object or null in - case of I/O error. If errorObj is not undefined, set its - errno property to the error code or to 0 if no error - occured. -

-
-
tmpfile(errorObj = undefined)
-
-

- Open a temporary file. Return the FILE object or null in - case of I/O error. If errorObj is not undefined, set its - errno property to the error code or to 0 if no error - occured. -

-
-
puts(str)
-
-

Equivalent to std.out.puts(str).

-
-
printf(fmt, ...args)
-
-

Equivalent to std.out.printf(fmt, ...args).

-
-
sprintf(fmt, ...args)
-

Equivalent to the libc sprintf().

-
in
-
out
-
err
-
-

- Wrappers to the libc file stdin, stdout, - stderr. -

-
-
SEEK_SET
-
SEEK_CUR
-
SEEK_END
-

Constants for seek().

-
Error
-
-

- Enumeration object containing the integer value of common errors - (additional error codes may be defined): -

-
-
EINVAL
-
EIO
-
EACCES
-
EEXIST
-
ENOSPC
-
ENOSYS
-
EBUSY
-
ENOENT
-
EPERM
-
EPIPE
-
-
-
strerror(errno)
-
-

Return a string that describes the error errno.

-
-
gc()
-
-

- Manually invoke the cycle removal algorithm. The cycle removal - algorithm is automatically started when needed, so this function is - useful in case of specific memory constraints or for testing. -

-
-
getenv(name)
-
-

- Return the value of the environment variable name or - undefined if it is not defined. -

-
-
setenv(name, value)
-
-

- Set the value of the environment variable name to the - string value. -

-
-
unsetenv(name)
-
-

Delete the environment variable name.

-
-
getenviron()
-
-

- Return an object containing the environment variables as key-value - pairs. -

-
-
urlGet(url, options = undefined)
-
-

- Download url using the curl command line - utility. options is an optional object containing the - following optional properties: -

-
-
binary
-
-

- Boolean (default = false). If true, the response is an ArrayBuffer - instead of a string. When a string is returned, the data is - assumed to be UTF-8 encoded. -

-
-
full
-
-

- Boolean (default = false). If true, return the an object contains - the properties response (response content), - responseHeaders (headers separated by CRLF), - status (status code). response is - null is case of protocol or network error. If - full is false, only the response is returned if the - status is between 200 and 299. Otherwise null - is returned. -

-
-
-
-
parseExtJSON(str)
-
-

- Parse str using a superset of JSON.parse. - The following extensions are accepted: -

-
    -
  • Single line and multiline comments
  • -
  • unquoted properties (ASCII-only Javascript identifiers)
  • -
  • trailing comma in array and object definitions
  • -
  • single quoted strings
  • -
  • - \f and \v are accepted as space characters -
  • -
  • leading plus in numbers
  • -
  • - octal (0o prefix) and hexadecimal (0x - prefix) numbers -
  • -
-
-
- -

FILE prototype:

-
-
close()
-
-

- Close the file. Return 0 if OK or -errno in case of I/O - error. -

-
-
puts(str)
-

Outputs the string with the UTF-8 encoding.

-
printf(fmt, ...args)
-
-

Formatted printf.

-

- The same formats as the standard C library printf are - supported. Integer format types (e.g. %d) truncate the - Numbers or BigInts to 32 bits. Use the l modifier (e.g. - %ld) to truncate to 64 bits. -

-
-
flush()
-

Flush the buffered file.

-
seek(offset, whence)
-
-

- Seek to a give file position (whence is std.SEEK_*). - offset can be a number or a bigint. Return 0 if OK or - -errno in case of I/O error. -

-
-
tell()
-

Return the current file position.

-
tello()
-

Return the current file position as a bigint.

-
eof()
-

Return true if end of file.

-
fileno()
-

Return the associated OS handle.

-
error()
-

Return true if there was an error.

-
clearerr()
-

Clear the error indication.

-
read(buffer, position, length)
-
-

- Read length bytes from the file to the ArrayBuffer - buffer at byte position position (wrapper to - the libc fread). -

-
-
write(buffer, position, length)
-
-

- Write length bytes to the file from the ArrayBuffer - buffer at byte position position (wrapper to - the libc fwrite). -

-
-
getline()
-
-

- Return the next line from the file, assuming UTF-8 encoding, excluding - the trailing line feed. -

-
-
readAsString(max_size = undefined)
-
-

- Read max_size bytes from the file and return them as a - string assuming UTF-8 encoding. If max_size is not - present, the file is read up its end. -

-
-
getByte()
-
-

- Return the next byte from the file. Return -1 if the end of file is - reached. -

-
-
putByte(c)
-

Write one byte to the file.

-
- - -

3.3.3 os module

- -

- The os module provides Operating System specific functions: -

-
    -
  • low level file access
  • -
  • signals
  • -
  • timers
  • -
  • asynchronous I/O
  • -
  • workers (threads)
  • -
- -

- The OS functions usually return 0 if OK or an OS specific negative error - code. -

-

Available exports:

-
-
open(filename, flags, mode = 0o666)
-

Open a file. Return a handle or < 0 if error.

-
O_RDONLY
-
O_WRONLY
-
O_RDWR
-
O_APPEND
-
O_CREAT
-
O_EXCL
-
O_TRUNC
-

POSIX open flags.

-
O_TEXT
-
-

- (Windows specific). Open the file in text mode. The default is binary - mode. -

-
-
close(fd)
-
-

Close the file handle fd.

-
-
seek(fd, offset, whence)
-
-

- Seek in the file. Use std.SEEK_* for whence. - offset is either a number or a bigint. If - offset is a bigint, a bigint is returned too. -

-
-
read(fd, buffer, offset, length)
-
-

- Read length bytes from the file handle fd to - the ArrayBuffer buffer at byte position - offset. Return the number of read bytes or < 0 if - error. -

-
-
write(fd, buffer, offset, length)
-
-

- Write length bytes to the file handle - fd from the ArrayBuffer buffer at byte - position offset. Return the number of written bytes or - < 0 if error. -

-
-
isatty(fd)
-
-

- Return true is fd is a TTY (terminal) - handle. -

-
-
ttyGetWinSize(fd)
-
-

- Return the TTY size as [width, height] or - null if not available. -

-
-
ttySetRaw(fd)
-

Set the TTY in raw mode.

-
remove(filename)
-
-

Remove a file. Return 0 if OK or -errno.

-
-
rename(oldname, newname)
-
-

Rename a file. Return 0 if OK or -errno.

-
-
realpath(path)
-
-

- Return [str, err] where str is the - canonicalized absolute pathname of path and - err the error code. -

-
-
getcwd()
-
-

- Return [str, err] where str is the current - working directory and err the error code. -

-
-
chdir(path)
-
-

- Change the current directory. Return 0 if OK or -errno. -

-
-
mkdir(path, mode = 0o777)
-
-

- Create a directory at path. Return 0 if OK or - -errno. -

-
-
stat(path)
-
lstat(path)
-
-

- Return [obj, err] where obj is an object - containing the file status of path. err is - the error code. The following fields are defined in obj: - dev, ino, mode, nlink, uid, gid, rdev, size, blocks, atime, mtime, - ctime. The times are specified in milliseconds since 1970. - lstat() is the same as stat() excepts that - it returns information about the link itself. -

-
-
S_IFMT
-
S_IFIFO
-
S_IFCHR
-
S_IFDIR
-
S_IFBLK
-
S_IFREG
-
S_IFSOCK
-
S_IFLNK
-
S_ISGID
-
S_ISUID
-
-

- Constants to interpret the mode property returned by - stat(). They have the same value as in the C system - header sys/stat.h. -

-
-
utimes(path, atime, mtime)
-
-

- Change the access and modification times of the file - path. The times are specified in milliseconds since 1970. - Return 0 if OK or -errno. -

-
-
symlink(target, linkpath)
-
-

- Create a link at linkpath containing the string - target. Return 0 if OK or -errno. -

-
-
readlink(path)
-
-

- Return [str, err] where str is the link - target and err - the error code. -

-
-
readdir(path)
-
-

- Return [array, err] where array is an array - of strings containing the filenames of the directory - path. err is the error code. -

-
-
setReadHandler(fd, func)
-
-

- Add a read handler to the file handle fd. - func is called each time there is data pending for - fd. A single read handler per file handle is supported. - Use func = null to remove the handler. -

-
-
setWriteHandler(fd, func)
-
-

- Add a write handler to the file handle fd. - func is called each time data can be written to - fd. A single write handler per file handle is supported. - Use func = null to remove the handler. -

-
-
signal(signal, func)
-
-

- Call the function func when the signal - signal - happens. Only a single handler per signal number is supported. Use - null to set the default handler or - undefined to ignore the signal. Signal handlers can only - be defined in the main thread. -

-
-
SIGINT
-
SIGABRT
-
SIGFPE
-
SIGILL
-
SIGSEGV
-
SIGTERM
-

POSIX signal numbers.

-
kill(pid, sig)
-
-

Send the signal sig to the process pid.

-
-
exec(args[, options])
-
-

- Execute a process with the arguments args. - options is an object containing optional parameters: -

-
-
block
-
-

- Boolean (default = true). If true, wait until the process is - terminated. In this case, exec return the exit code - if positive or the negated signal number if the process was - interrupted by a signal. If false, do not block and return the - process id of the child. -

-
-
usePath
-
-

- Boolean (default = true). If true, the file is searched in the - PATH environment variable. -

-
-
file
-
-

- String (default = args[0]). Set the file to be - executed. -

-
-
cwd
-
-

- String. If present, set the working directory of the new process. -

-
-
stdin
-
stdout
-
stderr
-
-

- If present, set the handle in the child for stdin, stdout or - stderr. -

-
-
env
-
-

- Object. If present, set the process environment from the object - key-value pairs. Otherwise use the same environment as the current - process. -

-
-
uid
-
-

- Integer. If present, the process uid with setuid. -

-
-
gid
-
-

- Integer. If present, the process gid with setgid. -

-
-
-
-
waitpid(pid, options)
-
-

- waitpid Unix system call. Return the array - [ret, status]. ret contains - -errno in case of error. -

-
-
WNOHANG
-
-

- Constant for the options argument of - waitpid. -

-
-
dup(fd)
-
-

dup Unix system call.

-
-
dup2(oldfd, newfd)
-
-

dup2 Unix system call.

-
-
pipe()
-
-

- pipe Unix system call. Return two handles as - [read_fd, write_fd] or null in case of error. -

-
-
sleep(delay_ms)
-
-

Sleep during delay_ms milliseconds.

-
-
setTimeout(func, delay)
-
-

- Call the function func after delay ms. - Return a handle to the timer. -

-
-
clearTimeout(handle)
-

Cancel a timer.

-
platform
-
-

- Return a string representing the platform: - "linux", "darwin", - "win32" or "js". -

-
-
Worker(module_filename)
-
-

- Constructor to create a new thread (worker) with an API close to the - WebWorkers. module_filename is a string - specifying the module filename which is executed in the newly created - thread. As for dynamically imported module, it is relative to the - current script or module path. Threads normally don’t share any - data and communicate between each other with messages. Nested workers - are not supported. An example is available in - tests/test_worker.js. -

-

The worker class has the following static properties:

-
-
parent
-
-

- In the created worker, Worker.parent represents the - parent worker and is used to send or receive messages. -

-
-
- -

The worker instances have the following properties:

-
-
postMessage(msg)
-
-

- Send a message to the corresponding worker. msg is - cloned in the destination worker using an algorithm similar to the - HTML structured clone algorithm. - SharedArrayBuffer are shared between workers. -

-

- Current limitations: Map and Set are not - supported yet. -

-
-
onmessage
-
-

- Getter and setter. Set a function which is called each time a - message is received. The function is called with a single - argument. It is an object with a data property - containing the received message. The thread is not terminated if - there is at least one non null - onmessage handler. -

-
-
-
-
- - -

3.4 QuickJS C API

- -

- The C API was designed to be simple and efficient. The C API is defined in - the header quickjs.h. -

- -

3.4.1 Runtime and contexts

- -

- JSRuntime represents a Javascript runtime corresponding to an - object heap. Several runtimes can exist at the same time but they cannot - exchange objects. Inside a given runtime, no multi-threading is supported. -

-

- JSContext represents a Javascript context (or Realm). Each - JSContext has its own global objects and system objects. There can be - several JSContexts per JSRuntime and they can share objects, similar to - frames of the same origin sharing Javascript objects in a web browser. -

- -

3.4.2 JSValue

- -

- JSValue represents a Javascript value which can be a - primitive type or an object. Reference counting is used, so it is - important to explicitly duplicate (JS_DupValue(), increment - the reference count) or free (JS_FreeValue(), decrement the - reference count) JSValues. -

- -

3.4.3 C functions

- -

- C functions can be created with JS_NewCFunction(). - JS_SetPropertyFunctionList() is a shortcut to easily add - functions, setters and getters properties to a given object. -

-

- Unlike other embedded Javascript engines, there is no implicit stack, so C - functions get their parameters as normal C parameters. As a general rule, - C functions take constant JSValues as parameters (so they - don’t need to free them) and return a newly allocated (=live) - JSValue. -

- -

3.4.4 Exceptions

- -

- Exceptions: most C functions can return a Javascript exception. It must be - explicitly tested and handled by the C code. The specific - JSValue JS_EXCEPTION indicates that an exception - occurred. The actual exception object is stored in the - JSContext and can be retrieved with - JS_GetException(). -

- -

3.4.5 Script evaluation

- -

Use JS_Eval() to evaluate a script or module source.

-

- If the script or module was compiled to bytecode with qjsc, - it can be evaluated by calling js_std_eval_binary(). The - advantage is that no compilation is needed so it is faster and smaller - because the compiler can be removed from the executable if no - eval is required. -

-

- Note: the bytecode format is linked to a given QuickJS version. Moreover, - no security check is done before its execution. Hence the bytecode should - not be loaded from untrusted sources. That’s why there is no option - to output the bytecode to a binary file in qjsc. -

- -

3.4.6 JS Classes

- -

- C opaque data can be attached to a Javascript object. The type of the C - opaque data is determined with the class ID (JSClassID) of - the object. Hence the first step is to register a new class ID and JS - class (JS_NewClassID(), JS_NewClass()). Then you - can create objects of this class with JS_NewObjectClass() and - get or set the C opaque point with - JS_GetOpaque()/JS_SetOpaque(). -

-

- When defining a new JS class, it is possible to declare a finalizer which - is called when the object is destroyed. The finalizer should be used to - release C resources. It is invalid to execute JS code from it. A - gc_mark method can be provided so that the cycle removal - algorithm can find the other objects referenced by this object. Other - methods are available to define exotic object behaviors. -

-

- The Class ID are globally allocated (i.e. for all runtimes). The JSClass - are allocated per JSRuntime. - JS_SetClassProto() is used to define a prototype for a given - class in a given JSContext. JS_NewObjectClass() sets this - prototype in the created object. -

-

Examples are available in quickjs-libc.c.

- -

3.4.7 C Modules

- -

- Native ES6 modules are supported and can be dynamically or statically - linked. Look at the test_bjson and - bjson.so examples. The standard library - quickjs-libc.c is also a good example of a native module. -

- -

3.4.8 Memory handling

- -

- Use JS_SetMemoryLimit() to set a global memory allocation - limit to a given JSRuntime. -

-

- Custom memory allocation functions can be provided with - JS_NewRuntime2(). -

-

- The maximum system stack size can be set with - JS_SetMaxStackSize(). -

- -

3.4.9 Execution timeout and interrupts

- -

- Use JS_SetInterruptHandler() to set a callback which is - regularly called by the engine when it is executing code. This callback - can be used to implement an execution timeout. -

-

- It is used by the command line interpreter to implement a - Ctrl-C handler. -

- -

4 Internals

- - -

4.1 Bytecode

- -

- The compiler generates bytecode directly with no intermediate - representation such as a parse tree, hence it is very fast. Several - optimizations passes are done over the generated bytecode. -

-

- A stack-based bytecode was chosen because it is simple and generates - compact code. -

-

- For each function, the maximum stack size is computed at compile time so - that no runtime stack overflow tests are needed. -

-

- A separate compressed line number table is maintained for the debug - information. -

-

- Access to closure variables is optimized and is almost as fast as local - variables. -

-

Direct eval in strict mode is optimized.

- -

4.2 Executable generation

- - -

4.2.1 qjsc compiler

- -

- The qjsc compiler generates C sources from Javascript files. - By default the C sources are compiled with the system compiler (gcc - or clang). -

-

- The generated C source contains the bytecode of the compiled functions or - modules. If a full complete executable is needed, it also contains a - main() function with the necessary C code to initialize the - Javascript engine and to load and execute the compiled functions and - modules. -

-

Javascript code can be mixed with C modules.

-

- In order to have smaller executables, specific Javascript features can be - disabled, in particular eval or the regular expressions. The - code removal relies on the Link Time Optimization of the system compiler. -

- -

4.2.2 Binary JSON

- -

- qjsc works by compiling scripts or modules and then - serializing them to a binary format. A subset of this format (without - functions or modules) can be used as binary JSON. The example - test_bjson.js - shows how to use it. -

-

- Warning: the binary JSON format may change without notice, so it should - not be used to store persistent data. The test_bjson.js - example is only used to test the binary object format functions. -

- -

4.3 Runtime

- - -

4.3.1 Strings

- -

- Strings are stored either as an 8 bit or a 16 bit array of characters. - Hence random access to characters is always fast. -

-

- The C API provides functions to convert Javascript Strings to C UTF-8 - encoded strings. The most common case where the Javascript string contains - only ASCII characters involves no copying. -

- -

4.3.2 Objects

- -

- The object shapes (object prototype, property names and flags) are shared - between objects to save memory. -

-

Arrays with no holes (except at the end of the array) are optimized.

-

TypedArray accesses are optimized.

- -

4.3.3 Atoms

- -

- Object property names and some strings are stored as Atoms (unique - strings) to save memory and allow fast comparison. Atoms are represented - as a 32 bit integer. Half of the atom range is reserved for immediate - integer literals from 0 to 2^{31}-1. -

- -

4.3.4 Numbers

- -

- Numbers are represented either as 32-bit signed integers or 64-bit - IEEE-754 floating point values. Most operations have fast paths for the - 32-bit integer case. -

- -

4.3.5 Garbage collection

- -

- Reference counting is used to free objects automatically and - deterministically. A separate cycle removal pass is done when the - allocated memory becomes too large. The cycle removal algorithm only uses - the reference counts and the object content, so no explicit garbage - collection roots need to be manipulated in the C code. -

- -

4.3.6 JSValue

- -

- It is a Javascript value which can be a primitive type (such as Number, - String, ...) or an Object. NaN boxing is used in the 32-bit version to - store 64-bit floating point numbers. The representation is optimized so - that 32-bit integers and reference counted values can be efficiently - tested. -

-

- In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The - rationale is that in 64-bit code memory usage is less critical. -

-

- In both cases (32 or 64 bits), JSValue exactly fits two CPU registers, so - it can be efficiently returned by C functions. -

- -

4.3.7 Function call

- -

- The engine is optimized so that function calls are fast. The system stack - holds the Javascript parameters and local variables. -

- -

4.4 RegExp

- -

- A specific regular expression engine was developed. It is both small and - efficient and supports all the ES2020 features including the Unicode - properties. As the Javascript compiler, it directly generates bytecode - without a parse tree. -

-

- Backtracking with an explicit stack is used so that there is no recursion - on the system stack. Simple quantifiers are specifically optimized to - avoid recursions. -

-

- Infinite recursions coming from quantifiers with empty terms are avoided. -

-

- The full regexp library weights about 15 KiB (x86 code), excluding the - Unicode library. -

- -

4.5 Unicode

- -

- A specific Unicode library was developed so that there is no dependency on - an external large Unicode library such as ICU. All the Unicode tables are - compressed while keeping a reasonable access speed. -

-

- The library supports case conversion, Unicode normalization, Unicode - script queries, Unicode general category queries and all Unicode binary - properties. -

-

The full Unicode library weights about 45 KiB (x86 code).

- -

4.6 BigInt, BigFloat, BigDecimal

- -

- BigInt, BigFloat and BigDecimal are implemented with the - libbf library7. It weights about 90 KiB (x86 code) and provides arbitrary precision - IEEE 754 floating point operations and transcendental functions with exact - rounding. -

- -

5 License

- -

QuickJS is released under the MIT license.

-

- Unless otherwise specified, the QuickJS sources are copyright Fabrice - Bellard and Charlie Gordon. -

-
-
-

Footnotes

- -

(1)

-

https://tc39.es/ecma262/

-

(2)

-

- https://github.com/tc39/test262 -

-

(3)

-

- https://tc39.github.io/ecma262/ -

-

(4)

-

- The old ES5.1 tests can be extracted with - git clone --single-branch --branch es5-tests - https://github.com/tc39/test262.git test262o -

-

(5)

-

- https://github.com/bterlson/test262-harness -

-

(6)

-

- We believe the current specification of tails calls is too complicated - and presents limited practical interests. -

-

(7)

-

https://bellard.org/libbf

-
-
- - diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode-table.h b/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode-table.h deleted file mode 100644 index 0ef21135..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode-table.h +++ /dev/null @@ -1,4368 +0,0 @@ -/* Compressed unicode tables */ -/* Automatically generated file - do not edit */ - -#include - -static const uint32_t case_conv_table1[361] = { - 0x00209a30, 0x00309a00, 0x005a8173, 0x00601730, - 0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700, - 0x007f8100, 0x00803040, 0x009801c3, 0x00988190, - 0x00990640, 0x009c9040, 0x00a481b4, 0x00a52e40, - 0x00bc0130, 0x00bc8640, 0x00bf8170, 0x00c00100, - 0x00c08130, 0x00c10440, 0x00c30130, 0x00c38240, - 0x00c48230, 0x00c58240, 0x00c70130, 0x00c78130, - 0x00c80130, 0x00c88240, 0x00c98130, 0x00ca0130, - 0x00ca8100, 0x00cb0130, 0x00cb8130, 0x00cc0240, - 0x00cd0100, 0x00ce0130, 0x00ce8130, 0x00cf0100, - 0x00cf8130, 0x00d00640, 0x00d30130, 0x00d38240, - 0x00d48130, 0x00d60240, 0x00d70130, 0x00d78240, - 0x00d88230, 0x00d98440, 0x00db8130, 0x00dc0240, - 0x00de0240, 0x00df8100, 0x00e20350, 0x00e38350, - 0x00e50350, 0x00e69040, 0x00ee8100, 0x00ef1240, - 0x00f801b4, 0x00f88350, 0x00fa0240, 0x00fb0130, - 0x00fb8130, 0x00fc2840, 0x01100130, 0x01111240, - 0x011d0131, 0x011d8240, 0x011e8130, 0x011f0131, - 0x011f8201, 0x01208240, 0x01218130, 0x01220130, - 0x01228130, 0x01230a40, 0x01280101, 0x01288101, - 0x01290101, 0x01298100, 0x012a0100, 0x012b0200, - 0x012c8100, 0x012d8100, 0x012e0101, 0x01300100, - 0x01308101, 0x01318100, 0x01328101, 0x01330101, - 0x01340100, 0x01348100, 0x01350101, 0x01358101, - 0x01360101, 0x01378100, 0x01388101, 0x01390100, - 0x013a8100, 0x013e8101, 0x01400100, 0x01410101, - 0x01418100, 0x01438101, 0x01440100, 0x01448100, - 0x01450200, 0x01460100, 0x01490100, 0x014e8101, - 0x014f0101, 0x01a28173, 0x01b80440, 0x01bb0240, - 0x01bd8300, 0x01bf8130, 0x01c30130, 0x01c40330, - 0x01c60130, 0x01c70230, 0x01c801d0, 0x01c89130, - 0x01d18930, 0x01d60100, 0x01d68300, 0x01d801d3, - 0x01d89100, 0x01e10173, 0x01e18900, 0x01e60100, - 0x01e68200, 0x01e78130, 0x01e80173, 0x01e88173, - 0x01ea8173, 0x01eb0173, 0x01eb8100, 0x01ec1840, - 0x01f80173, 0x01f88173, 0x01f90100, 0x01f98100, - 0x01fa01a0, 0x01fa8173, 0x01fb8240, 0x01fc8130, - 0x01fd0240, 0x01fe8330, 0x02001030, 0x02082030, - 0x02182000, 0x02281000, 0x02302240, 0x02453640, - 0x02600130, 0x02608e40, 0x02678100, 0x02686040, - 0x0298a630, 0x02b0a600, 0x02c381b5, 0x08502631, - 0x08638131, 0x08668131, 0x08682b00, 0x087e8300, - 0x09d05011, 0x09f80610, 0x09fc0620, 0x0e400174, - 0x0e408174, 0x0e410174, 0x0e418174, 0x0e420174, - 0x0e428174, 0x0e430174, 0x0e438180, 0x0e440180, - 0x0e482b30, 0x0e5e8330, 0x0ebc8101, 0x0ebe8101, - 0x0ec70101, 0x0f007e40, 0x0f3f1840, 0x0f4b01b5, - 0x0f4b81b6, 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7, - 0x0f4d8180, 0x0f4f0130, 0x0f506040, 0x0f800800, - 0x0f840830, 0x0f880600, 0x0f8c0630, 0x0f900800, - 0x0f940830, 0x0f980800, 0x0f9c0830, 0x0fa00600, - 0x0fa40630, 0x0fa801b0, 0x0fa88100, 0x0fa901d3, - 0x0fa98100, 0x0faa01d3, 0x0faa8100, 0x0fab01d3, - 0x0fab8100, 0x0fac8130, 0x0fad8130, 0x0fae8130, - 0x0faf8130, 0x0fb00800, 0x0fb40830, 0x0fb80200, - 0x0fb90400, 0x0fbb0200, 0x0fbc0201, 0x0fbd0201, - 0x0fbe0201, 0x0fc008b7, 0x0fc40867, 0x0fc808b8, - 0x0fcc0868, 0x0fd008b8, 0x0fd40868, 0x0fd80200, - 0x0fd901b9, 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1, - 0x0fdb81d7, 0x0fdc0230, 0x0fdd0230, 0x0fde0161, - 0x0fdf0173, 0x0fe101b9, 0x0fe181b2, 0x0fe201ba, - 0x0fe301b2, 0x0fe381d8, 0x0fe40430, 0x0fe60162, - 0x0fe80200, 0x0fe901d0, 0x0fe981d0, 0x0feb01b0, - 0x0feb81d0, 0x0fec0230, 0x0fed0230, 0x0ff00201, - 0x0ff101d3, 0x0ff181d3, 0x0ff201ba, 0x0ff28101, - 0x0ff301b0, 0x0ff381d3, 0x0ff40230, 0x0ff50230, - 0x0ff60131, 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb, - 0x0ffb01b2, 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230, - 0x0ffe0162, 0x109301a0, 0x109501a0, 0x109581a0, - 0x10990131, 0x10a70101, 0x10b01031, 0x10b81001, - 0x10c18240, 0x125b1a31, 0x12681a01, 0x16002f31, - 0x16182f01, 0x16300240, 0x16310130, 0x16318130, - 0x16320130, 0x16328100, 0x16330100, 0x16338640, - 0x16368130, 0x16370130, 0x16378130, 0x16380130, - 0x16390240, 0x163a8240, 0x163f0230, 0x16406440, - 0x16758440, 0x16790240, 0x16802600, 0x16938100, - 0x16968100, 0x53202e40, 0x53401c40, 0x53910e40, - 0x53993e40, 0x53bc8440, 0x53be8130, 0x53bf0a40, - 0x53c58240, 0x53c68130, 0x53c80440, 0x53ca0101, - 0x53cb1440, 0x53d50130, 0x53d58130, 0x53d60130, - 0x53d68130, 0x53d70130, 0x53d80130, 0x53d88130, - 0x53d90130, 0x53d98131, 0x53da0c40, 0x53e10240, - 0x53e20131, 0x53e28130, 0x53e30130, 0x53e38440, - 0x53fa8240, 0x55a98101, 0x55b85020, 0x7d8001b2, - 0x7d8081b2, 0x7d8101b2, 0x7d8181da, 0x7d8201da, - 0x7d8281b3, 0x7d8301b3, 0x7d8981bb, 0x7d8a01bb, - 0x7d8a81bb, 0x7d8b01bc, 0x7d8b81bb, 0x7f909a31, - 0x7fa09a01, 0x82002831, 0x82142801, 0x82582431, - 0x826c2401, 0x86403331, 0x86603301, 0x8c502031, - 0x8c602001, 0xb7202031, 0xb7302001, 0xf4802231, - 0xf4912201, -}; - -static const uint8_t case_conv_table2[361] = { - 0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04, - 0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00, - 0x08, 0x00, 0x53, 0x4a, 0x51, 0x00, 0x52, 0x00, - 0x53, 0x00, 0x3a, 0x54, 0x55, 0x00, 0x57, 0x59, - 0x3f, 0x5d, 0x5c, 0x00, 0x46, 0x61, 0x63, 0x42, - 0x64, 0x00, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, - 0x6c, 0x00, 0x6e, 0x00, 0x00, 0x40, 0x00, 0x00, - 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00, 0x20, - 0x35, 0x00, 0x27, 0x00, 0x21, 0x00, 0x24, 0x22, - 0x2a, 0x00, 0x13, 0x6b, 0x6d, 0x00, 0x26, 0x24, - 0x27, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x3e, 0x1e, - 0x3f, 0x1f, 0x39, 0x3d, 0x22, 0x21, 0x41, 0x1e, - 0x40, 0x25, 0x25, 0x26, 0x28, 0x20, 0x2a, 0x49, - 0x2c, 0x43, 0x2e, 0x4b, 0x30, 0x4c, 0x32, 0x44, - 0x42, 0x99, 0x00, 0x00, 0x95, 0x8f, 0x7d, 0x7e, - 0x83, 0x84, 0x12, 0x80, 0x82, 0x76, 0x77, 0x12, - 0x7b, 0xa3, 0x7c, 0x78, 0x79, 0x8a, 0x92, 0x98, - 0xa6, 0xa0, 0x85, 0x00, 0x9a, 0xa1, 0x93, 0x75, - 0x33, 0x95, 0x00, 0x8e, 0x00, 0x74, 0x99, 0x98, - 0x97, 0x96, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, - 0xa1, 0xa0, 0x15, 0x2e, 0x2f, 0x30, 0xb4, 0xb5, - 0x4e, 0xaa, 0xa9, 0x12, 0x14, 0x1e, 0x21, 0x22, - 0x22, 0x2a, 0x34, 0x35, 0xa6, 0xa7, 0x36, 0x1f, - 0x4a, 0x00, 0x00, 0x97, 0x01, 0x5a, 0xda, 0x1d, - 0x36, 0x05, 0x00, 0xc4, 0xc3, 0xc6, 0xc5, 0xc8, - 0xc7, 0xca, 0xc9, 0xcc, 0xcb, 0xc4, 0xd5, 0x45, - 0xd6, 0x42, 0xd7, 0x46, 0xd8, 0xce, 0xd0, 0xd2, - 0xd4, 0xda, 0xd9, 0xee, 0xf6, 0xfe, 0x0e, 0x07, - 0x0f, 0x80, 0x9f, 0x00, 0x21, 0x80, 0xa3, 0xed, - 0x00, 0xc0, 0x40, 0xc6, 0x60, 0xe7, 0xdb, 0xe6, - 0x99, 0xc0, 0x00, 0x00, 0x06, 0x60, 0xdc, 0x29, - 0xfd, 0x15, 0x12, 0x06, 0x16, 0xf8, 0xdd, 0x06, - 0x15, 0x12, 0x84, 0x08, 0xc6, 0x16, 0xff, 0xdf, - 0x03, 0xc0, 0x40, 0x00, 0x46, 0x60, 0xde, 0xe0, - 0x6d, 0x37, 0x38, 0x39, 0x15, 0x14, 0x17, 0x16, - 0x00, 0x1a, 0x19, 0x1c, 0x1b, 0x00, 0x5f, 0xb7, - 0x65, 0x44, 0x47, 0x00, 0x4f, 0x62, 0x4e, 0x50, - 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0xa4, - 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, - 0x00, 0x5a, 0x00, 0x48, 0x00, 0x5b, 0x56, 0x58, - 0x60, 0x5e, 0x70, 0x69, 0x6f, 0x4d, 0x00, 0x00, - 0x3b, 0x67, 0xb8, 0x00, 0x00, 0x45, 0xa8, 0x8a, - 0x8b, 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, 0x94, - 0xb0, 0x6f, 0xb2, 0x5c, 0x5b, 0x5e, 0x5d, 0x60, - 0x5f, 0x62, 0x61, 0x64, 0x63, 0x66, 0x65, 0x68, - 0x67, -}; - -static const uint16_t case_conv_ext[58] = { - 0x0399, 0x0308, 0x0301, 0x03a5, 0x0313, 0x0300, 0x0342, 0x0391, - 0x0397, 0x03a9, 0x0046, 0x0049, 0x004c, 0x0053, 0x0069, 0x0307, - 0x02bc, 0x004e, 0x004a, 0x030c, 0x0535, 0x0552, 0x0048, 0x0331, - 0x0054, 0x0057, 0x030a, 0x0059, 0x0041, 0x02be, 0x1f08, 0x1f80, - 0x1f28, 0x1f90, 0x1f68, 0x1fa0, 0x1fba, 0x0386, 0x1fb3, 0x1fca, - 0x0389, 0x1fc3, 0x03a1, 0x1ffa, 0x038f, 0x1ff3, 0x0544, 0x0546, - 0x053b, 0x054e, 0x053d, 0x03b8, 0x0462, 0xa64a, 0x1e60, 0x03c9, - 0x006b, 0x00e5, -}; - -static const uint8_t unicode_prop_Cased1_table[172] = { - 0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3, - 0x80, 0x8c, 0x80, 0x8d, 0x81, 0x8d, 0x02, 0x80, - 0xe1, 0x80, 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, - 0x11, 0x00, 0x01, 0x04, 0x08, 0x01, 0x08, 0x30, - 0x08, 0x01, 0x15, 0x20, 0x00, 0x39, 0x99, 0x31, - 0x9d, 0x84, 0x40, 0x94, 0x80, 0xd6, 0x82, 0xa6, - 0x80, 0x41, 0x62, 0x80, 0xa6, 0x80, 0x57, 0x76, - 0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb, - 0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f, - 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28, - 0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b, - 0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79, - 0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94, - 0x05, 0x80, 0x98, 0x80, 0xc7, 0x82, 0x43, 0x34, - 0xa2, 0x06, 0x80, 0x8c, 0x61, 0x28, 0x96, 0xd4, - 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, - 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, - 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, - 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, - 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, - 0x80, 0x9e, 0x80, 0x98, 0x07, 0x59, 0x63, 0x99, - 0x85, 0x99, 0x85, 0x99, -}; - -static const uint8_t unicode_prop_Cased1_index[18] = { - 0xb9, 0x02, 0xe0, 0xa0, 0x1e, 0x40, 0x9e, 0xa6, - 0x40, 0xba, 0xd4, 0x01, 0x89, 0xd7, 0x01, 0x8a, - 0xf1, 0x01, -}; - -static const uint8_t unicode_prop_Case_Ignorable_table[692] = { - 0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80, - 0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6, - 0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40, - 0xfa, 0x86, 0x40, 0xce, 0x04, 0x80, 0xb0, 0xac, - 0x00, 0x01, 0x01, 0x00, 0xab, 0x80, 0x8a, 0x85, - 0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f, - 0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80, - 0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08, - 0x97, 0x97, 0xaa, 0x82, 0xf6, 0xaf, 0xb6, 0x00, - 0x03, 0x3b, 0x02, 0x86, 0x89, 0x81, 0x8c, 0x80, - 0x8e, 0x80, 0xb9, 0x03, 0x1f, 0x80, 0x93, 0x81, - 0x99, 0x01, 0x81, 0xb8, 0x03, 0x0b, 0x09, 0x12, - 0x80, 0x9d, 0x0a, 0x80, 0x8a, 0x81, 0xb8, 0x03, - 0x20, 0x0b, 0x80, 0x93, 0x81, 0x95, 0x28, 0x80, - 0xb9, 0x01, 0x00, 0x1f, 0x06, 0x81, 0x8a, 0x81, - 0x9d, 0x80, 0xbc, 0x80, 0x8b, 0x80, 0xb1, 0x02, - 0x80, 0xb8, 0x14, 0x10, 0x1e, 0x81, 0x8a, 0x81, - 0x9c, 0x80, 0xb9, 0x01, 0x05, 0x04, 0x81, 0x93, - 0x81, 0x9b, 0x81, 0xb8, 0x0b, 0x1f, 0x80, 0x93, - 0x81, 0x9c, 0x80, 0xc7, 0x06, 0x10, 0x80, 0xd9, - 0x01, 0x86, 0x8a, 0x88, 0xe1, 0x01, 0x88, 0x88, - 0x00, 0x85, 0xc9, 0x81, 0x9a, 0x00, 0x00, 0x80, - 0xb6, 0x8d, 0x04, 0x01, 0x84, 0x8a, 0x80, 0xa3, - 0x88, 0x80, 0xe5, 0x18, 0x28, 0x09, 0x81, 0x98, - 0x0b, 0x82, 0x8f, 0x83, 0x8c, 0x01, 0x0d, 0x80, - 0x8e, 0x80, 0xdd, 0x80, 0x42, 0x5f, 0x82, 0x43, - 0xb1, 0x82, 0x9c, 0x82, 0x9c, 0x81, 0x9d, 0x81, - 0xbf, 0x08, 0x37, 0x01, 0x8a, 0x10, 0x20, 0xac, - 0x83, 0xb3, 0x80, 0xc0, 0x81, 0xa1, 0x80, 0xf5, - 0x13, 0x81, 0x88, 0x05, 0x82, 0x40, 0xda, 0x09, - 0x80, 0xb9, 0x00, 0x30, 0x00, 0x01, 0x3d, 0x89, - 0x08, 0xa6, 0x07, 0x90, 0xbe, 0x83, 0xaf, 0x00, - 0x20, 0x04, 0x80, 0xa7, 0x88, 0x8b, 0x81, 0x9f, - 0x19, 0x08, 0x82, 0xb7, 0x00, 0x0a, 0x00, 0x82, - 0xb9, 0x39, 0x81, 0xbf, 0x85, 0xd1, 0x10, 0x8c, - 0x06, 0x18, 0x28, 0x11, 0xb1, 0xbe, 0x8c, 0x80, - 0xa1, 0xde, 0x04, 0x41, 0xbc, 0x00, 0x82, 0x8a, - 0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c, 0x81, 0x8b, - 0x27, 0x81, 0x89, 0x01, 0x01, 0x84, 0xb0, 0x20, - 0x89, 0x00, 0x8c, 0x80, 0x8f, 0x8c, 0xb2, 0xa0, - 0x4b, 0x8a, 0x81, 0xf0, 0x82, 0xfc, 0x80, 0x8e, - 0x80, 0xdf, 0x9f, 0xae, 0x80, 0x41, 0xd4, 0x80, - 0xa3, 0x1a, 0x24, 0x80, 0xdc, 0x85, 0xdc, 0x82, - 0x60, 0x6f, 0x15, 0x80, 0x44, 0xe1, 0x85, 0x41, - 0x0d, 0x80, 0xe1, 0x18, 0x89, 0x00, 0x9b, 0x83, - 0xcf, 0x81, 0x8d, 0xa1, 0xcd, 0x80, 0x96, 0x82, - 0xec, 0x0f, 0x02, 0x03, 0x80, 0x98, 0x0c, 0x80, - 0x40, 0x96, 0x81, 0x99, 0x91, 0x8c, 0x80, 0xa5, - 0x87, 0x98, 0x8a, 0xad, 0x82, 0xaf, 0x01, 0x19, - 0x81, 0x90, 0x80, 0x94, 0x81, 0xc1, 0x29, 0x09, - 0x81, 0x8b, 0x07, 0x80, 0xa2, 0x80, 0x8a, 0x80, - 0xb2, 0x00, 0x11, 0x0c, 0x08, 0x80, 0x9a, 0x80, - 0x8d, 0x0c, 0x08, 0x80, 0xe3, 0x84, 0x88, 0x82, - 0xf8, 0x01, 0x03, 0x80, 0x60, 0x4f, 0x2f, 0x80, - 0x40, 0x92, 0x8f, 0x42, 0x3d, 0x8f, 0x10, 0x8b, - 0x8f, 0xa1, 0x01, 0x80, 0x40, 0xa8, 0x06, 0x05, - 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80, 0xae, 0x80, - 0xac, 0x81, 0xc2, 0x80, 0x94, 0x82, 0x42, 0x00, - 0x80, 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x46, - 0x85, 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80, 0x40, - 0xa4, 0x81, 0x42, 0x3c, 0x83, 0x41, 0x82, 0x81, - 0x40, 0x98, 0x8a, 0x40, 0xaf, 0x80, 0xb5, 0x8e, - 0xb7, 0x82, 0xb0, 0x19, 0x09, 0x80, 0x8e, 0x80, - 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b, - 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, 0x11, - 0x00, 0x0d, 0x80, 0x40, 0x9f, 0x02, 0x87, 0x94, - 0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0x40, - 0xc2, 0x39, 0x10, 0x80, 0x96, 0x80, 0xd3, 0x28, - 0x03, 0x08, 0x81, 0x40, 0xed, 0x1d, 0x08, 0x81, - 0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81, 0xe9, 0x00, - 0x01, 0x28, 0x80, 0xe4, 0x11, 0x18, 0x84, 0x41, - 0x02, 0x88, 0x01, 0x40, 0xff, 0x08, 0x03, 0x80, - 0x40, 0x8f, 0x19, 0x0b, 0x80, 0x9f, 0x89, 0xa7, - 0x29, 0x1f, 0x80, 0x88, 0x29, 0x82, 0xad, 0x8c, - 0x01, 0x41, 0x95, 0x30, 0x28, 0x80, 0xd1, 0x95, - 0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30, - 0x80, 0xc7, 0x0a, 0x00, 0x80, 0x41, 0x5a, 0x81, - 0x55, 0x3a, 0x88, 0x60, 0x36, 0xb6, 0x84, 0xba, - 0x86, 0x88, 0x83, 0x44, 0x0a, 0x80, 0xbe, 0x90, - 0xbf, 0x08, 0x81, 0x60, 0x4c, 0xb7, 0x08, 0x83, - 0x54, 0xc2, 0x82, 0x88, 0x8f, 0x0e, 0x9d, 0x83, - 0x40, 0x93, 0x82, 0x47, 0xba, 0xb6, 0x83, 0xb1, - 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45, 0x4f, - 0x30, 0x90, 0x0e, 0x01, 0x04, 0x41, 0x04, 0x8d, - 0x41, 0xad, 0x83, 0x45, 0xdf, 0x86, 0xec, 0x87, - 0x4a, 0xae, 0x84, 0x6c, 0x0c, 0x00, 0x80, 0x9d, - 0xdf, 0xff, 0x40, 0xef, -}; - -static const uint8_t unicode_prop_Case_Ignorable_index[66] = { - 0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a, - 0x20, 0x05, 0x0c, 0x20, 0x3b, 0x0e, 0x40, 0x61, - 0x10, 0x40, 0x0f, 0x18, 0x20, 0x43, 0x1b, 0x60, - 0x79, 0x1d, 0x00, 0xf1, 0x20, 0x00, 0x0d, 0xa6, - 0x40, 0x2e, 0xa9, 0x20, 0xde, 0xaa, 0x00, 0x0f, - 0xff, 0x20, 0xe7, 0x0a, 0x41, 0x82, 0x11, 0x21, - 0xc4, 0x14, 0x61, 0x44, 0x19, 0x01, 0x48, 0x1d, - 0x21, 0xa4, 0xbc, 0x01, 0x3e, 0xe1, 0x01, 0xf0, - 0x01, 0x0e, -}; - -static const uint8_t unicode_prop_ID_Start_table[1045] = { - 0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03, - 0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83, - 0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20, - 0x09, 0x18, 0x05, 0x00, 0x10, 0x00, 0x93, 0x80, - 0xd2, 0x80, 0x40, 0x8a, 0x87, 0x40, 0xa5, 0x80, - 0xa5, 0x08, 0x85, 0xa8, 0xc6, 0x9a, 0x1b, 0xac, - 0xaa, 0xa2, 0x08, 0xe2, 0x00, 0x8e, 0x0e, 0x81, - 0x89, 0x11, 0x80, 0x8f, 0x00, 0x9d, 0x9c, 0xd8, - 0x8a, 0x80, 0x97, 0xa0, 0x88, 0x0b, 0x04, 0x95, - 0x18, 0x88, 0x02, 0x80, 0x96, 0x98, 0x86, 0x8a, - 0xb4, 0x94, 0x80, 0x91, 0xbb, 0xb5, 0x10, 0x91, - 0x06, 0x89, 0x8e, 0x8f, 0x1f, 0x09, 0x81, 0x95, - 0x06, 0x00, 0x13, 0x10, 0x8f, 0x80, 0x8c, 0x08, - 0x82, 0x8d, 0x81, 0x89, 0x07, 0x2b, 0x09, 0x95, - 0x06, 0x01, 0x01, 0x01, 0x9e, 0x18, 0x80, 0x92, - 0x82, 0x8f, 0x88, 0x02, 0x80, 0x95, 0x06, 0x01, - 0x04, 0x10, 0x91, 0x80, 0x8e, 0x81, 0x96, 0x80, - 0x8a, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, 0x10, - 0x9d, 0x08, 0x82, 0x8e, 0x80, 0x90, 0x00, 0x2a, - 0x10, 0x1a, 0x08, 0x00, 0x0a, 0x0a, 0x12, 0x8b, - 0x95, 0x80, 0xb3, 0x38, 0x10, 0x96, 0x80, 0x8f, - 0x10, 0x99, 0x14, 0x81, 0x9d, 0x03, 0x38, 0x10, - 0x96, 0x80, 0x89, 0x04, 0x10, 0x9f, 0x00, 0x81, - 0x8e, 0x81, 0x90, 0x88, 0x02, 0x80, 0xa8, 0x08, - 0x8f, 0x04, 0x17, 0x82, 0x97, 0x2c, 0x91, 0x82, - 0x97, 0x80, 0x88, 0x00, 0x0e, 0xb9, 0xaf, 0x01, - 0x8b, 0x86, 0xb9, 0x08, 0x00, 0x20, 0x97, 0x00, - 0x80, 0x89, 0x01, 0x88, 0x01, 0x20, 0x80, 0x94, - 0x83, 0x9f, 0x80, 0xbe, 0x38, 0xa3, 0x9a, 0x84, - 0xf2, 0xaa, 0x93, 0x80, 0x8f, 0x2b, 0x1a, 0x02, - 0x0e, 0x13, 0x8c, 0x8b, 0x80, 0x90, 0xa5, 0x00, - 0x20, 0x81, 0xaa, 0x80, 0x41, 0x4c, 0x03, 0x0e, - 0x00, 0x03, 0x81, 0xa8, 0x03, 0x81, 0xa0, 0x03, - 0x0e, 0x00, 0x03, 0x81, 0x8e, 0x80, 0xb8, 0x03, - 0x81, 0xc2, 0xa4, 0x8f, 0x8f, 0xd5, 0x0d, 0x82, - 0x42, 0x6b, 0x81, 0x90, 0x80, 0x99, 0x84, 0xca, - 0x82, 0x8a, 0x86, 0x8c, 0x03, 0x8d, 0x91, 0x8d, - 0x91, 0x8d, 0x8c, 0x02, 0x8e, 0xb3, 0xa2, 0x03, - 0x80, 0xc2, 0xd8, 0x86, 0xa8, 0x00, 0x84, 0xc5, - 0x89, 0x9e, 0xb0, 0x9d, 0x0c, 0x8a, 0xab, 0x83, - 0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80, 0xdc, - 0xae, 0x90, 0x86, 0xb6, 0x9d, 0x8c, 0x81, 0x89, - 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3, 0x81, - 0x88, 0x86, 0xaa, 0x0a, 0xa8, 0x18, 0x28, 0x0a, - 0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d, 0x81, - 0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80, 0x9e, - 0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13, 0x0d, - 0x83, 0x8c, 0x22, 0x06, 0xf3, 0x80, 0x8c, 0x80, - 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x0d, - 0x28, 0x00, 0x00, 0x80, 0x8f, 0x0b, 0x24, 0x18, - 0x90, 0xa8, 0x4a, 0x76, 0xae, 0x80, 0xae, 0x80, - 0x40, 0x84, 0x2b, 0x11, 0x8b, 0xa5, 0x00, 0x20, - 0x81, 0xb7, 0x30, 0x8f, 0x96, 0x88, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x86, 0x42, 0x25, - 0x82, 0x98, 0x88, 0x34, 0x0c, 0x83, 0xd5, 0x1c, - 0x80, 0xd9, 0x03, 0x84, 0xaa, 0x80, 0xdd, 0x90, - 0x9f, 0xaf, 0x8f, 0x41, 0xff, 0x59, 0xbf, 0xbf, - 0x60, 0x51, 0xfc, 0x82, 0x44, 0x8c, 0xc2, 0xad, - 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89, 0x81, 0x93, - 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6, 0x88, 0x81, - 0xe6, 0x81, 0xb4, 0x81, 0x88, 0xa9, 0x8c, 0x02, - 0x03, 0x80, 0x96, 0x9c, 0xb3, 0x8d, 0xb1, 0xbd, - 0x2a, 0x00, 0x81, 0x8a, 0x9b, 0x89, 0x96, 0x98, - 0x9c, 0x86, 0xae, 0x9b, 0x80, 0x8f, 0x20, 0x89, - 0x89, 0x20, 0xa8, 0x96, 0x10, 0x87, 0x93, 0x96, - 0x10, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08, 0x00, - 0x97, 0x11, 0x8a, 0x32, 0x8b, 0x29, 0x29, 0x85, - 0x88, 0x30, 0x30, 0xaa, 0x80, 0x8d, 0x85, 0xf2, - 0x9c, 0x60, 0x2b, 0xa3, 0x8b, 0x96, 0x83, 0xb0, - 0x60, 0x21, 0x03, 0x41, 0x6d, 0x81, 0xe9, 0xa5, - 0x86, 0x8b, 0x24, 0x00, 0x89, 0x80, 0x8c, 0x04, - 0x00, 0x01, 0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a, - 0x91, 0xbf, 0x81, 0xb5, 0xa7, 0x8b, 0xf3, 0x20, - 0x40, 0x86, 0xa3, 0x99, 0x85, 0x99, 0x8a, 0xd8, - 0x15, 0x0d, 0x0d, 0x0a, 0xa2, 0x8b, 0x80, 0x99, - 0x80, 0x92, 0x01, 0x80, 0x8e, 0x81, 0x8d, 0xa1, - 0xfa, 0xc4, 0xb4, 0x41, 0x0a, 0x9c, 0x82, 0xb0, - 0xae, 0x9f, 0x8c, 0x9d, 0x84, 0xa5, 0x89, 0x9d, - 0x81, 0xa3, 0x1f, 0x04, 0xa9, 0x40, 0x9d, 0x91, - 0xa3, 0x83, 0xa3, 0x83, 0xa7, 0x87, 0xb3, 0x40, - 0x9b, 0x41, 0x36, 0x88, 0x95, 0x89, 0x87, 0x40, - 0x97, 0x29, 0x00, 0xab, 0x01, 0x10, 0x81, 0x96, - 0x89, 0x96, 0x88, 0x9e, 0xc0, 0x92, 0x01, 0x89, - 0x95, 0x89, 0x99, 0xc5, 0xb7, 0x29, 0xbf, 0x80, - 0x8e, 0x18, 0x10, 0x9c, 0xa9, 0x9c, 0x82, 0x9c, - 0xa2, 0x38, 0x9b, 0x9a, 0xb5, 0x89, 0x95, 0x89, - 0x92, 0x8c, 0x91, 0xed, 0xc8, 0xb6, 0xb2, 0x8c, - 0xb2, 0x8c, 0xa3, 0x41, 0x5b, 0xa9, 0x29, 0xcd, - 0x9c, 0x89, 0x07, 0x95, 0xe9, 0x94, 0x9a, 0x96, - 0x8b, 0xb4, 0xca, 0xac, 0x9f, 0x98, 0x99, 0xa3, - 0x9c, 0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, - 0x83, 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, - 0xd3, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, 0x86, - 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, - 0x10, 0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d, 0xb4, - 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93, 0x08, - 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3, 0xaf, - 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6, 0x9a, - 0x40, 0xe4, 0xab, 0xf3, 0xbf, 0x9e, 0x39, 0x01, - 0x38, 0x08, 0x97, 0x8e, 0x00, 0x80, 0xdd, 0x39, - 0xa6, 0x8f, 0x00, 0x80, 0x9b, 0x80, 0x89, 0xa7, - 0x30, 0x94, 0x80, 0x8a, 0xad, 0x92, 0x80, 0xa1, - 0xb8, 0x41, 0x06, 0x88, 0x80, 0xa4, 0x90, 0x80, - 0xb0, 0x9d, 0xef, 0x30, 0x08, 0xa5, 0x94, 0x80, - 0x98, 0x28, 0x08, 0x9f, 0x8d, 0x80, 0x41, 0x46, - 0x92, 0x40, 0xbc, 0x80, 0xce, 0x43, 0x99, 0xe5, - 0xee, 0x90, 0x40, 0xc3, 0x4a, 0xbb, 0x44, 0x2e, - 0x4f, 0xd0, 0x42, 0x46, 0x60, 0x21, 0xb8, 0x42, - 0x38, 0x86, 0x9e, 0xf0, 0x9d, 0x91, 0xaf, 0x8f, - 0x83, 0x9e, 0x94, 0x84, 0x92, 0x42, 0xaf, 0xbf, - 0xff, 0xca, 0x20, 0xc1, 0x8c, 0xbf, 0x08, 0x80, - 0x9b, 0x57, 0xf7, 0x87, 0x44, 0xd5, 0xa9, 0x88, - 0x60, 0x22, 0xf6, 0x41, 0x1e, 0xb0, 0x82, 0x90, - 0x1f, 0x41, 0x8b, 0x49, 0x03, 0xea, 0x84, 0x8c, - 0x82, 0x88, 0x86, 0x89, 0x57, 0x65, 0xd4, 0x80, - 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, - 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, - 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81, - 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, - 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, - 0x9e, 0x80, 0x98, 0x07, 0x49, 0x33, 0xac, 0x89, - 0x86, 0x8f, 0x80, 0x41, 0x70, 0xab, 0x45, 0x13, - 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44, 0xb3, 0x18, - 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, 0x03, 0x00, - 0x00, 0x28, 0x18, 0x00, 0x00, 0x02, 0x01, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, - 0x06, 0x03, 0x03, 0x00, 0x80, 0x89, 0x80, 0x90, - 0x22, 0x04, 0x80, 0x90, 0x51, 0x43, 0x60, 0xa6, - 0xdd, 0xa1, 0x50, 0x34, 0x8a, 0x40, 0xdd, 0x81, - 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x4c, 0x1e, 0x42, - 0x1d, 0x45, 0xe1, 0x53, 0x4a, -}; - -static const uint8_t unicode_prop_ID_Start_index[99] = { - 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09, - 0x00, 0xb4, 0x0a, 0x00, 0xba, 0x0b, 0x00, 0x3e, - 0x0d, 0x00, 0xe0, 0x0e, 0x20, 0x57, 0x12, 0x00, - 0xeb, 0x16, 0x00, 0xca, 0x19, 0x20, 0xc0, 0x1d, - 0x60, 0x80, 0x20, 0x00, 0x2e, 0x2d, 0x00, 0xc0, - 0x31, 0x20, 0x89, 0xa7, 0x20, 0xf0, 0xa9, 0x00, - 0xe3, 0xab, 0x00, 0x3e, 0xfd, 0x00, 0xfb, 0x00, - 0x21, 0x37, 0x07, 0x61, 0x01, 0x0a, 0x01, 0x1d, - 0x0f, 0x21, 0x2c, 0x12, 0x01, 0xc8, 0x14, 0x21, - 0xd1, 0x19, 0x21, 0x47, 0x1d, 0x01, 0x39, 0x6a, - 0x21, 0x09, 0x8d, 0x01, 0xbc, 0xd4, 0x01, 0xa9, - 0xd7, 0x21, 0x3a, 0xee, 0x01, 0xde, 0xa6, 0x22, - 0x4b, 0x13, 0x03, -}; - -static const uint8_t unicode_prop_ID_Continue1_table[626] = { - 0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47, - 0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08, - 0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, - 0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89, - 0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89, - 0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02, - 0x04, 0xaa, 0x82, 0xf6, 0x8e, 0x80, 0xa0, 0xb5, - 0x10, 0x91, 0x06, 0x89, 0x09, 0x89, 0x90, 0x82, - 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88, 0x80, 0x89, - 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7, 0x00, 0x23, - 0x09, 0x12, 0x80, 0x93, 0x8b, 0x10, 0x8a, 0x82, - 0xb7, 0x00, 0x38, 0x10, 0x82, 0x93, 0x09, 0x89, - 0x89, 0x28, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x16, - 0x82, 0x89, 0x09, 0x89, 0x91, 0x80, 0xba, 0x22, - 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89, 0x8f, 0x84, - 0xb8, 0x30, 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, - 0x90, 0x82, 0xb7, 0x00, 0x30, 0x10, 0x1e, 0x81, - 0x8a, 0x09, 0x89, 0x8f, 0x83, 0xb6, 0x08, 0x30, - 0x10, 0x83, 0x88, 0x80, 0x89, 0x09, 0x89, 0x90, - 0x82, 0xc5, 0x03, 0x28, 0x00, 0x3d, 0x89, 0x09, - 0xbc, 0x01, 0x86, 0x8b, 0x38, 0x89, 0xd6, 0x01, - 0x88, 0x8a, 0x29, 0x89, 0xbd, 0x0d, 0x89, 0x8a, - 0x00, 0x00, 0x03, 0x81, 0xb0, 0x93, 0x01, 0x84, - 0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe3, 0x93, 0x80, - 0x89, 0x8b, 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c, - 0x8b, 0x80, 0x8e, 0x42, 0xbe, 0x82, 0x88, 0x88, - 0x43, 0x9f, 0x82, 0x9c, 0x82, 0x9c, 0x81, 0x9d, - 0x81, 0xbf, 0x9f, 0x88, 0x01, 0x89, 0xa0, 0x11, - 0x89, 0x40, 0x8e, 0x80, 0xf5, 0x8b, 0x83, 0x8b, - 0x89, 0x89, 0xff, 0x8a, 0xbb, 0x84, 0xb8, 0x89, - 0x80, 0x9c, 0x81, 0x8a, 0x85, 0x89, 0x95, 0x8d, - 0x01, 0xbe, 0x84, 0xae, 0x90, 0x8a, 0x89, 0x90, - 0x88, 0x8b, 0x82, 0x9d, 0x8c, 0x81, 0x89, 0xab, - 0x8d, 0xaf, 0x93, 0x87, 0x89, 0x85, 0x89, 0xf5, - 0x10, 0x94, 0x18, 0x28, 0x0a, 0x40, 0xc5, 0xb9, - 0x04, 0x42, 0x3e, 0x81, 0x92, 0x80, 0xfa, 0x8c, - 0x18, 0x82, 0x8b, 0x4b, 0xfd, 0x82, 0x40, 0x8c, - 0x80, 0xdf, 0x9f, 0x42, 0x29, 0x85, 0xe8, 0x81, - 0x60, 0x75, 0x84, 0x89, 0xc4, 0x03, 0x89, 0x9f, - 0x81, 0xcf, 0x81, 0x41, 0x0f, 0x02, 0x03, 0x80, - 0x96, 0x23, 0x80, 0xd2, 0x81, 0xb1, 0x91, 0x89, - 0x89, 0x85, 0x91, 0x8c, 0x8a, 0x9b, 0x87, 0x98, - 0x8c, 0xab, 0x83, 0xae, 0x8d, 0x8e, 0x89, 0x8a, - 0x80, 0x89, 0x89, 0xae, 0x8d, 0x8b, 0x07, 0x09, - 0x89, 0xa0, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08, - 0x80, 0xa8, 0x24, 0x81, 0x40, 0xeb, 0x38, 0x09, - 0x89, 0x60, 0x4f, 0x23, 0x80, 0x42, 0xe0, 0x8f, - 0x8f, 0x8f, 0x11, 0x97, 0x82, 0x40, 0xbf, 0x89, - 0xa4, 0x80, 0x42, 0xbc, 0x80, 0x40, 0xe1, 0x80, - 0x40, 0x94, 0x84, 0x41, 0x24, 0x89, 0x45, 0x56, - 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80, 0x40, 0xa4, - 0x81, 0x42, 0x3c, 0x1f, 0x89, 0x41, 0x70, 0x81, - 0x40, 0x98, 0x8a, 0x40, 0xae, 0x82, 0xb4, 0x8e, - 0x9e, 0x89, 0x8e, 0x83, 0xac, 0x8a, 0xb4, 0x89, - 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80, - 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1, - 0x8b, 0x28, 0x40, 0x9f, 0x8b, 0x84, 0x89, 0x2b, - 0xb6, 0x08, 0x31, 0x09, 0x82, 0x88, 0x80, 0x89, - 0x09, 0x32, 0x84, 0x40, 0xbf, 0x91, 0x88, 0x89, - 0x18, 0xd0, 0x93, 0x8b, 0x89, 0x40, 0xd4, 0x31, - 0x88, 0x9a, 0x81, 0xd1, 0x90, 0x8e, 0x89, 0xd0, - 0x8c, 0x87, 0x89, 0xd2, 0x8e, 0x83, 0x89, 0x40, - 0xf1, 0x8e, 0x40, 0xa4, 0x89, 0xc5, 0x28, 0x09, - 0x18, 0x00, 0x81, 0x8b, 0x89, 0xf6, 0x31, 0x32, - 0x80, 0x9b, 0x89, 0xa7, 0x30, 0x1f, 0x80, 0x88, - 0x8a, 0xad, 0x8f, 0x41, 0x94, 0x38, 0x87, 0x8f, - 0x89, 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, - 0x08, 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, 0x27, - 0x89, 0x41, 0x48, 0x83, 0x60, 0x4b, 0x68, 0x89, - 0x40, 0x85, 0x84, 0xba, 0x86, 0x98, 0x89, 0x43, - 0xf4, 0x00, 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81, - 0x60, 0x4c, 0xaa, 0x81, 0x54, 0xc5, 0x22, 0x2f, - 0x39, 0x86, 0x9d, 0x83, 0x40, 0x93, 0x82, 0x45, - 0x88, 0xb1, 0x41, 0xff, 0xb6, 0x83, 0xb1, 0x38, - 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45, 0x4f, 0x30, - 0x90, 0x0e, 0x01, 0x04, 0x41, 0x04, 0x86, 0x88, - 0x89, 0x41, 0xa1, 0x8d, 0x45, 0xd5, 0x86, 0xec, - 0x34, 0x89, 0x52, 0x95, 0x89, 0x6c, 0x05, 0x05, - 0x40, 0xef, -}; - -static const uint8_t unicode_prop_ID_Continue1_index[60] = { - 0xfa, 0x06, 0x00, 0x84, 0x09, 0x00, 0xf0, 0x0a, - 0x00, 0x70, 0x0c, 0x00, 0xf4, 0x0d, 0x00, 0x4a, - 0x10, 0x20, 0x1a, 0x18, 0x20, 0x74, 0x1b, 0x20, - 0xdd, 0x20, 0x00, 0x0c, 0xa8, 0x00, 0x5a, 0xaa, - 0x20, 0x1a, 0xff, 0x00, 0xad, 0x0e, 0x01, 0x38, - 0x12, 0x21, 0xc1, 0x15, 0x21, 0xe5, 0x19, 0x21, - 0xaa, 0x1d, 0x21, 0x8c, 0xd1, 0x41, 0x4a, 0xe1, - 0x21, 0xf0, 0x01, 0x0e, -}; - -#ifdef CONFIG_ALL_UNICODE - -static const uint8_t unicode_cc_table[851] = { - 0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00, - 0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03, - 0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03, - 0xdc, 0xc7, 0x00, 0xf0, 0xc0, 0x02, 0xdc, 0xc2, - 0x01, 0xdc, 0x80, 0xc2, 0x03, 0xdc, 0xc0, 0x00, - 0xe8, 0x01, 0xdc, 0xc0, 0x41, 0xe9, 0x00, 0xea, - 0x41, 0xe9, 0x00, 0xea, 0x00, 0xe9, 0xcc, 0xb0, - 0xe2, 0xc4, 0xb0, 0xd8, 0x00, 0xdc, 0xc3, 0x00, - 0xdc, 0xc2, 0x00, 0xde, 0x00, 0xdc, 0xc5, 0x05, - 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xde, 0x00, - 0xe4, 0xc0, 0x49, 0x0a, 0x43, 0x13, 0x80, 0x00, - 0x17, 0x80, 0x41, 0x18, 0x80, 0xc0, 0x00, 0xdc, - 0x80, 0x00, 0x12, 0xb0, 0x17, 0xc7, 0x42, 0x1e, - 0xaf, 0x47, 0x1b, 0xc1, 0x01, 0xdc, 0xc4, 0x00, - 0xdc, 0xc1, 0x00, 0xdc, 0x8f, 0x00, 0x23, 0xb0, - 0x34, 0xc6, 0x81, 0xc3, 0x00, 0xdc, 0xc0, 0x81, - 0xc1, 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xa2, - 0x00, 0x24, 0x9d, 0xc0, 0x00, 0xdc, 0xc1, 0x00, - 0xdc, 0xc1, 0x02, 0xdc, 0xc0, 0x01, 0xdc, 0xc0, - 0x00, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x00, 0xdc, - 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xc1, 0xb0, - 0x6f, 0xc6, 0x00, 0xdc, 0xc0, 0x88, 0x00, 0xdc, - 0x97, 0xc3, 0x80, 0xc8, 0x80, 0xc2, 0x80, 0xc4, - 0xaa, 0x02, 0xdc, 0xb0, 0x46, 0x00, 0xdc, 0xcd, - 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, - 0xdc, 0xc2, 0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, - 0xdc, 0xc1, 0x01, 0xdc, 0xc4, 0xb0, 0x0b, 0x00, - 0x07, 0x8f, 0x00, 0x09, 0x82, 0xc0, 0x00, 0xdc, - 0xc1, 0xb0, 0x36, 0x00, 0x07, 0x8f, 0x00, 0x09, - 0xaf, 0xc0, 0xb0, 0x0c, 0x00, 0x07, 0x8f, 0x00, - 0x09, 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, - 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, - 0x4e, 0x00, 0x09, 0xb0, 0x4e, 0x00, 0x09, 0x86, - 0x00, 0x54, 0x00, 0x5b, 0xb0, 0x34, 0x00, 0x07, - 0x8f, 0x00, 0x09, 0xb0, 0x3c, 0x01, 0x09, 0x8f, - 0x00, 0x09, 0xb0, 0x4b, 0x00, 0x09, 0xb0, 0x3c, - 0x01, 0x67, 0x00, 0x09, 0x8c, 0x03, 0x6b, 0xb0, - 0x3b, 0x01, 0x76, 0x00, 0x09, 0x8c, 0x03, 0x7a, - 0xb0, 0x1b, 0x01, 0xdc, 0x9a, 0x00, 0xdc, 0x80, - 0x00, 0xdc, 0x80, 0x00, 0xd8, 0xb0, 0x06, 0x41, - 0x81, 0x80, 0x00, 0x84, 0x84, 0x03, 0x82, 0x81, - 0x00, 0x82, 0x80, 0xc1, 0x00, 0x09, 0x80, 0xc1, - 0xb0, 0x0d, 0x00, 0xdc, 0xb0, 0x3f, 0x00, 0x07, - 0x80, 0x01, 0x09, 0xb0, 0x21, 0x00, 0xdc, 0xb2, - 0x9e, 0xc2, 0xb3, 0x83, 0x00, 0x09, 0x9e, 0x00, - 0x09, 0xb0, 0x6c, 0x00, 0x09, 0x89, 0xc0, 0xb0, - 0x9a, 0x00, 0xe4, 0xb0, 0x5e, 0x00, 0xde, 0xc0, - 0x00, 0xdc, 0xb0, 0xaa, 0xc0, 0x00, 0xdc, 0xb0, - 0x16, 0x00, 0x09, 0x93, 0xc7, 0x81, 0x00, 0xdc, - 0xaf, 0xc4, 0x05, 0xdc, 0xc1, 0x00, 0xdc, 0x80, - 0x01, 0xdc, 0xb0, 0x42, 0x00, 0x07, 0x8e, 0x00, - 0x09, 0xa5, 0xc0, 0x00, 0xdc, 0xc6, 0xb0, 0x05, - 0x01, 0x09, 0xb0, 0x09, 0x00, 0x07, 0x8a, 0x01, - 0x09, 0xb0, 0x12, 0x00, 0x07, 0xb0, 0x67, 0xc2, - 0x41, 0x00, 0x04, 0xdc, 0xc1, 0x03, 0xdc, 0xc0, - 0x41, 0x00, 0x05, 0x01, 0x83, 0x00, 0xdc, 0x85, - 0xc0, 0x82, 0xc1, 0xb0, 0x95, 0xc1, 0x00, 0xdc, - 0xc6, 0x00, 0xdc, 0xc1, 0x00, 0xea, 0x00, 0xd6, - 0x00, 0xdc, 0x00, 0xca, 0xe4, 0x00, 0xe8, 0x01, - 0xe4, 0x00, 0xdc, 0x80, 0xc0, 0x00, 0xe9, 0x00, - 0xdc, 0xc0, 0x00, 0xdc, 0xb2, 0x9f, 0xc1, 0x01, - 0x01, 0xc3, 0x02, 0x01, 0xc1, 0x83, 0xc0, 0x82, - 0x01, 0x01, 0xc0, 0x00, 0xdc, 0xc0, 0x01, 0x01, - 0x03, 0xdc, 0xc0, 0xb8, 0x03, 0xcd, 0xc2, 0xb0, - 0x5c, 0x00, 0x09, 0xb0, 0x2f, 0xdf, 0xb1, 0xf9, - 0x00, 0xda, 0x00, 0xe4, 0x00, 0xe8, 0x00, 0xde, - 0x01, 0xe0, 0xb0, 0x38, 0x01, 0x08, 0xb8, 0x6d, - 0xa3, 0xc0, 0x83, 0xc9, 0x9f, 0xc1, 0xb0, 0x1f, - 0xc1, 0xb0, 0xe3, 0x00, 0x09, 0xa4, 0x00, 0x09, - 0xb0, 0x66, 0x00, 0x09, 0x9a, 0xd1, 0xb0, 0x08, - 0x02, 0xdc, 0xa4, 0x00, 0x09, 0xb0, 0x2e, 0x00, - 0x07, 0x8b, 0x00, 0x09, 0xb0, 0xbe, 0xc0, 0x80, - 0xc1, 0x00, 0xdc, 0x81, 0xc1, 0x84, 0xc1, 0x80, - 0xc0, 0xb0, 0x03, 0x00, 0x09, 0xb0, 0xc5, 0x00, - 0x09, 0xb8, 0x46, 0xff, 0x00, 0x1a, 0xb2, 0xd0, - 0xc6, 0x06, 0xdc, 0xc1, 0xb3, 0x9c, 0x00, 0xdc, - 0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64, 0xc4, 0xb6, - 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0, 0x00, - 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0, 0x74, - 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb1, 0x52, - 0xc1, 0xb0, 0x68, 0x01, 0xdc, 0xc2, 0x00, 0xdc, - 0xc0, 0x03, 0xdc, 0xb0, 0xc4, 0x00, 0x09, 0xb0, - 0x07, 0x00, 0x09, 0xb0, 0x08, 0x00, 0x09, 0x00, - 0x07, 0xb0, 0x14, 0xc2, 0xaf, 0x01, 0x09, 0xb0, - 0x0d, 0x00, 0x07, 0xb0, 0x1b, 0x00, 0x09, 0x88, - 0x00, 0x07, 0xb0, 0x39, 0x00, 0x09, 0x00, 0x07, - 0xb0, 0x81, 0x00, 0x07, 0x00, 0x09, 0xb0, 0x1f, - 0x01, 0x07, 0x8f, 0x00, 0x09, 0x97, 0xc6, 0x82, - 0xc4, 0xb0, 0x9c, 0x00, 0x09, 0x82, 0x00, 0x07, - 0x96, 0xc0, 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07, - 0xb0, 0xca, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d, - 0x00, 0x09, 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07, - 0xb0, 0x42, 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09, - 0x00, 0x07, 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00, - 0x07, 0xb0, 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00, - 0x09, 0x91, 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09, - 0xb1, 0x74, 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07, - 0x80, 0x01, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb8, - 0x45, 0x27, 0x04, 0x01, 0xb0, 0x0a, 0xc6, 0xb4, - 0x88, 0x01, 0x06, 0xb8, 0x44, 0x7b, 0x00, 0x01, - 0xb8, 0x0c, 0x95, 0x01, 0xd8, 0x02, 0x01, 0x82, - 0x00, 0xe2, 0x04, 0xd8, 0x87, 0x07, 0xdc, 0x81, - 0xc4, 0x01, 0xdc, 0x9d, 0xc3, 0xb0, 0x63, 0xc2, - 0xb8, 0x05, 0x8a, 0xc6, 0x80, 0xd0, 0x81, 0xc6, - 0x80, 0xc1, 0x80, 0xc4, 0xb0, 0xd4, 0xc6, 0xb1, - 0x84, 0xc3, 0xb5, 0xaf, 0x06, 0xdc, 0xb0, 0x3c, - 0xc5, 0x00, 0x07, -}; - -static const uint8_t unicode_cc_index[81] = { - 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05, - 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0xe2, - 0x08, 0x00, 0x53, 0x09, 0x00, 0xcd, 0x0b, 0x20, - 0x38, 0x0e, 0x00, 0x73, 0x0f, 0x20, 0x5d, 0x13, - 0x20, 0x60, 0x1a, 0x20, 0xaa, 0x1b, 0x00, 0xf4, - 0x1c, 0x00, 0xfe, 0x1d, 0x20, 0x7f, 0x2d, 0x20, - 0xf0, 0xa6, 0x00, 0xb2, 0xaa, 0x00, 0xfe, 0x01, - 0x01, 0xab, 0x0e, 0x01, 0x73, 0x11, 0x21, 0x70, - 0x13, 0x01, 0xb8, 0x16, 0x01, 0x9a, 0x1a, 0x01, - 0x9f, 0xbc, 0x01, 0x22, 0xe0, 0x01, 0x4b, 0xe9, - 0x01, -}; - -static const uint32_t unicode_decomp_table1[690] = { - 0x00280081, 0x002a0097, 0x002a8081, 0x002bc097, - 0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097, - 0x002e4115, 0x002f0199, 0x00302016, 0x00400842, - 0x00448a42, 0x004a0442, 0x004c0096, 0x004c8117, - 0x004d0242, 0x004e4342, 0x004fc12f, 0x0050c342, - 0x005240bf, 0x00530342, 0x00550942, 0x005a0842, - 0x005e0096, 0x005e4342, 0x005fc081, 0x00680142, - 0x006bc142, 0x00710185, 0x0071c317, 0x00734844, - 0x00778344, 0x00798342, 0x007b02be, 0x007c4197, - 0x007d0142, 0x007e0444, 0x00800e42, 0x00878142, - 0x00898744, 0x00ac0483, 0x00b60317, 0x00b80283, - 0x00d00214, 0x00d10096, 0x00dd0080, 0x00de8097, - 0x00df8080, 0x00e10097, 0x00e1413e, 0x00e1c080, - 0x00e204be, 0x00ea83ae, 0x00f282ae, 0x00f401ad, - 0x00f4c12e, 0x00f54103, 0x00fc0303, 0x00fe4081, - 0x0100023e, 0x0101c0be, 0x010301be, 0x010640be, - 0x010e40be, 0x0114023e, 0x0115c0be, 0x011701be, - 0x011d8144, 0x01304144, 0x01340244, 0x01358144, - 0x01368344, 0x01388344, 0x013a8644, 0x013e0144, - 0x0161c085, 0x018882ae, 0x019d422f, 0x01b00184, - 0x01b4c084, 0x024a4084, 0x024c4084, 0x024d0084, - 0x0256042e, 0x0272c12e, 0x02770120, 0x0277c084, - 0x028cc084, 0x028d8084, 0x029641ae, 0x02978084, - 0x02d20084, 0x02d2c12e, 0x02d70120, 0x02e50084, - 0x02f281ae, 0x03120084, 0x03300084, 0x0331c122, - 0x0332812e, 0x035281ae, 0x03768084, 0x037701ae, - 0x038cc085, 0x03acc085, 0x03b7012f, 0x03c30081, - 0x03d0c084, 0x03d34084, 0x03d48084, 0x03d5c084, - 0x03d70084, 0x03da4084, 0x03dcc084, 0x03dd412e, - 0x03ddc085, 0x03de0084, 0x03de4085, 0x03e04084, - 0x03e4c084, 0x03e74084, 0x03e88084, 0x03e9c084, - 0x03eb0084, 0x03ee4084, 0x04098084, 0x043f0081, - 0x06c18484, 0x06c48084, 0x06cec184, 0x06d00120, - 0x06d0c084, 0x074b0383, 0x074cc41f, 0x074f1783, - 0x075e0081, 0x0766d283, 0x07801d44, 0x078e8942, - 0x07931844, 0x079f0d42, 0x07a58216, 0x07a68085, - 0x07a6c0be, 0x07a80d44, 0x07aea044, 0x07c00122, - 0x07c08344, 0x07c20122, 0x07c28344, 0x07c40122, - 0x07c48244, 0x07c60122, 0x07c68244, 0x07c8113e, - 0x07d08244, 0x07d20122, 0x07d28244, 0x07d40122, - 0x07d48344, 0x07d64c3e, 0x07dc4080, 0x07dc80be, - 0x07dcc080, 0x07dd00be, 0x07dd4080, 0x07dd80be, - 0x07ddc080, 0x07de00be, 0x07de4080, 0x07de80be, - 0x07dec080, 0x07df00be, 0x07df4080, 0x07e00820, - 0x07e40820, 0x07e80820, 0x07ec05be, 0x07eec080, - 0x07ef00be, 0x07ef4097, 0x07ef8080, 0x07efc117, - 0x07f0443e, 0x07f24080, 0x07f280be, 0x07f2c080, - 0x07f303be, 0x07f4c080, 0x07f582ae, 0x07f6c080, - 0x07f7433e, 0x07f8c080, 0x07f903ae, 0x07fac080, - 0x07fb013e, 0x07fb8102, 0x07fc83be, 0x07fe4080, - 0x07fe80be, 0x07fec080, 0x07ff00be, 0x07ff4080, - 0x07ff8097, 0x0800011e, 0x08008495, 0x08044081, - 0x0805c097, 0x08090081, 0x08094097, 0x08098099, - 0x080bc081, 0x080cc085, 0x080d00b1, 0x080d8085, - 0x080dc0b1, 0x080f0197, 0x0811c197, 0x0815c0b3, - 0x0817c081, 0x081c0595, 0x081ec081, 0x081f0215, - 0x0820051f, 0x08228583, 0x08254415, 0x082a0097, - 0x08400119, 0x08408081, 0x0840c0bf, 0x08414119, - 0x0841c081, 0x084240bf, 0x0842852d, 0x08454081, - 0x08458097, 0x08464295, 0x08480097, 0x08484099, - 0x08488097, 0x08490081, 0x08498080, 0x084a0081, - 0x084a8102, 0x084b0495, 0x084d421f, 0x084e4081, - 0x084ec099, 0x084f0283, 0x08514295, 0x08540119, - 0x0854809b, 0x0854c619, 0x0857c097, 0x08580081, - 0x08584097, 0x08588099, 0x0858c097, 0x08590081, - 0x08594097, 0x08598099, 0x0859c09b, 0x085a0097, - 0x085a4081, 0x085a8097, 0x085ac099, 0x085b0295, - 0x085c4097, 0x085c8099, 0x085cc097, 0x085d0081, - 0x085d4097, 0x085d8099, 0x085dc09b, 0x085e0097, - 0x085e4081, 0x085e8097, 0x085ec099, 0x085f0215, - 0x08624099, 0x0866813e, 0x086b80be, 0x087341be, - 0x088100be, 0x088240be, 0x088300be, 0x088901be, - 0x088b0085, 0x088b40b1, 0x088bc085, 0x088c00b1, - 0x089040be, 0x089100be, 0x0891c1be, 0x089801be, - 0x089b42be, 0x089d0144, 0x089e0144, 0x08a00144, - 0x08a10144, 0x08a20144, 0x08ab023e, 0x08b80244, - 0x08ba8220, 0x08ca411e, 0x0918049f, 0x091a4523, - 0x091cc097, 0x091d04a5, 0x091f452b, 0x0921c09b, - 0x092204a1, 0x09244525, 0x0926c099, 0x09270d25, - 0x092d8d1f, 0x09340d1f, 0x093a8081, 0x0a8300b3, - 0x0a9d0099, 0x0a9d4097, 0x0a9d8099, 0x0ab700be, - 0x0b1f0115, 0x0b5bc081, 0x0ba7c081, 0x0bbcc081, - 0x0bc004ad, 0x0bc244ad, 0x0bc484ad, 0x0bc6f383, - 0x0be0852d, 0x0be31d03, 0x0bf1882d, 0x0c000081, - 0x0c0d8283, 0x0c130b84, 0x0c194284, 0x0c1c0122, - 0x0c1cc122, 0x0c1d8122, 0x0c1e4122, 0x0c1f0122, - 0x0c250084, 0x0c26c123, 0x0c278084, 0x0c27c085, - 0x0c2b0b84, 0x0c314284, 0x0c340122, 0x0c34c122, - 0x0c358122, 0x0c364122, 0x0c370122, 0x0c3d0084, - 0x0c3dc220, 0x0c3f8084, 0x0c3fc085, 0x0c4c4a2d, - 0x0c51451f, 0x0c53ca9f, 0x0c5915ad, 0x0c648703, - 0x0c800741, 0x0c838089, 0x0c83c129, 0x0c8441a9, - 0x0c850089, 0x0c854129, 0x0c85c2a9, 0x0c870089, - 0x0c87408f, 0x0c87808d, 0x0c881241, 0x0c910203, - 0x0c940099, 0x0c9444a3, 0x0c968323, 0x0c98072d, - 0x0c9b84af, 0x0c9dc2a1, 0x0c9f00b5, 0x0c9f40b3, - 0x0c9f8085, 0x0ca01883, 0x0cac4223, 0x0cad4523, - 0x0cafc097, 0x0cb004a1, 0x0cb241a5, 0x0cb30097, - 0x0cb34099, 0x0cb38097, 0x0cb3c099, 0x0cb417ad, - 0x0cbfc085, 0x0cc001b3, 0x0cc0c0b1, 0x0cc100b3, - 0x0cc14131, 0x0cc1c0b5, 0x0cc200b3, 0x0cc241b1, - 0x0cc30133, 0x0cc38131, 0x0cc40085, 0x0cc440b1, - 0x0cc48133, 0x0cc50085, 0x0cc540b5, 0x0cc580b7, - 0x0cc5c0b5, 0x0cc600b1, 0x0cc64135, 0x0cc6c0b3, - 0x0cc701b1, 0x0cc7c0b3, 0x0cc800b5, 0x0cc840b3, - 0x0cc881b1, 0x0cc9422f, 0x0cca4131, 0x0ccac0b5, - 0x0ccb00b1, 0x0ccb40b3, 0x0ccb80b5, 0x0ccbc0b1, - 0x0ccc012f, 0x0ccc80b5, 0x0cccc0b3, 0x0ccd00b5, - 0x0ccd40b1, 0x0ccd80b5, 0x0ccdc085, 0x0cce02b1, - 0x0ccf40b3, 0x0ccf80b1, 0x0ccfc085, 0x0cd001b1, - 0x0cd0c0b3, 0x0cd101b1, 0x0cd1c0b5, 0x0cd200b3, - 0x0cd24085, 0x0cd280b5, 0x0cd2c085, 0x0cd30133, - 0x0cd381b1, 0x0cd440b3, 0x0cd48085, 0x0cd4c0b1, - 0x0cd500b3, 0x0cd54085, 0x0cd580b5, 0x0cd5c0b1, - 0x0cd60521, 0x0cd88525, 0x0cdb02a5, 0x0cdc4099, - 0x0cdc8117, 0x0cdd0099, 0x0cdd4197, 0x0cde0127, - 0x0cde8285, 0x0cdfc089, 0x0ce0043f, 0x0ce20099, - 0x0ce2409b, 0x0ce283bf, 0x0ce44219, 0x0ce54205, - 0x0ce6433f, 0x0ce7c131, 0x0ce84085, 0x0ce881b1, - 0x0ce94085, 0x0ce98107, 0x0cea0089, 0x0cea4097, - 0x0cea8219, 0x0ceb809d, 0x0cebc08d, 0x0cec083f, - 0x0cf00105, 0x0cf0809b, 0x0cf0c197, 0x0cf1809b, - 0x0cf1c099, 0x0cf20517, 0x0cf48099, 0x0cf4c117, - 0x0cf54119, 0x0cf5c097, 0x0cf6009b, 0x0cf64099, - 0x0cf68217, 0x0cf78119, 0x0cf804a1, 0x0cfa4525, - 0x0cfcc525, 0x0cff4125, 0x0cffc099, 0x29a70103, - 0x29dc0081, 0x29fe0103, 0x2ad70203, 0x2ada4081, - 0x3e401482, 0x3e4a7f82, 0x3e6a3f82, 0x3e8aa102, - 0x3e9b0110, 0x3e9c2f82, 0x3eb3c590, 0x3ec00197, - 0x3ec0c119, 0x3ec1413f, 0x3ec4c2af, 0x3ec74184, - 0x3ec804ad, 0x3eca4081, 0x3eca8304, 0x3ecc03a0, - 0x3ece02a0, 0x3ecf8084, 0x3ed00120, 0x3ed0c120, - 0x3ed184ae, 0x3ed3c085, 0x3ed4312d, 0x3ef4cbad, - 0x3efa892f, 0x3eff022d, 0x3f002f2f, 0x3f1782a5, - 0x3f18c0b1, 0x3f1907af, 0x3f1cffaf, 0x3f3c81a5, - 0x3f3d64af, 0x3f542031, 0x3f649b31, 0x3f7c0131, - 0x3f7c83b3, 0x3f7e40b1, 0x3f7e80bd, 0x3f7ec0bb, - 0x3f7f00b3, 0x3f840503, 0x3f8c01ad, 0x3f8cc315, - 0x3f8e462d, 0x3f91cc03, 0x3f97c695, 0x3f9c01af, - 0x3f9d0085, 0x3f9d852f, 0x3fa03aad, 0x3fbd442f, - 0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad, 0x3fe80081, - 0x3fe84f1f, 0x3ff0831f, 0x3ff2831f, 0x3ff4831f, - 0x3ff6819f, 0x3ff80783, 0x44268192, 0x442ac092, - 0x444b8112, 0x44d2c112, 0x452ec212, 0x456e8112, - 0x464e0092, 0x74578392, 0x746ec312, 0x75000d1f, - 0x75068d1f, 0x750d0d1f, 0x7513839f, 0x7515891f, - 0x751a0d1f, 0x75208d1f, 0x75271015, 0x752f439f, - 0x7531459f, 0x75340d1f, 0x753a8d1f, 0x75410395, - 0x7543441f, 0x7545839f, 0x75478d1f, 0x754e0795, - 0x7552839f, 0x75548d1f, 0x755b0d1f, 0x75618d1f, - 0x75680d1f, 0x756e8d1f, 0x75750d1f, 0x757b8d1f, - 0x75820d1f, 0x75888d1f, 0x758f0d1f, 0x75958d1f, - 0x759c0d1f, 0x75a28d1f, 0x75a90103, 0x75aa089f, - 0x75ae4081, 0x75ae839f, 0x75b04081, 0x75b08c9f, - 0x75b6c081, 0x75b7032d, 0x75b8889f, 0x75bcc081, - 0x75bd039f, 0x75bec081, 0x75bf0c9f, 0x75c54081, - 0x75c5832d, 0x75c7089f, 0x75cb4081, 0x75cb839f, - 0x75cd4081, 0x75cd8c9f, 0x75d3c081, 0x75d4032d, - 0x75d5889f, 0x75d9c081, 0x75da039f, 0x75dbc081, - 0x75dc0c9f, 0x75e24081, 0x75e2832d, 0x75e4089f, - 0x75e84081, 0x75e8839f, 0x75ea4081, 0x75ea8c9f, - 0x75f0c081, 0x75f1042d, 0x75f3851f, 0x75f6051f, - 0x75f8851f, 0x75fb051f, 0x75fd851f, 0x7b80022d, - 0x7b814dad, 0x7b884203, 0x7b89c081, 0x7b8a452d, - 0x7b8d0403, 0x7b908081, 0x7b91dc03, 0x7ba0052d, - 0x7ba2c8ad, 0x7ba84483, 0x7baac8ad, 0x7c400097, - 0x7c404521, 0x7c440d25, 0x7c4a8087, 0x7c4ac115, - 0x7c4b4117, 0x7c4c0d1f, 0x7c528217, 0x7c538099, - 0x7c53c097, 0x7c5a8197, 0x7c640097, 0x7c80012f, - 0x7c808081, 0x7c841603, 0x7c9004c1, 0x7c940103, - 0x7efc051f, 0xbe0001ac, 0xbe00d110, 0xbe0947ac, - 0xbe0d3910, 0xbe29872c, 0xbe2d022c, 0xbe2e3790, - 0xbe49ff90, 0xbe69bc10, -}; - -static const uint16_t unicode_decomp_table2[690] = { - 0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008, - 0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3, - 0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8, - 0x0108, 0x010a, 0x0073, 0x0110, 0x0112, 0x0114, 0x0120, 0x012c, - 0x0144, 0x014d, 0x0153, 0x0162, 0x0168, 0x016a, 0x0176, 0x0192, - 0x0194, 0x01a9, 0x01bb, 0x01c7, 0x01d1, 0x01d5, 0x02b9, 0x01d7, - 0x003b, 0x01d9, 0x01db, 0x00b7, 0x01e1, 0x01fc, 0x020c, 0x0218, - 0x021d, 0x0223, 0x0227, 0x03a3, 0x0233, 0x023f, 0x0242, 0x024b, - 0x024e, 0x0251, 0x025d, 0x0260, 0x0269, 0x026c, 0x026f, 0x0275, - 0x0278, 0x0281, 0x028a, 0x029c, 0x029f, 0x02a3, 0x02af, 0x02b9, - 0x02c5, 0x02c9, 0x02cd, 0x02d1, 0x02d5, 0x02e7, 0x02ed, 0x02f1, - 0x02f5, 0x02f9, 0x02fd, 0x0305, 0x0309, 0x030d, 0x0313, 0x0317, - 0x031b, 0x0323, 0x0327, 0x032b, 0x032f, 0x0335, 0x033d, 0x0341, - 0x0349, 0x034d, 0x0351, 0x0f0b, 0x0357, 0x035b, 0x035f, 0x0363, - 0x0367, 0x036b, 0x036f, 0x0373, 0x0379, 0x037d, 0x0381, 0x0385, - 0x0389, 0x038d, 0x0391, 0x0395, 0x0399, 0x039d, 0x03a1, 0x10dc, - 0x03a5, 0x03c9, 0x03cd, 0x03d9, 0x03dd, 0x03e1, 0x03ef, 0x03f1, - 0x043d, 0x044f, 0x0499, 0x04f0, 0x0502, 0x054a, 0x0564, 0x056c, - 0x0570, 0x0573, 0x059a, 0x05fa, 0x05fe, 0x0607, 0x060b, 0x0614, - 0x0618, 0x061e, 0x0622, 0x0628, 0x068e, 0x0694, 0x0698, 0x069e, - 0x06a2, 0x06ab, 0x03ac, 0x06f3, 0x03ad, 0x06f6, 0x03ae, 0x06f9, - 0x03af, 0x06fc, 0x03cc, 0x06ff, 0x03cd, 0x0702, 0x03ce, 0x0705, - 0x0709, 0x070d, 0x0711, 0x0386, 0x0732, 0x0735, 0x03b9, 0x0737, - 0x073b, 0x0388, 0x0753, 0x0389, 0x0756, 0x0390, 0x076b, 0x038a, - 0x0777, 0x03b0, 0x0789, 0x038e, 0x0799, 0x079f, 0x07a3, 0x038c, - 0x07b8, 0x038f, 0x07bb, 0x00b4, 0x07be, 0x07c0, 0x07c2, 0x2010, - 0x07cb, 0x002e, 0x07cd, 0x07cf, 0x0020, 0x07d2, 0x07d6, 0x07db, - 0x07df, 0x07e4, 0x07ea, 0x07f0, 0x0020, 0x07f6, 0x2212, 0x0801, - 0x0805, 0x0807, 0x081d, 0x0825, 0x0827, 0x0043, 0x082d, 0x0830, - 0x0190, 0x0836, 0x0839, 0x004e, 0x0845, 0x0847, 0x084c, 0x084e, - 0x0851, 0x005a, 0x03a9, 0x005a, 0x0853, 0x0857, 0x0860, 0x0069, - 0x0862, 0x0865, 0x086f, 0x0874, 0x087a, 0x087e, 0x08a2, 0x0049, - 0x08a4, 0x08a6, 0x08a9, 0x0056, 0x08ab, 0x08ad, 0x08b0, 0x08b4, - 0x0058, 0x08b6, 0x08b8, 0x08bb, 0x08c0, 0x08c2, 0x08c5, 0x0076, - 0x08c7, 0x08c9, 0x08cc, 0x08d0, 0x0078, 0x08d2, 0x08d4, 0x08d7, - 0x08db, 0x08de, 0x08e4, 0x08e7, 0x08f0, 0x08f3, 0x08f6, 0x08f9, - 0x0902, 0x0906, 0x090b, 0x090f, 0x0914, 0x0917, 0x091a, 0x0923, - 0x092c, 0x093b, 0x093e, 0x0941, 0x0944, 0x0947, 0x094a, 0x0956, - 0x095c, 0x0960, 0x0962, 0x0964, 0x0968, 0x096a, 0x0970, 0x0978, - 0x097c, 0x0980, 0x0986, 0x0989, 0x098f, 0x0991, 0x0030, 0x0993, - 0x0999, 0x099c, 0x099e, 0x09a1, 0x09a4, 0x2d61, 0x6bcd, 0x9f9f, - 0x09a6, 0x09b1, 0x09bc, 0x09c7, 0x0a95, 0x0aa1, 0x0b15, 0x0020, - 0x0b27, 0x0b31, 0x0b8d, 0x0ba1, 0x0ba5, 0x0ba9, 0x0bad, 0x0bb1, - 0x0bb5, 0x0bb9, 0x0bbd, 0x0bc1, 0x0bc5, 0x0c21, 0x0c35, 0x0c39, - 0x0c3d, 0x0c41, 0x0c45, 0x0c49, 0x0c4d, 0x0c51, 0x0c55, 0x0c59, - 0x0c6f, 0x0c71, 0x0c73, 0x0ca0, 0x0cbc, 0x0cdc, 0x0ce4, 0x0cec, - 0x0cf4, 0x0cfc, 0x0d04, 0x0d0c, 0x0d14, 0x0d22, 0x0d2e, 0x0d7a, - 0x0d82, 0x0d85, 0x0d89, 0x0d8d, 0x0d9d, 0x0db1, 0x0db5, 0x0dbc, - 0x0dc2, 0x0dc6, 0x0e28, 0x0e2c, 0x0e30, 0x0e32, 0x0e36, 0x0e3c, - 0x0e3e, 0x0e41, 0x0e43, 0x0e46, 0x0e77, 0x0e7b, 0x0e89, 0x0e8e, - 0x0e94, 0x0e9c, 0x0ea3, 0x0ea9, 0x0eb4, 0x0ebe, 0x0ec6, 0x0eca, - 0x0ecf, 0x0ed9, 0x0edd, 0x0ee4, 0x0eec, 0x0ef3, 0x0ef8, 0x0f04, - 0x0f0a, 0x0f15, 0x0f1b, 0x0f22, 0x0f28, 0x0f33, 0x0f3d, 0x0f45, - 0x0f4c, 0x0f51, 0x0f57, 0x0f5e, 0x0f63, 0x0f69, 0x0f70, 0x0f76, - 0x0f7d, 0x0f82, 0x0f89, 0x0f8d, 0x0f9e, 0x0fa4, 0x0fa9, 0x0fad, - 0x0fb8, 0x0fbe, 0x0fc9, 0x0fd0, 0x0fd6, 0x0fda, 0x0fe1, 0x0fe5, - 0x0fef, 0x0ffa, 0x1000, 0x1004, 0x1009, 0x100f, 0x1013, 0x101a, - 0x101f, 0x1023, 0x1029, 0x102f, 0x1032, 0x1036, 0x1039, 0x103f, - 0x1045, 0x1059, 0x1061, 0x1079, 0x107c, 0x1080, 0x1095, 0x10a1, - 0x10b1, 0x10c3, 0x10cb, 0x10cf, 0x10da, 0x10de, 0x10ea, 0x10f2, - 0x10f4, 0x1100, 0x1105, 0x1111, 0x1141, 0x1149, 0x114d, 0x1153, - 0x1157, 0x115a, 0x116e, 0x1171, 0x1175, 0x117b, 0x117d, 0x1181, - 0x1184, 0x118c, 0x1192, 0x1196, 0x119c, 0x11a2, 0x11a8, 0x11ab, - 0xa76f, 0x11af, 0x11b3, 0x028d, 0x11bb, 0x120d, 0x130b, 0x1409, - 0x148d, 0x1492, 0x1550, 0x1569, 0x156f, 0x1575, 0x157b, 0x1587, - 0x1593, 0x002b, 0x159e, 0x15b6, 0x15ba, 0x15be, 0x15c2, 0x15c6, - 0x15ca, 0x15de, 0x15e2, 0x1646, 0x165f, 0x1685, 0x168b, 0x1749, - 0x174f, 0x1754, 0x1774, 0x1874, 0x187a, 0x190e, 0x19d0, 0x1a74, - 0x1a7c, 0x1a9a, 0x1a9f, 0x1ab3, 0x1abd, 0x1ac3, 0x1ad7, 0x1adc, - 0x1ae2, 0x1af0, 0x1b20, 0x1b2d, 0x1b35, 0x1b39, 0x1b4f, 0x1bc6, - 0x1bd8, 0x1bda, 0x1bdc, 0x3164, 0x1c1d, 0x1c1f, 0x1c21, 0x1c23, - 0x1c25, 0x1c27, 0x1c45, 0x1c53, 0x1c58, 0x1c61, 0x1c6a, 0x1c7c, - 0x1c85, 0x1c8a, 0x1caa, 0x1cc5, 0x1cc7, 0x1cc9, 0x1ccb, 0x1ccd, - 0x1ccf, 0x1cd1, 0x1cd3, 0x1cf3, 0x1cf5, 0x1cf7, 0x1cf9, 0x1cfb, - 0x1d02, 0x1d04, 0x1d06, 0x1d08, 0x1d17, 0x1d19, 0x1d1b, 0x1d1d, - 0x1d1f, 0x1d21, 0x1d23, 0x1d25, 0x1d27, 0x1d29, 0x1d2b, 0x1d2d, - 0x1d2f, 0x1d31, 0x1d33, 0x1d37, 0x03f4, 0x1d39, 0x2207, 0x1d3b, - 0x2202, 0x1d3d, 0x1d45, 0x03f4, 0x1d47, 0x2207, 0x1d49, 0x2202, - 0x1d4b, 0x1d53, 0x03f4, 0x1d55, 0x2207, 0x1d57, 0x2202, 0x1d59, - 0x1d61, 0x03f4, 0x1d63, 0x2207, 0x1d65, 0x2202, 0x1d67, 0x1d6f, - 0x03f4, 0x1d71, 0x2207, 0x1d73, 0x2202, 0x1d75, 0x1d7f, 0x1d81, - 0x1d83, 0x1d85, 0x1d87, 0x1d89, 0x1d8f, 0x1dac, 0x062d, 0x1db4, - 0x1dc0, 0x062c, 0x1dd0, 0x1e40, 0x1e4c, 0x1e5f, 0x1e71, 0x1e84, - 0x1e86, 0x1e8a, 0x1e90, 0x1e96, 0x1e98, 0x1e9c, 0x1e9e, 0x1ea6, - 0x1ea9, 0x1eab, 0x1eb1, 0x1eb3, 0x30b5, 0x1eb9, 0x1f11, 0x1f27, - 0x1f2b, 0x1f2d, 0x1f32, 0x1f7f, 0x1f90, 0x2091, 0x20a1, 0x20a7, - 0x21a1, 0x22bf, -}; - -static const uint8_t unicode_decomp_data[9165] = { - 0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81, - 0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31, - 0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41, - 0x81, 0x41, 0x82, 0x41, 0x83, 0x41, 0x88, 0x41, - 0x8a, 0x00, 0x00, 0x43, 0xa7, 0x45, 0x80, 0x45, - 0x81, 0x45, 0x82, 0x45, 0x88, 0x49, 0x80, 0x49, - 0x81, 0x49, 0x82, 0x49, 0x88, 0x00, 0x00, 0x4e, - 0x83, 0x4f, 0x80, 0x4f, 0x81, 0x4f, 0x82, 0x4f, - 0x83, 0x4f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x55, - 0x80, 0x55, 0x81, 0x55, 0x82, 0x55, 0x88, 0x59, - 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x61, - 0x81, 0x61, 0x82, 0x61, 0x83, 0x61, 0x88, 0x61, - 0x8a, 0x00, 0x00, 0x63, 0xa7, 0x65, 0x80, 0x65, - 0x81, 0x65, 0x82, 0x65, 0x88, 0x69, 0x80, 0x69, - 0x81, 0x69, 0x82, 0x69, 0x88, 0x00, 0x00, 0x6e, - 0x83, 0x6f, 0x80, 0x6f, 0x81, 0x6f, 0x82, 0x6f, - 0x83, 0x6f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x75, - 0x80, 0x75, 0x81, 0x75, 0x82, 0x75, 0x88, 0x79, - 0x81, 0x00, 0x00, 0x79, 0x88, 0x41, 0x84, 0x41, - 0x86, 0x41, 0xa8, 0x43, 0x81, 0x43, 0x82, 0x43, - 0x87, 0x43, 0x8c, 0x44, 0x8c, 0x45, 0x84, 0x45, - 0x86, 0x45, 0x87, 0x45, 0xa8, 0x45, 0x8c, 0x47, - 0x82, 0x47, 0x86, 0x47, 0x87, 0x47, 0xa7, 0x48, - 0x82, 0x49, 0x83, 0x49, 0x84, 0x49, 0x86, 0x49, - 0xa8, 0x49, 0x87, 0x49, 0x4a, 0x69, 0x6a, 0x4a, - 0x82, 0x4b, 0xa7, 0x4c, 0x81, 0x4c, 0xa7, 0x4c, - 0x8c, 0x4c, 0x00, 0x00, 0x6b, 0x20, 0x6b, 0x4e, - 0x81, 0x4e, 0xa7, 0x4e, 0x8c, 0xbc, 0x02, 0x6e, - 0x4f, 0x84, 0x4f, 0x86, 0x4f, 0x8b, 0x52, 0x81, - 0x52, 0xa7, 0x52, 0x8c, 0x53, 0x81, 0x53, 0x82, - 0x53, 0xa7, 0x53, 0x8c, 0x54, 0xa7, 0x54, 0x8c, - 0x55, 0x83, 0x55, 0x84, 0x55, 0x86, 0x55, 0x8a, - 0x55, 0x8b, 0x55, 0xa8, 0x57, 0x82, 0x59, 0x82, - 0x59, 0x88, 0x5a, 0x81, 0x5a, 0x87, 0x5a, 0x8c, - 0x4f, 0x9b, 0x55, 0x9b, 0x44, 0x00, 0x7d, 0x01, - 0x44, 0x00, 0x7e, 0x01, 0x64, 0x00, 0x7e, 0x01, - 0x4c, 0x4a, 0x4c, 0x6a, 0x6c, 0x6a, 0x4e, 0x4a, - 0x4e, 0x6a, 0x6e, 0x6a, 0x41, 0x00, 0x8c, 0x49, - 0x00, 0x8c, 0x4f, 0x00, 0x8c, 0x55, 0x00, 0x8c, - 0xdc, 0x00, 0x84, 0xdc, 0x00, 0x81, 0xdc, 0x00, - 0x8c, 0xdc, 0x00, 0x80, 0xc4, 0x00, 0x84, 0x26, - 0x02, 0x84, 0xc6, 0x00, 0x84, 0x47, 0x8c, 0x4b, - 0x8c, 0x4f, 0xa8, 0xea, 0x01, 0x84, 0xeb, 0x01, - 0x84, 0xb7, 0x01, 0x8c, 0x92, 0x02, 0x8c, 0x6a, - 0x00, 0x8c, 0x44, 0x5a, 0x44, 0x7a, 0x64, 0x7a, - 0x47, 0x81, 0x4e, 0x00, 0x80, 0xc5, 0x00, 0x81, - 0xc6, 0x00, 0x81, 0xd8, 0x00, 0x81, 0x41, 0x8f, - 0x41, 0x91, 0x45, 0x8f, 0x45, 0x91, 0x49, 0x8f, - 0x49, 0x91, 0x4f, 0x8f, 0x4f, 0x91, 0x52, 0x8f, - 0x52, 0x91, 0x55, 0x8f, 0x55, 0x91, 0x53, 0xa6, - 0x54, 0xa6, 0x48, 0x8c, 0x41, 0x00, 0x87, 0x45, - 0x00, 0xa7, 0xd6, 0x00, 0x84, 0xd5, 0x00, 0x84, - 0x4f, 0x00, 0x87, 0x2e, 0x02, 0x84, 0x59, 0x00, - 0x84, 0x68, 0x00, 0x66, 0x02, 0x6a, 0x00, 0x72, - 0x00, 0x79, 0x02, 0x7b, 0x02, 0x81, 0x02, 0x77, - 0x00, 0x79, 0x00, 0x20, 0x86, 0x20, 0x87, 0x20, - 0x8a, 0x20, 0xa8, 0x20, 0x83, 0x20, 0x8b, 0x63, - 0x02, 0x6c, 0x00, 0x73, 0x00, 0x78, 0x00, 0x95, - 0x02, 0x80, 0x81, 0x00, 0x93, 0x88, 0x81, 0x20, - 0xc5, 0x20, 0x81, 0xa8, 0x00, 0x81, 0x91, 0x03, - 0x81, 0x95, 0x03, 0x81, 0x97, 0x03, 0x81, 0x99, - 0x03, 0x81, 0x00, 0x00, 0x00, 0x9f, 0x03, 0x81, - 0x00, 0x00, 0x00, 0xa5, 0x03, 0x81, 0xa9, 0x03, - 0x81, 0xca, 0x03, 0x81, 0x01, 0x03, 0x98, 0x07, - 0xa4, 0x07, 0xb0, 0x00, 0xb4, 0x00, 0xb6, 0x00, - 0xb8, 0x00, 0xca, 0x00, 0x01, 0x03, 0xb8, 0x07, - 0xc4, 0x07, 0xbe, 0x00, 0xc4, 0x00, 0xc8, 0x00, - 0xa5, 0x03, 0x0d, 0x13, 0x00, 0x01, 0x03, 0xd1, - 0x00, 0xd1, 0x07, 0xc6, 0x03, 0xc0, 0x03, 0xba, - 0x03, 0xc1, 0x03, 0xc2, 0x03, 0x00, 0x00, 0x98, - 0x03, 0xb5, 0x03, 0x15, 0x04, 0x80, 0x15, 0x04, - 0x88, 0x00, 0x00, 0x00, 0x13, 0x04, 0x81, 0x06, - 0x04, 0x88, 0x1a, 0x04, 0x81, 0x18, 0x04, 0x80, - 0x23, 0x04, 0x86, 0x18, 0x04, 0x86, 0x38, 0x04, - 0x86, 0x35, 0x04, 0x80, 0x35, 0x04, 0x88, 0x00, - 0x00, 0x00, 0x33, 0x04, 0x81, 0x56, 0x04, 0x88, - 0x3a, 0x04, 0x81, 0x38, 0x04, 0x80, 0x43, 0x04, - 0x86, 0x74, 0x04, 0x8f, 0x16, 0x04, 0x86, 0x10, - 0x04, 0x86, 0x10, 0x04, 0x88, 0x15, 0x04, 0x86, - 0xd8, 0x04, 0x88, 0x16, 0x04, 0x88, 0x17, 0x04, - 0x88, 0x18, 0x04, 0x84, 0x18, 0x04, 0x88, 0x1e, - 0x04, 0x88, 0xe8, 0x04, 0x88, 0x2d, 0x04, 0x88, - 0x23, 0x04, 0x84, 0x23, 0x04, 0x88, 0x23, 0x04, - 0x8b, 0x27, 0x04, 0x88, 0x2b, 0x04, 0x88, 0x65, - 0x05, 0x82, 0x05, 0x27, 0x06, 0x00, 0x2c, 0x00, - 0x2d, 0x21, 0x2d, 0x00, 0x2e, 0x23, 0x2d, 0x27, - 0x06, 0x00, 0x4d, 0x21, 0x4d, 0xa0, 0x4d, 0x23, - 0x4d, 0xd5, 0x06, 0x54, 0x06, 0x00, 0x00, 0x00, - 0x00, 0xc1, 0x06, 0x54, 0x06, 0xd2, 0x06, 0x54, - 0x06, 0x28, 0x09, 0x3c, 0x09, 0x30, 0x09, 0x3c, - 0x09, 0x33, 0x09, 0x3c, 0x09, 0x15, 0x09, 0x00, - 0x27, 0x01, 0x27, 0x02, 0x27, 0x07, 0x27, 0x0c, - 0x27, 0x0d, 0x27, 0x16, 0x27, 0x1a, 0x27, 0xbe, - 0x09, 0x09, 0x00, 0x09, 0x19, 0xa1, 0x09, 0xbc, - 0x09, 0xaf, 0x09, 0xbc, 0x09, 0x32, 0x0a, 0x3c, - 0x0a, 0x38, 0x0a, 0x3c, 0x0a, 0x16, 0x0a, 0x00, - 0x26, 0x01, 0x26, 0x06, 0x26, 0x2b, 0x0a, 0x3c, - 0x0a, 0x47, 0x0b, 0x56, 0x0b, 0x3e, 0x0b, 0x09, - 0x00, 0x09, 0x19, 0x21, 0x0b, 0x3c, 0x0b, 0x92, - 0x0b, 0xd7, 0x0b, 0xbe, 0x0b, 0x08, 0x00, 0x09, - 0x00, 0x08, 0x19, 0x46, 0x0c, 0x56, 0x0c, 0xbf, - 0x0c, 0xd5, 0x0c, 0xc6, 0x0c, 0xd5, 0x0c, 0xc2, - 0x0c, 0x04, 0x00, 0x08, 0x13, 0x3e, 0x0d, 0x08, - 0x00, 0x09, 0x00, 0x08, 0x19, 0xd9, 0x0d, 0xca, - 0x0d, 0xca, 0x0d, 0x0f, 0x05, 0x12, 0x00, 0x0f, - 0x15, 0x4d, 0x0e, 0x32, 0x0e, 0xcd, 0x0e, 0xb2, - 0x0e, 0x99, 0x0e, 0x12, 0x00, 0x12, 0x08, 0x42, - 0x0f, 0xb7, 0x0f, 0x4c, 0x0f, 0xb7, 0x0f, 0x51, - 0x0f, 0xb7, 0x0f, 0x56, 0x0f, 0xb7, 0x0f, 0x5b, - 0x0f, 0xb7, 0x0f, 0x40, 0x0f, 0xb5, 0x0f, 0x71, - 0x0f, 0x72, 0x0f, 0x71, 0x0f, 0x00, 0x03, 0x41, - 0x0f, 0xb2, 0x0f, 0x81, 0x0f, 0xb3, 0x0f, 0x80, - 0x0f, 0xb3, 0x0f, 0x81, 0x0f, 0x71, 0x0f, 0x80, - 0x0f, 0x92, 0x0f, 0xb7, 0x0f, 0x9c, 0x0f, 0xb7, - 0x0f, 0xa1, 0x0f, 0xb7, 0x0f, 0xa6, 0x0f, 0xb7, - 0x0f, 0xab, 0x0f, 0xb7, 0x0f, 0x90, 0x0f, 0xb5, - 0x0f, 0x25, 0x10, 0x2e, 0x10, 0x05, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x09, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x1b, 0x35, - 0x1b, 0x11, 0x1b, 0x35, 0x1b, 0x3a, 0x1b, 0x35, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1b, 0x35, - 0x1b, 0x3e, 0x1b, 0x35, 0x1b, 0x42, 0x1b, 0x35, - 0x1b, 0x41, 0x00, 0xc6, 0x00, 0x42, 0x00, 0x00, - 0x00, 0x44, 0x00, 0x45, 0x00, 0x8e, 0x01, 0x47, - 0x00, 0x4f, 0x00, 0x22, 0x02, 0x50, 0x00, 0x52, - 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x61, - 0x00, 0x50, 0x02, 0x51, 0x02, 0x02, 0x1d, 0x62, - 0x00, 0x64, 0x00, 0x65, 0x00, 0x59, 0x02, 0x5b, - 0x02, 0x5c, 0x02, 0x67, 0x00, 0x00, 0x00, 0x6b, - 0x00, 0x6d, 0x00, 0x4b, 0x01, 0x6f, 0x00, 0x54, - 0x02, 0x16, 0x1d, 0x17, 0x1d, 0x70, 0x00, 0x74, - 0x00, 0x75, 0x00, 0x1d, 0x1d, 0x6f, 0x02, 0x76, - 0x00, 0x25, 0x1d, 0xb2, 0x03, 0xb3, 0x03, 0xb4, - 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x69, 0x00, 0x72, - 0x00, 0x75, 0x00, 0x76, 0x00, 0xb2, 0x03, 0xb3, - 0x03, 0xc1, 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x52, - 0x02, 0x63, 0x00, 0x55, 0x02, 0xf0, 0x00, 0x5c, - 0x02, 0x66, 0x00, 0x5f, 0x02, 0x61, 0x02, 0x65, - 0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x7b, - 0x1d, 0x9d, 0x02, 0x6d, 0x02, 0x85, 0x1d, 0x9f, - 0x02, 0x71, 0x02, 0x70, 0x02, 0x72, 0x02, 0x73, - 0x02, 0x74, 0x02, 0x75, 0x02, 0x78, 0x02, 0x82, - 0x02, 0x83, 0x02, 0xab, 0x01, 0x89, 0x02, 0x8a, - 0x02, 0x1c, 0x1d, 0x8b, 0x02, 0x8c, 0x02, 0x7a, - 0x00, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0xb8, - 0x03, 0x41, 0x00, 0xa5, 0x42, 0x00, 0x87, 0x42, - 0x00, 0xa3, 0x42, 0x00, 0xb1, 0xc7, 0x00, 0x81, - 0x44, 0x00, 0x87, 0x44, 0x00, 0xa3, 0x44, 0x00, - 0xb1, 0x44, 0x00, 0xa7, 0x44, 0x00, 0xad, 0x12, - 0x01, 0x80, 0x12, 0x01, 0x81, 0x45, 0x00, 0xad, - 0x45, 0x00, 0xb0, 0x28, 0x02, 0x86, 0x46, 0x00, - 0x87, 0x47, 0x00, 0x84, 0x48, 0x00, 0x87, 0x48, - 0x00, 0xa3, 0x48, 0x00, 0x88, 0x48, 0x00, 0xa7, - 0x48, 0x00, 0xae, 0x49, 0x00, 0xb0, 0xcf, 0x00, - 0x81, 0x4b, 0x00, 0x81, 0x4b, 0x00, 0xa3, 0x4b, - 0x00, 0xb1, 0x4c, 0x00, 0xa3, 0x36, 0x1e, 0x84, - 0x4c, 0xb1, 0x4c, 0xad, 0x4d, 0x81, 0x4d, 0x87, - 0x4d, 0xa3, 0x4e, 0x87, 0x4e, 0xa3, 0x4e, 0xb1, - 0x4e, 0xad, 0xd5, 0x00, 0x81, 0xd5, 0x00, 0x88, - 0x4c, 0x01, 0x80, 0x4c, 0x01, 0x81, 0x50, 0x00, - 0x81, 0x50, 0x00, 0x87, 0x52, 0x00, 0x87, 0x52, - 0x00, 0xa3, 0x5a, 0x1e, 0x84, 0x52, 0x00, 0xb1, - 0x53, 0x00, 0x87, 0x53, 0x00, 0xa3, 0x5a, 0x01, - 0x87, 0x60, 0x01, 0x87, 0x62, 0x1e, 0x87, 0x54, - 0x00, 0x87, 0x54, 0x00, 0xa3, 0x54, 0x00, 0xb1, - 0x54, 0x00, 0xad, 0x55, 0x00, 0xa4, 0x55, 0x00, - 0xb0, 0x55, 0x00, 0xad, 0x68, 0x01, 0x81, 0x6a, - 0x01, 0x88, 0x56, 0x83, 0x56, 0xa3, 0x57, 0x80, - 0x57, 0x81, 0x57, 0x88, 0x57, 0x87, 0x57, 0xa3, - 0x58, 0x87, 0x58, 0x88, 0x59, 0x87, 0x5a, 0x82, - 0x5a, 0xa3, 0x5a, 0xb1, 0x68, 0xb1, 0x74, 0x88, - 0x77, 0x8a, 0x79, 0x8a, 0x61, 0x00, 0xbe, 0x02, - 0x7f, 0x01, 0x87, 0x41, 0x00, 0xa3, 0x41, 0x00, - 0x89, 0xc2, 0x00, 0x81, 0xc2, 0x00, 0x80, 0xc2, - 0x00, 0x89, 0xc2, 0x00, 0x83, 0xa0, 0x1e, 0x82, - 0x02, 0x01, 0x81, 0x02, 0x01, 0x80, 0x02, 0x01, - 0x89, 0x02, 0x01, 0x83, 0xa0, 0x1e, 0x86, 0x45, - 0x00, 0xa3, 0x45, 0x00, 0x89, 0x45, 0x00, 0x83, - 0xca, 0x00, 0x81, 0xca, 0x00, 0x80, 0xca, 0x00, - 0x89, 0xca, 0x00, 0x83, 0xb8, 0x1e, 0x82, 0x49, - 0x00, 0x89, 0x49, 0x00, 0xa3, 0x4f, 0x00, 0xa3, - 0x4f, 0x00, 0x89, 0xd4, 0x00, 0x81, 0xd4, 0x00, - 0x80, 0xd4, 0x00, 0x89, 0xd4, 0x00, 0x83, 0xcc, - 0x1e, 0x82, 0xa0, 0x01, 0x81, 0xa0, 0x01, 0x80, - 0xa0, 0x01, 0x89, 0xa0, 0x01, 0x83, 0xa0, 0x01, - 0xa3, 0x55, 0x00, 0xa3, 0x55, 0x00, 0x89, 0xaf, - 0x01, 0x81, 0xaf, 0x01, 0x80, 0xaf, 0x01, 0x89, - 0xaf, 0x01, 0x83, 0xaf, 0x01, 0xa3, 0x59, 0x00, - 0x80, 0x59, 0x00, 0xa3, 0x59, 0x00, 0x89, 0x59, - 0x00, 0x83, 0xb1, 0x03, 0x13, 0x03, 0x00, 0x1f, - 0x80, 0x00, 0x1f, 0x81, 0x00, 0x1f, 0xc2, 0x91, - 0x03, 0x13, 0x03, 0x08, 0x1f, 0x80, 0x08, 0x1f, - 0x81, 0x08, 0x1f, 0xc2, 0xb5, 0x03, 0x13, 0x03, - 0x10, 0x1f, 0x80, 0x10, 0x1f, 0x81, 0x95, 0x03, - 0x13, 0x03, 0x18, 0x1f, 0x80, 0x18, 0x1f, 0x81, - 0xb7, 0x03, 0x93, 0xb7, 0x03, 0x94, 0x20, 0x1f, - 0x80, 0x21, 0x1f, 0x80, 0x20, 0x1f, 0x81, 0x21, - 0x1f, 0x81, 0x20, 0x1f, 0xc2, 0x21, 0x1f, 0xc2, - 0x97, 0x03, 0x93, 0x97, 0x03, 0x94, 0x28, 0x1f, - 0x80, 0x29, 0x1f, 0x80, 0x28, 0x1f, 0x81, 0x29, - 0x1f, 0x81, 0x28, 0x1f, 0xc2, 0x29, 0x1f, 0xc2, - 0xb9, 0x03, 0x93, 0xb9, 0x03, 0x94, 0x30, 0x1f, - 0x80, 0x31, 0x1f, 0x80, 0x30, 0x1f, 0x81, 0x31, - 0x1f, 0x81, 0x30, 0x1f, 0xc2, 0x31, 0x1f, 0xc2, - 0x99, 0x03, 0x93, 0x99, 0x03, 0x94, 0x38, 0x1f, - 0x80, 0x39, 0x1f, 0x80, 0x38, 0x1f, 0x81, 0x39, - 0x1f, 0x81, 0x38, 0x1f, 0xc2, 0x39, 0x1f, 0xc2, - 0xbf, 0x03, 0x93, 0xbf, 0x03, 0x94, 0x40, 0x1f, - 0x80, 0x40, 0x1f, 0x81, 0x9f, 0x03, 0x13, 0x03, - 0x48, 0x1f, 0x80, 0x48, 0x1f, 0x81, 0xc5, 0x03, - 0x13, 0x03, 0x50, 0x1f, 0x80, 0x50, 0x1f, 0x81, - 0x50, 0x1f, 0xc2, 0xa5, 0x03, 0x94, 0x00, 0x00, - 0x00, 0x59, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x59, - 0x1f, 0x81, 0x00, 0x00, 0x00, 0x59, 0x1f, 0xc2, - 0xc9, 0x03, 0x93, 0xc9, 0x03, 0x94, 0x60, 0x1f, - 0x80, 0x61, 0x1f, 0x80, 0x60, 0x1f, 0x81, 0x61, - 0x1f, 0x81, 0x60, 0x1f, 0xc2, 0x61, 0x1f, 0xc2, - 0xa9, 0x03, 0x93, 0xa9, 0x03, 0x94, 0x68, 0x1f, - 0x80, 0x69, 0x1f, 0x80, 0x68, 0x1f, 0x81, 0x69, - 0x1f, 0x81, 0x68, 0x1f, 0xc2, 0x69, 0x1f, 0xc2, - 0xb1, 0x03, 0x80, 0xb5, 0x03, 0x80, 0xb7, 0x03, - 0x80, 0xb9, 0x03, 0x80, 0xbf, 0x03, 0x80, 0xc5, - 0x03, 0x80, 0xc9, 0x03, 0x80, 0x00, 0x1f, 0x45, - 0x03, 0x20, 0x1f, 0x45, 0x03, 0x60, 0x1f, 0x45, - 0x03, 0xb1, 0x03, 0x86, 0xb1, 0x03, 0x84, 0x70, - 0x1f, 0xc5, 0xb1, 0x03, 0xc5, 0xac, 0x03, 0xc5, - 0x00, 0x00, 0x00, 0xb1, 0x03, 0xc2, 0xb6, 0x1f, - 0xc5, 0x91, 0x03, 0x86, 0x91, 0x03, 0x84, 0x91, - 0x03, 0x80, 0x91, 0x03, 0xc5, 0x20, 0x93, 0x20, - 0x93, 0x20, 0xc2, 0xa8, 0x00, 0xc2, 0x74, 0x1f, - 0xc5, 0xb7, 0x03, 0xc5, 0xae, 0x03, 0xc5, 0x00, - 0x00, 0x00, 0xb7, 0x03, 0xc2, 0xc6, 0x1f, 0xc5, - 0x95, 0x03, 0x80, 0x97, 0x03, 0x80, 0x97, 0x03, - 0xc5, 0xbf, 0x1f, 0x80, 0xbf, 0x1f, 0x81, 0xbf, - 0x1f, 0xc2, 0xb9, 0x03, 0x86, 0xb9, 0x03, 0x84, - 0xca, 0x03, 0x80, 0x00, 0x03, 0xb9, 0x42, 0xca, - 0x42, 0x99, 0x06, 0x99, 0x04, 0x99, 0x00, 0xfe, - 0x1f, 0x80, 0xfe, 0x1f, 0x81, 0xfe, 0x1f, 0xc2, - 0xc5, 0x03, 0x86, 0xc5, 0x03, 0x84, 0xcb, 0x03, - 0x80, 0x00, 0x03, 0xc1, 0x13, 0xc1, 0x14, 0xc5, - 0x42, 0xcb, 0x42, 0xa5, 0x06, 0xa5, 0x04, 0xa5, - 0x00, 0xa1, 0x03, 0x94, 0xa8, 0x00, 0x80, 0x85, - 0x03, 0x60, 0x00, 0x7c, 0x1f, 0xc5, 0xc9, 0x03, - 0xc5, 0xce, 0x03, 0xc5, 0x00, 0x00, 0x00, 0xc9, - 0x03, 0xc2, 0xf6, 0x1f, 0xc5, 0x9f, 0x03, 0x80, - 0xa9, 0x03, 0x80, 0xa9, 0x03, 0xc5, 0x20, 0x94, - 0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0xb3, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x32, 0x20, 0x32, 0x20, 0x32, 0x20, - 0x00, 0x00, 0x00, 0x35, 0x20, 0x35, 0x20, 0x35, - 0x20, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00, - 0x20, 0x85, 0x3f, 0x3f, 0x3f, 0x21, 0x21, 0x3f, - 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x69, - 0x00, 0x00, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x2b, 0x3d, 0x28, 0x29, 0x6e, 0x30, 0x00, 0x2b, - 0x00, 0x12, 0x22, 0x3d, 0x00, 0x28, 0x00, 0x29, - 0x00, 0x00, 0x00, 0x61, 0x00, 0x65, 0x00, 0x6f, - 0x00, 0x78, 0x00, 0x59, 0x02, 0x68, 0x6b, 0x6c, - 0x6d, 0x6e, 0x70, 0x73, 0x74, 0x52, 0x73, 0x61, - 0x2f, 0x63, 0x61, 0x2f, 0x73, 0xb0, 0x00, 0x43, - 0x63, 0x2f, 0x6f, 0x63, 0x2f, 0x75, 0xb0, 0x00, - 0x46, 0x48, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, - 0xdf, 0x01, 0x01, 0x04, 0x24, 0x4e, 0x6f, 0x50, - 0x51, 0x52, 0x52, 0x52, 0x53, 0x4d, 0x54, 0x45, - 0x4c, 0x54, 0x4d, 0x4b, 0x00, 0xc5, 0x00, 0x42, - 0x43, 0x00, 0x65, 0x45, 0x46, 0x00, 0x4d, 0x6f, - 0xd0, 0x05, 0x46, 0x41, 0x58, 0xc0, 0x03, 0xb3, - 0x03, 0x93, 0x03, 0xa0, 0x03, 0x11, 0x22, 0x44, - 0x64, 0x65, 0x69, 0x6a, 0x31, 0xd0, 0x37, 0x31, - 0xd0, 0x39, 0x31, 0xd0, 0x31, 0x30, 0x31, 0xd0, - 0x33, 0x32, 0xd0, 0x33, 0x31, 0xd0, 0x35, 0x32, - 0xd0, 0x35, 0x33, 0xd0, 0x35, 0x34, 0xd0, 0x35, - 0x31, 0xd0, 0x36, 0x35, 0xd0, 0x36, 0x31, 0xd0, - 0x38, 0x33, 0xd0, 0x38, 0x35, 0xd0, 0x38, 0x37, - 0xd0, 0x38, 0x31, 0xd0, 0x49, 0x49, 0x49, 0x49, - 0x49, 0x49, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49, - 0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x49, - 0x58, 0x49, 0x49, 0x4c, 0x43, 0x44, 0x4d, 0x69, - 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76, 0x76, - 0x69, 0x76, 0x69, 0x69, 0x76, 0x69, 0x69, 0x69, - 0x69, 0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6c, - 0x63, 0x64, 0x6d, 0x30, 0xd0, 0x33, 0x90, 0x21, - 0xb8, 0x92, 0x21, 0xb8, 0x94, 0x21, 0xb8, 0xd0, - 0x21, 0xb8, 0xd4, 0x21, 0xb8, 0xd2, 0x21, 0xb8, - 0x03, 0x22, 0xb8, 0x08, 0x22, 0xb8, 0x0b, 0x22, - 0xb8, 0x23, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x25, - 0x22, 0xb8, 0x2b, 0x22, 0x2b, 0x22, 0x2b, 0x22, - 0x00, 0x00, 0x00, 0x2e, 0x22, 0x2e, 0x22, 0x2e, - 0x22, 0x00, 0x00, 0x00, 0x3c, 0x22, 0xb8, 0x43, - 0x22, 0xb8, 0x45, 0x22, 0xb8, 0x00, 0x00, 0x00, - 0x48, 0x22, 0xb8, 0x3d, 0x00, 0xb8, 0x00, 0x00, - 0x00, 0x61, 0x22, 0xb8, 0x4d, 0x22, 0xb8, 0x3c, - 0x00, 0xb8, 0x3e, 0x00, 0xb8, 0x64, 0x22, 0xb8, - 0x65, 0x22, 0xb8, 0x72, 0x22, 0xb8, 0x76, 0x22, - 0xb8, 0x7a, 0x22, 0xb8, 0x82, 0x22, 0xb8, 0x86, - 0x22, 0xb8, 0xa2, 0x22, 0xb8, 0xa8, 0x22, 0xb8, - 0xa9, 0x22, 0xb8, 0xab, 0x22, 0xb8, 0x7c, 0x22, - 0xb8, 0x91, 0x22, 0xb8, 0xb2, 0x22, 0x38, 0x03, - 0x08, 0x30, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00, - 0x32, 0x30, 0x28, 0x00, 0x31, 0x00, 0x29, 0x00, - 0x28, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29, 0x00, - 0x28, 0x32, 0x30, 0x29, 0x31, 0x00, 0x2e, 0x00, - 0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x30, - 0x2e, 0x28, 0x00, 0x61, 0x00, 0x29, 0x00, 0x41, - 0x00, 0x61, 0x00, 0x2b, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0xdd, 0x2a, 0xb8, 0x6a, 0x56, 0x00, 0x4e, - 0x00, 0x28, 0x36, 0x3f, 0x59, 0x85, 0x8c, 0xa0, - 0xba, 0x3f, 0x51, 0x00, 0x26, 0x2c, 0x43, 0x57, - 0x6c, 0xa1, 0xb6, 0xc1, 0x9b, 0x52, 0x00, 0x5e, - 0x7a, 0x7f, 0x9d, 0xa6, 0xc1, 0xce, 0xe7, 0xb6, - 0x53, 0xc8, 0x53, 0xe3, 0x53, 0xd7, 0x56, 0x1f, - 0x57, 0xeb, 0x58, 0x02, 0x59, 0x0a, 0x59, 0x15, - 0x59, 0x27, 0x59, 0x73, 0x59, 0x50, 0x5b, 0x80, - 0x5b, 0xf8, 0x5b, 0x0f, 0x5c, 0x22, 0x5c, 0x38, - 0x5c, 0x6e, 0x5c, 0x71, 0x5c, 0xdb, 0x5d, 0xe5, - 0x5d, 0xf1, 0x5d, 0xfe, 0x5d, 0x72, 0x5e, 0x7a, - 0x5e, 0x7f, 0x5e, 0xf4, 0x5e, 0xfe, 0x5e, 0x0b, - 0x5f, 0x13, 0x5f, 0x50, 0x5f, 0x61, 0x5f, 0x73, - 0x5f, 0xc3, 0x5f, 0x08, 0x62, 0x36, 0x62, 0x4b, - 0x62, 0x2f, 0x65, 0x34, 0x65, 0x87, 0x65, 0x97, - 0x65, 0xa4, 0x65, 0xb9, 0x65, 0xe0, 0x65, 0xe5, - 0x65, 0xf0, 0x66, 0x08, 0x67, 0x28, 0x67, 0x20, - 0x6b, 0x62, 0x6b, 0x79, 0x6b, 0xb3, 0x6b, 0xcb, - 0x6b, 0xd4, 0x6b, 0xdb, 0x6b, 0x0f, 0x6c, 0x14, - 0x6c, 0x34, 0x6c, 0x6b, 0x70, 0x2a, 0x72, 0x36, - 0x72, 0x3b, 0x72, 0x3f, 0x72, 0x47, 0x72, 0x59, - 0x72, 0x5b, 0x72, 0xac, 0x72, 0x84, 0x73, 0x89, - 0x73, 0xdc, 0x74, 0xe6, 0x74, 0x18, 0x75, 0x1f, - 0x75, 0x28, 0x75, 0x30, 0x75, 0x8b, 0x75, 0x92, - 0x75, 0x76, 0x76, 0x7d, 0x76, 0xae, 0x76, 0xbf, - 0x76, 0xee, 0x76, 0xdb, 0x77, 0xe2, 0x77, 0xf3, - 0x77, 0x3a, 0x79, 0xb8, 0x79, 0xbe, 0x79, 0x74, - 0x7a, 0xcb, 0x7a, 0xf9, 0x7a, 0x73, 0x7c, 0xf8, - 0x7c, 0x36, 0x7f, 0x51, 0x7f, 0x8a, 0x7f, 0xbd, - 0x7f, 0x01, 0x80, 0x0c, 0x80, 0x12, 0x80, 0x33, - 0x80, 0x7f, 0x80, 0x89, 0x80, 0xe3, 0x81, 0x00, - 0x07, 0x10, 0x19, 0x29, 0x38, 0x3c, 0x8b, 0x8f, - 0x95, 0x4d, 0x86, 0x6b, 0x86, 0x40, 0x88, 0x4c, - 0x88, 0x63, 0x88, 0x7e, 0x89, 0x8b, 0x89, 0xd2, - 0x89, 0x00, 0x8a, 0x37, 0x8c, 0x46, 0x8c, 0x55, - 0x8c, 0x78, 0x8c, 0x9d, 0x8c, 0x64, 0x8d, 0x70, - 0x8d, 0xb3, 0x8d, 0xab, 0x8e, 0xca, 0x8e, 0x9b, - 0x8f, 0xb0, 0x8f, 0xb5, 0x8f, 0x91, 0x90, 0x49, - 0x91, 0xc6, 0x91, 0xcc, 0x91, 0xd1, 0x91, 0x77, - 0x95, 0x80, 0x95, 0x1c, 0x96, 0xb6, 0x96, 0xb9, - 0x96, 0xe8, 0x96, 0x51, 0x97, 0x5e, 0x97, 0x62, - 0x97, 0x69, 0x97, 0xcb, 0x97, 0xed, 0x97, 0xf3, - 0x97, 0x01, 0x98, 0xa8, 0x98, 0xdb, 0x98, 0xdf, - 0x98, 0x96, 0x99, 0x99, 0x99, 0xac, 0x99, 0xa8, - 0x9a, 0xd8, 0x9a, 0xdf, 0x9a, 0x25, 0x9b, 0x2f, - 0x9b, 0x32, 0x9b, 0x3c, 0x9b, 0x5a, 0x9b, 0xe5, - 0x9c, 0x75, 0x9e, 0x7f, 0x9e, 0xa5, 0x9e, 0x00, - 0x16, 0x1e, 0x28, 0x2c, 0x54, 0x58, 0x69, 0x6e, - 0x7b, 0x96, 0xa5, 0xad, 0xe8, 0xf7, 0xfb, 0x12, - 0x30, 0x00, 0x00, 0x41, 0x53, 0x44, 0x53, 0x45, - 0x53, 0x4b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x4d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x4f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x51, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x53, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x55, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x57, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x59, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x5b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x5d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x5f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x61, 0x30, 0x99, 0x30, 0x64, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x68, 0x30, 0x99, - 0x30, 0x6f, 0x30, 0x99, 0x30, 0x72, 0x30, 0x99, - 0x30, 0x75, 0x30, 0x99, 0x30, 0x78, 0x30, 0x99, - 0x30, 0x7b, 0x30, 0x99, 0x30, 0x46, 0x30, 0x99, - 0x30, 0x20, 0x00, 0x99, 0x30, 0x9d, 0x30, 0x99, - 0x30, 0x88, 0x30, 0x8a, 0x30, 0xab, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xad, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x30, 0x99, - 0x30, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x30, 0x99, - 0x30, 0xc4, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0xc6, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, - 0x00, 0xc8, 0x30, 0x99, 0x30, 0xcf, 0x30, 0x99, - 0x30, 0xd2, 0x30, 0x99, 0x30, 0xd5, 0x30, 0x99, - 0x30, 0xd8, 0x30, 0x99, 0x30, 0xdb, 0x30, 0x99, - 0x30, 0xa6, 0x30, 0x99, 0x30, 0xef, 0x30, 0x99, - 0x30, 0xfd, 0x30, 0x99, 0x30, 0xb3, 0x30, 0xc8, - 0x30, 0x00, 0x11, 0x00, 0x01, 0xaa, 0x02, 0xac, - 0xad, 0x03, 0x04, 0x05, 0xb0, 0xb1, 0xb2, 0xb3, - 0xb4, 0xb5, 0x1a, 0x06, 0x07, 0x08, 0x21, 0x09, - 0x11, 0x61, 0x11, 0x14, 0x11, 0x4c, 0x00, 0x01, - 0xb3, 0xb4, 0xb8, 0xba, 0xbf, 0xc3, 0xc5, 0x08, - 0xc9, 0xcb, 0x09, 0x0a, 0x0c, 0x0e, 0x0f, 0x13, - 0x15, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x22, - 0x2c, 0x33, 0x38, 0xdd, 0xde, 0x43, 0x44, 0x45, - 0x70, 0x71, 0x74, 0x7d, 0x7e, 0x80, 0x8a, 0x8d, - 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, - 0x0a, 0x4e, 0x2d, 0x4e, 0x0b, 0x4e, 0x32, 0x75, - 0x59, 0x4e, 0x19, 0x4e, 0x01, 0x4e, 0x29, 0x59, - 0x30, 0x57, 0xba, 0x4e, 0x28, 0x00, 0x29, 0x00, - 0x00, 0x11, 0x02, 0x11, 0x03, 0x11, 0x05, 0x11, - 0x06, 0x11, 0x07, 0x11, 0x09, 0x11, 0x0b, 0x11, - 0x0c, 0x11, 0x0e, 0x11, 0x0f, 0x11, 0x10, 0x11, - 0x11, 0x11, 0x12, 0x11, 0x28, 0x00, 0x00, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x02, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x05, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x09, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0e, 0x11, - 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0c, 0x11, - 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, - 0x69, 0x11, 0x0c, 0x11, 0x65, 0x11, 0xab, 0x11, - 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, 0x69, 0x11, - 0x12, 0x11, 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, - 0x29, 0x00, 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, - 0xdb, 0x56, 0x94, 0x4e, 0x6d, 0x51, 0x03, 0x4e, - 0x6b, 0x51, 0x5d, 0x4e, 0x41, 0x53, 0x08, 0x67, - 0x6b, 0x70, 0x34, 0x6c, 0x28, 0x67, 0xd1, 0x91, - 0x1f, 0x57, 0xe5, 0x65, 0x2a, 0x68, 0x09, 0x67, - 0x3e, 0x79, 0x0d, 0x54, 0x79, 0x72, 0xa1, 0x8c, - 0x5d, 0x79, 0xb4, 0x52, 0xe3, 0x4e, 0x7c, 0x54, - 0x66, 0x5b, 0xe3, 0x76, 0x01, 0x4f, 0xc7, 0x8c, - 0x54, 0x53, 0x6d, 0x79, 0x11, 0x4f, 0xea, 0x81, - 0xf3, 0x81, 0x4f, 0x55, 0x7c, 0x5e, 0x87, 0x65, - 0x8f, 0x7b, 0x50, 0x54, 0x45, 0x32, 0x00, 0x31, - 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x11, 0x00, - 0x02, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x0c, - 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x00, 0x11, 0x00, - 0x61, 0x02, 0x61, 0x03, 0x61, 0x05, 0x61, 0x06, - 0x61, 0x07, 0x61, 0x09, 0x61, 0x0b, 0x61, 0x0c, - 0x61, 0x0e, 0x11, 0x61, 0x11, 0x00, 0x11, 0x0e, - 0x61, 0xb7, 0x00, 0x69, 0x0b, 0x11, 0x01, 0x63, - 0x00, 0x69, 0x0b, 0x11, 0x6e, 0x11, 0x00, 0x4e, - 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, 0x94, 0x4e, - 0x6d, 0x51, 0x03, 0x4e, 0x6b, 0x51, 0x5d, 0x4e, - 0x41, 0x53, 0x08, 0x67, 0x6b, 0x70, 0x34, 0x6c, - 0x28, 0x67, 0xd1, 0x91, 0x1f, 0x57, 0xe5, 0x65, - 0x2a, 0x68, 0x09, 0x67, 0x3e, 0x79, 0x0d, 0x54, - 0x79, 0x72, 0xa1, 0x8c, 0x5d, 0x79, 0xb4, 0x52, - 0xd8, 0x79, 0x37, 0x75, 0x73, 0x59, 0x69, 0x90, - 0x2a, 0x51, 0x70, 0x53, 0xe8, 0x6c, 0x05, 0x98, - 0x11, 0x4f, 0x99, 0x51, 0x63, 0x6b, 0x0a, 0x4e, - 0x2d, 0x4e, 0x0b, 0x4e, 0xe6, 0x5d, 0xf3, 0x53, - 0x3b, 0x53, 0x97, 0x5b, 0x66, 0x5b, 0xe3, 0x76, - 0x01, 0x4f, 0xc7, 0x8c, 0x54, 0x53, 0x1c, 0x59, - 0x33, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00, - 0x35, 0x30, 0x31, 0x00, 0x08, 0x67, 0x31, 0x00, - 0x30, 0x00, 0x08, 0x67, 0x48, 0x67, 0x65, 0x72, - 0x67, 0x65, 0x56, 0x4c, 0x54, 0x44, 0xa2, 0x30, - 0x00, 0x02, 0x04, 0x06, 0x08, 0x09, 0x0b, 0x0d, - 0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, - 0x1f, 0x22, 0x24, 0x26, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3d, - 0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0xe4, - 0x4e, 0x8c, 0x54, 0xa1, 0x30, 0x01, 0x30, 0x5b, - 0x27, 0x01, 0x4a, 0x34, 0x00, 0x01, 0x52, 0x39, - 0x01, 0xa2, 0x30, 0x00, 0x5a, 0x49, 0xa4, 0x30, - 0x00, 0x27, 0x4f, 0x0c, 0xa4, 0x30, 0x00, 0x4f, - 0x1d, 0x02, 0x05, 0x4f, 0xa8, 0x30, 0x00, 0x11, - 0x07, 0x54, 0x21, 0xa8, 0x30, 0x00, 0x54, 0x03, - 0x54, 0xa4, 0x30, 0x06, 0x4f, 0x15, 0x06, 0x58, - 0x3c, 0x07, 0x00, 0x46, 0xab, 0x30, 0x00, 0x3e, - 0x18, 0x1d, 0x00, 0x42, 0x3f, 0x51, 0xac, 0x30, - 0x00, 0x41, 0x47, 0x00, 0x47, 0x32, 0xae, 0x30, - 0xac, 0x30, 0xae, 0x30, 0x00, 0x1d, 0x4e, 0xad, - 0x30, 0x00, 0x38, 0x3d, 0x4f, 0x01, 0x3e, 0x13, - 0x4f, 0xad, 0x30, 0xed, 0x30, 0xad, 0x30, 0x00, - 0x40, 0x03, 0x3c, 0x33, 0xad, 0x30, 0x00, 0x40, - 0x34, 0x4f, 0x1b, 0x3e, 0xad, 0x30, 0x00, 0x40, - 0x42, 0x16, 0x1b, 0xb0, 0x30, 0x00, 0x39, 0x30, - 0xa4, 0x30, 0x0c, 0x45, 0x3c, 0x24, 0x4f, 0x0b, - 0x47, 0x18, 0x00, 0x49, 0xaf, 0x30, 0x00, 0x3e, - 0x4d, 0x1e, 0xb1, 0x30, 0x00, 0x4b, 0x08, 0x02, - 0x3a, 0x19, 0x02, 0x4b, 0x2c, 0xa4, 0x30, 0x11, - 0x00, 0x0b, 0x47, 0xb5, 0x30, 0x00, 0x3e, 0x0c, - 0x47, 0x2b, 0xb0, 0x30, 0x07, 0x3a, 0x43, 0x00, - 0xb9, 0x30, 0x02, 0x3a, 0x08, 0x02, 0x3a, 0x0f, - 0x07, 0x43, 0x00, 0xb7, 0x30, 0x10, 0x00, 0x12, - 0x34, 0x11, 0x3c, 0x13, 0x17, 0xa4, 0x30, 0x2a, - 0x1f, 0x24, 0x2b, 0x00, 0x20, 0xbb, 0x30, 0x16, - 0x41, 0x00, 0x38, 0x0d, 0xc4, 0x30, 0x0d, 0x38, - 0x00, 0xd0, 0x30, 0x00, 0x2c, 0x1c, 0x1b, 0xa2, - 0x30, 0x32, 0x00, 0x17, 0x26, 0x49, 0xaf, 0x30, - 0x25, 0x00, 0x3c, 0xb3, 0x30, 0x21, 0x00, 0x20, - 0x38, 0xa1, 0x30, 0x34, 0x00, 0x48, 0x22, 0x28, - 0xa3, 0x30, 0x32, 0x00, 0x59, 0x25, 0xa7, 0x30, - 0x2f, 0x1c, 0x10, 0x00, 0x44, 0xd5, 0x30, 0x00, - 0x14, 0x1e, 0xaf, 0x30, 0x29, 0x00, 0x10, 0x4d, - 0x3c, 0xda, 0x30, 0xbd, 0x30, 0xb8, 0x30, 0x22, - 0x13, 0x1a, 0x20, 0x33, 0x0c, 0x22, 0x3b, 0x01, - 0x22, 0x44, 0x00, 0x21, 0x44, 0x07, 0xa4, 0x30, - 0x39, 0x00, 0x4f, 0x24, 0xc8, 0x30, 0x14, 0x23, - 0x00, 0xdb, 0x30, 0xf3, 0x30, 0xc9, 0x30, 0x14, - 0x2a, 0x00, 0x12, 0x33, 0x22, 0x12, 0x33, 0x2a, - 0xa4, 0x30, 0x3a, 0x00, 0x0b, 0x49, 0xa4, 0x30, - 0x3a, 0x00, 0x47, 0x3a, 0x1f, 0x2b, 0x3a, 0x47, - 0x0b, 0xb7, 0x30, 0x27, 0x3c, 0x00, 0x30, 0x3c, - 0xaf, 0x30, 0x30, 0x00, 0x3e, 0x44, 0xdf, 0x30, - 0xea, 0x30, 0xd0, 0x30, 0x0f, 0x1a, 0x00, 0x2c, - 0x1b, 0xe1, 0x30, 0xac, 0x30, 0xac, 0x30, 0x35, - 0x00, 0x1c, 0x47, 0x35, 0x50, 0x1c, 0x3f, 0xa2, - 0x30, 0x42, 0x5a, 0x27, 0x42, 0x5a, 0x49, 0x44, - 0x00, 0x51, 0xc3, 0x30, 0x27, 0x00, 0x05, 0x28, - 0xea, 0x30, 0xe9, 0x30, 0xd4, 0x30, 0x17, 0x00, - 0x28, 0xd6, 0x30, 0x15, 0x26, 0x00, 0x15, 0xec, - 0x30, 0xe0, 0x30, 0xb2, 0x30, 0x3a, 0x41, 0x16, - 0x00, 0x41, 0xc3, 0x30, 0x2c, 0x00, 0x05, 0x30, - 0x00, 0xb9, 0x70, 0x31, 0x00, 0x30, 0x00, 0xb9, - 0x70, 0x32, 0x00, 0x30, 0x00, 0xb9, 0x70, 0x68, - 0x50, 0x61, 0x64, 0x61, 0x41, 0x55, 0x62, 0x61, - 0x72, 0x6f, 0x56, 0x70, 0x63, 0x64, 0x6d, 0x64, - 0x00, 0x6d, 0x00, 0xb2, 0x00, 0x49, 0x00, 0x55, - 0x00, 0x73, 0x5e, 0x10, 0x62, 0x2d, 0x66, 0x8c, - 0x54, 0x27, 0x59, 0x63, 0x6b, 0x0e, 0x66, 0xbb, - 0x6c, 0x2a, 0x68, 0x0f, 0x5f, 0x1a, 0x4f, 0x3e, - 0x79, 0x70, 0x00, 0x41, 0x6e, 0x00, 0x41, 0xbc, - 0x03, 0x41, 0x6d, 0x00, 0x41, 0x6b, 0x00, 0x41, - 0x4b, 0x00, 0x42, 0x4d, 0x00, 0x42, 0x47, 0x00, - 0x42, 0x63, 0x61, 0x6c, 0x6b, 0x63, 0x61, 0x6c, - 0x70, 0x00, 0x46, 0x6e, 0x00, 0x46, 0xbc, 0x03, - 0x46, 0xbc, 0x03, 0x67, 0x6d, 0x00, 0x67, 0x6b, - 0x00, 0x67, 0x48, 0x00, 0x7a, 0x6b, 0x48, 0x7a, - 0x4d, 0x48, 0x7a, 0x47, 0x48, 0x7a, 0x54, 0x48, - 0x7a, 0xbc, 0x03, 0x13, 0x21, 0x6d, 0x00, 0x13, - 0x21, 0x64, 0x00, 0x13, 0x21, 0x6b, 0x00, 0x13, - 0x21, 0x66, 0x00, 0x6d, 0x6e, 0x00, 0x6d, 0xbc, - 0x03, 0x6d, 0x6d, 0x00, 0x6d, 0x63, 0x00, 0x6d, - 0x6b, 0x00, 0x6d, 0x63, 0x00, 0x0a, 0x0a, 0x4f, - 0x00, 0x0a, 0x4f, 0x6d, 0x00, 0xb2, 0x00, 0x63, - 0x00, 0x08, 0x0a, 0x4f, 0x0a, 0x0a, 0x50, 0x00, - 0x0a, 0x50, 0x6d, 0x00, 0xb3, 0x00, 0x6b, 0x00, - 0x6d, 0x00, 0xb3, 0x00, 0x6d, 0x00, 0x15, 0x22, - 0x73, 0x00, 0x6d, 0x00, 0x15, 0x22, 0x73, 0x00, - 0xb2, 0x00, 0x50, 0x61, 0x6b, 0x50, 0x61, 0x4d, - 0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64, - 0x72, 0x61, 0x64, 0xd1, 0x73, 0x72, 0x00, 0x61, - 0x00, 0x64, 0x00, 0x15, 0x22, 0x73, 0x00, 0xb2, - 0x00, 0x70, 0x00, 0x73, 0x6e, 0x00, 0x73, 0xbc, - 0x03, 0x73, 0x6d, 0x00, 0x73, 0x70, 0x00, 0x56, - 0x6e, 0x00, 0x56, 0xbc, 0x03, 0x56, 0x6d, 0x00, - 0x56, 0x6b, 0x00, 0x56, 0x4d, 0x00, 0x56, 0x70, - 0x00, 0x57, 0x6e, 0x00, 0x57, 0xbc, 0x03, 0x57, - 0x6d, 0x00, 0x57, 0x6b, 0x00, 0x57, 0x4d, 0x00, - 0x57, 0x6b, 0x00, 0xa9, 0x03, 0x4d, 0x00, 0xa9, - 0x03, 0x61, 0x2e, 0x6d, 0x2e, 0x42, 0x71, 0x63, - 0x63, 0x63, 0x64, 0x43, 0xd1, 0x6b, 0x67, 0x43, - 0x6f, 0x2e, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61, - 0x48, 0x50, 0x69, 0x6e, 0x4b, 0x4b, 0x4b, 0x4d, - 0x6b, 0x74, 0x6c, 0x6d, 0x6c, 0x6e, 0x6c, 0x6f, - 0x67, 0x6c, 0x78, 0x6d, 0x62, 0x6d, 0x69, 0x6c, - 0x6d, 0x6f, 0x6c, 0x50, 0x48, 0x70, 0x2e, 0x6d, - 0x2e, 0x50, 0x50, 0x4d, 0x50, 0x52, 0x73, 0x72, - 0x53, 0x76, 0x57, 0x62, 0x56, 0xd1, 0x6d, 0x41, - 0xd1, 0x6d, 0x31, 0x00, 0xe5, 0x65, 0x31, 0x00, - 0x30, 0x00, 0xe5, 0x65, 0x32, 0x00, 0x30, 0x00, - 0xe5, 0x65, 0x33, 0x00, 0x30, 0x00, 0xe5, 0x65, - 0x67, 0x61, 0x6c, 0x4a, 0x04, 0x4c, 0x04, 0x26, - 0x01, 0x53, 0x01, 0x27, 0xa7, 0x37, 0xab, 0x6b, - 0x02, 0x52, 0xab, 0x48, 0x8c, 0xf4, 0x66, 0xca, - 0x8e, 0xc8, 0x8c, 0xd1, 0x6e, 0x32, 0x4e, 0xe5, - 0x53, 0x9c, 0x9f, 0x9c, 0x9f, 0x51, 0x59, 0xd1, - 0x91, 0x87, 0x55, 0x48, 0x59, 0xf6, 0x61, 0x69, - 0x76, 0x85, 0x7f, 0x3f, 0x86, 0xba, 0x87, 0xf8, - 0x88, 0x8f, 0x90, 0x02, 0x6a, 0x1b, 0x6d, 0xd9, - 0x70, 0xde, 0x73, 0x3d, 0x84, 0x6a, 0x91, 0xf1, - 0x99, 0x82, 0x4e, 0x75, 0x53, 0x04, 0x6b, 0x1b, - 0x72, 0x2d, 0x86, 0x1e, 0x9e, 0x50, 0x5d, 0xeb, - 0x6f, 0xcd, 0x85, 0x64, 0x89, 0xc9, 0x62, 0xd8, - 0x81, 0x1f, 0x88, 0xca, 0x5e, 0x17, 0x67, 0x6a, - 0x6d, 0xfc, 0x72, 0xce, 0x90, 0x86, 0x4f, 0xb7, - 0x51, 0xde, 0x52, 0xc4, 0x64, 0xd3, 0x6a, 0x10, - 0x72, 0xe7, 0x76, 0x01, 0x80, 0x06, 0x86, 0x5c, - 0x86, 0xef, 0x8d, 0x32, 0x97, 0x6f, 0x9b, 0xfa, - 0x9d, 0x8c, 0x78, 0x7f, 0x79, 0xa0, 0x7d, 0xc9, - 0x83, 0x04, 0x93, 0x7f, 0x9e, 0xd6, 0x8a, 0xdf, - 0x58, 0x04, 0x5f, 0x60, 0x7c, 0x7e, 0x80, 0x62, - 0x72, 0xca, 0x78, 0xc2, 0x8c, 0xf7, 0x96, 0xd8, - 0x58, 0x62, 0x5c, 0x13, 0x6a, 0xda, 0x6d, 0x0f, - 0x6f, 0x2f, 0x7d, 0x37, 0x7e, 0x4b, 0x96, 0xd2, - 0x52, 0x8b, 0x80, 0xdc, 0x51, 0xcc, 0x51, 0x1c, - 0x7a, 0xbe, 0x7d, 0xf1, 0x83, 0x75, 0x96, 0x80, - 0x8b, 0xcf, 0x62, 0x02, 0x6a, 0xfe, 0x8a, 0x39, - 0x4e, 0xe7, 0x5b, 0x12, 0x60, 0x87, 0x73, 0x70, - 0x75, 0x17, 0x53, 0xfb, 0x78, 0xbf, 0x4f, 0xa9, - 0x5f, 0x0d, 0x4e, 0xcc, 0x6c, 0x78, 0x65, 0x22, - 0x7d, 0xc3, 0x53, 0x5e, 0x58, 0x01, 0x77, 0x49, - 0x84, 0xaa, 0x8a, 0xba, 0x6b, 0xb0, 0x8f, 0x88, - 0x6c, 0xfe, 0x62, 0xe5, 0x82, 0xa0, 0x63, 0x65, - 0x75, 0xae, 0x4e, 0x69, 0x51, 0xc9, 0x51, 0x81, - 0x68, 0xe7, 0x7c, 0x6f, 0x82, 0xd2, 0x8a, 0xcf, - 0x91, 0xf5, 0x52, 0x42, 0x54, 0x73, 0x59, 0xec, - 0x5e, 0xc5, 0x65, 0xfe, 0x6f, 0x2a, 0x79, 0xad, - 0x95, 0x6a, 0x9a, 0x97, 0x9e, 0xce, 0x9e, 0x9b, - 0x52, 0xc6, 0x66, 0x77, 0x6b, 0x62, 0x8f, 0x74, - 0x5e, 0x90, 0x61, 0x00, 0x62, 0x9a, 0x64, 0x23, - 0x6f, 0x49, 0x71, 0x89, 0x74, 0xca, 0x79, 0xf4, - 0x7d, 0x6f, 0x80, 0x26, 0x8f, 0xee, 0x84, 0x23, - 0x90, 0x4a, 0x93, 0x17, 0x52, 0xa3, 0x52, 0xbd, - 0x54, 0xc8, 0x70, 0xc2, 0x88, 0xaa, 0x8a, 0xc9, - 0x5e, 0xf5, 0x5f, 0x7b, 0x63, 0xae, 0x6b, 0x3e, - 0x7c, 0x75, 0x73, 0xe4, 0x4e, 0xf9, 0x56, 0xe7, - 0x5b, 0xba, 0x5d, 0x1c, 0x60, 0xb2, 0x73, 0x69, - 0x74, 0x9a, 0x7f, 0x46, 0x80, 0x34, 0x92, 0xf6, - 0x96, 0x48, 0x97, 0x18, 0x98, 0x8b, 0x4f, 0xae, - 0x79, 0xb4, 0x91, 0xb8, 0x96, 0xe1, 0x60, 0x86, - 0x4e, 0xda, 0x50, 0xee, 0x5b, 0x3f, 0x5c, 0x99, - 0x65, 0x02, 0x6a, 0xce, 0x71, 0x42, 0x76, 0xfc, - 0x84, 0x7c, 0x90, 0x8d, 0x9f, 0x88, 0x66, 0x2e, - 0x96, 0x89, 0x52, 0x7b, 0x67, 0xf3, 0x67, 0x41, - 0x6d, 0x9c, 0x6e, 0x09, 0x74, 0x59, 0x75, 0x6b, - 0x78, 0x10, 0x7d, 0x5e, 0x98, 0x6d, 0x51, 0x2e, - 0x62, 0x78, 0x96, 0x2b, 0x50, 0x19, 0x5d, 0xea, - 0x6d, 0x2a, 0x8f, 0x8b, 0x5f, 0x44, 0x61, 0x17, - 0x68, 0x87, 0x73, 0x86, 0x96, 0x29, 0x52, 0x0f, - 0x54, 0x65, 0x5c, 0x13, 0x66, 0x4e, 0x67, 0xa8, - 0x68, 0xe5, 0x6c, 0x06, 0x74, 0xe2, 0x75, 0x79, - 0x7f, 0xcf, 0x88, 0xe1, 0x88, 0xcc, 0x91, 0xe2, - 0x96, 0x3f, 0x53, 0xba, 0x6e, 0x1d, 0x54, 0xd0, - 0x71, 0x98, 0x74, 0xfa, 0x85, 0xa3, 0x96, 0x57, - 0x9c, 0x9f, 0x9e, 0x97, 0x67, 0xcb, 0x6d, 0xe8, - 0x81, 0xcb, 0x7a, 0x20, 0x7b, 0x92, 0x7c, 0xc0, - 0x72, 0x99, 0x70, 0x58, 0x8b, 0xc0, 0x4e, 0x36, - 0x83, 0x3a, 0x52, 0x07, 0x52, 0xa6, 0x5e, 0xd3, - 0x62, 0xd6, 0x7c, 0x85, 0x5b, 0x1e, 0x6d, 0xb4, - 0x66, 0x3b, 0x8f, 0x4c, 0x88, 0x4d, 0x96, 0x8b, - 0x89, 0xd3, 0x5e, 0x40, 0x51, 0xc0, 0x55, 0x00, - 0x00, 0x00, 0x00, 0x5a, 0x58, 0x00, 0x00, 0x74, - 0x66, 0x00, 0x00, 0x00, 0x00, 0xde, 0x51, 0x2a, - 0x73, 0xca, 0x76, 0x3c, 0x79, 0x5e, 0x79, 0x65, - 0x79, 0x8f, 0x79, 0x56, 0x97, 0xbe, 0x7c, 0xbd, - 0x7f, 0x00, 0x00, 0x12, 0x86, 0x00, 0x00, 0xf8, - 0x8a, 0x00, 0x00, 0x00, 0x00, 0x38, 0x90, 0xfd, - 0x90, 0xef, 0x98, 0xfc, 0x98, 0x28, 0x99, 0xb4, - 0x9d, 0xde, 0x90, 0xb7, 0x96, 0xae, 0x4f, 0xe7, - 0x50, 0x4d, 0x51, 0xc9, 0x52, 0xe4, 0x52, 0x51, - 0x53, 0x9d, 0x55, 0x06, 0x56, 0x68, 0x56, 0x40, - 0x58, 0xa8, 0x58, 0x64, 0x5c, 0x6e, 0x5c, 0x94, - 0x60, 0x68, 0x61, 0x8e, 0x61, 0xf2, 0x61, 0x4f, - 0x65, 0xe2, 0x65, 0x91, 0x66, 0x85, 0x68, 0x77, - 0x6d, 0x1a, 0x6e, 0x22, 0x6f, 0x6e, 0x71, 0x2b, - 0x72, 0x22, 0x74, 0x91, 0x78, 0x3e, 0x79, 0x49, - 0x79, 0x48, 0x79, 0x50, 0x79, 0x56, 0x79, 0x5d, - 0x79, 0x8d, 0x79, 0x8e, 0x79, 0x40, 0x7a, 0x81, - 0x7a, 0xc0, 0x7b, 0xf4, 0x7d, 0x09, 0x7e, 0x41, - 0x7e, 0x72, 0x7f, 0x05, 0x80, 0xed, 0x81, 0x79, - 0x82, 0x79, 0x82, 0x57, 0x84, 0x10, 0x89, 0x96, - 0x89, 0x01, 0x8b, 0x39, 0x8b, 0xd3, 0x8c, 0x08, - 0x8d, 0xb6, 0x8f, 0x38, 0x90, 0xe3, 0x96, 0xff, - 0x97, 0x3b, 0x98, 0x75, 0x60, 0xee, 0x42, 0x18, - 0x82, 0x02, 0x26, 0x4e, 0xb5, 0x51, 0x68, 0x51, - 0x80, 0x4f, 0x45, 0x51, 0x80, 0x51, 0xc7, 0x52, - 0xfa, 0x52, 0x9d, 0x55, 0x55, 0x55, 0x99, 0x55, - 0xe2, 0x55, 0x5a, 0x58, 0xb3, 0x58, 0x44, 0x59, - 0x54, 0x59, 0x62, 0x5a, 0x28, 0x5b, 0xd2, 0x5e, - 0xd9, 0x5e, 0x69, 0x5f, 0xad, 0x5f, 0xd8, 0x60, - 0x4e, 0x61, 0x08, 0x61, 0x8e, 0x61, 0x60, 0x61, - 0xf2, 0x61, 0x34, 0x62, 0xc4, 0x63, 0x1c, 0x64, - 0x52, 0x64, 0x56, 0x65, 0x74, 0x66, 0x17, 0x67, - 0x1b, 0x67, 0x56, 0x67, 0x79, 0x6b, 0xba, 0x6b, - 0x41, 0x6d, 0xdb, 0x6e, 0xcb, 0x6e, 0x22, 0x6f, - 0x1e, 0x70, 0x6e, 0x71, 0xa7, 0x77, 0x35, 0x72, - 0xaf, 0x72, 0x2a, 0x73, 0x71, 0x74, 0x06, 0x75, - 0x3b, 0x75, 0x1d, 0x76, 0x1f, 0x76, 0xca, 0x76, - 0xdb, 0x76, 0xf4, 0x76, 0x4a, 0x77, 0x40, 0x77, - 0xcc, 0x78, 0xb1, 0x7a, 0xc0, 0x7b, 0x7b, 0x7c, - 0x5b, 0x7d, 0xf4, 0x7d, 0x3e, 0x7f, 0x05, 0x80, - 0x52, 0x83, 0xef, 0x83, 0x79, 0x87, 0x41, 0x89, - 0x86, 0x89, 0x96, 0x89, 0xbf, 0x8a, 0xf8, 0x8a, - 0xcb, 0x8a, 0x01, 0x8b, 0xfe, 0x8a, 0xed, 0x8a, - 0x39, 0x8b, 0x8a, 0x8b, 0x08, 0x8d, 0x38, 0x8f, - 0x72, 0x90, 0x99, 0x91, 0x76, 0x92, 0x7c, 0x96, - 0xe3, 0x96, 0x56, 0x97, 0xdb, 0x97, 0xff, 0x97, - 0x0b, 0x98, 0x3b, 0x98, 0x12, 0x9b, 0x9c, 0x9f, - 0x4a, 0x28, 0x44, 0x28, 0xd5, 0x33, 0x9d, 0x3b, - 0x18, 0x40, 0x39, 0x40, 0x49, 0x52, 0xd0, 0x5c, - 0xd3, 0x7e, 0x43, 0x9f, 0x8e, 0x9f, 0x2a, 0xa0, - 0x02, 0x66, 0x66, 0x66, 0x69, 0x66, 0x6c, 0x66, - 0x66, 0x69, 0x66, 0x66, 0x6c, 0x7f, 0x01, 0x74, - 0x73, 0x00, 0x74, 0x65, 0x05, 0x0f, 0x11, 0x0f, - 0x00, 0x0f, 0x06, 0x19, 0x11, 0x0f, 0x08, 0xd9, - 0x05, 0xb4, 0x05, 0x00, 0x00, 0x00, 0x00, 0xf2, - 0x05, 0xb7, 0x05, 0xd0, 0x05, 0x12, 0x00, 0x03, - 0x04, 0x0b, 0x0c, 0x0d, 0x18, 0x1a, 0xe9, 0x05, - 0xc1, 0x05, 0xe9, 0x05, 0xc2, 0x05, 0x49, 0xfb, - 0xc1, 0x05, 0x49, 0xfb, 0xc2, 0x05, 0xd0, 0x05, - 0xb7, 0x05, 0xd0, 0x05, 0xb8, 0x05, 0xd0, 0x05, - 0xbc, 0x05, 0xd8, 0x05, 0xbc, 0x05, 0xde, 0x05, - 0xbc, 0x05, 0xe0, 0x05, 0xbc, 0x05, 0xe3, 0x05, - 0xbc, 0x05, 0xb9, 0x05, 0x2d, 0x03, 0x2e, 0x03, - 0x2f, 0x03, 0x30, 0x03, 0x31, 0x03, 0x1c, 0x00, - 0x18, 0x06, 0x22, 0x06, 0x2b, 0x06, 0xd0, 0x05, - 0xdc, 0x05, 0x71, 0x06, 0x00, 0x00, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0d, 0x0d, 0x0d, 0x0d, 0x0f, 0x0f, - 0x0f, 0x0f, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, - 0x0e, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x33, 0x33, - 0x33, 0x33, 0x35, 0x35, 0x35, 0x35, 0x13, 0x13, - 0x13, 0x13, 0x12, 0x12, 0x12, 0x12, 0x15, 0x15, - 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x1c, 0x1c, - 0x1b, 0x1b, 0x1d, 0x1d, 0x17, 0x17, 0x27, 0x27, - 0x20, 0x20, 0x38, 0x38, 0x38, 0x38, 0x3e, 0x3e, - 0x3e, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x40, 0x40, - 0x40, 0x40, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, - 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x4d, 0x4d, - 0x4d, 0x4d, 0x61, 0x61, 0x62, 0x62, 0x49, 0x06, - 0x64, 0x64, 0x64, 0x64, 0x7e, 0x7e, 0x7d, 0x7d, - 0x7f, 0x7f, 0x2e, 0x82, 0x82, 0x7c, 0x7c, 0x80, - 0x80, 0x87, 0x87, 0x87, 0x87, 0x00, 0x00, 0x26, - 0x06, 0x00, 0x01, 0x00, 0x01, 0x00, 0xaf, 0x00, - 0xaf, 0x00, 0x22, 0x00, 0x22, 0x00, 0xa1, 0x00, - 0xa1, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa2, 0x00, - 0xa2, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, - 0x23, 0x00, 0x23, 0x00, 0x23, 0xcc, 0x06, 0x00, - 0x00, 0x00, 0x00, 0x26, 0x06, 0x00, 0x06, 0x00, - 0x07, 0x00, 0x1f, 0x00, 0x23, 0x00, 0x24, 0x02, - 0x06, 0x02, 0x07, 0x02, 0x08, 0x02, 0x1f, 0x02, - 0x23, 0x02, 0x24, 0x04, 0x06, 0x04, 0x07, 0x04, - 0x08, 0x04, 0x1f, 0x04, 0x23, 0x04, 0x24, 0x05, - 0x06, 0x05, 0x1f, 0x05, 0x23, 0x05, 0x24, 0x06, - 0x07, 0x06, 0x1f, 0x07, 0x06, 0x07, 0x1f, 0x08, - 0x06, 0x08, 0x07, 0x08, 0x1f, 0x0d, 0x06, 0x0d, - 0x07, 0x0d, 0x08, 0x0d, 0x1f, 0x0f, 0x07, 0x0f, - 0x1f, 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, - 0x1f, 0x11, 0x07, 0x11, 0x1f, 0x12, 0x1f, 0x13, - 0x06, 0x13, 0x1f, 0x14, 0x06, 0x14, 0x1f, 0x1b, - 0x06, 0x1b, 0x07, 0x1b, 0x08, 0x1b, 0x1f, 0x1b, - 0x23, 0x1b, 0x24, 0x1c, 0x07, 0x1c, 0x1f, 0x1c, - 0x23, 0x1c, 0x24, 0x1d, 0x01, 0x1d, 0x06, 0x1d, - 0x07, 0x1d, 0x08, 0x1d, 0x1e, 0x1d, 0x1f, 0x1d, - 0x23, 0x1d, 0x24, 0x1e, 0x06, 0x1e, 0x07, 0x1e, - 0x08, 0x1e, 0x1f, 0x1e, 0x23, 0x1e, 0x24, 0x1f, - 0x06, 0x1f, 0x07, 0x1f, 0x08, 0x1f, 0x1f, 0x1f, - 0x23, 0x1f, 0x24, 0x20, 0x06, 0x20, 0x07, 0x20, - 0x08, 0x20, 0x1f, 0x20, 0x23, 0x20, 0x24, 0x21, - 0x06, 0x21, 0x1f, 0x21, 0x23, 0x21, 0x24, 0x24, - 0x06, 0x24, 0x07, 0x24, 0x08, 0x24, 0x1f, 0x24, - 0x23, 0x24, 0x24, 0x0a, 0x4a, 0x0b, 0x4a, 0x23, - 0x4a, 0x20, 0x00, 0x4c, 0x06, 0x51, 0x06, 0x51, - 0x06, 0xff, 0x00, 0x1f, 0x26, 0x06, 0x00, 0x0b, - 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x23, - 0x00, 0x24, 0x02, 0x0b, 0x02, 0x0c, 0x02, 0x1f, - 0x02, 0x20, 0x02, 0x23, 0x02, 0x24, 0x04, 0x0b, - 0x04, 0x0c, 0x04, 0x1f, 0x26, 0x06, 0x04, 0x20, - 0x04, 0x23, 0x04, 0x24, 0x05, 0x0b, 0x05, 0x0c, - 0x05, 0x1f, 0x05, 0x20, 0x05, 0x23, 0x05, 0x24, - 0x1b, 0x23, 0x1b, 0x24, 0x1c, 0x23, 0x1c, 0x24, - 0x1d, 0x01, 0x1d, 0x1e, 0x1d, 0x1f, 0x1d, 0x23, - 0x1d, 0x24, 0x1e, 0x1f, 0x1e, 0x23, 0x1e, 0x24, - 0x1f, 0x01, 0x1f, 0x1f, 0x20, 0x0b, 0x20, 0x0c, - 0x20, 0x1f, 0x20, 0x20, 0x20, 0x23, 0x20, 0x24, - 0x23, 0x4a, 0x24, 0x0b, 0x24, 0x0c, 0x24, 0x1f, - 0x24, 0x20, 0x24, 0x23, 0x24, 0x24, 0x00, 0x06, - 0x00, 0x07, 0x00, 0x08, 0x00, 0x1f, 0x00, 0x21, - 0x02, 0x06, 0x02, 0x07, 0x02, 0x08, 0x02, 0x1f, - 0x02, 0x21, 0x04, 0x06, 0x04, 0x07, 0x04, 0x08, - 0x04, 0x1f, 0x04, 0x21, 0x05, 0x1f, 0x06, 0x07, - 0x06, 0x1f, 0x07, 0x06, 0x07, 0x1f, 0x08, 0x06, - 0x08, 0x1f, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x08, - 0x0d, 0x1f, 0x0f, 0x07, 0x0f, 0x08, 0x0f, 0x1f, - 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, 0x1f, - 0x11, 0x07, 0x12, 0x1f, 0x13, 0x06, 0x13, 0x1f, - 0x14, 0x06, 0x14, 0x1f, 0x1b, 0x06, 0x1b, 0x07, - 0x1b, 0x08, 0x1b, 0x1f, 0x1c, 0x07, 0x1c, 0x1f, - 0x1d, 0x06, 0x1d, 0x07, 0x1d, 0x08, 0x1d, 0x1e, - 0x1d, 0x1f, 0x1e, 0x06, 0x1e, 0x07, 0x1e, 0x08, - 0x1e, 0x1f, 0x1e, 0x21, 0x1f, 0x06, 0x1f, 0x07, - 0x1f, 0x08, 0x1f, 0x1f, 0x20, 0x06, 0x20, 0x07, - 0x20, 0x08, 0x20, 0x1f, 0x20, 0x21, 0x21, 0x06, - 0x21, 0x1f, 0x21, 0x4a, 0x24, 0x06, 0x24, 0x07, - 0x24, 0x08, 0x24, 0x1f, 0x24, 0x21, 0x00, 0x1f, - 0x00, 0x21, 0x02, 0x1f, 0x02, 0x21, 0x04, 0x1f, - 0x04, 0x21, 0x05, 0x1f, 0x05, 0x21, 0x0d, 0x1f, - 0x0d, 0x21, 0x0e, 0x1f, 0x0e, 0x21, 0x1d, 0x1e, - 0x1d, 0x1f, 0x1e, 0x1f, 0x20, 0x1f, 0x20, 0x21, - 0x24, 0x1f, 0x24, 0x21, 0x40, 0x06, 0x4e, 0x06, - 0x51, 0x06, 0x27, 0x06, 0x10, 0x22, 0x10, 0x23, - 0x12, 0x22, 0x12, 0x23, 0x13, 0x22, 0x13, 0x23, - 0x0c, 0x22, 0x0c, 0x23, 0x0d, 0x22, 0x0d, 0x23, - 0x06, 0x22, 0x06, 0x23, 0x05, 0x22, 0x05, 0x23, - 0x07, 0x22, 0x07, 0x23, 0x0e, 0x22, 0x0e, 0x23, - 0x0f, 0x22, 0x0f, 0x23, 0x0d, 0x05, 0x0d, 0x06, - 0x0d, 0x07, 0x0d, 0x1e, 0x0d, 0x0a, 0x0c, 0x0a, - 0x0e, 0x0a, 0x0f, 0x0a, 0x10, 0x22, 0x10, 0x23, - 0x12, 0x22, 0x12, 0x23, 0x13, 0x22, 0x13, 0x23, - 0x0c, 0x22, 0x0c, 0x23, 0x0d, 0x22, 0x0d, 0x23, - 0x06, 0x22, 0x06, 0x23, 0x05, 0x22, 0x05, 0x23, - 0x07, 0x22, 0x07, 0x23, 0x0e, 0x22, 0x0e, 0x23, - 0x0f, 0x22, 0x0f, 0x23, 0x0d, 0x05, 0x0d, 0x06, - 0x0d, 0x07, 0x0d, 0x1e, 0x0d, 0x0a, 0x0c, 0x0a, - 0x0e, 0x0a, 0x0f, 0x0a, 0x0d, 0x05, 0x0d, 0x06, - 0x0d, 0x07, 0x0d, 0x1e, 0x0c, 0x20, 0x0d, 0x20, - 0x10, 0x1e, 0x0c, 0x05, 0x0c, 0x06, 0x0c, 0x07, - 0x0d, 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x10, 0x1e, - 0x11, 0x1e, 0x00, 0x24, 0x00, 0x24, 0x2a, 0x06, - 0x00, 0x02, 0x1b, 0x00, 0x03, 0x02, 0x00, 0x03, - 0x02, 0x00, 0x03, 0x1b, 0x00, 0x04, 0x1b, 0x00, - 0x1b, 0x02, 0x00, 0x1b, 0x03, 0x00, 0x1b, 0x04, - 0x02, 0x1b, 0x03, 0x02, 0x1b, 0x03, 0x03, 0x1b, - 0x20, 0x03, 0x1b, 0x1f, 0x09, 0x03, 0x02, 0x09, - 0x02, 0x03, 0x09, 0x02, 0x1f, 0x09, 0x1b, 0x03, - 0x09, 0x1b, 0x03, 0x09, 0x1b, 0x02, 0x09, 0x1b, - 0x1b, 0x09, 0x1b, 0x1b, 0x0b, 0x03, 0x03, 0x0b, - 0x03, 0x03, 0x0b, 0x1b, 0x1b, 0x0a, 0x03, 0x1b, - 0x0a, 0x03, 0x1b, 0x0a, 0x02, 0x20, 0x0a, 0x1b, - 0x04, 0x0a, 0x1b, 0x04, 0x0a, 0x1b, 0x1b, 0x0a, - 0x1b, 0x1b, 0x0c, 0x03, 0x1f, 0x0c, 0x04, 0x1b, - 0x0c, 0x04, 0x1b, 0x0d, 0x1b, 0x03, 0x0d, 0x1b, - 0x03, 0x0d, 0x1b, 0x1b, 0x0d, 0x1b, 0x20, 0x0f, - 0x02, 0x1b, 0x0f, 0x1b, 0x1b, 0x0f, 0x1b, 0x1b, - 0x0f, 0x1b, 0x1f, 0x10, 0x1b, 0x1b, 0x10, 0x1b, - 0x20, 0x10, 0x1b, 0x1f, 0x17, 0x04, 0x1b, 0x17, - 0x04, 0x1b, 0x18, 0x1b, 0x03, 0x18, 0x1b, 0x1b, - 0x1a, 0x03, 0x1b, 0x1a, 0x03, 0x20, 0x1a, 0x03, - 0x1f, 0x1a, 0x02, 0x02, 0x1a, 0x02, 0x02, 0x1a, - 0x04, 0x1b, 0x1a, 0x04, 0x1b, 0x1a, 0x1b, 0x03, - 0x1a, 0x1b, 0x03, 0x1b, 0x03, 0x02, 0x1b, 0x03, - 0x1b, 0x1b, 0x03, 0x20, 0x1b, 0x02, 0x03, 0x1b, - 0x02, 0x1b, 0x1b, 0x04, 0x02, 0x1b, 0x04, 0x1b, - 0x28, 0x06, 0x1d, 0x04, 0x06, 0x1f, 0x1d, 0x04, - 0x1f, 0x1d, 0x1d, 0x1e, 0x05, 0x1d, 0x1e, 0x05, - 0x21, 0x1e, 0x04, 0x1d, 0x1e, 0x04, 0x1d, 0x1e, - 0x04, 0x21, 0x1e, 0x1d, 0x22, 0x1e, 0x1d, 0x21, - 0x22, 0x1d, 0x1d, 0x22, 0x1d, 0x1d, 0x00, 0x06, - 0x22, 0x02, 0x04, 0x22, 0x02, 0x04, 0x21, 0x02, - 0x06, 0x22, 0x02, 0x06, 0x21, 0x02, 0x1d, 0x22, - 0x02, 0x1d, 0x21, 0x04, 0x1d, 0x22, 0x04, 0x05, - 0x21, 0x04, 0x1d, 0x21, 0x0b, 0x06, 0x21, 0x0d, - 0x05, 0x22, 0x0c, 0x05, 0x22, 0x0e, 0x05, 0x22, - 0x1c, 0x04, 0x22, 0x1c, 0x1d, 0x22, 0x22, 0x05, - 0x22, 0x22, 0x04, 0x22, 0x22, 0x1d, 0x22, 0x1d, - 0x1d, 0x22, 0x1a, 0x1d, 0x22, 0x1e, 0x05, 0x22, - 0x1a, 0x1d, 0x05, 0x1c, 0x05, 0x1d, 0x11, 0x1d, - 0x22, 0x1b, 0x1d, 0x22, 0x1e, 0x04, 0x05, 0x1d, - 0x06, 0x22, 0x1c, 0x04, 0x1d, 0x1b, 0x1d, 0x1d, - 0x1c, 0x04, 0x1d, 0x1e, 0x04, 0x05, 0x04, 0x05, - 0x22, 0x05, 0x04, 0x22, 0x1d, 0x04, 0x22, 0x19, - 0x1d, 0x22, 0x00, 0x05, 0x22, 0x1b, 0x1d, 0x1d, - 0x11, 0x04, 0x1d, 0x0d, 0x1d, 0x1d, 0x0b, 0x06, - 0x22, 0x1e, 0x04, 0x22, 0x35, 0x06, 0x00, 0x0f, - 0x9d, 0x0d, 0x0f, 0x9d, 0x27, 0x06, 0x00, 0x1d, - 0x1d, 0x20, 0x00, 0x1c, 0x01, 0x0a, 0x1e, 0x06, - 0x1e, 0x08, 0x0e, 0x1d, 0x12, 0x1e, 0x0a, 0x0c, - 0x21, 0x1d, 0x12, 0x1d, 0x23, 0x20, 0x21, 0x0c, - 0x1d, 0x1e, 0x35, 0x06, 0x00, 0x0f, 0x14, 0x27, - 0x06, 0x0e, 0x1d, 0x22, 0xff, 0x00, 0x1d, 0x1d, - 0x20, 0xff, 0x12, 0x1d, 0x23, 0x20, 0xff, 0x21, - 0x0c, 0x1d, 0x1e, 0x27, 0x06, 0x05, 0x1d, 0xff, - 0x05, 0x1d, 0x00, 0x1d, 0x20, 0x27, 0x06, 0x0a, - 0xa5, 0x00, 0x1d, 0x2c, 0x00, 0x01, 0x30, 0x02, - 0x30, 0x3a, 0x00, 0x3b, 0x00, 0x21, 0x00, 0x3f, - 0x00, 0x16, 0x30, 0x17, 0x30, 0x26, 0x20, 0x13, - 0x20, 0x12, 0x01, 0x00, 0x5f, 0x5f, 0x28, 0x29, - 0x7b, 0x7d, 0x08, 0x30, 0x0c, 0x0d, 0x08, 0x09, - 0x02, 0x03, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, - 0x5b, 0x00, 0x5d, 0x00, 0x3e, 0x20, 0x3e, 0x20, - 0x3e, 0x20, 0x3e, 0x20, 0x5f, 0x00, 0x5f, 0x00, - 0x5f, 0x00, 0x2c, 0x00, 0x01, 0x30, 0x2e, 0x00, - 0x00, 0x00, 0x3b, 0x00, 0x3a, 0x00, 0x3f, 0x00, - 0x21, 0x00, 0x14, 0x20, 0x28, 0x00, 0x29, 0x00, - 0x7b, 0x00, 0x7d, 0x00, 0x14, 0x30, 0x15, 0x30, - 0x23, 0x26, 0x2a, 0x2b, 0x2d, 0x3c, 0x3e, 0x3d, - 0x00, 0x5c, 0x24, 0x25, 0x40, 0x40, 0x06, 0xff, - 0x0b, 0x00, 0x0b, 0xff, 0x0c, 0x20, 0x00, 0x4d, - 0x06, 0x40, 0x06, 0xff, 0x0e, 0x00, 0x0e, 0xff, - 0x0f, 0x00, 0x0f, 0xff, 0x10, 0x00, 0x10, 0xff, - 0x11, 0x00, 0x11, 0xff, 0x12, 0x00, 0x12, 0x21, - 0x06, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, - 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, - 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x10, - 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, - 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, - 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, - 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, - 0x19, 0x19, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, - 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, - 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, - 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, - 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x22, 0x06, - 0x22, 0x00, 0x22, 0x00, 0x22, 0x01, 0x22, 0x01, - 0x22, 0x03, 0x22, 0x03, 0x22, 0x05, 0x22, 0x05, - 0x21, 0x00, 0x85, 0x29, 0x01, 0x30, 0x01, 0x0b, - 0x0c, 0x00, 0xfa, 0xf1, 0xa0, 0xa2, 0xa4, 0xa6, - 0xa8, 0xe2, 0xe4, 0xe6, 0xc2, 0xfb, 0xa1, 0xa3, - 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xae, 0xb0, 0xb2, - 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 0xc0, 0xc3, - 0xc5, 0xc7, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, - 0xd1, 0xd4, 0xd7, 0xda, 0xdd, 0xde, 0xdf, 0xe0, - 0xe1, 0xe3, 0xe5, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, - 0xec, 0xee, 0xf2, 0x98, 0x99, 0x31, 0x31, 0x4f, - 0x31, 0x55, 0x31, 0x5b, 0x31, 0x61, 0x31, 0xa2, - 0x00, 0xa3, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xa6, - 0x00, 0xa5, 0x00, 0xa9, 0x20, 0x00, 0x00, 0x02, - 0x25, 0x90, 0x21, 0x91, 0x21, 0x92, 0x21, 0x93, - 0x21, 0xa0, 0x25, 0xcb, 0x25, 0x99, 0x10, 0xba, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x10, 0xba, - 0x10, 0x05, 0x05, 0xa5, 0x10, 0xba, 0x10, 0x05, - 0x31, 0x11, 0x27, 0x11, 0x32, 0x11, 0x27, 0x11, - 0x55, 0x47, 0x13, 0x3e, 0x13, 0x47, 0x13, 0x57, - 0x13, 0x55, 0xb9, 0x14, 0xba, 0x14, 0xb9, 0x14, - 0xb0, 0x14, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x14, - 0xbd, 0x14, 0x55, 0x50, 0xb8, 0x15, 0xaf, 0x15, - 0xb9, 0x15, 0xaf, 0x15, 0x55, 0x35, 0x19, 0x30, - 0x19, 0x05, 0x57, 0xd1, 0x65, 0xd1, 0x58, 0xd1, - 0x65, 0xd1, 0x5f, 0xd1, 0x6e, 0xd1, 0x5f, 0xd1, - 0x6f, 0xd1, 0x5f, 0xd1, 0x70, 0xd1, 0x5f, 0xd1, - 0x71, 0xd1, 0x5f, 0xd1, 0x72, 0xd1, 0x55, 0x55, - 0x55, 0x05, 0xb9, 0xd1, 0x65, 0xd1, 0xba, 0xd1, - 0x65, 0xd1, 0xbb, 0xd1, 0x6e, 0xd1, 0xbc, 0xd1, - 0x6e, 0xd1, 0xbb, 0xd1, 0x6f, 0xd1, 0xbc, 0xd1, - 0x6f, 0xd1, 0x55, 0x55, 0x55, 0x41, 0x00, 0x61, - 0x00, 0x41, 0x00, 0x61, 0x00, 0x69, 0x00, 0x41, - 0x00, 0x61, 0x00, 0x41, 0x00, 0x43, 0x44, 0x00, - 0x00, 0x47, 0x00, 0x00, 0x4a, 0x4b, 0x00, 0x00, - 0x4e, 0x4f, 0x50, 0x51, 0x00, 0x53, 0x54, 0x55, - 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, - 0x64, 0x00, 0x66, 0x68, 0x00, 0x70, 0x00, 0x41, - 0x00, 0x61, 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, - 0x46, 0x47, 0x4a, 0x00, 0x53, 0x00, 0x61, 0x00, - 0x41, 0x42, 0x00, 0x44, 0x45, 0x46, 0x47, 0x00, - 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f, 0x53, - 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, - 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, - 0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, - 0x00, 0x61, 0x00, 0x31, 0x01, 0x37, 0x02, 0x91, - 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, - 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, - 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, - 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, - 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, - 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, - 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, - 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, - 0x00, 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, 0x30, - 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, - 0x00, 0x27, 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, - 0x06, 0x1e, 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, - 0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, - 0x0a, 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, - 0x44, 0x90, 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, - 0x00, 0x00, 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, - 0x11, 0x12, 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, - 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, - 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, - 0x2d, 0x06, 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00, - 0x44, 0x06, 0x00, 0x00, 0x46, 0x06, 0x33, 0x06, - 0x39, 0x06, 0x00, 0x00, 0x35, 0x06, 0x42, 0x06, - 0x00, 0x00, 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x2e, 0x06, 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, - 0x3a, 0x06, 0x00, 0x00, 0xba, 0x06, 0x00, 0x00, - 0x6f, 0x06, 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06, - 0x00, 0x00, 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06, - 0x00, 0x00, 0x45, 0x06, 0x46, 0x06, 0x33, 0x06, - 0x39, 0x06, 0x41, 0x06, 0x35, 0x06, 0x42, 0x06, - 0x00, 0x00, 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, - 0x2e, 0x06, 0x00, 0x00, 0x36, 0x06, 0x38, 0x06, - 0x3a, 0x06, 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06, - 0x27, 0x06, 0x00, 0x01, 0x05, 0x08, 0x20, 0x21, - 0x0b, 0x06, 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, - 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, - 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28, - 0x06, 0x2c, 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48, - 0x06, 0x32, 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a, - 0x06, 0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, - 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, - 0x06, 0x0c, 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00, - 0x2c, 0x00, 0x28, 0x00, 0x41, 0x00, 0x29, 0x00, - 0x14, 0x30, 0x53, 0x00, 0x15, 0x30, 0x43, 0x52, - 0x43, 0x44, 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56, - 0x4d, 0x56, 0x53, 0x44, 0x53, 0x53, 0x50, 0x50, - 0x56, 0x57, 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d, - 0x52, 0x44, 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68, - 0x68, 0x4b, 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7, - 0x30, 0x8c, 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29, - 0x59, 0xa4, 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99, - 0x65, 0x4d, 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0, - 0x65, 0x1d, 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9, - 0x8c, 0xf0, 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95, - 0x62, 0x55, 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a, - 0x90, 0xe6, 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07, - 0x63, 0x70, 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a, - 0x7a, 0x08, 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08, - 0x67, 0x33, 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d, - 0x91, 0x14, 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09, - 0x4e, 0x8c, 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53, - 0x62, 0xd7, 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97, - 0x5f, 0xef, 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05, - 0x00, 0x09, 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f, - 0xbb, 0x4f, 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50, - 0xe7, 0x50, 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06, - 0x4d, 0x51, 0x54, 0x51, 0x64, 0x51, 0x77, 0x51, - 0x1c, 0x05, 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51, - 0x4b, 0x05, 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e, - 0xac, 0x51, 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51, - 0x03, 0x52, 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52, - 0x72, 0x52, 0x77, 0x52, 0x15, 0x35, 0x02, 0x00, - 0x20, 0x80, 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7, - 0x52, 0x00, 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50, - 0x82, 0x8a, 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8, - 0x2c, 0x0a, 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53, - 0x63, 0x0b, 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54, - 0x9e, 0x54, 0x38, 0x54, 0x48, 0x54, 0x68, 0x54, - 0xa2, 0x54, 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55, - 0x63, 0x55, 0x84, 0x55, 0x84, 0x55, 0x99, 0x55, - 0xab, 0x55, 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57, - 0x06, 0x56, 0x17, 0x57, 0x51, 0x56, 0x74, 0x56, - 0x07, 0x52, 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57, - 0x0d, 0x58, 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58, - 0xac, 0x58, 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58, - 0x06, 0x59, 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59, - 0xa8, 0x16, 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a, - 0x27, 0x5a, 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36, - 0xfc, 0x36, 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b, - 0xc8, 0x19, 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b, - 0xf3, 0x5b, 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c, - 0x53, 0x5f, 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c, - 0x6e, 0x5c, 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d, - 0x43, 0x5d, 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d, - 0x7c, 0x5d, 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38, - 0xfd, 0x5d, 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e, - 0x62, 0x38, 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e, - 0xb3, 0x5e, 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3, - 0xfe, 0x5e, 0x31, 0x23, 0x31, 0x23, 0x01, 0x82, - 0x22, 0x5f, 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32, - 0xda, 0x61, 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38, - 0x9a, 0x5f, 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f, - 0x81, 0x60, 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60, - 0xd4, 0x26, 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, - 0x00, 0x00, 0x02, 0x08, 0x00, 0x80, 0x08, 0x00, - 0x00, 0x08, 0x80, 0x28, 0x80, 0x02, 0x00, 0x00, - 0x02, 0x48, 0x61, 0x00, 0x04, 0x06, 0x04, 0x32, - 0x46, 0x6a, 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8, - 0xd3, 0x5d, 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c, - 0x2b, 0x3d, 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83, - 0x63, 0xe4, 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5, - 0x63, 0xa9, 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e, - 0x64, 0x9d, 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f, - 0x65, 0x6c, 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8, - 0x66, 0x49, 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08, - 0x3b, 0xe4, 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00, - 0x67, 0x9c, 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17, - 0x67, 0x1b, 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53, - 0x67, 0xc3, 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85, - 0x67, 0x52, 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e, - 0x68, 0x1f, 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42, - 0x69, 0xa3, 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3, - 0x36, 0xdb, 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7, - 0x38, 0x54, 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f, - 0x6b, 0xba, 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b, - 0x1d, 0xfa, 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf, - 0x6c, 0xcd, 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e, - 0x6d, 0x77, 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78, - 0x6d, 0x85, 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f, - 0x6e, 0x6e, 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7, - 0x6e, 0xd1, 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e, - 0x3f, 0x8e, 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e, - 0x70, 0x1b, 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d, - 0x70, 0x77, 0x70, 0xad, 0x70, 0x25, 0x05, 0x45, - 0x71, 0x63, 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28, - 0x72, 0x35, 0x72, 0x50, 0x72, 0x08, 0x46, 0x80, - 0x72, 0x95, 0x72, 0x35, 0x47, 0x02, 0x20, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, - 0x00, 0x00, 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00, - 0x20, 0x00, 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80, - 0x20, 0x14, 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac, - 0x3e, 0xa5, 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47, - 0x74, 0x5c, 0x74, 0x71, 0x74, 0x85, 0x74, 0xca, - 0x74, 0x1b, 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e, - 0x75, 0x92, 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10, - 0x76, 0xa1, 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc, - 0x3f, 0x08, 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2, - 0x50, 0x19, 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f, - 0x77, 0x1f, 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b, - 0x77, 0x46, 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e, - 0x78, 0x8c, 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26, - 0x56, 0x56, 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f, - 0x79, 0xeb, 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a, - 0x7a, 0x4f, 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7, - 0x5a, 0xee, 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6, - 0x7b, 0xc9, 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2, - 0x7c, 0xa0, 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00, - 0x7d, 0x86, 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7, - 0x7d, 0x02, 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28, - 0x62, 0x47, 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a, - 0x7f, 0x3e, 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05, - 0x80, 0xda, 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8, - 0x65, 0x70, 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2, - 0x80, 0x03, 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5, - 0x5a, 0xa7, 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c, - 0x33, 0x01, 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b, - 0x44, 0x91, 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3, - 0x52, 0xb1, 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6, - 0x82, 0x3c, 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63, - 0x83, 0xad, 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7, - 0x83, 0x57, 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc, - 0x83, 0xdc, 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02, - 0x00, 0x00, 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00, - 0x20, 0x80, 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00, - 0x02, 0x80, 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5, - 0x6c, 0x2b, 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16, - 0x85, 0xca, 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d, - 0x45, 0x61, 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b, - 0x45, 0x50, 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69, - 0x86, 0xa9, 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2, - 0x86, 0x79, 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86, - 0x87, 0xd7, 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9, - 0x45, 0x60, 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7, - 0x88, 0xde, 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb, - 0x34, 0xae, 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7, - 0x46, 0xa0, 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55, - 0x8c, 0xa8, 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b, - 0x8d, 0x77, 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb, - 0x8d, 0xbc, 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4, - 0x8e, 0x38, 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94, - 0x90, 0xf1, 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b, - 0x91, 0x38, 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c, - 0x92, 0xf9, 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b, - 0x95, 0x95, 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6, - 0x49, 0xc3, 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45, - 0x91, 0x1a, 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0, - 0x97, 0x0a, 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b, - 0x98, 0x0b, 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2, - 0x98, 0x33, 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2, - 0x99, 0xfe, 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12, - 0x9b, 0x40, 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed, - 0x4c, 0x67, 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05, - 0xa1, 0x0e, 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56, - 0x4d, 0xf9, 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f, - 0x9f, 0x16, 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02, - 0x88, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x28, 0x00, 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00, - 0x80, 0x80, 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80, - 0x00, 0x20, 0x2a, 0x00, 0x80, -}; - -static const uint16_t unicode_comp_table[945] = { - 0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0, - 0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982, - 0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8, - 0x02ca, 0x02cc, 0x0287, 0x228a, 0x02ce, 0x228c, 0x2290, 0x2292, - 0x228e, 0x0288, 0x0289, 0x028a, 0x2482, 0x0300, 0x0302, 0x0304, - 0x028b, 0x2480, 0x0308, 0x0984, 0x0986, 0x2458, 0x0a02, 0x0306, - 0x2298, 0x229a, 0x229e, 0x0900, 0x030a, 0x22a0, 0x030c, 0x030e, - 0x0840, 0x0310, 0x0312, 0x22a2, 0x22a6, 0x09c0, 0x22a4, 0x22a8, - 0x22aa, 0x028c, 0x028d, 0x028e, 0x0340, 0x0342, 0x0344, 0x0380, - 0x028f, 0x248e, 0x07c2, 0x0988, 0x098a, 0x2490, 0x0346, 0x22ac, - 0x0400, 0x22b0, 0x0842, 0x22b2, 0x0402, 0x22b4, 0x0440, 0x0444, - 0x22b6, 0x0442, 0x22c2, 0x22c0, 0x22c4, 0x22c6, 0x22c8, 0x0940, - 0x04c0, 0x0291, 0x22ca, 0x04c4, 0x22cc, 0x04c2, 0x22d0, 0x22ce, - 0x0292, 0x0293, 0x0294, 0x0295, 0x0540, 0x0542, 0x0a08, 0x0296, - 0x2494, 0x0544, 0x07c4, 0x098c, 0x098e, 0x06c0, 0x2492, 0x0844, - 0x2308, 0x230a, 0x0580, 0x230c, 0x0584, 0x0990, 0x0992, 0x230e, - 0x0582, 0x2312, 0x0586, 0x0588, 0x2314, 0x058c, 0x2316, 0x0998, - 0x058a, 0x231e, 0x0590, 0x2320, 0x099a, 0x058e, 0x2324, 0x2322, - 0x0299, 0x029a, 0x029b, 0x05c0, 0x05c2, 0x05c4, 0x029c, 0x24ac, - 0x05c6, 0x05c8, 0x07c6, 0x0994, 0x0996, 0x0700, 0x24aa, 0x2326, - 0x05ca, 0x232a, 0x2328, 0x2340, 0x2342, 0x2344, 0x2346, 0x05cc, - 0x234a, 0x2348, 0x234c, 0x234e, 0x2350, 0x24b8, 0x029d, 0x05ce, - 0x24be, 0x0a0c, 0x2352, 0x0600, 0x24bc, 0x24ba, 0x0640, 0x2354, - 0x0642, 0x0644, 0x2356, 0x2358, 0x02a0, 0x02a1, 0x02a2, 0x02a3, - 0x02c1, 0x02c3, 0x0a01, 0x02a4, 0x2443, 0x02a5, 0x07c1, 0x0981, - 0x0983, 0x2441, 0x2281, 0x02c5, 0x2283, 0x2285, 0x2287, 0x02c7, - 0x02c9, 0x02cb, 0x02cd, 0x02a7, 0x228b, 0x02cf, 0x228d, 0x2291, - 0x2293, 0x228f, 0x02a8, 0x02a9, 0x02aa, 0x2483, 0x0301, 0x0303, - 0x0305, 0x02ab, 0x2481, 0x0309, 0x0985, 0x0987, 0x2459, 0x0a03, - 0x0307, 0x2299, 0x229b, 0x229f, 0x0901, 0x030b, 0x22a1, 0x030d, - 0x030f, 0x0841, 0x0311, 0x0313, 0x22a3, 0x22a7, 0x09c1, 0x22a5, - 0x22a9, 0x22ab, 0x2380, 0x02ac, 0x02ad, 0x02ae, 0x0341, 0x0343, - 0x0345, 0x02af, 0x248f, 0x07c3, 0x0989, 0x098b, 0x2491, 0x0347, - 0x22ad, 0x0401, 0x0884, 0x22b1, 0x0843, 0x22b3, 0x0403, 0x22b5, - 0x0441, 0x0445, 0x22b7, 0x0443, 0x22c3, 0x22c1, 0x22c5, 0x22c7, - 0x22c9, 0x0941, 0x04c1, 0x02b1, 0x22cb, 0x04c5, 0x22cd, 0x04c3, - 0x22d1, 0x22cf, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x0541, 0x0543, - 0x0a09, 0x02b6, 0x2495, 0x0545, 0x07c5, 0x098d, 0x098f, 0x06c1, - 0x2493, 0x0845, 0x2309, 0x230b, 0x0581, 0x230d, 0x0585, 0x0991, - 0x0993, 0x230f, 0x0583, 0x2313, 0x0587, 0x0589, 0x2315, 0x058d, - 0x2317, 0x0999, 0x058b, 0x231f, 0x2381, 0x0591, 0x2321, 0x099b, - 0x058f, 0x2325, 0x2323, 0x02b9, 0x02ba, 0x02bb, 0x05c1, 0x05c3, - 0x05c5, 0x02bc, 0x24ad, 0x05c7, 0x05c9, 0x07c7, 0x0995, 0x0997, - 0x0701, 0x24ab, 0x2327, 0x05cb, 0x232b, 0x2329, 0x2341, 0x2343, - 0x2345, 0x2347, 0x05cd, 0x234b, 0x2349, 0x2382, 0x234d, 0x234f, - 0x2351, 0x24b9, 0x02bd, 0x05cf, 0x24bf, 0x0a0d, 0x2353, 0x02bf, - 0x24bd, 0x2383, 0x24bb, 0x0641, 0x2355, 0x0643, 0x0645, 0x2357, - 0x2359, 0x3101, 0x0c80, 0x2e00, 0x2446, 0x2444, 0x244a, 0x2448, - 0x0800, 0x0942, 0x0944, 0x0804, 0x2288, 0x2486, 0x2484, 0x248a, - 0x2488, 0x22ae, 0x2498, 0x2496, 0x249c, 0x249a, 0x2300, 0x0a06, - 0x2302, 0x0a04, 0x0946, 0x07ce, 0x07ca, 0x07c8, 0x07cc, 0x2447, - 0x2445, 0x244b, 0x2449, 0x0801, 0x0943, 0x0945, 0x0805, 0x2289, - 0x2487, 0x2485, 0x248b, 0x2489, 0x22af, 0x2499, 0x2497, 0x249d, - 0x249b, 0x2301, 0x0a07, 0x2303, 0x0a05, 0x0947, 0x07cf, 0x07cb, - 0x07c9, 0x07cd, 0x2450, 0x244e, 0x2454, 0x2452, 0x2451, 0x244f, - 0x2455, 0x2453, 0x2294, 0x2296, 0x2295, 0x2297, 0x2304, 0x2306, - 0x2305, 0x2307, 0x2318, 0x2319, 0x231a, 0x231b, 0x232c, 0x232d, - 0x232e, 0x232f, 0x2400, 0x24a2, 0x24a0, 0x24a6, 0x24a4, 0x24a8, - 0x24a3, 0x24a1, 0x24a7, 0x24a5, 0x24a9, 0x24b0, 0x24ae, 0x24b4, - 0x24b2, 0x24b6, 0x24b1, 0x24af, 0x24b5, 0x24b3, 0x24b7, 0x0882, - 0x0880, 0x0881, 0x0802, 0x0803, 0x229c, 0x229d, 0x0a0a, 0x0a0b, - 0x0883, 0x0b40, 0x2c8a, 0x0c81, 0x2c89, 0x2c88, 0x2540, 0x2541, - 0x2d00, 0x2e07, 0x0d00, 0x2640, 0x2641, 0x2e80, 0x0d01, 0x26c8, - 0x26c9, 0x2f00, 0x2f84, 0x0d02, 0x2f83, 0x2f82, 0x0d40, 0x26d8, - 0x26d9, 0x3186, 0x0d04, 0x2740, 0x2741, 0x3100, 0x3086, 0x0d06, - 0x3085, 0x3084, 0x0d41, 0x2840, 0x3200, 0x0d07, 0x284f, 0x2850, - 0x3280, 0x2c84, 0x2e03, 0x2857, 0x0d42, 0x2c81, 0x2c80, 0x24c0, - 0x24c1, 0x2c86, 0x2c83, 0x28c0, 0x0d43, 0x25c0, 0x25c1, 0x2940, - 0x0d44, 0x26c0, 0x26c1, 0x2e05, 0x2e02, 0x29c0, 0x0d45, 0x2f05, - 0x2f04, 0x0d80, 0x26d0, 0x26d1, 0x2f80, 0x2a40, 0x0d82, 0x26e0, - 0x26e1, 0x3080, 0x3081, 0x2ac0, 0x0d83, 0x3004, 0x3003, 0x0d81, - 0x27c0, 0x27c1, 0x3082, 0x2b40, 0x0d84, 0x2847, 0x2848, 0x3184, - 0x3181, 0x2f06, 0x0d08, 0x2f81, 0x3005, 0x0d46, 0x3083, 0x3182, - 0x0e00, 0x0e01, 0x0f40, 0x1180, 0x1182, 0x0f03, 0x0f00, 0x11c0, - 0x0f01, 0x1140, 0x1202, 0x1204, 0x0f81, 0x1240, 0x0fc0, 0x1242, - 0x0f80, 0x1244, 0x1284, 0x0f82, 0x1286, 0x1288, 0x128a, 0x12c0, - 0x1282, 0x1181, 0x1183, 0x1043, 0x1040, 0x11c1, 0x1041, 0x1141, - 0x1203, 0x1205, 0x10c1, 0x1241, 0x1000, 0x1243, 0x10c0, 0x1245, - 0x1285, 0x10c2, 0x1287, 0x1289, 0x128b, 0x12c1, 0x1283, 0x1080, - 0x1100, 0x1101, 0x1200, 0x1201, 0x1280, 0x1281, 0x1340, 0x1341, - 0x1343, 0x1342, 0x1344, 0x13c2, 0x1400, 0x13c0, 0x1440, 0x1480, - 0x14c0, 0x1540, 0x1541, 0x1740, 0x1700, 0x1741, 0x17c0, 0x1800, - 0x1802, 0x1801, 0x1840, 0x1880, 0x1900, 0x18c0, 0x18c1, 0x1901, - 0x1940, 0x1942, 0x1941, 0x1980, 0x19c0, 0x19c2, 0x19c1, 0x1c80, - 0x1cc0, 0x1dc0, 0x1f80, 0x2000, 0x2002, 0x2004, 0x2006, 0x2008, - 0x2040, 0x2080, 0x2082, 0x20c0, 0x20c1, 0x2100, 0x22b8, 0x22b9, - 0x2310, 0x2311, 0x231c, 0x231d, 0x244c, 0x2456, 0x244d, 0x2457, - 0x248c, 0x248d, 0x249e, 0x249f, 0x2500, 0x2502, 0x2504, 0x2bc0, - 0x2501, 0x2503, 0x2505, 0x2bc1, 0x2bc2, 0x2bc3, 0x2bc4, 0x2bc5, - 0x2bc6, 0x2bc7, 0x2580, 0x2582, 0x2584, 0x2bc8, 0x2581, 0x2583, - 0x2585, 0x2bc9, 0x2bca, 0x2bcb, 0x2bcc, 0x2bcd, 0x2bce, 0x2bcf, - 0x2600, 0x2602, 0x2601, 0x2603, 0x2680, 0x2682, 0x2681, 0x2683, - 0x26c2, 0x26c4, 0x26c6, 0x2c00, 0x26c3, 0x26c5, 0x26c7, 0x2c01, - 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x26ca, 0x26cc, - 0x26ce, 0x2c08, 0x26cb, 0x26cd, 0x26cf, 0x2c09, 0x2c0a, 0x2c0b, - 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x26d2, 0x26d4, 0x26d6, 0x26d3, - 0x26d5, 0x26d7, 0x26da, 0x26dc, 0x26de, 0x26db, 0x26dd, 0x26df, - 0x2700, 0x2702, 0x2701, 0x2703, 0x2780, 0x2782, 0x2781, 0x2783, - 0x2800, 0x2802, 0x2804, 0x2801, 0x2803, 0x2805, 0x2842, 0x2844, - 0x2846, 0x2849, 0x284b, 0x284d, 0x2c40, 0x284a, 0x284c, 0x284e, - 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2851, - 0x2853, 0x2855, 0x2c48, 0x2852, 0x2854, 0x2856, 0x2c49, 0x2c4a, - 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c82, 0x2e01, 0x3180, - 0x2c87, 0x2f01, 0x2f02, 0x2f03, 0x2e06, 0x3185, 0x3000, 0x3001, - 0x3002, 0x4640, 0x4641, 0x4680, 0x46c0, 0x46c2, 0x46c1, 0x4700, - 0x4740, 0x4780, 0x47c0, 0x47c2, 0x4900, 0x4940, 0x4980, 0x4982, - 0x4a00, 0x49c2, 0x4a03, 0x4a04, 0x4a40, 0x4a41, 0x4a80, 0x4a81, - 0x4ac0, 0x4ac1, 0x4bc0, 0x4bc1, 0x4b00, 0x4b01, 0x4b40, 0x4b41, - 0x4bc2, 0x4bc3, 0x4b80, 0x4b81, 0x4b82, 0x4b83, 0x4c00, 0x4c01, - 0x4c02, 0x4c03, 0x5600, 0x5440, 0x5442, 0x5444, 0x5446, 0x5448, - 0x544a, 0x544c, 0x544e, 0x5450, 0x5452, 0x5454, 0x5456, 0x5480, - 0x5482, 0x5484, 0x54c0, 0x54c1, 0x5500, 0x5501, 0x5540, 0x5541, - 0x5580, 0x5581, 0x55c0, 0x55c1, 0x5680, 0x58c0, 0x5700, 0x5702, - 0x5704, 0x5706, 0x5708, 0x570a, 0x570c, 0x570e, 0x5710, 0x5712, - 0x5714, 0x5716, 0x5740, 0x5742, 0x5744, 0x5780, 0x5781, 0x57c0, - 0x57c1, 0x5800, 0x5801, 0x5840, 0x5841, 0x5880, 0x5881, 0x5900, - 0x5901, 0x5902, 0x5903, 0x5940, 0x8e80, 0x8e82, 0x8ec0, 0x8f00, - 0x8f01, 0x8f40, 0x8f41, 0x8f81, 0x8f80, 0x8f83, 0x8fc0, 0x8fc1, - 0x9000, -}; - -typedef enum { - UNICODE_GC_Cn, - UNICODE_GC_Lu, - UNICODE_GC_Ll, - UNICODE_GC_Lt, - UNICODE_GC_Lm, - UNICODE_GC_Lo, - UNICODE_GC_Mn, - UNICODE_GC_Mc, - UNICODE_GC_Me, - UNICODE_GC_Nd, - UNICODE_GC_Nl, - UNICODE_GC_No, - UNICODE_GC_Sm, - UNICODE_GC_Sc, - UNICODE_GC_Sk, - UNICODE_GC_So, - UNICODE_GC_Pc, - UNICODE_GC_Pd, - UNICODE_GC_Ps, - UNICODE_GC_Pe, - UNICODE_GC_Pi, - UNICODE_GC_Pf, - UNICODE_GC_Po, - UNICODE_GC_Zs, - UNICODE_GC_Zl, - UNICODE_GC_Zp, - UNICODE_GC_Cc, - UNICODE_GC_Cf, - UNICODE_GC_Cs, - UNICODE_GC_Co, - UNICODE_GC_LC, - UNICODE_GC_L, - UNICODE_GC_M, - UNICODE_GC_N, - UNICODE_GC_S, - UNICODE_GC_P, - UNICODE_GC_Z, - UNICODE_GC_C, - UNICODE_GC_COUNT, -} UnicodeGCEnum; - -static const char unicode_gc_name_table[] = - "Cn,Unassigned" "\0" - "Lu,Uppercase_Letter" "\0" - "Ll,Lowercase_Letter" "\0" - "Lt,Titlecase_Letter" "\0" - "Lm,Modifier_Letter" "\0" - "Lo,Other_Letter" "\0" - "Mn,Nonspacing_Mark" "\0" - "Mc,Spacing_Mark" "\0" - "Me,Enclosing_Mark" "\0" - "Nd,Decimal_Number,digit" "\0" - "Nl,Letter_Number" "\0" - "No,Other_Number" "\0" - "Sm,Math_Symbol" "\0" - "Sc,Currency_Symbol" "\0" - "Sk,Modifier_Symbol" "\0" - "So,Other_Symbol" "\0" - "Pc,Connector_Punctuation" "\0" - "Pd,Dash_Punctuation" "\0" - "Ps,Open_Punctuation" "\0" - "Pe,Close_Punctuation" "\0" - "Pi,Initial_Punctuation" "\0" - "Pf,Final_Punctuation" "\0" - "Po,Other_Punctuation" "\0" - "Zs,Space_Separator" "\0" - "Zl,Line_Separator" "\0" - "Zp,Paragraph_Separator" "\0" - "Cc,Control,cntrl" "\0" - "Cf,Format" "\0" - "Cs,Surrogate" "\0" - "Co,Private_Use" "\0" - "LC,Cased_Letter" "\0" - "L,Letter" "\0" - "M,Mark,Combining_Mark" "\0" - "N,Number" "\0" - "S,Symbol" "\0" - "P,Punctuation,punct" "\0" - "Z,Separator" "\0" - "C,Other" "\0" -; - -static const uint8_t unicode_gc_table[3790] = { - 0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13, - 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, - 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, - 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c, - 0xfa, 0x19, 0x17, 0x16, 0x6d, 0x0f, 0x16, 0x0e, - 0x0f, 0x05, 0x14, 0x0c, 0x1b, 0x0f, 0x0e, 0x0f, - 0x0c, 0x2b, 0x0e, 0x02, 0x36, 0x0e, 0x0b, 0x05, - 0x15, 0x4b, 0x16, 0xe1, 0x0f, 0x0c, 0xc1, 0xe2, - 0x10, 0x0c, 0xe2, 0x00, 0xff, 0x30, 0x02, 0xff, - 0x08, 0x02, 0xff, 0x27, 0xbf, 0x22, 0x21, 0x02, - 0x5f, 0x5f, 0x21, 0x22, 0x61, 0x02, 0x21, 0x02, - 0x41, 0x42, 0x21, 0x02, 0x21, 0x02, 0x9f, 0x7f, - 0x02, 0x5f, 0x5f, 0x21, 0x02, 0x5f, 0x3f, 0x02, - 0x05, 0x3f, 0x22, 0x65, 0x01, 0x03, 0x02, 0x01, - 0x03, 0x02, 0x01, 0x03, 0x02, 0xff, 0x08, 0x02, - 0xff, 0x0a, 0x02, 0x01, 0x03, 0x02, 0x5f, 0x21, - 0x02, 0xff, 0x32, 0xa2, 0x21, 0x02, 0x21, 0x22, - 0x5f, 0x41, 0x02, 0xff, 0x00, 0xe2, 0x3c, 0x05, - 0xe2, 0x13, 0xe4, 0x0a, 0x6e, 0xe4, 0x04, 0xee, - 0x06, 0x84, 0xce, 0x04, 0x0e, 0x04, 0xee, 0x09, - 0xe6, 0x68, 0x7f, 0x04, 0x0e, 0x3f, 0x20, 0x04, - 0x42, 0x16, 0x01, 0x60, 0x2e, 0x01, 0x16, 0x41, - 0x00, 0x01, 0x00, 0x21, 0x02, 0xe1, 0x09, 0x00, - 0xe1, 0x01, 0xe2, 0x1b, 0x3f, 0x02, 0x41, 0x42, - 0xff, 0x10, 0x62, 0x3f, 0x0c, 0x5f, 0x3f, 0x02, - 0xe1, 0x2b, 0xe2, 0x28, 0xff, 0x1a, 0x0f, 0x86, - 0x28, 0xff, 0x2f, 0xff, 0x06, 0x02, 0xff, 0x58, - 0x00, 0xe1, 0x1e, 0x20, 0x04, 0xb6, 0xe2, 0x21, - 0x16, 0x11, 0x20, 0x2f, 0x0d, 0x00, 0xe6, 0x25, - 0x11, 0x06, 0x16, 0x26, 0x16, 0x26, 0x16, 0x06, - 0xe0, 0x00, 0xe5, 0x13, 0x60, 0x65, 0x36, 0xe0, - 0x03, 0xbb, 0x4c, 0x36, 0x0d, 0x36, 0x2f, 0xe6, - 0x03, 0x16, 0x1b, 0x00, 0x36, 0xe5, 0x18, 0x04, - 0xe5, 0x02, 0xe6, 0x0d, 0xe9, 0x02, 0x76, 0x25, - 0x06, 0xe5, 0x5b, 0x16, 0x05, 0xc6, 0x1b, 0x0f, - 0xa6, 0x24, 0x26, 0x0f, 0x66, 0x25, 0xe9, 0x02, - 0x45, 0x2f, 0x05, 0xf6, 0x06, 0x00, 0x1b, 0x05, - 0x06, 0xe5, 0x16, 0xe6, 0x13, 0x20, 0xe5, 0x51, - 0xe6, 0x03, 0x05, 0xe0, 0x06, 0xe9, 0x02, 0xe5, - 0x19, 0xe6, 0x01, 0x24, 0x0f, 0x56, 0x04, 0x20, - 0x06, 0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01, - 0x04, 0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00, - 0xe5, 0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03, - 0xe0, 0x2d, 0xe5, 0x0d, 0x00, 0xe5, 0x0a, 0xe0, - 0x03, 0xe6, 0x07, 0x1b, 0xe6, 0x18, 0x07, 0xe5, - 0x2e, 0x06, 0x07, 0x06, 0x05, 0x47, 0xe6, 0x00, - 0x67, 0x06, 0x27, 0x05, 0xc6, 0xe5, 0x02, 0x26, - 0x36, 0xe9, 0x02, 0x16, 0x04, 0xe5, 0x07, 0x06, - 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, 0x20, 0xe5, - 0x0e, 0x00, 0xc5, 0x00, 0x05, 0x40, 0x65, 0x20, - 0x06, 0x05, 0x47, 0x66, 0x20, 0x27, 0x20, 0x27, - 0x06, 0x05, 0xe0, 0x00, 0x07, 0x60, 0x25, 0x00, - 0x45, 0x26, 0x20, 0xe9, 0x02, 0x25, 0x2d, 0xab, - 0x0f, 0x0d, 0x05, 0x16, 0x06, 0x20, 0x26, 0x07, - 0x00, 0xa5, 0x60, 0x25, 0x20, 0xe5, 0x0e, 0x00, - 0xc5, 0x00, 0x25, 0x00, 0x25, 0x00, 0x25, 0x20, - 0x06, 0x00, 0x47, 0x26, 0x60, 0x26, 0x20, 0x46, - 0x40, 0x06, 0xc0, 0x65, 0x00, 0x05, 0xc0, 0xe9, - 0x02, 0x26, 0x45, 0x06, 0x16, 0xe0, 0x02, 0x26, - 0x07, 0x00, 0xe5, 0x01, 0x00, 0x45, 0x00, 0xe5, - 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x85, 0x20, - 0x06, 0x05, 0x47, 0x86, 0x00, 0x26, 0x07, 0x00, - 0x27, 0x06, 0x20, 0x05, 0xe0, 0x07, 0x25, 0x26, - 0x20, 0xe9, 0x02, 0x16, 0x0d, 0xc0, 0x05, 0xa6, - 0x00, 0x06, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, - 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, - 0x85, 0x20, 0x06, 0x05, 0x07, 0x06, 0x07, 0x66, - 0x20, 0x27, 0x20, 0x27, 0x06, 0xc0, 0x26, 0x07, - 0x60, 0x25, 0x00, 0x45, 0x26, 0x20, 0xe9, 0x02, - 0x0f, 0x05, 0xab, 0xe0, 0x02, 0x06, 0x05, 0x00, - 0xa5, 0x40, 0x45, 0x00, 0x65, 0x40, 0x25, 0x00, - 0x05, 0x00, 0x25, 0x40, 0x25, 0x40, 0x45, 0x40, - 0xe5, 0x04, 0x60, 0x27, 0x06, 0x27, 0x40, 0x47, - 0x00, 0x47, 0x06, 0x20, 0x05, 0xa0, 0x07, 0xe0, - 0x06, 0xe9, 0x02, 0x4b, 0xaf, 0x0d, 0x0f, 0x80, - 0x06, 0x47, 0x06, 0xe5, 0x00, 0x00, 0x45, 0x00, - 0xe5, 0x0f, 0x00, 0xe5, 0x08, 0x40, 0x05, 0x46, - 0x67, 0x00, 0x46, 0x00, 0x66, 0xc0, 0x26, 0x00, - 0x45, 0x80, 0x25, 0x26, 0x20, 0xe9, 0x02, 0xc0, - 0x16, 0xcb, 0x0f, 0x05, 0x06, 0x27, 0x16, 0xe5, - 0x00, 0x00, 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, - 0x02, 0x00, 0x85, 0x20, 0x06, 0x05, 0x07, 0x06, - 0x87, 0x00, 0x06, 0x27, 0x00, 0x27, 0x26, 0xc0, - 0x27, 0xc0, 0x05, 0x00, 0x25, 0x26, 0x20, 0xe9, - 0x02, 0x00, 0x25, 0xe0, 0x05, 0x26, 0x27, 0xe5, - 0x01, 0x00, 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, - 0x47, 0x66, 0x00, 0x47, 0x00, 0x47, 0x06, 0x05, - 0x0f, 0x60, 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, - 0xe9, 0x02, 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, - 0x27, 0x00, 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, - 0xe5, 0x01, 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, - 0x60, 0x47, 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, - 0xa0, 0xe9, 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, - 0xe5, 0x28, 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, - 0x04, 0xe6, 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, - 0x1d, 0x25, 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, - 0x10, 0x00, 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, - 0xe6, 0x01, 0x05, 0x20, 0x85, 0x00, 0x04, 0x00, - 0xa6, 0x20, 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, - 0x05, 0x4f, 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, - 0xaf, 0xe9, 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, - 0x06, 0x0f, 0x06, 0x12, 0x13, 0x12, 0x13, 0x27, - 0xe5, 0x00, 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, - 0x07, 0x86, 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, - 0xe6, 0x1c, 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, - 0x2f, 0x96, 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, - 0x27, 0x66, 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, - 0x05, 0xe9, 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, - 0x46, 0x05, 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, - 0x05, 0x06, 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, - 0xe9, 0x02, 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, - 0x01, 0x80, 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, - 0x42, 0xe5, 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, - 0x00, 0x05, 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, - 0x65, 0x20, 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, - 0x00, 0x05, 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, - 0xe5, 0x31, 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, - 0x46, 0xf6, 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, - 0xef, 0x02, 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, - 0x11, 0xe5, 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, - 0x17, 0xe5, 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, - 0x56, 0x4a, 0xe5, 0x00, 0xc0, 0xe5, 0x05, 0x00, - 0x65, 0x46, 0xe0, 0x03, 0xe5, 0x0a, 0x46, 0x36, - 0xe0, 0x01, 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, - 0x05, 0x00, 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, - 0x2c, 0x26, 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, - 0xe6, 0x03, 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, - 0x20, 0xe9, 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, - 0x11, 0x76, 0x46, 0x1b, 0x00, 0xe9, 0x02, 0xa0, - 0xe5, 0x1b, 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, - 0xe5, 0x1a, 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, - 0x02, 0xe5, 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, - 0x60, 0x27, 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, - 0x36, 0xe9, 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, - 0x03, 0xe5, 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, - 0x02, 0x0b, 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, - 0x27, 0x06, 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, - 0x07, 0xc6, 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, - 0x00, 0xa7, 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, - 0xa0, 0xe9, 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, - 0xe6, 0x06, 0x08, 0x26, 0xe0, 0x37, 0x66, 0x07, - 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87, - 0x06, 0x27, 0xc5, 0x60, 0xe9, 0x02, 0xd6, 0xef, - 0x02, 0xe6, 0x01, 0xef, 0x01, 0x40, 0x26, 0x07, - 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26, 0x07, 0x46, - 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06, 0x07, 0x26, - 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0, 0x00, 0x76, - 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00, 0x27, 0x26, - 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45, 0xe9, 0x02, - 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01, 0xc0, 0xe1, - 0x23, 0x20, 0x41, 0xf6, 0x00, 0xe0, 0x00, 0x46, - 0x16, 0xe6, 0x05, 0x07, 0xc6, 0x65, 0x06, 0xa5, - 0x06, 0x25, 0x07, 0x26, 0x05, 0x80, 0xe2, 0x24, - 0xe4, 0x37, 0xe2, 0x05, 0x04, 0xe2, 0x1a, 0xe4, - 0x1d, 0xe6, 0x32, 0x00, 0x86, 0xff, 0x80, 0x0e, - 0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00, - 0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00, - 0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, - 0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20, - 0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, - 0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61, - 0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61, - 0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e, - 0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22, - 0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1, - 0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14, - 0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01, - 0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13, - 0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17, - 0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab, - 0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12, - 0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x18, 0xe0, - 0x08, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04, - 0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02, - 0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c, - 0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, - 0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f, - 0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f, - 0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a, - 0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c, - 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17, - 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec, - 0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13, - 0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49, - 0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac, - 0xef, 0x3d, 0xe0, 0x11, 0xef, 0x03, 0xe0, 0x0d, - 0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, 0x80, - 0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, 0xec, - 0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, 0xef, - 0x24, 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, 0x12, - 0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, 0xec, - 0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, 0xac, - 0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, 0x61, - 0xe1, 0x27, 0x00, 0xe2, 0x27, 0x00, 0x5f, 0x21, - 0x22, 0xdf, 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, - 0x24, 0x41, 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, - 0x46, 0x3f, 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, - 0x00, 0x02, 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, - 0x04, 0x16, 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, - 0x01, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, - 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, - 0x00, 0xe6, 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, - 0x56, 0x14, 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, - 0x11, 0x36, 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, - 0x15, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x96, 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, - 0x16, 0x12, 0xf6, 0x05, 0x2f, 0x16, 0xe0, 0x25, - 0xef, 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, - 0x80, 0x4e, 0xe0, 0x12, 0xef, 0x04, 0x60, 0x17, - 0x56, 0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x11, 0x12, 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, - 0x11, 0x84, 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, - 0x00, 0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, - 0x11, 0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, - 0x23, 0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, - 0x02, 0xe5, 0x18, 0xef, 0x1c, 0xe0, 0x04, 0xe5, - 0x08, 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, - 0xeb, 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, - 0x02, 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, - 0xe5, 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, - 0x75, 0x40, 0xe5, 0x0d, 0x04, 0xe5, 0x83, 0xef, - 0x40, 0xef, 0x2f, 0xe0, 0x01, 0xe5, 0x20, 0xa4, - 0x36, 0xe5, 0x80, 0x84, 0x04, 0x56, 0xe5, 0x08, - 0xe9, 0x02, 0x25, 0xe0, 0x0c, 0xff, 0x26, 0x05, - 0x06, 0x48, 0x16, 0xe6, 0x02, 0x16, 0x04, 0xff, - 0x14, 0x24, 0x26, 0xe5, 0x3e, 0xea, 0x02, 0x26, - 0xb6, 0xe0, 0x00, 0xee, 0x0f, 0xe4, 0x01, 0x2e, - 0xff, 0x06, 0x22, 0xff, 0x36, 0x04, 0xe2, 0x00, - 0x9f, 0xff, 0x02, 0x04, 0x2e, 0x7f, 0x05, 0x7f, - 0x22, 0xff, 0x0d, 0x61, 0x02, 0x81, 0x02, 0xff, - 0x02, 0x20, 0x5f, 0x41, 0x02, 0x3f, 0xe0, 0x22, - 0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06, 0x45, 0x06, - 0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26, 0x07, 0x6f, - 0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f, 0xa0, 0xe5, - 0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5, 0x2a, 0xe7, - 0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9, 0x02, 0xa0, - 0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16, 0x25, 0x06, - 0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00, 0x36, 0xe5, - 0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03, 0x16, 0xe5, - 0x15, 0x40, 0x46, 0x07, 0xe5, 0x27, 0x06, 0x27, - 0x66, 0x27, 0x26, 0x47, 0xf6, 0x05, 0x00, 0x04, - 0xe9, 0x02, 0x60, 0x36, 0x85, 0x06, 0x04, 0xe5, - 0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5, 0x21, 0xa6, - 0x27, 0x26, 0x27, 0x26, 0xe0, 0x01, 0x45, 0x06, - 0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9, 0x02, 0x20, - 0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f, 0x05, 0x07, - 0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05, 0x46, 0x25, - 0x26, 0x85, 0x26, 0x05, 0x06, 0x05, 0xe0, 0x10, - 0x25, 0x04, 0x36, 0xe5, 0x03, 0x07, 0x26, 0x27, - 0x36, 0x05, 0x24, 0x07, 0x06, 0xe0, 0x02, 0xa5, - 0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01, 0xc5, 0x00, - 0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64, 0xe2, 0x01, - 0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5, 0x1b, 0x27, - 0x06, 0x27, 0x06, 0x27, 0x16, 0x07, 0x06, 0x20, - 0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c, 0xe0, 0x04, - 0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60, 0xfc, 0x87, - 0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80, 0xe6, 0x20, - 0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0, 0x04, 0x82, - 0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c, 0xe5, 0x05, - 0x00, 0x85, 0x00, 0x05, 0x00, 0x25, 0x00, 0x25, - 0x00, 0xe5, 0x64, 0xee, 0x08, 0xe0, 0x09, 0xe5, - 0x80, 0xe3, 0x13, 0x12, 0xe0, 0x08, 0xe5, 0x38, - 0x20, 0xe5, 0x2e, 0xe0, 0x20, 0xe5, 0x04, 0x0d, - 0x0f, 0x20, 0xe6, 0x08, 0xd6, 0x12, 0x13, 0x16, - 0xa0, 0xe6, 0x08, 0x16, 0x31, 0x30, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x36, 0x12, - 0x13, 0x76, 0x50, 0x56, 0x00, 0x76, 0x11, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x56, 0x0c, 0x11, - 0x4c, 0x00, 0x16, 0x0d, 0x36, 0x60, 0x85, 0x00, - 0xe5, 0x7f, 0x20, 0x1b, 0x00, 0x56, 0x0d, 0x56, - 0x12, 0x13, 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, - 0x02, 0x36, 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, - 0x13, 0x0e, 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, - 0x13, 0x0c, 0x12, 0x13, 0x16, 0x12, 0x13, 0x36, - 0xe5, 0x02, 0x04, 0xe5, 0x25, 0x24, 0xe5, 0x17, - 0x40, 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0x20, 0x45, - 0x40, 0x2d, 0x0c, 0x0e, 0x0f, 0x2d, 0x00, 0x0f, - 0x6c, 0x2f, 0xe0, 0x02, 0x5b, 0x2f, 0x20, 0xe5, - 0x04, 0x00, 0xe5, 0x12, 0x00, 0xe5, 0x0b, 0x00, - 0x25, 0x00, 0xe5, 0x07, 0x20, 0xe5, 0x06, 0xe0, - 0x1a, 0xe5, 0x73, 0x80, 0x56, 0x60, 0xeb, 0x25, - 0x40, 0xef, 0x01, 0xea, 0x2d, 0x6b, 0xef, 0x09, - 0x2b, 0x4f, 0x00, 0xef, 0x05, 0x40, 0x0f, 0xe0, - 0x27, 0xef, 0x25, 0x06, 0xe0, 0x7a, 0xe5, 0x15, - 0x40, 0xe5, 0x29, 0xe0, 0x07, 0x06, 0xeb, 0x13, - 0x60, 0xe5, 0x18, 0x6b, 0xe0, 0x01, 0xe5, 0x0c, - 0x0a, 0xe5, 0x00, 0x0a, 0x80, 0xe5, 0x1e, 0x86, - 0x80, 0xe5, 0x16, 0x00, 0x16, 0xe5, 0x1c, 0x60, - 0xe5, 0x00, 0x16, 0x8a, 0xe0, 0x22, 0xe1, 0x20, - 0xe2, 0x20, 0xe5, 0x46, 0x20, 0xe9, 0x02, 0xa0, - 0xe1, 0x1c, 0x60, 0xe2, 0x1c, 0x60, 0xe5, 0x20, - 0xe0, 0x00, 0xe5, 0x2c, 0xe0, 0x03, 0x16, 0xe0, - 0x80, 0x08, 0xe5, 0x80, 0xaf, 0xe0, 0x01, 0xe5, - 0x0e, 0xe0, 0x02, 0xe5, 0x00, 0xe0, 0x80, 0x10, - 0xa5, 0x20, 0x05, 0x00, 0xe5, 0x24, 0x00, 0x25, - 0x40, 0x05, 0x20, 0xe5, 0x0f, 0x00, 0x16, 0xeb, - 0x00, 0xe5, 0x0f, 0x2f, 0xcb, 0xe5, 0x17, 0xe0, - 0x00, 0xeb, 0x01, 0xe0, 0x28, 0xe5, 0x0b, 0x00, - 0x25, 0x80, 0x8b, 0xe5, 0x0e, 0xab, 0x40, 0x16, - 0xe5, 0x12, 0x80, 0x16, 0xe0, 0x38, 0xe5, 0x30, - 0x60, 0x2b, 0x25, 0xeb, 0x08, 0x20, 0xeb, 0x26, - 0x05, 0x46, 0x00, 0x26, 0x80, 0x66, 0x65, 0x00, - 0x45, 0x00, 0xe5, 0x15, 0x20, 0x46, 0x60, 0x06, - 0xeb, 0x01, 0xc0, 0xf6, 0x01, 0xc0, 0xe5, 0x15, - 0x2b, 0x16, 0xe5, 0x15, 0x4b, 0xe0, 0x18, 0xe5, - 0x00, 0x0f, 0xe5, 0x14, 0x26, 0x60, 0x8b, 0xd6, - 0xe0, 0x01, 0xe5, 0x2e, 0x40, 0xd6, 0xe5, 0x0e, - 0x20, 0xeb, 0x00, 0xe5, 0x0b, 0x80, 0xeb, 0x00, - 0xe5, 0x0a, 0xc0, 0x76, 0xe0, 0x04, 0xcb, 0xe0, - 0x48, 0xe5, 0x41, 0xe0, 0x2f, 0xe1, 0x2b, 0xe0, - 0x05, 0xe2, 0x2b, 0xc0, 0xab, 0xe5, 0x1c, 0x66, - 0xe0, 0x00, 0xe9, 0x02, 0xe0, 0x80, 0x9e, 0xeb, - 0x17, 0x00, 0xe5, 0x22, 0x00, 0x26, 0x11, 0x20, - 0x25, 0xe0, 0x46, 0xe5, 0x15, 0xeb, 0x02, 0x05, - 0xe0, 0x00, 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96, - 0xe0, 0x4e, 0xe5, 0x0d, 0xcb, 0xe0, 0x0c, 0xe5, - 0x0f, 0xe0, 0x01, 0x07, 0x06, 0x07, 0xe5, 0x2d, - 0xe6, 0x07, 0xd6, 0x60, 0xeb, 0x0c, 0xe9, 0x02, - 0xe0, 0x07, 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66, - 0x27, 0x26, 0x36, 0x1b, 0x76, 0xe0, 0x03, 0x1b, - 0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0, 0x46, - 0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00, 0xe9, - 0x02, 0x76, 0x05, 0x27, 0x05, 0xe0, 0x00, 0xe5, - 0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01, 0x26, 0x07, - 0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27, 0x65, 0x76, - 0x66, 0x16, 0x07, 0x06, 0xe9, 0x02, 0x05, 0x16, - 0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03, 0xe5, - 0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46, 0x27, 0x06, - 0x07, 0x26, 0xb6, 0x06, 0xe0, 0x39, 0xc5, 0x00, - 0x05, 0x00, 0x65, 0x00, 0xe5, 0x07, 0x00, 0xe5, - 0x02, 0x16, 0xa0, 0xe5, 0x27, 0x06, 0x47, 0xe6, - 0x00, 0x80, 0xe9, 0x02, 0xa0, 0x26, 0x27, 0x00, - 0xe5, 0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, - 0xc5, 0x00, 0x25, 0x00, 0x85, 0x00, 0x26, 0x05, - 0x27, 0x06, 0x67, 0x20, 0x27, 0x20, 0x47, 0x20, - 0x05, 0xa0, 0x07, 0x80, 0x85, 0x27, 0x20, 0xc6, - 0x40, 0x86, 0xe0, 0x80, 0x03, 0xe5, 0x2d, 0x47, - 0xe6, 0x00, 0x27, 0x46, 0x07, 0x06, 0x65, 0x96, - 0xe9, 0x02, 0x36, 0x00, 0x16, 0x06, 0x45, 0xe0, - 0x16, 0xe5, 0x28, 0x47, 0xa6, 0x07, 0x06, 0x67, - 0x26, 0x07, 0x26, 0x25, 0x16, 0x05, 0xe0, 0x00, - 0xe9, 0x02, 0xe0, 0x80, 0x1e, 0xe5, 0x27, 0x47, - 0x66, 0x20, 0x67, 0x26, 0x07, 0x26, 0xf6, 0x0f, - 0x65, 0x26, 0xe0, 0x1a, 0xe5, 0x28, 0x47, 0xe6, - 0x00, 0x27, 0x06, 0x07, 0x26, 0x56, 0x05, 0xe0, - 0x03, 0xe9, 0x02, 0xa0, 0xf6, 0x05, 0xe0, 0x0b, - 0xe5, 0x23, 0x06, 0x07, 0x06, 0x27, 0xa6, 0x07, - 0x06, 0x05, 0xc0, 0xe9, 0x02, 0xe0, 0x2e, 0xe5, - 0x13, 0x20, 0x46, 0x27, 0x66, 0x07, 0x86, 0x60, - 0xe9, 0x02, 0x2b, 0x56, 0x0f, 0xe0, 0x80, 0x38, - 0xe5, 0x24, 0x47, 0xe6, 0x01, 0x07, 0x26, 0x16, - 0xe0, 0x5c, 0xe1, 0x18, 0xe2, 0x18, 0xe9, 0x02, - 0xeb, 0x01, 0xe0, 0x04, 0xe5, 0x00, 0x20, 0x05, - 0x20, 0xe5, 0x00, 0x00, 0x25, 0x00, 0xe5, 0x10, - 0xa7, 0x00, 0x27, 0x20, 0x26, 0x07, 0x06, 0x05, - 0x07, 0x05, 0x07, 0x06, 0x56, 0xe0, 0x01, 0xe9, - 0x02, 0xe0, 0x3e, 0xe5, 0x00, 0x20, 0xe5, 0x1f, - 0x47, 0x66, 0x20, 0x26, 0x67, 0x06, 0x05, 0x16, - 0x05, 0x07, 0xe0, 0x13, 0x05, 0xe6, 0x02, 0xe5, - 0x20, 0xa6, 0x07, 0x05, 0x66, 0xf6, 0x00, 0x06, - 0xe0, 0x00, 0x05, 0xa6, 0x27, 0x46, 0xe5, 0x26, - 0xe6, 0x05, 0x07, 0x26, 0x56, 0x05, 0x96, 0xe0, - 0x15, 0xe5, 0x31, 0xe0, 0x80, 0x7f, 0xe5, 0x01, - 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, 0x07, - 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, 0xeb, - 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, 0x0e, - 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26, 0xe0, - 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e, 0xa6, - 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05, 0x06, - 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00, 0x25, - 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00, 0x27, - 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02, 0xe0, - 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, 0xe0, - 0x80, 0x2f, 0x05, 0xe0, 0x07, 0xeb, 0x0d, 0xef, - 0x00, 0x6d, 0xef, 0x09, 0xe0, 0x05, 0x16, 0xe5, - 0x83, 0x12, 0xe0, 0x5e, 0xea, 0x67, 0x00, 0x96, - 0xe0, 0x03, 0xe5, 0x80, 0x3c, 0xe0, 0x8a, 0x34, - 0xe5, 0x83, 0xa7, 0x00, 0xfb, 0x01, 0xe0, 0x8f, - 0x3f, 0xe5, 0x81, 0xbf, 0xe0, 0xa1, 0x31, 0xe5, - 0x81, 0xb1, 0xc0, 0xe5, 0x17, 0x00, 0xe9, 0x02, - 0x60, 0x36, 0xe0, 0x58, 0xe5, 0x16, 0x20, 0x86, - 0x16, 0xe0, 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, - 0x64, 0x16, 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, - 0xcb, 0x00, 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, - 0x82, 0x28, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f, - 0x76, 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05, - 0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38, - 0x24, 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0, - 0x06, 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84, - 0x4e, 0xe0, 0x22, 0xe5, 0x01, 0xe0, 0xa2, 0x6f, - 0xe5, 0x80, 0x97, 0xe0, 0x29, 0x45, 0xe0, 0x09, - 0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04, 0xe0, 0x88, - 0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05, 0x40, 0xe5, - 0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f, 0x26, 0x16, - 0x7b, 0xe0, 0x92, 0xd4, 0xef, 0x80, 0x6e, 0xe0, - 0x02, 0xef, 0x1f, 0x20, 0xef, 0x34, 0x27, 0x46, - 0x4f, 0xa7, 0xfb, 0x00, 0xe6, 0x00, 0x2f, 0xc6, - 0xef, 0x16, 0x66, 0xef, 0x33, 0xe0, 0x0f, 0xef, - 0x3a, 0x46, 0x0f, 0xe0, 0x80, 0x12, 0xeb, 0x0c, - 0xe0, 0x04, 0xef, 0x4f, 0xe0, 0x01, 0xeb, 0x11, - 0xe0, 0x7f, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, - 0xc2, 0x00, 0xe2, 0x0a, 0xe1, 0x12, 0xe2, 0x12, - 0x01, 0x00, 0x21, 0x20, 0x01, 0x20, 0x21, 0x20, - 0x61, 0x00, 0xe1, 0x00, 0x62, 0x00, 0x02, 0x00, - 0xc2, 0x00, 0xe2, 0x03, 0xe1, 0x12, 0xe2, 0x12, - 0x21, 0x00, 0x61, 0x20, 0xe1, 0x00, 0x00, 0xc1, - 0x00, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x00, 0x81, - 0x00, 0x01, 0x40, 0xc1, 0x00, 0xe2, 0x12, 0xe1, - 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, - 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, - 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x14, 0x20, - 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, - 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, - 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, - 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, - 0x11, 0x0c, 0xa2, 0x3f, 0x20, 0xe9, 0x2a, 0xef, - 0x81, 0x78, 0xe6, 0x2f, 0x6f, 0xe6, 0x2a, 0xef, - 0x00, 0x06, 0xef, 0x06, 0x06, 0x2f, 0x96, 0xe0, - 0x07, 0x86, 0x00, 0xe6, 0x07, 0xe0, 0x84, 0xc8, - 0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6, 0x00, 0x26, - 0x00, 0x86, 0xe0, 0x80, 0x4d, 0xe5, 0x25, 0x40, - 0xc6, 0xc4, 0x20, 0xe9, 0x02, 0x60, 0x05, 0x0f, - 0xe0, 0x80, 0xe8, 0xe5, 0x24, 0x66, 0xe9, 0x02, - 0x80, 0x0d, 0xe0, 0x84, 0x78, 0xe5, 0x80, 0x3d, - 0x20, 0xeb, 0x01, 0xc6, 0xe0, 0x21, 0xe1, 0x1a, - 0xe2, 0x1a, 0xc6, 0x04, 0x60, 0xe9, 0x02, 0x60, - 0x36, 0xe0, 0x82, 0x89, 0xeb, 0x33, 0x0f, 0x4b, - 0x0d, 0x6b, 0xe0, 0x44, 0xeb, 0x25, 0x0f, 0xeb, - 0x07, 0xe0, 0x80, 0x3a, 0x65, 0x00, 0xe5, 0x13, - 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5, - 0x02, 0x00, 0x65, 0x00, 0x05, 0x00, 0x05, 0xa0, - 0x05, 0x60, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x45, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x25, 0x00, 0x05, 0x20, 0x65, 0x00, 0xc5, 0x00, - 0x65, 0x00, 0x65, 0x00, 0x05, 0x00, 0xe5, 0x02, - 0x00, 0xe5, 0x09, 0x80, 0x45, 0x00, 0x85, 0x00, - 0xe5, 0x09, 0xe0, 0x2c, 0x2c, 0xe0, 0x80, 0x86, - 0xef, 0x24, 0x60, 0xef, 0x5c, 0xe0, 0x04, 0xef, - 0x07, 0x20, 0xef, 0x07, 0x00, 0xef, 0x07, 0x00, - 0xef, 0x1d, 0xe0, 0x02, 0xeb, 0x05, 0xef, 0x80, - 0x19, 0xe0, 0x30, 0xef, 0x15, 0xe0, 0x05, 0xef, - 0x24, 0x60, 0xef, 0x01, 0xc0, 0x2f, 0xe0, 0x06, - 0xaf, 0xe0, 0x80, 0x12, 0xef, 0x80, 0x73, 0x8e, - 0xef, 0x82, 0x50, 0xe0, 0x00, 0xef, 0x05, 0x40, - 0xef, 0x05, 0x40, 0xef, 0x6c, 0xe0, 0x04, 0xef, - 0x51, 0xc0, 0xef, 0x04, 0xe0, 0x0c, 0xef, 0x04, - 0x60, 0xef, 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0, - 0xef, 0x20, 0xe0, 0x00, 0xef, 0x16, 0x20, 0x2f, - 0xe0, 0x46, 0xef, 0x71, 0x00, 0xef, 0x4a, 0x00, - 0xef, 0x7f, 0xe0, 0x04, 0xef, 0x06, 0x20, 0x8f, - 0x40, 0x4f, 0x80, 0xcf, 0xe0, 0x01, 0xef, 0x11, - 0xc0, 0xcf, 0xe0, 0x01, 0x4f, 0xe0, 0x05, 0xcf, - 0xe0, 0x21, 0xef, 0x80, 0x0b, 0x00, 0xef, 0x2f, - 0xe0, 0x1d, 0xe9, 0x02, 0xe0, 0x83, 0x7e, 0xe5, - 0xc0, 0x66, 0x56, 0xe0, 0x1a, 0xe5, 0x8f, 0xad, - 0xe0, 0x03, 0xe5, 0x80, 0x56, 0x20, 0xe5, 0x95, - 0xfa, 0xe0, 0x06, 0xe5, 0x9c, 0xa9, 0xe0, 0x8b, - 0x97, 0xe5, 0x81, 0x96, 0xe0, 0x85, 0x5a, 0xe5, - 0x92, 0xc3, 0xe0, 0xca, 0xac, 0x2e, 0x1b, 0xe0, - 0x16, 0xfb, 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68, - 0xe0, 0xc0, 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76, - 0x20, 0xfd, 0xc0, 0xbf, 0x76, 0x20, -}; - -typedef enum { - UNICODE_SCRIPT_Unknown, - UNICODE_SCRIPT_Adlam, - UNICODE_SCRIPT_Ahom, - UNICODE_SCRIPT_Anatolian_Hieroglyphs, - UNICODE_SCRIPT_Arabic, - UNICODE_SCRIPT_Armenian, - UNICODE_SCRIPT_Avestan, - UNICODE_SCRIPT_Balinese, - UNICODE_SCRIPT_Bamum, - UNICODE_SCRIPT_Bassa_Vah, - UNICODE_SCRIPT_Batak, - UNICODE_SCRIPT_Bengali, - UNICODE_SCRIPT_Bhaiksuki, - UNICODE_SCRIPT_Bopomofo, - UNICODE_SCRIPT_Brahmi, - UNICODE_SCRIPT_Braille, - UNICODE_SCRIPT_Buginese, - UNICODE_SCRIPT_Buhid, - UNICODE_SCRIPT_Canadian_Aboriginal, - UNICODE_SCRIPT_Carian, - UNICODE_SCRIPT_Caucasian_Albanian, - UNICODE_SCRIPT_Chakma, - UNICODE_SCRIPT_Cham, - UNICODE_SCRIPT_Cherokee, - UNICODE_SCRIPT_Chorasmian, - UNICODE_SCRIPT_Common, - UNICODE_SCRIPT_Coptic, - UNICODE_SCRIPT_Cuneiform, - UNICODE_SCRIPT_Cypriot, - UNICODE_SCRIPT_Cyrillic, - UNICODE_SCRIPT_Deseret, - UNICODE_SCRIPT_Devanagari, - UNICODE_SCRIPT_Dives_Akuru, - UNICODE_SCRIPT_Dogra, - UNICODE_SCRIPT_Duployan, - UNICODE_SCRIPT_Egyptian_Hieroglyphs, - UNICODE_SCRIPT_Elbasan, - UNICODE_SCRIPT_Elymaic, - UNICODE_SCRIPT_Ethiopic, - UNICODE_SCRIPT_Georgian, - UNICODE_SCRIPT_Glagolitic, - UNICODE_SCRIPT_Gothic, - UNICODE_SCRIPT_Grantha, - UNICODE_SCRIPT_Greek, - UNICODE_SCRIPT_Gujarati, - UNICODE_SCRIPT_Gunjala_Gondi, - UNICODE_SCRIPT_Gurmukhi, - UNICODE_SCRIPT_Han, - UNICODE_SCRIPT_Hangul, - UNICODE_SCRIPT_Hanifi_Rohingya, - UNICODE_SCRIPT_Hanunoo, - UNICODE_SCRIPT_Hatran, - UNICODE_SCRIPT_Hebrew, - UNICODE_SCRIPT_Hiragana, - UNICODE_SCRIPT_Imperial_Aramaic, - UNICODE_SCRIPT_Inherited, - UNICODE_SCRIPT_Inscriptional_Pahlavi, - UNICODE_SCRIPT_Inscriptional_Parthian, - UNICODE_SCRIPT_Javanese, - UNICODE_SCRIPT_Kaithi, - UNICODE_SCRIPT_Kannada, - UNICODE_SCRIPT_Katakana, - UNICODE_SCRIPT_Kayah_Li, - UNICODE_SCRIPT_Kharoshthi, - UNICODE_SCRIPT_Khmer, - UNICODE_SCRIPT_Khojki, - UNICODE_SCRIPT_Khitan_Small_Script, - UNICODE_SCRIPT_Khudawadi, - UNICODE_SCRIPT_Lao, - UNICODE_SCRIPT_Latin, - UNICODE_SCRIPT_Lepcha, - UNICODE_SCRIPT_Limbu, - UNICODE_SCRIPT_Linear_A, - UNICODE_SCRIPT_Linear_B, - UNICODE_SCRIPT_Lisu, - UNICODE_SCRIPT_Lycian, - UNICODE_SCRIPT_Lydian, - UNICODE_SCRIPT_Makasar, - UNICODE_SCRIPT_Mahajani, - UNICODE_SCRIPT_Malayalam, - UNICODE_SCRIPT_Mandaic, - UNICODE_SCRIPT_Manichaean, - UNICODE_SCRIPT_Marchen, - UNICODE_SCRIPT_Masaram_Gondi, - UNICODE_SCRIPT_Medefaidrin, - UNICODE_SCRIPT_Meetei_Mayek, - UNICODE_SCRIPT_Mende_Kikakui, - UNICODE_SCRIPT_Meroitic_Cursive, - UNICODE_SCRIPT_Meroitic_Hieroglyphs, - UNICODE_SCRIPT_Miao, - UNICODE_SCRIPT_Modi, - UNICODE_SCRIPT_Mongolian, - UNICODE_SCRIPT_Mro, - UNICODE_SCRIPT_Multani, - UNICODE_SCRIPT_Myanmar, - UNICODE_SCRIPT_Nabataean, - UNICODE_SCRIPT_Nandinagari, - UNICODE_SCRIPT_New_Tai_Lue, - UNICODE_SCRIPT_Newa, - UNICODE_SCRIPT_Nko, - UNICODE_SCRIPT_Nushu, - UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong, - UNICODE_SCRIPT_Ogham, - UNICODE_SCRIPT_Ol_Chiki, - UNICODE_SCRIPT_Old_Hungarian, - UNICODE_SCRIPT_Old_Italic, - UNICODE_SCRIPT_Old_North_Arabian, - UNICODE_SCRIPT_Old_Permic, - UNICODE_SCRIPT_Old_Persian, - UNICODE_SCRIPT_Old_Sogdian, - UNICODE_SCRIPT_Old_South_Arabian, - UNICODE_SCRIPT_Old_Turkic, - UNICODE_SCRIPT_Oriya, - UNICODE_SCRIPT_Osage, - UNICODE_SCRIPT_Osmanya, - UNICODE_SCRIPT_Pahawh_Hmong, - UNICODE_SCRIPT_Palmyrene, - UNICODE_SCRIPT_Pau_Cin_Hau, - UNICODE_SCRIPT_Phags_Pa, - UNICODE_SCRIPT_Phoenician, - UNICODE_SCRIPT_Psalter_Pahlavi, - UNICODE_SCRIPT_Rejang, - UNICODE_SCRIPT_Runic, - UNICODE_SCRIPT_Samaritan, - UNICODE_SCRIPT_Saurashtra, - UNICODE_SCRIPT_Sharada, - UNICODE_SCRIPT_Shavian, - UNICODE_SCRIPT_Siddham, - UNICODE_SCRIPT_SignWriting, - UNICODE_SCRIPT_Sinhala, - UNICODE_SCRIPT_Sogdian, - UNICODE_SCRIPT_Sora_Sompeng, - UNICODE_SCRIPT_Soyombo, - UNICODE_SCRIPT_Sundanese, - UNICODE_SCRIPT_Syloti_Nagri, - UNICODE_SCRIPT_Syriac, - UNICODE_SCRIPT_Tagalog, - UNICODE_SCRIPT_Tagbanwa, - UNICODE_SCRIPT_Tai_Le, - UNICODE_SCRIPT_Tai_Tham, - UNICODE_SCRIPT_Tai_Viet, - UNICODE_SCRIPT_Takri, - UNICODE_SCRIPT_Tamil, - UNICODE_SCRIPT_Tangut, - UNICODE_SCRIPT_Telugu, - UNICODE_SCRIPT_Thaana, - UNICODE_SCRIPT_Thai, - UNICODE_SCRIPT_Tibetan, - UNICODE_SCRIPT_Tifinagh, - UNICODE_SCRIPT_Tirhuta, - UNICODE_SCRIPT_Ugaritic, - UNICODE_SCRIPT_Vai, - UNICODE_SCRIPT_Wancho, - UNICODE_SCRIPT_Warang_Citi, - UNICODE_SCRIPT_Yezidi, - UNICODE_SCRIPT_Yi, - UNICODE_SCRIPT_Zanabazar_Square, - UNICODE_SCRIPT_COUNT, -} UnicodeScriptEnum; - -static const char unicode_script_name_table[] = - "Adlam,Adlm" "\0" - "Ahom,Ahom" "\0" - "Anatolian_Hieroglyphs,Hluw" "\0" - "Arabic,Arab" "\0" - "Armenian,Armn" "\0" - "Avestan,Avst" "\0" - "Balinese,Bali" "\0" - "Bamum,Bamu" "\0" - "Bassa_Vah,Bass" "\0" - "Batak,Batk" "\0" - "Bengali,Beng" "\0" - "Bhaiksuki,Bhks" "\0" - "Bopomofo,Bopo" "\0" - "Brahmi,Brah" "\0" - "Braille,Brai" "\0" - "Buginese,Bugi" "\0" - "Buhid,Buhd" "\0" - "Canadian_Aboriginal,Cans" "\0" - "Carian,Cari" "\0" - "Caucasian_Albanian,Aghb" "\0" - "Chakma,Cakm" "\0" - "Cham,Cham" "\0" - "Cherokee,Cher" "\0" - "Chorasmian,Chrs" "\0" - "Common,Zyyy" "\0" - "Coptic,Copt,Qaac" "\0" - "Cuneiform,Xsux" "\0" - "Cypriot,Cprt" "\0" - "Cyrillic,Cyrl" "\0" - "Deseret,Dsrt" "\0" - "Devanagari,Deva" "\0" - "Dives_Akuru,Diak" "\0" - "Dogra,Dogr" "\0" - "Duployan,Dupl" "\0" - "Egyptian_Hieroglyphs,Egyp" "\0" - "Elbasan,Elba" "\0" - "Elymaic,Elym" "\0" - "Ethiopic,Ethi" "\0" - "Georgian,Geor" "\0" - "Glagolitic,Glag" "\0" - "Gothic,Goth" "\0" - "Grantha,Gran" "\0" - "Greek,Grek" "\0" - "Gujarati,Gujr" "\0" - "Gunjala_Gondi,Gong" "\0" - "Gurmukhi,Guru" "\0" - "Han,Hani" "\0" - "Hangul,Hang" "\0" - "Hanifi_Rohingya,Rohg" "\0" - "Hanunoo,Hano" "\0" - "Hatran,Hatr" "\0" - "Hebrew,Hebr" "\0" - "Hiragana,Hira" "\0" - "Imperial_Aramaic,Armi" "\0" - "Inherited,Zinh,Qaai" "\0" - "Inscriptional_Pahlavi,Phli" "\0" - "Inscriptional_Parthian,Prti" "\0" - "Javanese,Java" "\0" - "Kaithi,Kthi" "\0" - "Kannada,Knda" "\0" - "Katakana,Kana" "\0" - "Kayah_Li,Kali" "\0" - "Kharoshthi,Khar" "\0" - "Khmer,Khmr" "\0" - "Khojki,Khoj" "\0" - "Khitan_Small_Script,Kits" "\0" - "Khudawadi,Sind" "\0" - "Lao,Laoo" "\0" - "Latin,Latn" "\0" - "Lepcha,Lepc" "\0" - "Limbu,Limb" "\0" - "Linear_A,Lina" "\0" - "Linear_B,Linb" "\0" - "Lisu,Lisu" "\0" - "Lycian,Lyci" "\0" - "Lydian,Lydi" "\0" - "Makasar,Maka" "\0" - "Mahajani,Mahj" "\0" - "Malayalam,Mlym" "\0" - "Mandaic,Mand" "\0" - "Manichaean,Mani" "\0" - "Marchen,Marc" "\0" - "Masaram_Gondi,Gonm" "\0" - "Medefaidrin,Medf" "\0" - "Meetei_Mayek,Mtei" "\0" - "Mende_Kikakui,Mend" "\0" - "Meroitic_Cursive,Merc" "\0" - "Meroitic_Hieroglyphs,Mero" "\0" - "Miao,Plrd" "\0" - "Modi,Modi" "\0" - "Mongolian,Mong" "\0" - "Mro,Mroo" "\0" - "Multani,Mult" "\0" - "Myanmar,Mymr" "\0" - "Nabataean,Nbat" "\0" - "Nandinagari,Nand" "\0" - "New_Tai_Lue,Talu" "\0" - "Newa,Newa" "\0" - "Nko,Nkoo" "\0" - "Nushu,Nshu" "\0" - "Nyiakeng_Puachue_Hmong,Hmnp" "\0" - "Ogham,Ogam" "\0" - "Ol_Chiki,Olck" "\0" - "Old_Hungarian,Hung" "\0" - "Old_Italic,Ital" "\0" - "Old_North_Arabian,Narb" "\0" - "Old_Permic,Perm" "\0" - "Old_Persian,Xpeo" "\0" - "Old_Sogdian,Sogo" "\0" - "Old_South_Arabian,Sarb" "\0" - "Old_Turkic,Orkh" "\0" - "Oriya,Orya" "\0" - "Osage,Osge" "\0" - "Osmanya,Osma" "\0" - "Pahawh_Hmong,Hmng" "\0" - "Palmyrene,Palm" "\0" - "Pau_Cin_Hau,Pauc" "\0" - "Phags_Pa,Phag" "\0" - "Phoenician,Phnx" "\0" - "Psalter_Pahlavi,Phlp" "\0" - "Rejang,Rjng" "\0" - "Runic,Runr" "\0" - "Samaritan,Samr" "\0" - "Saurashtra,Saur" "\0" - "Sharada,Shrd" "\0" - "Shavian,Shaw" "\0" - "Siddham,Sidd" "\0" - "SignWriting,Sgnw" "\0" - "Sinhala,Sinh" "\0" - "Sogdian,Sogd" "\0" - "Sora_Sompeng,Sora" "\0" - "Soyombo,Soyo" "\0" - "Sundanese,Sund" "\0" - "Syloti_Nagri,Sylo" "\0" - "Syriac,Syrc" "\0" - "Tagalog,Tglg" "\0" - "Tagbanwa,Tagb" "\0" - "Tai_Le,Tale" "\0" - "Tai_Tham,Lana" "\0" - "Tai_Viet,Tavt" "\0" - "Takri,Takr" "\0" - "Tamil,Taml" "\0" - "Tangut,Tang" "\0" - "Telugu,Telu" "\0" - "Thaana,Thaa" "\0" - "Thai,Thai" "\0" - "Tibetan,Tibt" "\0" - "Tifinagh,Tfng" "\0" - "Tirhuta,Tirh" "\0" - "Ugaritic,Ugar" "\0" - "Vai,Vaii" "\0" - "Wancho,Wcho" "\0" - "Warang_Citi,Wara" "\0" - "Yezidi,Yezi" "\0" - "Yi,Yiii" "\0" - "Zanabazar_Square,Zanb" "\0" -; - -static const uint8_t unicode_script_table[2609] = { - 0xc0, 0x19, 0x99, 0x45, 0x85, 0x19, 0x99, 0x45, - 0xae, 0x19, 0x80, 0x45, 0x8e, 0x19, 0x80, 0x45, - 0x84, 0x19, 0x96, 0x45, 0x80, 0x19, 0x9e, 0x45, - 0x80, 0x19, 0xe1, 0x60, 0x45, 0xa6, 0x19, 0x84, - 0x45, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0, - 0x0f, 0x37, 0x83, 0x2b, 0x80, 0x19, 0x82, 0x2b, - 0x01, 0x83, 0x2b, 0x80, 0x19, 0x80, 0x2b, 0x03, - 0x80, 0x2b, 0x80, 0x19, 0x80, 0x2b, 0x80, 0x19, - 0x82, 0x2b, 0x00, 0x80, 0x2b, 0x00, 0x93, 0x2b, - 0x00, 0xbe, 0x2b, 0x8d, 0x1a, 0x8f, 0x2b, 0xe0, - 0x24, 0x1d, 0x81, 0x37, 0xe0, 0x48, 0x1d, 0x00, - 0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05, - 0x00, 0xb6, 0x34, 0x07, 0x9a, 0x34, 0x03, 0x85, - 0x34, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04, - 0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x80, 0x04, - 0x00, 0x80, 0x04, 0x80, 0x19, 0x9f, 0x04, 0x80, - 0x19, 0x89, 0x04, 0x8a, 0x37, 0x99, 0x04, 0x80, - 0x37, 0xe0, 0x0b, 0x04, 0x80, 0x19, 0xa1, 0x04, - 0x8d, 0x87, 0x00, 0xbb, 0x87, 0x01, 0x82, 0x87, - 0xaf, 0x04, 0xb1, 0x91, 0x0d, 0xba, 0x63, 0x01, - 0x82, 0x63, 0xad, 0x7b, 0x01, 0x8e, 0x7b, 0x00, - 0x9b, 0x50, 0x01, 0x80, 0x50, 0x00, 0x8a, 0x87, - 0x34, 0x94, 0x04, 0x00, 0x91, 0x04, 0x0a, 0x8e, - 0x04, 0x80, 0x19, 0x9c, 0x04, 0xd0, 0x1f, 0x83, - 0x37, 0x8e, 0x1f, 0x81, 0x19, 0x99, 0x1f, 0x83, - 0x0b, 0x00, 0x87, 0x0b, 0x01, 0x81, 0x0b, 0x01, - 0x95, 0x0b, 0x00, 0x86, 0x0b, 0x00, 0x80, 0x0b, - 0x02, 0x83, 0x0b, 0x01, 0x88, 0x0b, 0x01, 0x81, - 0x0b, 0x01, 0x83, 0x0b, 0x07, 0x80, 0x0b, 0x03, - 0x81, 0x0b, 0x00, 0x84, 0x0b, 0x01, 0x98, 0x0b, - 0x01, 0x82, 0x2e, 0x00, 0x85, 0x2e, 0x03, 0x81, - 0x2e, 0x01, 0x95, 0x2e, 0x00, 0x86, 0x2e, 0x00, - 0x81, 0x2e, 0x00, 0x81, 0x2e, 0x00, 0x81, 0x2e, - 0x01, 0x80, 0x2e, 0x00, 0x84, 0x2e, 0x03, 0x81, - 0x2e, 0x01, 0x82, 0x2e, 0x02, 0x80, 0x2e, 0x06, - 0x83, 0x2e, 0x00, 0x80, 0x2e, 0x06, 0x90, 0x2e, - 0x09, 0x82, 0x2c, 0x00, 0x88, 0x2c, 0x00, 0x82, - 0x2c, 0x00, 0x95, 0x2c, 0x00, 0x86, 0x2c, 0x00, - 0x81, 0x2c, 0x00, 0x84, 0x2c, 0x01, 0x89, 0x2c, - 0x00, 0x82, 0x2c, 0x00, 0x82, 0x2c, 0x01, 0x80, - 0x2c, 0x0e, 0x83, 0x2c, 0x01, 0x8b, 0x2c, 0x06, - 0x86, 0x2c, 0x00, 0x82, 0x70, 0x00, 0x87, 0x70, - 0x01, 0x81, 0x70, 0x01, 0x95, 0x70, 0x00, 0x86, - 0x70, 0x00, 0x81, 0x70, 0x00, 0x84, 0x70, 0x01, - 0x88, 0x70, 0x01, 0x81, 0x70, 0x01, 0x82, 0x70, - 0x06, 0x82, 0x70, 0x03, 0x81, 0x70, 0x00, 0x84, - 0x70, 0x01, 0x91, 0x70, 0x09, 0x81, 0x8e, 0x00, - 0x85, 0x8e, 0x02, 0x82, 0x8e, 0x00, 0x83, 0x8e, - 0x02, 0x81, 0x8e, 0x00, 0x80, 0x8e, 0x00, 0x81, - 0x8e, 0x02, 0x81, 0x8e, 0x02, 0x82, 0x8e, 0x02, - 0x8b, 0x8e, 0x03, 0x84, 0x8e, 0x02, 0x82, 0x8e, - 0x00, 0x83, 0x8e, 0x01, 0x80, 0x8e, 0x05, 0x80, - 0x8e, 0x0d, 0x94, 0x8e, 0x04, 0x8c, 0x90, 0x00, - 0x82, 0x90, 0x00, 0x96, 0x90, 0x00, 0x8f, 0x90, - 0x02, 0x87, 0x90, 0x00, 0x82, 0x90, 0x00, 0x83, - 0x90, 0x06, 0x81, 0x90, 0x00, 0x82, 0x90, 0x04, - 0x83, 0x90, 0x01, 0x89, 0x90, 0x06, 0x88, 0x90, - 0x8c, 0x3c, 0x00, 0x82, 0x3c, 0x00, 0x96, 0x3c, - 0x00, 0x89, 0x3c, 0x00, 0x84, 0x3c, 0x01, 0x88, - 0x3c, 0x00, 0x82, 0x3c, 0x00, 0x83, 0x3c, 0x06, - 0x81, 0x3c, 0x06, 0x80, 0x3c, 0x00, 0x83, 0x3c, - 0x01, 0x89, 0x3c, 0x00, 0x81, 0x3c, 0x0c, 0x8c, - 0x4f, 0x00, 0x82, 0x4f, 0x00, 0xb2, 0x4f, 0x00, - 0x82, 0x4f, 0x00, 0x85, 0x4f, 0x03, 0x8f, 0x4f, - 0x01, 0x99, 0x4f, 0x00, 0x82, 0x81, 0x00, 0x91, - 0x81, 0x02, 0x97, 0x81, 0x00, 0x88, 0x81, 0x00, - 0x80, 0x81, 0x01, 0x86, 0x81, 0x02, 0x80, 0x81, - 0x03, 0x85, 0x81, 0x00, 0x80, 0x81, 0x00, 0x87, - 0x81, 0x05, 0x89, 0x81, 0x01, 0x82, 0x81, 0x0b, - 0xb9, 0x92, 0x03, 0x80, 0x19, 0x9b, 0x92, 0x24, - 0x81, 0x44, 0x00, 0x80, 0x44, 0x00, 0x84, 0x44, - 0x00, 0x97, 0x44, 0x00, 0x80, 0x44, 0x00, 0x96, - 0x44, 0x01, 0x84, 0x44, 0x00, 0x80, 0x44, 0x00, - 0x85, 0x44, 0x01, 0x89, 0x44, 0x01, 0x83, 0x44, - 0x1f, 0xc7, 0x93, 0x00, 0xa3, 0x93, 0x03, 0xa6, - 0x93, 0x00, 0xa3, 0x93, 0x00, 0x8e, 0x93, 0x00, - 0x86, 0x93, 0x83, 0x19, 0x81, 0x93, 0x24, 0xe0, - 0x3f, 0x5e, 0xa5, 0x27, 0x00, 0x80, 0x27, 0x04, - 0x80, 0x27, 0x01, 0xaa, 0x27, 0x80, 0x19, 0x83, - 0x27, 0xe0, 0x9f, 0x30, 0xc8, 0x26, 0x00, 0x83, - 0x26, 0x01, 0x86, 0x26, 0x00, 0x80, 0x26, 0x00, - 0x83, 0x26, 0x01, 0xa8, 0x26, 0x00, 0x83, 0x26, - 0x01, 0xa0, 0x26, 0x00, 0x83, 0x26, 0x01, 0x86, - 0x26, 0x00, 0x80, 0x26, 0x00, 0x83, 0x26, 0x01, - 0x8e, 0x26, 0x00, 0xb8, 0x26, 0x00, 0x83, 0x26, - 0x01, 0xc2, 0x26, 0x01, 0x9f, 0x26, 0x02, 0x99, - 0x26, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01, - 0xe2, 0x1f, 0x12, 0x9c, 0x66, 0x02, 0xca, 0x7a, - 0x82, 0x19, 0x8a, 0x7a, 0x06, 0x8c, 0x88, 0x00, - 0x86, 0x88, 0x0a, 0x94, 0x32, 0x81, 0x19, 0x08, - 0x93, 0x11, 0x0b, 0x8c, 0x89, 0x00, 0x82, 0x89, - 0x00, 0x81, 0x89, 0x0b, 0xdd, 0x40, 0x01, 0x89, - 0x40, 0x05, 0x89, 0x40, 0x05, 0x81, 0x5b, 0x81, - 0x19, 0x80, 0x5b, 0x80, 0x19, 0x88, 0x5b, 0x00, - 0x89, 0x5b, 0x05, 0xd8, 0x5b, 0x06, 0xaa, 0x5b, - 0x04, 0xc5, 0x12, 0x09, 0x9e, 0x47, 0x00, 0x8b, - 0x47, 0x03, 0x8b, 0x47, 0x03, 0x80, 0x47, 0x02, - 0x8b, 0x47, 0x9d, 0x8a, 0x01, 0x84, 0x8a, 0x0a, - 0xab, 0x61, 0x03, 0x99, 0x61, 0x05, 0x8a, 0x61, - 0x02, 0x81, 0x61, 0x9f, 0x40, 0x9b, 0x10, 0x01, - 0x81, 0x10, 0xbe, 0x8b, 0x00, 0x9c, 0x8b, 0x01, - 0x8a, 0x8b, 0x05, 0x89, 0x8b, 0x05, 0x8d, 0x8b, - 0x01, 0x90, 0x37, 0x3e, 0xcb, 0x07, 0x03, 0xac, - 0x07, 0x02, 0xbf, 0x85, 0xb3, 0x0a, 0x07, 0x83, - 0x0a, 0xb7, 0x46, 0x02, 0x8e, 0x46, 0x02, 0x82, - 0x46, 0xaf, 0x67, 0x88, 0x1d, 0x06, 0xaa, 0x27, - 0x01, 0x82, 0x27, 0x87, 0x85, 0x07, 0x82, 0x37, - 0x80, 0x19, 0x8c, 0x37, 0x80, 0x19, 0x86, 0x37, - 0x83, 0x19, 0x80, 0x37, 0x85, 0x19, 0x80, 0x37, - 0x82, 0x19, 0x81, 0x37, 0x80, 0x19, 0x04, 0xa5, - 0x45, 0x84, 0x2b, 0x80, 0x1d, 0xb0, 0x45, 0x84, - 0x2b, 0x83, 0x45, 0x84, 0x2b, 0x8c, 0x45, 0x80, - 0x1d, 0xc5, 0x45, 0x80, 0x2b, 0xb9, 0x37, 0x00, - 0x84, 0x37, 0xe0, 0x9f, 0x45, 0x95, 0x2b, 0x01, - 0x85, 0x2b, 0x01, 0xa5, 0x2b, 0x01, 0x85, 0x2b, - 0x01, 0x87, 0x2b, 0x00, 0x80, 0x2b, 0x00, 0x80, - 0x2b, 0x00, 0x80, 0x2b, 0x00, 0x9e, 0x2b, 0x01, - 0xb4, 0x2b, 0x00, 0x8e, 0x2b, 0x00, 0x8d, 0x2b, - 0x01, 0x85, 0x2b, 0x00, 0x92, 0x2b, 0x01, 0x82, - 0x2b, 0x00, 0x88, 0x2b, 0x00, 0x8b, 0x19, 0x81, - 0x37, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, 0x45, - 0x01, 0x8a, 0x19, 0x80, 0x45, 0x8e, 0x19, 0x00, - 0x8c, 0x45, 0x02, 0x9f, 0x19, 0x0f, 0xa0, 0x37, - 0x0e, 0xa5, 0x19, 0x80, 0x2b, 0x82, 0x19, 0x81, - 0x45, 0x85, 0x19, 0x80, 0x45, 0x9a, 0x19, 0x80, - 0x45, 0x90, 0x19, 0xa8, 0x45, 0x82, 0x19, 0x03, - 0xe2, 0x36, 0x19, 0x18, 0x8a, 0x19, 0x14, 0xe3, - 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, 0x19, - 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, 0xae, - 0x28, 0x00, 0xae, 0x28, 0x00, 0x9f, 0x45, 0xe0, - 0x13, 0x1a, 0x04, 0x86, 0x1a, 0xa5, 0x27, 0x00, - 0x80, 0x27, 0x04, 0x80, 0x27, 0x01, 0xb7, 0x94, - 0x06, 0x81, 0x94, 0x0d, 0x80, 0x94, 0x96, 0x26, - 0x08, 0x86, 0x26, 0x00, 0x86, 0x26, 0x00, 0x86, - 0x26, 0x00, 0x86, 0x26, 0x00, 0x86, 0x26, 0x00, - 0x86, 0x26, 0x00, 0x86, 0x26, 0x00, 0x86, 0x26, - 0x00, 0x9f, 0x1d, 0xd2, 0x19, 0x2c, 0x99, 0x2f, - 0x00, 0xd8, 0x2f, 0x0b, 0xe0, 0x75, 0x2f, 0x19, - 0x8b, 0x19, 0x03, 0x84, 0x19, 0x80, 0x2f, 0x80, - 0x19, 0x80, 0x2f, 0x98, 0x19, 0x88, 0x2f, 0x83, - 0x37, 0x81, 0x30, 0x87, 0x19, 0x83, 0x2f, 0x83, - 0x19, 0x00, 0xd5, 0x35, 0x01, 0x81, 0x37, 0x81, - 0x19, 0x82, 0x35, 0x80, 0x19, 0xd9, 0x3d, 0x81, - 0x19, 0x82, 0x3d, 0x04, 0xaa, 0x0d, 0x00, 0xdd, - 0x30, 0x00, 0x8f, 0x19, 0x9f, 0x0d, 0xa3, 0x19, - 0x0b, 0x8f, 0x3d, 0x9e, 0x30, 0x00, 0xbf, 0x19, - 0x9e, 0x30, 0xd0, 0x19, 0xae, 0x3d, 0x80, 0x19, - 0xd7, 0x3d, 0xe0, 0x47, 0x19, 0xf0, 0x09, 0x5f, - 0x2f, 0xbf, 0x19, 0xf0, 0x41, 0x9c, 0x2f, 0x02, - 0xe4, 0x2c, 0x9b, 0x02, 0xb6, 0x9b, 0x08, 0xaf, - 0x4a, 0xe0, 0xcb, 0x97, 0x13, 0xdf, 0x1d, 0xd7, - 0x08, 0x07, 0xa1, 0x19, 0xe0, 0x05, 0x45, 0x82, - 0x19, 0xb4, 0x45, 0x01, 0x88, 0x45, 0x29, 0x8a, - 0x45, 0xac, 0x86, 0x02, 0x89, 0x19, 0x05, 0xb7, - 0x76, 0x07, 0xc5, 0x7c, 0x07, 0x8b, 0x7c, 0x05, - 0x9f, 0x1f, 0xad, 0x3e, 0x80, 0x19, 0x80, 0x3e, - 0xa3, 0x79, 0x0a, 0x80, 0x79, 0x9c, 0x30, 0x02, - 0xcd, 0x3a, 0x00, 0x80, 0x19, 0x89, 0x3a, 0x03, - 0x81, 0x3a, 0x9e, 0x5e, 0x00, 0xb6, 0x16, 0x08, - 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, 0x83, 0x16, - 0x9f, 0x5e, 0xc2, 0x8c, 0x17, 0x84, 0x8c, 0x96, - 0x55, 0x09, 0x85, 0x26, 0x01, 0x85, 0x26, 0x01, - 0x85, 0x26, 0x08, 0x86, 0x26, 0x00, 0x86, 0x26, - 0x00, 0xaa, 0x45, 0x80, 0x19, 0x88, 0x45, 0x80, - 0x2b, 0x83, 0x45, 0x81, 0x19, 0x03, 0xcf, 0x17, - 0xad, 0x55, 0x01, 0x89, 0x55, 0x05, 0xf0, 0x1b, - 0x43, 0x30, 0x0b, 0x96, 0x30, 0x03, 0xb0, 0x30, - 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x2f, 0x01, 0xe0, - 0x09, 0x2f, 0x25, 0x86, 0x45, 0x0b, 0x84, 0x05, - 0x04, 0x99, 0x34, 0x00, 0x84, 0x34, 0x00, 0x80, - 0x34, 0x00, 0x81, 0x34, 0x00, 0x81, 0x34, 0x00, - 0x89, 0x34, 0xe0, 0x11, 0x04, 0x10, 0xe1, 0x0a, - 0x04, 0x81, 0x19, 0x0f, 0xbf, 0x04, 0x01, 0xb5, - 0x04, 0x27, 0x8d, 0x04, 0x01, 0x8f, 0x37, 0x89, - 0x19, 0x05, 0x8d, 0x37, 0x81, 0x1d, 0xa2, 0x19, - 0x00, 0x92, 0x19, 0x00, 0x83, 0x19, 0x03, 0x84, - 0x04, 0x00, 0xe0, 0x26, 0x04, 0x01, 0x80, 0x19, - 0x00, 0x9f, 0x19, 0x99, 0x45, 0x85, 0x19, 0x99, - 0x45, 0x8a, 0x19, 0x89, 0x3d, 0x80, 0x19, 0xac, - 0x3d, 0x81, 0x19, 0x9e, 0x30, 0x02, 0x85, 0x30, - 0x01, 0x85, 0x30, 0x01, 0x85, 0x30, 0x01, 0x82, - 0x30, 0x02, 0x86, 0x19, 0x00, 0x86, 0x19, 0x09, - 0x84, 0x19, 0x01, 0x8b, 0x49, 0x00, 0x99, 0x49, - 0x00, 0x92, 0x49, 0x00, 0x81, 0x49, 0x00, 0x8e, - 0x49, 0x01, 0x8d, 0x49, 0x21, 0xe0, 0x1a, 0x49, - 0x04, 0x82, 0x19, 0x03, 0xac, 0x19, 0x02, 0x88, - 0x19, 0xce, 0x2b, 0x00, 0x8c, 0x19, 0x02, 0x80, - 0x2b, 0x2e, 0xac, 0x19, 0x80, 0x37, 0x60, 0x21, - 0x9c, 0x4b, 0x02, 0xb0, 0x13, 0x0e, 0x80, 0x37, - 0x9a, 0x19, 0x03, 0xa3, 0x69, 0x08, 0x82, 0x69, - 0x9a, 0x29, 0x04, 0xaa, 0x6b, 0x04, 0x9d, 0x96, - 0x00, 0x80, 0x96, 0xa3, 0x6c, 0x03, 0x8d, 0x6c, - 0x29, 0xcf, 0x1e, 0xaf, 0x7e, 0x9d, 0x72, 0x01, - 0x89, 0x72, 0x05, 0xa3, 0x71, 0x03, 0xa3, 0x71, - 0x03, 0xa7, 0x24, 0x07, 0xb3, 0x14, 0x0a, 0x80, - 0x14, 0x60, 0x2f, 0xe0, 0xd6, 0x48, 0x08, 0x95, - 0x48, 0x09, 0x87, 0x48, 0x60, 0x37, 0x85, 0x1c, - 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00, 0x81, - 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c, 0x95, - 0x36, 0x00, 0x88, 0x36, 0x9f, 0x74, 0x9e, 0x5f, - 0x07, 0x88, 0x5f, 0x2f, 0x92, 0x33, 0x00, 0x81, - 0x33, 0x04, 0x84, 0x33, 0x9b, 0x77, 0x02, 0x80, - 0x77, 0x99, 0x4c, 0x04, 0x80, 0x4c, 0x3f, 0x9f, - 0x58, 0x97, 0x57, 0x03, 0x93, 0x57, 0x01, 0xad, - 0x57, 0x83, 0x3f, 0x00, 0x81, 0x3f, 0x04, 0x87, - 0x3f, 0x00, 0x82, 0x3f, 0x00, 0x9c, 0x3f, 0x01, - 0x82, 0x3f, 0x03, 0x89, 0x3f, 0x06, 0x88, 0x3f, - 0x06, 0x9f, 0x6e, 0x9f, 0x6a, 0x1f, 0xa6, 0x51, - 0x03, 0x8b, 0x51, 0x08, 0xb5, 0x06, 0x02, 0x86, - 0x06, 0x95, 0x39, 0x01, 0x87, 0x39, 0x92, 0x38, - 0x04, 0x87, 0x38, 0x91, 0x78, 0x06, 0x83, 0x78, - 0x0b, 0x86, 0x78, 0x4f, 0xc8, 0x6f, 0x36, 0xb2, - 0x68, 0x0c, 0xb2, 0x68, 0x06, 0x85, 0x68, 0xa7, - 0x31, 0x07, 0x89, 0x31, 0x60, 0xc5, 0x9e, 0x04, - 0x00, 0xa9, 0x9a, 0x00, 0x82, 0x9a, 0x01, 0x81, - 0x9a, 0x4d, 0xa7, 0x6d, 0x07, 0xa9, 0x82, 0x55, - 0x9b, 0x18, 0x13, 0x96, 0x25, 0x08, 0xcd, 0x0e, - 0x03, 0x9d, 0x0e, 0x0e, 0x80, 0x0e, 0xc1, 0x3b, - 0x0a, 0x80, 0x3b, 0x01, 0x98, 0x83, 0x06, 0x89, - 0x83, 0x05, 0xb4, 0x15, 0x00, 0x91, 0x15, 0x07, - 0xa6, 0x4e, 0x08, 0xdf, 0x7d, 0x00, 0x93, 0x81, - 0x0a, 0x91, 0x41, 0x00, 0xab, 0x41, 0x40, 0x86, - 0x5d, 0x00, 0x80, 0x5d, 0x00, 0x83, 0x5d, 0x00, - 0x8e, 0x5d, 0x00, 0x8a, 0x5d, 0x05, 0xba, 0x43, - 0x04, 0x89, 0x43, 0x05, 0x83, 0x2a, 0x00, 0x87, - 0x2a, 0x01, 0x81, 0x2a, 0x01, 0x95, 0x2a, 0x00, - 0x86, 0x2a, 0x00, 0x81, 0x2a, 0x00, 0x84, 0x2a, - 0x00, 0x80, 0x37, 0x88, 0x2a, 0x01, 0x81, 0x2a, - 0x01, 0x82, 0x2a, 0x01, 0x80, 0x2a, 0x05, 0x80, - 0x2a, 0x04, 0x86, 0x2a, 0x01, 0x86, 0x2a, 0x02, - 0x84, 0x2a, 0x60, 0x2a, 0xdb, 0x62, 0x00, 0x84, - 0x62, 0x1d, 0xc7, 0x95, 0x07, 0x89, 0x95, 0x60, - 0x45, 0xb5, 0x7f, 0x01, 0xa5, 0x7f, 0x21, 0xc4, - 0x5a, 0x0a, 0x89, 0x5a, 0x05, 0x8c, 0x5b, 0x12, - 0xb8, 0x8d, 0x06, 0x89, 0x8d, 0x35, 0x9a, 0x02, - 0x01, 0x8e, 0x02, 0x03, 0x8f, 0x02, 0x60, 0x5f, - 0xbb, 0x21, 0x60, 0x03, 0xd2, 0x99, 0x0b, 0x80, - 0x99, 0x86, 0x20, 0x01, 0x80, 0x20, 0x01, 0x87, - 0x20, 0x00, 0x81, 0x20, 0x00, 0x9d, 0x20, 0x00, - 0x81, 0x20, 0x01, 0x8b, 0x20, 0x08, 0x89, 0x20, - 0x45, 0x87, 0x60, 0x01, 0xad, 0x60, 0x01, 0x8a, - 0x60, 0x1a, 0xc7, 0x9c, 0x07, 0xd2, 0x84, 0x1c, - 0xb8, 0x75, 0x60, 0xa6, 0x88, 0x0c, 0x00, 0xac, - 0x0c, 0x00, 0x8d, 0x0c, 0x09, 0x9c, 0x0c, 0x02, - 0x9f, 0x52, 0x01, 0x95, 0x52, 0x00, 0x8d, 0x52, - 0x48, 0x86, 0x53, 0x00, 0x81, 0x53, 0x00, 0xab, - 0x53, 0x02, 0x80, 0x53, 0x00, 0x81, 0x53, 0x00, - 0x88, 0x53, 0x07, 0x89, 0x53, 0x05, 0x85, 0x2d, - 0x00, 0x81, 0x2d, 0x00, 0xa4, 0x2d, 0x00, 0x81, - 0x2d, 0x00, 0x85, 0x2d, 0x06, 0x89, 0x2d, 0x60, - 0xd5, 0x98, 0x4d, 0x60, 0x56, 0x80, 0x4a, 0x0e, - 0xb1, 0x8e, 0x0c, 0x80, 0x8e, 0xe3, 0x39, 0x1b, - 0x60, 0x05, 0xe0, 0x0e, 0x1b, 0x00, 0x84, 0x1b, - 0x0a, 0xe0, 0x63, 0x1b, 0x6a, 0x5b, 0xe3, 0xce, - 0x23, 0x00, 0x88, 0x23, 0x6f, 0x66, 0xe1, 0xe6, - 0x03, 0x70, 0x11, 0x58, 0xe1, 0xd8, 0x08, 0x06, - 0x9e, 0x5c, 0x00, 0x89, 0x5c, 0x03, 0x81, 0x5c, - 0x5f, 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, - 0x73, 0x09, 0x89, 0x73, 0x00, 0x86, 0x73, 0x00, - 0x94, 0x73, 0x04, 0x92, 0x73, 0x62, 0x4f, 0xda, - 0x54, 0x60, 0x04, 0xca, 0x59, 0x03, 0xb8, 0x59, - 0x06, 0x90, 0x59, 0x3f, 0x80, 0x8f, 0x80, 0x64, - 0x81, 0x19, 0x80, 0x42, 0x0a, 0x81, 0x2f, 0x0d, - 0xf0, 0x07, 0x97, 0x8f, 0x07, 0xe2, 0x9f, 0x8f, - 0xe1, 0x75, 0x42, 0x29, 0x88, 0x8f, 0x70, 0x12, - 0x96, 0x80, 0x3d, 0xe0, 0xbd, 0x35, 0x30, 0x82, - 0x35, 0x10, 0x83, 0x3d, 0x07, 0xe1, 0x2b, 0x64, - 0x68, 0xa3, 0xe0, 0x0a, 0x22, 0x04, 0x8c, 0x22, - 0x02, 0x88, 0x22, 0x06, 0x89, 0x22, 0x01, 0x83, - 0x22, 0x83, 0x19, 0x70, 0x02, 0xfb, 0xe0, 0x95, - 0x19, 0x09, 0xa6, 0x19, 0x01, 0xbd, 0x19, 0x82, - 0x37, 0x90, 0x19, 0x87, 0x37, 0x81, 0x19, 0x86, - 0x37, 0x9d, 0x19, 0x83, 0x37, 0xba, 0x19, 0x16, - 0xc5, 0x2b, 0x60, 0x39, 0x93, 0x19, 0x0b, 0xd6, - 0x19, 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4, 0x19, - 0x00, 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01, 0x80, - 0x19, 0x01, 0x81, 0x19, 0x01, 0x83, 0x19, 0x00, - 0x8b, 0x19, 0x00, 0x80, 0x19, 0x00, 0x86, 0x19, - 0x00, 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01, 0x87, - 0x19, 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19, 0x00, - 0x83, 0x19, 0x00, 0x84, 0x19, 0x00, 0x80, 0x19, - 0x02, 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19, 0x01, - 0xe0, 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2, 0x2b, - 0x80, 0x0e, 0x84, 0x80, 0x00, 0x8e, 0x80, 0x64, - 0xef, 0x86, 0x28, 0x00, 0x90, 0x28, 0x01, 0x86, - 0x28, 0x00, 0x81, 0x28, 0x00, 0x84, 0x28, 0x60, - 0x74, 0xac, 0x65, 0x02, 0x8d, 0x65, 0x01, 0x89, - 0x65, 0x03, 0x81, 0x65, 0x61, 0x0f, 0xb9, 0x98, - 0x04, 0x80, 0x98, 0x64, 0x9f, 0xe0, 0x64, 0x56, - 0x01, 0x8f, 0x56, 0x28, 0xcb, 0x01, 0x03, 0x89, - 0x01, 0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19, - 0x4b, 0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00, - 0x9a, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, - 0x01, 0x80, 0x04, 0x00, 0x89, 0x04, 0x00, 0x83, - 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x05, - 0x80, 0x04, 0x03, 0x80, 0x04, 0x00, 0x80, 0x04, - 0x00, 0x80, 0x04, 0x00, 0x82, 0x04, 0x00, 0x81, - 0x04, 0x00, 0x80, 0x04, 0x01, 0x80, 0x04, 0x00, - 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, - 0x00, 0x80, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, - 0x04, 0x01, 0x83, 0x04, 0x00, 0x86, 0x04, 0x00, - 0x83, 0x04, 0x00, 0x83, 0x04, 0x00, 0x80, 0x04, - 0x00, 0x89, 0x04, 0x00, 0x90, 0x04, 0x04, 0x82, - 0x04, 0x00, 0x84, 0x04, 0x00, 0x90, 0x04, 0x33, - 0x81, 0x04, 0x60, 0xad, 0xab, 0x19, 0x03, 0xe0, - 0x03, 0x19, 0x0b, 0x8e, 0x19, 0x01, 0x8e, 0x19, - 0x00, 0x8e, 0x19, 0x00, 0xa4, 0x19, 0x09, 0xe0, - 0x4d, 0x19, 0x37, 0x99, 0x19, 0x80, 0x35, 0x81, - 0x19, 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06, - 0x81, 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3, - 0x77, 0x19, 0x07, 0x8c, 0x19, 0x02, 0x8c, 0x19, - 0x02, 0xe0, 0x13, 0x19, 0x0b, 0xd8, 0x19, 0x06, - 0x8b, 0x19, 0x13, 0x8b, 0x19, 0x03, 0xb7, 0x19, - 0x07, 0x89, 0x19, 0x05, 0xa7, 0x19, 0x07, 0x9d, - 0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0, 0x18, 0x19, - 0x00, 0xd1, 0x19, 0x00, 0xe0, 0x26, 0x19, 0x0b, - 0x8d, 0x19, 0x01, 0x84, 0x19, 0x02, 0x82, 0x19, - 0x04, 0x86, 0x19, 0x08, 0x98, 0x19, 0x06, 0x86, - 0x19, 0x08, 0x82, 0x19, 0x0c, 0x86, 0x19, 0x28, - 0xe0, 0x32, 0x19, 0x00, 0xb6, 0x19, 0x24, 0x89, - 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7d, 0x2f, 0x21, - 0xef, 0xd4, 0x2f, 0x0a, 0xe0, 0x7d, 0x2f, 0x01, - 0xf0, 0x06, 0x21, 0x2f, 0x0d, 0xf0, 0x0c, 0xd0, - 0x2f, 0x6b, 0xbe, 0xe1, 0xbd, 0x2f, 0x65, 0x81, - 0xf0, 0x02, 0xea, 0x2f, 0x7a, 0xdc, 0x55, 0x80, - 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, 0x8f, - 0x37, -}; - -static const uint8_t unicode_script_ext_table[799] = { - 0x82, 0xc1, 0x00, 0x00, 0x01, 0x2b, 0x01, 0x00, - 0x00, 0x01, 0x2b, 0x1c, 0x00, 0x0c, 0x01, 0x45, - 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6b, 0x00, - 0x02, 0x1d, 0x28, 0x01, 0x02, 0x1d, 0x45, 0x00, - 0x02, 0x1d, 0x28, 0x81, 0x03, 0x00, 0x00, 0x05, - 0x04, 0x31, 0x87, 0x91, 0x9a, 0x0d, 0x00, 0x00, - 0x05, 0x04, 0x31, 0x87, 0x91, 0x9a, 0x00, 0x03, - 0x04, 0x87, 0x91, 0x01, 0x00, 0x00, 0x05, 0x04, - 0x31, 0x87, 0x91, 0x9a, 0x1f, 0x00, 0x00, 0x08, - 0x01, 0x04, 0x50, 0x51, 0x78, 0x31, 0x82, 0x87, - 0x09, 0x00, 0x0a, 0x02, 0x04, 0x87, 0x09, 0x00, - 0x09, 0x03, 0x04, 0x91, 0x9a, 0x05, 0x00, 0x00, - 0x02, 0x04, 0x87, 0x62, 0x00, 0x00, 0x02, 0x04, - 0x31, 0x81, 0xfb, 0x00, 0x00, 0x0d, 0x0b, 0x1f, - 0x2a, 0x2c, 0x2e, 0x3c, 0x45, 0x4f, 0x70, 0x7d, - 0x8e, 0x90, 0x95, 0x00, 0x0c, 0x0b, 0x1f, 0x2a, - 0x2c, 0x2e, 0x3c, 0x45, 0x4f, 0x70, 0x8e, 0x90, - 0x95, 0x10, 0x00, 0x00, 0x14, 0x0b, 0x1f, 0x21, - 0x2d, 0x53, 0x2a, 0x2c, 0x2e, 0x3c, 0x4e, 0x4f, - 0x60, 0x70, 0x43, 0x81, 0x86, 0x8d, 0x8e, 0x90, - 0x95, 0x00, 0x15, 0x0b, 0x1f, 0x21, 0x2d, 0x53, - 0x2a, 0x2c, 0x2e, 0x3c, 0x47, 0x4e, 0x4f, 0x60, - 0x70, 0x43, 0x81, 0x86, 0x8d, 0x8e, 0x90, 0x95, - 0x09, 0x04, 0x1f, 0x21, 0x3b, 0x4e, 0x75, 0x00, - 0x09, 0x03, 0x0b, 0x15, 0x86, 0x75, 0x00, 0x09, - 0x02, 0x2e, 0x5d, 0x75, 0x00, 0x09, 0x02, 0x2c, - 0x41, 0x80, 0x75, 0x00, 0x0d, 0x02, 0x2a, 0x8e, - 0x80, 0x71, 0x00, 0x09, 0x02, 0x3c, 0x60, 0x82, - 0xcf, 0x00, 0x09, 0x03, 0x15, 0x5e, 0x8a, 0x80, - 0x30, 0x00, 0x00, 0x02, 0x27, 0x45, 0x85, 0xb8, - 0x00, 0x01, 0x04, 0x11, 0x32, 0x89, 0x88, 0x80, - 0x4a, 0x00, 0x01, 0x02, 0x5b, 0x76, 0x00, 0x00, - 0x00, 0x02, 0x5b, 0x76, 0x84, 0x49, 0x00, 0x00, - 0x04, 0x0b, 0x1f, 0x2a, 0x3c, 0x00, 0x01, 0x1f, - 0x00, 0x04, 0x0b, 0x1f, 0x2a, 0x3c, 0x00, 0x02, - 0x1f, 0x2a, 0x00, 0x01, 0x1f, 0x01, 0x02, 0x0b, - 0x1f, 0x00, 0x02, 0x1f, 0x7d, 0x00, 0x02, 0x0b, - 0x1f, 0x00, 0x02, 0x1f, 0x7d, 0x00, 0x06, 0x1f, - 0x3c, 0x4f, 0x70, 0x8e, 0x90, 0x00, 0x01, 0x1f, - 0x01, 0x02, 0x1f, 0x7d, 0x01, 0x01, 0x1f, 0x00, - 0x02, 0x1f, 0x7d, 0x00, 0x02, 0x0b, 0x1f, 0x06, - 0x01, 0x1f, 0x00, 0x02, 0x1f, 0x60, 0x00, 0x02, - 0x0b, 0x1f, 0x01, 0x01, 0x1f, 0x00, 0x02, 0x0b, - 0x1f, 0x03, 0x01, 0x1f, 0x00, 0x08, 0x0b, 0x1f, - 0x2a, 0x3c, 0x60, 0x70, 0x90, 0x95, 0x00, 0x02, - 0x1f, 0x2a, 0x00, 0x03, 0x1f, 0x2a, 0x3c, 0x01, - 0x02, 0x0b, 0x1f, 0x00, 0x01, 0x0b, 0x01, 0x02, - 0x1f, 0x2a, 0x00, 0x01, 0x60, 0x80, 0x44, 0x00, - 0x01, 0x01, 0x2b, 0x35, 0x00, 0x00, 0x02, 0x1d, - 0x87, 0x81, 0xb5, 0x00, 0x00, 0x02, 0x45, 0x5b, - 0x80, 0x3f, 0x00, 0x00, 0x03, 0x1f, 0x2a, 0x45, - 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d, 0x28, 0x81, - 0x3c, 0x00, 0x01, 0x06, 0x0d, 0x30, 0x2f, 0x35, - 0x3d, 0x9b, 0x00, 0x05, 0x0d, 0x30, 0x2f, 0x35, - 0x3d, 0x01, 0x00, 0x00, 0x01, 0x2f, 0x00, 0x00, - 0x09, 0x06, 0x0d, 0x30, 0x2f, 0x35, 0x3d, 0x9b, - 0x00, 0x00, 0x00, 0x05, 0x0d, 0x30, 0x2f, 0x35, - 0x3d, 0x07, 0x06, 0x0d, 0x30, 0x2f, 0x35, 0x3d, - 0x9b, 0x03, 0x05, 0x0d, 0x30, 0x2f, 0x35, 0x3d, - 0x09, 0x00, 0x03, 0x02, 0x0d, 0x2f, 0x01, 0x00, - 0x00, 0x05, 0x0d, 0x30, 0x2f, 0x35, 0x3d, 0x04, - 0x02, 0x35, 0x3d, 0x00, 0x00, 0x00, 0x05, 0x0d, - 0x30, 0x2f, 0x35, 0x3d, 0x03, 0x00, 0x01, 0x03, - 0x2f, 0x35, 0x3d, 0x01, 0x01, 0x2f, 0x58, 0x00, - 0x03, 0x02, 0x35, 0x3d, 0x02, 0x00, 0x00, 0x02, - 0x35, 0x3d, 0x59, 0x00, 0x00, 0x06, 0x0d, 0x30, - 0x2f, 0x35, 0x3d, 0x9b, 0x00, 0x02, 0x35, 0x3d, - 0x80, 0x12, 0x00, 0x0f, 0x01, 0x2f, 0x1f, 0x00, - 0x23, 0x01, 0x2f, 0x3b, 0x00, 0x27, 0x01, 0x2f, - 0x37, 0x00, 0x30, 0x01, 0x2f, 0x0e, 0x00, 0x0b, - 0x01, 0x2f, 0x32, 0x00, 0x00, 0x01, 0x2f, 0x57, - 0x00, 0x18, 0x01, 0x2f, 0x09, 0x00, 0x04, 0x01, - 0x2f, 0x5f, 0x00, 0x1e, 0x01, 0x2f, 0xc0, 0x31, - 0xef, 0x00, 0x00, 0x02, 0x1d, 0x28, 0x80, 0x0f, - 0x00, 0x07, 0x02, 0x2f, 0x45, 0x80, 0xa7, 0x00, - 0x02, 0x0e, 0x1f, 0x21, 0x2c, 0x2e, 0x41, 0x3c, - 0x3b, 0x4e, 0x4f, 0x5a, 0x60, 0x43, 0x8d, 0x95, - 0x02, 0x0d, 0x1f, 0x21, 0x2c, 0x2e, 0x41, 0x3c, - 0x3b, 0x4e, 0x5a, 0x60, 0x43, 0x8d, 0x95, 0x03, - 0x0b, 0x1f, 0x21, 0x2c, 0x2e, 0x41, 0x3b, 0x4e, - 0x5a, 0x43, 0x8d, 0x95, 0x80, 0x36, 0x00, 0x00, - 0x02, 0x0b, 0x1f, 0x00, 0x00, 0x00, 0x02, 0x1f, - 0x8e, 0x39, 0x00, 0x00, 0x03, 0x3e, 0x45, 0x5e, - 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10, 0x3a, 0xc0, - 0x13, 0xa1, 0x00, 0x00, 0x02, 0x04, 0x91, 0x09, - 0x00, 0x00, 0x02, 0x04, 0x91, 0x46, 0x00, 0x01, - 0x05, 0x0d, 0x30, 0x2f, 0x35, 0x3d, 0x80, 0x99, - 0x00, 0x04, 0x06, 0x0d, 0x30, 0x2f, 0x35, 0x3d, - 0x9b, 0x09, 0x00, 0x00, 0x02, 0x35, 0x3d, 0x2c, - 0x00, 0x01, 0x02, 0x35, 0x3d, 0x80, 0xdf, 0x00, - 0x02, 0x02, 0x1c, 0x49, 0x03, 0x00, 0x2c, 0x03, - 0x1c, 0x48, 0x49, 0x02, 0x00, 0x08, 0x02, 0x1c, - 0x49, 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, - 0x8f, 0x84, 0x00, 0x00, 0x02, 0x2a, 0x8e, 0x00, - 0x00, 0x00, 0x02, 0x2a, 0x8e, 0x36, 0x00, 0x01, - 0x02, 0x2a, 0x8e, 0x8c, 0x12, 0x00, 0x01, 0x02, - 0x2a, 0x8e, 0x00, 0x00, 0x00, 0x02, 0x2a, 0x8e, - 0xc0, 0x5c, 0x4b, 0x00, 0x03, 0x01, 0x22, 0x96, - 0x3b, 0x00, 0x11, 0x01, 0x2f, 0x9e, 0x5d, 0x00, - 0x01, 0x01, 0x2f, 0xce, 0xcd, 0x2d, 0x00, -}; - -static const uint8_t unicode_prop_Hyphen_table[28] = { - 0xac, 0x80, 0xfe, 0x80, 0x44, 0xdb, 0x80, 0x52, - 0x7a, 0x80, 0x48, 0x08, 0x81, 0x4e, 0x04, 0x80, - 0x42, 0xe2, 0x80, 0x60, 0xcd, 0x66, 0x80, 0x40, - 0xa8, 0x80, 0xd6, 0x80, -}; - -static const uint8_t unicode_prop_Other_Math_table[200] = { - 0xdd, 0x80, 0x43, 0x70, 0x11, 0x80, 0x99, 0x09, - 0x81, 0x5c, 0x1f, 0x80, 0x9a, 0x82, 0x8a, 0x80, - 0x9f, 0x83, 0x97, 0x81, 0x8d, 0x81, 0xc0, 0x8c, - 0x18, 0x11, 0x1c, 0x91, 0x03, 0x01, 0x89, 0x00, - 0x14, 0x28, 0x11, 0x09, 0x02, 0x05, 0x13, 0x24, - 0xca, 0x21, 0x18, 0x08, 0x08, 0x00, 0x21, 0x0b, - 0x0b, 0x91, 0x09, 0x00, 0x06, 0x00, 0x29, 0x41, - 0x21, 0x83, 0x40, 0xa7, 0x08, 0x80, 0x97, 0x80, - 0x90, 0x80, 0x41, 0xbc, 0x81, 0x8b, 0x88, 0x24, - 0x21, 0x09, 0x14, 0x8d, 0x00, 0x01, 0x85, 0x97, - 0x81, 0xb8, 0x00, 0x80, 0x9c, 0x83, 0x88, 0x81, - 0x41, 0x55, 0x81, 0x9e, 0x89, 0x41, 0x92, 0x95, - 0xbe, 0x83, 0x9f, 0x81, 0x60, 0xd4, 0x62, 0x00, - 0x03, 0x80, 0x40, 0xd2, 0x00, 0x80, 0x60, 0xd4, - 0xc0, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, - 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, - 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, - 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, - 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, - 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x81, - 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00, 0x08, - 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, - 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, - 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, -}; - -static const uint8_t unicode_prop_Other_Alphabetic_table[411] = { - 0x43, 0x44, 0x80, 0x42, 0x69, 0x8d, 0x00, 0x01, - 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, 0x06, 0x8f, - 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, 0xa2, 0x80, - 0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a, 0x88, 0x02, - 0x03, 0x40, 0xa6, 0x8b, 0x16, 0x85, 0x93, 0xb5, - 0x09, 0x8e, 0x01, 0x22, 0x89, 0x81, 0x9c, 0x82, - 0xb9, 0x31, 0x09, 0x81, 0x89, 0x80, 0x89, 0x81, - 0x9c, 0x82, 0xb9, 0x23, 0x09, 0x0b, 0x80, 0x9d, - 0x0a, 0x80, 0x8a, 0x82, 0xb9, 0x38, 0x10, 0x81, - 0x94, 0x81, 0x95, 0x13, 0x82, 0xb9, 0x31, 0x09, - 0x81, 0x88, 0x81, 0x89, 0x81, 0x9d, 0x80, 0xba, - 0x22, 0x10, 0x82, 0x89, 0x80, 0xa7, 0x83, 0xb9, - 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9c, 0x82, - 0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9b, - 0x83, 0xb9, 0x30, 0x10, 0x82, 0x89, 0x80, 0x89, - 0x81, 0x9c, 0x82, 0xca, 0x28, 0x00, 0x87, 0x91, - 0x81, 0xbc, 0x01, 0x86, 0x91, 0x80, 0xe2, 0x01, - 0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2, 0x90, 0x8a, - 0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00, 0x0b, 0x96, - 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x00, - 0x89, 0x83, 0x46, 0x73, 0x81, 0x9d, 0x81, 0x9d, - 0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40, 0xbb, 0x81, - 0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88, 0x40, 0xdd, - 0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9, 0x81, 0xbe, - 0x84, 0xaf, 0x8e, 0xbb, 0x82, 0x9d, 0x88, 0x09, - 0xb8, 0x8a, 0xb1, 0x92, 0x41, 0xaf, 0x8d, 0x46, - 0xc0, 0xb3, 0x48, 0xf5, 0x9f, 0x60, 0x78, 0x73, - 0x87, 0xa1, 0x81, 0x41, 0x61, 0x07, 0x80, 0x96, - 0x84, 0xd7, 0x81, 0xb1, 0x8f, 0x00, 0xb8, 0x80, - 0xa5, 0x84, 0x9b, 0x8b, 0xac, 0x83, 0xaf, 0x8b, - 0xa4, 0x80, 0xc2, 0x8d, 0x8b, 0x07, 0x81, 0xac, - 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x80, 0xab, 0x24, - 0x80, 0x40, 0xec, 0x87, 0x60, 0x4f, 0x32, 0x80, - 0x48, 0x56, 0x84, 0x46, 0x85, 0x10, 0x0c, 0x83, - 0x43, 0x13, 0x83, 0x41, 0x82, 0x81, 0x41, 0x52, - 0x82, 0xb4, 0x8d, 0xbb, 0x80, 0xac, 0x88, 0xc6, - 0x82, 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, - 0x8c, 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x40, - 0x9f, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81, - 0x89, 0x80, 0x89, 0x81, 0x40, 0xd0, 0x8c, 0x02, - 0xe9, 0x91, 0x40, 0xec, 0x31, 0x86, 0x9c, 0x81, - 0xd1, 0x8e, 0x00, 0xe9, 0x8a, 0xe6, 0x8d, 0x41, - 0x00, 0x8c, 0x40, 0xf6, 0x28, 0x09, 0x0a, 0x00, - 0x80, 0x40, 0x8d, 0x31, 0x2b, 0x80, 0x9b, 0x89, - 0xa9, 0x20, 0x83, 0x91, 0x8a, 0xad, 0x8d, 0x41, - 0x96, 0x38, 0x86, 0xd2, 0x95, 0x80, 0x8d, 0xf9, - 0x2a, 0x00, 0x08, 0x10, 0x02, 0x80, 0xc1, 0x20, - 0x08, 0x83, 0x41, 0x5b, 0x83, 0x60, 0x50, 0x57, - 0x00, 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, - 0x80, 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, - 0x04, 0x49, 0x1b, 0x80, 0x47, 0xe7, 0x99, 0x85, - 0x99, 0x85, 0x99, -}; - -static const uint8_t unicode_prop_Other_Lowercase_table[51] = { - 0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88, - 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x59, - 0xb0, 0xbe, 0x8c, 0x80, 0xa1, 0xa4, 0x42, 0xb0, - 0x80, 0x8c, 0x80, 0x8f, 0x8c, 0x40, 0xd2, 0x8f, - 0x43, 0x4f, 0x99, 0x47, 0x91, 0x81, 0x60, 0x7a, - 0x1d, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x86, 0x81, - 0x43, 0x61, 0x83, -}; - -static const uint8_t unicode_prop_Other_Uppercase_table[15] = { - 0x60, 0x21, 0x5f, 0x8f, 0x43, 0x45, 0x99, 0x61, - 0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99, -}; - -static const uint8_t unicode_prop_Other_Grapheme_Extend_table[65] = { - 0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80, - 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe9, - 0x80, 0x91, 0x81, 0xe6, 0x80, 0x97, 0x80, 0xf6, - 0x80, 0x8e, 0x80, 0x4d, 0x54, 0x80, 0x44, 0xd5, - 0x80, 0x50, 0x20, 0x81, 0x60, 0xcf, 0x6d, 0x81, - 0x53, 0x9d, 0x80, 0x97, 0x80, 0x41, 0x57, 0x80, - 0x8b, 0x80, 0x40, 0xf0, 0x80, 0x43, 0x7f, 0x80, - 0x60, 0xb8, 0x33, 0x07, 0x84, 0x6c, 0x2e, 0xac, - 0xdf, -}; - -static const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = { - 0x43, 0x4e, 0x80, 0x4e, 0x0e, 0x81, 0x46, 0x52, - 0x81, 0x48, 0xae, 0x80, 0x50, 0xfd, 0x80, 0x60, - 0xce, 0x3a, 0x80, 0xce, 0x88, 0x6d, 0x00, 0x06, - 0x00, 0x9d, 0xdf, 0xff, 0x40, 0xef, 0x4e, 0x0f, -}; - -static const uint8_t unicode_prop_Other_ID_Start_table[11] = { - 0x58, 0x84, 0x81, 0x48, 0x90, 0x80, 0x94, 0x80, - 0x4f, 0x6b, 0x81, -}; - -static const uint8_t unicode_prop_Other_ID_Continue_table[12] = { - 0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0, - 0x88, 0x46, 0x67, 0x80, -}; - -static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[17] = { - 0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80, - 0x41, 0xd1, 0x80, 0x61, 0x07, 0xd9, 0x80, 0x8e, - 0x80, -}; - -static const uint8_t unicode_prop_XID_Start1_table[31] = { - 0x43, 0x79, 0x80, 0x4a, 0xb7, 0x80, 0xfe, 0x80, - 0x60, 0x21, 0xe6, 0x81, 0x60, 0xcb, 0xc0, 0x85, - 0x41, 0x95, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x80, 0x41, 0x1e, 0x81, -}; - -static const uint8_t unicode_prop_XID_Continue1_table[23] = { - 0x43, 0x79, 0x80, 0x60, 0x2d, 0x1f, 0x81, 0x60, - 0xcb, 0xc0, 0x85, 0x41, 0x95, 0x81, 0xf3, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -}; - -static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = { - 0x41, 0xc3, 0x08, 0x08, 0x81, 0xa4, 0x81, 0x4e, - 0xdc, 0xaa, 0x0a, 0x4e, 0x87, 0x3f, 0x3f, 0x87, - 0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80, -}; - -static const uint8_t unicode_prop_Changes_When_Casefolded1_table[33] = { - 0x40, 0xde, 0x80, 0xcf, 0x80, 0x97, 0x80, 0x44, - 0x3c, 0x80, 0x59, 0x11, 0x80, 0x40, 0xe4, 0x3f, - 0x3f, 0x87, 0x89, 0x11, 0x05, 0x02, 0x11, 0x80, - 0xa9, 0x11, 0x80, 0x60, 0xdb, 0x07, 0x86, 0x8b, - 0x84, -}; - -static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[441] = { - 0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12, - 0x10, 0x82, 0x9f, 0x80, 0xcf, 0x01, 0x80, 0x8b, - 0x07, 0x80, 0xfb, 0x01, 0x01, 0x80, 0xa5, 0x80, - 0x40, 0xbb, 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, - 0x81, 0x89, 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, - 0x80, 0xc9, 0x82, 0x9c, 0x80, 0x41, 0x93, 0x80, - 0x40, 0x93, 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, - 0xfb, 0x08, 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, - 0x80, 0x40, 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, - 0x80, 0xa7, 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, - 0x03, 0x03, 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, - 0x26, 0x80, 0x90, 0x80, 0x88, 0x03, 0x03, 0x03, - 0x80, 0x8b, 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, - 0x46, 0x52, 0x81, 0xd4, 0x83, 0x45, 0x1c, 0x10, - 0x8a, 0x80, 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, - 0xa4, 0x40, 0xd9, 0x80, 0x40, 0xd5, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x3f, 0x87, - 0x89, 0x11, 0x04, 0x00, 0x29, 0x04, 0x12, 0x80, - 0x88, 0x12, 0x80, 0x88, 0x11, 0x11, 0x04, 0x08, - 0x8f, 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, - 0x00, 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, - 0x80, 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, - 0x01, 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, - 0x05, 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, - 0x40, 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, - 0x34, 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, - 0x82, 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, - 0x80, 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, - 0xd5, 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, - 0x80, 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, - 0x9e, 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, - 0x60, 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40, - 0x86, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60, - 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89, - 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xa5, - 0x86, 0x8b, 0x24, 0x00, 0x97, 0x04, 0x00, 0x01, - 0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a, 0x91, 0xbf, - 0x81, 0xb5, 0xa7, 0x8c, 0x82, 0x99, 0x95, 0x94, - 0x81, 0x8b, 0x80, 0x92, 0x03, 0x1a, 0x00, 0x80, - 0x40, 0x86, 0x08, 0x80, 0x9f, 0x99, 0x40, 0x83, - 0x15, 0x0d, 0x0d, 0x0a, 0x16, 0x06, 0x80, 0x88, - 0x60, 0xbc, 0xa6, 0x83, 0x54, 0xb9, 0x86, 0x8d, - 0x87, 0xbf, 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6, - 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, - 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, - 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81, 0x41, - 0x23, 0x81, 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, - 0x00, 0x08, 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, - 0x18, 0x00, 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, - 0x03, 0x00, 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, - 0x80, 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, - 0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, - 0xab, 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, - 0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, - 0xff, -}; - -static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = { - 0xaf, 0x89, 0x35, 0x99, 0x85, -}; - -static const uint8_t unicode_prop_Bidi_Control_table[10] = { - 0x46, 0x1b, 0x80, 0x59, 0xf0, 0x81, 0x99, 0x84, - 0xb6, 0x83, -}; - -static const uint8_t unicode_prop_Dash_table[53] = { - 0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e, - 0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85, - 0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85, - 0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80, - 0x41, 0xda, 0x80, 0x92, 0x80, 0xee, 0x80, 0x60, - 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89, 0x80, 0x40, - 0xa8, 0x80, 0x4f, 0x9e, 0x80, -}; - -static const uint8_t unicode_prop_Deprecated_table[23] = { - 0x41, 0x48, 0x80, 0x45, 0x28, 0x80, 0x49, 0x02, - 0x00, 0x80, 0x48, 0x28, 0x81, 0x48, 0xc4, 0x85, - 0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80, -}; - -static const uint8_t unicode_prop_Diacritic_table[358] = { - 0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81, - 0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b, - 0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0, - 0x80, 0xb6, 0x90, 0x80, 0x9a, 0x00, 0x01, 0x00, - 0x40, 0x85, 0x3b, 0x81, 0x40, 0x85, 0x0b, 0x0a, - 0x82, 0xc2, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0xa1, - 0x81, 0x40, 0xc8, 0x9b, 0xbc, 0x80, 0x8f, 0x02, - 0x83, 0x9b, 0x80, 0xc9, 0x80, 0x8f, 0x80, 0xed, - 0x80, 0x8f, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xae, - 0x82, 0xbb, 0x80, 0x8f, 0x06, 0x80, 0xf6, 0x80, - 0xfe, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xec, 0x81, - 0x8f, 0x80, 0xfb, 0x80, 0xfb, 0x28, 0x80, 0xea, - 0x80, 0x8c, 0x84, 0xca, 0x81, 0x9a, 0x00, 0x00, - 0x03, 0x81, 0xc1, 0x10, 0x81, 0xbd, 0x80, 0xef, - 0x00, 0x81, 0xa7, 0x0b, 0x84, 0x98, 0x30, 0x80, - 0x89, 0x81, 0x42, 0xc0, 0x82, 0x44, 0x68, 0x8a, - 0x88, 0x80, 0x41, 0x5a, 0x82, 0x41, 0x38, 0x39, - 0x80, 0xaf, 0x8d, 0xf5, 0x80, 0x8e, 0x80, 0xa5, - 0x88, 0xb5, 0x81, 0x40, 0x89, 0x81, 0xbf, 0x85, - 0xd1, 0x98, 0x18, 0x28, 0x0a, 0xb1, 0xbe, 0xd8, - 0x8b, 0xa4, 0x22, 0x82, 0x41, 0xbc, 0x00, 0x82, - 0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c, 0x81, - 0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80, 0x41, 0xf9, - 0x85, 0xe8, 0x83, 0xde, 0x80, 0x60, 0x75, 0x71, - 0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81, 0xd1, 0x81, - 0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81, 0x40, 0xc9, - 0x80, 0x9a, 0x91, 0xb8, 0x83, 0xa3, 0x80, 0xde, - 0x80, 0x8b, 0x80, 0xa3, 0x80, 0x40, 0x94, 0x82, - 0xc0, 0x83, 0xb2, 0x80, 0xe3, 0x84, 0x88, 0x82, - 0xff, 0x81, 0x60, 0x4f, 0x2f, 0x80, 0x43, 0x00, - 0x8f, 0x41, 0x0d, 0x00, 0x80, 0xae, 0x80, 0xac, - 0x81, 0xc2, 0x80, 0x42, 0xfb, 0x80, 0x48, 0x03, - 0x81, 0x42, 0x3a, 0x85, 0x42, 0x1d, 0x8a, 0x41, - 0x67, 0x81, 0xf7, 0x81, 0xbd, 0x80, 0xcb, 0x80, - 0x88, 0x82, 0xe7, 0x81, 0x40, 0xb1, 0x81, 0xd0, - 0x80, 0x8f, 0x80, 0x97, 0x32, 0x84, 0x40, 0xcc, - 0x02, 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd, - 0x80, 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81, - 0x41, 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2, - 0x80, 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80, - 0x41, 0x01, 0x00, 0x81, 0xd0, 0x80, 0x60, 0x4d, - 0x57, 0x84, 0xba, 0x86, 0x44, 0x57, 0x90, 0xcf, - 0x81, 0x60, 0x61, 0x74, 0x12, 0x2f, 0x39, 0x86, - 0x9d, 0x83, 0x4f, 0x81, 0x86, 0x41, 0xb4, 0x83, - 0x45, 0xdf, 0x86, 0xec, 0x10, 0x82, -}; - -static const uint8_t unicode_prop_Extender_table[89] = { - 0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d, - 0x80, 0x41, 0xb8, 0x80, 0x43, 0x59, 0x80, 0x42, - 0xef, 0x80, 0xfe, 0x80, 0x49, 0x42, 0x80, 0xb7, - 0x80, 0x42, 0x62, 0x80, 0x41, 0x8d, 0x80, 0xc3, - 0x80, 0x53, 0x88, 0x80, 0xaa, 0x84, 0xe6, 0x81, - 0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80, 0x45, 0xf5, - 0x80, 0x43, 0xc1, 0x80, 0x95, 0x80, 0x40, 0x88, - 0x80, 0xeb, 0x80, 0x94, 0x81, 0x60, 0x54, 0x7a, - 0x80, 0x53, 0xeb, 0x80, 0x42, 0x67, 0x82, 0x44, - 0xce, 0x80, 0x60, 0x50, 0xa8, 0x81, 0x44, 0x9b, - 0x08, 0x80, 0x60, 0x71, 0x57, 0x81, 0x48, 0x05, - 0x82, -}; - -static const uint8_t unicode_prop_Hex_Digit_table[12] = { - 0xaf, 0x89, 0x35, 0x99, 0x85, 0x60, 0xfe, 0xa8, - 0x89, 0x35, 0x99, 0x85, -}; - -static const uint8_t unicode_prop_IDS_Binary_Operator_table[5] = { - 0x60, 0x2f, 0xef, 0x09, 0x87, -}; - -static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = { - 0x60, 0x2f, 0xf1, 0x81, -}; - -static const uint8_t unicode_prop_Ideographic_table[66] = { - 0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82, - 0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xfc, - 0x60, 0x59, 0x02, 0x41, 0x6d, 0x81, 0xe9, 0x60, - 0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44, - 0xd5, 0xa9, 0x88, 0x60, 0x24, 0x66, 0x41, 0x8b, - 0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdd, 0xa1, 0x50, - 0x34, 0x8a, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, - 0x5d, 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1, - 0x53, 0x4a, -}; - -static const uint8_t unicode_prop_Join_Control_table[4] = { - 0x60, 0x20, 0x0b, 0x81, -}; - -static const uint8_t unicode_prop_Logical_Order_Exception_table[15] = { - 0x4e, 0x3f, 0x84, 0xfa, 0x84, 0x4a, 0xef, 0x11, - 0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81, -}; - -static const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = { - 0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, - 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, -}; - -static const uint8_t unicode_prop_Pattern_Syntax_table[58] = { - 0xa0, 0x8e, 0x89, 0x86, 0x99, 0x18, 0x80, 0x99, - 0x83, 0xa1, 0x30, 0x00, 0x08, 0x00, 0x0b, 0x03, - 0x02, 0x80, 0x96, 0x80, 0x9e, 0x80, 0x5f, 0x17, - 0x97, 0x87, 0x8e, 0x81, 0x92, 0x80, 0x89, 0x41, - 0x30, 0x42, 0xcf, 0x40, 0x9f, 0x42, 0x75, 0x9d, - 0x44, 0x6b, 0x41, 0xff, 0xff, 0x41, 0x80, 0x13, - 0x98, 0x8e, 0x80, 0x60, 0xcd, 0x0c, 0x81, 0x41, - 0x04, 0x81, -}; - -static const uint8_t unicode_prop_Pattern_White_Space_table[11] = { - 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x5f, 0x87, - 0x81, 0x97, 0x81, -}; - -static const uint8_t unicode_prop_Quotation_Mark_table[31] = { - 0xa1, 0x03, 0x80, 0x40, 0x82, 0x80, 0x8e, 0x80, - 0x5f, 0x5b, 0x87, 0x98, 0x81, 0x4e, 0x06, 0x80, - 0x41, 0xc8, 0x83, 0x8c, 0x82, 0x60, 0xce, 0x20, - 0x83, 0x40, 0xbc, 0x03, 0x80, 0xd9, 0x81, -}; - -static const uint8_t unicode_prop_Radical_table[9] = { - 0x60, 0x2e, 0x7f, 0x99, 0x80, 0xd8, 0x8b, 0x40, - 0xd5, -}; - -static const uint8_t unicode_prop_Regional_Indicator_table[4] = { - 0x61, 0xf1, 0xe5, 0x99, -}; - -static const uint8_t unicode_prop_Sentence_Terminal_table[188] = { - 0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48, - 0x80, 0x40, 0x93, 0x81, 0x40, 0xb3, 0x80, 0xaa, - 0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81, - 0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15, - 0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81, - 0x40, 0xcb, 0x04, 0x80, 0x41, 0x39, 0x81, 0x41, - 0x61, 0x83, 0x40, 0xad, 0x09, 0x81, 0x40, 0xda, - 0x81, 0xc0, 0x81, 0x43, 0xbb, 0x81, 0x88, 0x82, - 0x4d, 0xe3, 0x80, 0x8c, 0x80, 0x41, 0xc4, 0x80, - 0x60, 0x74, 0xfb, 0x80, 0x41, 0x0d, 0x81, 0x40, - 0xe2, 0x02, 0x80, 0x41, 0x7d, 0x81, 0xd5, 0x81, - 0xde, 0x80, 0x40, 0x97, 0x81, 0x40, 0x92, 0x82, - 0x40, 0x8f, 0x81, 0x40, 0xf8, 0x80, 0x60, 0x52, - 0x65, 0x02, 0x81, 0x40, 0xa8, 0x80, 0x8b, 0x80, - 0x8f, 0x80, 0xc0, 0x80, 0x4a, 0xf3, 0x81, 0x44, - 0xfc, 0x84, 0x40, 0xec, 0x81, 0xf4, 0x83, 0xfe, - 0x82, 0x40, 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, - 0x08, 0x81, 0xeb, 0x80, 0x41, 0xa0, 0x81, 0x41, - 0x74, 0x0c, 0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82, - 0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6, - 0x81, 0x41, 0xa3, 0x81, 0x42, 0xb3, 0x81, 0x60, - 0x4b, 0x74, 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, - 0x8a, 0x80, 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05, - 0x80, 0x5d, 0xe7, 0x80, -}; - -static const uint8_t unicode_prop_Soft_Dotted_table[71] = { - 0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80, - 0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f, - 0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2, - 0x80, 0x8c, 0x02, 0x80, 0x40, 0x83, 0x80, 0x40, - 0x9c, 0x80, 0x41, 0xa4, 0x80, 0x40, 0xd5, 0x81, - 0x4b, 0x31, 0x80, 0x61, 0xa7, 0xa4, 0x81, 0xb1, - 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, - 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, - 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, -}; - -static const uint8_t unicode_prop_Terminal_Punctuation_table[241] = { - 0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80, - 0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8, - 0x80, 0xc7, 0x80, 0x8d, 0x01, 0x81, 0x40, 0xb3, - 0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5, - 0x8e, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44, 0xf3, - 0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36, 0x81, - 0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb, 0x82, - 0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6, 0x19, - 0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83, 0x40, - 0xad, 0x08, 0x82, 0x40, 0xda, 0x84, 0xbd, 0x81, - 0x43, 0xbb, 0x81, 0x88, 0x82, 0x4d, 0xe3, 0x80, - 0x8c, 0x03, 0x80, 0x89, 0x00, 0x81, 0x41, 0xb0, - 0x81, 0x60, 0x74, 0xfa, 0x81, 0x41, 0x0c, 0x82, - 0x40, 0xe2, 0x84, 0x41, 0x7d, 0x81, 0xd5, 0x81, - 0xde, 0x80, 0x40, 0x96, 0x82, 0x40, 0x92, 0x82, - 0xfe, 0x80, 0x8f, 0x81, 0x40, 0xf8, 0x80, 0x60, - 0x52, 0x63, 0x10, 0x83, 0x40, 0xa8, 0x80, 0x89, - 0x00, 0x80, 0x8a, 0x0a, 0x80, 0xc0, 0x01, 0x80, - 0x44, 0x39, 0x80, 0xaf, 0x80, 0x44, 0x85, 0x80, - 0x40, 0xc6, 0x80, 0x41, 0x35, 0x81, 0x40, 0x97, - 0x85, 0xc3, 0x85, 0xd8, 0x83, 0x43, 0xb7, 0x84, - 0x40, 0xec, 0x86, 0xef, 0x83, 0xfe, 0x82, 0x40, - 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x84, 0xeb, - 0x80, 0x41, 0xa0, 0x82, 0x8b, 0x81, 0x41, 0x65, - 0x1a, 0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82, 0x42, - 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6, 0x0b, - 0x81, 0x41, 0x9d, 0x82, 0xac, 0x80, 0x42, 0x84, - 0x81, 0x45, 0x76, 0x84, 0x60, 0x45, 0xf8, 0x81, - 0x40, 0x84, 0x80, 0xc0, 0x82, 0x89, 0x80, 0x43, - 0x51, 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, - 0x83, -}; - -static const uint8_t unicode_prop_Unified_Ideograph_table[42] = { - 0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51, - 0xfc, 0x60, 0x5a, 0x10, 0x08, 0x00, 0x81, 0x89, - 0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60, - 0xa6, 0xdd, 0xa1, 0x50, 0x34, 0x8a, 0x40, 0xdd, - 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e, - 0x53, 0x4a, -}; - -static const uint8_t unicode_prop_Variation_Selector_table[12] = { - 0x58, 0x0a, 0x82, 0x60, 0xe5, 0xf1, 0x8f, 0x6d, - 0x02, 0xef, 0x40, 0xef, -}; - -static const uint8_t unicode_prop_White_Space_table[22] = { - 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80, - 0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c, - 0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80, -}; - -static const uint8_t unicode_prop_Bidi_Mirrored_table[171] = { - 0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80, - 0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e, - 0x7d, 0x83, 0x47, 0x5c, 0x81, 0x49, 0x9b, 0x81, - 0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0, - 0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18, - 0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23, - 0x88, 0x08, 0x00, 0x39, 0x9e, 0x0b, 0x20, 0x88, - 0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81, - 0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d, - 0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d, - 0x41, 0x92, 0x95, 0x0d, 0x80, 0x8d, 0x38, 0x35, - 0x10, 0x1c, 0x01, 0x0c, 0x18, 0x02, 0x09, 0x89, - 0x29, 0x81, 0x8b, 0x92, 0x03, 0x08, 0x00, 0x08, - 0x03, 0x21, 0x2a, 0x97, 0x81, 0x8a, 0x0b, 0x18, - 0x09, 0x0b, 0xaa, 0x0f, 0x80, 0xa7, 0x20, 0x00, - 0x14, 0x22, 0x18, 0x14, 0x00, 0x40, 0xff, 0x80, - 0x42, 0x02, 0x1a, 0x08, 0x81, 0x8d, 0x09, 0x89, - 0x41, 0xdd, 0x89, 0x0f, 0x60, 0xce, 0x3c, 0x2c, - 0x81, 0x40, 0xa1, 0x81, 0x91, 0x00, 0x80, 0x9b, - 0x00, 0x80, 0x9c, 0x00, 0x00, 0x08, 0x81, 0x60, - 0xd7, 0x76, 0x80, 0xb8, 0x80, 0xb8, 0x80, 0xb8, - 0x80, 0xb8, 0x80, -}; - -static const uint8_t unicode_prop_Emoji_table[238] = { - 0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f, - 0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95, - 0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81, - 0x8b, 0x80, 0x40, 0xa5, 0x80, 0x98, 0x8a, 0x1a, - 0x40, 0xc6, 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, - 0x88, 0x80, 0xb9, 0x18, 0x84, 0x88, 0x01, 0x01, - 0x09, 0x03, 0x01, 0x00, 0x09, 0x02, 0x02, 0x0f, - 0x14, 0x00, 0x04, 0x8b, 0x8a, 0x09, 0x00, 0x08, - 0x80, 0x91, 0x01, 0x81, 0x91, 0x28, 0x00, 0x0a, - 0x0c, 0x01, 0x0b, 0x81, 0x8a, 0x0c, 0x09, 0x04, - 0x08, 0x00, 0x81, 0x93, 0x0c, 0x28, 0x19, 0x03, - 0x01, 0x01, 0x28, 0x01, 0x00, 0x00, 0x05, 0x02, - 0x05, 0x80, 0x89, 0x81, 0x8e, 0x01, 0x03, 0x00, - 0x03, 0x10, 0x80, 0x8a, 0x81, 0xaf, 0x82, 0x88, - 0x80, 0x8d, 0x80, 0x8d, 0x80, 0x41, 0x73, 0x81, - 0x41, 0xce, 0x82, 0x92, 0x81, 0xb2, 0x03, 0x80, - 0x44, 0xd9, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00, - 0x80, 0x61, 0xbd, 0x69, 0x80, 0x40, 0xc9, 0x80, - 0x40, 0x9f, 0x81, 0x8b, 0x81, 0x8d, 0x01, 0x89, - 0xca, 0x99, 0x01, 0x96, 0x80, 0x93, 0x01, 0x88, - 0x94, 0x81, 0x40, 0xad, 0xa1, 0x81, 0xef, 0x09, - 0x02, 0x81, 0xd2, 0x0a, 0x80, 0x41, 0x06, 0x80, - 0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01, - 0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88, - 0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05, - 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x3d, - 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, 0x8b, - 0x41, 0x1f, 0xae, 0x80, 0x89, 0x80, 0xb1, 0x80, - 0xd1, 0x80, 0xb2, 0xef, 0x22, 0x14, 0x86, 0x88, - 0x98, 0x36, 0x88, 0x82, 0x8c, 0x86, -}; - -static const uint8_t unicode_prop_Emoji_Component_table[28] = { - 0xa2, 0x05, 0x04, 0x89, 0x5f, 0xd2, 0x80, 0x40, - 0xd4, 0x80, 0x60, 0xdd, 0x2a, 0x80, 0x60, 0xf3, - 0xd5, 0x99, 0x41, 0xfa, 0x84, 0x45, 0xaf, 0x83, - 0x6c, 0x06, 0x6b, 0xdf, -}; - -static const uint8_t unicode_prop_Emoji_Modifier_table[4] = { - 0x61, 0xf3, 0xfa, 0x84, -}; - -static const uint8_t unicode_prop_Emoji_Modifier_Base_table[66] = { - 0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f, - 0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01, - 0x82, 0xf4, 0x09, 0x8a, 0x94, 0x92, 0x10, 0x1a, - 0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8, 0x0b, - 0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12, 0x84, - 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80, - 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89, - 0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90, - 0x10, 0x8c, -}; - -static const uint8_t unicode_prop_Emoji_Presentation_table[144] = { - 0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01, - 0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b, - 0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90, - 0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03, - 0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00, - 0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d, - 0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61, - 0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd, - 0x01, 0x89, 0xca, 0x99, 0x00, 0x97, 0x80, 0x93, - 0x01, 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0, - 0x8b, 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa, - 0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80, - 0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91, - 0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf, - 0xc5, 0x28, 0x12, 0x0a, 0x92, 0x0e, 0x88, 0x40, - 0xe2, 0x8b, 0x41, 0x1f, 0xae, 0x80, 0x89, 0x80, - 0xb1, 0x80, 0xd1, 0x80, 0xb2, 0xef, 0x22, 0x14, - 0x86, 0x88, 0x98, 0x36, 0x88, 0x82, 0x8c, 0x86, -}; - -static const uint8_t unicode_prop_Extended_Pictographic_table[156] = { - 0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b, - 0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85, - 0x8e, 0x81, 0x41, 0x6e, 0x81, 0x8b, 0x80, 0xde, - 0x80, 0xc5, 0x80, 0x98, 0x8a, 0x1a, 0x40, 0xc6, - 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80, - 0xb9, 0x18, 0x28, 0x8b, 0x80, 0xf1, 0x89, 0xf5, - 0x81, 0x8a, 0x00, 0x00, 0x28, 0x10, 0x28, 0x89, - 0x81, 0x8e, 0x01, 0x03, 0x00, 0x03, 0x10, 0x80, - 0x8a, 0x84, 0xac, 0x82, 0x88, 0x80, 0x8d, 0x80, - 0x8d, 0x80, 0x41, 0x73, 0x81, 0x41, 0xce, 0x82, - 0x92, 0x81, 0xb2, 0x03, 0x80, 0x44, 0xd9, 0x80, - 0x8b, 0x80, 0x42, 0x58, 0x00, 0x80, 0x61, 0xbd, - 0x65, 0x40, 0xff, 0x8c, 0x82, 0x9e, 0x80, 0xbb, - 0x85, 0x8b, 0x81, 0x8d, 0x01, 0x89, 0x91, 0xb8, - 0x9a, 0x8e, 0x89, 0x80, 0x93, 0x01, 0x88, 0x03, - 0x88, 0x41, 0xb1, 0x84, 0x41, 0x3d, 0x87, 0x41, - 0x09, 0xaf, 0xff, 0xf3, 0x8b, 0xd4, 0xaa, 0x8b, - 0x83, 0xb7, 0x87, 0x89, 0x85, 0xa7, 0x87, 0x9d, - 0xd1, 0x8b, 0xae, 0x80, 0x89, 0x80, 0x41, 0xb8, - 0x40, 0xff, 0x43, 0xfd, -}; - -static const uint8_t unicode_prop_Default_Ignorable_Code_Point_table[51] = { - 0x40, 0xac, 0x80, 0x42, 0xa0, 0x80, 0x42, 0xcb, - 0x80, 0x4b, 0x41, 0x81, 0x46, 0x52, 0x81, 0xd4, - 0x83, 0x47, 0xfb, 0x84, 0x99, 0x84, 0xb0, 0x8f, - 0x50, 0xf3, 0x80, 0x60, 0xcc, 0x9a, 0x8f, 0x40, - 0xee, 0x80, 0x40, 0x9f, 0x80, 0xce, 0x88, 0x60, - 0xbc, 0xa6, 0x83, 0x54, 0xce, 0x87, 0x6c, 0x2e, - 0x84, 0x4f, 0xff, -}; - -typedef enum { - UNICODE_PROP_Hyphen, - UNICODE_PROP_Other_Math, - UNICODE_PROP_Other_Alphabetic, - UNICODE_PROP_Other_Lowercase, - UNICODE_PROP_Other_Uppercase, - UNICODE_PROP_Other_Grapheme_Extend, - UNICODE_PROP_Other_Default_Ignorable_Code_Point, - UNICODE_PROP_Other_ID_Start, - UNICODE_PROP_Other_ID_Continue, - UNICODE_PROP_Prepended_Concatenation_Mark, - UNICODE_PROP_ID_Continue1, - UNICODE_PROP_XID_Start1, - UNICODE_PROP_XID_Continue1, - UNICODE_PROP_Changes_When_Titlecased1, - UNICODE_PROP_Changes_When_Casefolded1, - UNICODE_PROP_Changes_When_NFKC_Casefolded1, - UNICODE_PROP_ASCII_Hex_Digit, - UNICODE_PROP_Bidi_Control, - UNICODE_PROP_Dash, - UNICODE_PROP_Deprecated, - UNICODE_PROP_Diacritic, - UNICODE_PROP_Extender, - UNICODE_PROP_Hex_Digit, - UNICODE_PROP_IDS_Binary_Operator, - UNICODE_PROP_IDS_Trinary_Operator, - UNICODE_PROP_Ideographic, - UNICODE_PROP_Join_Control, - UNICODE_PROP_Logical_Order_Exception, - UNICODE_PROP_Noncharacter_Code_Point, - UNICODE_PROP_Pattern_Syntax, - UNICODE_PROP_Pattern_White_Space, - UNICODE_PROP_Quotation_Mark, - UNICODE_PROP_Radical, - UNICODE_PROP_Regional_Indicator, - UNICODE_PROP_Sentence_Terminal, - UNICODE_PROP_Soft_Dotted, - UNICODE_PROP_Terminal_Punctuation, - UNICODE_PROP_Unified_Ideograph, - UNICODE_PROP_Variation_Selector, - UNICODE_PROP_White_Space, - UNICODE_PROP_Bidi_Mirrored, - UNICODE_PROP_Emoji, - UNICODE_PROP_Emoji_Component, - UNICODE_PROP_Emoji_Modifier, - UNICODE_PROP_Emoji_Modifier_Base, - UNICODE_PROP_Emoji_Presentation, - UNICODE_PROP_Extended_Pictographic, - UNICODE_PROP_Default_Ignorable_Code_Point, - UNICODE_PROP_ID_Start, - UNICODE_PROP_Case_Ignorable, - UNICODE_PROP_ASCII, - UNICODE_PROP_Alphabetic, - UNICODE_PROP_Any, - UNICODE_PROP_Assigned, - UNICODE_PROP_Cased, - UNICODE_PROP_Changes_When_Casefolded, - UNICODE_PROP_Changes_When_Casemapped, - UNICODE_PROP_Changes_When_Lowercased, - UNICODE_PROP_Changes_When_NFKC_Casefolded, - UNICODE_PROP_Changes_When_Titlecased, - UNICODE_PROP_Changes_When_Uppercased, - UNICODE_PROP_Grapheme_Base, - UNICODE_PROP_Grapheme_Extend, - UNICODE_PROP_ID_Continue, - UNICODE_PROP_Lowercase, - UNICODE_PROP_Math, - UNICODE_PROP_Uppercase, - UNICODE_PROP_XID_Continue, - UNICODE_PROP_XID_Start, - UNICODE_PROP_Cased1, - UNICODE_PROP_COUNT, -} UnicodePropertyEnum; - -static const char unicode_prop_name_table[] = - "ASCII_Hex_Digit,AHex" "\0" - "Bidi_Control,Bidi_C" "\0" - "Dash" "\0" - "Deprecated,Dep" "\0" - "Diacritic,Dia" "\0" - "Extender,Ext" "\0" - "Hex_Digit,Hex" "\0" - "IDS_Binary_Operator,IDSB" "\0" - "IDS_Trinary_Operator,IDST" "\0" - "Ideographic,Ideo" "\0" - "Join_Control,Join_C" "\0" - "Logical_Order_Exception,LOE" "\0" - "Noncharacter_Code_Point,NChar" "\0" - "Pattern_Syntax,Pat_Syn" "\0" - "Pattern_White_Space,Pat_WS" "\0" - "Quotation_Mark,QMark" "\0" - "Radical" "\0" - "Regional_Indicator,RI" "\0" - "Sentence_Terminal,STerm" "\0" - "Soft_Dotted,SD" "\0" - "Terminal_Punctuation,Term" "\0" - "Unified_Ideograph,UIdeo" "\0" - "Variation_Selector,VS" "\0" - "White_Space,space" "\0" - "Bidi_Mirrored,Bidi_M" "\0" - "Emoji" "\0" - "Emoji_Component,EComp" "\0" - "Emoji_Modifier,EMod" "\0" - "Emoji_Modifier_Base,EBase" "\0" - "Emoji_Presentation,EPres" "\0" - "Extended_Pictographic,ExtPict" "\0" - "Default_Ignorable_Code_Point,DI" "\0" - "ID_Start,IDS" "\0" - "Case_Ignorable,CI" "\0" - "ASCII" "\0" - "Alphabetic,Alpha" "\0" - "Any" "\0" - "Assigned" "\0" - "Cased" "\0" - "Changes_When_Casefolded,CWCF" "\0" - "Changes_When_Casemapped,CWCM" "\0" - "Changes_When_Lowercased,CWL" "\0" - "Changes_When_NFKC_Casefolded,CWKCF" "\0" - "Changes_When_Titlecased,CWT" "\0" - "Changes_When_Uppercased,CWU" "\0" - "Grapheme_Base,Gr_Base" "\0" - "Grapheme_Extend,Gr_Ext" "\0" - "ID_Continue,IDC" "\0" - "Lowercase,Lower" "\0" - "Math" "\0" - "Uppercase,Upper" "\0" - "XID_Continue,XIDC" "\0" - "XID_Start,XIDS" "\0" -; - -static const uint8_t * const unicode_prop_table[] = { - unicode_prop_Hyphen_table, - unicode_prop_Other_Math_table, - unicode_prop_Other_Alphabetic_table, - unicode_prop_Other_Lowercase_table, - unicode_prop_Other_Uppercase_table, - unicode_prop_Other_Grapheme_Extend_table, - unicode_prop_Other_Default_Ignorable_Code_Point_table, - unicode_prop_Other_ID_Start_table, - unicode_prop_Other_ID_Continue_table, - unicode_prop_Prepended_Concatenation_Mark_table, - unicode_prop_ID_Continue1_table, - unicode_prop_XID_Start1_table, - unicode_prop_XID_Continue1_table, - unicode_prop_Changes_When_Titlecased1_table, - unicode_prop_Changes_When_Casefolded1_table, - unicode_prop_Changes_When_NFKC_Casefolded1_table, - unicode_prop_ASCII_Hex_Digit_table, - unicode_prop_Bidi_Control_table, - unicode_prop_Dash_table, - unicode_prop_Deprecated_table, - unicode_prop_Diacritic_table, - unicode_prop_Extender_table, - unicode_prop_Hex_Digit_table, - unicode_prop_IDS_Binary_Operator_table, - unicode_prop_IDS_Trinary_Operator_table, - unicode_prop_Ideographic_table, - unicode_prop_Join_Control_table, - unicode_prop_Logical_Order_Exception_table, - unicode_prop_Noncharacter_Code_Point_table, - unicode_prop_Pattern_Syntax_table, - unicode_prop_Pattern_White_Space_table, - unicode_prop_Quotation_Mark_table, - unicode_prop_Radical_table, - unicode_prop_Regional_Indicator_table, - unicode_prop_Sentence_Terminal_table, - unicode_prop_Soft_Dotted_table, - unicode_prop_Terminal_Punctuation_table, - unicode_prop_Unified_Ideograph_table, - unicode_prop_Variation_Selector_table, - unicode_prop_White_Space_table, - unicode_prop_Bidi_Mirrored_table, - unicode_prop_Emoji_table, - unicode_prop_Emoji_Component_table, - unicode_prop_Emoji_Modifier_table, - unicode_prop_Emoji_Modifier_Base_table, - unicode_prop_Emoji_Presentation_table, - unicode_prop_Extended_Pictographic_table, - unicode_prop_Default_Ignorable_Code_Point_table, - unicode_prop_ID_Start_table, - unicode_prop_Case_Ignorable_table, -}; - -static const uint16_t unicode_prop_len_table[] = { - countof(unicode_prop_Hyphen_table), - countof(unicode_prop_Other_Math_table), - countof(unicode_prop_Other_Alphabetic_table), - countof(unicode_prop_Other_Lowercase_table), - countof(unicode_prop_Other_Uppercase_table), - countof(unicode_prop_Other_Grapheme_Extend_table), - countof(unicode_prop_Other_Default_Ignorable_Code_Point_table), - countof(unicode_prop_Other_ID_Start_table), - countof(unicode_prop_Other_ID_Continue_table), - countof(unicode_prop_Prepended_Concatenation_Mark_table), - countof(unicode_prop_ID_Continue1_table), - countof(unicode_prop_XID_Start1_table), - countof(unicode_prop_XID_Continue1_table), - countof(unicode_prop_Changes_When_Titlecased1_table), - countof(unicode_prop_Changes_When_Casefolded1_table), - countof(unicode_prop_Changes_When_NFKC_Casefolded1_table), - countof(unicode_prop_ASCII_Hex_Digit_table), - countof(unicode_prop_Bidi_Control_table), - countof(unicode_prop_Dash_table), - countof(unicode_prop_Deprecated_table), - countof(unicode_prop_Diacritic_table), - countof(unicode_prop_Extender_table), - countof(unicode_prop_Hex_Digit_table), - countof(unicode_prop_IDS_Binary_Operator_table), - countof(unicode_prop_IDS_Trinary_Operator_table), - countof(unicode_prop_Ideographic_table), - countof(unicode_prop_Join_Control_table), - countof(unicode_prop_Logical_Order_Exception_table), - countof(unicode_prop_Noncharacter_Code_Point_table), - countof(unicode_prop_Pattern_Syntax_table), - countof(unicode_prop_Pattern_White_Space_table), - countof(unicode_prop_Quotation_Mark_table), - countof(unicode_prop_Radical_table), - countof(unicode_prop_Regional_Indicator_table), - countof(unicode_prop_Sentence_Terminal_table), - countof(unicode_prop_Soft_Dotted_table), - countof(unicode_prop_Terminal_Punctuation_table), - countof(unicode_prop_Unified_Ideograph_table), - countof(unicode_prop_Variation_Selector_table), - countof(unicode_prop_White_Space_table), - countof(unicode_prop_Bidi_Mirrored_table), - countof(unicode_prop_Emoji_table), - countof(unicode_prop_Emoji_Component_table), - countof(unicode_prop_Emoji_Modifier_table), - countof(unicode_prop_Emoji_Modifier_Base_table), - countof(unicode_prop_Emoji_Presentation_table), - countof(unicode_prop_Extended_Pictographic_table), - countof(unicode_prop_Default_Ignorable_Code_Point_table), - countof(unicode_prop_ID_Start_table), - countof(unicode_prop_Case_Ignorable_table), -}; - -#endif /* CONFIG_ALL_UNICODE */ diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjscalc.js b/packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjscalc.js deleted file mode 100644 index 27efc186..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjscalc.js +++ /dev/null @@ -1,2591 +0,0 @@ -/* - * QuickJS Javascript Calculator - * - * Copyright (c) 2017-2020 Fabrice Bellard - * - * 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'; -'use math'; - -var Integer, - Float, - Fraction, - Complex, - Mod, - Polynomial, - PolyMod, - RationalFunction, - Series, - Matrix; - -(function (global) { - global.Integer = global.BigInt; - global.Float = global.BigFloat; - global.algebraicMode = true; - - /* add non enumerable properties */ - function add_props(obj, props) { - var i, val, prop, tab, desc; - tab = Reflect.ownKeys(props); - for (i = 0; i < tab.length; i++) { - prop = tab[i]; - desc = Object.getOwnPropertyDescriptor(props, prop); - desc.enumerable = false; - if ('value' in desc) { - if (typeof desc.value !== 'function') { - desc.writable = false; - desc.configurable = false; - } - } else { - /* getter/setter */ - desc.configurable = false; - } - Object.defineProperty(obj, prop, desc); - } - } - - /* same as proto[Symbol.operatorSet] = Operators.create(..op_list) - but allow shortcuts: left: [], right: [] or both - */ - function operators_set(proto, ...op_list) { - var new_op_list, i, a, j, b, k, obj, tab; - var fields = ['left', 'right']; - new_op_list = []; - for (i = 0; i < op_list.length; i++) { - a = op_list[i]; - if (a.left || a.right) { - tab = [a.left, a.right]; - delete a.left; - delete a.right; - for (k = 0; k < 2; k++) { - obj = tab[k]; - if (obj) { - if (!Array.isArray(obj)) { - obj = [obj]; - } - for (j = 0; j < obj.length; j++) { - b = {}; - Object.assign(b, a); - b[fields[k]] = obj[j]; - new_op_list.push(b); - } - } - } - } else { - new_op_list.push(a); - } - } - proto[Symbol.operatorSet] = Operators.create.call(null, ...new_op_list); - } - - /* Integer */ - - function generic_pow(a, b) { - var r, is_neg, i; - if (!Integer.isInteger(b)) { - return exp(log(a) * b); - } - if (Array.isArray(a) && !(a instanceof Polynomial || a instanceof Series)) { - r = idn(Matrix.check_square(a)); - } else { - r = 1; - } - if (b == 0) return r; - is_neg = false; - if (b < 0) { - is_neg = true; - b = -b; - } - r = a; - for (i = Integer.floorLog2(b) - 1; i >= 0; i--) { - r *= r; - if ((b >> i) & 1) r *= a; - } - if (is_neg) { - if (typeof r.inverse != 'function') - throw 'negative powers are not supported for this type'; - r = r.inverse(); - } - return r; - } - - var small_primes = [ - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, - 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, - 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, - 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, - 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, - 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, - ]; - - function miller_rabin_test(n, t) { - var d, r, s, i, j, a; - d = n - 1; - s = 0; - while ((d & 1) == 0) { - d >>= 1; - s++; - } - if (small_primes.length < t) t = small_primes.length; - loop: for (j = 0; j < t; j++) { - a = small_primes[j]; - r = Integer.pmod(a, d, n); - if (r == 1 || r == n - 1) continue; - for (i = 1; i < s; i++) { - r = (r * r) % n; - if (r == 1) return false; - if (r == n - 1) continue loop; - } - return false; /* n is composite */ - } - return true; /* n is probably prime with probability (1-0.5^t) */ - } - - function fact_rec(a, b) { - /* assumes a <= b */ - var i, r; - if (b - a <= 5) { - r = a; - for (i = a + 1; i <= b; i++) r *= i; - return r; - } else { - /* to avoid a quadratic running time it is better to - multiply numbers of similar size */ - i = (a + b) >> 1; - return fact_rec(a, i) * fact_rec(i + 1, b); - } - } - - /* math mode specific quirk to overload the integer division and power */ - Operators.updateBigIntOperators({ - '/'(a, b) { - if (algebraicMode) { - return Fraction.toFraction(a, b); - } else { - return Float(a) / Float(b); - } - }, - '**'(a, b) { - if (algebraicMode) { - return generic_pow(a, b); - } else { - return Float(a) ** Float(b); - } - }, - }); - - add_props(Integer, { - isInteger(a) { - /* integers are represented either as bigint or as number */ - return ( - typeof a === 'bigint' || - (typeof a === 'number' && Number.isSafeInteger(a)) - ); - }, - gcd(a, b) { - var r; - while (b != 0) { - r = a % b; - a = b; - b = r; - } - return a; - }, - fact(n) { - return n <= 0 ? 1 : fact_rec(1, n); - }, - /* binomial coefficient */ - comb(n, k) { - if (k < 0 || k > n) return 0; - if (k > n - k) k = n - k; - if (k == 0) return 1; - return Integer.tdiv(fact_rec(n - k + 1, n), fact_rec(1, k)); - }, - /* inverse of x modulo y */ - invmod(x, y) { - var q, u, v, a, c, t; - u = x; - v = y; - c = 1; - a = 0; - while (u != 0) { - t = Integer.fdivrem(v, u); - q = t[0]; - v = u; - u = t[1]; - t = c; - c = a - q * c; - a = t; - } - /* v = gcd(x, y) */ - if (v != 1) throw RangeError('not invertible'); - return a % y; - }, - /* return a ^ b modulo m */ - pmod(a, b, m) { - var r; - if (b == 0) return 1; - if (b < 0) { - a = Integer.invmod(a, m); - b = -b; - } - r = 1; - for (;;) { - if (b & 1) { - r = (r * a) % m; - } - b >>= 1; - if (b == 0) break; - a = (a * a) % m; - } - return r; - }, - - /* return true if n is prime (or probably prime with - probability 1-0.5^t) */ - isPrime(n, t) { - var i, d, n1; - if (!Integer.isInteger(n)) throw TypeError('invalid type'); - if (n <= 1) return false; - n1 = small_primes.length; - /* XXX: need Integer.sqrt() */ - for (i = 0; i < n1; i++) { - d = small_primes[i]; - if (d == n) return true; - if (d > n) return false; - if (n % d == 0) return false; - } - if (n < d * d) return true; - if (typeof t == 'undefined') t = 64; - return miller_rabin_test(n, t); - }, - nextPrime(n) { - if (!Integer.isInteger(n)) throw TypeError('invalid type'); - if (n < 1) n = 1; - for (;;) { - n++; - if (Integer.isPrime(n)) return n; - } - }, - factor(n) { - var r, d; - if (!Integer.isInteger(n)) throw TypeError('invalid type'); - r = []; - if (abs(n) <= 1) { - r.push(n); - return r; - } - if (n < 0) { - r.push(-1); - n = -n; - } - - while (n % 2 == 0) { - n >>= 1; - r.push(2); - } - - d = 3; - while (n != 1) { - if (Integer.isPrime(n)) { - r.push(n); - break; - } - /* we are sure there is at least one divisor, so one test */ - for (;;) { - if (n % d == 0) break; - d += 2; - } - for (;;) { - r.push(d); - n = Integer.tdiv(n, d); - if (n % d != 0) break; - } - } - return r; - }, - }); - - add_props(Integer.prototype, { - inverse() { - return 1 / this; - }, - norm2() { - return this * this; - }, - abs() { - var v = this; - if (v < 0) v = -v; - return v; - }, - conj() { - return this; - }, - arg() { - if (this >= 0) return 0; - else return Float.PI; - }, - exp() { - if (this == 0) return 1; - else return Float.exp(this); - }, - log() { - if (this == 1) return 0; - else return Float(this).log(); - }, - }); - - /* Fraction */ - - Fraction = function Fraction(a, b) { - var d, r, obj; - - if (new.target) throw TypeError('not a constructor'); - if (a instanceof Fraction) return a; - if (!Integer.isInteger(a)) throw TypeError('integer expected'); - if (typeof b === 'undefined') { - b = 1; - } else { - if (!Integer.isInteger(b)) throw TypeError('integer expected'); - if (b == 0) throw RangeError('division by zero'); - d = Integer.gcd(a, b); - if (d != 1) { - a = Integer.tdiv(a, d); - b = Integer.tdiv(b, d); - } - - /* the fractions are normalized with den > 0 */ - if (b < 0) { - a = -a; - b = -b; - } - } - obj = Object.create(Fraction.prototype); - obj.num = a; - obj.den = b; - return obj; - }; - - function fraction_add(a, b) { - a = Fraction(a); - b = Fraction(b); - return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den); - } - function fraction_sub(a, b) { - a = Fraction(a); - b = Fraction(b); - return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den); - } - function fraction_mul(a, b) { - a = Fraction(a); - b = Fraction(b); - return Fraction.toFraction(a.num * b.num, a.den * b.den); - } - function fraction_div(a, b) { - a = Fraction(a); - b = Fraction(b); - return Fraction.toFraction(a.num * b.den, a.den * b.num); - } - function fraction_mod(a, b) { - var a1 = Fraction(a); - var b1 = Fraction(b); - return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b; - } - function fraction_eq(a, b) { - a = Fraction(a); - b = Fraction(b); - /* we assume the fractions are normalized */ - return a.num == b.num && a.den == b.den; - } - function fraction_lt(a, b) { - a = Fraction(a); - b = Fraction(b); - return a.num * b.den < b.num * a.den; - } - - /* operators are needed for fractions */ - function float_add(a, b) { - return Float(a) + Float(b); - } - function float_sub(a, b) { - return Float(a) - Float(b); - } - function float_mul(a, b) { - return Float(a) * Float(b); - } - function float_div(a, b) { - return Float(a) / Float(b); - } - function float_mod(a, b) { - return Float(a) % Float(b); - } - function float_pow(a, b) { - return Float(a) ** Float(b); - } - function float_eq(a, b) { - /* XXX: may be better to use infinite precision for the comparison */ - return Float(a) === Float(b); - } - function float_lt(a, b) { - a = Float(a); - b = Float(b); - /* XXX: may be better to use infinite precision for the comparison */ - if (Float.isNaN(a) || Float.isNaN(b)) return undefined; - else return a < b; - } - - operators_set( - Fraction.prototype, - { - '+': fraction_add, - '-': fraction_sub, - '*': fraction_mul, - '/': fraction_div, - '%': fraction_mod, - '**': generic_pow, - '==': fraction_eq, - '<': fraction_lt, - 'pos'(a) { - return a; - }, - 'neg'(a) { - return Fraction(-a.num, a.den); - }, - }, - { - 'left': [Number, BigInt], - 'right': [Number, BigInt], - '+': fraction_add, - '-': fraction_sub, - '*': fraction_mul, - '/': fraction_div, - '%': fraction_mod, - '**': generic_pow, - '==': fraction_eq, - '<': fraction_lt, - }, - { - 'left': Float, - 'right': Float, - '+': float_add, - '-': float_sub, - '*': float_mul, - '/': float_div, - '%': float_mod, - '**': float_pow, - '==': float_eq, - '<': float_lt, - }, - ); - - add_props(Fraction, { - /* (internal use) simplify 'a' to an integer when possible */ - toFraction(a, b) { - var r = Fraction(a, b); - if (algebraicMode && r.den == 1) return r.num; - else return r; - }, - }); - - add_props(Fraction.prototype, { - [Symbol.toPrimitive](hint) { - if (hint === 'string') { - return this.toString(); - } else { - return Float(this.num) / this.den; - } - }, - inverse() { - return Fraction(this.den, this.num); - }, - toString() { - return this.num + '/' + this.den; - }, - norm2() { - return this * this; - }, - abs() { - if (this.num < 0) return -this; - else return this; - }, - conj() { - return this; - }, - arg() { - if (this.num >= 0) return 0; - else return Float.PI; - }, - exp() { - return Float.exp(Float(this)); - }, - log() { - return Float(this).log(); - }, - }); - - /* Number (Float64) */ - - add_props(Number.prototype, { - inverse() { - return 1 / this; - }, - norm2() { - return this * this; - }, - abs() { - return Math.abs(this); - }, - conj() { - return this; - }, - arg() { - if (this >= 0) return 0; - else return Float.PI; - }, - exp() { - return Float.exp(this); - }, - log() { - if (this < 0) { - return Complex(this).log(); - } else { - return Float.log(this); - } - }, - }); - - /* Float */ - - var const_tab = []; - - /* we cache the constants for small precisions */ - function get_const(n) { - var t, c, p; - t = const_tab[n]; - p = BigFloatEnv.prec; - if (t && t.prec == p) { - return t.val; - } else { - switch (n) { - case 0: - c = Float.exp(1); - break; - case 1: - c = Float.log(10); - break; - // case 2: c = Float.log(2); break; - case 3: - c = 1 / Float.log(2); - break; - case 4: - c = 1 / Float.log(10); - break; - // case 5: c = Float.atan(1) * 4; break; - case 6: - c = Float.sqrt(0.5); - break; - case 7: - c = Float.sqrt(2); - break; - } - if (p <= 1024) { - const_tab[n] = { prec: p, val: c }; - } - return c; - } - } - - add_props(Float, { - isFloat(a) { - return typeof a === 'number' || typeof a === 'bigfloat'; - }, - bestappr(u, b) { - var num1, num0, den1, den0, u, num, den, n; - - if (typeof b === 'undefined') throw TypeError('second argument expected'); - num1 = 1; - num0 = 0; - den1 = 0; - den0 = 1; - for (;;) { - n = Integer(Float.floor(u)); - num = n * num1 + num0; - den = n * den1 + den0; - if (den > b) break; - u = 1.0 / (u - n); - num0 = num1; - num1 = num; - den0 = den1; - den1 = den; - } - return Fraction(num1, den1); - }, - /* similar constants as Math.x */ - get E() { - return get_const(0); - }, - get LN10() { - return get_const(1); - }, - // get LN2() { return get_const(2); }, - get LOG2E() { - return get_const(3); - }, - get LOG10E() { - return get_const(4); - }, - // get PI() { return get_const(5); }, - get SQRT1_2() { - return get_const(6); - }, - get SQRT2() { - return get_const(7); - }, - }); - - add_props(Float.prototype, { - inverse() { - return 1.0 / this; - }, - norm2() { - return this * this; - }, - abs() { - return Float.abs(this); - }, - conj() { - return this; - }, - arg() { - if (this >= 0) return 0; - else return Float.PI; - }, - exp() { - return Float.exp(this); - }, - log() { - if (this < 0) { - return Complex(this).log(); - } else { - return Float.log(this); - } - }, - }); - - /* Complex */ - - Complex = function Complex(re, im) { - var obj; - if (new.target) throw TypeError('not a constructor'); - if (re instanceof Complex) return re; - if (typeof im === 'undefined') { - im = 0; - } - obj = Object.create(Complex.prototype); - obj.re = re; - obj.im = im; - return obj; - }; - - function complex_add(a, b) { - a = Complex(a); - b = Complex(b); - return Complex.toComplex(a.re + b.re, a.im + b.im); - } - function complex_sub(a, b) { - a = Complex(a); - b = Complex(b); - return Complex.toComplex(a.re - b.re, a.im - b.im); - } - function complex_mul(a, b) { - a = Complex(a); - b = Complex(b); - return Complex.toComplex( - a.re * b.re - a.im * b.im, - a.re * b.im + a.im * b.re, - ); - } - function complex_div(a, b) { - a = Complex(a); - b = Complex(b); - return a * b.inverse(); - } - function complex_eq(a, b) { - a = Complex(a); - b = Complex(b); - return a.re == b.re && a.im == b.im; - } - - operators_set( - Complex.prototype, - { - '+': complex_add, - '-': complex_sub, - '*': complex_mul, - '/': complex_div, - '**': generic_pow, - '==': complex_eq, - 'pos'(a) { - return a; - }, - 'neg'(a) { - return Complex(-a.re, -a.im); - }, - }, - { - 'left': [Number, BigInt, Float, Fraction], - 'right': [Number, BigInt, Float, Fraction], - '+': complex_add, - '-': complex_sub, - '*': complex_mul, - '/': complex_div, - '**': generic_pow, - '==': complex_eq, - }, - ); - - add_props(Complex, { - /* simplify to real number when possible */ - toComplex(re, im) { - if (algebraicMode && im == 0) return re; - else return Complex(re, im); - }, - }); - - add_props(Complex.prototype, { - inverse() { - var c = this.norm2(); - return Complex(this.re / c, -this.im / c); - }, - toString() { - var v, - s = '', - a = this; - if (a.re != 0) s += a.re.toString(); - if (a.im == 1) { - if (s != '') s += '+'; - s += 'I'; - } else if (a.im == -1) { - s += '-I'; - } else { - v = a.im.toString(); - if (v[0] != '-' && s != '') s += '+'; - s += v + '*I'; - } - return s; - }, - norm2() { - return this.re * this.re + this.im * this.im; - }, - abs() { - return Float.sqrt(norm2(this)); - }, - conj() { - return Complex(this.re, -this.im); - }, - arg() { - return Float.atan2(this.im, this.re); - }, - exp() { - var arg = this.im, - r = this.re.exp(); - return Complex(r * cos(arg), r * sin(arg)); - }, - log() { - return Complex(abs(this).log(), atan2(this.im, this.re)); - }, - }); - - /* Mod */ - - Mod = function Mod(a, m) { - var obj, t; - if (new.target) throw TypeError('not a constructor'); - obj = Object.create(Mod.prototype); - if (Integer.isInteger(m)) { - if (m <= 0) throw RangeError('the modulo cannot be <= 0'); - if (Integer.isInteger(a)) { - a %= m; - } else if (a instanceof Fraction) { - return Mod(a.num, m) / a.den; - } else { - throw TypeError('invalid types'); - } - } else { - throw TypeError('invalid types'); - } - obj.res = a; - obj.mod = m; - return obj; - }; - - function mod_add(a, b) { - if (!(a instanceof Mod)) { - return Mod(a + b.res, b.mod); - } else if (!(b instanceof Mod)) { - return Mod(a.res + b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError('different modulo for binary operator'); - return Mod(a.res + b.res, a.mod); - } - } - function mod_sub(a, b) { - if (!(a instanceof Mod)) { - return Mod(a - b.res, b.mod); - } else if (!(b instanceof Mod)) { - return Mod(a.res - b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError('different modulo for binary operator'); - return Mod(a.res - b.res, a.mod); - } - } - function mod_mul(a, b) { - if (!(a instanceof Mod)) { - return Mod(a * b.res, b.mod); - } else if (!(b instanceof Mod)) { - return Mod(a.res * b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError('different modulo for binary operator'); - return Mod(a.res * b.res, a.mod); - } - } - function mod_div(a, b) { - if (!(b instanceof Mod)) b = Mod(b, a.mod); - return mod_mul(a, b.inverse()); - } - function mod_eq(a, b) { - return a.mod == b.mod && a.res == b.res; - } - - operators_set( - Mod.prototype, - { - '+': mod_add, - '-': mod_sub, - '*': mod_mul, - '/': mod_div, - '**': generic_pow, - '==': mod_eq, - 'pos'(a) { - return a; - }, - 'neg'(a) { - return Mod(-a.res, a.mod); - }, - }, - { - 'left': [Number, BigInt, Float, Fraction], - 'right': [Number, BigInt, Float, Fraction], - '+': mod_add, - '-': mod_sub, - '*': mod_mul, - '/': mod_div, - '**': generic_pow, - }, - ); - - add_props(Mod.prototype, { - inverse() { - var a = this, - m = a.mod; - if (Integer.isInteger(m)) { - return Mod(Integer.invmod(a.res, m), m); - } else { - throw TypeError('unsupported type'); - } - }, - toString() { - return 'Mod(' + this.res + ',' + this.mod + ')'; - }, - }); - - /* Polynomial */ - - function polynomial_is_scalar(a) { - if ( - typeof a === 'number' || - typeof a === 'bigint' || - typeof a === 'bigfloat' - ) - return true; - if (a instanceof Fraction || a instanceof Complex || a instanceof Mod) - return true; - return false; - } - - Polynomial = function Polynomial(a) { - if (new.target) throw TypeError('not a constructor'); - if (a instanceof Polynomial) { - return a; - } else if (Array.isArray(a)) { - if (a.length == 0) a = [0]; - Object.setPrototypeOf(a, Polynomial.prototype); - return a.trim(); - } else if (polynomial_is_scalar(a)) { - a = [a]; - Object.setPrototypeOf(a, Polynomial.prototype); - return a; - } else { - throw TypeError('invalid type'); - } - }; - - function number_need_paren(c) { - return !( - Integer.isInteger(c) || - Float.isFloat(c) || - c instanceof Fraction || - (c instanceof Complex && c.re == 0) - ); - } - - /* string for c*X^i */ - function monomial_toString(c, i) { - var str1; - if (i == 0) { - str1 = c.toString(); - } else { - if (c == 1) { - str1 = ''; - } else if (c == -1) { - str1 = '-'; - } else { - if (number_need_paren(c)) { - str1 = '(' + c + ')'; - } else { - str1 = String(c); - } - str1 += '*'; - } - str1 += 'X'; - if (i != 1) { - str1 += '^' + i; - } - } - return str1; - } - - /* find one complex root of 'p' starting from z at precision eps using - at most max_it iterations. Return null if could not find root. */ - function poly_root_laguerre1(p, z, max_it) { - var p1, p2, i, z0, z1, z2, d, t0, t1, d1, d2, e, el, zl; - - d = p.deg(); - if (d == 1) { - /* monomial case */ - return -p[0] / p[1]; - } - /* trivial zero */ - if (p[0] == 0) return 0.0; - - p1 = p.deriv(); - p2 = p1.deriv(); - el = 0.0; - zl = 0.0; - for (i = 0; i < max_it; i++) { - z0 = p.apply(z); - if (z0 == 0) return z; /* simple exit case */ - - /* Ward stopping criteria */ - e = abs(z - zl); - // print("e", i, e); - if (i >= 2 && e >= el) { - if (abs(zl) < 1e-4) { - if (e < 1e-7) return zl; - } else { - if (e < abs(zl) * 1e-3) return zl; - } - } - el = e; - zl = z; - - z1 = p1.apply(z); - z2 = p2.apply(z); - t0 = (d - 1) * z1; - t0 = t0 * t0; - t1 = d * (d - 1) * z0 * z2; - t0 = sqrt(t0 - t1); - d1 = z1 + t0; - d2 = z1 - t0; - if (norm2(d2) > norm2(d1)) d1 = d2; - if (d1 == 0) return null; - z = z - (d * z0) / d1; - } - return null; - } - - function poly_roots(p) { - var d, i, roots, j, z, eps; - var start_points = [0.1, -1.4, 1.7]; - - if (!(p instanceof Polynomial)) throw TypeError('polynomial expected'); - d = p.deg(); - if (d <= 0) return []; - eps = 2.0 ^ -BigFloatEnv.prec; - roots = []; - for (i = 0; i < d; i++) { - /* XXX: should select another start point if error */ - for (j = 0; j < 3; j++) { - z = poly_root_laguerre1(p, start_points[j], 100); - if (z !== null) break; - } - if (j == 3) throw RangeError('error in root finding algorithm'); - roots[i] = z; - p = Polynomial.divrem(p, X - z)[0]; - } - return roots; - } - - add_props(Polynomial.prototype, { - trim() { - var a = this, - i; - i = a.length; - while (i > 1 && a[i - 1] == 0) i--; - a.length = i; - return a; - }, - conj() { - var r, i, n, a; - a = this; - n = a.length; - r = []; - for (i = 0; i < n; i++) r[i] = a[i].conj(); - return Polynomial(r); - }, - inverse() { - return RationalFunction(Polynomial([1]), this); - }, - toString() { - var i, - str, - str1, - c, - a = this; - if (a.length == 1) { - return a[0].toString(); - } - str = ''; - for (i = a.length - 1; i >= 0; i--) { - c = a[i]; - if (c == 0 || (c instanceof Mod && c.res == 0)) continue; - str1 = monomial_toString(c, i); - if (str1[0] != '-') { - if (str != '') str += '+'; - } - str += str1; - } - return str; - }, - deg() { - if (this.length == 1 && this[0] == 0) return -Infinity; - else return this.length - 1; - }, - apply(b) { - var i, - n, - r, - a = this; - n = a.length - 1; - r = a[n]; - while (n > 0) { - n--; - r = r * b + a[n]; - } - return r; - }, - deriv() { - var a = this, - n, - r, - i; - n = a.length; - if (n == 1) { - return Polynomial(0); - } else { - r = []; - for (i = 1; i < n; i++) { - r[i - 1] = i * a[i]; - } - return Polynomial(r); - } - }, - integ() { - var a = this, - n, - r, - i; - n = a.length; - r = [0]; - for (i = 0; i < n; i++) { - r[i + 1] = a[i] / (i + 1); - } - return Polynomial(r); - }, - norm2() { - var a = this, - n, - r, - i; - n = a.length; - r = 0; - for (i = 0; i < n; i++) { - r += a[i].norm2(); - } - return r; - }, - }); - - function polynomial_add(a, b) { - var tmp, r, i, n1, n2; - a = Polynomial(a); - b = Polynomial(b); - if (a.length < b.length) { - tmp = a; - a = b; - b = tmp; - } - n1 = b.length; - n2 = a.length; - r = []; - for (i = 0; i < n1; i++) r[i] = a[i] + b[i]; - for (i = n1; i < n2; i++) r[i] = a[i]; - return Polynomial(r); - } - function polynomial_sub(a, b) { - return polynomial_add(a, -b); - } - function polynomial_mul(a, b) { - var i, j, n1, n2, n, r; - a = Polynomial(a); - b = Polynomial(b); - n1 = a.length; - n2 = b.length; - n = n1 + n2 - 1; - r = []; - for (i = 0; i < n; i++) r[i] = 0; - for (i = 0; i < n1; i++) { - for (j = 0; j < n2; j++) { - r[i + j] += a[i] * b[j]; - } - } - return Polynomial(r); - } - function polynomial_div_scalar(a, b) { - return a * (1 / b); - } - function polynomial_div(a, b) { - return RationalFunction(Polynomial(a), Polynomial(b)); - } - function polynomial_mod(a, b) { - return Polynomial.divrem(a, b)[1]; - } - function polynomial_eq(a, b) { - var n, i; - n = a.length; - if (n != b.length) return false; - for (i = 0; i < n; i++) { - if (a[i] != b[i]) return false; - } - return true; - } - - operators_set( - Polynomial.prototype, - { - '+': polynomial_add, - '-': polynomial_sub, - '*': polynomial_mul, - '/': polynomial_div, - '**': generic_pow, - '==': polynomial_eq, - 'pos'(a) { - return a; - }, - 'neg'(a) { - var r, i, n, a; - n = a.length; - r = []; - for (i = 0; i < n; i++) r[i] = -a[i]; - return Polynomial(r); - }, - }, - { - 'left': [Number, BigInt, Float, Fraction, Complex, Mod], - '+': polynomial_add, - '-': polynomial_sub, - '*': polynomial_mul, - '/': polynomial_div, - '**': generic_pow /* XXX: only for integer */, - }, - { - 'right': [Number, BigInt, Float, Fraction, Complex, Mod], - '+': polynomial_add, - '-': polynomial_sub, - '*': polynomial_mul, - '/': polynomial_div_scalar, - '**': generic_pow /* XXX: only for integer */, - }, - ); - - add_props(Polynomial, { - divrem(a, b) { - var n1, n2, i, j, q, r, n, c; - if (b.deg() < 0) throw RangeError('division by zero'); - n1 = a.length; - n2 = b.length; - if (n1 < n2) return [Polynomial([0]), a]; - r = Array.prototype.dup.call(a); - q = []; - n2--; - n = n1 - n2; - for (i = 0; i < n; i++) q[i] = 0; - for (i = n - 1; i >= 0; i--) { - c = r[i + n2]; - if (c != 0) { - c = c / b[n2]; - r[i + n2] = 0; - for (j = 0; j < n2; j++) { - r[i + j] -= b[j] * c; - } - q[i] = c; - } - } - return [Polynomial(q), Polynomial(r)]; - }, - gcd(a, b) { - var t; - while (b.deg() >= 0) { - t = Polynomial.divrem(a, b); - a = b; - b = t[1]; - } - /* convert to monic form */ - return a / a[a.length - 1]; - }, - invmod(x, y) { - var q, u, v, a, c, t; - u = x; - v = y; - c = Polynomial([1]); - a = Polynomial([0]); - while (u.deg() >= 0) { - t = Polynomial.divrem(v, u); - q = t[0]; - v = u; - u = t[1]; - t = c; - c = a - q * c; - a = t; - } - /* v = gcd(x, y) */ - if (v.deg() > 0) throw RangeError('not invertible'); - return Polynomial.divrem(a, y)[1]; - }, - roots(p) { - return poly_roots(p); - }, - }); - - /* Polynomial Modulo Q */ - - PolyMod = function PolyMod(a, m) { - var obj, t; - if (new.target) throw TypeError('not a constructor'); - obj = Object.create(PolyMod.prototype); - if (m instanceof Polynomial) { - if (m.deg() <= 0) - throw RangeError('the modulo cannot have a degree <= 0'); - if (a instanceof RationalFunction) { - return PolyMod(a.num, m) / a.den; - } else { - a = Polynomial(a); - t = Polynomial.divrem(a, m); - a = t[1]; - } - } else { - throw TypeError('invalid types'); - } - obj.res = a; - obj.mod = m; - return obj; - }; - - function polymod_add(a, b) { - if (!(a instanceof PolyMod)) { - return PolyMod(a + b.res, b.mod); - } else if (!(b instanceof PolyMod)) { - return PolyMod(a.res + b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError('different modulo for binary operator'); - return PolyMod(a.res + b.res, a.mod); - } - } - function polymod_sub(a, b) { - return polymod_add(a, -b); - } - function polymod_mul(a, b) { - if (!(a instanceof PolyMod)) { - return PolyMod(a * b.res, b.mod); - } else if (!(b instanceof PolyMod)) { - return PolyMod(a.res * b, a.mod); - } else { - if (a.mod != b.mod) - throw TypeError('different modulo for binary operator'); - return PolyMod(a.res * b.res, a.mod); - } - } - function polymod_div(a, b) { - if (!(b instanceof PolyMod)) b = PolyMod(b, a.mod); - return polymod_mul(a, b.inverse()); - } - function polymod_eq(a, b) { - return a.mod == b.mod && a.res == b.res; - } - - operators_set( - PolyMod.prototype, - { - '+': polymod_add, - '-': polymod_sub, - '*': polymod_mul, - '/': polymod_div, - '**': generic_pow, - '==': polymod_eq, - 'pos'(a) { - return a; - }, - 'neg'(a) { - return PolyMod(-a.res, a.mod); - }, - }, - { - 'left': [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - 'right': [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - '+': polymod_add, - '-': polymod_sub, - '*': polymod_mul, - '/': polymod_div, - '**': generic_pow /* XXX: only for integer */, - }, - ); - - add_props(PolyMod.prototype, { - inverse() { - var a = this, - m = a.mod; - if (m instanceof Polynomial) { - return PolyMod(Polynomial.invmod(a.res, m), m); - } else { - throw TypeError('unsupported type'); - } - }, - toString() { - return 'PolyMod(' + this.res + ',' + this.mod + ')'; - }, - }); - - /* Rational function */ - - RationalFunction = function RationalFunction(a, b) { - var t, r, d, obj; - if (new.target) throw TypeError('not a constructor'); - if (!(a instanceof Polynomial) || !(b instanceof Polynomial)) - throw TypeError('polynomial expected'); - t = Polynomial.divrem(a, b); - r = t[1]; - if (r.deg() < 0) return t[0]; /* no need for a fraction */ - d = Polynomial.gcd(b, r); - if (d.deg() > 0) { - a = Polynomial.divrem(a, d)[0]; - b = Polynomial.divrem(b, d)[0]; - } - obj = Object.create(RationalFunction.prototype); - obj.num = a; - obj.den = b; - return obj; - }; - - add_props(RationalFunction.prototype, { - inverse() { - return RationalFunction(this.den, this.num); - }, - conj() { - return RationalFunction(this.num.conj(), this.den.conj()); - }, - toString() { - var str; - if (this.num.deg() <= 0 && !number_need_paren(this.num[0])) - str = this.num.toString(); - else str = '(' + this.num.toString() + ')'; - str += '/(' + this.den.toString() + ')'; - return str; - }, - apply(b) { - return this.num.apply(b) / this.den.apply(b); - }, - deriv() { - var n = this.num, - d = this.den; - return RationalFunction(n.deriv() * d - n * d.deriv(), d * d); - }, - }); - - function ratfunc_add(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den); - } - function ratfunc_sub(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den); - } - function ratfunc_mul(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - return RationalFunction(a.num * b.num, a.den * b.den); - } - function ratfunc_div(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - return RationalFunction(a.num * b.den, a.den * b.num); - } - function ratfunc_eq(a, b) { - a = RationalFunction.toRationalFunction(a); - b = RationalFunction.toRationalFunction(b); - /* we assume the fractions are normalized */ - return a.num == b.num && a.den == b.den; - } - - operators_set( - RationalFunction.prototype, - { - '+': ratfunc_add, - '-': ratfunc_sub, - '*': ratfunc_mul, - '/': ratfunc_div, - '**': generic_pow, - '==': ratfunc_eq, - 'pos'(a) { - return a; - }, - 'neg'(a) { - return RationalFunction(-this.num, this.den); - }, - }, - { - 'left': [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - 'right': [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - '+': ratfunc_add, - '-': ratfunc_sub, - '*': ratfunc_mul, - '/': ratfunc_div, - '**': generic_pow /* should only be used with integers */, - }, - ); - - add_props(RationalFunction, { - /* This function always return a RationalFunction object even - if it could simplified to a polynomial, so it is not - equivalent to RationalFunction(a) */ - toRationalFunction(a) { - var obj; - if (a instanceof RationalFunction) { - return a; - } else { - obj = Object.create(RationalFunction.prototype); - obj.num = Polynomial(a); - obj.den = Polynomial(1); - return obj; - } - }, - }); - - /* Power series */ - - /* 'a' is an array */ - function get_emin(a) { - var i, n; - n = a.length; - for (i = 0; i < n; i++) { - if (a[i] != 0) return i; - } - return n; - } - - function series_is_scalar_or_polynomial(a) { - return polynomial_is_scalar(a) || a instanceof Polynomial; - } - - /* n is the maximum number of terms if 'a' is not a serie */ - Series = function Series(a, n) { - var emin, r, i; - - if (a instanceof Series) { - return a; - } else if (series_is_scalar_or_polynomial(a)) { - if (n <= 0) { - /* XXX: should still use the polynomial degree */ - return Series.zero(0, 0); - } else { - a = Polynomial(a); - emin = get_emin(a); - r = Series.zero(n, emin); - n = Math.min(a.length - emin, n); - for (i = 0; i < n; i++) r[i] = a[i + emin]; - return r; - } - } else if (a instanceof RationalFunction) { - return Series(a.num, n) / a.den; - } else { - throw TypeError('invalid type'); - } - }; - - function series_add(v1, v2) { - var tmp, d, emin, n, r, i, j, v2_emin, c1, c2; - if (!(v1 instanceof Series)) { - tmp = v1; - v1 = v2; - v2 = tmp; - } - d = v1.emin + v1.length; - if (series_is_scalar_or_polynomial(v2)) { - v2 = Polynomial(v2); - if (d <= 0) return v1; - v2_emin = 0; - } else if (v2 instanceof RationalFunction) { - /* compute the emin of the rational fonction */ - i = get_emin(v2.num) - get_emin(v2.den); - if (d <= i) return v1; - /* compute the serie with the required terms */ - v2 = Series(v2, d - i); - v2_emin = v2.emin; - } else { - v2_emin = v2.emin; - d = Math.min(d, v2_emin + v2.length); - } - emin = Math.min(v1.emin, v2_emin); - n = d - emin; - r = Series.zero(n, emin); - /* XXX: slow */ - for (i = emin; i < d; i++) { - j = i - v1.emin; - if (j >= 0 && j < v1.length) c1 = v1[j]; - else c1 = 0; - j = i - v2_emin; - if (j >= 0 && j < v2.length) c2 = v2[j]; - else c2 = 0; - r[i - emin] = c1 + c2; - } - return r.trim(); - } - function series_sub(a, b) { - return series_add(a, -b); - } - function series_mul(v1, v2) { - var n, i, j, r, n, emin, n1, n2, k; - if (!(v1 instanceof Series)) v1 = Series(v1, v2.length); - else if (!(v2 instanceof Series)) v2 = Series(v2, v1.length); - emin = v1.emin + v2.emin; - n = Math.min(v1.length, v2.length); - n1 = v1.length; - n2 = v2.length; - r = Series.zero(n, emin); - for (i = 0; i < n1; i++) { - k = Math.min(n2, n - i); - for (j = 0; j < k; j++) { - r[i + j] += v1[i] * v2[j]; - } - } - return r.trim(); - } - function series_div(v1, v2) { - if (!(v2 instanceof Series)) v2 = Series(v2, v1.length); - return series_mul(v1, v2.inverse()); - } - function series_pow(a, b) { - if (Integer.isInteger(b)) { - return generic_pow(a, b); - } else { - if (!(a instanceof Series)) a = Series(a, b.length); - return exp(log(a) * b); - } - } - function series_eq(a, b) { - var n, i; - if (a.emin != b.emin) return false; - n = a.length; - if (n != b.length) return false; - for (i = 0; i < n; i++) { - if (a[i] != b[i]) return false; - } - return true; - } - - operators_set( - Series.prototype, - { - '+': series_add, - '-': series_sub, - '*': series_mul, - '/': series_div, - '**': series_pow, - '==': series_eq, - 'pos'(a) { - return a; - }, - 'neg'(a) { - var obj, n, i; - n = a.length; - obj = Series.zero(a.length, a.emin); - for (i = 0; i < n; i++) { - obj[i] = -a[i]; - } - return obj; - }, - }, - { - 'left': [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - 'right': [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], - '+': series_add, - '-': series_sub, - '*': series_mul, - '/': series_div, - '**': series_pow, - }, - ); - - add_props(Series.prototype, { - conj() { - var obj, n, i; - n = this.length; - obj = Series.zero(this.length, this.emin); - for (i = 0; i < n; i++) { - obj[i] = this[i].conj(); - } - return obj; - }, - inverse() { - var r, - n, - i, - j, - sum, - v1 = this; - n = v1.length; - if (n == 0) throw RangeError('division by zero'); - r = Series.zero(n, -v1.emin); - r[0] = 1 / v1[0]; - for (i = 1; i < n; i++) { - sum = 0; - for (j = 1; j <= i; j++) { - sum += v1[j] * r[i - j]; - } - r[i] = -sum * r[0]; - } - return r; - }, - /* remove leading zero terms */ - trim() { - var i, - j, - n, - r, - v1 = this; - n = v1.length; - i = 0; - while (i < n && v1[i] == 0) i++; - if (i == 0) return v1; - for (j = i; j < n; j++) v1[j - i] = v1[j]; - v1.length = n - i; - v1.__proto__.emin += i; - return v1; - }, - toString() { - var i, - j, - str, - str1, - c, - a = this, - emin, - n; - str = ''; - emin = this.emin; - n = this.length; - for (j = 0; j < n; j++) { - i = j + emin; - c = a[j]; - if (c != 0) { - str1 = monomial_toString(c, i); - if (str1[0] != '-') { - if (str != '') str += '+'; - } - str += str1; - } - } - if (str != '') str += '+'; - str += 'O(' + monomial_toString(1, n + emin) + ')'; - return str; - }, - apply(b) { - var i, - n, - r, - a = this; - n = a.length; - if (n == 0) return 0; - r = a[--n]; - while (n > 0) { - n--; - r = r * b + a[n]; - } - if (a.emin != 0) r *= b ^ a.emin; - return r; - }, - deriv() { - var a = this, - n = a.length, - emin = a.emin, - r, - i, - j; - if (n == 0 && emin == 0) { - return Series.zero(0, 0); - } else { - r = Series.zero(n, emin - 1); - for (i = 0; i < n; i++) { - j = emin + i; - if (j == 0) r[i] = 0; - else r[i] = j * a[i]; - } - return r.trim(); - } - }, - integ() { - var a = this, - n = a.length, - emin = a.emin, - i, - j, - r; - r = Series.zero(n, emin + 1); - for (i = 0; i < n; i++) { - j = emin + i; - if (j == -1) { - if (a[i] != 0) throw RangeError('cannot represent integ(1/X)'); - } else { - r[i] = a[i] / (j + 1); - } - } - return r.trim(); - }, - exp() { - var c, - i, - r, - n, - a = this; - if (a.emin < 0) throw RangeError('negative exponent in exp'); - n = a.emin + a.length; - if (a.emin > 0 || a[0] == 0) { - c = 1; - } else { - c = global.exp(a[0]); - a -= a[0]; - } - r = Series.zero(n, 0); - for (i = 0; i < n; i++) { - r[i] = c / fact(i); - } - return r.apply(a); - }, - log() { - var a = this, - r; - if (a.emin != 0) - throw RangeError('log argument must have a non zero constant term'); - r = integ(deriv(a) / a); - /* add the constant term */ - r += global.log(a[0]); - return r; - }, - }); - - add_props(Series, { - /* new series of length n and first exponent emin */ - zero(n, emin) { - var r, i, obj; - - r = []; - for (i = 0; i < n; i++) r[i] = 0; - /* we return an array and store emin in its prototype */ - obj = Object.create(Series.prototype); - obj.emin = emin; - Object.setPrototypeOf(r, obj); - return r; - }, - O(a) { - function ErrorO() { - return TypeError('invalid O() argument'); - } - var n; - if (series_is_scalar_or_polynomial(a)) { - a = Polynomial(a); - n = a.deg(); - if (n < 0) throw ErrorO(); - } else if (a instanceof RationalFunction) { - if (a.num.deg() != 0) throw ErrorO(); - n = a.den.deg(); - if (n < 0) throw ErrorO(); - n = -n; - } else throw ErrorO(); - return Series.zero(0, n); - }, - }); - - /* Array (Matrix) */ - - Matrix = function Matrix(h, w) { - var i, j, r, rl; - if (typeof w === 'undefined') w = h; - r = []; - for (i = 0; i < h; i++) { - rl = []; - for (j = 0; j < w; j++) rl[j] = 0; - r[i] = rl; - } - return r; - }; - - add_props(Matrix, { - idn(n) { - var r, i; - r = Matrix(n, n); - for (i = 0; i < n; i++) r[i][i] = 1; - return r; - }, - diag(a) { - var r, i, n; - n = a.length; - r = Matrix(n, n); - for (i = 0; i < n; i++) r[i][i] = a[i]; - return r; - }, - hilbert(n) { - var i, j, r; - r = Matrix(n); - for (i = 0; i < n; i++) { - for (j = 0; j < n; j++) { - r[i][j] = 1 / (1 + i + j); - } - } - return r; - }, - trans(a) { - var h, w, r, i, j; - if (!Array.isArray(a)) throw TypeError('matrix expected'); - h = a.length; - if (!Array.isArray(a[0])) { - w = 1; - r = Matrix(w, h); - for (i = 0; i < h; i++) { - r[0][i] = a[i]; - } - } else { - w = a[0].length; - r = Matrix(w, h); - for (i = 0; i < h; i++) { - for (j = 0; j < w; j++) { - r[j][i] = a[i][j]; - } - } - } - return r; - }, - check_square(a) { - var a, n; - if (!Array.isArray(a)) throw TypeError('array expected'); - n = a.length; - if (!Array.isArray(a[0]) || n != a[0].length) - throw TypeError('square matrix expected'); - return n; - }, - trace(a) { - var n, r, i; - n = Matrix.check_square(a); - r = a[0][0]; - for (i = 1; i < n; i++) { - r += a[i][i]; - } - return r; - }, - charpoly(a) { - var n, p, c, i, j, coef; - n = Matrix.check_square(a); - p = []; - for (i = 0; i < n + 1; i++) p[i] = 0; - p[n] = 1; - c = Matrix.idn(n); - for (i = 0; i < n; i++) { - c = c * a; - coef = -trace(c) / (i + 1); - p[n - i - 1] = coef; - for (j = 0; j < n; j++) c[j][j] += coef; - } - return Polynomial(p); - }, - eigenvals(a) { - return Polynomial.roots(Matrix.charpoly(a)); - }, - det(a) { - var n, i, j, k, s, src, v, c; - - n = Matrix.check_square(a); - s = 1; - src = a.dup(); - for (i = 0; i < n; i++) { - for (j = i; j < n; j++) { - if (src[j][i] != 0) break; - } - if (j == n) return 0; - if (j != i) { - for (k = 0; k < n; k++) { - v = src[j][k]; - src[j][k] = src[i][k]; - src[i][k] = v; - } - s = -s; - } - c = src[i][i].inverse(); - for (j = i + 1; j < n; j++) { - v = c * src[j][i]; - for (k = 0; k < n; k++) { - src[j][k] -= src[i][k] * v; - } - } - } - c = s; - for (i = 0; i < n; i++) c *= src[i][i]; - return c; - }, - inverse(a) { - var n, dst, src, i, j, k, n2, r, c, v; - n = Matrix.check_square(a); - src = a.dup(); - dst = Matrix.idn(n); - for (i = 0; i < n; i++) { - for (j = i; j < n; j++) { - if (src[j][i] != 0) break; - } - if (j == n) throw RangeError('matrix is not invertible'); - if (j != i) { - /* swap lines in src and dst */ - v = src[j]; - src[j] = src[i]; - src[i] = v; - v = dst[j]; - dst[j] = dst[i]; - dst[i] = v; - } - - c = src[i][i].inverse(); - for (k = 0; k < n; k++) { - src[i][k] *= c; - dst[i][k] *= c; - } - - for (j = 0; j < n; j++) { - if (j != i) { - c = src[j][i]; - for (k = i; k < n; k++) { - src[j][k] -= src[i][k] * c; - } - for (k = 0; k < n; k++) { - dst[j][k] -= dst[i][k] * c; - } - } - } - } - return dst; - }, - rank(a) { - var src, i, j, k, w, h, l, c; - - if (!Array.isArray(a) || !Array.isArray(a[0])) - throw TypeError('matrix expected'); - h = a.length; - w = a[0].length; - src = a.dup(); - l = 0; - for (i = 0; i < w; i++) { - for (j = l; j < h; j++) { - if (src[j][i] != 0) break; - } - if (j == h) continue; - if (j != l) { - /* swap lines */ - for (k = 0; k < w; k++) { - v = src[j][k]; - src[j][k] = src[l][k]; - src[l][k] = v; - } - } - - c = src[l][i].inverse(); - for (k = 0; k < w; k++) { - src[l][k] *= c; - } - - for (j = l + 1; j < h; j++) { - c = src[j][i]; - for (k = i; k < w; k++) { - src[j][k] -= src[l][k] * c; - } - } - l++; - } - return l; - }, - ker(a) { - var src, i, j, k, w, h, l, m, r, im_cols, ker_dim, c; - - if (!Array.isArray(a) || !Array.isArray(a[0])) - throw TypeError('matrix expected'); - h = a.length; - w = a[0].length; - src = a.dup(); - im_cols = []; - l = 0; - for (i = 0; i < w; i++) { - im_cols[i] = false; - for (j = l; j < h; j++) { - if (src[j][i] != 0) break; - } - if (j == h) continue; - im_cols[i] = true; - if (j != l) { - /* swap lines */ - for (k = 0; k < w; k++) { - v = src[j][k]; - src[j][k] = src[l][k]; - src[l][k] = v; - } - } - - c = src[l][i].inverse(); - for (k = 0; k < w; k++) { - src[l][k] *= c; - } - - for (j = 0; j < h; j++) { - if (j != l) { - c = src[j][i]; - for (k = i; k < w; k++) { - src[j][k] -= src[l][k] * c; - } - } - } - l++; - // log_str("m=" + cval_toString(v1) + "\n"); - } - // log_str("im cols="+im_cols+"\n"); - - /* build the kernel vectors */ - ker_dim = w - l; - r = Matrix(w, ker_dim); - k = 0; - for (i = 0; i < w; i++) { - if (!im_cols[i]) { - /* select this column from the matrix */ - l = 0; - m = 0; - for (j = 0; j < w; j++) { - if (im_cols[j]) { - r[j][k] = -src[m][i]; - m++; - } else { - if (l == k) { - r[j][k] = 1; - } else { - r[j][k] = 0; - } - l++; - } - } - k++; - } - } - return r; - }, - dp(a, b) { - var i, n, r; - n = a.length; - if (n != b.length) throw TypeError('incompatible array length'); - /* XXX: could do complex product */ - r = 0; - for (i = 0; i < n; i++) { - r += a[i] * b[i]; - } - return r; - }, - /* cross product */ - cp(v1, v2) { - var r; - if (v1.length != 3 || v2.length != 3) - throw TypeError('vectors must have 3 elements'); - r = []; - r[0] = v1[1] * v2[2] - v1[2] * v2[1]; - r[1] = v1[2] * v2[0] - v1[0] * v2[2]; - r[2] = v1[0] * v2[1] - v1[1] * v2[0]; - return r; - }, - }); - - function array_add(a, b) { - var r, i, n; - n = a.length; - if (n != b.length) throw TypeError('incompatible array size'); - r = []; - for (i = 0; i < n; i++) r[i] = a[i] + b[i]; - return r; - } - function array_sub(a, b) { - var r, i, n; - n = a.length; - if (n != b.length) throw TypeError('incompatible array size'); - r = []; - for (i = 0; i < n; i++) r[i] = a[i] - b[i]; - return r; - } - function array_scalar_mul(a, b) { - var r, i, n; - n = a.length; - r = []; - for (i = 0; i < n; i++) r[i] = a[i] * b; - return r; - } - function array_mul(a, b) { - var h, w, l, i, j, k, r, rl, sum, a_mat, b_mat; - h = a.length; - a_mat = Array.isArray(a[0]); - if (a_mat) { - l = a[0].length; - } else { - l = 1; - } - if (l != b.length) throw RangeError('incompatible matrix size'); - b_mat = Array.isArray(b[0]); - if (b_mat) w = b[0].length; - else w = 1; - r = []; - if (a_mat && b_mat) { - for (i = 0; i < h; i++) { - rl = []; - for (j = 0; j < w; j++) { - sum = 0; - for (k = 0; k < l; k++) { - sum += a[i][k] * b[k][j]; - } - rl[j] = sum; - } - r[i] = rl; - } - } else if (a_mat && !b_mat) { - for (i = 0; i < h; i++) { - sum = 0; - for (k = 0; k < l; k++) { - sum += a[i][k] * b[k]; - } - r[i] = sum; - } - } else if (!a_mat && b_mat) { - for (i = 0; i < h; i++) { - rl = []; - for (j = 0; j < w; j++) { - rl[j] = a[i] * b[0][j]; - } - r[i] = rl; - } - } else { - for (i = 0; i < h; i++) { - r[i] = a[i] * b[0]; - } - } - return r; - } - function array_div(a, b) { - return array_mul(a, b.inverse()); - } - function array_element_wise_inverse(a) { - var r, i, n; - n = a.length; - r = []; - for (i = 0; i < n; i++) r[i] = a[i].inverse(); - return r; - } - function array_eq(a, b) { - var n, i; - n = a.length; - if (n != b.length) return false; - for (i = 0; i < n; i++) { - if (a[i] != b[i]) return false; - } - return true; - } - - operators_set( - Array.prototype, - { - '+': array_add, - '-': array_sub, - '*': array_mul, - '/': array_div, - '==': array_eq, - 'pos'(a) { - return a; - }, - 'neg'(a) { - var i, n, r; - n = a.length; - r = []; - for (i = 0; i < n; i++) r[i] = -a[i]; - return r; - }, - }, - { - 'right': [ - Number, - BigInt, - Float, - Fraction, - Complex, - Mod, - Polynomial, - PolyMod, - RationalFunction, - Series, - ], - '*': array_scalar_mul, - '/'(a, b) { - return a * b.inverse(); - }, - '**': generic_pow /* XXX: only for integer */, - }, - { - 'left': [ - Number, - BigInt, - Float, - Fraction, - Complex, - Mod, - Polynomial, - PolyMod, - RationalFunction, - Series, - ], - '*'(a, b) { - return array_scalar_mul(b, a); - }, - '/'(a, b) { - return a * array_element_wise_inverse(b); - }, - }, - ); - - add_props(Array.prototype, { - conj() { - var i, n, r; - n = this.length; - r = []; - for (i = 0; i < n; i++) r[i] = this[i].conj(); - return r; - }, - dup() { - var r, - i, - n, - el, - a = this; - r = []; - n = a.length; - for (i = 0; i < n; i++) { - el = a[i]; - if (Array.isArray(el)) el = el.dup(); - r[i] = el; - } - return r; - }, - inverse() { - return Matrix.inverse(this); - }, - norm2: Polynomial.prototype.norm2, - }); -})(this); - -/* global definitions */ -var I = Complex(0, 1); -var X = Polynomial([0, 1]); -var O = Series.O; - -Object.defineProperty(this, 'PI', { - get: function () { - return Float.PI; - }, -}); - -/* put frequently used functions in the global context */ -var gcd = Integer.gcd; -var fact = Integer.fact; -var comb = Integer.comb; -var pmod = Integer.pmod; -var invmod = Integer.invmod; -var factor = Integer.factor; -var isprime = Integer.isPrime; -var nextprime = Integer.nextPrime; - -function deriv(a) { - return a.deriv(); -} - -function integ(a) { - return a.integ(); -} - -function norm2(a) { - return a.norm2(); -} - -function abs(a) { - return a.abs(); -} - -function conj(a) { - return a.conj(); -} - -function arg(a) { - return a.arg(); -} - -function inverse(a) { - return a.inverse(); -} - -function trunc(a) { - if (Integer.isInteger(a)) { - return a; - } else if (a instanceof Fraction) { - return Integer.tdiv(a.num, a.den); - } else if (a instanceof Polynomial) { - return a; - } else if (a instanceof RationalFunction) { - return Polynomial.divrem(a.num, a.den)[0]; - } else { - return Float.ceil(a); - } -} - -function floor(a) { - if (Integer.isInteger(a)) { - return a; - } else if (a instanceof Fraction) { - return Integer.fdiv(a.num, a.den); - } else { - return Float.floor(a); - } -} - -function ceil(a) { - if (Integer.isInteger(a)) { - return a; - } else if (a instanceof Fraction) { - return Integer.cdiv(a.num, a.den); - } else { - return Float.ceil(a); - } -} - -function sqrt(a) { - var t, u, re, im; - if (a instanceof Series) { - return a ^ (1 / 2); - } else if (a instanceof Complex) { - t = abs(a); - u = a.re; - re = sqrt((t + u) / 2); - im = sqrt((t - u) / 2); - if (a.im < 0) im = -im; - return Complex.toComplex(re, im); - } else { - a = Float(a); - if (a < 0) { - return Complex(0, Float.sqrt(-a)); - } else { - return Float.sqrt(a); - } - } -} - -function exp(a) { - return a.exp(); -} - -function log(a) { - return a.log(); -} - -function log2(a) { - return log(a) * Float.LOG2E; -} - -function log10(a) { - return log(a) * Float.LOG10E; -} - -function todb(a) { - return log10(a) * 10; -} - -function fromdb(a) { - return 10 ^ (a / 10); -} - -function sin(a) { - var t; - if (a instanceof Complex || a instanceof Series) { - t = exp(a * I); - return (t - 1 / t) / (2 * I); - } else { - return Float.sin(Float(a)); - } -} - -function cos(a) { - var t; - if (a instanceof Complex || a instanceof Series) { - t = exp(a * I); - return (t + 1 / t) / 2; - } else { - return Float.cos(Float(a)); - } -} - -function tan(a) { - if (a instanceof Complex || a instanceof Series) { - return sin(a) / cos(a); - } else { - return Float.tan(Float(a)); - } -} - -function asin(a) { - return Float.asin(Float(a)); -} - -function acos(a) { - return Float.acos(Float(a)); -} - -function atan(a) { - return Float.atan(Float(a)); -} - -function atan2(a, b) { - return Float.atan2(Float(a), Float(b)); -} - -function sinc(a) { - if (a == 0) { - return 1; - } else { - a *= Float.PI; - return sin(a) / a; - } -} - -function todeg(a) { - return (a * 180) / Float.PI; -} - -function fromdeg(a) { - return (a * Float.PI) / 180; -} - -function sinh(a) { - var e = Float.exp(Float(a)); - return (e - 1 / e) * 0.5; -} - -function cosh(a) { - var e = Float.exp(Float(a)); - return (e + 1 / e) * 0.5; -} - -function tanh(a) { - var e = Float.exp(Float(a) * 2); - return (e - 1) / (e + 1); -} - -function asinh(a) { - var x = Float(a); - return log(sqrt(x * x + 1) + x); -} - -function acosh(a) { - var x = Float(a); - return log(sqrt(x * x - 1) + x); -} - -function atanh(a) { - var x = Float(a); - return 0.5 * log((1 + x) / (1 - x)); -} - -function sigmoid(x) { - x = Float(x); - return 1 / (1 + exp(-x)); -} - -function lerp(a, b, t) { - return a + (b - a) * t; -} - -var idn = Matrix.idn; -var diag = Matrix.diag; -var trans = Matrix.trans; -var trace = Matrix.trace; -var charpoly = Matrix.charpoly; -var eigenvals = Matrix.eigenvals; -var det = Matrix.det; -var rank = Matrix.rank; -var ker = Matrix.ker; -var cp = Matrix.cp; -var dp = Matrix.dp; - -var polroots = Polynomial.roots; -var bestappr = Float.bestappr; diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/repl.js b/packages/android-engine/android-js-engine/src/main/cpp/quickjs/repl.js deleted file mode 100644 index 977f4aa4..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/repl.js +++ /dev/null @@ -1,1579 +0,0 @@ -/* - * QuickJS Read Eval Print Loop - * - * Copyright (c) 2017-2020 Fabrice Bellard - * Copyright (c) 2017-2020 Charlie Gordon - * - * 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 strip'; - -import * as std from 'std'; -import * as os from 'os'; - -(function (g) { - /* add 'os' and 'std' bindings */ - g.os = os; - g.std = std; - - /* close global objects */ - var Object = g.Object; - var String = g.String; - var Array = g.Array; - var Date = g.Date; - var Math = g.Math; - var isFinite = g.isFinite; - var parseFloat = g.parseFloat; - - /* XXX: use preprocessor ? */ - var config_numcalc = typeof os.open === 'undefined'; - var has_jscalc = typeof Fraction === 'function'; - var has_bignum = typeof BigFloat === 'function'; - - var colors = { - none: '\x1b[0m', - black: '\x1b[30m', - red: '\x1b[31m', - green: '\x1b[32m', - yellow: '\x1b[33m', - blue: '\x1b[34m', - magenta: '\x1b[35m', - cyan: '\x1b[36m', - white: '\x1b[37m', - gray: '\x1b[30;1m', - grey: '\x1b[30;1m', - bright_red: '\x1b[31;1m', - bright_green: '\x1b[32;1m', - bright_yellow: '\x1b[33;1m', - bright_blue: '\x1b[34;1m', - bright_magenta: '\x1b[35;1m', - bright_cyan: '\x1b[36;1m', - bright_white: '\x1b[37;1m', - }; - - var styles; - if (config_numcalc) { - styles = { - default: 'black', - comment: 'white', - string: 'green', - regex: 'cyan', - number: 'green', - keyword: 'blue', - function: 'gray', - type: 'bright_magenta', - identifier: 'yellow', - error: 'bright_red', - result: 'black', - error_msg: 'bright_red', - }; - } else { - styles = { - default: 'bright_green', - comment: 'white', - string: 'bright_cyan', - regex: 'cyan', - number: 'green', - keyword: 'bright_white', - function: 'bright_yellow', - type: 'bright_magenta', - identifier: 'bright_green', - error: 'red', - result: 'bright_white', - error_msg: 'bright_red', - }; - } - - var history = []; - var clip_board = ''; - var prec; - var expBits; - var log2_10; - - var pstate = ''; - var prompt = ''; - var plen = 0; - var ps1; - if (config_numcalc) ps1 = '> '; - else ps1 = 'qjs > '; - var ps2 = ' ... '; - var utf8 = true; - var show_time = false; - var show_colors = true; - var eval_time = 0; - - var mexpr = ''; - var level = 0; - var cmd = ''; - var cursor_pos = 0; - var last_cmd = ''; - var last_cursor_pos = 0; - var history_index; - var this_fun, last_fun; - var quote_flag = false; - - var utf8_state = 0; - var utf8_val = 0; - - var term_fd; - var term_read_buf; - var term_width; - /* current X position of the cursor in the terminal */ - var term_cursor_x = 0; - - function termInit() { - var tab; - term_fd = std.in.fileno(); - - /* get the terminal size */ - term_width = 80; - if (os.isatty(term_fd)) { - if (os.ttyGetWinSize) { - tab = os.ttyGetWinSize(term_fd); - if (tab) term_width = tab[0]; - } - if (os.ttySetRaw) { - /* set the TTY to raw mode */ - os.ttySetRaw(term_fd); - } - } - - /* install a Ctrl-C signal handler */ - os.signal(os.SIGINT, sigint_handler); - - /* install a handler to read stdin */ - term_read_buf = new Uint8Array(64); - os.setReadHandler(term_fd, term_read_handler); - } - - function sigint_handler() { - /* send Ctrl-C to readline */ - handle_byte(3); - } - - function term_read_handler() { - var l, i; - l = os.read(term_fd, term_read_buf.buffer, 0, term_read_buf.length); - for (i = 0; i < l; i++) handle_byte(term_read_buf[i]); - } - - function handle_byte(c) { - if (!utf8) { - handle_char(c); - } else if (utf8_state !== 0 && c >= 0x80 && c < 0xc0) { - utf8_val = (utf8_val << 6) | (c & 0x3f); - utf8_state--; - if (utf8_state === 0) { - handle_char(utf8_val); - } - } else if (c >= 0xc0 && c < 0xf8) { - utf8_state = 1 + (c >= 0xe0) + (c >= 0xf0); - utf8_val = c & ((1 << (6 - utf8_state)) - 1); - } else { - utf8_state = 0; - handle_char(c); - } - } - - function is_alpha(c) { - return ( - typeof c === 'string' && - ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) - ); - } - - function is_digit(c) { - return typeof c === 'string' && c >= '0' && c <= '9'; - } - - function is_word(c) { - return ( - typeof c === 'string' && - (is_alpha(c) || is_digit(c) || c == '_' || c == '$') - ); - } - - function ucs_length(str) { - var len, - c, - i, - str_len = str.length; - len = 0; - /* we never count the trailing surrogate to have the - following property: ucs_length(str) = - ucs_length(str.substring(0, a)) + ucs_length(str.substring(a, - str.length)) for 0 <= a <= str.length */ - for (i = 0; i < str_len; i++) { - c = str.charCodeAt(i); - if (c < 0xdc00 || c >= 0xe000) len++; - } - return len; - } - - function is_trailing_surrogate(c) { - var d; - if (typeof c !== 'string') return false; - d = c.codePointAt(0); /* can be NaN if empty string */ - return d >= 0xdc00 && d < 0xe000; - } - - function is_balanced(a, b) { - switch (a + b) { - case '()': - case '[]': - case '{}': - return true; - } - return false; - } - - function print_color_text(str, start, style_names) { - var i, j; - for (j = start; j < str.length; ) { - var style = style_names[(i = j)]; - while (++j < str.length && style_names[j] == style) continue; - std.puts(colors[styles[style] || 'default']); - std.puts(str.substring(i, j)); - std.puts(colors['none']); - } - } - - function print_csi(n, code) { - std.puts('\x1b[' + (n != 1 ? n : '') + code); - } - - /* XXX: handle double-width characters */ - function move_cursor(delta) { - var i, l; - if (delta > 0) { - while (delta != 0) { - if (term_cursor_x == term_width - 1) { - std.puts('\n'); /* translated to CRLF */ - term_cursor_x = 0; - delta--; - } else { - l = Math.min(term_width - 1 - term_cursor_x, delta); - print_csi(l, 'C'); /* right */ - delta -= l; - term_cursor_x += l; - } - } - } else { - delta = -delta; - while (delta != 0) { - if (term_cursor_x == 0) { - print_csi(1, 'A'); /* up */ - print_csi(term_width - 1, 'C'); /* right */ - delta--; - term_cursor_x = term_width - 1; - } else { - l = Math.min(delta, term_cursor_x); - print_csi(l, 'D'); /* left */ - delta -= l; - term_cursor_x -= l; - } - } - } - } - - function update() { - var i, cmd_len; - /* cursor_pos is the position in 16 bit characters inside the - UTF-16 string 'cmd' */ - if (cmd != last_cmd) { - if ( - !show_colors && - last_cmd.substring(0, last_cursor_pos) == - cmd.substring(0, last_cursor_pos) - ) { - /* optimize common case */ - std.puts(cmd.substring(last_cursor_pos)); - } else { - /* goto the start of the line */ - move_cursor(-ucs_length(last_cmd.substring(0, last_cursor_pos))); - if (show_colors) { - var str = mexpr ? mexpr + '\n' + cmd : cmd; - var start = str.length - cmd.length; - var colorstate = colorize_js(str); - print_color_text(str, start, colorstate[2]); - } else { - std.puts(cmd); - } - } - term_cursor_x = (term_cursor_x + ucs_length(cmd)) % term_width; - if (term_cursor_x == 0) { - /* show the cursor on the next line */ - std.puts(' \x08'); - } - /* remove the trailing characters */ - std.puts('\x1b[J'); - last_cmd = cmd; - last_cursor_pos = cmd.length; - } - if (cursor_pos > last_cursor_pos) { - move_cursor(ucs_length(cmd.substring(last_cursor_pos, cursor_pos))); - } else if (cursor_pos < last_cursor_pos) { - move_cursor(-ucs_length(cmd.substring(cursor_pos, last_cursor_pos))); - } - last_cursor_pos = cursor_pos; - std.out.flush(); - } - - /* editing commands */ - function insert(str) { - if (str) { - cmd = cmd.substring(0, cursor_pos) + str + cmd.substring(cursor_pos); - cursor_pos += str.length; - } - } - - function quoted_insert() { - quote_flag = true; - } - - function abort() { - cmd = ''; - cursor_pos = 0; - return -2; - } - - function alert() {} - - function beginning_of_line() { - cursor_pos = 0; - } - - function end_of_line() { - cursor_pos = cmd.length; - } - - function forward_char() { - if (cursor_pos < cmd.length) { - cursor_pos++; - while (is_trailing_surrogate(cmd.charAt(cursor_pos))) cursor_pos++; - } - } - - function backward_char() { - if (cursor_pos > 0) { - cursor_pos--; - while (is_trailing_surrogate(cmd.charAt(cursor_pos))) cursor_pos--; - } - } - - function skip_word_forward(pos) { - while (pos < cmd.length && !is_word(cmd.charAt(pos))) pos++; - while (pos < cmd.length && is_word(cmd.charAt(pos))) pos++; - return pos; - } - - function skip_word_backward(pos) { - while (pos > 0 && !is_word(cmd.charAt(pos - 1))) pos--; - while (pos > 0 && is_word(cmd.charAt(pos - 1))) pos--; - return pos; - } - - function forward_word() { - cursor_pos = skip_word_forward(cursor_pos); - } - - function backward_word() { - cursor_pos = skip_word_backward(cursor_pos); - } - - function accept_line() { - std.puts('\n'); - history_add(cmd); - return -1; - } - - function history_add(str) { - if (str) { - history.push(str); - } - history_index = history.length; - } - - function previous_history() { - if (history_index > 0) { - if (history_index == history.length) { - history.push(cmd); - } - history_index--; - cmd = history[history_index]; - cursor_pos = cmd.length; - } - } - - function next_history() { - if (history_index < history.length - 1) { - history_index++; - cmd = history[history_index]; - cursor_pos = cmd.length; - } - } - - function history_search(dir) { - var pos = cursor_pos; - for (var i = 1; i <= history.length; i++) { - var index = (history.length + i * dir + history_index) % history.length; - if (history[index].substring(0, pos) == cmd.substring(0, pos)) { - history_index = index; - cmd = history[index]; - return; - } - } - } - - function history_search_backward() { - return history_search(-1); - } - - function history_search_forward() { - return history_search(1); - } - - function delete_char_dir(dir) { - var start, end; - - start = cursor_pos; - if (dir < 0) { - start--; - while (is_trailing_surrogate(cmd.charAt(start))) start--; - } - end = start + 1; - while (is_trailing_surrogate(cmd.charAt(end))) end++; - - if (start >= 0 && start < cmd.length) { - if (last_fun === kill_region) { - kill_region(start, end, dir); - } else { - cmd = cmd.substring(0, start) + cmd.substring(end); - cursor_pos = start; - } - } - } - - function delete_char() { - delete_char_dir(1); - } - - function control_d() { - if (cmd.length == 0) { - std.puts('\n'); - return -3; /* exit read eval print loop */ - } else { - delete_char_dir(1); - } - } - - function backward_delete_char() { - delete_char_dir(-1); - } - - function transpose_chars() { - var pos = cursor_pos; - if (cmd.length > 1 && pos > 0) { - if (pos == cmd.length) pos--; - cmd = - cmd.substring(0, pos - 1) + - cmd.substring(pos, pos + 1) + - cmd.substring(pos - 1, pos) + - cmd.substring(pos + 1); - cursor_pos = pos + 1; - } - } - - function transpose_words() { - var p1 = skip_word_backward(cursor_pos); - var p2 = skip_word_forward(p1); - var p4 = skip_word_forward(cursor_pos); - var p3 = skip_word_backward(p4); - - if (p1 < p2 && p2 <= cursor_pos && cursor_pos <= p3 && p3 < p4) { - cmd = - cmd.substring(0, p1) + - cmd.substring(p3, p4) + - cmd.substring(p2, p3) + - cmd.substring(p1, p2); - cursor_pos = p4; - } - } - - function upcase_word() { - var end = skip_word_forward(cursor_pos); - cmd = - cmd.substring(0, cursor_pos) + - cmd.substring(cursor_pos, end).toUpperCase() + - cmd.substring(end); - } - - function downcase_word() { - var end = skip_word_forward(cursor_pos); - cmd = - cmd.substring(0, cursor_pos) + - cmd.substring(cursor_pos, end).toLowerCase() + - cmd.substring(end); - } - - function kill_region(start, end, dir) { - var s = cmd.substring(start, end); - if (last_fun !== kill_region) clip_board = s; - else if (dir < 0) clip_board = s + clip_board; - else clip_board = clip_board + s; - - cmd = cmd.substring(0, start) + cmd.substring(end); - if (cursor_pos > end) cursor_pos -= end - start; - else if (cursor_pos > start) cursor_pos = start; - this_fun = kill_region; - } - - function kill_line() { - kill_region(cursor_pos, cmd.length, 1); - } - - function backward_kill_line() { - kill_region(0, cursor_pos, -1); - } - - function kill_word() { - kill_region(cursor_pos, skip_word_forward(cursor_pos), 1); - } - - function backward_kill_word() { - kill_region(skip_word_backward(cursor_pos), cursor_pos, -1); - } - - function yank() { - insert(clip_board); - } - - function control_c() { - if (last_fun === control_c) { - std.puts('\n'); - std.exit(0); - } else { - std.puts('\n(Press Ctrl-C again to quit)\n'); - readline_print_prompt(); - } - } - - function reset() { - cmd = ''; - cursor_pos = 0; - } - - function get_context_word(line, pos) { - var s = ''; - while (pos > 0 && is_word(line[pos - 1])) { - pos--; - s = line[pos] + s; - } - return s; - } - function get_context_object(line, pos) { - var obj, base, c; - if (pos <= 0 || ' ~!%^&*(-+={[|:;,<>?/'.indexOf(line[pos - 1]) >= 0) - return g; - if (pos >= 2 && line[pos - 1] === '.') { - pos--; - obj = {}; - switch ((c = line[pos - 1])) { - case "'": - case '"': - return 'a'; - case ']': - return []; - case '}': - return {}; - case '/': - return / /; - default: - if (is_word(c)) { - base = get_context_word(line, pos); - if ( - ['true', 'false', 'null', 'this'].includes(base) || - !isNaN(+base) - ) - return eval(base); - obj = get_context_object(line, pos - base.length); - if (obj === null || obj === void 0) return obj; - if (obj === g && obj[base] === void 0) return eval(base); - else return obj[base]; - } - return {}; - } - } - return void 0; - } - - function get_completions(line, pos) { - var s, obj, ctx_obj, r, i, j, paren; - - s = get_context_word(line, pos); - ctx_obj = get_context_object(line, pos - s.length); - r = []; - /* enumerate properties from object and its prototype chain, - add non-numeric regular properties with s as e prefix - */ - for (i = 0, obj = ctx_obj; i < 10 && obj !== null && obj !== void 0; i++) { - var props = Object.getOwnPropertyNames(obj); - /* add non-numeric regular properties */ - for (j = 0; j < props.length; j++) { - var prop = props[j]; - if (typeof prop == 'string' && '' + +prop != prop && prop.startsWith(s)) - r.push(prop); - } - obj = Object.getPrototypeOf(obj); - } - if (r.length > 1) { - /* sort list with internal names last and remove duplicates */ - function symcmp(a, b) { - if (a[0] != b[0]) { - if (a[0] == '_') return 1; - if (b[0] == '_') return -1; - } - if (a < b) return -1; - if (a > b) return +1; - return 0; - } - r.sort(symcmp); - for (i = j = 1; i < r.length; i++) { - if (r[i] != r[i - 1]) r[j++] = r[i]; - } - r.length = j; - } - /* 'tab' = list of completions, 'pos' = cursor position inside - the completions */ - return { tab: r, pos: s.length, ctx: ctx_obj }; - } - - function completion() { - var tab, res, s, i, j, len, t, max_width, col, n_cols, row, n_rows; - res = get_completions(cmd, cursor_pos); - tab = res.tab; - if (tab.length === 0) return; - s = tab[0]; - len = s.length; - /* add the chars which are identical in all the completions */ - for (i = 1; i < tab.length; i++) { - t = tab[i]; - for (j = 0; j < len; j++) { - if (t[j] !== s[j]) { - len = j; - break; - } - } - } - for (i = res.pos; i < len; i++) { - insert(s[i]); - } - if (last_fun === completion && tab.length == 1) { - /* append parentheses to function names */ - var m = res.ctx[tab[0]]; - if (typeof m == 'function') { - insert('('); - if (m.length == 0) insert(')'); - } else if (typeof m == 'object') { - insert('.'); - } - } - /* show the possible completions */ - if (last_fun === completion && tab.length >= 2) { - max_width = 0; - for (i = 0; i < tab.length; i++) - max_width = Math.max(max_width, tab[i].length); - max_width += 2; - n_cols = Math.max(1, Math.floor((term_width + 1) / max_width)); - n_rows = Math.ceil(tab.length / n_cols); - std.puts('\n'); - /* display the sorted list column-wise */ - for (row = 0; row < n_rows; row++) { - for (col = 0; col < n_cols; col++) { - i = col * n_rows + row; - if (i >= tab.length) break; - s = tab[i]; - if (col != n_cols - 1) s = s.padEnd(max_width); - std.puts(s); - } - std.puts('\n'); - } - /* show a new prompt */ - readline_print_prompt(); - } - } - - var commands = { - /* command table */ '\x01': beginning_of_line /* ^A - bol */, - '\x02': backward_char /* ^B - backward-char */, - '\x03': control_c /* ^C - abort */, - '\x04': control_d /* ^D - delete-char or exit */, - '\x05': end_of_line /* ^E - eol */, - '\x06': forward_char /* ^F - forward-char */, - '\x07': abort /* ^G - bell */, - '\x08': backward_delete_char /* ^H - backspace */, - '\x09': completion /* ^I - history-search-backward */, - '\x0a': accept_line /* ^J - newline */, - '\x0b': kill_line /* ^K - delete to end of line */, - '\x0d': accept_line /* ^M - enter */, - '\x0e': next_history /* ^N - down */, - '\x10': previous_history /* ^P - up */, - '\x11': quoted_insert /* ^Q - quoted-insert */, - '\x12': alert /* ^R - reverse-search */, - '\x13': alert /* ^S - search */, - '\x14': transpose_chars /* ^T - transpose */, - '\x18': reset /* ^X - cancel */, - '\x19': yank /* ^Y - yank */, - '\x1bOA': previous_history /* ^[OA - up */, - '\x1bOB': next_history /* ^[OB - down */, - '\x1bOC': forward_char /* ^[OC - right */, - '\x1bOD': backward_char /* ^[OD - left */, - '\x1bOF': forward_word /* ^[OF - ctrl-right */, - '\x1bOH': backward_word /* ^[OH - ctrl-left */, - '\x1b[1;5C': forward_word /* ^[[1;5C - ctrl-right */, - '\x1b[1;5D': backward_word /* ^[[1;5D - ctrl-left */, - '\x1b[1~': beginning_of_line /* ^[[1~ - bol */, - '\x1b[3~': delete_char /* ^[[3~ - delete */, - '\x1b[4~': end_of_line /* ^[[4~ - eol */, - '\x1b[5~': history_search_backward /* ^[[5~ - page up */, - '\x1b[6~': history_search_forward /* ^[[5~ - page down */, - '\x1b[A': previous_history /* ^[[A - up */, - '\x1b[B': next_history /* ^[[B - down */, - '\x1b[C': forward_char /* ^[[C - right */, - '\x1b[D': backward_char /* ^[[D - left */, - '\x1b[F': end_of_line /* ^[[F - end */, - '\x1b[H': beginning_of_line /* ^[[H - home */, - '\x1b\x7f': backward_kill_word /* M-C-? - backward_kill_word */, - '\x1bb': backward_word /* M-b - backward_word */, - '\x1bd': kill_word /* M-d - kill_word */, - '\x1bf': forward_word /* M-f - backward_word */, - '\x1bk': backward_kill_line /* M-k - backward_kill_line */, - '\x1bl': downcase_word /* M-l - downcase_word */, - '\x1bt': transpose_words /* M-t - transpose_words */, - '\x1bu': upcase_word /* M-u - upcase_word */, - '\x7f': backward_delete_char /* ^? - delete */, - }; - - function dupstr(str, count) { - var res = ''; - while (count-- > 0) res += str; - return res; - } - - var readline_keys; - var readline_state; - var readline_cb; - - function readline_print_prompt() { - std.puts(prompt); - term_cursor_x = ucs_length(prompt) % term_width; - last_cmd = ''; - last_cursor_pos = 0; - } - - function readline_start(defstr, cb) { - cmd = defstr || ''; - cursor_pos = cmd.length; - history_index = history.length; - readline_cb = cb; - - prompt = pstate; - - if (mexpr) { - prompt += dupstr(' ', plen - prompt.length); - prompt += ps2; - } else { - if (show_time) { - var t = Math.round(eval_time) + ' '; - eval_time = 0; - t = dupstr('0', 5 - t.length) + t; - prompt += - t.substring(0, t.length - 4) + '.' + t.substring(t.length - 4); - } - plen = prompt.length; - prompt += ps1; - } - readline_print_prompt(); - update(); - readline_state = 0; - } - - function handle_char(c1) { - var c; - c = String.fromCodePoint(c1); - switch (readline_state) { - case 0: - if (c == '\x1b') { - /* '^[' - ESC */ - readline_keys = c; - readline_state = 1; - } else { - handle_key(c); - } - break; - case 1 /* '^[ */: - readline_keys += c; - if (c == '[') { - readline_state = 2; - } else if (c == 'O') { - readline_state = 3; - } else { - handle_key(readline_keys); - readline_state = 0; - } - break; - case 2 /* '^[[' - CSI */: - readline_keys += c; - if (!(c == ';' || (c >= '0' && c <= '9'))) { - handle_key(readline_keys); - readline_state = 0; - } - break; - case 3 /* '^[O' - ESC2 */: - readline_keys += c; - handle_key(readline_keys); - readline_state = 0; - break; - } - } - - function handle_key(keys) { - var fun; - - if (quote_flag) { - if (ucs_length(keys) === 1) insert(keys); - quote_flag = false; - } else if ((fun = commands[keys])) { - this_fun = fun; - switch (fun(keys)) { - case -1: - readline_cb(cmd); - return; - case -2: - readline_cb(null); - return; - case -3: - /* uninstall a Ctrl-C signal handler */ - os.signal(os.SIGINT, null); - /* uninstall the stdin read handler */ - os.setReadHandler(term_fd, null); - return; - } - last_fun = this_fun; - } else if (ucs_length(keys) === 1 && keys >= ' ') { - insert(keys); - last_fun = insert; - } else { - alert(); /* beep! */ - } - - cursor_pos = - cursor_pos < 0 ? 0 : cursor_pos > cmd.length ? cmd.length : cursor_pos; - update(); - } - - var hex_mode = false; - var eval_mode = 'std'; - - function number_to_string(a, radix) { - var s; - if (!isFinite(a)) { - /* NaN, Infinite */ - return a.toString(); - } else { - if (a == 0) { - if (1 / a < 0) s = '-0'; - else s = '0'; - } else { - if (radix == 16 && a === Math.floor(a)) { - var s; - if (a < 0) { - a = -a; - s = '-'; - } else { - s = ''; - } - s += '0x' + a.toString(16); - } else { - s = a.toString(); - } - } - return s; - } - } - - function bigfloat_to_string(a, radix) { - var s; - if (!BigFloat.isFinite(a)) { - /* NaN, Infinite */ - if (eval_mode !== 'math') { - return 'BigFloat(' + a.toString() + ')'; - } else { - return a.toString(); - } - } else { - if (a == 0) { - if (1 / a < 0) s = '-0'; - else s = '0'; - } else { - if (radix == 16) { - var s; - if (a < 0) { - a = -a; - s = '-'; - } else { - s = ''; - } - s += '0x' + a.toString(16); - } else { - s = a.toString(); - } - } - if (typeof a === 'bigfloat' && eval_mode !== 'math') { - s += 'l'; - } else if ( - eval_mode !== 'std' && - s.indexOf('.') < 0 && - ((radix == 16 && s.indexOf('p') < 0) || - (radix == 10 && s.indexOf('e') < 0)) - ) { - /* add a decimal point so that the floating point type - is visible */ - s += '.0'; - } - return s; - } - } - - function bigint_to_string(a, radix) { - var s; - if (radix == 16) { - var s; - if (a < 0) { - a = -a; - s = '-'; - } else { - s = ''; - } - s += '0x' + a.toString(16); - } else { - s = a.toString(); - } - if (eval_mode === 'std') s += 'n'; - return s; - } - - function print(a) { - var stack = []; - - function print_rec(a) { - var n, i, keys, key, type, s; - - type = typeof a; - if (type === 'object') { - if (a === null) { - std.puts(a); - } else if (stack.indexOf(a) >= 0) { - std.puts('[circular]'); - } else if ( - has_jscalc && - (a instanceof Fraction || - a instanceof Complex || - a instanceof Mod || - a instanceof Polynomial || - a instanceof PolyMod || - a instanceof RationalFunction || - a instanceof Series) - ) { - std.puts(a.toString()); - } else { - stack.push(a); - if (Array.isArray(a)) { - n = a.length; - std.puts('[ '); - for (i = 0; i < n; i++) { - if (i !== 0) std.puts(', '); - if (i in a) { - print_rec(a[i]); - } else { - std.puts(''); - } - if (i > 20) { - std.puts('...'); - break; - } - } - std.puts(' ]'); - } else if (Object.__getClass(a) === 'RegExp') { - std.puts(a.toString()); - } else { - keys = Object.keys(a); - n = keys.length; - std.puts('{ '); - for (i = 0; i < n; i++) { - if (i !== 0) std.puts(', '); - key = keys[i]; - std.puts(key, ': '); - print_rec(a[key]); - } - std.puts(' }'); - } - stack.pop(a); - } - } else if (type === 'string') { - s = a.__quote(); - if (s.length > 79) s = s.substring(0, 75) + '..."'; - std.puts(s); - } else if (type === 'number') { - std.puts(number_to_string(a, hex_mode ? 16 : 10)); - } else if (type === 'bigint') { - std.puts(bigint_to_string(a, hex_mode ? 16 : 10)); - } else if (type === 'bigfloat') { - std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10)); - } else if (type === 'bigdecimal') { - std.puts(a.toString() + 'm'); - } else if (type === 'symbol') { - std.puts(String(a)); - } else if (type === 'function') { - std.puts('function ' + a.name + '()'); - } else { - std.puts(a); - } - } - print_rec(a); - } - - function extract_directive(a) { - var pos; - if (a[0] !== '\\') return ''; - for (pos = 1; pos < a.length; pos++) { - if (!is_alpha(a[pos])) break; - } - return a.substring(1, pos); - } - - /* return true if the string after cmd can be evaluted as JS */ - function handle_directive(cmd, expr) { - var param, prec1, expBits1; - - if (cmd === 'h' || cmd === '?' || cmd == 'help') { - help(); - } else if (cmd === 'load') { - var filename = expr.substring(cmd.length + 1).trim(); - if (filename.lastIndexOf('.') <= filename.lastIndexOf('/')) - filename += '.js'; - std.loadScript(filename); - return false; - } else if (cmd === 'x') { - hex_mode = true; - } else if (cmd === 'd') { - hex_mode = false; - } else if (cmd === 't') { - show_time = !show_time; - } else if (has_bignum && cmd === 'p') { - param = expr - .substring(cmd.length + 1) - .trim() - .split(' '); - if (param.length === 1 && param[0] === '') { - std.puts( - 'BigFloat precision=' + - prec + - ' bits (~' + - Math.floor(prec / log2_10) + - ' digits), exponent size=' + - expBits + - ' bits\n', - ); - } else if (param[0] === 'f16') { - prec = 11; - expBits = 5; - } else if (param[0] === 'f32') { - prec = 24; - expBits = 8; - } else if (param[0] === 'f64') { - prec = 53; - expBits = 11; - } else if (param[0] === 'f128') { - prec = 113; - expBits = 15; - } else { - prec1 = parseInt(param[0]); - if (param.length >= 2) expBits1 = parseInt(param[1]); - else expBits1 = BigFloatEnv.expBitsMax; - if ( - Number.isNaN(prec1) || - prec1 < BigFloatEnv.precMin || - prec1 > BigFloatEnv.precMax - ) { - std.puts('Invalid precision\n'); - return false; - } - if ( - Number.isNaN(expBits1) || - expBits1 < BigFloatEnv.expBitsMin || - expBits1 > BigFloatEnv.expBitsMax - ) { - std.puts('Invalid exponent bits\n'); - return false; - } - prec = prec1; - expBits = expBits1; - } - return false; - } else if (has_bignum && cmd === 'digits') { - param = expr.substring(cmd.length + 1).trim(); - prec1 = Math.ceil(parseFloat(param) * log2_10); - if (prec1 < BigFloatEnv.precMin || prec1 > BigFloatEnv.precMax) { - std.puts('Invalid precision\n'); - return false; - } - prec = prec1; - expBits = BigFloatEnv.expBitsMax; - return false; - } else if (has_bignum && cmd === 'mode') { - param = expr.substring(cmd.length + 1).trim(); - if (param === '') { - std.puts('Running mode=' + eval_mode + '\n'); - } else if (param === 'std' || param === 'math') { - eval_mode = param; - } else { - std.puts('Invalid mode\n'); - } - return false; - } else if (cmd === 'clear') { - std.puts('\x1b[H\x1b[J'); - } else if (cmd === 'q') { - std.exit(0); - } else if (has_jscalc && cmd === 'a') { - algebraicMode = true; - } else if (has_jscalc && cmd === 'n') { - algebraicMode = false; - } else { - std.puts('Unknown directive: ' + cmd + '\n'); - return false; - } - return true; - } - - if (config_numcalc) { - /* called by the GUI */ - g.execCmd = function (cmd) { - switch (cmd) { - case 'dec': - hex_mode = false; - break; - case 'hex': - hex_mode = true; - break; - case 'num': - algebraicMode = false; - break; - case 'alg': - algebraicMode = true; - break; - } - }; - } - - function help() { - function sel(n) { - return n ? '*' : ' '; - } - std.puts( - '\\h this help\n' + - '\\x ' + - sel(hex_mode) + - 'hexadecimal number display\n' + - '\\d ' + - sel(!hex_mode) + - 'decimal number display\n' + - '\\t ' + - sel(show_time) + - 'toggle timing display\n' + - '\\clear clear the terminal\n', - ); - if (has_jscalc) { - std.puts( - '\\a ' + - sel(algebraicMode) + - 'algebraic mode\n' + - '\\n ' + - sel(!algebraicMode) + - 'numeric mode\n', - ); - } - if (has_bignum) { - std.puts( - "\\p [m [e]] set the BigFloat precision to 'm' bits\n" + - "\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n", - ); - if (!has_jscalc) { - std.puts( - '\\mode [std|math] change the running mode (current = ' + - eval_mode + - ')\n', - ); - } - } - if (!config_numcalc) { - std.puts('\\q exit\n'); - } - } - - function eval_and_print(expr) { - var result; - - try { - if (eval_mode === 'math') expr = '"use math"; void 0;' + expr; - var now = new Date().getTime(); - /* eval as a script */ - result = std.evalScript(expr, { backtrace_barrier: true }); - eval_time = new Date().getTime() - now; - std.puts(colors[styles.result]); - print(result); - std.puts('\n'); - std.puts(colors.none); - /* set the last result */ - g._ = result; - } catch (error) { - std.puts(colors[styles.error_msg]); - if (error instanceof Error) { - console.log(error); - if (error.stack) { - std.puts(error.stack); - } - } else { - std.puts('Throw: '); - console.log(error); - } - std.puts(colors.none); - } - } - - function cmd_start() { - if (!config_numcalc) { - if (has_jscalc) std.puts('QJSCalc - Type "\\h" for help\n'); - else std.puts('QuickJS - Type "\\h" for help\n'); - } - if (has_bignum) { - log2_10 = Math.log(10) / Math.log(2); - prec = 113; - expBits = 15; - if (has_jscalc) { - eval_mode = 'math'; - /* XXX: numeric mode should always be the default ? */ - g.algebraicMode = config_numcalc; - } - } - - cmd_readline_start(); - } - - function cmd_readline_start() { - readline_start(dupstr(' ', level), readline_handle_cmd); - } - - function readline_handle_cmd(expr) { - handle_cmd(expr); - cmd_readline_start(); - } - - function handle_cmd(expr) { - var colorstate, cmd; - - if (expr === null) { - expr = ''; - return; - } - if (expr === '?') { - help(); - return; - } - cmd = extract_directive(expr); - if (cmd.length > 0) { - if (!handle_directive(cmd, expr)) return; - expr = expr.substring(cmd.length + 1); - } - if (expr === '') return; - - if (mexpr) expr = mexpr + '\n' + expr; - colorstate = colorize_js(expr); - pstate = colorstate[0]; - level = colorstate[1]; - if (pstate) { - mexpr = expr; - return; - } - mexpr = ''; - - if (has_bignum) { - BigFloatEnv.setPrec(eval_and_print.bind(null, expr), prec, expBits); - } else { - eval_and_print(expr); - } - level = 0; - - /* run the garbage collector after each command */ - std.gc(); - } - - function colorize_js(str) { - var i, - c, - start, - n = str.length; - var style, - state = '', - level = 0; - var primary, - can_regex = 1; - var r = []; - - function push_state(c) { - state += c; - } - function last_state(c) { - return state.substring(state.length - 1); - } - function pop_state(c) { - var c = last_state(); - state = state.substring(0, state.length - 1); - return c; - } - - function parse_block_comment() { - style = 'comment'; - push_state('/'); - for (i++; i < n - 1; i++) { - if (str[i] == '*' && str[i + 1] == '/') { - i += 2; - pop_state('/'); - break; - } - } - } - - function parse_line_comment() { - style = 'comment'; - for (i++; i < n; i++) { - if (str[i] == '\n') { - break; - } - } - } - - function parse_string(delim) { - style = 'string'; - push_state(delim); - while (i < n) { - c = str[i++]; - if (c == '\n') { - style = 'error'; - continue; - } - if (c == '\\') { - if (i >= n) break; - i++; - } else if (c == delim) { - pop_state(); - break; - } - } - } - - function parse_regex() { - style = 'regex'; - push_state('/'); - while (i < n) { - c = str[i++]; - if (c == '\n') { - style = 'error'; - continue; - } - if (c == '\\') { - if (i < n) { - i++; - } - continue; - } - if (last_state() == '[') { - if (c == ']') { - pop_state(); - } - // ECMA 5: ignore '/' inside char classes - continue; - } - if (c == '[') { - push_state('['); - if (str[i] == '[' || str[i] == ']') i++; - continue; - } - if (c == '/') { - pop_state(); - while (i < n && is_word(str[i])) i++; - break; - } - } - } - - function parse_number() { - style = 'number'; - while ( - i < n && - (is_word(str[i]) || - (str[i] == '.' && (i == n - 1 || str[i + 1] != '.'))) - ) { - i++; - } - } - - var js_keywords = - '|' + - 'break|case|catch|continue|debugger|default|delete|do|' + - 'else|finally|for|function|if|in|instanceof|new|' + - 'return|switch|this|throw|try|typeof|while|with|' + - 'class|const|enum|import|export|extends|super|' + - 'implements|interface|let|package|private|protected|' + - 'public|static|yield|' + - 'undefined|null|true|false|Infinity|NaN|' + - 'eval|arguments|' + - 'await|'; - - var js_no_regex = - '|this|super|undefined|null|true|false|Infinity|NaN|arguments|'; - var js_types = '|void|var|'; - - function parse_identifier() { - can_regex = 1; - - while (i < n && is_word(str[i])) i++; - - var w = '|' + str.substring(start, i) + '|'; - - if (js_keywords.indexOf(w) >= 0) { - style = 'keyword'; - if (js_no_regex.indexOf(w) >= 0) can_regex = 0; - return; - } - - var i1 = i; - while (i1 < n && str[i1] == ' ') i1++; - - if (i1 < n && str[i1] == '(') { - style = 'function'; - return; - } - - if (js_types.indexOf(w) >= 0) { - style = 'type'; - return; - } - - style = 'identifier'; - can_regex = 0; - } - - function set_style(from, to) { - while (r.length < from) r.push('default'); - while (r.length < to) r.push(style); - } - - for (i = 0; i < n; ) { - style = null; - start = i; - switch ((c = str[i++])) { - case ' ': - case '\t': - case '\r': - case '\n': - continue; - case '+': - case '-': - if (i < n && str[i] == c) { - i++; - continue; - } - can_regex = 1; - continue; - case '/': - if (i < n && str[i] == '*') { - // block comment - parse_block_comment(); - break; - } - if (i < n && str[i] == '/') { - // line comment - parse_line_comment(); - break; - } - if (can_regex) { - parse_regex(); - can_regex = 0; - break; - } - can_regex = 1; - continue; - case "'": - case '"': - case '`': - parse_string(c); - can_regex = 0; - break; - case '(': - case '[': - case '{': - can_regex = 1; - level++; - push_state(c); - continue; - case ')': - case ']': - case '}': - can_regex = 0; - if (level > 0 && is_balanced(last_state(), c)) { - level--; - pop_state(); - continue; - } - style = 'error'; - break; - default: - if (is_digit(c)) { - parse_number(); - can_regex = 0; - break; - } - if (is_word(c) || c == '$') { - parse_identifier(); - break; - } - can_regex = 1; - continue; - } - if (style) set_style(start, i); - } - set_style(n, n); - return [state, level, r]; - } - - termInit(); - - cmd_start(); -})(globalThis); diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262_errors.txt b/packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262_errors.txt deleted file mode 100644 index b7f6aef3..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262_errors.txt +++ /dev/null @@ -1,35 +0,0 @@ -test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError -test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError -test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name -test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name -test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: Test262Error: (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: strict mode: Test262Error: (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: Test262Error: (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: strict mode: Test262Error: (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: strict mode: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: strict mode: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: strict mode: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: strict mode: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: strict mode: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: strict mode: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.) -test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called -test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called -test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined -test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined -test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: unexpected error type: Test262: This statement should not be evaluated. -test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: strict mode: unexpected error type: Test262: This statement should not be evaluated. diff --git a/packages/android-engine/android-js-engine/src/main/cpp/runner.cpp b/packages/android-engine/android-js-engine/src/main/cpp/runner.cpp deleted file mode 100644 index 36e0c74f..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/runner.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "runner.h" - -#include "api/api_console.h" - -Runner::Runner() { - this->rt = JS_NewRuntime(); - JS_SetCanBlock(rt, 0); - JS_SetMaxStackSize(rt, 0); - - this->log_debug("created runner"); -} - -Runner::~Runner() { - this->log_debug("destroying runner"); - - this->stop(); - - if (!this->contexts.empty()) { - for (const auto &kv : this->contexts) { - this->destroy_context(kv.first); - } - } - - this->contexts.clear(); - - this->log_debug("freeing runtime"); - - JS_FreeRuntime(this->rt); - this->rt = nullptr; - - this->log_debug("destroyed runner"); -} - -void Runner::start() { - this->log_debug("starting runner run loop..."); - - this->run_loop_started = true; - this->stop_run_loop = false; - - this->run_loop(); -} - -void Runner::stop() { - if (this->stop_run_loop) { - return; - } - - this->stop_run_loop = true; - - while (this->run_loop_started) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - - this->log_debug("stopped runner run loop"); -} - -long Runner::create_context(std::string name, JNIEnv *env) { - auto *context = new Context(name, this->rt, env); - this->contexts.insert_or_assign(name, context); - - return (long)context; -} - -void Runner::destroy_context(std::string name) { - try { - this->log_debug("try to destroy context " + name); - auto *context = this->contexts.at(name); - delete context; - - this->contexts.erase(name); - } catch (std::exception &ex) { - } -} - -void Runner::run_loop() { - JSContext *job_ctx; - - for (;;) { - if (this->stop_run_loop && !JS_IsJobPending(this->rt)) { - break; - } - - if (JS_IsJobPending(this->rt)) { - int const status = JS_ExecutePendingJob(this->rt, &job_ctx); - if (status < 0) { - auto exception_val = JS_GetException(job_ctx); - auto err_message = JS_GetPropertyStr(job_ctx, exception_val, "message"); - const char *err_str = JS_ToCString(job_ctx, err_message); - - this->log_debug(std::string(err_str)); - - JS_FreeValue(job_ctx, exception_val); - JS_FreeCString(job_ctx, err_str); - JS_FreeValue(job_ctx, err_message); - } - } - - for (const auto &kv : this->contexts) { - kv.second->run_loop(); - } - } - - this->run_loop_started = false; -} - -void Runner::log_debug(const std::string &msg) { write_to_logcat(ANDROID_LOG_DEBUG, "[Runner]", msg.c_str()); } diff --git a/packages/android-engine/android-js-engine/src/main/cpp/runner.h b/packages/android-engine/android-js-engine/src/main/cpp/runner.h deleted file mode 100644 index 5189f30f..00000000 --- a/packages/android-engine/android-js-engine/src/main/cpp/runner.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef CAPACITOR_BACKGROUND_RUNNER_RUNNER_H -#define CAPACITOR_BACKGROUND_RUNNER_RUNNER_H - -#include -#include -#include -#include - -#include - -#include "./quickjs/quickjs.h" -#include "context.h" - -class Runner { -public: - JSRuntime *rt; - std::unordered_map contexts; - - Runner(); - ~Runner(); - - void start(); - void stop(); - - long create_context(std::string name, JNIEnv *env); - void destroy_context(std::string name); - -private: - bool run_loop_started; - bool stop_run_loop; - - void run_loop(); - - void log_debug(const std::string& msg); -}; - -#endif //CAPACITOR_BACKGROUND_RUNNER_RUNNER_H diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/Context.kt b/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/Context.kt deleted file mode 100644 index 32194464..00000000 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/Context.kt +++ /dev/null @@ -1,52 +0,0 @@ -package io.ionic.android_js_engine - -import io.ionic.android_js_engine.api.CapacitorAPI -import org.json.JSONObject - -class Context(name: String, runnerPtr: Long) { - val name: String - private val runnerPtr: Long - - private var ptr: Long? = null - - init { - System.loadLibrary("android_js_engine") - this.name = name - this.runnerPtr = runnerPtr - this.ptr = createRunnerContext(runnerPtr, name) - } - - private external fun createRunnerContext(runnerPtr: Long, name: String): Long - private external fun destroyRunnerContext(runnerPtr: Long, ptr: Long) - private external fun evaluate(ptr: Long, code: String, retValue: Boolean): String - private external fun registerGlobalFunction(ptr: Long, functionName: String, function: JSFunction) - private external fun dispatchEvent(ptr: Long, event: String, details: String) - private external fun setCapacitorAPI(ptr: Long, api: CapacitorAPI) - - fun execute(code: String, returnValue: Boolean = false): JSValue { - val ptr = this.ptr ?: throw EngineErrors.ContextException("pointer is nil") - val jsonString = this.evaluate(ptr, code, returnValue) - - return JSValue(jsonString) - } - - fun registerFunction(funcName: String, func: JSFunction) { - val ptr = this.ptr ?: throw EngineErrors.ContextException("pointer is nil") - this.registerGlobalFunction(ptr, funcName, func) - } - - fun dispatchEvent(event: String, details: JSONObject) { - val ptr = this.ptr ?: throw EngineErrors.ContextException("pointer is nil") - this.dispatchEvent(ptr, event, details.toString(0)) - } - - fun setCapacitorAPI(capAPI: CapacitorAPI) { - val ptr = this.ptr ?: throw EngineErrors.ContextException("pointer is nil") - this.setCapacitorAPI(ptr, capAPI) - } - - internal fun destroy() { - val contextPtr = this.ptr ?: throw EngineErrors.ContextException("pointer is nil") - destroyRunnerContext(runnerPtr, contextPtr) - } -} diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSFetchOptions.kt b/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSFetchOptions.kt deleted file mode 100644 index 54edfbd1..00000000 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSFetchOptions.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.ionic.android_js_engine - -import org.json.JSONObject -import java.nio.charset.Charset - -class JSFetchOptions(jsonString: String) { - public val httpMethod: String - public val headers = HashMap() - public var body: ByteArray? = null - - init { - val jsObject = JSONObject(jsonString) - - val bodyString = jsObject.getString("body") - if (!bodyString.isNullOrEmpty()) { - body = bodyString.toByteArray(Charset.defaultCharset()) - } - - val jsHeaders = jsObject.getJSONObject("headers") - jsHeaders.keys().forEach { - headers[it] = jsHeaders.getString(it) - } - - httpMethod = jsObject.optString("method", "GET").uppercase() - } -} diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSFunction.kt b/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSFunction.kt deleted file mode 100644 index 97f369a3..00000000 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSFunction.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.ionic.android_js_engine - -import org.json.JSONObject - -open class JSFunction(jsName: String, args: JSONObject? = null) : Runnable { - public var args: JSONObject? = null - public var name: String - - init { - this.name = jsName - this.args = args - } - - override fun run() {} -} diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/CapacitorAPI.kt b/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/CapacitorAPI.kt deleted file mode 100644 index 7c28c29a..00000000 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/CapacitorAPI.kt +++ /dev/null @@ -1,34 +0,0 @@ -package io.ionic.android_js_engine.api - -class CapacitorAPI(contextLabel: String) { - private val label: String - - private var kv: KVAPI? - private var device: DeviceAPI? - private var notifications: NotificationsAPI? - private var geolocation: GeolocationAPI? - - init { - label = contextLabel - notifications = null - device = null - kv = null - geolocation = null - } - - fun initNotificationsAPI(api: NotificationsAPI) { - this.notifications = api - } - - fun initDeviceAPI(api: DeviceAPI) { - this.device = api - } - - fun initGeolocationAPI(api: GeolocationAPI) { - this.geolocation = api - } - - fun initKVAPI(api: KVAPI) { - this.kv = api - } -} diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/KVAPI.kt b/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/KVAPI.kt deleted file mode 100644 index c7db0393..00000000 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/KVAPI.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.ionic.android_js_engine.api - -interface KVAPI { - fun set(key: String, value: String) - fun get(key: String): String? - fun remove(key: String) -} diff --git a/packages/android-engine/android-js-engine/src/test/java/io/ionic/android_js_engine/ExampleUnitTest.kt b/packages/android-engine/android-js-engine/src/test/java/io/ionic/android_js_engine/ExampleUnitTest.kt deleted file mode 100644 index b56e2f8e..00000000 --- a/packages/android-engine/android-js-engine/src/test/java/io/ionic/android_js_engine/ExampleUnitTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.ionic.android_js_engine - -import org.junit.Assert.* -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/packages/android-engine/app/src/main/res/values/strings.xml b/packages/android-engine/app/src/main/res/values/strings.xml deleted file mode 100644 index beca20cc..00000000 --- a/packages/android-engine/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - Capacitor Background Runner - \ No newline at end of file diff --git a/packages/android-engine/gradle/wrapper/gradle-wrapper.jar b/packages/android-engine/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index ccebba7710deaf9f98673a68957ea02138b60d0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61608 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 diff --git a/packages/android-engine/gradlew b/packages/android-engine/gradlew deleted file mode 100755 index 79a61d42..00000000 --- a/packages/android-engine/gradlew +++ /dev/null @@ -1,244 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original 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 -# -# https://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. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/packages/android-engine/package.json b/packages/android-engine/package.json deleted file mode 100644 index c6a98445..00000000 --- a/packages/android-engine/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "android-engine", - "private": true, - "dependencies": { - "@naturalcycles/ktlint": "1.7.0", - "clang-format": "^1.8.0", - "prettier": "~2.3.2", - "prettier-plugin-java": "~1.0.2" - }, - "devDependencies": { - "@ionic/prettier-config": "^1.0.1" - }, - "prettier": "@ionic/prettier-config", - "scripts": { - "lint": "pnpm prettier --check && pnpm clang-format --dry-run && ktlint 'android-js-engine/src/**/*.kt'", - "fmt": "pnpm prettier --write && pnpm clang-format -i && ktlint --format 'android-js-engine/src/**/*.kt'", - "prettier": "prettier --plugin-search-dir=. \"**/*.{css,html,ts,js,java}\"", - "clang-format": "clang-format --glob=android-js-engine/src/main/cpp/**/*.{cpp,h}" - }, - "version": "1.0.5" -} diff --git a/packages/android-engine/settings.gradle b/packages/android-engine/settings.gradle deleted file mode 100644 index c68553bd..00000000 --- a/packages/android-engine/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -pluginManagement { - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -rootProject.name = "Capacitor Background Runner" -include ':app' -include ':android-js-engine' diff --git a/packages/android-engine/.clang-format b/packages/android-js-engine/.clang-format similarity index 100% rename from packages/android-engine/.clang-format rename to packages/android-js-engine/.clang-format diff --git a/packages/android-engine/.clang-tidy b/packages/android-js-engine/.clang-tidy similarity index 100% rename from packages/android-engine/.clang-tidy rename to packages/android-js-engine/.clang-tidy diff --git a/packages/android-js-engine/.editorconfig b/packages/android-js-engine/.editorconfig new file mode 100644 index 00000000..cfec781a --- /dev/null +++ b/packages/android-js-engine/.editorconfig @@ -0,0 +1,2 @@ +[*.{kt,kts}] +ktlint_standard_package-name = disabled \ No newline at end of file diff --git a/packages/android-engine/.gitignore b/packages/android-js-engine/.gitignore similarity index 100% rename from packages/android-engine/.gitignore rename to packages/android-js-engine/.gitignore diff --git a/packages/android-js-engine/.idea/.gitignore b/packages/android-js-engine/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/packages/android-js-engine/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/packages/android-js-engine/.idea/.name b/packages/android-js-engine/.idea/.name new file mode 100644 index 00000000..70b1bfaf --- /dev/null +++ b/packages/android-js-engine/.idea/.name @@ -0,0 +1 @@ +Android JS Engine Test Project \ No newline at end of file diff --git a/packages/android-js-engine/.idea/androidTestResultsUserPreferences.xml b/packages/android-js-engine/.idea/androidTestResultsUserPreferences.xml new file mode 100644 index 00000000..37663ae6 --- /dev/null +++ b/packages/android-js-engine/.idea/androidTestResultsUserPreferences.xml @@ -0,0 +1,182 @@ + + + + + + \ No newline at end of file diff --git a/packages/android-engine/.idea/compiler.xml b/packages/android-js-engine/.idea/compiler.xml similarity index 100% rename from packages/android-engine/.idea/compiler.xml rename to packages/android-js-engine/.idea/compiler.xml diff --git a/packages/android-js-engine/.idea/deploymentTargetDropDown.xml b/packages/android-js-engine/.idea/deploymentTargetDropDown.xml new file mode 100644 index 00000000..7389d62b --- /dev/null +++ b/packages/android-js-engine/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/android-engine/.idea/gradle.xml b/packages/android-js-engine/.idea/gradle.xml similarity index 71% rename from packages/android-engine/.idea/gradle.xml rename to packages/android-js-engine/.idea/gradle.xml index 0905a649..d7cb91a0 100644 --- a/packages/android-engine/.idea/gradle.xml +++ b/packages/android-js-engine/.idea/gradle.xml @@ -4,17 +4,16 @@ diff --git a/packages/android-engine/.idea/kotlinc.xml b/packages/android-js-engine/.idea/kotlinc.xml similarity index 100% rename from packages/android-engine/.idea/kotlinc.xml rename to packages/android-js-engine/.idea/kotlinc.xml diff --git a/packages/android-js-engine/.idea/migrations.xml b/packages/android-js-engine/.idea/migrations.xml new file mode 100644 index 00000000..f8051a6f --- /dev/null +++ b/packages/android-js-engine/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/packages/android-engine/.idea/misc.xml b/packages/android-js-engine/.idea/misc.xml similarity index 100% rename from packages/android-engine/.idea/misc.xml rename to packages/android-js-engine/.idea/misc.xml diff --git a/packages/android-engine/.idea/vcs.xml b/packages/android-js-engine/.idea/vcs.xml similarity index 100% rename from packages/android-engine/.idea/vcs.xml rename to packages/android-js-engine/.idea/vcs.xml diff --git a/packages/android-engine/android-js-engine/.gitignore b/packages/android-js-engine/AndroidJSEngine/.gitignore similarity index 100% rename from packages/android-engine/android-js-engine/.gitignore rename to packages/android-js-engine/AndroidJSEngine/.gitignore diff --git a/packages/android-engine/android-js-engine/build.gradle b/packages/android-js-engine/AndroidJSEngine/build.gradle similarity index 90% rename from packages/android-engine/android-js-engine/build.gradle rename to packages/android-js-engine/AndroidJSEngine/build.gradle index ded7a52f..ad1dd747 100644 --- a/packages/android-engine/android-js-engine/build.gradle +++ b/packages/android-js-engine/AndroidJSEngine/build.gradle @@ -4,8 +4,7 @@ ext { androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5' androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1' androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.10.0' - androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.8.0' - okHttpVersion = project.hasProperty('okHttpVersion') ? rootProject.ext.okHttpVersion : '4.11.0' + androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.9.0' } buildscript { @@ -25,7 +24,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - namespace "com.capacitorjs.android_js_engine" + namespace 'com.capacitorjs.android_js_engine' compileSdk 33 defaultConfig { @@ -41,6 +40,10 @@ android { cppFlags "-std=c++17" } } + + ndk { + debugSymbolLevel 'FULL' + } } buildTypes { @@ -64,11 +67,6 @@ android { } } -repositories { - google() - mavenCentral() -} - dependencies { implementation "androidx.core:core-ktx:$androidxCoreKTXVersion" implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" diff --git a/packages/android-engine/android-js-engine/consumer-rules.pro b/packages/android-js-engine/AndroidJSEngine/consumer-rules.pro similarity index 100% rename from packages/android-engine/android-js-engine/consumer-rules.pro rename to packages/android-js-engine/AndroidJSEngine/consumer-rules.pro diff --git a/packages/android-engine/android-js-engine/proguard-rules.pro b/packages/android-js-engine/AndroidJSEngine/proguard-rules.pro similarity index 100% rename from packages/android-engine/android-js-engine/proguard-rules.pro rename to packages/android-js-engine/AndroidJSEngine/proguard-rules.pro diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/AndroidManifest.xml b/packages/android-js-engine/AndroidJSEngine/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a5918e68 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/CMakeLists.txt b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/CMakeLists.txt new file mode 100644 index 00000000..b7c4f504 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.22.1) + +project("android_js_engine") + +add_library( + ${CMAKE_PROJECT_NAME} SHARED + android_js_engine.cpp + native_runner.cpp + native_context.cpp + native_android_interface.cpp + native_capacitor_interface.cpp + java.cpp + java_errors.cpp +) + +add_subdirectory("./js-engine") + +target_link_libraries(${CMAKE_PROJECT_NAME} android log JSEngine) \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/android_js_engine.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/android_js_engine.cpp new file mode 100644 index 00000000..abc24cad --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/android_js_engine.cpp @@ -0,0 +1,11 @@ +#include + +#include + +#include "./js-engine/src/native.hpp" + +extern "C" JNIEXPORT jstring JNICALL Java_io_ionic_android_1js_1engine_NativeLib_stringFromJNI(JNIEnv* env, jobject /* this */) { + std::string hello = "Hello from C++"; + + return env->NewStringUTF(hello.c_str()); +} \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/java.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java.cpp similarity index 74% rename from packages/android-engine/android-js-engine/src/main/cpp/java.cpp rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/java.cpp index 1645389b..5b295221 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/java.cpp +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java.cpp @@ -9,111 +9,110 @@ Java::Java(JNIEnv *env) { jclass tmp_class; // Context API - tmp_class = env->FindClass("io/ionic/android_js_engine/WebAPI"); + tmp_class = env->FindClass("io/ionic/android_js_engine/NativeWebAPI"); this->check_exception(env); this->web_api_class = (jclass)env->NewGlobalRef(tmp_class); env->DeleteLocalRef(tmp_class); tmp_class = nullptr; - tmp_class = env->FindClass("io/ionic/android_js_engine/JSFetchOptions"); + tmp_class = env->FindClass("io/ionic/android_js_engine/NativeJSFetchOptions"); this->check_exception(env); - this->js_fetch_options_class = (jclass)env->NewGlobalRef(tmp_class); + this->native_js_fetch_options_class = (jclass)env->NewGlobalRef(tmp_class); env->DeleteLocalRef(tmp_class); tmp_class = nullptr; - tmp_class = env->FindClass("io/ionic/android_js_engine/JSResponse"); + tmp_class = env->FindClass("io/ionic/android_js_engine/NativeJSResponse"); this->check_exception(env); - this->js_response_class = (jclass)env->NewGlobalRef(tmp_class); + this->native_js_response_class = (jclass)env->NewGlobalRef(tmp_class); env->DeleteLocalRef(tmp_class); tmp_class = nullptr; - tmp_class = env->FindClass("io/ionic/android_js_engine/api/CapacitorAPI"); + this->web_api_byteArrayToString_method = env->GetStaticMethodID(this->web_api_class, "byteArrayToString", "([BLjava/lang/String;)Ljava/lang/String;"); this->check_exception(env); - this->capacitor_api_class = (jclass)env->NewGlobalRef(tmp_class); - env->DeleteLocalRef(tmp_class); - tmp_class = nullptr; - - tmp_class = env->FindClass("io/ionic/android_js_engine/api/KVAPI"); + this->web_api_stringToByteArray_method = env->GetStaticMethodID(this->web_api_class, "stringToByteArray", "(Ljava/lang/String;)[B"); this->check_exception(env); - this->capacitor_kv_api_class = (jclass)env->NewGlobalRef(tmp_class); - env->DeleteLocalRef(tmp_class); - tmp_class = nullptr; - - tmp_class = env->FindClass("io/ionic/android_js_engine/api/DeviceAPI"); + this->web_api_randomHashCode_method = env->GetStaticMethodID(this->web_api_class, "randomHashCode", "()I"); this->check_exception(env); - this->capacitor_device_api_class = (jclass)env->NewGlobalRef(tmp_class); - env->DeleteLocalRef(tmp_class); - tmp_class = nullptr; - - tmp_class = env->FindClass("io/ionic/android_js_engine/api/GeolocationAPI"); + this->web_api_cryptoGetRandom_method = env->GetStaticMethodID(this->web_api_class, "cryptoGetRandom", "(I)[B"); this->check_exception(env); - this->capacitor_geolocation_api_class = (jclass)env->NewGlobalRef(tmp_class); - env->DeleteLocalRef(tmp_class); - tmp_class = nullptr; - - tmp_class = env->FindClass("io/ionic/android_js_engine/api/NotificationsAPI"); + this->web_api_cryptoRandomUUID_method = env->GetStaticMethodID(this->web_api_class, "cryptoRandomUUID", "()Ljava/lang/String;"); this->check_exception(env); - this->capacitor_notification_api_class = (jclass)env->NewGlobalRef(tmp_class); - env->DeleteLocalRef(tmp_class); - tmp_class = nullptr; - - this->web_api_byteArrayToString_method = env->GetStaticMethodID(this->web_api_class, "byteArrayToString", "([BLjava/lang/String;)Ljava/lang/String;"); + this->web_api_fetch_method = env->GetStaticMethodID(this->web_api_class, "fetch", "(Ljava/lang/String;Lio/ionic/android_js_engine/NativeJSFetchOptions;)Lio/ionic/android_js_engine/NativeJSResponse;"); this->check_exception(env); - this->web_api_stringToByteArray_method = env->GetStaticMethodID(this->web_api_class, "stringToByteArray", "(Ljava/lang/String;)[B"); + this->native_js_fetch_options_constructor = env->GetMethodID(this->native_js_fetch_options_class, "", "(Ljava/lang/String;Ljava/util/HashMap;[B)V"); this->check_exception(env); - this->web_api_randomHashCode_method = env->GetStaticMethodID(this->web_api_class, "randomHashCode", "()I"); + this->native_js_response_ok_field = env->GetFieldID(this->native_js_response_class, "ok", "Z"); this->check_exception(env); - this->web_api_cryptoGetRandom_method = env->GetStaticMethodID(this->web_api_class, "cryptoGetRandom", "(I)[B"); + this->native_js_response_status_field = env->GetFieldID(this->native_js_response_class, "status", "I"); this->check_exception(env); - this->web_api_cryptoRandomUUID_method = env->GetStaticMethodID(this->web_api_class, "cryptoRandomUUID", "()Ljava/lang/String;"); + this->native_js_response_url_field = env->GetFieldID(this->native_js_response_class, "url", "Ljava/lang/String;"); this->check_exception(env); - this->web_api_fetch_method = env->GetStaticMethodID(this->web_api_class, "fetch", "(Ljava/lang/String;Lio/ionic/android_js_engine/JSFetchOptions;)Lio/ionic/android_js_engine/JSResponse;"); + this->native_js_response_data_field = env->GetFieldID(this->native_js_response_class, "data", "[B"); this->check_exception(env); - this->js_fetch_options_constructor = env->GetMethodID(this->js_fetch_options_class, "", "(Ljava/lang/String;)V"); + this->native_js_response_error_field = env->GetFieldID(this->native_js_response_class, "error", "Ljava/lang/String;"); this->check_exception(env); - this->js_response_ok_field = env->GetFieldID(this->js_response_class, "ok", "Z"); + // Capacitor API + tmp_class = env->FindClass("io/ionic/android_js_engine/NativeCapacitorAPI"); this->check_exception(env); - this->js_response_status_field = env->GetFieldID(this->js_response_class, "status", "I"); - this->check_exception(env); + this->capacitor_api_class = (jclass)env->NewGlobalRef(tmp_class); + env->DeleteLocalRef(tmp_class); + tmp_class = nullptr; - this->js_response_url_field = env->GetFieldID(this->js_response_class, "url", "Ljava/lang/String;"); + tmp_class = env->FindClass("io/ionic/android_js_engine/capacitor_api/KVAPI"); this->check_exception(env); - this->js_response_data_field = env->GetFieldID(this->js_response_class, "data", "[B"); + this->capacitor_kv_api_class = (jclass)env->NewGlobalRef(tmp_class); + env->DeleteLocalRef(tmp_class); + tmp_class = nullptr; + + tmp_class = env->FindClass("io/ionic/android_js_engine/capacitor_api/DeviceAPI"); this->check_exception(env); - this->js_response_error_field = env->GetFieldID(this->js_response_class, "error", "Ljava/lang/String;"); + this->capacitor_device_api_class = (jclass)env->NewGlobalRef(tmp_class); + env->DeleteLocalRef(tmp_class); + tmp_class = nullptr; + + tmp_class = env->FindClass("io/ionic/android_js_engine/capacitor_api/GeolocationAPI"); this->check_exception(env); - this->capacitor_api_kv_field = env->GetFieldID(this->capacitor_api_class, "kv", "Lio/ionic/android_js_engine/api/KVAPI;"); + this->capacitor_geolocation_api_class = (jclass)env->NewGlobalRef(tmp_class); + env->DeleteLocalRef(tmp_class); + tmp_class = nullptr; + + tmp_class = env->FindClass("io/ionic/android_js_engine/capacitor_api/NotificationsAPI"); this->check_exception(env); - this->capacitor_api_device_field = env->GetFieldID(this->capacitor_api_class, "device", "Lio/ionic/android_js_engine/api/DeviceAPI;"); + this->capacitor_notification_api_class = (jclass)env->NewGlobalRef(tmp_class); + env->DeleteLocalRef(tmp_class); + tmp_class = nullptr; + + this->capacitor_api_kv_field = env->GetFieldID(this->capacitor_api_class, "kv", "Lio/ionic/android_js_engine/capacitor_api/KVAPI;"); this->check_exception(env); - this->capacitor_api_geolocation_field = env->GetFieldID(this->capacitor_api_class, "geolocation", "Lio/ionic/android_js_engine/api/GeolocationAPI;"); + this->capacitor_api_device_field = env->GetFieldID(this->capacitor_api_class, "device", "Lio/ionic/android_js_engine/capacitor_api/DeviceAPI;"); this->check_exception(env); - this->capacitor_api_notification_field = env->GetFieldID(this->capacitor_api_class, "notifications", "Lio/ionic/android_js_engine/api/NotificationsAPI;"); + this->capacitor_api_geolocation_field = env->GetFieldID(this->capacitor_api_class, "geolocation", "Lio/ionic/android_js_engine/capacitor_api/GeolocationAPI;"); this->check_exception(env); - // Capacitor API + this->capacitor_api_notification_field = env->GetFieldID(this->capacitor_api_class, "notifications", "Lio/ionic/android_js_engine/capacitor_api/NotificationsAPI;"); + this->check_exception(env); this->capacitor_api_kv_set_method = env->GetMethodID(this->capacitor_kv_api_class, "set", "(Ljava/lang/String;Ljava/lang/String;)V"); this->check_exception(env); @@ -143,13 +142,11 @@ JNIEnv *Java::getEnv() { int status = this->vm->GetEnv((void **)&env, JNI_VERSION_1_6); if (status == JNI_EDETACHED) { if (this->vm->AttachCurrentThread(&env, NULL) != JNI_OK) { - // TODO: throw exception here return nullptr; } } if (status == JNI_EVERSION) { - // TODO: throw exception here return nullptr; } @@ -174,4 +171,4 @@ void Java::check_exception(JNIEnv *env) { const auto *c_err_msg = env->GetStringUTFChars(err_msg, nullptr); throw std::runtime_error(c_err_msg); -} +} \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/java.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java.h similarity index 72% rename from packages/android-engine/android-js-engine/src/main/cpp/java.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/java.h index 89382941..d0075252 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/java.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java.h @@ -1,5 +1,5 @@ -#ifndef CAPACITOR_BACKGROUND_RUNNER_JAVA_H -#define CAPACITOR_BACKGROUND_RUNNER_JAVA_H +#ifndef ANDROID_JS_ENGINE_JAVA_H +#define ANDROID_JS_ENGINE_JAVA_H #include @@ -8,8 +8,9 @@ class Java { JavaVM *vm; jclass web_api_class; - jclass js_response_class; - jclass js_fetch_options_class; + jclass native_js_response_class; + jclass native_js_fetch_options_class; + jclass capacitor_api_class; jclass capacitor_kv_api_class; jclass capacitor_notification_api_class; @@ -22,7 +23,8 @@ class Java { jmethodID web_api_randomHashCode_method; jmethodID web_api_cryptoRandomUUID_method; jmethodID web_api_cryptoGetRandom_method; - jmethodID js_fetch_options_constructor; + jmethodID native_js_fetch_options_constructor; + jmethodID capacitor_api_kv_set_method; jmethodID capacitor_api_kv_get_method; jmethodID capacitor_api_kv_remove_method; @@ -31,11 +33,12 @@ class Java { jmethodID capacitor_api_geolocation_getCurrentPosition_method; jmethodID capacitor_api_notifications_schedule_method; - jfieldID js_response_ok_field; - jfieldID js_response_status_field; - jfieldID js_response_url_field; - jfieldID js_response_data_field; - jfieldID js_response_error_field; + jfieldID native_js_response_ok_field; + jfieldID native_js_response_status_field; + jfieldID native_js_response_url_field; + jfieldID native_js_response_data_field; + jfieldID native_js_response_error_field; + jfieldID capacitor_api_kv_field; jfieldID capacitor_api_device_field; jfieldID capacitor_api_notification_field; @@ -43,9 +46,9 @@ class Java { Java(JNIEnv *env); JNIEnv *getEnv(); - private: void check_exception(JNIEnv *env); }; -#endif //CAPACITOR_BACKGROUND_RUNNER_JAVA_H + +#endif //ANDROID_JS_ENGINE_JAVA_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java_errors.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java_errors.cpp new file mode 100644 index 00000000..5e50040a --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java_errors.cpp @@ -0,0 +1,40 @@ +#import "java_errors.h" + +NativeInterfaceException *get_jvm_exception(JNIEnv *env) { + if (!env->ExceptionCheck()) { + return nullptr; + } + + auto *throwable = env->ExceptionOccurred(); + env->ExceptionClear(); + + jclass exception_class = env->FindClass("java/lang/Exception"); + jmethodID exception_constructor = env->GetMethodID(exception_class, "", "(Ljava/lang/Throwable;)V"); + jmethodID get_message_method = env->GetMethodID(exception_class, "getMessage", "()Ljava/lang/String;"); + + auto *err_obj = env->NewObject(exception_class, exception_constructor, throwable); + auto *err_msg = (jstring)env->CallObjectMethod(err_obj, get_message_method); + + const auto *err_message_c_str = env->GetStringUTFChars(err_msg, nullptr); + + return new NativeInterfaceException(err_message_c_str); +} + +bool throw_js_error_in_jvm(JNIEnv *env, JSContext *ctx, JSValue value) { + if (!JS_IsError(ctx, value) && !JS_IsException(value)) { + return false; + } + + jclass error_class = env->FindClass("io/ionic/android_js_engine/EngineErrors$JavaScriptException"); + + JSValue const err_message = JS_GetPropertyStr(ctx, value, "message"); + const char *err_message_c_str = JS_ToCString(ctx, err_message); + + env->ThrowNew(error_class, err_message_c_str); + + JS_FreeCString(ctx, err_message_c_str); + JS_FreeValue(ctx, err_message); + JS_FreeValue(ctx, value); + + return true; +} diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java_errors.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java_errors.h new file mode 100644 index 00000000..c870b5d1 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/java_errors.h @@ -0,0 +1,11 @@ +#ifndef ANDROID_JS_ENGINE_JAVA_ERRORS_H +#define ANDROID_JS_ENGINE_JAVA_ERRORS_H + +#include +#include "js-engine/src/quickjs/quickjs.h" +#include "js-engine/src/errors.hpp" + +NativeInterfaceException* get_jvm_exception(JNIEnv *env); +bool throw_js_error_in_jvm(JNIEnv *env, JSContext *ctx, JSValue value); + +#endif //ANDROID_JS_ENGINE_JAVA_ERRORS_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.clang-format b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.clang-format new file mode 100644 index 00000000..389f2740 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.clang-format @@ -0,0 +1,169 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 240 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +... + + + + + + + + + + + + + + diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.clang-tidy b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.clang-tidy new file mode 100644 index 00000000..804f5c14 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.clang-tidy @@ -0,0 +1 @@ +Checks: '*, -android-*, -bugprone-bool-pointer-implicit-conversion, -bugprone-exception-escape, -cert-dcl16-c, -cert-dcl50-cpp, -cert-dcl59-cpp, -cert-env33-c, -clang-analyzer-*, -clang-diagnostic-*, -cppcoreguidelines-avoid-c-arrays, -cppcoreguidelines-avoid-goto, -cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-macro-usage, -cppcoreguidelines-no-malloc, -cppcoreguidelines-non-private-member-variables-in-classes, -cppcoreguidelines-owning-memory, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-bounds-constant-array-index, -cppcoreguidelines-pro-bounds-pointer-arithmetic, -cppcoreguidelines-pro-type-const-cast, -cppcoreguidelines-pro-type-cstyle-cast, -cppcoreguidelines-pro-type-reinterpret-cast, -cppcoreguidelines-pro-type-union-access, -cppcoreguidelines-pro-type-vararg, -cppcoreguidelines-special-member-functions, -fuchsia-*, -google-*, -hicpp-avoid-c-arrays, -hicpp-avoid-goto, -hicpp-braces-around-statements, -hicpp-function-size, -hicpp-named-parameter, -hicpp-no-array-decay, -hicpp-no-assembler, -hicpp-no-malloc, -hicpp-special-member-functions, -hicpp-uppercase-literal-suffix, -hicpp-vararg, -llvm-*, -misc-bool-pointer-implicit-conversion, -misc-definitions-in-headers, -misc-non-private-member-variables-in-classes, -misc-unused-alias-decls, -misc-unused-parameters, -misc-unused-using-decls, -modernize-avoid-c-arrays, -modernize-use-default-member-init, -modernize-use-trailing-return-type, -modernize-use-using, -objc-*, -openmp-exception-escape, -readability-braces-around-statements, -readability-convert-member-functions-to-static, -readability-else-after-return, -readability-function-size, -readability-identifier-naming, -readability-implicit-bool-conversion, -readability-isolate-declaration, -readability-magic-numbers, -readability-named-parameter, -readability-redundant-member-init, -readability-redundant-preprocessor, -readability-simplify-boolean-expr, -readability-uppercase-literal-suffix, -zircon-*, google-default-arguments, google-explicit-constructor, google-runtime-operator, -llvmlibc-*' \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.gitignore b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.gitignore new file mode 100644 index 00000000..3a820eb1 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.gitignore @@ -0,0 +1,18 @@ +.DS_Store + +build/* +build_iOS/* +vcpkg_installed + +*.moved-aside +*.xcuserstate + +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/.gitignore b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/.name b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/.name new file mode 100644 index 00000000..2db745b8 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/.name @@ -0,0 +1 @@ +JSEngine \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/codeStyles/Project.xml b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..f6038816 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/codeStyles/Project.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/codeStyles/codeStyleConfig.xml b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..79ee123c --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/misc.xml b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/misc.xml new file mode 100644 index 00000000..79b3c948 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/modules.xml b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/modules.xml new file mode 100644 index 00000000..0a527c00 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/vcs.xml b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/vcs.xml new file mode 100644 index 00000000..09141479 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.idea/vcs.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.vscode/launch.json b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.vscode/launch.json new file mode 100644 index 00000000..ac567057 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.vscode/launch.json @@ -0,0 +1,34 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Runner Tests", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/tests/EngineTests", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "lldb" + //"preLaunchTask": "C/C++: clang++ build active file" + }, + { + "name": "Context Tests", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/tests/ContextTests", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "lldb" + //"preLaunchTask": "C/C++: clang++ build active file" + } + ] +} diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.vscode/settings.json b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.vscode/settings.json new file mode 100644 index 00000000..50df1c97 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/.vscode/settings.json @@ -0,0 +1,89 @@ +{ + "editor.formatOnSave": true, + "files.associations": { + "*.module": "php", + "unordered_map": "cpp", + "fstream": "cpp", + "future": "cpp", + "regex": "cpp", + "string": "cpp", + "vector": "cpp", + "map": "cpp", + "ostream": "cpp", + "set": "cpp", + "sstream": "cpp", + "stack": "cpp", + "__config": "cpp", + "__debug": "cpp", + "array": "cpp", + "atomic": "cpp", + "cctype": "cpp", + "cmath": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "deque": "cpp", + "exception": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "optional": "cpp", + "ratio": "cpp", + "stdexcept": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "typeinfo": "cpp", + "variant": "cpp", + "__bit_reference": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__node_handle": "cpp", + "__split_buffer": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__verbose_abort": "cpp", + "bitset": "cpp", + "charconv": "cpp", + "clocale": "cpp", + "complex": "cpp", + "cstdarg": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "execution": "cpp", + "ios": "cpp", + "istream": "cpp", + "list": "cpp", + "locale": "cpp", + "streambuf": "cpp", + "algorithm": "cpp", + "__errc": "cpp", + "__mutex_base": "cpp", + "__std_stream": "cpp", + "any": "cpp", + "forward_list": "cpp", + "queue": "cpp", + "span": "cpp", + "typeindex": "cpp", + "valarray": "cpp", + "codecvt": "cpp", + "condition_variable": "cpp", + "csignal": "cpp", + "shared_mutex": "cpp", + "source_location": "cpp", + "strstream": "cpp", + "unordered_set": "cpp", + "*.ipp": "cpp" + }, + "cmake.configureSettings": { + "CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + } +} diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/CMakeLists.txt b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/CMakeLists.txt new file mode 100644 index 00000000..b3e92bc6 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.22.1) + +project("JSEngine") + +add_library( + ${PROJECT_NAME} + SHARED + src/context.cpp + src/runner.cpp + src/errors.cpp + src/api/api_console.cpp + src/api/api_events.cpp + src/api/api_timeout.cpp + src/api/api_js_response.cpp + src/api/api_blob.cpp + src/api/api_fetch.cpp + src/api/api_crypto.cpp + src/api/api_text.cpp + src/capacitor-api/api_device.cpp + src/capacitor-api/api_geolocation.cpp + src/capacitor-api/api_kv.cpp + src/capacitor-api/api_notifications.cpp + +) + +add_subdirectory("src/quickjs") + +target_link_libraries(${PROJECT_NAME} quickjs) + +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) + +#enable_testing() +#add_subdirectory("tests") diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/CMakePresets.json b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/CMakePresets.json new file mode 100644 index 00000000..8fbb92dc --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/CMakePresets.json @@ -0,0 +1,15 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "default", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "CMAKE_CXX_COMPILER": "/opt/homebrew/opt/llvm/bin/clang++", + "CMAKE_C_COMPILER": "/opt/homebrew/opt/llvm/bin/clang" + } + } + ] +} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_blob.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_blob.cpp similarity index 77% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_blob.cpp rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_blob.cpp index e9dc6a73..d49f7752 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_blob.cpp +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_blob.cpp @@ -1,7 +1,7 @@ #include "api_blob.h" -#include "../context.h" -#include "../errors.h" +#include "../context.hpp" +#include "../errors.hpp" #include "../quickjs/cutils.h" struct blob_data { @@ -23,7 +23,8 @@ static JSClassDef js_blob_class = {"Blob", .finalizer = js_blob_data_finalizer}; static JSValue api_blob_get_array_buffer(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { auto *blob = (blob_data *)JS_GetOpaque(this_val, js_blob_class_id); if (blob == nullptr) { - return throw_js_exception(ctx, "backing data is null"); + auto js_error = create_js_error("backing data is null", ctx); + return JS_Throw(ctx, js_error); } auto array_buffer = JS_NewArrayBuffer(ctx, blob->data, blob->size, nullptr, nullptr, 0); @@ -37,29 +38,19 @@ static JSValue api_blob_get_array_buffer(JSContext *ctx, JSValueConst this_val, static JSValue api_blob_get_text(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { auto *blob = (blob_data *)JS_GetOpaque(this_val, js_blob_class_id); if (blob == nullptr) { - return throw_js_exception(ctx, "backing data is null"); + auto js_error = create_js_error("backing data is null", ctx); + return JS_Throw(ctx, js_error); } auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - if (env == nullptr) { - return throw_js_exception(ctx, "JVM Environment is null"); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); } - jstring encoding = env->NewStringUTF("utf-8"); - jbyteArray j_byte_array = env->NewByteArray(blob->size); - - env->SetByteArrayRegion(j_byte_array, 0, blob->size, reinterpret_cast(blob->data)); - - auto *text_string = (jstring)env->CallStaticObjectMethod(context->java->web_api_class, context->java->web_api_byteArrayToString_method, j_byte_array, encoding); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - const char *text_c_string = env->GetStringUTFChars(text_string, nullptr); - - return JS_NewString(ctx, text_c_string); + // TODO handle exception + auto text_string = context->native_interface->byte_array_to_str(blob->data, 0, "utf-8").c_str(); + return JS_NewString(ctx, text_string); } static const JSCFunctionListEntry js_blob_proto_funcs[] = { diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_blob.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_blob.h similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_blob.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_blob.h diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_console.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_console.cpp similarity index 70% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_console.cpp rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_console.cpp index c0a77296..45770781 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_console.cpp +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_console.cpp @@ -1,8 +1,6 @@ #include "api_console.h" -#include "../context.h" - -void write_to_logcat(android_LogPriority priority, const char *tag, const char *message) { __android_log_write(priority, tag, message); } +#include "../context.hpp" JSValue api_console_log(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { int i; @@ -10,7 +8,12 @@ JSValue api_console_log(JSContext *ctx, JSValueConst this_val, int argc, JSValue size_t len; auto *parent_ctx = (Context *)JS_GetContextOpaque(ctx); - std::string const tag = "[Runner Context " + parent_ctx->name + "]"; + if (parent_ctx == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } + + std::string const tag = "Runner Context " + parent_ctx->name; for (i = 0; i < argc; i++) { str = JS_ToCStringLen(ctx, &len, argv[i]); @@ -18,7 +21,7 @@ JSValue api_console_log(JSContext *ctx, JSValueConst this_val, int argc, JSValue return JS_EXCEPTION; } - write_to_logcat(ANDROID_LOG_INFO, tag.c_str(), str); + parent_ctx->native_interface->logger(INFO, tag, str); JS_FreeCString(ctx, str); } @@ -32,7 +35,7 @@ JSValue api_console_warn(JSContext *ctx, JSValueConst this_val, int argc, JSValu size_t len; auto *parent_ctx = (Context *)JS_GetContextOpaque(ctx); - std::string const tag = "[Runner Context " + parent_ctx->name + "]"; + std::string const tag = "Runner Context " + parent_ctx->name; for (i = 0; i < argc; i++) { str = JS_ToCStringLen(ctx, &len, argv[i]); @@ -40,7 +43,7 @@ JSValue api_console_warn(JSContext *ctx, JSValueConst this_val, int argc, JSValu return JS_EXCEPTION; } - write_to_logcat(ANDROID_LOG_WARN, tag.c_str(), str); + parent_ctx->native_interface->logger(WARN, tag, str); JS_FreeCString(ctx, str); } @@ -54,7 +57,7 @@ JSValue api_console_error(JSContext *ctx, JSValueConst this_val, int argc, JSVal size_t len; auto *parent_ctx = (Context *)JS_GetContextOpaque(ctx); - std::string const tag = "[Runner Context " + parent_ctx->name + "]"; + std::string const tag = "Runner Context " + parent_ctx->name; for (i = 0; i < argc; i++) { str = JS_ToCStringLen(ctx, &len, argv[i]); @@ -62,7 +65,7 @@ JSValue api_console_error(JSContext *ctx, JSValueConst this_val, int argc, JSVal return JS_EXCEPTION; } - write_to_logcat(ANDROID_LOG_ERROR, tag.c_str(), str); + parent_ctx->native_interface->logger(ERROR, tag, str); JS_FreeCString(ctx, str); } @@ -76,7 +79,7 @@ JSValue api_console_debug(JSContext *ctx, JSValueConst this_val, int argc, JSVal size_t len; auto *parent_ctx = (Context *)JS_GetContextOpaque(ctx); - std::string const tag = "[Runner Context " + parent_ctx->name + "]"; + std::string const tag = "Runner Context " + parent_ctx->name; for (i = 0; i < argc; i++) { str = JS_ToCStringLen(ctx, &len, argv[i]); @@ -84,7 +87,7 @@ JSValue api_console_debug(JSContext *ctx, JSValueConst this_val, int argc, JSVal return JS_EXCEPTION; } - write_to_logcat(ANDROID_LOG_DEBUG, tag.c_str(), str); + parent_ctx->native_interface->logger(DEBUG, tag, str); JS_FreeCString(ctx, str); } diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_console.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_console.h similarity index 83% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_console.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_console.h index 1965709c..d4a9f3a0 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_console.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_console.h @@ -1,11 +1,9 @@ #ifndef CAPACITOR_BACKGROUND_RUNNER_API_CONSOLE_H #define CAPACITOR_BACKGROUND_RUNNER_API_CONSOLE_H -#include +#include "../native.hpp" #include "../quickjs/quickjs.h" -void write_to_logcat(android_LogPriority priority, const char *tag, const char *message); - JSValue api_console_log(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); JSValue api_console_warn(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); JSValue api_console_error(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_crypto.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_crypto.cpp new file mode 100644 index 00000000..3429f2e0 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_crypto.cpp @@ -0,0 +1,59 @@ +#include "api_crypto.h" + +#include "../context.hpp" +#include "../errors.hpp" + +JSValue api_crypto_get_random_values(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + uint8_t *buf; + size_t elem, len, offset, buf_size; + int size; + + auto t_arr_buf = JS_GetTypedArrayBuffer(ctx, argv[0], &offset, &len, &elem); + buf = JS_GetArrayBuffer(ctx, &buf_size, t_arr_buf); + + if (!buf) { + return JS_EXCEPTION; + } + + size = buf_size; + + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("parent context is null", ctx); + return JS_Throw(ctx, js_error); + } + + try { + auto random_bytes = context->native_interface->crypto_get_random(size); + + for (int i = 0; i < size; i++) { + buf[i] = random_bytes[i]; + } + + JS_FreeValue(ctx, t_arr_buf); + + return JS_DupValue(ctx, argv[0]); + } catch (std::exception &ex) { + JS_FreeValue(ctx, t_arr_buf); + + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } +} + +JSValue api_crypto_random_uuid(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("parent context is null", ctx); + return JS_Throw(ctx, js_error); + } + + try { + auto uuid_string = context->native_interface->crypto_get_random_uuid(); + auto ret_value = JS_NewString(ctx, uuid_string.c_str()); + return ret_value; + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } +} \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_crypto.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_crypto.h similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_crypto.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_crypto.h diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_events.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_events.cpp similarity index 81% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_events.cpp rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_events.cpp index 8747ed29..d9a32eed 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_events.cpp +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_events.cpp @@ -1,6 +1,6 @@ #include "api_events.h" -#include "../context.h" +#include "../context.hpp" JSValue api_add_event_listener(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { const char *event = JS_ToCString(ctx, argv[0]); @@ -14,6 +14,11 @@ JSValue api_add_event_listener(JSContext *ctx, JSValueConst this_val, int argc, callback = JS_DupValue(ctx, callback); auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } + auto itr = context->event_listeners.find(event); if (itr == context->event_listeners.end()) { diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_events.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_events.h similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_events.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_events.h diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_fetch.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_fetch.cpp new file mode 100644 index 00000000..174c1d87 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_fetch.cpp @@ -0,0 +1,159 @@ +#include "api_fetch.h" + +#include +#include + +#include "../context.hpp" +#include "../errors.hpp" + +std::vector js_body_to_data(JSContext *ctx, JSValue body) { + std::vector data; + + if (JS_IsNull(body) || JS_IsUndefined(body) || !JS_IsString(body)) { + return data; + } + + const char *c_body = JS_ToCString(ctx, body); + auto str = std::string(c_body); + auto str_data = str.data(); + + data = std::vector(&str_data[0], &str_data[str.length()]); + + JS_FreeCString(ctx, c_body); + + return data; +} + +std::unordered_map js_header_to_map(JSContext *ctx, JSValue header) { + std::unordered_map header_map; + + if (JS_IsNull(header) || JS_IsUndefined(header) || !JS_IsObject(header)) { + return header_map; + } + + JSPropertyEnum *properties; + uint32_t count; + JS_GetOwnPropertyNames(ctx, &properties, &count, header, JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY); + for (uint32_t i = 0; i < count; i++) { + JSAtom atom = properties[i].atom; + const char *key = JS_AtomToCString(ctx, atom); + JSValue val = JS_GetProperty(ctx, header, atom); + if (JS_IsString(val)) { + const char *c_str_val = JS_ToCString(ctx, val); + header_map[std::string(key)] = std::string(c_str_val); + JS_FreeCString(ctx, c_str_val); + } + + JS_FreeValue(ctx, val); + JS_FreeAtom(ctx, atom); + JS_FreeCString(ctx, key); + } + + return header_map; +} + +JSValue js_fetch_job(JSContext *ctx, int argc, JSValueConst *argv) { + JSValue resolve, reject, request, options; + + resolve = argv[0]; + reject = argv[1]; + request = argv[2]; + options = argv[3]; + + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("parent context is null", ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); + return JS_UNDEFINED; + } + + if (JS_IsNull(request) || !JS_IsString(request)) { + auto js_error = create_js_error("invalid url", ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); + return JS_UNDEFINED; + } + + const auto *c_url_str = JS_ToCString(ctx, request); + + NativeRequest native_request; + native_request.url = std::string(c_url_str); + + JS_FreeCString(ctx, c_url_str); + + context->native_interface->logger(LoggerLevel::DEBUG, "FETCH", native_request.url); + + if (!JS_IsNull(options) && !JS_IsUndefined(options)) { + JSValue method, body, headers; + + method = JS_GetPropertyStr(ctx, options, "method"); + body = JS_GetPropertyStr(ctx, options, "body"); + headers = JS_GetPropertyStr(ctx, options, "headers"); + + native_request.method = std::string(JS_ToCString(ctx, method)); + native_request.headers = js_header_to_map(ctx, headers); + native_request.body = js_body_to_data(ctx, body); + + JS_FreeValue(ctx, method); + JS_FreeValue(ctx, body); + JS_FreeValue(ctx, headers); + } else { + native_request.method = "GET"; + } + + NativeResponse response; + + try { + response = context->native_interface->fetch(native_request); + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); + return JS_UNDEFINED; + } + + if (!response.ok) { + auto js_error = create_js_error(response.error.c_str(), ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); + return JS_UNDEFINED; + } + + auto js_response = new_js_response(ctx, response); + + auto global_obj = JS_GetGlobalObject(ctx); + JSValueConst resolve_args[1]; + resolve_args[0] = js_response; + + JS_Call(ctx, resolve, global_obj, 1, resolve_args); + + JS_FreeValue(ctx, js_response); + JS_FreeValue(ctx, global_obj); + + return JS_UNDEFINED; +} + +JSValue api_fetch(JSContext *ctx, JSValueConst this_val, int argc, JSValue *argv) { + JSValue promise, resolving_funcs[2]; + JSValueConst args[4]; + + promise = JS_NewPromiseCapability(ctx, resolving_funcs); + if (JS_IsException(promise)) { + return promise; + } + + args[0] = resolving_funcs[0]; + args[1] = resolving_funcs[1]; + args[2] = JS_DupValue(ctx, argv[0]); + args[3] = JS_DupValue(ctx, argv[1]); + + JS_EnqueueJob(ctx, js_fetch_job, 4, args); + + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + JS_FreeValue(ctx, argv[0]); + JS_FreeValue(ctx, argv[1]); + + return promise; +} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_fetch.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_fetch.h similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_fetch.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_fetch.h diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_js_response.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_js_response.cpp similarity index 54% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_js_response.cpp rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_js_response.cpp index d6364e82..0bdd36d6 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_js_response.cpp +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_js_response.cpp @@ -1,11 +1,11 @@ #include "api_js_response.h" -#include "../context.h" -#include "../errors.h" +#include "../context.hpp" +#include "../errors.hpp" #include "../quickjs/cutils.h" struct response_data { - uint8_t *data; + std::vector data; size_t size; }; @@ -20,52 +20,42 @@ JSValue js_response_json_job(JSContext *ctx, int argc, JSValueConst *argv) { auto *data = (response_data *)JS_GetOpaque(response, js_response_class_id); if (data == nullptr) { - auto exception = throw_js_exception(ctx, "backing data is null"); - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); + auto js_error = create_js_error("backing data is null", ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); return JS_UNDEFINED; } auto *context = (Context *)JS_GetContextOpaque(ctx); - - auto *env = context->java->getEnv(); - if (env == nullptr) { - auto exception = throw_js_exception(ctx, "JVM Environment is null"); - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); - return JS_UNDEFINED; + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); } - jstring encoding = env->NewStringUTF("utf-8"); - jbyteArray j_byte_array = env->NewByteArray(data->size); - - env->SetByteArrayRegion(j_byte_array, 0, data->size, reinterpret_cast(data->data)); + try { + auto json_string = context->native_interface->byte_array_to_str(data->data.data(), data->data.size(), "utf-8"); - auto json_string = (jstring)env->CallStaticObjectMethod(context->java->web_api_class, context->java->web_api_byteArrayToString_method, j_byte_array, encoding); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); - return JS_UNDEFINED; - } + auto global_obj = JS_GetGlobalObject(ctx); - const char *json_c_string = env->GetStringUTFChars(json_string, nullptr); + if (!json_string.empty()) { + auto json = JS_ParseJSON(ctx, json_string.c_str(), strlen(json_string.c_str()), ""); + auto res = JS_Call(ctx, resolve, global_obj, 1, (JSValueConst *)&json); + JS_FreeValue(ctx, res); + JS_FreeValue(ctx, json); + } else { + auto res = JS_Call(ctx, resolve, global_obj, 0, nullptr); + JS_FreeValue(ctx, res); + } - auto global_obj = JS_GetGlobalObject(ctx); + JS_FreeValue(ctx, global_obj); - if (json_c_string != nullptr && strlen(json_c_string) > 0) { - auto json = JS_ParseJSON(ctx, json_c_string, strlen(json_c_string), ""); - auto res = JS_Call(ctx, resolve, global_obj, 1, (JSValueConst *)&json); - JS_FreeValue(ctx, res); - JS_FreeValue(ctx, json); - } else { - auto res = JS_Call(ctx, resolve, global_obj, 0, nullptr); - JS_FreeValue(ctx, res); + return JS_UNDEFINED; + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); + return JS_UNDEFINED; } - - JS_FreeValue(ctx, global_obj); - - return JS_UNDEFINED; } JSValue js_response_text_job(JSContext *ctx, int argc, JSValueConst *argv) { @@ -77,48 +67,35 @@ JSValue js_response_text_job(JSContext *ctx, int argc, JSValueConst *argv) { auto *data = (response_data *)JS_GetOpaque(response, js_response_class_id); if (data == nullptr) { - auto exception = throw_js_exception(ctx, "backing data is null"); - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); + auto js_error = create_js_error("backing data is null", ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); return JS_UNDEFINED; } auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - if (env == nullptr) { - auto exception = throw_js_exception(ctx, "JVM Environment is null"); - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); - return JS_UNDEFINED; - } - - jstring encoding = env->NewStringUTF("utf-8"); - jbyteArray j_byte_array = env->NewByteArray(data->size); + try { + auto text_string = context->native_interface->byte_array_to_str(data->data.data(), data->data.size(), "utf-8"); - env->SetByteArrayRegion(j_byte_array, 0, data->size, reinterpret_cast(data->data)); + auto text = JS_NewString(ctx, text_string.c_str()); - auto text_string = (jstring)env->CallStaticObjectMethod(context->java->web_api_class, context->java->web_api_byteArrayToString_method, j_byte_array, encoding); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); - return JS_UNDEFINED; - } + JSValueConst resolve_args[1]; + resolve_args[0] = text; - const char *text_c_string = env->GetStringUTFChars(text_string, nullptr); - auto text = JS_NewString(ctx, text_c_string); + auto global_obj = JS_GetGlobalObject(ctx); + JS_Call(ctx, resolve, global_obj, 1, resolve_args); - JSValueConst resolve_args[1]; - resolve_args[0] = text; + JS_FreeValue(ctx, text); + JS_FreeValue(ctx, global_obj); - auto global_obj = JS_GetGlobalObject(ctx); - JS_Call(ctx, resolve, global_obj, 1, resolve_args); - - JS_FreeValue(ctx, text); - JS_FreeValue(ctx, global_obj); - - return JS_UNDEFINED; + return JS_UNDEFINED; + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); + return JS_UNDEFINED; + } } JSValue js_response_array_buffer_job(JSContext *ctx, int argc, JSValueConst *argv) { @@ -130,13 +107,13 @@ JSValue js_response_array_buffer_job(JSContext *ctx, int argc, JSValueConst *arg auto *data = (response_data *)JS_GetOpaque(response, js_response_class_id); if (data == nullptr) { - auto exception = throw_js_exception(ctx, "backing data is null"); - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); + auto js_error = create_js_error("backing data is null", ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); return JS_UNDEFINED; } - auto array_buffer = JS_NewArrayBuffer(ctx, data->data, data->size, nullptr, nullptr, 0); + auto array_buffer = JS_NewArrayBuffer(ctx, data->data.data(), data->size, nullptr, nullptr, 0); auto buf = JS_NewUInt8Array(ctx, array_buffer, 0, data->size); auto global_obj = JS_GetGlobalObject(ctx); @@ -159,13 +136,13 @@ JSValue js_response_blob_job(JSContext *ctx, int argc, JSValueConst *argv) { auto *data = (response_data *)JS_GetOpaque(response, js_response_class_id); if (data == nullptr) { - auto exception = throw_js_exception(ctx, "backing data is null"); - reject_promise(ctx, reject, exception); - JS_FreeValue(ctx, exception); + auto js_error = create_js_error("backing data is null", ctx); + reject_promise(ctx, reject, js_error); + JS_FreeValue(ctx, js_error); return JS_UNDEFINED; } - auto blob = new_blob(ctx, data->data, data->size); + auto blob = new_blob(ctx, data->data.data(), data->size); auto global_obj = JS_GetGlobalObject(ctx); auto res = JS_Call(ctx, resolve, global_obj, 1, (JSValueConst *)&blob); @@ -286,57 +263,32 @@ static JSValue api_response_constructor(JSContext *ctx, JSValueConst new_target, return new_object; } -JSValue new_js_response(JSContext *ctx, jobject j_response) { - auto *context = (Context *)JS_GetContextOpaque(ctx); +JSValue new_js_response(JSContext *ctx, NativeResponse native_response) { + // auto *context = (Context *)JS_GetContextOpaque(ctx); - auto *env = context->java->getEnv(); - if (env == nullptr) { - return throw_js_exception(ctx, "JVM Environment is null"); - } - - auto j_ok = env->GetBooleanField(j_response, context->java->js_response_ok_field); - auto j_status = env->GetIntField(j_response, context->java->js_response_status_field); - auto *j_url = (jstring)env->GetObjectField(j_response, context->java->js_response_url_field); - auto *j_data = static_cast(env->GetObjectField(j_response, context->java->js_response_data_field)); - auto *j_err = (jstring)env->GetObjectField(j_response, context->java->js_response_error_field); - - const auto *c_url = env->GetStringUTFChars(j_url, nullptr); + // auto *j_data = static_cast(env->GetObjectField(j_response, context->java->js_response_data_field)); auto response = api_response_constructor(ctx, JS_UNDEFINED, 0, nullptr); - JS_SetPropertyStr(ctx, response, "ok", JS_NewBool(ctx, (int)j_ok)); - JS_SetPropertyStr(ctx, response, "status", JS_NewInt32(ctx, (int)j_status)); - JS_SetPropertyStr(ctx, response, "url", JS_NewString(ctx, c_url)); - JS_SetPropertyStr(ctx, response, "error", JS_NULL); - - if (j_data != nullptr) { - auto j_data_len = env->GetArrayLength(j_data); - auto *j_data_arr = env->GetByteArrayElements(j_data, 0); + JS_DefinePropertyValueStr(ctx, response, "ok", JS_NewBool(ctx, native_response.ok), JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, response, "status", JS_NewInt32(ctx, native_response.status), JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, response, "url", JS_NewString(ctx, native_response.url.c_str()), JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, response, "error", JS_NULL, JS_PROP_C_W_E); - auto *buf = new uint8_t(j_data_len); + if (!native_response.data.empty()) { + auto data = native_response.data.data(); - for (int i = 0; i < j_data_len; i++) { - buf[i] = j_data_arr[i]; - } - - env->ReleaseByteArrayElements(j_data, j_data_arr, 0); - - // attach the array buffer to the js_response auto *res_data = new response_data; - res_data->data = buf; - res_data->size = j_data_len; + res_data->data = native_response.data; + res_data->size = native_response.data.size(); JS_SetOpaque(response, res_data); } - if (j_err != nullptr) { - const auto *c_err = env->GetStringUTFChars(j_err, nullptr); - JS_SetPropertyStr(ctx, response, "error", JS_NewString(ctx, c_err)); - env->ReleaseStringUTFChars(j_err, c_err); + if (!native_response.error.empty()) { + JS_DefinePropertyValueStr(ctx, response, "error", JS_NewString(ctx, native_response.error.c_str()), JS_PROP_C_W_E); } - env->ReleaseStringUTFChars(j_url, c_url); - return response; } diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_js_response.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_js_response.h similarity index 57% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_js_response.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_js_response.h index 47767e8f..570a9744 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_js_response.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_js_response.h @@ -1,11 +1,11 @@ #ifndef CAPACITOR_BACKGROUND_RUNNER_API_JS_RESPONSE_H #define CAPACITOR_BACKGROUND_RUNNER_API_JS_RESPONSE_H +#include "../native.hpp" #include "../quickjs/quickjs.h" -#include #include "api_blob.h" void init_response_class(JSContext *ctx); -JSValue new_js_response(JSContext *ctx, jobject j_response); +JSValue new_js_response(JSContext *ctx, NativeResponse native_response); -#endif //CAPACITOR_BACKGROUND_RUNNER_API_JS_RESPONSE_H +#endif // CAPACITOR_BACKGROUND_RUNNER_API_JS_RESPONSE_H diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_text.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_text.cpp similarity index 64% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_text.cpp rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_text.cpp index dcb9f564..aac4241c 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_text.cpp +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_text.cpp @@ -1,7 +1,7 @@ #include "api_text.h" -#include "../context.h" -#include "../errors.h" +#include "../context.hpp" +#include "../errors.hpp" #include "../quickjs/cutils.h" static JSClassID js_text_encoder_class_id; @@ -48,51 +48,42 @@ static JSValue api_text_decoder_constructor(JSContext *ctx, JSValueConst new_tar } static JSValue api_text_encoder_encode(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - uint8_t *buf; - if (!JS_IsString(argv[0])) { return JS_EXCEPTION; } auto *context = (Context *)JS_GetContextOpaque(ctx); - - auto *env = context->java->getEnv(); - if (env == nullptr) { - return throw_js_exception(ctx, "JVM Environment is null"); + if (context == nullptr) { + auto js_error = create_js_error("parent context is null", ctx); + return JS_Throw(ctx, js_error); } - const auto *c_str = JS_ToCString(ctx, argv[0]); - jstring j_string = env->NewStringUTF(c_str); - - auto *byte_array = static_cast(env->CallStaticObjectMethod(context->java->web_api_class, context->java->web_api_stringToByteArray_method, j_string)); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - JS_FreeCString(ctx, c_str); - return exception; - } + try { + const auto *c_str = JS_ToCString(ctx, argv[0]); + auto byte_array = context->native_interface->string_to_byte_array(std::string(c_str)); - auto length = env->GetArrayLength(byte_array); - auto arr = env->GetByteArrayElements(byte_array, 0); - buf = new uint8_t(length); + uint8_t *buf = new uint8_t[byte_array.size()]; - for (int i = 0; i < length; i++) { - buf[i] = arr[i]; - } + for (int i = 0; i < byte_array.size(); i++) { + buf[i] = byte_array.at(i); + } - auto array_buffer = JS_NewArrayBuffer(ctx, buf, length, nullptr, nullptr, 0); - auto ret_value = JS_NewUInt8Array(ctx, array_buffer, 0, length); + auto array_buffer = JS_NewArrayBuffer(ctx, buf, byte_array.size(), nullptr, nullptr, 0); + auto ret_value = JS_NewUInt8Array(ctx, array_buffer, 0, byte_array.size()); - env->ReleaseByteArrayElements(byte_array, arr, 0); - JS_FreeCString(ctx, c_str); - JS_FreeValue(ctx, array_buffer); + JS_FreeCString(ctx, c_str); + JS_FreeValue(ctx, array_buffer); - return ret_value; + return ret_value; + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } } static JSValue api_text_decoder_decode(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { uint8_t *buf; size_t elem, len, offset, buf_size; - int size; auto t_arr_buf = JS_GetTypedArrayBuffer(ctx, argv[0], &offset, &len, &elem); buf = JS_GetArrayBuffer(ctx, &buf_size, t_arr_buf); @@ -102,52 +93,29 @@ static JSValue api_text_decoder_decode(JSContext *ctx, JSValueConst this_val, in return JS_EXCEPTION; } - size = buf_size; - JS_FreeValue(ctx, t_arr_buf); auto *context = (Context *)JS_GetContextOpaque(ctx); - - auto *env = context->java->getEnv(); - if (env == nullptr) { - return throw_js_exception(ctx, "JVM Environment is null"); + if (context == nullptr) { + auto js_error = create_js_error("parent context is null", ctx); + return JS_Throw(ctx, js_error); } auto label_prop_str = JS_GetPropertyStr(ctx, this_val, "label"); const auto *encoding = JS_ToCString(ctx, label_prop_str); - auto *j_encoding = env->NewStringUTF(encoding); + try { + auto str = context->native_interface->byte_array_to_str(buf, buf_size, std::string(encoding)); + auto ret_value = JS_NewString(ctx, str.c_str()); - jbyteArray byte_array = env->NewByteArray(size); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { JS_FreeCString(ctx, encoding); - return exception; - } - - env->SetByteArrayRegion(byte_array, 0, size, reinterpret_cast(buf)); - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { + return ret_value; + } catch (std::exception &ex) { JS_FreeCString(ctx, encoding); - return exception; - } - auto *str = (jstring)env->CallStaticObjectMethod(context->java->web_api_class, context->java->web_api_byteArrayToString_method, byte_array, j_encoding); - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - JS_FreeCString(ctx, encoding); - return exception; + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); } - - const char *c_str = env->GetStringUTFChars(str, nullptr); - - auto ret_value = JS_NewString(ctx, c_str); - - env->ReleaseStringUTFChars(str, c_str); - - JS_FreeCString(ctx, encoding); - - return ret_value; } static const JSCFunctionListEntry js_text_encoder_proto_funcs[] = { diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_text.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_text.h similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_text.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_text.h diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_timeout.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_timeout.cpp similarity index 59% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_timeout.cpp rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_timeout.cpp index 11c8741d..67fa426e 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/api/api_timeout.cpp +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_timeout.cpp @@ -1,7 +1,6 @@ #include "api_timeout.h" -#include "../context.h" -#include "../errors.h" +#include "../context.hpp" JSValue create_timer(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, bool repeat) { JSValue ret_value = JS_UNDEFINED; @@ -17,30 +16,30 @@ JSValue create_timer(JSContext *ctx, JSValueConst this_val, int argc, JSValueCon int const timeout = JS_VALUE_GET_INT(argv[1]); auto *context = (Context *)JS_GetContextOpaque(ctx); - - auto *env = context->java->getEnv(); - if (env == nullptr) { - return throw_js_exception(ctx, "JVM Environment is null"); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); } - int const unique = env->CallStaticIntMethod(context->java->web_api_class, context->java->web_api_randomHashCode_method); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } + try { + int const unique = context->native_interface->get_random_hash(); - Timer timer{}; - timer.js_func = JS_DupValue(ctx, argv[0]); + Timer timer{}; + timer.js_func = JS_DupValue(ctx, argv[0]); - timer.timeout = timeout; - timer.start = std::chrono::system_clock::now(); - timer.repeat = repeat; + timer.timeout = timeout; + timer.start = std::chrono::system_clock::now(); + timer.repeat = repeat; - context->timers[unique] = timer; + context->timers[unique] = timer; - ret_value = JS_NewInt32(ctx, unique); + ret_value = JS_NewInt32(ctx, unique); - return ret_value; + return ret_value; + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } } JSValue api_set_timeout(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { return create_timer(ctx, this_val, argc, argv, false); } @@ -57,6 +56,10 @@ JSValue api_clear_timeout(JSContext *ctx, JSValueConst this_val, int argc, JSVal int const id = JS_VALUE_GET_INT(argv[0]); auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } JS_FreeValue(ctx, context->timers[id].js_func); context->timers.erase(id); diff --git a/packages/android-engine/android-js-engine/src/main/cpp/api/api_timeout.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_timeout.h similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/api/api_timeout.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/api/api_timeout.h diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_device.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_device.cpp new file mode 100644 index 00000000..2c8bb141 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_device.cpp @@ -0,0 +1,43 @@ +#include "api_device.h" + +#include "../context.hpp" + +JSValue api_device_battery(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } + + try { + auto json_result = context->capacitor_interface->device_api_getBatteryStatus(); + if (json_result.empty()) { + return JS_NULL; + } + + return JS_ParseJSON(ctx, json_result.c_str(), strlen(json_result.c_str()), ""); + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } +} + +JSValue api_device_network(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } + + try { + auto json_result = context->capacitor_interface->device_api_getNetworkStatus(); + if (json_result.empty()) { + return JS_NULL; + } + + return JS_ParseJSON(ctx, json_result.c_str(), strlen(json_result.c_str()), ""); + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } +} \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_device.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_device.h similarity index 65% rename from packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_device.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_device.h index c2caf812..e930f1a8 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_device.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_device.h @@ -1,9 +1,9 @@ -#ifndef ANDROID_API_CAP_DEVICE_H -#define ANDROID_API_CAP_DEVICE_H +#ifndef ANDROID_JS_ENGINE_API_DEVICE_H +#define ANDROID_JS_ENGINE_API_DEVICE_H #include "../quickjs/quickjs.h" JSValue api_device_battery(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); JSValue api_device_network(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); -#endif //ANDROID_API_CAP_DEVICE_H +#endif //ANDROID_JS_ENGINE_API_DEVICE_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_geolocation.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_geolocation.cpp new file mode 100644 index 00000000..2950137f --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_geolocation.cpp @@ -0,0 +1,23 @@ +#include "api_geolocation.h" + +#include "../context.hpp" + +JSValue api_geolocation_current_location(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } + + try { + auto json_result = context->capacitor_interface->geolocation_api_getCurrentPosition(); + if (json_result.empty()) { + return JS_NULL; + } + + return JS_ParseJSON(ctx, json_result.c_str(), strlen(json_result.c_str()), ""); + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } +} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_geolocation.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_geolocation.h similarity index 52% rename from packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_geolocation.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_geolocation.h index 1483cc71..6db663c9 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_geolocation.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_geolocation.h @@ -1,8 +1,8 @@ -#ifndef ANDROID_API_CAP_GEOLOCATION_H -#define ANDROID_API_CAP_GEOLOCATION_H +#ifndef ANDROID_JS_ENGINE_API_GEOLOCATION_H +#define ANDROID_JS_ENGINE_API_GEOLOCATION_H #include "../quickjs/quickjs.h" JSValue api_geolocation_current_location(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); -#endif //ANDROID_API_CAP_GEOLOCATION_H +#endif //ANDROID_JS_ENGINE_API_GEOLOCATION_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_kv.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_kv.cpp new file mode 100644 index 00000000..5f2ee3c4 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_kv.cpp @@ -0,0 +1,87 @@ +#include "api_kv.h" + +#include "../context.hpp" + +JSValue api_kv_set(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } + + const auto *key_c_str = JS_ToCString(ctx, argv[0]); + const auto *value_c_str = JS_ToCString(ctx, argv[1]); + + try { + context->capacitor_interface->kv_api_set(key_c_str, value_c_str); + + JS_FreeCString(ctx, key_c_str); + JS_FreeCString(ctx, value_c_str); + + return JS_UNDEFINED; + } catch (std::exception &ex) { + JS_FreeCString(ctx, key_c_str); + JS_FreeCString(ctx, value_c_str); + + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } +} + +JSValue api_kv_get(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } + + const auto *key_c_str = JS_ToCString(ctx, argv[0]); + + try { + JSValue return_value = JS_NULL; + + auto value_json = context->capacitor_interface->kv_api_get(key_c_str); + + if (value_json.empty()) { + JS_FreeCString(ctx, key_c_str); + return return_value; + } + + auto value_str_obj = JS_NewString(ctx, value_json.c_str()); + + return_value = JS_NewObject(ctx); + JS_SetPropertyStr(ctx, return_value, "value", value_str_obj); + + JS_FreeCString(ctx, key_c_str); + + return return_value; + } catch (std::exception &ex) { + JS_FreeCString(ctx, key_c_str); + + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } +} + +JSValue api_kv_remove(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } + + const auto *key_c_str = JS_ToCString(ctx, argv[0]); + + try { + context->capacitor_interface->kv_api_remove(key_c_str); + + JS_FreeCString(ctx, key_c_str); + + return JS_UNDEFINED; + } catch (std::exception &ex) { + JS_FreeCString(ctx, key_c_str); + + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } +} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_kv.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_kv.h similarity index 67% rename from packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_kv.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_kv.h index bdfb0f39..98cf27ef 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_kv.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_kv.h @@ -1,5 +1,5 @@ -#ifndef CAPACITOR_BACKGROUND_RUNNER_API_CAP_KV_H -#define CAPACITOR_BACKGROUND_RUNNER_API_CAP_KV_H +#ifndef ANDROID_JS_ENGINE_API_KV_H +#define ANDROID_JS_ENGINE_API_KV_H #include "../quickjs/quickjs.h" @@ -7,4 +7,4 @@ JSValue api_kv_set(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst JSValue api_kv_get(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); JSValue api_kv_remove(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); -#endif //CAPACITOR_BACKGROUND_RUNNER_API_CAP_KV_H +#endif //ANDROID_JS_ENGINE_API_KV_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_notifications.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_notifications.cpp new file mode 100644 index 00000000..b35be925 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_notifications.cpp @@ -0,0 +1,27 @@ +#include "api_notifications.h" + +#include "../context.hpp" + +JSValue api_notifications_schedule(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + auto *context = (Context *)JS_GetContextOpaque(ctx); + if (context == nullptr) { + auto js_error = create_js_error("context is null", ctx); + return JS_Throw(ctx, js_error); + } + + auto options_str = JS_JSONStringify(ctx, argv[0], JS_UNDEFINED, JS_UNDEFINED); + const auto *options_c_str = JS_ToCString(ctx, options_str); + + try { + context->capacitor_interface->notifications_api_schedule(options_c_str); + + JS_FreeCString(ctx, options_c_str); + + return JS_UNDEFINED; + } catch (std::exception &ex) { + JS_FreeCString(ctx, options_c_str); + + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); + } +} \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_notifications.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_notifications.h similarity index 50% rename from packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_notifications.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_notifications.h index a0294737..966853b5 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/cap_api/api_cap_notifications.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor-api/api_notifications.h @@ -1,8 +1,8 @@ -#ifndef ANDROID_API_CAP_NOTIFICATIONS_H -#define ANDROID_API_CAP_NOTIFICATIONS_H +#ifndef ANDROID_JS_ENGINE_API_NOTIFICATIONS_H +#define ANDROID_JS_ENGINE_API_NOTIFICATIONS_H #include "../quickjs/quickjs.h" JSValue api_notifications_schedule(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); -#endif //ANDROID_API_CAP_NOTIFICATIONS_H +#endif //ANDROID_JS_ENGINE_API_NOTIFICATIONS_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor.hpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor.hpp new file mode 100644 index 00000000..bf3fb3ec --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/capacitor.hpp @@ -0,0 +1,28 @@ +#ifndef CAPACITOR_BACKGROUND_CAPACITOR_H +#define CAPACITOR_BACKGROUND_CAPACITOR_H + +#include "quickjs/quickjs.h" +#include + +class CapacitorInterface { +public: + virtual ~CapacitorInterface() = default; + CapacitorInterface(const CapacitorInterface&) = delete; + CapacitorInterface(CapacitorInterface&&) = delete; + CapacitorInterface& operator=(const CapacitorInterface&) = delete; + + virtual std::string device_api_getBatteryStatus() = 0; + virtual std::string device_api_getNetworkStatus() = 0; + + virtual std::string geolocation_api_getCurrentPosition() = 0; + + virtual void kv_api_set(std::string key, std::string json_value) = 0; + virtual std::string kv_api_get(std::string key) = 0; + virtual void kv_api_remove(std::string key) = 0; + + virtual void notifications_api_schedule(std::string options_json) = 0; +protected: + CapacitorInterface() = default; +}; + +#endif //CAPACITOR_BACKGROUND_CAPACITOR_H diff --git a/packages/android-engine/android-js-engine/src/main/cpp/context.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/context.cpp similarity index 69% rename from packages/android-engine/android-js-engine/src/main/cpp/context.cpp rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/context.cpp index 2b2dda6f..b6239d31 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/context.cpp +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/context.cpp @@ -1,13 +1,16 @@ -#include "context.h" +#include "context.hpp" -#include "errors.h" +#include "capacitor-api/api_device.h" +#include "capacitor-api/api_geolocation.h" +#include "capacitor-api/api_kv.h" +#include "capacitor-api/api_notifications.h" #include "quickjs/cutils.h" -Context::Context(const std::string &name, JSRuntime *parent_rt, JNIEnv *env) { +Context::Context(const std::string &name, JSRuntime *parent_rt, NativeInterface *native, CapacitorInterface *cap) { this->name = name; this->qjs_context = JS_NewContext(parent_rt); - this->java = new Java(env); - this->cap_api = nullptr; + this->native_interface = native; + this->capacitor_interface = cap; JS_SetContextOpaque(this->qjs_context, this); @@ -17,9 +20,11 @@ Context::Context(const std::string &name, JSRuntime *parent_rt, JNIEnv *env) { this->init_api_crypto(); this->init_api_text(); this->init_api_fetch(); - this->init_api_blob(); + // this->init_api_blob(); - this->log_debug("created context"); + if (this->capacitor_interface != nullptr) { + this->init_capacitor_api(); + } } Context::~Context() { @@ -27,7 +32,6 @@ Context::~Context() { JS_FreeValue(this->qjs_context, kv.second); } this->event_listeners.clear(); - this->registered_functions.clear(); for (const auto &kv : this->timers) { JS_FreeValue(this->qjs_context, kv.second.js_func); @@ -36,116 +40,54 @@ Context::~Context() { JS_FreeContext(this->qjs_context); - this->log_debug("destroyed context"); + this->native_interface->logger(LoggerLevel::INFO, this->name, "Destroying context"); } -void Context::run_loop() { - if (!this->timers.empty()) { - for (const auto &timer_kv : this->timers) { - auto duration = std::chrono::duration_cast(std::chrono::system_clock::now() - timer_kv.second.start); - if (duration.count() >= timer_kv.second.timeout) { +bool Context::has_timers() { return !this->timers.empty(); } + +void Context::run_timers() { + if (this->timers.empty()) { + return; + } + + std::vector dead_timers; + + for (const auto &timer_kv : this->timers) { + auto elapsed = std::chrono::duration_cast(std::chrono::system_clock::now() - timer_kv.second.start); + + if (elapsed.count() >= timer_kv.second.timeout) { + this->execute_timer(timer_kv.second.js_func); + if (timer_kv.second.repeat) { this->timers[timer_kv.first].start = std::chrono::system_clock::now(); - this->execute_timer(timer_kv.second.js_func); - if (!this->timers[timer_kv.first].repeat) { - JS_FreeValue(this->qjs_context, this->timers[timer_kv.first].js_func); - this->timers.erase(timer_kv.first); - } + } else { + dead_timers.push_back(timer_kv.first); } } } + + for (const auto hash : dead_timers) { + JS_FreeValue(this->qjs_context, this->timers[hash].js_func); + this->timers.erase(hash); + } } static JSValue call_registered_function(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic, JSValue *func_data) { - JSValue ret_value = JS_UNDEFINED; - auto *context = (Context *)JS_GetContextOpaque(ctx); JSValue func_name_obj = func_data[0]; auto func_name_str = std::string(JS_ToCString(ctx, func_name_obj)); JS_FreeValue(ctx, func_name_obj); - auto j_func = context->registered_functions.at(func_name_str); - - auto *env = context->java->getEnv(); - if (env == nullptr) { - throw_js_exception(ctx, "JVM Environment is null"); - return JS_UNDEFINED; - } - - auto j_function_class = env->GetObjectClass(j_func); - auto exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - auto j_method = env->GetMethodID(j_function_class, "run", "()V"); - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - JSValue args = argv[0]; - if (!JS_IsNull(args) && !JS_IsUndefined(args)) { - std::string json_string; - - if (JS_IsError(context->qjs_context, args)) { - auto error_object = JS_NewObject(ctx); - - auto error_name = JS_GetPropertyStr(ctx, args, "name"); - auto error_message = JS_GetPropertyStr(ctx, args, "message"); - - JS_SetPropertyStr(ctx, error_object, "name", error_name); - JS_SetPropertyStr(ctx, error_object, "message", error_message); - - auto json_string_obj = JS_JSONStringify(ctx, error_object, JS_UNDEFINED, JS_UNDEFINED); - auto json_c_string = JS_ToCString(ctx, json_string_obj); - - json_string = std::string(json_c_string); - - JS_FreeCString(ctx, json_c_string); - JS_FreeValue(ctx, json_string_obj); - JS_FreeValue(ctx, error_object); - } else { - auto json_string_obj = JS_JSONStringify(ctx, args, JS_UNDEFINED, JS_UNDEFINED); - auto json_c_string = JS_ToCString(ctx, json_string_obj); - - json_string = std::string(json_c_string); - - JS_FreeCString(ctx, json_c_string); - JS_FreeValue(ctx, json_string_obj); - } - - jstring j_json_string = env->NewStringUTF(json_string.c_str()); - - // create a JSONObject - jclass json_object_class = env->FindClass("org/json/JSONObject"); - jmethodID json_object_constructor = env->GetMethodID(json_object_class, "", "(Ljava/lang/String;)V"); - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - jobject json_object = env->NewObject(json_object_class, json_object_constructor, j_json_string); - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; - } - - jfieldID args_field = env->GetFieldID(j_function_class, "args", "Lorg/json/JSONObject;"); - env->SetObjectField(j_func, args_field, json_object); - } - - env->CallVoidMethod(j_func, j_method); - exception = throw_jvm_exception_in_js(env, ctx); - if (JS_IsException(exception)) { - return exception; + try { + return context->native_interface->invoke_native_function(func_name_str, ctx, argv[0]); + } catch (std::exception &ex) { + auto js_error = create_js_error(ex.what(), ctx); + return JS_Throw(ctx, js_error); } - - return ret_value; } -void Context::register_function(const std::string &func_name, jobject func) { - this->registered_functions.insert_or_assign(func_name, func); +void Context::register_function(const std::string &func_name, std::any func) { + this->native_interface->register_native_function(func_name, func); auto global_obj = JS_GetGlobalObject(this->qjs_context); auto func_name_value = JS_NewString(this->qjs_context, func_name.c_str()); @@ -165,7 +107,6 @@ JSValue Context::evaluate(const std::string &code, bool ret_val) const { int flags = JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_BACKTRACE_BARRIER; size_t len = strlen(code.c_str()); - write_to_logcat(ANDROID_LOG_DEBUG, "[RUNNER DEV TRACER]", "evaluate context code"); JSValue value = JS_Eval(this->qjs_context, code.c_str(), len, "", flags); if (JS_IsException(value)) { @@ -243,15 +184,6 @@ JSValue Context::dispatch_event(const std::string &event, JSValue details) { return ret_value; } -void Context::init_capacitor_api(jobject cap_api_obj) { - this->cap_api = cap_api_obj; - - this->init_capacitor_kv_api(); - this->init_capacitor_device_api(); - this->init_capacitor_notifications_api(); - this->init_capacitor_geolocation_api(); -} - void Context::init_callbacks(JSValue callbacks) const { // look for __cbr:: and replace with JSFunction JSPropertyEnum *properties; @@ -269,20 +201,17 @@ void Context::init_callbacks(JSValue callbacks) const { std::string const prefix = str_value.substr(0, 7); if (prefix == "__cbr::") { - try { - auto global_func_name = str_value.substr(7); + auto global_func_name = str_value.substr(7); - if (this->registered_functions.find(global_func_name) != this->registered_functions.end()) { - auto func_name_value = JS_NewString(this->qjs_context, global_func_name.c_str()); + if (this->native_interface->has_native_function(global_func_name)) { + auto func_name_value = JS_NewString(this->qjs_context, global_func_name.c_str()); - JSValueConst ptr[1]; - ptr[0] = func_name_value; + JSValueConst ptr[1]; + ptr[0] = func_name_value; - JS_SetPropertyStr(this->qjs_context, callbacks, key, JS_NewCFunctionData(this->qjs_context, call_registered_function, 1, 0, 1, ptr)); + JS_SetPropertyStr(this->qjs_context, callbacks, key, JS_NewCFunctionData(this->qjs_context, call_registered_function, 1, 0, 1, ptr)); - JS_FreeValue(this->qjs_context, func_name_value); - } - } catch (std::exception &ex) { + JS_FreeValue(this->qjs_context, func_name_value); } } @@ -295,13 +224,7 @@ void Context::init_callbacks(JSValue callbacks) const { } } -void Context::log_debug(const std::string &msg) const { - auto tag = "[Runner Context " + this->name + "]"; - write_to_logcat(ANDROID_LOG_DEBUG, tag.c_str(), msg.c_str()); -} - void Context::execute_timer(JSValue timerFunc) const { - write_to_logcat(ANDROID_LOG_DEBUG, "[RUNNER DEV TRACER]", "fire timer"); JSValue dupFunc = JS_DupValue(this->qjs_context, timerFunc); auto ret = JS_Call(this->qjs_context, dupFunc, JS_UNDEFINED, 0, nullptr); JS_FreeValue(this->qjs_context, dupFunc); @@ -374,21 +297,13 @@ void Context::init_api_fetch() const { JS_FreeValue(this->qjs_context, global_obj); } -void Context::init_api_blob() const { init_blob_class(this->qjs_context); } - -void Context::init_capacitor_kv_api() const { - JSValue global_obj, kv; - - global_obj = JS_GetGlobalObject(this->qjs_context); - - kv = JS_NewObject(this->qjs_context); - JS_SetPropertyStr(this->qjs_context, kv, "set", JS_NewCFunction(this->qjs_context, api_kv_set, "set", 2)); - JS_SetPropertyStr(this->qjs_context, kv, "get", JS_NewCFunction(this->qjs_context, api_kv_get, "get", 1)); - JS_SetPropertyStr(this->qjs_context, kv, "remove", JS_NewCFunction(this->qjs_context, api_kv_remove, "remove", 1)); - - JS_SetPropertyStr(this->qjs_context, global_obj, "CapacitorKV", kv); +// void Context::init_api_blob() const { init_blob_class(this->qjs_context); } - JS_FreeValue(this->qjs_context, global_obj); +void Context::init_capacitor_api() { + this->init_capacitor_device_api(); + this->init_capacitor_geolocation_api(); + this->init_capacitor_kv_api(); + this->init_capacitor_notifications_api(); } void Context::init_capacitor_device_api() const { @@ -405,6 +320,21 @@ void Context::init_capacitor_device_api() const { JS_FreeValue(this->qjs_context, global_obj); } +void Context::init_capacitor_kv_api() const { + JSValue global_obj, kv; + + global_obj = JS_GetGlobalObject(this->qjs_context); + + kv = JS_NewObject(this->qjs_context); + JS_SetPropertyStr(this->qjs_context, kv, "set", JS_NewCFunction(this->qjs_context, api_kv_set, "set", 2)); + JS_SetPropertyStr(this->qjs_context, kv, "get", JS_NewCFunction(this->qjs_context, api_kv_get, "get", 1)); + JS_SetPropertyStr(this->qjs_context, kv, "remove", JS_NewCFunction(this->qjs_context, api_kv_remove, "remove", 1)); + + JS_SetPropertyStr(this->qjs_context, global_obj, "CapacitorKV", kv); + + JS_FreeValue(this->qjs_context, global_obj); +} + void Context::init_capacitor_notifications_api() const { JSValue global_obj, notifications; diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/context.hpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/context.hpp new file mode 100644 index 00000000..5c513f20 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/context.hpp @@ -0,0 +1,60 @@ +#ifndef CAPACITOR_BACKGROUND_RUNNER_CONTEXT_H +#define CAPACITOR_BACKGROUND_RUNNER_CONTEXT_H +#include +#include + +#include "./quickjs/quickjs.h" +#include "api/api_blob.h" +#include "api/api_console.h" +#include "api/api_crypto.h" +#include "api/api_events.h" +#include "api/api_fetch.h" +#include "api/api_js_response.h" +#include "api/api_text.h" +#include "api/api_timeout.h" +#include "native.hpp" +#include "capacitor.hpp" + +class Context { + public: + std::string name; + + JSContext *qjs_context; + + NativeInterface *native_interface; + CapacitorInterface *capacitor_interface; + + std::unordered_map event_listeners; + std::unordered_map timers; + + Context(const std::string &name, JSRuntime *parent_rt, NativeInterface *native, CapacitorInterface *cap); + ~Context(); + + void run_timers(); + bool has_timers(); + + void register_function(const std::string &func_name, std::any func); + JSValue evaluate(const std::string &code, bool ret_val) const; + JSValue dispatch_event(const std::string &event, JSValue details); + + private: + void init_callbacks(JSValue callbacks) const; + + void execute_timer(JSValue timerFunc) const; + + void init_api_console() const; + void init_api_event_listeners() const; + void init_api_timeout() const; + void init_api_crypto() const; + void init_api_text() const; + void init_api_fetch() const; + // void init_api_blob() const; + + void init_capacitor_api(); + void init_capacitor_device_api() const; + void init_capacitor_geolocation_api() const; + void init_capacitor_kv_api() const; + void init_capacitor_notifications_api() const; +}; + +#endif // CAPACITOR_BACKGROUND_RUNNER_CONTEXT_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/errors.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/errors.cpp new file mode 100644 index 00000000..1243d879 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/errors.cpp @@ -0,0 +1,29 @@ +#include "errors.hpp" + +NativeInterfaceException::NativeInterfaceException(const char *error) { this->message = error; } + +const char *NativeInterfaceException::what() const throw() { return this->message.c_str(); } + +JSValue create_js_error(const char *error_message, JSContext *ctx) { + auto error = JS_NewError(ctx); + JS_SetPropertyStr(ctx, error, "message", JS_NewString(ctx, error_message)); + return error; +} + +JSValue get_js_exception(JSContext *ctx) { + auto exception = JS_GetException(ctx); + if (!JS_IsException(exception) && !JS_IsError(ctx, exception)) { + return JS_NULL; + } + + return exception; +} + +void reject_promise(JSContext *ctx, JSValue reject_func, JSValue reject_obj) { + auto global_obj = JS_GetGlobalObject(ctx); + JSValueConst reject_args[1]; + reject_args[0] = reject_obj; + + JS_Call(ctx, reject_func, global_obj, 1, reject_args); + JS_FreeValue(ctx, global_obj); +} \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/errors.hpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/errors.hpp new file mode 100644 index 00000000..3e508c2b --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/errors.hpp @@ -0,0 +1,22 @@ +#ifndef CAPACITOR_BACKGROUND_RUNNER_ERRORS_H +#define CAPACITOR_BACKGROUND_RUNNER_ERRORS_H + +#include +#include +#include "quickjs/quickjs.h" + +class NativeInterfaceException : public std::exception { +public: + NativeInterfaceException(const char* error); + const char* what() const throw(); + +private: + std::string message; +}; + +JSValue create_js_error(const char * error_message, JSContext *ctx); +JSValue get_js_exception(JSContext *ctx); + +void reject_promise(JSContext *ctx, JSValue reject_func, JSValue reject_obj); + +#endif // CAPACITOR_BACKGROUND_RUNNER_ERRORS_H \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/native.hpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/native.hpp new file mode 100644 index 00000000..63d3f9b7 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/native.hpp @@ -0,0 +1,51 @@ +#ifndef CAPACITOR_BACKGROUND_NATIVE_H +#define CAPACITOR_BACKGROUND_NATIVE_H + +#include +#include +#include +#include + +#include "quickjs/quickjs.h" +#include "errors.hpp" + +enum LoggerLevel { INFO, WARN, ERROR, DEBUG }; + +struct NativeResponse { + bool ok; + int status; + std::string url; + std::string error; + std::vector data; +}; + +struct NativeRequest { + std::string url; + std::string method; + std::unordered_map headers; + std::vector body; +}; + +class NativeInterface { + public: + virtual ~NativeInterface() = default; + NativeInterface(const NativeInterface&) = delete; + NativeInterface(NativeInterface&&) = delete; + NativeInterface& operator=(const NativeInterface&) = delete; + + virtual void logger(LoggerLevel level, const std::string& tag, const std::string& messages) = 0; + virtual void register_native_function(const std::string& func_name, std::any func_obj) = 0; + virtual bool has_native_function(const std::string& func_name) = 0; + virtual JSValue invoke_native_function(const std::string& func_name, JSContext* ctx, JSValue args) = 0; + virtual std::string crypto_get_random_uuid() = 0; + virtual std::vector crypto_get_random(size_t size) = 0; + virtual int get_random_hash() = 0; + virtual NativeResponse fetch(NativeRequest request) = 0; + virtual std::string byte_array_to_str(uint8_t* arr, size_t size,const std::string& encoding) = 0; + virtual std::vector string_to_byte_array(std::string str) = 0; + + protected: + NativeInterface() = default; +}; + +#endif // CAPACITOR_BACKGROUND_NATIVE_H \ No newline at end of file diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/CMakeLists.txt b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/CMakeLists.txt similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/CMakeLists.txt rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/CMakeLists.txt diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/Changelog b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/Changelog similarity index 81% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/Changelog rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/Changelog index c09af91c..944d96ac 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/Changelog +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/Changelog @@ -1,3 +1,30 @@ +2024-01-13: + +- top-level-await support in modules +- allow 'await' in the REPL +- added Array.prototype.{with,toReversed,toSpliced,toSorted} and +TypedArray.prototype.{with,toReversed,toSorted} +- added String.prototype.isWellFormed and String.prototype.toWellFormed +- added Object.groupBy and Map.groupBy +- added Promise.withResolvers +- class static block +- 'in' operator support for private fields +- optional chaining fixes +- added RegExp 'd' flag +- fixed RegExp zero length match logic +- fixed RegExp case insensitive flag +- added os.getpid() and os.now() +- added cosmopolitan build +- misc bug fixes + +2023-12-09: + +- added Object.hasOwn, {String|Array|TypedArray}.prototype.at, + {Array|TypedArray}.prototype.findLast{Index} +- BigInt support is enabled even if CONFIG_BIGNUM disabled +- updated to Unicode 15.0.0 +- misc bug fixes + 2021-03-27: - faster Array.prototype.push and Array.prototype.unshift diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/LICENSE b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/LICENSE similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/LICENSE rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/LICENSE diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/Makefile b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/Makefile similarity index 87% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/Makefile rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/Makefile index 49b1f6fa..57cdd7ef 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/Makefile +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/Makefile @@ -33,40 +33,43 @@ CONFIG_LTO=y #CONFIG_WERROR=y # force 32 bit build for some utilities #CONFIG_M32=y - -ifdef CONFIG_DARWIN -# use clang instead of gcc -CONFIG_CLANG=y -CONFIG_DEFAULT_AR=y -endif +# cosmopolitan build (see https://github.com/jart/cosmopolitan) +#CONFIG_COSMO=y # installation directory -prefix=/usr/local +PREFIX?=/usr/local # use the gprof profiler #CONFIG_PROFILE=y # use address sanitizer #CONFIG_ASAN=y -# include the code for BigInt/BigFloat/BigDecimal and math mode +# include the code for BigFloat/BigDecimal, math mode and faster large integers CONFIG_BIGNUM=y OBJDIR=.obj +ifdef CONFIG_DARWIN +# use clang instead of gcc +CONFIG_CLANG=y +CONFIG_DEFAULT_AR=y +endif + ifdef CONFIG_WIN32 ifdef CONFIG_M32 - CROSS_PREFIX=i686-w64-mingw32- + CROSS_PREFIX?=i686-w64-mingw32- else - CROSS_PREFIX=x86_64-w64-mingw32- + CROSS_PREFIX?=x86_64-w64-mingw32- endif EXE=.exe else - CROSS_PREFIX= + CROSS_PREFIX?= EXE= endif + ifdef CONFIG_CLANG HOST_CC=clang CC=$(CROSS_PREFIX)clang - CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d + CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d CFLAGS += -Wextra CFLAGS += -Wno-sign-compare CFLAGS += -Wno-missing-field-initializers @@ -84,10 +87,18 @@ ifdef CONFIG_CLANG AR=$(CROSS_PREFIX)ar endif endif +else ifdef CONFIG_COSMO + CONFIG_LTO= + HOST_CC=gcc + CC=cosmocc + # cosmocc does not correct support -MF + CFLAGS=-g -Wall #-MMD -MF $(OBJDIR)/$(@F).d + CFLAGS += -Wno-array-bounds -Wno-format-truncation + AR=cosmoar else HOST_CC=gcc CC=$(CROSS_PREFIX)gcc - CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d + CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d CFLAGS += -Wno-array-bounds -Wno-format-truncation ifdef CONFIG_LTO AR=$(CROSS_PREFIX)gcc-ar @@ -96,6 +107,7 @@ else endif endif STRIP=$(CROSS_PREFIX)strip +CFLAGS+=-fwrapv # ensure that signed overflows behave as expected ifdef CONFIG_WERROR CFLAGS+=-Werror endif @@ -112,7 +124,11 @@ CFLAGS_DEBUG=$(CFLAGS) -O0 CFLAGS_SMALL=$(CFLAGS) -Os CFLAGS_OPT=$(CFLAGS) -O2 CFLAGS_NOLTO:=$(CFLAGS_OPT) -LDFLAGS=-g +ifdef CONFIG_COSMO +LDFLAGS+=-s # better to strip by default +else +LDFLAGS+=-g +endif ifdef CONFIG_LTO CFLAGS_SMALL+=-flto CFLAGS_OPT+=-flto @@ -132,6 +148,12 @@ else LDEXPORT=-rdynamic endif +ifndef CONFIG_COSMO +ifndef CONFIG_DARWIN +CONFIG_SHARED_LIBS=y # building shared libraries is supported +endif +endif + PROGS=qjs$(EXE) qjsc$(EXE) run-test262 ifneq ($(CROSS_PREFIX),) QJSC_CC=gcc @@ -154,23 +176,21 @@ endif # examples ifeq ($(CROSS_PREFIX),) -ifdef CONFIG_ASAN -PROGS+= -else -PROGS+=examples/hello examples/hello_module examples/test_fib -ifndef CONFIG_DARWIN -PROGS+=examples/fib.so examples/point.so +PROGS+=examples/hello +ifndef CONFIG_ASAN +PROGS+=examples/hello_module endif +ifdef CONFIG_SHARED_LIBS +PROGS+=examples/test_fib examples/fib.so examples/point.so endif endif all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) -QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o +QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/libbf.o QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) ifdef CONFIG_BIGNUM -QJS_LIB_OBJS+=$(OBJDIR)/libbf.o QJS_OBJS+=$(OBJDIR)/qjscalc.o endif @@ -201,11 +221,11 @@ $(QJSC): $(OBJDIR)/qjsc.host.o \ endif #CROSS_PREFIX -QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(prefix)\" +QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\" ifdef CONFIG_LTO QJSC_DEFINES+=-DCONFIG_LTO endif -QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(prefix)\" +QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\" $(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES) $(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES) @@ -298,17 +318,17 @@ clean: rm -rf run-test262-debug run-test262-32 install: all - mkdir -p "$(DESTDIR)$(prefix)/bin" + mkdir -p "$(DESTDIR)$(PREFIX)/bin" $(STRIP) qjs qjsc - install -m755 qjs qjsc "$(DESTDIR)$(prefix)/bin" - ln -sf qjs "$(DESTDIR)$(prefix)/bin/qjscalc" - mkdir -p "$(DESTDIR)$(prefix)/lib/quickjs" - install -m644 libquickjs.a "$(DESTDIR)$(prefix)/lib/quickjs" + install -m755 qjs qjsc "$(DESTDIR)$(PREFIX)/bin" + ln -sf qjs "$(DESTDIR)$(PREFIX)/bin/qjscalc" + mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs" + install -m644 libquickjs.a "$(DESTDIR)$(PREFIX)/lib/quickjs" ifdef CONFIG_LTO - install -m644 libquickjs.lto.a "$(DESTDIR)$(prefix)/lib/quickjs" + install -m644 libquickjs.lto.a "$(DESTDIR)$(PREFIX)/lib/quickjs" endif - mkdir -p "$(DESTDIR)$(prefix)/include/quickjs" - install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(prefix)/include/quickjs" + mkdir -p "$(DESTDIR)$(PREFIX)/include/quickjs" + install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(PREFIX)/include/quickjs" ############################################################################### # examples @@ -317,10 +337,7 @@ endif HELLO_SRCS=examples/hello.js HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \ -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \ - -fno-date -fno-module-loader -ifdef CONFIG_BIGNUM -HELLO_OPTS+=-fno-bigint -endif + -fno-date -fno-module-loader -fno-bigint hello.c: $(QJSC) $(HELLO_SRCS) $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) @@ -377,7 +394,7 @@ doc/%.html: doc/%.html.pre ############################################################################### # tests -ifndef CONFIG_DARWIN +ifdef CONFIG_SHARED_LIBS test: tests/bjson.so examples/point.so endif ifdef CONFIG_M32 @@ -391,7 +408,7 @@ test: qjs ./qjs tests/test_loop.js ./qjs tests/test_std.js ./qjs tests/test_worker.js -ifndef CONFIG_DARWIN +ifdef CONFIG_SHARED_LIBS ifdef CONFIG_BIGNUM ./qjs --bignum tests/test_bjson.js else diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/TODO b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/TODO similarity index 94% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/TODO rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/TODO index 2a3b3c31..bbd1a450 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/TODO +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/TODO @@ -1,6 +1,3 @@ -Bugs: -- modules: better error handling with cyclic module references - Misc ideas: - use custom printf to avoid compatibility issues with floating point numbers - consistent naming for preprocessor defines @@ -66,5 +63,5 @@ Optimization ideas: Test262o: 0/11262 errors, 463 excluded Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) -Result: 35/75280 errors, 909 excluded, 585 skipped -Test262 commit: 31126581e7290f9233c29cefd93f66c6ac78f1c9 +Result: 10/76947 errors, 1497 excluded, 8117 skipped +Test262 commit: 6cbb6da9473c56d95358d8e679c5a6d2b4574efb diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/VERSION b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/VERSION new file mode 100644 index 00000000..e89de35f --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/VERSION @@ -0,0 +1 @@ +2024-01-13 diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/cutils.c b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/cutils.c similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/cutils.c rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/cutils.c diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/cutils.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/cutils.h similarity index 97% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/cutils.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/cutils.h index 31f7cd84..8399d614 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/cutils.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/cutils.h @@ -49,6 +49,9 @@ #define countof(x) (sizeof(x) / sizeof((x)[0])) #endif +/* return the pointer of type 'type *' containing 'ptr' as field 'member' */ +#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member))) + typedef int BOOL; #ifndef FALSE diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/jsbignum.html b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/jsbignum.html new file mode 100644 index 00000000..ab31612b --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/jsbignum.html @@ -0,0 +1,734 @@ + + + + +Javascript Bignum Extensions + + + + + + + + + + + + + + + +

Javascript Bignum Extensions

+ + +

Table of Contents

+ + + + + +

1 Introduction

+ +

The Bignum extensions add the following features to the Javascript +language while being 100% backward compatible: +

+
    +
  • Operator overloading with a dispatch logic inspired from the proposal available at https://github.com/tc39/proposal-operator-overloading/. + +
  • Arbitrarily large floating point numbers (BigFloat) in base 2 using the IEEE 754 semantics. + +
  • Arbitrarily large floating point numbers (BigDecimal) in base 10 based on the proposal available at +https://github.com/littledan/proposal-bigdecimal. + +
  • math mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (%) is defined as the Euclidian +remainder. ^ is an alias to the power operator +(**). ^^ is used as the exclusive or operator. + +
+ +

The extensions are independent from each other except the math +mode which relies on BigFloat and operator overloading. +

+ +

2 Operator overloading

+ +

Operator overloading is inspired from the proposal available at +https://github.com/tc39/proposal-operator-overloading/. It +implements the same dispatch logic but finds the operator sets by +looking at the Symbol.operatorSet property in the objects. The +changes were done in order to simplify the implementation. +

+

More precisely, the following modifications were made: +

+
    +
  • with operators from is not supported. Operator overloading is always enabled. + +
  • The dispatch is not based on a static [[OperatorSet]] field in all instances. Instead, a dynamic lookup of the Symbol.operatorSet property is done. This property is typically added in the prototype of each object. + +
  • Operators.create(...dictionaries) is used to create a new OperatorSet object. The Operators function is supported as an helper to be closer to the TC39 proposal. + +
  • [] cannot be overloaded. + +
  • In math mode, the BigInt division and power operators can be overloaded with Operators.updateBigIntOperators(dictionary). + +
+ + +

3 BigInt extensions

+ +

A few properties are added to the BigInt object: +

+
+
tdiv(a, b)
+

Return trunc(a/b). b = 0 raises a RangeError +exception. +

+
+
fdiv(a, b)
+

Return \lfloor a/b \rfloor. b = 0 raises a RangeError +exception. +

+
+
cdiv(a, b)
+

Return \lceil a/b \rceil. b = 0 raises a RangeError +exception. +

+
+
ediv(a, b)
+

Return sgn(b) \lfloor a/{|b|} \rfloor (Euclidian +division). b = 0 raises a RangeError exception. +

+
+
tdivrem(a, b)
+
fdivrem(a, b)
+
cdivrem(a, b)
+
edivrem(a, b)
+

Return an array of two elements. The first element is the quotient, +the second is the remainder. The same rounding is done as the +corresponding division operation. +

+
+
sqrt(a)
+

Return \lfloor \sqrt(a) \rfloor. A RangeError exception is +raised if a < 0. +

+
+
sqrtrem(a)
+

Return an array of two elements. The first element is \lfloor +\sqrt{a} \rfloor. The second element is a-\lfloor \sqrt{a} +\rfloor^2. A RangeError exception is raised if a < 0. +

+
+
floorLog2(a)
+

Return -1 if a \leq 0 otherwise return \lfloor \log2(a) \rfloor. +

+
+
ctz(a)
+

Return the number of trailing zeros in the two’s complement binary representation of a. Return -1 if a=0. +

+
+
+ + +

4 BigFloat

+ + +

4.1 Introduction

+ +

This extension adds the BigFloat primitive type. The +BigFloat type represents floating point numbers in base 2 +with the IEEE 754 semantics. A floating +point number is represented as a sign, mantissa and exponent. The +special values NaN, +/-Infinity, +0 and -0 +are supported. The mantissa and exponent can have any bit length with +an implementation specific minimum and maximum. +

+ +

4.2 Floating point rounding

+ +

Each floating point operation operates with infinite precision and +then rounds the result according to the specified floating point +environment (BigFloatEnv object). The status flags of the +environment are also set according to the result of the operation. +

+

If no floating point environment is provided, the global floating +point environment is used. +

+

The rounding mode of the global floating point environment is always +RNDN (“round to nearest with ties to even”)1. The status flags of the global environment cannot be +read2. The precision of the global environment is +BigFloatEnv.prec. The number of exponent bits of the global +environment is BigFloatEnv.expBits. The global environment +subnormal flag is set to true. +

+

For example, prec = 53 and expBits = 11 exactly give +the same precision as the IEEE 754 64 bit floating point format. The +default precision is prec = 113 and expBits = 15 (IEEE +754 128 bit floating point format). +

+

The global floating point environment can only be modified temporarily +when calling a function (see BigFloatEnv.setPrec). Hence a +function can change the global floating point environment for its +callees but not for its caller. +

+ +

4.3 Operators

+ +

The builtin operators are extended so that a BigFloat is returned if +at least one operand is a BigFloat. The computations are always done +with infinite precision and rounded according to the global floating +point environment. +

+

typeof applied on a BigFloat returns bigfloat. +

+

BigFloat can be compared with all the other numeric types and the +result follows the expected mathematical relations. +

+

However, since BigFloat and Number are different types they are never +equal when using the strict comparison operators (e.g. 0.0 === +0.0l is false). +

+ +

4.4 BigFloat literals

+ +

BigFloat literals are floating point numbers with a trailing l +suffix. BigFloat literals have an infinite precision. They are rounded +according to the global floating point environment when they are +evaluated.3 +

+ +

4.5 Builtin Object changes

+ + +

4.5.1 BigFloat function

+ +

The BigFloat function cannot be invoked as a constructor. When +invoked as a function: the parameter is converted to a primitive +type. If the result is a numeric type, it is converted to BigFloat +without rounding. If the result is a string, it is converted to +BigFloat using the precision of the global floating point environment. +

+

BigFloat properties: +

+
+
LN2
+
PI
+

Getter. Return the value of the corresponding mathematical constant +rounded to nearest, ties to even with the current global +precision. The constant values are cached for small precisions. +

+
+
MIN_VALUE
+
MAX_VALUE
+
EPSILON
+

Getter. Return the minimum, maximum and epsilon BigFloat values +(same definition as the corresponding Number constants). +

+
+
fpRound(a[, e])
+

Round the floating point number a according to the floating +point environment e or the global environment if e is +undefined. +

+
+
parseFloat(a[, radix[, e]])
+

Parse the string a as a floating point number in radix +radix. The radix is 0 (default) or from 2 to 36. The radix 0 +means radix 10 unless there is a hexadecimal or binary prefix. The +result is rounded according to the floating point environment e +or the global environment if e is undefined. +

+
+
isFinite(a)
+

Return true if a is a finite bigfloat. +

+
+
isNaN(a)
+

Return true if a is a NaN bigfloat. +

+
+
add(a, b[, e])
+
sub(a, b[, e])
+
mul(a, b[, e])
+
div(a, b[, e])
+

Perform the specified floating point operation and round the floating +point number a according to the floating point environment +e or the global environment if e is undefined. If +e is specified, the floating point status flags are updated. +

+
+
floor(x)
+
ceil(x)
+
round(x)
+
trunc(x)
+

Round to an integer. No additional rounding is performed. +

+
+
abs(x)
+

Return the absolute value of x. No additional rounding is performed. +

+
+
fmod(x, y[, e])
+
remainder(x, y[, e])
+

Floating point remainder. The quotient is truncated to zero (fmod) or +to the nearest integer with ties to even (remainder). e is an +optional floating point environment. +

+
+
sqrt(x[, e])
+

Square root. Return a rounded floating point number. e is an +optional floating point environment. +

+
+
sin(x[, e])
+
cos(x[, e])
+
tan(x[, e])
+
asin(x[, e])
+
acos(x[, e])
+
atan(x[, e])
+
atan2(x, y[, e])
+
exp(x[, e])
+
log(x[, e])
+
pow(x, y[, e])
+

Transcendental operations. Return a rounded floating point +number. e is an optional floating point environment. +

+
+
+ + +

4.5.2 BigFloat.prototype

+ +

The following properties are modified: +

+
+
valueOf()
+

Return the bigfloat primitive value corresponding to this. +

+
+
toString(radix)
+
+

For floating point numbers: +

+
    +
  • If the radix is a power of two, the conversion is done with infinite +precision. +
  • Otherwise, the number is rounded to nearest with ties to even using +the global precision. It is then converted to string using the minimum +number of digits so that its conversion back to a floating point using +the global precision and round to nearest gives the same number. + +
+ +

The exponent letter is e for base 10, p for bases 2, 8, +16 with a binary exponent and @ for the other bases. +

+
+
toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
+
toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
+
toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
+

Same semantics as the corresponding Number functions with +BigFloats. There is no limit on the accepted precision p. The +rounding mode and radix can be optionally specified. The radix must be +between 2 and 36. +

+
+
+ + +

4.5.3 BigFloatEnv constructor

+ +

The BigFloatEnv([p, [,rndMode]] constructor cannot be invoked as a +function. The floating point environment contains: +

+
    +
  • the mantissa precision in bits + +
  • the exponent size in bits assuming an IEEE 754 representation; + +
  • the subnormal flag (if true, subnormal floating point numbers can +be generated by the floating point operations). + +
  • the rounding mode + +
  • the floating point status. The status flags can only be set by the floating point operations. They can be reset with BigFloatEnv.prototype.clearStatus() or with the various status flag setters. + +
+ +

new BigFloatEnv([p, [,rndMode]] creates a new floating point +environment. The status flags are reset. If no parameter is given the +precision, exponent bits and subnormal flags are copied from the +global floating point environment. Otherwise, the precision is set to +p, the number of exponent bits is set to expBitsMax and the +subnormal flags is set to false. If rndMode is +undefined, the rounding mode is set to RNDN. +

+

BigFloatEnv properties: +

+
+
prec
+

Getter. Return the precision in bits of the global floating point +environment. The initial value is 113. +

+
+
expBits
+

Getter. Return the exponent size in bits of the global floating point +environment assuming an IEEE 754 representation. The initial value is +15. +

+
+
setPrec(f, p[, e])
+

Set the precision of the global floating point environment to p +and the exponent size to e then call the function +f. Then the Float precision and exponent size are reset to +their precious value and the return value of f is returned (or +an exception is raised if f raised an exception). If e +is undefined it is set to BigFloatEnv.expBitsMax. +

+
+
precMin
+

Read-only integer. Return the minimum allowed precision. Must be at least 2. +

+
+
precMax
+

Read-only integer. Return the maximum allowed precision. Must be at least 113. +

+
+
expBitsMin
+

Read-only integer. Return the minimum allowed exponent size in +bits. Must be at least 3. +

+
+
expBitsMax
+

Read-only integer. Return the maximum allowed exponent size in +bits. Must be at least 15. +

+
+
RNDN
+

Read-only integer. Round to nearest, with ties to even rounding mode. +

+
+
RNDZ
+

Read-only integer. Round to zero rounding mode. +

+
+
RNDD
+

Read-only integer. Round to -Infinity rounding mode. +

+
+
RNDU
+

Read-only integer. Round to +Infinity rounding mode. +

+
+
RNDNA
+

Read-only integer. Round to nearest, with ties away from zero rounding mode. +

+
+
RNDA
+

Read-only integer. Round away from zero rounding mode. +

+
+
RNDF4
+

Read-only integer. Faithful rounding mode. The result is +non-deterministically rounded to -Infinity or +Infinity. This rounding +mode usually gives a faster and deterministic running time for the +floating point operations. +

+
+
+ +

BigFloatEnv.prototype properties: +

+
+
prec
+

Getter and setter (Integer). Return or set the precision in bits. +

+
+
expBits
+

Getter and setter (Integer). Return or set the exponent size in bits +assuming an IEEE 754 representation. +

+
+
rndMode
+

Getter and setter (Integer). Return or set the rounding mode. +

+
+
subnormal
+

Getter and setter (Boolean). subnormal flag. It is false when +expBits = expBitsMax. +

+
+
clearStatus()
+

Clear the status flags. +

+
+
invalidOperation
+
divideByZero
+
overflow
+
underflow
+
inexact
+

Getter and setter (Boolean). Status flags. +

+
+
+ + +

5 BigDecimal

+ +

This extension adds the BigDecimal primitive type. The +BigDecimal type represents floating point numbers in base +10. It is inspired from the proposal available at +https://github.com/littledan/proposal-bigdecimal. +

+

The BigDecimal floating point numbers are always normalized and +finite. There is no concept of -0, Infinity or +NaN. By default, all the computations are done with infinite +precision. +

+ +

5.1 Operators

+ +

The following builtin operators support BigDecimal: +

+
+
+
+
-
+
*
+

Both operands must be BigDecimal. The result is computed with infinite +precision. +

+
%
+

Both operands must be BigDecimal. The result is computed with infinite +precision. A range error is throws in case of division by zero. +

+
+
/
+

Both operands must be BigDecimal. A range error is throws in case of +division by zero or if the result cannot be represented with infinite +precision (use BigDecimal.div to specify the rounding). +

+
+
**
+

Both operands must be BigDecimal. The exponent must be a positive +integer. The result is computed with infinite precision. +

+
+
===
+

When one of the operand is a BigDecimal, return true if both operands +are a BigDecimal and if they are equal. +

+
+
==
+
!=
+
<=
+
>=
+
<
+
>
+
+

Numerical comparison. When one of the operand is not a BigDecimal, it is +converted to BigDecimal by using ToString(). Hence comparisons between +Number and BigDecimal do not use the exact mathematical value of the +Number value. +

+
+
+ + +

5.2 BigDecimal literals

+ +

BigDecimal literals are decimal floating point numbers with a trailing +m suffix. +

+ +

5.3 Builtin Object changes

+ + +

5.3.1 The BigDecimal function.

+ +

It returns 0m if no parameter is provided. Otherwise the first +parameter is converted to a bigdecimal by using ToString(). Hence +Number values are not converted to their exact numerical value as +BigDecimal. +

+ +

5.3.2 Properties of the BigDecimal object

+ +
+
add(a, b[, e])
+
sub(a, b[, e])
+
mul(a, b[, e])
+
div(a, b[, e])
+
mod(a, b[, e])
+
sqrt(a, e)
+
round(a, e)
+

Perform the specified floating point operation and round the floating +point result according to the rounding object e. If the +rounding object is not present, the operation is executed with +infinite precision. +

+

For div, a RangeError exception is thrown in case of +division by zero or if the result cannot be represented with infinite +precision if no rounding object is present. +

+

For sqrt, a range error is thrown if a is less than +zero. +

+

The rounding object must contain the following properties: +roundingMode is a string specifying the rounding mode +("floor", "ceiling", "down", "up", +"half-even", "half-up"). Either +maximumSignificantDigits or maximumFractionDigits must +be present to specify respectively the number of significant digits +(must be >= 1) or the number of digits after the decimal point (must +be >= 0). +

+
+
+ + +

5.3.3 Properties of the BigDecimal.prototype object

+ +
+
valueOf()
+

Return the bigdecimal primitive value corresponding to this. +

+
+
toString()
+

Convert this to a string with infinite precision in base 10. +

+
+
toPrecision(p, rnd_mode = "half-up")
+
toFixed(p, rnd_mode = "half-up")
+
toExponential(p, rnd_mode = "half-up")
+

Convert the BigDecimal this to string with the specified +precision p. There is no limit on the accepted precision +p. The rounding mode can be optionally +specified. toPrecision outputs either in decimal fixed notation +or in decimal exponential notation with a p digits of +precision. toExponential outputs in decimal exponential +notation with p digits after the decimal point. toFixed +outputs in decimal notation with p digits after the decimal +point. +

+
+
+ + +

6 Math mode

+ +

A new math mode is enabled with the "use math" +directive. It propagates the same way as the strict mode. It is +designed so that arbitrarily large integers and floating point numbers +are available by default. In order to minimize the number of changes +in the Javascript semantics, integers are represented either as Number +or BigInt depending on their magnitude. Floating point numbers are +always represented as BigFloat. +

+

The following changes are made to the Javascript semantics: +

+
    +
  • Floating point literals (i.e. number with a decimal point or an exponent) are BigFloat by default (i.e. a l suffix is implied). Hence typeof 1.0 === "bigfloat". + +
  • Integer literals (i.e. numbers without a decimal point or an exponent) with or without the n suffix are BigInt if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to 2**53-1. Hence typeof 1 === "number ", typeof 1n === "number" but typeof 9007199254740992 === "bigint" . + +
  • All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt. + +
  • The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result. + +
  • The ^ operator is an alias to the power operator (**). + +
  • The power operator (both ^ and **) grammar is modified so that -2^2 is allowed and yields -4. + +
  • The logical xor operator is still available with the ^^ operator. + +
  • The modulo operator (%) returns the Euclidian remainder (always positive) instead of the truncated remainder. + +
  • The integer division operator can be overloaded with Operators.updateBigIntOperators(dictionary). + +
  • The integer power operator with a non zero negative exponent can be overloaded with Operators.updateBigIntOperators(dictionary). + +
+ +
+
+

Footnotes

+ +

(1)

+

The +rationale is that the rounding mode changes must always be +explicit.

+

(2)

+

The rationale is to avoid side effects for the built-in +operators.

+

(3)

+

Base 10 floating point literals cannot usually be +exactly represented as base 2 floating point number. In order to +ensure that the literal is represented accurately with the current +precision, it must be evaluated at runtime.

+

(4)

+

Could be removed in case a deterministic behavior for floating point operations is required.

+
+
+ + + + + diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/jsbignum.pdf b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/jsbignum.pdf similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/jsbignum.pdf rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/jsbignum.pdf diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/jsbignum.texi b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/jsbignum.texi similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/jsbignum.texi rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/jsbignum.texi diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/quickjs.html b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/quickjs.html new file mode 100644 index 00000000..1ac9c547 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/quickjs.html @@ -0,0 +1,1410 @@ + + + + +QuickJS Javascript Engine + + + + + + + + + + + + + + + +

QuickJS Javascript Engine

+ + +

Table of Contents

+ + + + + +

1 Introduction

+ +

QuickJS is a small and embeddable Javascript engine. It supports most of the +ES2023 specification +1 +including modules, asynchronous generators, proxies and BigInt. +

+

It supports mathematical extensions such as big decimal float float +numbers (BigDecimal), big binary floating point numbers (BigFloat), +and operator overloading. +

+ +

1.1 Main Features

+ +
    +
  • Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple “hello world” program. + +
  • Fast interpreter with very low startup time: runs the 77000 tests of the ECMAScript Test Suite2 in less than 2 minutes on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds. + +
  • Almost complete ES2023 support including modules, asynchronous +generators and full Annex B support (legacy web compatibility). Some +features from the upcoming ES2024 specification +3 are also supported. + +
  • Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2023 features. + +
  • Compile Javascript sources to executables with no external dependency. + +
  • Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal. + +
  • Mathematical extensions: BigDecimal, BigFloat, operator overloading, bigint mode, math mode. + +
  • Command line interpreter with contextual colorization and completion implemented in Javascript. + +
  • Small built-in standard library with C library wrappers. + +
+ + +

2 Usage

+ + +

2.1 Installation

+ +

A Makefile is provided to compile the engine on Linux or MacOS/X. A +preliminary Windows support is available thru cross compilation on a +Linux host with the MingGW tools. +

+

Edit the top of the Makefile if you wish to select specific +options then run make. +

+

You can type make install as root if you wish to install the binaries and support files to +/usr/local (this is not necessary to use QuickJS). +

+

Note: On some OSes atomic operations are not available or need a +specific library. If you get related errors, you should either add +-latomics in the Makefile LIBS variable or disable +CONFIG_ATOMICS in quickjs.c. +

+ +

2.2 Quick start

+ +

qjs is the command line interpreter (Read-Eval-Print Loop). You can pass +Javascript files and/or expressions as arguments to execute them: +

+
+
./qjs examples/hello.js
+
+ +

qjsc is the command line compiler: +

+
+
./qjsc -o hello examples/hello.js
+./hello
+
+ +

generates a hello executable with no external dependency. +

+ +

2.3 Command line options

+ + +

2.3.1 qjs interpreter

+ +
usage: qjs [options] [file [args]]
+
+

Options are: +

+
-h
+
--help
+

List options. +

+
+
-e EXPR
+
--eval EXPR
+

Evaluate EXPR. +

+
+
-i
+
--interactive
+

Go to interactive mode (it is not the default when files are provided on the command line). +

+
+
-m
+
--module
+

Load as ES6 module (default=autodetect). A module is autodetected if +the filename extension is .mjs or if the first keyword of the +source is import. +

+
+
--script
+

Load as ES6 script (default=autodetect). +

+
+
--bignum
+

Enable the bignum extensions: BigDecimal object, BigFloat object and +the "use math" directive. +

+
+
-I file
+
--include file
+

Include an additional file. +

+
+
+ +

Advanced options are: +

+
+
--std
+

Make the std and os modules available to the loaded +script even if it is not a module. +

+
+
-d
+
--dump
+

Dump the memory usage stats. +

+
+
-q
+
--quit
+

just instantiate the interpreter and quit. +

+
+
+ + +

2.3.2 qjsc compiler

+ +
usage: qjsc [options] [files]
+
+

Options are: +

+
-c
+

Only output bytecode in a C file. The default is to output an executable file. +

+
-e
+

Output main() and bytecode in a C file. The default is to output an +executable file. +

+
-o output
+

Set the output filename (default = out.c or a.out). +

+
+
-N cname
+

Set the C name of the generated data. +

+
+
-m
+

Compile as Javascript module (default=autodetect). +

+
+
-D module_name
+

Compile a dynamically loaded module and its dependencies. This option +is needed when your code uses the import keyword or the +os.Worker constructor because the compiler cannot statically +find the name of the dynamically loaded modules. +

+
+
-M module_name[,cname]
+

Add initialization code for an external C module. See the +c_module example. +

+
+
-x
+

Byte swapped output (only used for cross compilation). +

+
+
-flto
+

Use link time optimization. The compilation is slower but the +executable is smaller and faster. This option is automatically set +when the -fno-x options are used. +

+
+
-fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint]
+

Disable selected language features to produce a smaller executable file. +

+
+
-fbignum
+

Enable the bignum extensions: BigDecimal object, BigFloat object and +the "use math" directive. +

+
+
+ + +

2.4 qjscalc application

+ +

The qjscalc application is a superset of the qjs +command line interpreter implementing a Javascript calculator with +arbitrarily large integer and floating point numbers, fractions, +complex numbers, polynomials and matrices. The source code is in +qjscalc.js. More documentation and a web version are available at +http://numcalc.com. +

+ +

2.5 Built-in tests

+ +

Run make test to run the few built-in tests included in the +QuickJS archive. +

+ +

2.6 Test262 (ECMAScript Test Suite)

+ +

A test262 runner is included in the QuickJS archive. The test262 tests +can be installed in the QuickJS source directory with: +

+
+
git clone https://github.com/tc39/test262.git test262
+cd test262
+patch -p1 < ../tests/test262.patch
+cd ..
+
+ +

The patch adds the implementation specific harness functions +and optimizes the inefficient RegExp character classes and Unicode +property escapes tests (the tests themselves are not modified, only a +slow string initialization function is optimized). +

+

The tests can be run with +

+
make test2
+
+ +

The configuration files test262.conf +(resp. test262o.conf for the old ES5.1 tests4)) +contain the options to run the various tests. Tests can be excluded +based on features or filename. +

+

The file test262_errors.txt contains the current list of +errors. The runner displays a message when a new error appears or when +an existing error is corrected or modified. Use the -u option +to update the current list of errors (or make test2-update). +

+

The file test262_report.txt contains the logs of all the +tests. It is useful to have a clearer analysis of a particular +error. In case of crash, the last line corresponds to the failing +test. +

+

Use the syntax ./run-test262 -c test262.conf -f filename.js to +run a single test. Use the syntax ./run-test262 -c test262.conf +N to start testing at test number N. +

+

For more information, run ./run-test262 to see the command line +options of the test262 runner. +

+

run-test262 accepts the -N option to be invoked from +test262-harness5 +thru eshost. Unless you want to compare QuickJS with other +engines under the same conditions, we do not recommend to run the +tests this way as it is much slower (typically half an hour instead of +about 100 seconds). +

+ +

3 Specifications

+ + +

3.1 Language support

+ + +

3.1.1 ES2023 support

+ +

The ES2023 specification is almost fully supported including the Annex +B (legacy web compatibility) and the Unicode related features. +

+

The following features are not supported yet: +

+
    +
  • Tail calls6 + +
  • WeakRef and FinalizationRegistry objects + +
  • Symbols as WeakMap keys + +
+ + +

3.1.2 ECMA402

+ +

ECMA402 (Internationalization API) is not supported. +

+ +

3.1.3 Extensions

+ +
    +
  • The directive "use strip" indicates that the debug information (including the source code of the functions) should not be retained to save memory. As "use strict", the directive can be global to a script or local to a function. + +
  • The first line of a script beginning with #! is ignored. + +
+ + +

3.1.4 Mathematical extensions

+ +

The mathematical extensions are fully backward compatible with +standard Javascript. See jsbignum.pdf for more information. +

+
    +
  • BigDecimal support: arbitrary large floating point numbers in base 10. + +
  • BigFloat support: arbitrary large floating point numbers in base 2. + +
  • Operator overloading. + +
  • The directive "use bigint" enables the bigint mode where integers are BigInt by default. + +
  • The directive "use math" enables the math mode where the division and power operators on integers produce fractions. Floating point literals are BigFloat by default and integers are BigInt by default. + +
+ + +

3.2 Modules

+ +

ES6 modules are fully supported. The default name resolution is the +following: +

+
    +
  • Module names with a leading . or .. are relative +to the current module path. + +
  • Module names without a leading . or .. are system +modules, such as std or os. + +
  • Module names ending with .so are native modules using the +QuickJS C API. + +
+ + +

3.3 Standard library

+ +

The standard library is included by default in the command line +interpreter. It contains the two modules std and os and +a few global objects. +

+ +

3.3.1 Global objects

+ +
+
scriptArgs
+

Provides the command line arguments. The first argument is the script name. +

+
print(...args)
+

Print the arguments separated by spaces and a trailing newline. +

+
console.log(...args)
+

Same as print(). +

+
+
+ + +

3.3.2 std module

+ +

The std module provides wrappers to the libc stdlib.h +and stdio.h and a few other utilities. +

+

Available exports: +

+
+
exit(n)
+

Exit the process. +

+
+
evalScript(str, options = undefined)
+

Evaluate the string str as a script (global +eval). options is an optional object containing the following +optional properties: +

+
+
backtrace_barrier
+

Boolean (default = false). If true, error backtraces do not list the + stack frames below the evalScript. +

+
async
+

Boolean (default = false). If true, await is accepted in the + script and a promise is returned. +

+
+ +
+
loadScript(filename)
+

Evaluate the file filename as a script (global eval). +

+
+
loadFile(filename)
+

Load the file filename and return it as a string assuming UTF-8 +encoding. Return null in case of I/O error. +

+
+
open(filename, flags, errorObj = undefined)
+

Open a file (wrapper to the libc fopen()). Return the FILE +object or null in case of I/O error. If errorObj is not +undefined, set its errno property to the error code or to 0 if +no error occured. +

+
+
popen(command, flags, errorObj = undefined)
+

Open a process by creating a pipe (wrapper to the libc +popen()). Return the FILE +object or null in case of I/O error. If errorObj is not +undefined, set its errno property to the error code or to 0 if +no error occured. +

+
+
fdopen(fd, flags, errorObj = undefined)
+

Open a file from a file handle (wrapper to the libc +fdopen()). Return the FILE +object or null in case of I/O error. If errorObj is not +undefined, set its errno property to the error code or to 0 if +no error occured. +

+
+
tmpfile(errorObj = undefined)
+

Open a temporary file. Return the FILE +object or null in case of I/O error. If errorObj is not +undefined, set its errno property to the error code or to 0 if +no error occured. +

+
+
puts(str)
+

Equivalent to std.out.puts(str). +

+
+
printf(fmt, ...args)
+

Equivalent to std.out.printf(fmt, ...args). +

+
+
sprintf(fmt, ...args)
+

Equivalent to the libc sprintf(). +

+
+
in
+
out
+
err
+

Wrappers to the libc file stdin, stdout, stderr. +

+
+
SEEK_SET
+
SEEK_CUR
+
SEEK_END
+

Constants for seek(). +

+
+
Error
+
+

Enumeration object containing the integer value of common errors +(additional error codes may be defined): +

+
+
EINVAL
+
EIO
+
EACCES
+
EEXIST
+
ENOSPC
+
ENOSYS
+
EBUSY
+
ENOENT
+
EPERM
+
EPIPE
+
+ +
+
strerror(errno)
+

Return a string that describes the error errno. +

+
+
gc()
+

Manually invoke the cycle removal algorithm. The cycle removal +algorithm is automatically started when needed, so this function is +useful in case of specific memory constraints or for testing. +

+
+
getenv(name)
+

Return the value of the environment variable name or +undefined if it is not defined. +

+
+
setenv(name, value)
+

Set the value of the environment variable name to the string +value. +

+
+
unsetenv(name)
+

Delete the environment variable name. +

+
+
getenviron()
+

Return an object containing the environment variables as key-value pairs. +

+
+
urlGet(url, options = undefined)
+
+

Download url using the curl command line +utility. options is an optional object containing the following +optional properties: +

+
+
binary
+

Boolean (default = false). If true, the response is an ArrayBuffer + instead of a string. When a string is returned, the data is assumed + to be UTF-8 encoded. +

+
+
full
+
+

Boolean (default = false). If true, return the an object contains + the properties response (response content), + responseHeaders (headers separated by CRLF), status + (status code). response is null is case of protocol or + network error. If full is false, only the response is + returned if the status is between 200 and 299. Otherwise null + is returned. +

+
+
+ +
+
parseExtJSON(str)
+
+

Parse str using a superset of JSON.parse. The + following extensions are accepted: +

+
    +
  • Single line and multiline comments +
  • unquoted properties (ASCII-only Javascript identifiers) +
  • trailing comma in array and object definitions +
  • single quoted strings +
  • \f and \v are accepted as space characters +
  • leading plus in numbers +
  • octal (0o prefix) and hexadecimal (0x prefix) numbers +
+
+
+ +

FILE prototype: +

+
+
close()
+

Close the file. Return 0 if OK or -errno in case of I/O error. +

+
puts(str)
+

Outputs the string with the UTF-8 encoding. +

+
printf(fmt, ...args)
+

Formatted printf. +

+

The same formats as the standard C library printf are +supported. Integer format types (e.g. %d) truncate the Numbers +or BigInts to 32 bits. Use the l modifier (e.g. %ld) to +truncate to 64 bits. +

+
+
flush()
+

Flush the buffered file. +

+
seek(offset, whence)
+

Seek to a give file position (whence is +std.SEEK_*). offset can be a number or a bigint. Return +0 if OK or -errno in case of I/O error. +

+
tell()
+

Return the current file position. +

+
tello()
+

Return the current file position as a bigint. +

+
eof()
+

Return true if end of file. +

+
fileno()
+

Return the associated OS handle. +

+
error()
+

Return true if there was an error. +

+
clearerr()
+

Clear the error indication. +

+
+
read(buffer, position, length)
+

Read length bytes from the file to the ArrayBuffer buffer at byte +position position (wrapper to the libc fread). +

+
+
write(buffer, position, length)
+

Write length bytes to the file from the ArrayBuffer buffer at byte +position position (wrapper to the libc fwrite). +

+
+
getline()
+

Return the next line from the file, assuming UTF-8 encoding, excluding +the trailing line feed. +

+
+
readAsString(max_size = undefined)
+

Read max_size bytes from the file and return them as a string +assuming UTF-8 encoding. If max_size is not present, the file +is read up its end. +

+
+
getByte()
+

Return the next byte from the file. Return -1 if the end of file is reached. +

+
+
putByte(c)
+

Write one byte to the file. +

+
+ + +

3.3.3 os module

+ +

The os module provides Operating System specific functions: +

+
    +
  • low level file access +
  • signals +
  • timers +
  • asynchronous I/O +
  • workers (threads) +
+ +

The OS functions usually return 0 if OK or an OS specific negative +error code. +

+

Available exports: +

+
+
open(filename, flags, mode = 0o666)
+

Open a file. Return a handle or < 0 if error. +

+
+
O_RDONLY
+
O_WRONLY
+
O_RDWR
+
O_APPEND
+
O_CREAT
+
O_EXCL
+
O_TRUNC
+

POSIX open flags. +

+
+
O_TEXT
+

(Windows specific). Open the file in text mode. The default is binary mode. +

+
+
close(fd)
+

Close the file handle fd. +

+
+
seek(fd, offset, whence)
+

Seek in the file. Use std.SEEK_* for +whence. offset is either a number or a bigint. If +offset is a bigint, a bigint is returned too. +

+
+
read(fd, buffer, offset, length)
+

Read length bytes from the file handle fd to the +ArrayBuffer buffer at byte position offset. +Return the number of read bytes or < 0 if error. +

+
+
write(fd, buffer, offset, length)
+

Write length bytes to the file handle fd from the +ArrayBuffer buffer at byte position offset. +Return the number of written bytes or < 0 if error. +

+
+
isatty(fd)
+

Return true is fd is a TTY (terminal) handle. +

+
+
ttyGetWinSize(fd)
+

Return the TTY size as [width, height] or null if not available. +

+
+
ttySetRaw(fd)
+

Set the TTY in raw mode. +

+
+
remove(filename)
+

Remove a file. Return 0 if OK or -errno. +

+
+
rename(oldname, newname)
+

Rename a file. Return 0 if OK or -errno. +

+
+
realpath(path)
+

Return [str, err] where str is the canonicalized absolute +pathname of path and err the error code. +

+
+
getcwd()
+

Return [str, err] where str is the current working directory +and err the error code. +

+
+
chdir(path)
+

Change the current directory. Return 0 if OK or -errno. +

+
+
mkdir(path, mode = 0o777)
+

Create a directory at path. Return 0 if OK or -errno. +

+
+
stat(path)
+
lstat(path)
+
+

Return [obj, err] where obj is an object containing the +file status of path. err is the error code. The +following fields are defined in obj: dev, ino, mode, nlink, +uid, gid, rdev, size, blocks, atime, mtime, ctime. The times are +specified in milliseconds since 1970. lstat() is the same as +stat() excepts that it returns information about the link +itself. +

+
+
S_IFMT
+
S_IFIFO
+
S_IFCHR
+
S_IFDIR
+
S_IFBLK
+
S_IFREG
+
S_IFSOCK
+
S_IFLNK
+
S_ISGID
+
S_ISUID
+

Constants to interpret the mode property returned by +stat(). They have the same value as in the C system header +sys/stat.h. +

+
+
utimes(path, atime, mtime)
+

Change the access and modification times of the file path. The +times are specified in milliseconds since 1970. Return 0 if OK or -errno. +

+
+
symlink(target, linkpath)
+

Create a link at linkpath containing the string target. Return 0 if OK or -errno. +

+
+
readlink(path)
+

Return [str, err] where str is the link target and err +the error code. +

+
+
readdir(path)
+

Return [array, err] where array is an array of strings +containing the filenames of the directory path. err is +the error code. +

+
+
setReadHandler(fd, func)
+

Add a read handler to the file handle fd. func is called +each time there is data pending for fd. A single read handler +per file handle is supported. Use func = null to remove the +handler. +

+
+
setWriteHandler(fd, func)
+

Add a write handler to the file handle fd. func is +called each time data can be written to fd. A single write +handler per file handle is supported. Use func = null to remove +the handler. +

+
+
signal(signal, func)
+

Call the function func when the signal signal +happens. Only a single handler per signal number is supported. Use +null to set the default handler or undefined to ignore +the signal. Signal handlers can only be defined in the main thread. +

+
+
SIGINT
+
SIGABRT
+
SIGFPE
+
SIGILL
+
SIGSEGV
+
SIGTERM
+

POSIX signal numbers. +

+
+
kill(pid, sig)
+

Send the signal sig to the process pid. +

+
+
exec(args[, options])
+

Execute a process with the arguments args. options is an +object containing optional parameters: +

+
+
block
+

Boolean (default = true). If true, wait until the process is + terminated. In this case, exec return the exit code if positive + or the negated signal number if the process was interrupted by a + signal. If false, do not block and return the process id of the child. +

+
+
usePath
+

Boolean (default = true). If true, the file is searched in the + PATH environment variable. +

+
+
file
+

String (default = args[0]). Set the file to be executed. +

+
+
cwd
+

String. If present, set the working directory of the new process. +

+
+
stdin
+
stdout
+
stderr
+

If present, set the handle in the child for stdin, stdout or stderr. +

+
+
env
+

Object. If present, set the process environment from the object + key-value pairs. Otherwise use the same environment as the current + process. +

+
+
uid
+

Integer. If present, the process uid with setuid. +

+
+
gid
+

Integer. If present, the process gid with setgid. +

+
+
+ +
+
getpid()
+

Return the current process ID. +

+
+
waitpid(pid, options)
+

waitpid Unix system call. Return the array [ret, +status]. ret contains -errno in case of error. +

+
+
WNOHANG
+

Constant for the options argument of waitpid. +

+
+
dup(fd)
+

dup Unix system call. +

+
+
dup2(oldfd, newfd)
+

dup2 Unix system call. +

+
+
pipe()
+

pipe Unix system call. Return two handles as [read_fd, +write_fd] or null in case of error. +

+
+
sleep(delay_ms)
+

Sleep during delay_ms milliseconds. +

+
+
sleepAsync(delay_ms)
+

Asynchronouse sleep during delay_ms milliseconds. Returns a promise. Example: +

+
await os.sleepAsync(500);
+
+ +
+
now()
+

Return a timestamp in milliseconds with more precision than +Date.now(). The time origin is unspecified and is normally not +impacted by system clock adjustments. +

+
+
setTimeout(func, delay)
+

Call the function func after delay ms. Return a handle +to the timer. +

+
+
clearTimeout(handle)
+

Cancel a timer. +

+
+
platform
+

Return a string representing the platform: "linux", "darwin", +"win32" or "js". +

+
+
Worker(module_filename)
+

Constructor to create a new thread (worker) with an API close to the +WebWorkers. module_filename is a string specifying the +module filename which is executed in the newly created thread. As for +dynamically imported module, it is relative to the current script or +module path. Threads normally don’t share any data and communicate +between each other with messages. Nested workers are not supported. An +example is available in tests/test_worker.js. +

+

The worker class has the following static properties: +

+
+
parent
+

In the created worker, Worker.parent represents the parent + worker and is used to send or receive messages. +

+
+ +

The worker instances have the following properties: +

+
+
postMessage(msg)
+
+

Send a message to the corresponding worker. msg is cloned in + the destination worker using an algorithm similar to the HTML + structured clone algorithm. SharedArrayBuffer are shared + between workers. +

+

Current limitations: Map and Set are not supported + yet. +

+
+
onmessage
+
+

Getter and setter. Set a function which is called each time a + message is received. The function is called with a single + argument. It is an object with a data property containing the + received message. The thread is not terminated if there is at least + one non null onmessage handler. +

+
+
+ +
+
+ + +

3.4 QuickJS C API

+ +

The C API was designed to be simple and efficient. The C API is +defined in the header quickjs.h. +

+ +

3.4.1 Runtime and contexts

+ +

JSRuntime represents a Javascript runtime corresponding to an +object heap. Several runtimes can exist at the same time but they +cannot exchange objects. Inside a given runtime, no multi-threading is +supported. +

+

JSContext represents a Javascript context (or Realm). Each +JSContext has its own global objects and system objects. There can be +several JSContexts per JSRuntime and they can share objects, similar +to frames of the same origin sharing Javascript objects in a +web browser. +

+ +

3.4.2 JSValue

+ +

JSValue represents a Javascript value which can be a primitive +type or an object. Reference counting is used, so it is important to +explicitly duplicate (JS_DupValue(), increment the reference +count) or free (JS_FreeValue(), decrement the reference count) +JSValues. +

+ +

3.4.3 C functions

+ +

C functions can be created with +JS_NewCFunction(). JS_SetPropertyFunctionList() is a +shortcut to easily add functions, setters and getters properties to a +given object. +

+

Unlike other embedded Javascript engines, there is no implicit stack, +so C functions get their parameters as normal C parameters. As a +general rule, C functions take constant JSValues as parameters +(so they don’t need to free them) and return a newly allocated (=live) +JSValue. +

+ +

3.4.4 Exceptions

+ +

Exceptions: most C functions can return a Javascript exception. It +must be explicitly tested and handled by the C code. The specific +JSValue JS_EXCEPTION indicates that an exception +occurred. The actual exception object is stored in the +JSContext and can be retrieved with JS_GetException(). +

+ +

3.4.5 Script evaluation

+ +

Use JS_Eval() to evaluate a script or module source. +

+

If the script or module was compiled to bytecode with qjsc, it +can be evaluated by calling js_std_eval_binary(). The advantage +is that no compilation is needed so it is faster and smaller because +the compiler can be removed from the executable if no eval is +required. +

+

Note: the bytecode format is linked to a given QuickJS +version. Moreover, no security check is done before its +execution. Hence the bytecode should not be loaded from untrusted +sources. That’s why there is no option to output the bytecode to a +binary file in qjsc. +

+ +

3.4.6 JS Classes

+ +

C opaque data can be attached to a Javascript object. The type of the +C opaque data is determined with the class ID (JSClassID) of +the object. Hence the first step is to register a new class ID and JS +class (JS_NewClassID(), JS_NewClass()). Then you can +create objects of this class with JS_NewObjectClass() and get or +set the C opaque point with +JS_GetOpaque()/JS_SetOpaque(). +

+

When defining a new JS class, it is possible to declare a finalizer +which is called when the object is destroyed. The finalizer should be +used to release C resources. It is invalid to execute JS code from +it. A gc_mark method can be provided so that the cycle removal +algorithm can find the other objects referenced by this object. Other +methods are available to define exotic object behaviors. +

+

The Class ID are globally allocated (i.e. for all runtimes). The +JSClass are allocated per JSRuntime. JS_SetClassProto() +is used to define a prototype for a given class in a given +JSContext. JS_NewObjectClass() sets this prototype in the +created object. +

+

Examples are available in quickjs-libc.c. +

+ +

3.4.7 C Modules

+ +

Native ES6 modules are supported and can be dynamically or statically +linked. Look at the test_bjson and bjson.so +examples. The standard library quickjs-libc.c is also a good example +of a native module. +

+ +

3.4.8 Memory handling

+ +

Use JS_SetMemoryLimit() to set a global memory allocation limit +to a given JSRuntime. +

+

Custom memory allocation functions can be provided with +JS_NewRuntime2(). +

+

The maximum system stack size can be set with JS_SetMaxStackSize(). +

+ +

3.4.9 Execution timeout and interrupts

+ +

Use JS_SetInterruptHandler() to set a callback which is +regularly called by the engine when it is executing code. This +callback can be used to implement an execution timeout. +

+

It is used by the command line interpreter to implement a +Ctrl-C handler. +

+ +

4 Internals

+ + +

4.1 Bytecode

+ +

The compiler generates bytecode directly with no intermediate +representation such as a parse tree, hence it is very fast. Several +optimizations passes are done over the generated bytecode. +

+

A stack-based bytecode was chosen because it is simple and generates +compact code. +

+

For each function, the maximum stack size is computed at compile time so that +no runtime stack overflow tests are needed. +

+

A separate compressed line number table is maintained for the debug +information. +

+

Access to closure variables is optimized and is almost as fast as local +variables. +

+

Direct eval in strict mode is optimized. +

+ +

4.2 Executable generation

+ + +

4.2.1 qjsc compiler

+ +

The qjsc compiler generates C sources from Javascript files. By +default the C sources are compiled with the system compiler +(gcc or clang). +

+

The generated C source contains the bytecode of the compiled functions +or modules. If a full complete executable is needed, it also +contains a main() function with the necessary C code to initialize the +Javascript engine and to load and execute the compiled functions and +modules. +

+

Javascript code can be mixed with C modules. +

+

In order to have smaller executables, specific Javascript features can +be disabled, in particular eval or the regular expressions. The +code removal relies on the Link Time Optimization of the system +compiler. +

+ +

4.2.2 Binary JSON

+ +

qjsc works by compiling scripts or modules and then serializing +them to a binary format. A subset of this format (without functions or +modules) can be used as binary JSON. The example test_bjson.js +shows how to use it. +

+

Warning: the binary JSON format may change without notice, so it +should not be used to store persistent data. The test_bjson.js +example is only used to test the binary object format functions. +

+ +

4.3 Runtime

+ + +

4.3.1 Strings

+ +

Strings are stored either as an 8 bit or a 16 bit array of +characters. Hence random access to characters is always fast. +

+

The C API provides functions to convert Javascript Strings to C UTF-8 encoded +strings. The most common case where the Javascript string contains +only ASCII characters involves no copying. +

+ +

4.3.2 Objects

+ +

The object shapes (object prototype, property names and flags) are shared +between objects to save memory. +

+

Arrays with no holes (except at the end of the array) are optimized. +

+

TypedArray accesses are optimized. +

+ +

4.3.3 Atoms

+ +

Object property names and some strings are stored as Atoms (unique +strings) to save memory and allow fast comparison. Atoms are +represented as a 32 bit integer. Half of the atom range is reserved for +immediate integer literals from 0 to 2^{31}-1. +

+ +

4.3.4 Numbers

+ +

Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754 +floating point values. Most operations have fast paths for the 32-bit +integer case. +

+ +

4.3.5 Garbage collection

+ +

Reference counting is used to free objects automatically and +deterministically. A separate cycle removal pass is done when the allocated +memory becomes too large. The cycle removal algorithm only uses the +reference counts and the object content, so no explicit garbage +collection roots need to be manipulated in the C code. +

+ +

4.3.6 JSValue

+ +

It is a Javascript value which can be a primitive type (such as +Number, String, ...) or an Object. NaN boxing is used in the 32-bit version +to store 64-bit floating point numbers. The representation is +optimized so that 32-bit integers and reference counted values can be +efficiently tested. +

+

In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The +rationale is that in 64-bit code memory usage is less critical. +

+

In both cases (32 or 64 bits), JSValue exactly fits two CPU registers, +so it can be efficiently returned by C functions. +

+ +

4.3.7 Function call

+ +

The engine is optimized so that function calls are fast. The system +stack holds the Javascript parameters and local variables. +

+ +

4.4 RegExp

+ +

A specific regular expression engine was developed. It is both small +and efficient and supports all the ES2023 features including the +Unicode properties. As the Javascript compiler, it directly generates +bytecode without a parse tree. +

+

Backtracking with an explicit stack is used so that there is no +recursion on the system stack. Simple quantifiers are specifically +optimized to avoid recursions. +

+

The full regexp library weights about 15 KiB (x86 code), excluding the +Unicode library. +

+ +

4.5 Unicode

+ +

A specific Unicode library was developed so that there is no +dependency on an external large Unicode library such as ICU. All the +Unicode tables are compressed while keeping a reasonable access +speed. +

+

The library supports case conversion, Unicode normalization, Unicode +script queries, Unicode general category queries and all Unicode +binary properties. +

+

The full Unicode library weights about 45 KiB (x86 code). +

+ +

4.6 BigInt, BigFloat, BigDecimal

+ +

BigInt, BigFloat and BigDecimal are implemented with the libbf +library7. It weights about 90 +KiB (x86 code) and provides arbitrary precision IEEE 754 floating +point operations and transcendental functions with exact rounding. +

+ +

5 License

+ +

QuickJS is released under the MIT license. +

+

Unless otherwise specified, the QuickJS sources are copyright Fabrice +Bellard and Charlie Gordon. +

+
+
+

Footnotes

+ +

(1)

+

https://tc39.es/ecma262/2023

+

(2)

+

https://github.com/tc39/test262

+

(3)

+

https://tc39.es/ecma262/

+

(4)

+

The old +ES5.1 tests can be extracted with git clone --single-branch +--branch es5-tests https://github.com/tc39/test262.git test262o

+

(5)

+

https://github.com/bterlson/test262-harness

+

(6)

+

We believe the current specification of tails calls is too complicated and presents limited practical interests.

+

(7)

+

https://bellard.org/libbf

+
+
+ + + + + diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/quickjs.pdf b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/quickjs.pdf similarity index 58% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/quickjs.pdf rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/quickjs.pdf index 53c8e7345eb94d10edfd7e6c01be7357be2634b6..2338d7a723de6ba18542ac3797ea7da27576c70a 100644 GIT binary patch delta 69931 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

{tkUM!KDM$aq1r#-HH2uN?QP%FztYR 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 delta 68461 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 diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/quickjs.texi b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/quickjs.texi similarity index 95% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/quickjs.texi rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/quickjs.texi index 9eb6354b..898d46c8 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/doc/quickjs.texi +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/doc/quickjs.texi @@ -19,9 +19,9 @@ @chapter Introduction -QuickJS is a small and embeddable Javascript engine. It supports the -ES2020 specification -@footnote{@url{https://tc39.es/ecma262/}} +QuickJS is a small and embeddable Javascript engine. It supports most of the +ES2023 specification +@footnote{@url{https://tc39.es/ecma262/2023 }} including modules, asynchronous generators, proxies and BigInt. It supports mathematical extensions such as big decimal float float @@ -34,14 +34,14 @@ and operator overloading. @item Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple ``hello world'' program. -@item Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds. +@item Fast interpreter with very low startup time: runs the 77000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in less than 2 minutes on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds. -@item Almost complete ES2020 support including modules, asynchronous -generators and full Annex B support (legacy web compatibility). Many -features from the upcoming ES2021 specification -@footnote{@url{https://tc39.github.io/ecma262/}} are also supported. +@item Almost complete ES2023 support including modules, asynchronous +generators and full Annex B support (legacy web compatibility). Some +features from the upcoming ES2024 specification +@footnote{@url{https://tc39.es/ecma262/}} are also supported. -@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2020 features. +@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2023 features. @item Compile Javascript sources to executables with no external dependency. @@ -69,6 +69,11 @@ options then run @code{make}. You can type @code{make install} as root if you wish to install the binaries and support files to @code{/usr/local} (this is not necessary to use QuickJS). +Note: On some OSes atomic operations are not available or need a +specific library. If you get related errors, you should either add +@code{-latomics} in the Makefile @code{LIBS} variable or disable +@code{CONFIG_ATOMICS} in @file{quickjs.c}. + @section Quick start @code{qjs} is the command line interpreter (Read-Eval-Print Loop). You can pass @@ -265,9 +270,9 @@ about 100 seconds). @section Language support -@subsection ES2020 support +@subsection ES2023 support -The ES2020 specification is almost fully supported including the Annex +The ES2023 specification is almost fully supported including the Annex B (legacy web compatibility) and the Unicode related features. The following features are not supported yet: @@ -276,6 +281,10 @@ The following features are not supported yet: @item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.} +@item WeakRef and FinalizationRegistry objects + +@item Symbols as WeakMap keys + @end itemize @subsection ECMA402 @@ -368,6 +377,9 @@ optional properties: @item backtrace_barrier Boolean (default = false). If true, error backtraces do not list the stack frames below the evalScript. + @item async + Boolean (default = false). If true, @code{await} is accepted in the + script and a promise is returned. @end table @item loadScript(filename) @@ -749,6 +761,9 @@ object containing optional parameters: @end table +@item getpid() +Return the current process ID. + @item waitpid(pid, options) @code{waitpid} Unix system call. Return the array @code{[ret, status]}. @code{ret} contains @code{-errno} in case of error. @@ -769,6 +784,17 @@ write_fd]} or null in case of error. @item sleep(delay_ms) Sleep during @code{delay_ms} milliseconds. +@item sleepAsync(delay_ms) +Asynchronouse sleep during @code{delay_ms} milliseconds. Returns a promise. Example: +@example +await os.sleepAsync(500); +@end example + +@item now() +Return a timestamp in milliseconds with more precision than +@code{Date.now()}. The time origin is unspecified and is normally not +impacted by system clock adjustments. + @item setTimeout(func, delay) Call the function @code{func} after @code{delay} ms. Return a handle to the timer. @@ -1053,7 +1079,7 @@ stack holds the Javascript parameters and local variables. @section RegExp A specific regular expression engine was developed. It is both small -and efficient and supports all the ES2020 features including the +and efficient and supports all the ES2023 features including the Unicode properties. As the Javascript compiler, it directly generates bytecode without a parse tree. @@ -1061,9 +1087,6 @@ Backtracking with an explicit stack is used so that there is no recursion on the system stack. Simple quantifiers are specifically optimized to avoid recursions. -Infinite recursions coming from quantifiers with empty terms are -avoided. - The full regexp library weights about 15 KiB (x86 code), excluding the Unicode library. diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libbf.c b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libbf.c similarity index 99% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/libbf.c rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libbf.c index fe1628e7..234b956b 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libbf.c +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libbf.c @@ -37,10 +37,12 @@ /* enable it to check the multiplication result */ //#define USE_MUL_CHECK +#ifdef CONFIG_BIGNUM /* enable it to use FFT/NTT multiplication */ #define USE_FFT_MUL /* enable decimal floating point support */ #define USE_BF_DEC +#endif //#define inline __attribute__((always_inline)) @@ -164,6 +166,21 @@ static inline slimb_t sat_add(slimb_t a, slimb_t b) return r; } +static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift) +{ + if (shift != 0) + low = (low >> shift) | (high << (LIMB_BITS - shift)); + return low; +} + +static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift) +{ + if (shift != 0) + return (a1 << shift) | (a0 >> (LIMB_BITS - shift)); + else + return a1; +} + #define malloc(s) malloc_is_forbidden(s) #define free(p) free_is_forbidden(p) #define realloc(p, s) realloc_is_forbidden(p, s) @@ -236,7 +253,7 @@ int bf_set_ui(bf_t *r, uint64_t a) a1 = a >> 32; shift = clz(a1); r->tab[0] = a0 << shift; - r->tab[1] = (a1 << shift) | (a0 >> (LIMB_BITS - shift)); + r->tab[1] = shld(a1, a0, shift); r->expn = 2 * LIMB_BITS - shift; } #endif @@ -1585,7 +1602,9 @@ int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, r = &tmp; } if (bf_resize(r, a_len + b_len)) { +#ifdef USE_FFT_MUL fail: +#endif bf_set_nan(r); ret = BF_ST_MEM_ERROR; goto done; @@ -2282,11 +2301,14 @@ static int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b, bf_t a; int ret; +#ifdef USE_BF_DEC if (a1 == 10 && b <= LIMB_DIGITS) { /* use precomputed powers. We do not round at this point because we expect the caller to do it */ ret = bf_set_ui(r, mp_pow_dec[b]); - } else { + } else +#endif + { bf_init(r->ctx, &a); ret = bf_set_ui(&a, a1); ret |= bf_pow_ui(r, &a, b, prec, flags); @@ -5392,21 +5414,6 @@ int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) #endif /* LIMB_BITS != 64 */ -static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift) -{ - if (shift != 0) - low = (low >> shift) | (high << (LIMB_BITS - shift)); - return low; -} - -static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift) -{ - if (shift != 0) - return (a1 << shift) | (a0 >> (LIMB_BITS - shift)); - else - return a1; -} - #if LIMB_DIGITS == 19 /* WARNING: hardcoded for b = 1e19. It is assumed that: diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libbf.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libbf.h similarity index 99% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/libbf.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libbf.h index 48e9d956..0457c180 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libbf.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libbf.h @@ -27,7 +27,7 @@ #include #include -#if INTPTR_MAX >= INT64_MAX +#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX) #define LIMB_LOG2_BITS 6 #else #define LIMB_LOG2_BITS 5 diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libregexp-opcode.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libregexp-opcode.h similarity index 95% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/libregexp-opcode.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libregexp-opcode.h index f90c23b3..189d1215 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libregexp-opcode.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libregexp-opcode.h @@ -50,8 +50,7 @@ DEF(range32, 3) /* variable length */ DEF(lookahead, 5) DEF(negative_lookahead, 5) DEF(push_char_pos, 1) /* push the character position on the stack */ -DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character - position */ +DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */ DEF(prev, 1) /* go to the previous char */ DEF(simple_greedy_quant, 17) diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libregexp.c b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libregexp.c similarity index 94% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/libregexp.c rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libregexp.c index 379bfc7a..b6af4548 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libregexp.c +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libregexp.c @@ -34,9 +34,6 @@ /* TODO: - - Add full unicode canonicalize rules for character ranges (not - really useful but needed for exact "ignorecase" compatibility). - - Add a lock step execution mode (=linear time execution guaranteed) when the regular expression is "simple" i.e. no backreference nor complicated lookahead. The opcodes are designed for this execution @@ -120,33 +117,6 @@ static int dbuf_insert(DynBuf *s, int pos, int len) return 0; } -/* canonicalize with the specific JS regexp rules */ -static uint32_t lre_canonicalize(uint32_t c, BOOL is_utf16) -{ - uint32_t res[LRE_CC_RES_LEN_MAX]; - int len; - if (is_utf16) { - if (likely(c < 128)) { - if (c >= 'A' && c <= 'Z') - c = c - 'A' + 'a'; - } else { - lre_case_conv(res, c, 2); - c = res[0]; - } - } else { - if (likely(c < 128)) { - if (c >= 'a' && c <= 'z') - c = c - 'a' + 'A'; - } else { - /* legacy regexp: to upper case if single char >= 128 */ - len = lre_case_conv(res, c, FALSE); - if (len == 1 && res[0] >= 128) - c = res[0]; - } - } - return c; -} - static const uint16_t char_range_d[] = { 1, 0x0030, 0x0039 + 1, @@ -245,31 +215,6 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c) return -1; } -static int cr_canonicalize(CharRange *cr) -{ - CharRange a; - uint32_t pt[2]; - int i, ret; - - cr_init(&a, cr->mem_opaque, lre_realloc); - pt[0] = 'a'; - pt[1] = 'z' + 1; - ret = cr_op(&a, cr->points, cr->len, pt, 2, CR_OP_INTER); - if (ret) - goto fail; - /* convert to upper case */ - /* XXX: the generic unicode case would be much more complicated - and not really useful */ - for(i = 0; i < a.len; i++) { - a.points[i] += 'A' - 'a'; - } - /* Note: for simplicity we keep the lower case ranges */ - ret = cr_union1(cr, a.points, a.len); - fail: - cr_free(&a); - return ret; -} - #ifdef DUMP_REOP static __maybe_unused void lre_dump_bytecode(const uint8_t *buf, int buf_len) @@ -335,7 +280,6 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf, case REOP_loop: case REOP_lookahead: case REOP_negative_lookahead: - case REOP_bne_char_pos: val = get_u32(buf + pos + 1); val += (pos + 5); printf(" %u", val); @@ -922,7 +866,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp) } } if (s->ignore_case) { - if (cr_canonicalize(cr)) + if (cr_regexp_canonicalize(cr, s->is_utf16)) goto memory_error; } if (invert) { @@ -943,22 +887,17 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp) } /* Return: - 1 if the opcodes in bc_buf[] always advance the character pointer. - 0 if the character pointer may not be advanced. - -1 if the code may depend on side effects of its previous execution (backreference) + - true if the opcodes may not advance the char pointer + - false if the opcodes always advance the char pointer */ -static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len) +static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len) { - int pos, opcode, ret, len, i; - uint32_t val, last; - BOOL has_back_reference; - uint8_t capture_bitmap[CAPTURE_COUNT_MAX]; + int pos, opcode, len; + uint32_t val; + BOOL ret; - ret = -2; /* not known yet */ + ret = TRUE; pos = 0; - has_back_reference = FALSE; - memset(capture_bitmap, 0, sizeof(capture_bitmap)); - while (pos < bc_buf_len) { opcode = bc_buf[pos]; len = reopcode_info[opcode].size; @@ -976,8 +915,7 @@ static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len) case REOP_dot: case REOP_any: simple_char: - if (ret == -2) - ret = 1; + ret = FALSE; break; case REOP_line_start: case REOP_line_end: @@ -991,41 +929,16 @@ static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len) break; case REOP_save_start: case REOP_save_end: - val = bc_buf[pos + 1]; - capture_bitmap[val] |= 1; - break; case REOP_save_reset: - { - val = bc_buf[pos + 1]; - last = bc_buf[pos + 2]; - while (val < last) - capture_bitmap[val++] |= 1; - } - break; case REOP_back_reference: case REOP_backward_back_reference: - val = bc_buf[pos + 1]; - capture_bitmap[val] |= 2; - has_back_reference = TRUE; break; default: /* safe behvior: we cannot predict the outcome */ - if (ret == -2) - ret = 0; - break; + return TRUE; } pos += len; } - if (has_back_reference) { - /* check if there is back reference which references a capture - made in the some code */ - for(i = 0; i < CAPTURE_COUNT_MAX; i++) { - if (capture_bitmap[i] == 3) - return -1; - } - } - if (ret == -2) - ret = 0; return ret; } @@ -1071,11 +984,10 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len) } /* '*pp' is the first char after '<' */ -static int re_parse_group_name(char *buf, int buf_size, - const uint8_t **pp, BOOL is_utf16) +static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp) { - const uint8_t *p; - uint32_t c; + const uint8_t *p, *p1; + uint32_t c, d; char *q; p = *pp; @@ -1086,11 +998,18 @@ static int re_parse_group_name(char *buf, int buf_size, p++; if (*p != 'u') return -1; - c = lre_parse_escape(&p, is_utf16 * 2); + c = lre_parse_escape(&p, 2); // accept surrogate pairs } else if (c == '>') { break; } else if (c >= 128) { c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); + if (c >= 0xD800 && c <= 0xDBFF) { + d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); + if (d >= 0xDC00 && d <= 0xDFFF) { + c = 0x10000 + 0x400 * (c - 0xD800) + (d - 0xDC00); + p = p1; + } + } } else { p++; } @@ -1140,8 +1059,7 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures, /* potential named capture */ if (capture_name) { p += 3; - if (re_parse_group_name(name, sizeof(name), &p, - s->is_utf16) == 0) { + if (re_parse_group_name(name, sizeof(name), &p) == 0) { if (!strcmp(name, capture_name)) return capture_index; } @@ -1314,7 +1232,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) } else if (p[2] == '<') { p += 3; if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf), - &p, s->is_utf16)) { + &p)) { return re_parse_error(s, "invalid group name"); } if (find_group_name(s, s->u.tmp_buf) > 0) { @@ -1378,7 +1296,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) } p1 += 3; if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf), - &p1, s->is_utf16)) { + &p1)) { if (s->is_utf16 || re_has_named_captures(s)) return re_parse_error(s, "invalid group name"); else @@ -1591,8 +1509,12 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) if (dbuf_error(&s->byte_code)) goto out_of_memory; - add_zero_advance_check = (re_check_advance(s->byte_code.buf + last_atom_start, - s->byte_code.size - last_atom_start) == 0); + /* the spec tells that if there is no advance when + running the atom after the first quant_min times, + then there is no match. We remove this test when we + are sure the atom always advances the position. */ + add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start, + s->byte_code.size - last_atom_start); } else { add_zero_advance_check = FALSE; } @@ -1612,38 +1534,34 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) } if (quant_max == 0) { s->byte_code.size = last_atom_start; - } else if (quant_max == 1) { - if (dbuf_insert(&s->byte_code, last_atom_start, 5)) - goto out_of_memory; - s->byte_code.buf[last_atom_start] = REOP_split_goto_first + - greedy; - put_u32(s->byte_code.buf + last_atom_start + 1, len); - } else if (quant_max == INT32_MAX) { + } else if (quant_max == 1 || quant_max == INT32_MAX) { + BOOL has_goto = (quant_max == INT32_MAX); if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check)) goto out_of_memory; s->byte_code.buf[last_atom_start] = REOP_split_goto_first + greedy; put_u32(s->byte_code.buf + last_atom_start + 1, - len + 5 + add_zero_advance_check); + len + 5 * has_goto + add_zero_advance_check * 2); if (add_zero_advance_check) { - /* avoid infinite loop by stoping the - recursion if no advance was made in the - atom (only works if the atom has no - side effect) */ s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos; - re_emit_goto(s, REOP_bne_char_pos, last_atom_start); - } else { - re_emit_goto(s, REOP_goto, last_atom_start); + re_emit_op(s, REOP_check_advance); } + if (has_goto) + re_emit_goto(s, REOP_goto, last_atom_start); } else { - if (dbuf_insert(&s->byte_code, last_atom_start, 10)) + if (dbuf_insert(&s->byte_code, last_atom_start, 10 + add_zero_advance_check)) goto out_of_memory; pos = last_atom_start; s->byte_code.buf[pos++] = REOP_push_i32; put_u32(s->byte_code.buf + pos, quant_max); pos += 4; s->byte_code.buf[pos++] = REOP_split_goto_first + greedy; - put_u32(s->byte_code.buf + pos, len + 5); + put_u32(s->byte_code.buf + pos, len + 5 + add_zero_advance_check * 2); + pos += 4; + if (add_zero_advance_check) { + s->byte_code.buf[pos++] = REOP_push_char_pos; + re_emit_op(s, REOP_check_advance); + } re_emit_goto(s, REOP_loop, last_atom_start + 5); re_emit_op(s, REOP_drop); } @@ -1667,22 +1585,25 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) if (quant_max == INT32_MAX) { pos = s->byte_code.size; re_emit_op_u32(s, REOP_split_goto_first + greedy, - len + 5 + add_zero_advance_check); + len + 5 + add_zero_advance_check * 2); if (add_zero_advance_check) re_emit_op(s, REOP_push_char_pos); /* copy the atom */ dbuf_put_self(&s->byte_code, last_atom_start, len); if (add_zero_advance_check) - re_emit_goto(s, REOP_bne_char_pos, pos); - else - re_emit_goto(s, REOP_goto, pos); + re_emit_op(s, REOP_check_advance); + re_emit_goto(s, REOP_goto, pos); } else if (quant_max > quant_min) { re_emit_op_u32(s, REOP_push_i32, quant_max - quant_min); pos = s->byte_code.size; - re_emit_op_u32(s, REOP_split_goto_first + greedy, len + 5); + re_emit_op_u32(s, REOP_split_goto_first + greedy, + len + 5 + add_zero_advance_check * 2); + if (add_zero_advance_check) + re_emit_op(s, REOP_push_char_pos); /* copy the atom */ dbuf_put_self(&s->byte_code, last_atom_start, len); - + if (add_zero_advance_check) + re_emit_op(s, REOP_check_advance); re_emit_goto(s, REOP_loop, pos); re_emit_op(s, REOP_drop); } @@ -1796,7 +1717,7 @@ static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len) } break; case REOP_drop: - case REOP_bne_char_pos: + case REOP_check_advance: assert(stack_size > 0); stack_size--; break; @@ -2292,11 +2213,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, case REOP_push_char_pos: stack[stack_len++] = (uintptr_t)cptr; break; - case REOP_bne_char_pos: - val = get_u32(pc); - pc += 4; - if (stack[--stack_len] != (uintptr_t)cptr) - pc += (int)val; + case REOP_check_advance: + if (stack[--stack_len] == (uintptr_t)cptr) + goto no_match; break; case REOP_word_boundary: case REOP_not_word_boundary: diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libregexp.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libregexp.h similarity index 97% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/libregexp.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libregexp.h index 9aedb7e9..c0bc58d0 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libregexp.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libregexp.h @@ -36,6 +36,7 @@ #define LRE_FLAG_DOTALL (1 << 3) #define LRE_FLAG_UTF16 (1 << 4) #define LRE_FLAG_STICKY (1 << 5) +#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */ #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode-table.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode-table.h new file mode 100644 index 00000000..513ed94b --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode-table.h @@ -0,0 +1,4486 @@ +/* Compressed unicode tables */ +/* Automatically generated file - do not edit */ + +#include + +static const uint32_t case_conv_table1[370] = { + 0x00209a30, 0x00309a00, 0x005a8173, 0x00601730, + 0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700, + 0x007f8100, 0x00803040, 0x009801c3, 0x00988190, + 0x00990640, 0x009c9040, 0x00a481b4, 0x00a52e40, + 0x00bc0130, 0x00bc8640, 0x00bf8170, 0x00c00100, + 0x00c08130, 0x00c10440, 0x00c30130, 0x00c38240, + 0x00c48230, 0x00c58240, 0x00c70130, 0x00c78130, + 0x00c80130, 0x00c88240, 0x00c98130, 0x00ca0130, + 0x00ca8100, 0x00cb0130, 0x00cb8130, 0x00cc0240, + 0x00cd0100, 0x00ce0130, 0x00ce8130, 0x00cf0100, + 0x00cf8130, 0x00d00640, 0x00d30130, 0x00d38240, + 0x00d48130, 0x00d60240, 0x00d70130, 0x00d78240, + 0x00d88230, 0x00d98440, 0x00db8130, 0x00dc0240, + 0x00de0240, 0x00df8100, 0x00e20350, 0x00e38350, + 0x00e50350, 0x00e69040, 0x00ee8100, 0x00ef1240, + 0x00f801b4, 0x00f88350, 0x00fa0240, 0x00fb0130, + 0x00fb8130, 0x00fc2840, 0x01100130, 0x01111240, + 0x011d0131, 0x011d8240, 0x011e8130, 0x011f0131, + 0x011f8201, 0x01208240, 0x01218130, 0x01220130, + 0x01228130, 0x01230a40, 0x01280101, 0x01288101, + 0x01290101, 0x01298100, 0x012a0100, 0x012b0200, + 0x012c8100, 0x012d8100, 0x012e0101, 0x01300100, + 0x01308101, 0x01318100, 0x01328101, 0x01330101, + 0x01340100, 0x01348100, 0x01350101, 0x01358101, + 0x01360101, 0x01378100, 0x01388101, 0x01390100, + 0x013a8100, 0x013e8101, 0x01400100, 0x01410101, + 0x01418100, 0x01438101, 0x01440100, 0x01448100, + 0x01450200, 0x01460100, 0x01490100, 0x014e8101, + 0x014f0101, 0x01a28173, 0x01b80440, 0x01bb0240, + 0x01bd8300, 0x01bf8130, 0x01c30130, 0x01c40330, + 0x01c60130, 0x01c70230, 0x01c801d0, 0x01c89130, + 0x01d18930, 0x01d60100, 0x01d68300, 0x01d801d3, + 0x01d89100, 0x01e10173, 0x01e18900, 0x01e60100, + 0x01e68200, 0x01e78130, 0x01e80173, 0x01e88173, + 0x01ea8173, 0x01eb0173, 0x01eb8100, 0x01ec1840, + 0x01f80173, 0x01f88173, 0x01f90100, 0x01f98100, + 0x01fa01a0, 0x01fa8173, 0x01fb8240, 0x01fc8130, + 0x01fd0240, 0x01fe8330, 0x02001030, 0x02082030, + 0x02182000, 0x02281000, 0x02302240, 0x02453640, + 0x02600130, 0x02608e40, 0x02678100, 0x02686040, + 0x0298a630, 0x02b0a600, 0x02c381b5, 0x08502631, + 0x08638131, 0x08668131, 0x08682b00, 0x087e8300, + 0x09d05011, 0x09f80610, 0x09fc0620, 0x0e400174, + 0x0e408174, 0x0e410174, 0x0e418174, 0x0e420174, + 0x0e428174, 0x0e430174, 0x0e438180, 0x0e440180, + 0x0e482b30, 0x0e5e8330, 0x0ebc8101, 0x0ebe8101, + 0x0ec70101, 0x0f007e40, 0x0f3f1840, 0x0f4b01b5, + 0x0f4b81b6, 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7, + 0x0f4d8180, 0x0f4f0130, 0x0f506040, 0x0f800800, + 0x0f840830, 0x0f880600, 0x0f8c0630, 0x0f900800, + 0x0f940830, 0x0f980800, 0x0f9c0830, 0x0fa00600, + 0x0fa40630, 0x0fa801b0, 0x0fa88100, 0x0fa901d3, + 0x0fa98100, 0x0faa01d3, 0x0faa8100, 0x0fab01d3, + 0x0fab8100, 0x0fac8130, 0x0fad8130, 0x0fae8130, + 0x0faf8130, 0x0fb00800, 0x0fb40830, 0x0fb80200, + 0x0fb90400, 0x0fbb0200, 0x0fbc0201, 0x0fbd0201, + 0x0fbe0201, 0x0fc008b7, 0x0fc40867, 0x0fc808b8, + 0x0fcc0868, 0x0fd008b8, 0x0fd40868, 0x0fd80200, + 0x0fd901b9, 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1, + 0x0fdb81d7, 0x0fdc0230, 0x0fdd0230, 0x0fde0161, + 0x0fdf0173, 0x0fe101b9, 0x0fe181b2, 0x0fe201ba, + 0x0fe301b2, 0x0fe381d8, 0x0fe40430, 0x0fe60162, + 0x0fe80200, 0x0fe901d0, 0x0fe981d0, 0x0feb01b0, + 0x0feb81d0, 0x0fec0230, 0x0fed0230, 0x0ff00201, + 0x0ff101d3, 0x0ff181d3, 0x0ff201ba, 0x0ff28101, + 0x0ff301b0, 0x0ff381d3, 0x0ff40230, 0x0ff50230, + 0x0ff60131, 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb, + 0x0ffb01b2, 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230, + 0x0ffe0162, 0x109301a0, 0x109501a0, 0x109581a0, + 0x10990131, 0x10a70101, 0x10b01031, 0x10b81001, + 0x10c18240, 0x125b1a31, 0x12681a01, 0x16003031, + 0x16183001, 0x16300240, 0x16310130, 0x16318130, + 0x16320130, 0x16328100, 0x16330100, 0x16338640, + 0x16368130, 0x16370130, 0x16378130, 0x16380130, + 0x16390240, 0x163a8240, 0x163f0230, 0x16406440, + 0x16758440, 0x16790240, 0x16802600, 0x16938100, + 0x16968100, 0x53202e40, 0x53401c40, 0x53910e40, + 0x53993e40, 0x53bc8440, 0x53be8130, 0x53bf0a40, + 0x53c58240, 0x53c68130, 0x53c80440, 0x53ca0101, + 0x53cb1440, 0x53d50130, 0x53d58130, 0x53d60130, + 0x53d68130, 0x53d70130, 0x53d80130, 0x53d88130, + 0x53d90130, 0x53d98131, 0x53da1040, 0x53e20131, + 0x53e28130, 0x53e30130, 0x53e38440, 0x53e80240, + 0x53eb0440, 0x53fa8240, 0x55a98101, 0x55b85020, + 0x7d8001b2, 0x7d8081b2, 0x7d8101b2, 0x7d8181da, + 0x7d8201da, 0x7d8281b3, 0x7d8301b3, 0x7d8981bb, + 0x7d8a01bb, 0x7d8a81bb, 0x7d8b01bc, 0x7d8b81bb, + 0x7f909a31, 0x7fa09a01, 0x82002831, 0x82142801, + 0x82582431, 0x826c2401, 0x82b80b31, 0x82be0f31, + 0x82c60731, 0x82ca0231, 0x82cb8b01, 0x82d18f01, + 0x82d98701, 0x82dd8201, 0x86403331, 0x86603301, + 0x8c502031, 0x8c602001, 0xb7202031, 0xb7302001, + 0xf4802231, 0xf4912201, +}; + +static const uint8_t case_conv_table2[370] = { + 0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04, + 0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00, + 0x08, 0x00, 0x53, 0x4a, 0x51, 0x00, 0x52, 0x00, + 0x53, 0x00, 0x3a, 0x54, 0x55, 0x00, 0x57, 0x59, + 0x3f, 0x5d, 0x5c, 0x00, 0x46, 0x61, 0x63, 0x42, + 0x64, 0x00, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, + 0x6c, 0x00, 0x6e, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00, 0x20, + 0x35, 0x00, 0x27, 0x00, 0x21, 0x00, 0x24, 0x22, + 0x2a, 0x00, 0x13, 0x6b, 0x6d, 0x00, 0x26, 0x24, + 0x27, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x3e, 0x1e, + 0x3f, 0x1f, 0x39, 0x3d, 0x22, 0x21, 0x41, 0x1e, + 0x40, 0x25, 0x25, 0x26, 0x28, 0x20, 0x2a, 0x48, + 0x2c, 0x43, 0x2e, 0x4b, 0x30, 0x4c, 0x32, 0x44, + 0x42, 0x99, 0x00, 0x00, 0x95, 0x8f, 0x7d, 0x7e, + 0x83, 0x84, 0x12, 0x80, 0x82, 0x76, 0x77, 0x12, + 0x7b, 0xa3, 0x7c, 0x78, 0x79, 0x8a, 0x92, 0x98, + 0xa6, 0xa0, 0x85, 0x00, 0x9a, 0xa1, 0x93, 0x75, + 0x33, 0x95, 0x00, 0x8e, 0x00, 0x74, 0x99, 0x98, + 0x97, 0x96, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, + 0xa1, 0xa0, 0x15, 0x2e, 0x2f, 0x30, 0xb4, 0xb5, + 0x4f, 0xaa, 0xa9, 0x12, 0x14, 0x1e, 0x21, 0x22, + 0x22, 0x2a, 0x34, 0x35, 0xa6, 0xa7, 0x36, 0x1f, + 0x49, 0x00, 0x00, 0x97, 0x01, 0x5a, 0xda, 0x1d, + 0x36, 0x05, 0x00, 0xc4, 0xc3, 0xc6, 0xc5, 0xc8, + 0xc7, 0xca, 0xc9, 0xcc, 0xcb, 0xc4, 0xd5, 0x45, + 0xd6, 0x42, 0xd7, 0x46, 0xd8, 0xce, 0xd0, 0xd2, + 0xd4, 0xda, 0xd9, 0xee, 0xf6, 0xfe, 0x0e, 0x07, + 0x0f, 0x80, 0x9f, 0x00, 0x21, 0x80, 0xa3, 0xed, + 0x00, 0xc0, 0x40, 0xc6, 0x60, 0xe7, 0xdb, 0xe6, + 0x99, 0xc0, 0x00, 0x00, 0x06, 0x60, 0xdc, 0x29, + 0xfd, 0x15, 0x12, 0x06, 0x16, 0xf8, 0xdd, 0x06, + 0x15, 0x12, 0x84, 0x08, 0xc6, 0x16, 0xff, 0xdf, + 0x03, 0xc0, 0x40, 0x00, 0x46, 0x60, 0xde, 0xe0, + 0x6d, 0x37, 0x38, 0x39, 0x15, 0x14, 0x17, 0x16, + 0x00, 0x1a, 0x19, 0x1c, 0x1b, 0x00, 0x5f, 0xb7, + 0x65, 0x44, 0x47, 0x00, 0x4f, 0x62, 0x4e, 0x50, + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0xa4, + 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, + 0x00, 0x5a, 0x00, 0x47, 0x00, 0x5b, 0x56, 0x58, + 0x60, 0x5e, 0x70, 0x69, 0x6f, 0x4e, 0x00, 0x3b, + 0x67, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa8, + 0x8a, 0x8b, 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, + 0x94, 0xb0, 0x6f, 0xb2, 0x5d, 0x5c, 0x5f, 0x5e, + 0x61, 0x60, 0x66, 0x67, 0x68, 0x69, 0x62, 0x63, + 0x64, 0x65, 0x6b, 0x6a, 0x6d, 0x6c, 0x6f, 0x6e, + 0x71, 0x70, +}; + +static const uint16_t case_conv_ext[58] = { + 0x0399, 0x0308, 0x0301, 0x03a5, 0x0313, 0x0300, 0x0342, 0x0391, + 0x0397, 0x03a9, 0x0046, 0x0049, 0x004c, 0x0053, 0x0069, 0x0307, + 0x02bc, 0x004e, 0x004a, 0x030c, 0x0535, 0x0552, 0x0048, 0x0331, + 0x0054, 0x0057, 0x030a, 0x0059, 0x0041, 0x02be, 0x1f08, 0x1f80, + 0x1f28, 0x1f90, 0x1f68, 0x1fa0, 0x1fba, 0x0386, 0x1fb3, 0x1fca, + 0x0389, 0x1fc3, 0x03a1, 0x1ffa, 0x038f, 0x1ff3, 0x0544, 0x0546, + 0x053b, 0x054e, 0x053d, 0x03b8, 0x0462, 0xa64a, 0x1e60, 0x03c9, + 0x006b, 0x00e5, +}; + +static const uint8_t unicode_prop_Cased1_table[196] = { + 0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3, + 0x80, 0x8c, 0x80, 0x8d, 0x81, 0x8d, 0x02, 0x80, + 0xe1, 0x80, 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, + 0x11, 0x00, 0x01, 0x04, 0x08, 0x01, 0x08, 0x30, + 0x08, 0x01, 0x15, 0x20, 0x00, 0x39, 0x99, 0x31, + 0x9d, 0x84, 0x40, 0x94, 0x80, 0xd6, 0x82, 0xa6, + 0x80, 0x41, 0x62, 0x80, 0xa6, 0x80, 0x4b, 0x72, + 0x80, 0x4c, 0x02, 0xf8, 0x02, 0x80, 0x8f, 0x80, + 0xb0, 0x40, 0xdb, 0x08, 0x80, 0x41, 0xd0, 0x80, + 0x8c, 0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, + 0x00, 0x14, 0x28, 0x10, 0x11, 0x02, 0x01, 0x18, + 0x0b, 0x24, 0x4b, 0x26, 0x01, 0x01, 0x86, 0xe5, + 0x80, 0x60, 0x79, 0xb6, 0x81, 0x40, 0x91, 0x81, + 0xbd, 0x88, 0x94, 0x05, 0x80, 0x98, 0x80, 0xa2, + 0x00, 0x80, 0x9b, 0x12, 0x82, 0x43, 0x34, 0xa2, + 0x06, 0x80, 0x8d, 0x60, 0x5c, 0x15, 0x01, 0x10, + 0xa9, 0x80, 0x88, 0x60, 0xcc, 0x44, 0xd4, 0x80, + 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, + 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, + 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81, + 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, + 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, + 0x9e, 0x80, 0x98, 0x07, 0x47, 0x33, 0x89, 0x80, + 0x93, 0x2d, 0x41, 0x04, 0xbd, 0x50, 0xc1, 0x99, + 0x85, 0x99, 0x85, 0x99, +}; + +static const uint8_t unicode_prop_Cased1_index[21] = { + 0xb9, 0x02, 0xe0, 0xc0, 0x1d, 0x20, 0xe5, 0x2c, + 0x20, 0xb1, 0x07, 0x21, 0xc1, 0xd6, 0x21, 0x4a, + 0xf1, 0x01, 0x8a, 0xf1, 0x01, +}; + +static const uint8_t unicode_prop_Case_Ignorable_table[737] = { + 0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80, + 0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6, + 0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40, + 0xfa, 0x86, 0x40, 0xce, 0x04, 0x80, 0xb0, 0xac, + 0x00, 0x01, 0x01, 0x00, 0xab, 0x80, 0x8a, 0x85, + 0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f, + 0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80, + 0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08, + 0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0d, 0x87, + 0xa8, 0xb9, 0xb6, 0x00, 0x03, 0x3b, 0x02, 0x86, + 0x89, 0x81, 0x8c, 0x80, 0x8e, 0x80, 0xb9, 0x03, + 0x1f, 0x80, 0x93, 0x81, 0x99, 0x01, 0x81, 0xb8, + 0x03, 0x0b, 0x09, 0x12, 0x80, 0x9d, 0x0a, 0x80, + 0x8a, 0x81, 0xb8, 0x03, 0x20, 0x0b, 0x80, 0x93, + 0x81, 0x95, 0x28, 0x80, 0xb9, 0x01, 0x00, 0x1f, + 0x06, 0x81, 0x8a, 0x81, 0x9d, 0x80, 0xbc, 0x80, + 0x8b, 0x80, 0xb1, 0x02, 0x80, 0xb6, 0x00, 0x14, + 0x10, 0x1e, 0x81, 0x8a, 0x81, 0x9c, 0x80, 0xb9, + 0x01, 0x05, 0x04, 0x81, 0x93, 0x81, 0x9b, 0x81, + 0xb8, 0x0b, 0x1f, 0x80, 0x93, 0x81, 0x9c, 0x80, + 0xc7, 0x06, 0x10, 0x80, 0xd9, 0x01, 0x86, 0x8a, + 0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x86, 0xc8, + 0x81, 0x9a, 0x00, 0x00, 0x80, 0xb6, 0x8d, 0x04, + 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe5, + 0x18, 0x28, 0x09, 0x81, 0x98, 0x0b, 0x82, 0x8f, + 0x83, 0x8c, 0x01, 0x0d, 0x80, 0x8e, 0x80, 0xdd, + 0x80, 0x42, 0x5f, 0x82, 0x43, 0xb1, 0x82, 0x9c, + 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xbf, 0x08, 0x37, + 0x01, 0x8a, 0x10, 0x20, 0xac, 0x84, 0xb2, 0x80, + 0xc0, 0x81, 0xa1, 0x80, 0xf5, 0x13, 0x81, 0x88, + 0x05, 0x82, 0x40, 0xda, 0x09, 0x80, 0xb9, 0x00, + 0x30, 0x00, 0x01, 0x3d, 0x89, 0x08, 0xa6, 0x07, + 0x9e, 0xb0, 0x83, 0xaf, 0x00, 0x20, 0x04, 0x80, + 0xa7, 0x88, 0x8b, 0x81, 0x9f, 0x19, 0x08, 0x82, + 0xb7, 0x00, 0x0a, 0x00, 0x82, 0xb9, 0x39, 0x81, + 0xbf, 0x85, 0xd1, 0x10, 0x8c, 0x06, 0x18, 0x28, + 0x11, 0xb1, 0xbe, 0x8c, 0x80, 0xa1, 0xe4, 0x41, + 0xbc, 0x00, 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, + 0x82, 0x8c, 0x81, 0x8b, 0x27, 0x81, 0x89, 0x01, + 0x01, 0x84, 0xb0, 0x20, 0x89, 0x00, 0x8c, 0x80, + 0x8f, 0x8c, 0xb2, 0xa0, 0x4b, 0x8a, 0x81, 0xf0, + 0x82, 0xfc, 0x80, 0x8e, 0x80, 0xdf, 0x9f, 0xae, + 0x80, 0x41, 0xd4, 0x80, 0xa3, 0x1a, 0x24, 0x80, + 0xdc, 0x85, 0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80, + 0x44, 0xe1, 0x85, 0x41, 0x0d, 0x80, 0xe1, 0x18, + 0x89, 0x00, 0x9b, 0x83, 0xcf, 0x81, 0x8d, 0xa1, + 0xcd, 0x80, 0x96, 0x82, 0xe6, 0x12, 0x0f, 0x02, + 0x03, 0x80, 0x98, 0x0c, 0x80, 0x40, 0x96, 0x81, + 0x99, 0x91, 0x8c, 0x80, 0xa5, 0x87, 0x98, 0x8a, + 0xad, 0x82, 0xaf, 0x01, 0x19, 0x81, 0x90, 0x80, + 0x94, 0x81, 0xc1, 0x29, 0x09, 0x81, 0x8b, 0x07, + 0x80, 0xa2, 0x80, 0x8a, 0x80, 0xb2, 0x00, 0x11, + 0x0c, 0x08, 0x80, 0x9a, 0x80, 0x8d, 0x0c, 0x08, + 0x80, 0xe3, 0x84, 0x88, 0x82, 0xf8, 0x01, 0x03, + 0x80, 0x60, 0x4f, 0x2f, 0x80, 0x40, 0x92, 0x90, + 0x42, 0x3c, 0x8f, 0x10, 0x8b, 0x8f, 0xa1, 0x01, + 0x80, 0x40, 0xa8, 0x06, 0x05, 0x80, 0x8a, 0x80, + 0xa2, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2, + 0x80, 0x94, 0x82, 0x42, 0x00, 0x80, 0x40, 0xe1, + 0x80, 0x40, 0x94, 0x84, 0x44, 0x04, 0x28, 0xa9, + 0x80, 0x88, 0x42, 0x45, 0x10, 0x0c, 0x83, 0xa7, + 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x83, + 0x41, 0x82, 0x81, 0xcf, 0x82, 0xc5, 0x8a, 0xb0, + 0x83, 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, 0x81, + 0x89, 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, 0x89, + 0x80, 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, + 0x8b, 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, + 0x11, 0x00, 0x0d, 0x01, 0x80, 0x40, 0x9c, 0x02, + 0x87, 0x94, 0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32, + 0x84, 0x40, 0xc2, 0x39, 0x10, 0x80, 0x96, 0x80, + 0xd3, 0x28, 0x03, 0x08, 0x81, 0x40, 0xed, 0x1d, + 0x08, 0x81, 0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81, + 0xe9, 0x00, 0x01, 0x28, 0x80, 0xe4, 0x11, 0x18, + 0x84, 0x41, 0x02, 0x88, 0x01, 0x40, 0xff, 0x08, + 0x03, 0x80, 0x40, 0x8f, 0x19, 0x0b, 0x80, 0x9f, + 0x89, 0xa7, 0x29, 0x1f, 0x80, 0x88, 0x29, 0x82, + 0xad, 0x8c, 0x01, 0x41, 0x95, 0x30, 0x28, 0x80, + 0xd1, 0x95, 0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, + 0x08, 0x30, 0x80, 0xc7, 0x0a, 0x00, 0x80, 0x41, + 0x5a, 0x81, 0x8a, 0x81, 0xb3, 0x24, 0x00, 0x80, + 0x54, 0xec, 0x90, 0x85, 0x8e, 0x60, 0x36, 0x99, + 0x84, 0xba, 0x86, 0x88, 0x83, 0x44, 0x0a, 0x80, + 0xbe, 0x90, 0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a, + 0x18, 0x30, 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52, + 0x5b, 0xad, 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88, + 0x8f, 0x0e, 0x9d, 0x83, 0x40, 0x93, 0x82, 0x47, + 0xba, 0xb6, 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, + 0x20, 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, + 0x04, 0x84, 0xbd, 0xa0, 0x80, 0x40, 0x9f, 0x8d, + 0x41, 0x6f, 0x80, 0xbc, 0x83, 0x41, 0xfa, 0x84, + 0x43, 0xdf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84, + 0x6c, 0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40, + 0xef, +}; + +static const uint8_t unicode_prop_Case_Ignorable_index[69] = { + 0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a, + 0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f, + 0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20, + 0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0, + 0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56, + 0xfe, 0x20, 0xb1, 0x07, 0x01, 0x75, 0x10, 0x01, + 0xeb, 0x12, 0x21, 0x41, 0x16, 0x01, 0x5c, 0x1a, + 0x01, 0x43, 0x1f, 0x01, 0x2e, 0xcf, 0x41, 0x25, + 0xe0, 0x01, 0xf0, 0x01, 0x0e, +}; + +static const uint8_t unicode_prop_ID_Start_table[1100] = { + 0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03, + 0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83, + 0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20, + 0x09, 0x18, 0x05, 0x00, 0x10, 0x00, 0x93, 0x80, + 0xd2, 0x80, 0x40, 0x8a, 0x87, 0x40, 0xa5, 0x80, + 0xa5, 0x08, 0x85, 0xa8, 0xc6, 0x9a, 0x1b, 0xac, + 0xaa, 0xa2, 0x08, 0xe2, 0x00, 0x8e, 0x0e, 0x81, + 0x89, 0x11, 0x80, 0x8f, 0x00, 0x9d, 0x9c, 0xd8, + 0x8a, 0x80, 0x97, 0xa0, 0x88, 0x0b, 0x04, 0x95, + 0x18, 0x88, 0x02, 0x80, 0x96, 0x98, 0x86, 0x8a, + 0x84, 0x97, 0x05, 0x90, 0xa9, 0xb9, 0xb5, 0x10, + 0x91, 0x06, 0x89, 0x8e, 0x8f, 0x1f, 0x09, 0x81, + 0x95, 0x06, 0x00, 0x13, 0x10, 0x8f, 0x80, 0x8c, + 0x08, 0x82, 0x8d, 0x81, 0x89, 0x07, 0x2b, 0x09, + 0x95, 0x06, 0x01, 0x01, 0x01, 0x9e, 0x18, 0x80, + 0x92, 0x82, 0x8f, 0x88, 0x02, 0x80, 0x95, 0x06, + 0x01, 0x04, 0x10, 0x91, 0x80, 0x8e, 0x81, 0x96, + 0x80, 0x8a, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, + 0x10, 0x9d, 0x08, 0x82, 0x8e, 0x80, 0x90, 0x00, + 0x2a, 0x10, 0x1a, 0x08, 0x00, 0x0a, 0x0a, 0x12, + 0x8b, 0x95, 0x80, 0xb3, 0x38, 0x10, 0x96, 0x80, + 0x8f, 0x10, 0x99, 0x11, 0x01, 0x81, 0x9d, 0x03, + 0x38, 0x10, 0x96, 0x80, 0x89, 0x04, 0x10, 0x9e, + 0x08, 0x81, 0x8e, 0x81, 0x90, 0x88, 0x02, 0x80, + 0xa8, 0x08, 0x8f, 0x04, 0x17, 0x82, 0x97, 0x2c, + 0x91, 0x82, 0x97, 0x80, 0x88, 0x00, 0x0e, 0xb9, + 0xaf, 0x01, 0x8b, 0x86, 0xb9, 0x08, 0x00, 0x20, + 0x97, 0x00, 0x80, 0x89, 0x01, 0x88, 0x01, 0x20, + 0x80, 0x94, 0x83, 0x9f, 0x80, 0xbe, 0x38, 0xa3, + 0x9a, 0x84, 0xf2, 0xaa, 0x93, 0x80, 0x8f, 0x2b, + 0x1a, 0x02, 0x0e, 0x13, 0x8c, 0x8b, 0x80, 0x90, + 0xa5, 0x00, 0x20, 0x81, 0xaa, 0x80, 0x41, 0x4c, + 0x03, 0x0e, 0x00, 0x03, 0x81, 0xa8, 0x03, 0x81, + 0xa0, 0x03, 0x0e, 0x00, 0x03, 0x81, 0x8e, 0x80, + 0xb8, 0x03, 0x81, 0xc2, 0xa4, 0x8f, 0x8f, 0xd5, + 0x0d, 0x82, 0x42, 0x6b, 0x81, 0x90, 0x80, 0x99, + 0x84, 0xca, 0x82, 0x8a, 0x86, 0x91, 0x8c, 0x92, + 0x8d, 0x91, 0x8d, 0x8c, 0x02, 0x8e, 0xb3, 0xa2, + 0x03, 0x80, 0xc2, 0xd8, 0x86, 0xa8, 0x00, 0x84, + 0xc5, 0x89, 0x9e, 0xb0, 0x9d, 0x0c, 0x8a, 0xab, + 0x83, 0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80, + 0xdc, 0xae, 0x90, 0x87, 0xb5, 0x9d, 0x8c, 0x81, + 0x89, 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3, + 0x81, 0x88, 0x86, 0xaa, 0x0a, 0xa8, 0x18, 0x28, + 0x0a, 0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d, + 0x81, 0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80, + 0x9e, 0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13, + 0x0d, 0x83, 0x8c, 0x22, 0x06, 0xf3, 0x80, 0x8c, + 0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, + 0x0d, 0x28, 0x00, 0x00, 0x80, 0x8f, 0x0b, 0x24, + 0x18, 0x90, 0xa8, 0x4a, 0x76, 0x40, 0xe4, 0x2b, + 0x11, 0x8b, 0xa5, 0x00, 0x20, 0x81, 0xb7, 0x30, + 0x8f, 0x96, 0x88, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x86, 0x42, 0x25, 0x82, 0x98, 0x88, + 0x34, 0x0c, 0x83, 0xd5, 0x1c, 0x80, 0xd9, 0x03, + 0x84, 0xaa, 0x80, 0xdd, 0x90, 0x9f, 0xaf, 0x8f, + 0x41, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x56, 0x8c, + 0xc2, 0xad, 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89, + 0x81, 0x93, 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6, + 0x88, 0x81, 0xe6, 0x81, 0xbf, 0x21, 0x00, 0x04, + 0x97, 0x8f, 0x02, 0x03, 0x80, 0x96, 0x9c, 0xb3, + 0x8d, 0xb1, 0xbd, 0x2a, 0x00, 0x81, 0x8a, 0x9b, + 0x89, 0x96, 0x98, 0x9c, 0x86, 0xae, 0x9b, 0x80, + 0x8f, 0x20, 0x89, 0x89, 0x20, 0xa8, 0x96, 0x10, + 0x87, 0x93, 0x96, 0x10, 0x82, 0xb1, 0x00, 0x11, + 0x0c, 0x08, 0x00, 0x97, 0x11, 0x8a, 0x32, 0x8b, + 0x29, 0x29, 0x85, 0x88, 0x30, 0x30, 0xaa, 0x80, + 0x8d, 0x85, 0xf2, 0x9c, 0x60, 0x2b, 0xa3, 0x8b, + 0x96, 0x83, 0xb0, 0x60, 0x21, 0x03, 0x41, 0x6d, + 0x81, 0xe9, 0xa5, 0x86, 0x8b, 0x24, 0x00, 0x89, + 0x80, 0x8c, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb, + 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7, + 0x8b, 0xf3, 0x20, 0x40, 0x86, 0xa3, 0x99, 0x85, + 0x99, 0x8a, 0xd8, 0x15, 0x0d, 0x0d, 0x0a, 0xa2, + 0x8b, 0x80, 0x99, 0x80, 0x92, 0x01, 0x80, 0x8e, + 0x81, 0x8d, 0xa1, 0xfa, 0xc4, 0xb4, 0x41, 0x0a, + 0x9c, 0x82, 0xb0, 0xae, 0x9f, 0x8c, 0x9d, 0x84, + 0xa5, 0x89, 0x9d, 0x81, 0xa3, 0x1f, 0x04, 0xa9, + 0x40, 0x9d, 0x91, 0xa3, 0x83, 0xa3, 0x83, 0xa7, + 0x87, 0xb3, 0x8b, 0x8a, 0x80, 0x8e, 0x06, 0x01, + 0x80, 0x8a, 0x80, 0x8e, 0x06, 0x01, 0xc2, 0x41, + 0x36, 0x88, 0x95, 0x89, 0x87, 0x97, 0x28, 0xa9, + 0x80, 0x88, 0xc4, 0x29, 0x00, 0xab, 0x01, 0x10, + 0x81, 0x96, 0x89, 0x96, 0x88, 0x9e, 0xc0, 0x92, + 0x01, 0x89, 0x95, 0x89, 0x99, 0xc5, 0xb7, 0x29, + 0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c, 0xa9, 0x9c, + 0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a, 0xb5, 0x89, + 0x95, 0x89, 0x92, 0x8c, 0x91, 0xed, 0xc8, 0xb6, + 0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0x41, 0x5b, 0xa9, + 0x29, 0xcd, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91, + 0xad, 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09, + 0x80, 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c, + 0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83, + 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0x92, + 0x81, 0xbe, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, + 0x86, 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, + 0x04, 0x10, 0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d, + 0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93, + 0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3, + 0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6, + 0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf, + 0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e, 0x00, + 0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b, + 0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad, + 0x92, 0x80, 0x91, 0xc8, 0x41, 0x06, 0x88, 0x80, + 0xa4, 0x90, 0x80, 0xb0, 0x9d, 0xef, 0x30, 0x08, + 0xa5, 0x94, 0x80, 0x98, 0x28, 0x08, 0x9f, 0x8d, + 0x80, 0x41, 0x46, 0x92, 0x8e, 0x00, 0x8c, 0x80, + 0xa1, 0xfb, 0x80, 0xce, 0x43, 0x99, 0xe5, 0xee, + 0x90, 0x40, 0xc3, 0x4a, 0x4b, 0xe0, 0x8e, 0x44, + 0x2f, 0x90, 0x85, 0x4f, 0xb8, 0x42, 0x46, 0x60, + 0x21, 0xb8, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce, + 0x90, 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94, + 0x84, 0x92, 0x42, 0xaf, 0xbf, 0xff, 0xca, 0x20, + 0xc1, 0x8c, 0xbf, 0x08, 0x80, 0x9b, 0x57, 0xf7, + 0x87, 0x44, 0xd5, 0xa9, 0x88, 0x60, 0x22, 0xe6, + 0x18, 0x30, 0x08, 0x41, 0x22, 0x8e, 0x80, 0x9c, + 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b, 0x49, 0x03, + 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86, 0x89, 0x57, + 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, + 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, + 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, + 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x47, + 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd, 0x40, 0x91, + 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40, 0x9d, + 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x42, 0xf3, 0x30, + 0x18, 0x08, 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, + 0x30, 0x44, 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, + 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, + 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, + 0x51, 0x43, 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39, + 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, + 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1, 0x53, + 0x4a, 0x84, 0x50, 0x5f, +}; + +static const uint8_t unicode_prop_ID_Start_index[105] = { + 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09, + 0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b, + 0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00, + 0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d, + 0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00, + 0x32, 0x00, 0xda, 0xa7, 0x00, 0x4c, 0xaa, 0x20, + 0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02, + 0x21, 0x96, 0x05, 0x01, 0xf3, 0x08, 0x01, 0xb3, + 0x0c, 0x21, 0x73, 0x11, 0x61, 0x34, 0x13, 0x01, + 0x1b, 0x17, 0x21, 0x8a, 0x1a, 0x01, 0x34, 0x1f, + 0x21, 0xbf, 0x6a, 0x01, 0x23, 0xb1, 0xa1, 0xad, + 0xd4, 0x01, 0x6f, 0xd7, 0x01, 0xff, 0xe7, 0x61, + 0x5e, 0xee, 0x01, 0xe1, 0xeb, 0x22, 0xb0, 0x23, + 0x03, +}; + +static const uint8_t unicode_prop_ID_Continue1_table[660] = { + 0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47, + 0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08, + 0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, + 0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89, + 0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89, + 0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02, + 0x04, 0xaa, 0x82, 0xbb, 0x87, 0xa9, 0x97, 0x80, + 0xa0, 0xb5, 0x10, 0x91, 0x06, 0x89, 0x09, 0x89, + 0x90, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88, + 0x80, 0x89, 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7, + 0x00, 0x23, 0x09, 0x12, 0x80, 0x93, 0x8b, 0x10, + 0x8a, 0x82, 0xb7, 0x00, 0x38, 0x10, 0x82, 0x93, + 0x09, 0x89, 0x89, 0x28, 0x82, 0xb7, 0x00, 0x31, + 0x09, 0x16, 0x82, 0x89, 0x09, 0x89, 0x91, 0x80, + 0xba, 0x22, 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89, + 0x8f, 0x84, 0xb6, 0x00, 0x30, 0x10, 0x1e, 0x81, + 0x8a, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x30, + 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x10, 0x8b, + 0x83, 0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80, + 0x89, 0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28, + 0x00, 0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b, + 0x38, 0x89, 0xd6, 0x01, 0x88, 0x8a, 0x30, 0x89, + 0xbd, 0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81, + 0xb0, 0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, + 0x80, 0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10, + 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42, + 0xbe, 0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b, + 0x82, 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88, + 0x01, 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80, + 0xf5, 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a, + 0xbb, 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a, + 0x85, 0x89, 0x95, 0x8d, 0x80, 0x8f, 0xb0, 0x84, + 0xae, 0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82, + 0x9d, 0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93, + 0x87, 0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18, + 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x3e, 0x81, + 0x92, 0x80, 0xfa, 0x8c, 0x18, 0x82, 0x8b, 0x4b, + 0xfd, 0x82, 0x40, 0x8c, 0x80, 0xdf, 0x9f, 0x42, + 0x29, 0x85, 0xe8, 0x81, 0x60, 0x75, 0x84, 0x89, + 0xc4, 0x03, 0x89, 0x9f, 0x81, 0xcf, 0x81, 0x41, + 0x0f, 0x02, 0x03, 0x80, 0x96, 0x23, 0x80, 0xd2, + 0x81, 0xb1, 0x91, 0x89, 0x89, 0x85, 0x91, 0x8c, + 0x8a, 0x9b, 0x87, 0x98, 0x8c, 0xab, 0x83, 0xae, + 0x8d, 0x8e, 0x89, 0x8a, 0x80, 0x89, 0x89, 0xae, + 0x8d, 0x8b, 0x07, 0x09, 0x89, 0xa0, 0x82, 0xb1, + 0x00, 0x11, 0x0c, 0x08, 0x80, 0xa8, 0x24, 0x81, + 0x40, 0xeb, 0x38, 0x09, 0x89, 0x60, 0x4f, 0x23, + 0x80, 0x42, 0xe0, 0x8f, 0x8f, 0x8f, 0x11, 0x97, + 0x82, 0x40, 0xbf, 0x89, 0xa4, 0x80, 0x42, 0xbc, + 0x80, 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, + 0x24, 0x89, 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, + 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, + 0x89, 0x41, 0x70, 0x81, 0xcf, 0x82, 0xc5, 0x8a, + 0xb0, 0x83, 0xf9, 0x82, 0xb4, 0x8e, 0x9e, 0x8a, + 0x09, 0x89, 0x83, 0xac, 0x8a, 0x30, 0xac, 0x89, + 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80, + 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1, + 0x8b, 0x28, 0x08, 0x40, 0x9c, 0x8b, 0x84, 0x89, + 0x2b, 0xb6, 0x08, 0x31, 0x09, 0x82, 0x88, 0x80, + 0x89, 0x09, 0x32, 0x84, 0x40, 0xbf, 0x91, 0x88, + 0x89, 0x18, 0xd0, 0x93, 0x8b, 0x89, 0x40, 0xd4, + 0x31, 0x88, 0x9a, 0x81, 0xd1, 0x90, 0x8e, 0x89, + 0xd0, 0x8c, 0x87, 0x89, 0xd2, 0x8e, 0x83, 0x89, + 0x40, 0xf1, 0x8e, 0x40, 0xa4, 0x89, 0xc5, 0x28, + 0x09, 0x18, 0x00, 0x81, 0x8b, 0x89, 0xf6, 0x31, + 0x32, 0x80, 0x9b, 0x89, 0xa7, 0x30, 0x1f, 0x80, + 0x88, 0x8a, 0xad, 0x8f, 0x41, 0x94, 0x38, 0x87, + 0x8f, 0x89, 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, + 0x00, 0x08, 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, + 0x27, 0x89, 0x41, 0x48, 0x83, 0x88, 0x08, 0x80, + 0xaf, 0x32, 0x84, 0x8c, 0x89, 0x54, 0xe5, 0x05, + 0x8e, 0x60, 0x36, 0x09, 0x89, 0xd5, 0x89, 0xa5, + 0x84, 0xba, 0x86, 0x98, 0x89, 0x43, 0xf4, 0x00, + 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81, 0x60, 0x4c, + 0xaa, 0x81, 0x52, 0x60, 0xad, 0x81, 0x96, 0x42, + 0x1d, 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40, + 0x93, 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6, + 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, + 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, + 0x80, 0x40, 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63, + 0x80, 0xbc, 0x8d, 0x41, 0xf1, 0x8d, 0x43, 0xd5, + 0x86, 0xec, 0x34, 0x89, 0x52, 0x95, 0x89, 0x6c, + 0x05, 0x05, 0x40, 0xef, +}; + +static const uint8_t unicode_prop_ID_Continue1_index[63] = { + 0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a, + 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x60, 0xc7, + 0x0f, 0x20, 0xea, 0x17, 0x40, 0x05, 0x1b, 0x00, + 0x41, 0x20, 0x00, 0x0c, 0xa8, 0x80, 0x37, 0xaa, + 0x20, 0x50, 0xfe, 0x20, 0x3a, 0x0d, 0x21, 0x74, + 0x11, 0x01, 0x5a, 0x14, 0x21, 0x44, 0x19, 0x81, + 0x5a, 0x1d, 0xa1, 0xf5, 0x6a, 0x21, 0x45, 0xd2, + 0x41, 0xaf, 0xe2, 0x21, 0xf0, 0x01, 0x0e, +}; + +#ifdef CONFIG_ALL_UNICODE + +static const uint8_t unicode_cc_table[899] = { + 0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00, + 0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03, + 0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03, + 0xdc, 0xc7, 0x00, 0xf0, 0xc0, 0x02, 0xdc, 0xc2, + 0x01, 0xdc, 0x80, 0xc2, 0x03, 0xdc, 0xc0, 0x00, + 0xe8, 0x01, 0xdc, 0xc0, 0x41, 0xe9, 0x00, 0xea, + 0x41, 0xe9, 0x00, 0xea, 0x00, 0xe9, 0xcc, 0xb0, + 0xe2, 0xc4, 0xb0, 0xd8, 0x00, 0xdc, 0xc3, 0x00, + 0xdc, 0xc2, 0x00, 0xde, 0x00, 0xdc, 0xc5, 0x05, + 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xde, 0x00, + 0xe4, 0xc0, 0x49, 0x0a, 0x43, 0x13, 0x80, 0x00, + 0x17, 0x80, 0x41, 0x18, 0x80, 0xc0, 0x00, 0xdc, + 0x80, 0x00, 0x12, 0xb0, 0x17, 0xc7, 0x42, 0x1e, + 0xaf, 0x47, 0x1b, 0xc1, 0x01, 0xdc, 0xc4, 0x00, + 0xdc, 0xc1, 0x00, 0xdc, 0x8f, 0x00, 0x23, 0xb0, + 0x34, 0xc6, 0x81, 0xc3, 0x00, 0xdc, 0xc0, 0x81, + 0xc1, 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xa2, + 0x00, 0x24, 0x9d, 0xc0, 0x00, 0xdc, 0xc1, 0x00, + 0xdc, 0xc1, 0x02, 0xdc, 0xc0, 0x01, 0xdc, 0xc0, + 0x00, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x00, 0xdc, + 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xc1, 0xb0, + 0x6f, 0xc6, 0x00, 0xdc, 0xc0, 0x88, 0x00, 0xdc, + 0x97, 0xc3, 0x80, 0xc8, 0x80, 0xc2, 0x80, 0xc4, + 0xaa, 0x02, 0xdc, 0xb0, 0x0b, 0xc0, 0x02, 0xdc, + 0xc3, 0xa9, 0xc4, 0x04, 0xdc, 0xcd, 0x80, 0x00, + 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc2, + 0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, 0xdc, 0xc1, + 0x01, 0xdc, 0xc4, 0xb0, 0x0b, 0x00, 0x07, 0x8f, + 0x00, 0x09, 0x82, 0xc0, 0x00, 0xdc, 0xc1, 0xb0, + 0x36, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xaf, 0xc0, + 0xb0, 0x0c, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, + 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3d, + 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x4e, 0x00, + 0x09, 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, + 0x86, 0x00, 0x54, 0x00, 0x5b, 0xb0, 0x34, 0x00, + 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3c, 0x01, 0x09, + 0x8f, 0x00, 0x09, 0xb0, 0x4b, 0x00, 0x09, 0xb0, + 0x3c, 0x01, 0x67, 0x00, 0x09, 0x8c, 0x03, 0x6b, + 0xb0, 0x3b, 0x01, 0x76, 0x00, 0x09, 0x8c, 0x03, + 0x7a, 0xb0, 0x1b, 0x01, 0xdc, 0x9a, 0x00, 0xdc, + 0x80, 0x00, 0xdc, 0x80, 0x00, 0xd8, 0xb0, 0x06, + 0x41, 0x81, 0x80, 0x00, 0x84, 0x84, 0x03, 0x82, + 0x81, 0x00, 0x82, 0x80, 0xc1, 0x00, 0x09, 0x80, + 0xc1, 0xb0, 0x0d, 0x00, 0xdc, 0xb0, 0x3f, 0x00, + 0x07, 0x80, 0x01, 0x09, 0xb0, 0x21, 0x00, 0xdc, + 0xb2, 0x9e, 0xc2, 0xb3, 0x83, 0x01, 0x09, 0x9d, + 0x00, 0x09, 0xb0, 0x6c, 0x00, 0x09, 0x89, 0xc0, + 0xb0, 0x9a, 0x00, 0xe4, 0xb0, 0x5e, 0x00, 0xde, + 0xc0, 0x00, 0xdc, 0xb0, 0xaa, 0xc0, 0x00, 0xdc, + 0xb0, 0x16, 0x00, 0x09, 0x93, 0xc7, 0x81, 0x00, + 0xdc, 0xaf, 0xc4, 0x05, 0xdc, 0xc1, 0x00, 0xdc, + 0x80, 0x01, 0xdc, 0xc1, 0x01, 0xdc, 0xc4, 0x00, + 0xdc, 0xc3, 0xb0, 0x34, 0x00, 0x07, 0x8e, 0x00, + 0x09, 0xa5, 0xc0, 0x00, 0xdc, 0xc6, 0xb0, 0x05, + 0x01, 0x09, 0xb0, 0x09, 0x00, 0x07, 0x8a, 0x01, + 0x09, 0xb0, 0x12, 0x00, 0x07, 0xb0, 0x67, 0xc2, + 0x41, 0x00, 0x04, 0xdc, 0xc1, 0x03, 0xdc, 0xc0, + 0x41, 0x00, 0x05, 0x01, 0x83, 0x00, 0xdc, 0x85, + 0xc0, 0x82, 0xc1, 0xb0, 0x95, 0xc1, 0x00, 0xdc, + 0xc6, 0x00, 0xdc, 0xc1, 0x00, 0xea, 0x00, 0xd6, + 0x00, 0xdc, 0x00, 0xca, 0xe4, 0x00, 0xe8, 0x01, + 0xe4, 0x00, 0xdc, 0x00, 0xda, 0xc0, 0x00, 0xe9, + 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xb2, 0x9f, 0xc1, + 0x01, 0x01, 0xc3, 0x02, 0x01, 0xc1, 0x83, 0xc0, + 0x82, 0x01, 0x01, 0xc0, 0x00, 0xdc, 0xc0, 0x01, + 0x01, 0x03, 0xdc, 0xc0, 0xb8, 0x03, 0xcd, 0xc2, + 0xb0, 0x5c, 0x00, 0x09, 0xb0, 0x2f, 0xdf, 0xb1, + 0xf9, 0x00, 0xda, 0x00, 0xe4, 0x00, 0xe8, 0x00, + 0xde, 0x01, 0xe0, 0xb0, 0x38, 0x01, 0x08, 0xb8, + 0x6d, 0xa3, 0xc0, 0x83, 0xc9, 0x9f, 0xc1, 0xb0, + 0x1f, 0xc1, 0xb0, 0xe3, 0x00, 0x09, 0xa4, 0x00, + 0x09, 0xb0, 0x66, 0x00, 0x09, 0x9a, 0xd1, 0xb0, + 0x08, 0x02, 0xdc, 0xa4, 0x00, 0x09, 0xb0, 0x2e, + 0x00, 0x07, 0x8b, 0x00, 0x09, 0xb0, 0xbe, 0xc0, + 0x80, 0xc1, 0x00, 0xdc, 0x81, 0xc1, 0x84, 0xc1, + 0x80, 0xc0, 0xb0, 0x03, 0x00, 0x09, 0xb0, 0xc5, + 0x00, 0x09, 0xb8, 0x46, 0xff, 0x00, 0x1a, 0xb2, + 0xd0, 0xc6, 0x06, 0xdc, 0xc1, 0xb3, 0x9c, 0x00, + 0xdc, 0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64, 0xc4, + 0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0, + 0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0, + 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb1, + 0x52, 0xc1, 0xb0, 0x1f, 0x02, 0xdc, 0xb0, 0x15, + 0x01, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x03, 0xdc, + 0xb0, 0x00, 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, + 0xb0, 0x8f, 0x00, 0x09, 0xa8, 0x00, 0x09, 0x8d, + 0x00, 0x09, 0xb0, 0x08, 0x00, 0x09, 0x00, 0x07, + 0xb0, 0x14, 0xc2, 0xaf, 0x01, 0x09, 0xb0, 0x0d, + 0x00, 0x07, 0xb0, 0x1b, 0x00, 0x09, 0x88, 0x00, + 0x07, 0xb0, 0x39, 0x00, 0x09, 0x00, 0x07, 0xb0, + 0x81, 0x00, 0x07, 0x00, 0x09, 0xb0, 0x1f, 0x01, + 0x07, 0x8f, 0x00, 0x09, 0x97, 0xc6, 0x82, 0xc4, + 0xb0, 0x9c, 0x00, 0x09, 0x82, 0x00, 0x07, 0x96, + 0xc0, 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07, 0xb0, + 0xca, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d, 0x00, + 0x09, 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07, 0xb0, + 0x42, 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09, 0x00, + 0x07, 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00, 0x07, + 0xb0, 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00, 0x09, + 0x91, 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, + 0x74, 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07, 0x80, + 0x01, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x78, + 0x01, 0x09, 0xb8, 0x43, 0x7c, 0x04, 0x01, 0xb0, + 0x0a, 0xc6, 0xb4, 0x88, 0x01, 0x06, 0xb8, 0x44, + 0x7b, 0x00, 0x01, 0xb8, 0x0c, 0x95, 0x01, 0xd8, + 0x02, 0x01, 0x82, 0x00, 0xe2, 0x04, 0xd8, 0x87, + 0x07, 0xdc, 0x81, 0xc4, 0x01, 0xdc, 0x9d, 0xc3, + 0xb0, 0x63, 0xc2, 0xb8, 0x05, 0x8a, 0xc6, 0x80, + 0xd0, 0x81, 0xc6, 0x80, 0xc1, 0x80, 0xc4, 0xb0, + 0x33, 0xc0, 0xb0, 0x6f, 0xc6, 0xb1, 0x46, 0xc0, + 0xb0, 0x0c, 0xc3, 0xb1, 0xcb, 0x01, 0xe8, 0x00, + 0xdc, 0xc0, 0xb3, 0xaf, 0x06, 0xdc, 0xb0, 0x3c, + 0xc5, 0x00, 0x07, +}; + +static const uint8_t unicode_cc_index[87] = { + 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05, + 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c, + 0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00, + 0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10, + 0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3, + 0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00, + 0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab, + 0x00, 0x39, 0x0a, 0x01, 0x51, 0x0f, 0x01, 0x73, + 0x11, 0x01, 0x75, 0x13, 0x01, 0x2b, 0x17, 0x21, + 0x3f, 0x1c, 0x21, 0x9e, 0xbc, 0x21, 0x08, 0xe0, + 0x01, 0x44, 0xe9, 0x01, 0x4b, 0xe9, 0x01, +}; + +static const uint32_t unicode_decomp_table1[699] = { + 0x00280081, 0x002a0097, 0x002a8081, 0x002bc097, + 0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097, + 0x002e4115, 0x002f0199, 0x00302016, 0x00400842, + 0x00448a42, 0x004a0442, 0x004c0096, 0x004c8117, + 0x004d0242, 0x004e4342, 0x004fc12f, 0x0050c342, + 0x005240bf, 0x00530342, 0x00550942, 0x005a0842, + 0x005e0096, 0x005e4342, 0x005fc081, 0x00680142, + 0x006bc142, 0x00710185, 0x0071c317, 0x00734844, + 0x00778344, 0x00798342, 0x007b02be, 0x007c4197, + 0x007d0142, 0x007e0444, 0x00800e42, 0x00878142, + 0x00898744, 0x00ac0483, 0x00b60317, 0x00b80283, + 0x00d00214, 0x00d10096, 0x00dd0080, 0x00de8097, + 0x00df8080, 0x00e10097, 0x00e1413e, 0x00e1c080, + 0x00e204be, 0x00ea83ae, 0x00f282ae, 0x00f401ad, + 0x00f4c12e, 0x00f54103, 0x00fc0303, 0x00fe4081, + 0x0100023e, 0x0101c0be, 0x010301be, 0x010640be, + 0x010e40be, 0x0114023e, 0x0115c0be, 0x011701be, + 0x011d8144, 0x01304144, 0x01340244, 0x01358144, + 0x01368344, 0x01388344, 0x013a8644, 0x013e0144, + 0x0161c085, 0x018882ae, 0x019d422f, 0x01b00184, + 0x01b4c084, 0x024a4084, 0x024c4084, 0x024d0084, + 0x0256042e, 0x0272c12e, 0x02770120, 0x0277c084, + 0x028cc084, 0x028d8084, 0x029641ae, 0x02978084, + 0x02d20084, 0x02d2c12e, 0x02d70120, 0x02e50084, + 0x02f281ae, 0x03120084, 0x03300084, 0x0331c122, + 0x0332812e, 0x035281ae, 0x03768084, 0x037701ae, + 0x038cc085, 0x03acc085, 0x03b7012f, 0x03c30081, + 0x03d0c084, 0x03d34084, 0x03d48084, 0x03d5c084, + 0x03d70084, 0x03da4084, 0x03dcc084, 0x03dd412e, + 0x03ddc085, 0x03de0084, 0x03de4085, 0x03e04084, + 0x03e4c084, 0x03e74084, 0x03e88084, 0x03e9c084, + 0x03eb0084, 0x03ee4084, 0x04098084, 0x043f0081, + 0x06c18484, 0x06c48084, 0x06cec184, 0x06d00120, + 0x06d0c084, 0x074b0383, 0x074cc41f, 0x074f1783, + 0x075e0081, 0x0766d283, 0x07801d44, 0x078e8942, + 0x07931844, 0x079f0d42, 0x07a58216, 0x07a68085, + 0x07a6c0be, 0x07a80d44, 0x07aea044, 0x07c00122, + 0x07c08344, 0x07c20122, 0x07c28344, 0x07c40122, + 0x07c48244, 0x07c60122, 0x07c68244, 0x07c8113e, + 0x07d08244, 0x07d20122, 0x07d28244, 0x07d40122, + 0x07d48344, 0x07d64c3e, 0x07dc4080, 0x07dc80be, + 0x07dcc080, 0x07dd00be, 0x07dd4080, 0x07dd80be, + 0x07ddc080, 0x07de00be, 0x07de4080, 0x07de80be, + 0x07dec080, 0x07df00be, 0x07df4080, 0x07e00820, + 0x07e40820, 0x07e80820, 0x07ec05be, 0x07eec080, + 0x07ef00be, 0x07ef4097, 0x07ef8080, 0x07efc117, + 0x07f0443e, 0x07f24080, 0x07f280be, 0x07f2c080, + 0x07f303be, 0x07f4c080, 0x07f582ae, 0x07f6c080, + 0x07f7433e, 0x07f8c080, 0x07f903ae, 0x07fac080, + 0x07fb013e, 0x07fb8102, 0x07fc83be, 0x07fe4080, + 0x07fe80be, 0x07fec080, 0x07ff00be, 0x07ff4080, + 0x07ff8097, 0x0800011e, 0x08008495, 0x08044081, + 0x0805c097, 0x08090081, 0x08094097, 0x08098099, + 0x080bc081, 0x080cc085, 0x080d00b1, 0x080d8085, + 0x080dc0b1, 0x080f0197, 0x0811c197, 0x0815c0b3, + 0x0817c081, 0x081c0595, 0x081ec081, 0x081f0215, + 0x0820051f, 0x08228583, 0x08254415, 0x082a0097, + 0x08400119, 0x08408081, 0x0840c0bf, 0x08414119, + 0x0841c081, 0x084240bf, 0x0842852d, 0x08454081, + 0x08458097, 0x08464295, 0x08480097, 0x08484099, + 0x08488097, 0x08490081, 0x08498080, 0x084a0081, + 0x084a8102, 0x084b0495, 0x084d421f, 0x084e4081, + 0x084ec099, 0x084f0283, 0x08514295, 0x08540119, + 0x0854809b, 0x0854c619, 0x0857c097, 0x08580081, + 0x08584097, 0x08588099, 0x0858c097, 0x08590081, + 0x08594097, 0x08598099, 0x0859c09b, 0x085a0097, + 0x085a4081, 0x085a8097, 0x085ac099, 0x085b0295, + 0x085c4097, 0x085c8099, 0x085cc097, 0x085d0081, + 0x085d4097, 0x085d8099, 0x085dc09b, 0x085e0097, + 0x085e4081, 0x085e8097, 0x085ec099, 0x085f0215, + 0x08624099, 0x0866813e, 0x086b80be, 0x087341be, + 0x088100be, 0x088240be, 0x088300be, 0x088901be, + 0x088b0085, 0x088b40b1, 0x088bc085, 0x088c00b1, + 0x089040be, 0x089100be, 0x0891c1be, 0x089801be, + 0x089b42be, 0x089d0144, 0x089e0144, 0x08a00144, + 0x08a10144, 0x08a20144, 0x08ab023e, 0x08b80244, + 0x08ba8220, 0x08ca411e, 0x0918049f, 0x091a4523, + 0x091cc097, 0x091d04a5, 0x091f452b, 0x0921c09b, + 0x092204a1, 0x09244525, 0x0926c099, 0x09270d25, + 0x092d8d1f, 0x09340d1f, 0x093a8081, 0x0a8300b3, + 0x0a9d0099, 0x0a9d4097, 0x0a9d8099, 0x0ab700be, + 0x0b1f0115, 0x0b5bc081, 0x0ba7c081, 0x0bbcc081, + 0x0bc004ad, 0x0bc244ad, 0x0bc484ad, 0x0bc6f383, + 0x0be0852d, 0x0be31d03, 0x0bf1882d, 0x0c000081, + 0x0c0d8283, 0x0c130b84, 0x0c194284, 0x0c1c0122, + 0x0c1cc122, 0x0c1d8122, 0x0c1e4122, 0x0c1f0122, + 0x0c250084, 0x0c26c123, 0x0c278084, 0x0c27c085, + 0x0c2b0b84, 0x0c314284, 0x0c340122, 0x0c34c122, + 0x0c358122, 0x0c364122, 0x0c370122, 0x0c3d0084, + 0x0c3dc220, 0x0c3f8084, 0x0c3fc085, 0x0c4c4a2d, + 0x0c51451f, 0x0c53ca9f, 0x0c5915ad, 0x0c648703, + 0x0c800741, 0x0c838089, 0x0c83c129, 0x0c8441a9, + 0x0c850089, 0x0c854129, 0x0c85c2a9, 0x0c870089, + 0x0c87408f, 0x0c87808d, 0x0c881241, 0x0c910203, + 0x0c940099, 0x0c9444a3, 0x0c968323, 0x0c98072d, + 0x0c9b84af, 0x0c9dc2a1, 0x0c9f00b5, 0x0c9f40b3, + 0x0c9f8085, 0x0ca01883, 0x0cac4223, 0x0cad4523, + 0x0cafc097, 0x0cb004a1, 0x0cb241a5, 0x0cb30097, + 0x0cb34099, 0x0cb38097, 0x0cb3c099, 0x0cb417ad, + 0x0cbfc085, 0x0cc001b3, 0x0cc0c0b1, 0x0cc100b3, + 0x0cc14131, 0x0cc1c0b5, 0x0cc200b3, 0x0cc241b1, + 0x0cc30133, 0x0cc38131, 0x0cc40085, 0x0cc440b1, + 0x0cc48133, 0x0cc50085, 0x0cc540b5, 0x0cc580b7, + 0x0cc5c0b5, 0x0cc600b1, 0x0cc64135, 0x0cc6c0b3, + 0x0cc701b1, 0x0cc7c0b3, 0x0cc800b5, 0x0cc840b3, + 0x0cc881b1, 0x0cc9422f, 0x0cca4131, 0x0ccac0b5, + 0x0ccb00b1, 0x0ccb40b3, 0x0ccb80b5, 0x0ccbc0b1, + 0x0ccc012f, 0x0ccc80b5, 0x0cccc0b3, 0x0ccd00b5, + 0x0ccd40b1, 0x0ccd80b5, 0x0ccdc085, 0x0cce02b1, + 0x0ccf40b3, 0x0ccf80b1, 0x0ccfc085, 0x0cd001b1, + 0x0cd0c0b3, 0x0cd101b1, 0x0cd1c0b5, 0x0cd200b3, + 0x0cd24085, 0x0cd280b5, 0x0cd2c085, 0x0cd30133, + 0x0cd381b1, 0x0cd440b3, 0x0cd48085, 0x0cd4c0b1, + 0x0cd500b3, 0x0cd54085, 0x0cd580b5, 0x0cd5c0b1, + 0x0cd60521, 0x0cd88525, 0x0cdb02a5, 0x0cdc4099, + 0x0cdc8117, 0x0cdd0099, 0x0cdd4197, 0x0cde0127, + 0x0cde8285, 0x0cdfc089, 0x0ce0043f, 0x0ce20099, + 0x0ce2409b, 0x0ce283bf, 0x0ce44219, 0x0ce54205, + 0x0ce6433f, 0x0ce7c131, 0x0ce84085, 0x0ce881b1, + 0x0ce94085, 0x0ce98107, 0x0cea0089, 0x0cea4097, + 0x0cea8219, 0x0ceb809d, 0x0cebc08d, 0x0cec083f, + 0x0cf00105, 0x0cf0809b, 0x0cf0c197, 0x0cf1809b, + 0x0cf1c099, 0x0cf20517, 0x0cf48099, 0x0cf4c117, + 0x0cf54119, 0x0cf5c097, 0x0cf6009b, 0x0cf64099, + 0x0cf68217, 0x0cf78119, 0x0cf804a1, 0x0cfa4525, + 0x0cfcc525, 0x0cff4125, 0x0cffc099, 0x29a70103, + 0x29dc0081, 0x29fc8195, 0x29fe0103, 0x2ad70203, + 0x2ada4081, 0x3e401482, 0x3e4a7f82, 0x3e6a3f82, + 0x3e8aa102, 0x3e9b0110, 0x3e9c2f82, 0x3eb3c590, + 0x3ec00197, 0x3ec0c119, 0x3ec1413f, 0x3ec4c2af, + 0x3ec74184, 0x3ec804ad, 0x3eca4081, 0x3eca8304, + 0x3ecc03a0, 0x3ece02a0, 0x3ecf8084, 0x3ed00120, + 0x3ed0c120, 0x3ed184ae, 0x3ed3c085, 0x3ed4312d, + 0x3ef4cbad, 0x3efa892f, 0x3eff022d, 0x3f002f2f, + 0x3f1782a5, 0x3f18c0b1, 0x3f1907af, 0x3f1cffaf, + 0x3f3c81a5, 0x3f3d64af, 0x3f542031, 0x3f649b31, + 0x3f7c0131, 0x3f7c83b3, 0x3f7e40b1, 0x3f7e80bd, + 0x3f7ec0bb, 0x3f7f00b3, 0x3f840503, 0x3f8c01ad, + 0x3f8cc315, 0x3f8e462d, 0x3f91cc03, 0x3f97c695, + 0x3f9c01af, 0x3f9d0085, 0x3f9d852f, 0x3fa03aad, + 0x3fbd442f, 0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad, + 0x3fe80081, 0x3fe84f1f, 0x3ff0831f, 0x3ff2831f, + 0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41e04d83, + 0x41e70f91, 0x44268192, 0x442ac092, 0x444b8112, + 0x44d2c112, 0x452ec212, 0x456e8112, 0x464e0092, + 0x74578392, 0x746ec312, 0x75000d1f, 0x75068d1f, + 0x750d0d1f, 0x7513839f, 0x7515891f, 0x751a0d1f, + 0x75208d1f, 0x75271015, 0x752f439f, 0x7531459f, + 0x75340d1f, 0x753a8d1f, 0x75410395, 0x7543441f, + 0x7545839f, 0x75478d1f, 0x754e0795, 0x7552839f, + 0x75548d1f, 0x755b0d1f, 0x75618d1f, 0x75680d1f, + 0x756e8d1f, 0x75750d1f, 0x757b8d1f, 0x75820d1f, + 0x75888d1f, 0x758f0d1f, 0x75958d1f, 0x759c0d1f, + 0x75a28d1f, 0x75a90103, 0x75aa089f, 0x75ae4081, + 0x75ae839f, 0x75b04081, 0x75b08c9f, 0x75b6c081, + 0x75b7032d, 0x75b8889f, 0x75bcc081, 0x75bd039f, + 0x75bec081, 0x75bf0c9f, 0x75c54081, 0x75c5832d, + 0x75c7089f, 0x75cb4081, 0x75cb839f, 0x75cd4081, + 0x75cd8c9f, 0x75d3c081, 0x75d4032d, 0x75d5889f, + 0x75d9c081, 0x75da039f, 0x75dbc081, 0x75dc0c9f, + 0x75e24081, 0x75e2832d, 0x75e4089f, 0x75e84081, + 0x75e8839f, 0x75ea4081, 0x75ea8c9f, 0x75f0c081, + 0x75f1042d, 0x75f3851f, 0x75f6051f, 0x75f8851f, + 0x75fb051f, 0x75fd851f, 0x780c049f, 0x780e419f, + 0x780f059f, 0x7811c203, 0x7812d0ad, 0x781b0103, + 0x7b80022d, 0x7b814dad, 0x7b884203, 0x7b89c081, + 0x7b8a452d, 0x7b8d0403, 0x7b908081, 0x7b91dc03, + 0x7ba0052d, 0x7ba2c8ad, 0x7ba84483, 0x7baac8ad, + 0x7c400097, 0x7c404521, 0x7c440d25, 0x7c4a8087, + 0x7c4ac115, 0x7c4b4117, 0x7c4c0d1f, 0x7c528217, + 0x7c538099, 0x7c53c097, 0x7c5a8197, 0x7c640097, + 0x7c80012f, 0x7c808081, 0x7c841603, 0x7c9004c1, + 0x7c940103, 0x7efc051f, 0xbe0001ac, 0xbe00d110, + 0xbe0947ac, 0xbe0d3910, 0xbe29872c, 0xbe2d022c, + 0xbe2e3790, 0xbe49ff90, 0xbe69bc10, +}; + +static const uint16_t unicode_decomp_table2[699] = { + 0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008, + 0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3, + 0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8, + 0x0108, 0x010a, 0x0073, 0x0110, 0x0112, 0x0114, 0x0120, 0x012c, + 0x0144, 0x014d, 0x0153, 0x0162, 0x0168, 0x016a, 0x0176, 0x0192, + 0x0194, 0x01a9, 0x01bb, 0x01c7, 0x01d1, 0x01d5, 0x02b9, 0x01d7, + 0x003b, 0x01d9, 0x01db, 0x00b7, 0x01e1, 0x01fc, 0x020c, 0x0218, + 0x021d, 0x0223, 0x0227, 0x03a3, 0x0233, 0x023f, 0x0242, 0x024b, + 0x024e, 0x0251, 0x025d, 0x0260, 0x0269, 0x026c, 0x026f, 0x0275, + 0x0278, 0x0281, 0x028a, 0x029c, 0x029f, 0x02a3, 0x02af, 0x02b9, + 0x02c5, 0x02c9, 0x02cd, 0x02d1, 0x02d5, 0x02e7, 0x02ed, 0x02f1, + 0x02f5, 0x02f9, 0x02fd, 0x0305, 0x0309, 0x030d, 0x0313, 0x0317, + 0x031b, 0x0323, 0x0327, 0x032b, 0x032f, 0x0335, 0x033d, 0x0341, + 0x0349, 0x034d, 0x0351, 0x0f0b, 0x0357, 0x035b, 0x035f, 0x0363, + 0x0367, 0x036b, 0x036f, 0x0373, 0x0379, 0x037d, 0x0381, 0x0385, + 0x0389, 0x038d, 0x0391, 0x0395, 0x0399, 0x039d, 0x03a1, 0x10dc, + 0x03a5, 0x03c9, 0x03cd, 0x03d9, 0x03dd, 0x03e1, 0x03ef, 0x03f1, + 0x043d, 0x044f, 0x0499, 0x04f0, 0x0502, 0x054a, 0x0564, 0x056c, + 0x0570, 0x0573, 0x059a, 0x05fa, 0x05fe, 0x0607, 0x060b, 0x0614, + 0x0618, 0x061e, 0x0622, 0x0628, 0x068e, 0x0694, 0x0698, 0x069e, + 0x06a2, 0x06ab, 0x03ac, 0x06f3, 0x03ad, 0x06f6, 0x03ae, 0x06f9, + 0x03af, 0x06fc, 0x03cc, 0x06ff, 0x03cd, 0x0702, 0x03ce, 0x0705, + 0x0709, 0x070d, 0x0711, 0x0386, 0x0732, 0x0735, 0x03b9, 0x0737, + 0x073b, 0x0388, 0x0753, 0x0389, 0x0756, 0x0390, 0x076b, 0x038a, + 0x0777, 0x03b0, 0x0789, 0x038e, 0x0799, 0x079f, 0x07a3, 0x038c, + 0x07b8, 0x038f, 0x07bb, 0x00b4, 0x07be, 0x07c0, 0x07c2, 0x2010, + 0x07cb, 0x002e, 0x07cd, 0x07cf, 0x0020, 0x07d2, 0x07d6, 0x07db, + 0x07df, 0x07e4, 0x07ea, 0x07f0, 0x0020, 0x07f6, 0x2212, 0x0801, + 0x0805, 0x0807, 0x081d, 0x0825, 0x0827, 0x0043, 0x082d, 0x0830, + 0x0190, 0x0836, 0x0839, 0x004e, 0x0845, 0x0847, 0x084c, 0x084e, + 0x0851, 0x005a, 0x03a9, 0x005a, 0x0853, 0x0857, 0x0860, 0x0069, + 0x0862, 0x0865, 0x086f, 0x0874, 0x087a, 0x087e, 0x08a2, 0x0049, + 0x08a4, 0x08a6, 0x08a9, 0x0056, 0x08ab, 0x08ad, 0x08b0, 0x08b4, + 0x0058, 0x08b6, 0x08b8, 0x08bb, 0x08c0, 0x08c2, 0x08c5, 0x0076, + 0x08c7, 0x08c9, 0x08cc, 0x08d0, 0x0078, 0x08d2, 0x08d4, 0x08d7, + 0x08db, 0x08de, 0x08e4, 0x08e7, 0x08f0, 0x08f3, 0x08f6, 0x08f9, + 0x0902, 0x0906, 0x090b, 0x090f, 0x0914, 0x0917, 0x091a, 0x0923, + 0x092c, 0x093b, 0x093e, 0x0941, 0x0944, 0x0947, 0x094a, 0x0956, + 0x095c, 0x0960, 0x0962, 0x0964, 0x0968, 0x096a, 0x0970, 0x0978, + 0x097c, 0x0980, 0x0986, 0x0989, 0x098f, 0x0991, 0x0030, 0x0993, + 0x0999, 0x099c, 0x099e, 0x09a1, 0x09a4, 0x2d61, 0x6bcd, 0x9f9f, + 0x09a6, 0x09b1, 0x09bc, 0x09c7, 0x0a95, 0x0aa1, 0x0b15, 0x0020, + 0x0b27, 0x0b31, 0x0b8d, 0x0ba1, 0x0ba5, 0x0ba9, 0x0bad, 0x0bb1, + 0x0bb5, 0x0bb9, 0x0bbd, 0x0bc1, 0x0bc5, 0x0c21, 0x0c35, 0x0c39, + 0x0c3d, 0x0c41, 0x0c45, 0x0c49, 0x0c4d, 0x0c51, 0x0c55, 0x0c59, + 0x0c6f, 0x0c71, 0x0c73, 0x0ca0, 0x0cbc, 0x0cdc, 0x0ce4, 0x0cec, + 0x0cf4, 0x0cfc, 0x0d04, 0x0d0c, 0x0d14, 0x0d22, 0x0d2e, 0x0d7a, + 0x0d82, 0x0d85, 0x0d89, 0x0d8d, 0x0d9d, 0x0db1, 0x0db5, 0x0dbc, + 0x0dc2, 0x0dc6, 0x0e28, 0x0e2c, 0x0e30, 0x0e32, 0x0e36, 0x0e3c, + 0x0e3e, 0x0e41, 0x0e43, 0x0e46, 0x0e77, 0x0e7b, 0x0e89, 0x0e8e, + 0x0e94, 0x0e9c, 0x0ea3, 0x0ea9, 0x0eb4, 0x0ebe, 0x0ec6, 0x0eca, + 0x0ecf, 0x0ed9, 0x0edd, 0x0ee4, 0x0eec, 0x0ef3, 0x0ef8, 0x0f04, + 0x0f0a, 0x0f15, 0x0f1b, 0x0f22, 0x0f28, 0x0f33, 0x0f3d, 0x0f45, + 0x0f4c, 0x0f51, 0x0f57, 0x0f5e, 0x0f63, 0x0f69, 0x0f70, 0x0f76, + 0x0f7d, 0x0f82, 0x0f89, 0x0f8d, 0x0f9e, 0x0fa4, 0x0fa9, 0x0fad, + 0x0fb8, 0x0fbe, 0x0fc9, 0x0fd0, 0x0fd6, 0x0fda, 0x0fe1, 0x0fe5, + 0x0fef, 0x0ffa, 0x1000, 0x1004, 0x1009, 0x100f, 0x1013, 0x101a, + 0x101f, 0x1023, 0x1029, 0x102f, 0x1032, 0x1036, 0x1039, 0x103f, + 0x1045, 0x1059, 0x1061, 0x1079, 0x107c, 0x1080, 0x1095, 0x10a1, + 0x10b1, 0x10c3, 0x10cb, 0x10cf, 0x10da, 0x10de, 0x10ea, 0x10f2, + 0x10f4, 0x1100, 0x1105, 0x1111, 0x1141, 0x1149, 0x114d, 0x1153, + 0x1157, 0x115a, 0x116e, 0x1171, 0x1175, 0x117b, 0x117d, 0x1181, + 0x1184, 0x118c, 0x1192, 0x1196, 0x119c, 0x11a2, 0x11a8, 0x11ab, + 0xa76f, 0x11af, 0x11b2, 0x11b6, 0x028d, 0x11be, 0x1210, 0x130e, + 0x140c, 0x1490, 0x1495, 0x1553, 0x156c, 0x1572, 0x1578, 0x157e, + 0x158a, 0x1596, 0x002b, 0x15a1, 0x15b9, 0x15bd, 0x15c1, 0x15c5, + 0x15c9, 0x15cd, 0x15e1, 0x15e5, 0x1649, 0x1662, 0x1688, 0x168e, + 0x174c, 0x1752, 0x1757, 0x1777, 0x1877, 0x187d, 0x1911, 0x19d3, + 0x1a77, 0x1a7f, 0x1a9d, 0x1aa2, 0x1ab6, 0x1ac0, 0x1ac6, 0x1ada, + 0x1adf, 0x1ae5, 0x1af3, 0x1b23, 0x1b30, 0x1b38, 0x1b3c, 0x1b52, + 0x1bc9, 0x1bdb, 0x1bdd, 0x1bdf, 0x3164, 0x1c20, 0x1c22, 0x1c24, + 0x1c26, 0x1c28, 0x1c2a, 0x1c48, 0x1c7e, 0x1cc4, 0x1cd2, 0x1cd7, + 0x1ce0, 0x1ce9, 0x1cfb, 0x1d04, 0x1d09, 0x1d29, 0x1d44, 0x1d46, + 0x1d48, 0x1d4a, 0x1d4c, 0x1d4e, 0x1d50, 0x1d52, 0x1d72, 0x1d74, + 0x1d76, 0x1d78, 0x1d7a, 0x1d81, 0x1d83, 0x1d85, 0x1d87, 0x1d96, + 0x1d98, 0x1d9a, 0x1d9c, 0x1d9e, 0x1da0, 0x1da2, 0x1da4, 0x1da6, + 0x1da8, 0x1daa, 0x1dac, 0x1dae, 0x1db0, 0x1db2, 0x1db6, 0x03f4, + 0x1db8, 0x2207, 0x1dba, 0x2202, 0x1dbc, 0x1dc4, 0x03f4, 0x1dc6, + 0x2207, 0x1dc8, 0x2202, 0x1dca, 0x1dd2, 0x03f4, 0x1dd4, 0x2207, + 0x1dd6, 0x2202, 0x1dd8, 0x1de0, 0x03f4, 0x1de2, 0x2207, 0x1de4, + 0x2202, 0x1de6, 0x1dee, 0x03f4, 0x1df0, 0x2207, 0x1df2, 0x2202, + 0x1df4, 0x1dfe, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, + 0x1e0c, 0x1e0e, 0x1e16, 0x1e39, 0x1e3d, 0x1e43, 0x1e60, 0x062d, + 0x1e68, 0x1e74, 0x062c, 0x1e84, 0x1ef4, 0x1f00, 0x1f13, 0x1f25, + 0x1f38, 0x1f3a, 0x1f3e, 0x1f44, 0x1f4a, 0x1f4c, 0x1f50, 0x1f52, + 0x1f5a, 0x1f5d, 0x1f5f, 0x1f65, 0x1f67, 0x30b5, 0x1f6d, 0x1fc5, + 0x1fdb, 0x1fdf, 0x1fe1, 0x1fe6, 0x2033, 0x2044, 0x2145, 0x2155, + 0x215b, 0x2255, 0x2373, +}; + +static const uint8_t unicode_decomp_data[9345] = { + 0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81, + 0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31, + 0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41, + 0x81, 0x41, 0x82, 0x41, 0x83, 0x41, 0x88, 0x41, + 0x8a, 0x00, 0x00, 0x43, 0xa7, 0x45, 0x80, 0x45, + 0x81, 0x45, 0x82, 0x45, 0x88, 0x49, 0x80, 0x49, + 0x81, 0x49, 0x82, 0x49, 0x88, 0x00, 0x00, 0x4e, + 0x83, 0x4f, 0x80, 0x4f, 0x81, 0x4f, 0x82, 0x4f, + 0x83, 0x4f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x55, + 0x80, 0x55, 0x81, 0x55, 0x82, 0x55, 0x88, 0x59, + 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x61, + 0x81, 0x61, 0x82, 0x61, 0x83, 0x61, 0x88, 0x61, + 0x8a, 0x00, 0x00, 0x63, 0xa7, 0x65, 0x80, 0x65, + 0x81, 0x65, 0x82, 0x65, 0x88, 0x69, 0x80, 0x69, + 0x81, 0x69, 0x82, 0x69, 0x88, 0x00, 0x00, 0x6e, + 0x83, 0x6f, 0x80, 0x6f, 0x81, 0x6f, 0x82, 0x6f, + 0x83, 0x6f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x75, + 0x80, 0x75, 0x81, 0x75, 0x82, 0x75, 0x88, 0x79, + 0x81, 0x00, 0x00, 0x79, 0x88, 0x41, 0x84, 0x41, + 0x86, 0x41, 0xa8, 0x43, 0x81, 0x43, 0x82, 0x43, + 0x87, 0x43, 0x8c, 0x44, 0x8c, 0x45, 0x84, 0x45, + 0x86, 0x45, 0x87, 0x45, 0xa8, 0x45, 0x8c, 0x47, + 0x82, 0x47, 0x86, 0x47, 0x87, 0x47, 0xa7, 0x48, + 0x82, 0x49, 0x83, 0x49, 0x84, 0x49, 0x86, 0x49, + 0xa8, 0x49, 0x87, 0x49, 0x4a, 0x69, 0x6a, 0x4a, + 0x82, 0x4b, 0xa7, 0x4c, 0x81, 0x4c, 0xa7, 0x4c, + 0x8c, 0x4c, 0x00, 0x00, 0x6b, 0x20, 0x6b, 0x4e, + 0x81, 0x4e, 0xa7, 0x4e, 0x8c, 0xbc, 0x02, 0x6e, + 0x4f, 0x84, 0x4f, 0x86, 0x4f, 0x8b, 0x52, 0x81, + 0x52, 0xa7, 0x52, 0x8c, 0x53, 0x81, 0x53, 0x82, + 0x53, 0xa7, 0x53, 0x8c, 0x54, 0xa7, 0x54, 0x8c, + 0x55, 0x83, 0x55, 0x84, 0x55, 0x86, 0x55, 0x8a, + 0x55, 0x8b, 0x55, 0xa8, 0x57, 0x82, 0x59, 0x82, + 0x59, 0x88, 0x5a, 0x81, 0x5a, 0x87, 0x5a, 0x8c, + 0x4f, 0x9b, 0x55, 0x9b, 0x44, 0x00, 0x7d, 0x01, + 0x44, 0x00, 0x7e, 0x01, 0x64, 0x00, 0x7e, 0x01, + 0x4c, 0x4a, 0x4c, 0x6a, 0x6c, 0x6a, 0x4e, 0x4a, + 0x4e, 0x6a, 0x6e, 0x6a, 0x41, 0x00, 0x8c, 0x49, + 0x00, 0x8c, 0x4f, 0x00, 0x8c, 0x55, 0x00, 0x8c, + 0xdc, 0x00, 0x84, 0xdc, 0x00, 0x81, 0xdc, 0x00, + 0x8c, 0xdc, 0x00, 0x80, 0xc4, 0x00, 0x84, 0x26, + 0x02, 0x84, 0xc6, 0x00, 0x84, 0x47, 0x8c, 0x4b, + 0x8c, 0x4f, 0xa8, 0xea, 0x01, 0x84, 0xeb, 0x01, + 0x84, 0xb7, 0x01, 0x8c, 0x92, 0x02, 0x8c, 0x6a, + 0x00, 0x8c, 0x44, 0x5a, 0x44, 0x7a, 0x64, 0x7a, + 0x47, 0x81, 0x4e, 0x00, 0x80, 0xc5, 0x00, 0x81, + 0xc6, 0x00, 0x81, 0xd8, 0x00, 0x81, 0x41, 0x8f, + 0x41, 0x91, 0x45, 0x8f, 0x45, 0x91, 0x49, 0x8f, + 0x49, 0x91, 0x4f, 0x8f, 0x4f, 0x91, 0x52, 0x8f, + 0x52, 0x91, 0x55, 0x8f, 0x55, 0x91, 0x53, 0xa6, + 0x54, 0xa6, 0x48, 0x8c, 0x41, 0x00, 0x87, 0x45, + 0x00, 0xa7, 0xd6, 0x00, 0x84, 0xd5, 0x00, 0x84, + 0x4f, 0x00, 0x87, 0x2e, 0x02, 0x84, 0x59, 0x00, + 0x84, 0x68, 0x00, 0x66, 0x02, 0x6a, 0x00, 0x72, + 0x00, 0x79, 0x02, 0x7b, 0x02, 0x81, 0x02, 0x77, + 0x00, 0x79, 0x00, 0x20, 0x86, 0x20, 0x87, 0x20, + 0x8a, 0x20, 0xa8, 0x20, 0x83, 0x20, 0x8b, 0x63, + 0x02, 0x6c, 0x00, 0x73, 0x00, 0x78, 0x00, 0x95, + 0x02, 0x80, 0x81, 0x00, 0x93, 0x88, 0x81, 0x20, + 0xc5, 0x20, 0x81, 0xa8, 0x00, 0x81, 0x91, 0x03, + 0x81, 0x95, 0x03, 0x81, 0x97, 0x03, 0x81, 0x99, + 0x03, 0x81, 0x00, 0x00, 0x00, 0x9f, 0x03, 0x81, + 0x00, 0x00, 0x00, 0xa5, 0x03, 0x81, 0xa9, 0x03, + 0x81, 0xca, 0x03, 0x81, 0x01, 0x03, 0x98, 0x07, + 0xa4, 0x07, 0xb0, 0x00, 0xb4, 0x00, 0xb6, 0x00, + 0xb8, 0x00, 0xca, 0x00, 0x01, 0x03, 0xb8, 0x07, + 0xc4, 0x07, 0xbe, 0x00, 0xc4, 0x00, 0xc8, 0x00, + 0xa5, 0x03, 0x0d, 0x13, 0x00, 0x01, 0x03, 0xd1, + 0x00, 0xd1, 0x07, 0xc6, 0x03, 0xc0, 0x03, 0xba, + 0x03, 0xc1, 0x03, 0xc2, 0x03, 0x00, 0x00, 0x98, + 0x03, 0xb5, 0x03, 0x15, 0x04, 0x80, 0x15, 0x04, + 0x88, 0x00, 0x00, 0x00, 0x13, 0x04, 0x81, 0x06, + 0x04, 0x88, 0x1a, 0x04, 0x81, 0x18, 0x04, 0x80, + 0x23, 0x04, 0x86, 0x18, 0x04, 0x86, 0x38, 0x04, + 0x86, 0x35, 0x04, 0x80, 0x35, 0x04, 0x88, 0x00, + 0x00, 0x00, 0x33, 0x04, 0x81, 0x56, 0x04, 0x88, + 0x3a, 0x04, 0x81, 0x38, 0x04, 0x80, 0x43, 0x04, + 0x86, 0x74, 0x04, 0x8f, 0x16, 0x04, 0x86, 0x10, + 0x04, 0x86, 0x10, 0x04, 0x88, 0x15, 0x04, 0x86, + 0xd8, 0x04, 0x88, 0x16, 0x04, 0x88, 0x17, 0x04, + 0x88, 0x18, 0x04, 0x84, 0x18, 0x04, 0x88, 0x1e, + 0x04, 0x88, 0xe8, 0x04, 0x88, 0x2d, 0x04, 0x88, + 0x23, 0x04, 0x84, 0x23, 0x04, 0x88, 0x23, 0x04, + 0x8b, 0x27, 0x04, 0x88, 0x2b, 0x04, 0x88, 0x65, + 0x05, 0x82, 0x05, 0x27, 0x06, 0x00, 0x2c, 0x00, + 0x2d, 0x21, 0x2d, 0x00, 0x2e, 0x23, 0x2d, 0x27, + 0x06, 0x00, 0x4d, 0x21, 0x4d, 0xa0, 0x4d, 0x23, + 0x4d, 0xd5, 0x06, 0x54, 0x06, 0x00, 0x00, 0x00, + 0x00, 0xc1, 0x06, 0x54, 0x06, 0xd2, 0x06, 0x54, + 0x06, 0x28, 0x09, 0x3c, 0x09, 0x30, 0x09, 0x3c, + 0x09, 0x33, 0x09, 0x3c, 0x09, 0x15, 0x09, 0x00, + 0x27, 0x01, 0x27, 0x02, 0x27, 0x07, 0x27, 0x0c, + 0x27, 0x0d, 0x27, 0x16, 0x27, 0x1a, 0x27, 0xbe, + 0x09, 0x09, 0x00, 0x09, 0x19, 0xa1, 0x09, 0xbc, + 0x09, 0xaf, 0x09, 0xbc, 0x09, 0x32, 0x0a, 0x3c, + 0x0a, 0x38, 0x0a, 0x3c, 0x0a, 0x16, 0x0a, 0x00, + 0x26, 0x01, 0x26, 0x06, 0x26, 0x2b, 0x0a, 0x3c, + 0x0a, 0x47, 0x0b, 0x56, 0x0b, 0x3e, 0x0b, 0x09, + 0x00, 0x09, 0x19, 0x21, 0x0b, 0x3c, 0x0b, 0x92, + 0x0b, 0xd7, 0x0b, 0xbe, 0x0b, 0x08, 0x00, 0x09, + 0x00, 0x08, 0x19, 0x46, 0x0c, 0x56, 0x0c, 0xbf, + 0x0c, 0xd5, 0x0c, 0xc6, 0x0c, 0xd5, 0x0c, 0xc2, + 0x0c, 0x04, 0x00, 0x08, 0x13, 0x3e, 0x0d, 0x08, + 0x00, 0x09, 0x00, 0x08, 0x19, 0xd9, 0x0d, 0xca, + 0x0d, 0xca, 0x0d, 0x0f, 0x05, 0x12, 0x00, 0x0f, + 0x15, 0x4d, 0x0e, 0x32, 0x0e, 0xcd, 0x0e, 0xb2, + 0x0e, 0x99, 0x0e, 0x12, 0x00, 0x12, 0x08, 0x42, + 0x0f, 0xb7, 0x0f, 0x4c, 0x0f, 0xb7, 0x0f, 0x51, + 0x0f, 0xb7, 0x0f, 0x56, 0x0f, 0xb7, 0x0f, 0x5b, + 0x0f, 0xb7, 0x0f, 0x40, 0x0f, 0xb5, 0x0f, 0x71, + 0x0f, 0x72, 0x0f, 0x71, 0x0f, 0x00, 0x03, 0x41, + 0x0f, 0xb2, 0x0f, 0x81, 0x0f, 0xb3, 0x0f, 0x80, + 0x0f, 0xb3, 0x0f, 0x81, 0x0f, 0x71, 0x0f, 0x80, + 0x0f, 0x92, 0x0f, 0xb7, 0x0f, 0x9c, 0x0f, 0xb7, + 0x0f, 0xa1, 0x0f, 0xb7, 0x0f, 0xa6, 0x0f, 0xb7, + 0x0f, 0xab, 0x0f, 0xb7, 0x0f, 0x90, 0x0f, 0xb5, + 0x0f, 0x25, 0x10, 0x2e, 0x10, 0x05, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x09, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x1b, 0x35, + 0x1b, 0x11, 0x1b, 0x35, 0x1b, 0x3a, 0x1b, 0x35, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1b, 0x35, + 0x1b, 0x3e, 0x1b, 0x35, 0x1b, 0x42, 0x1b, 0x35, + 0x1b, 0x41, 0x00, 0xc6, 0x00, 0x42, 0x00, 0x00, + 0x00, 0x44, 0x00, 0x45, 0x00, 0x8e, 0x01, 0x47, + 0x00, 0x4f, 0x00, 0x22, 0x02, 0x50, 0x00, 0x52, + 0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x61, + 0x00, 0x50, 0x02, 0x51, 0x02, 0x02, 0x1d, 0x62, + 0x00, 0x64, 0x00, 0x65, 0x00, 0x59, 0x02, 0x5b, + 0x02, 0x5c, 0x02, 0x67, 0x00, 0x00, 0x00, 0x6b, + 0x00, 0x6d, 0x00, 0x4b, 0x01, 0x6f, 0x00, 0x54, + 0x02, 0x16, 0x1d, 0x17, 0x1d, 0x70, 0x00, 0x74, + 0x00, 0x75, 0x00, 0x1d, 0x1d, 0x6f, 0x02, 0x76, + 0x00, 0x25, 0x1d, 0xb2, 0x03, 0xb3, 0x03, 0xb4, + 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x69, 0x00, 0x72, + 0x00, 0x75, 0x00, 0x76, 0x00, 0xb2, 0x03, 0xb3, + 0x03, 0xc1, 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x52, + 0x02, 0x63, 0x00, 0x55, 0x02, 0xf0, 0x00, 0x5c, + 0x02, 0x66, 0x00, 0x5f, 0x02, 0x61, 0x02, 0x65, + 0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x7b, + 0x1d, 0x9d, 0x02, 0x6d, 0x02, 0x85, 0x1d, 0x9f, + 0x02, 0x71, 0x02, 0x70, 0x02, 0x72, 0x02, 0x73, + 0x02, 0x74, 0x02, 0x75, 0x02, 0x78, 0x02, 0x82, + 0x02, 0x83, 0x02, 0xab, 0x01, 0x89, 0x02, 0x8a, + 0x02, 0x1c, 0x1d, 0x8b, 0x02, 0x8c, 0x02, 0x7a, + 0x00, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0xb8, + 0x03, 0x41, 0x00, 0xa5, 0x42, 0x00, 0x87, 0x42, + 0x00, 0xa3, 0x42, 0x00, 0xb1, 0xc7, 0x00, 0x81, + 0x44, 0x00, 0x87, 0x44, 0x00, 0xa3, 0x44, 0x00, + 0xb1, 0x44, 0x00, 0xa7, 0x44, 0x00, 0xad, 0x12, + 0x01, 0x80, 0x12, 0x01, 0x81, 0x45, 0x00, 0xad, + 0x45, 0x00, 0xb0, 0x28, 0x02, 0x86, 0x46, 0x00, + 0x87, 0x47, 0x00, 0x84, 0x48, 0x00, 0x87, 0x48, + 0x00, 0xa3, 0x48, 0x00, 0x88, 0x48, 0x00, 0xa7, + 0x48, 0x00, 0xae, 0x49, 0x00, 0xb0, 0xcf, 0x00, + 0x81, 0x4b, 0x00, 0x81, 0x4b, 0x00, 0xa3, 0x4b, + 0x00, 0xb1, 0x4c, 0x00, 0xa3, 0x36, 0x1e, 0x84, + 0x4c, 0xb1, 0x4c, 0xad, 0x4d, 0x81, 0x4d, 0x87, + 0x4d, 0xa3, 0x4e, 0x87, 0x4e, 0xa3, 0x4e, 0xb1, + 0x4e, 0xad, 0xd5, 0x00, 0x81, 0xd5, 0x00, 0x88, + 0x4c, 0x01, 0x80, 0x4c, 0x01, 0x81, 0x50, 0x00, + 0x81, 0x50, 0x00, 0x87, 0x52, 0x00, 0x87, 0x52, + 0x00, 0xa3, 0x5a, 0x1e, 0x84, 0x52, 0x00, 0xb1, + 0x53, 0x00, 0x87, 0x53, 0x00, 0xa3, 0x5a, 0x01, + 0x87, 0x60, 0x01, 0x87, 0x62, 0x1e, 0x87, 0x54, + 0x00, 0x87, 0x54, 0x00, 0xa3, 0x54, 0x00, 0xb1, + 0x54, 0x00, 0xad, 0x55, 0x00, 0xa4, 0x55, 0x00, + 0xb0, 0x55, 0x00, 0xad, 0x68, 0x01, 0x81, 0x6a, + 0x01, 0x88, 0x56, 0x83, 0x56, 0xa3, 0x57, 0x80, + 0x57, 0x81, 0x57, 0x88, 0x57, 0x87, 0x57, 0xa3, + 0x58, 0x87, 0x58, 0x88, 0x59, 0x87, 0x5a, 0x82, + 0x5a, 0xa3, 0x5a, 0xb1, 0x68, 0xb1, 0x74, 0x88, + 0x77, 0x8a, 0x79, 0x8a, 0x61, 0x00, 0xbe, 0x02, + 0x7f, 0x01, 0x87, 0x41, 0x00, 0xa3, 0x41, 0x00, + 0x89, 0xc2, 0x00, 0x81, 0xc2, 0x00, 0x80, 0xc2, + 0x00, 0x89, 0xc2, 0x00, 0x83, 0xa0, 0x1e, 0x82, + 0x02, 0x01, 0x81, 0x02, 0x01, 0x80, 0x02, 0x01, + 0x89, 0x02, 0x01, 0x83, 0xa0, 0x1e, 0x86, 0x45, + 0x00, 0xa3, 0x45, 0x00, 0x89, 0x45, 0x00, 0x83, + 0xca, 0x00, 0x81, 0xca, 0x00, 0x80, 0xca, 0x00, + 0x89, 0xca, 0x00, 0x83, 0xb8, 0x1e, 0x82, 0x49, + 0x00, 0x89, 0x49, 0x00, 0xa3, 0x4f, 0x00, 0xa3, + 0x4f, 0x00, 0x89, 0xd4, 0x00, 0x81, 0xd4, 0x00, + 0x80, 0xd4, 0x00, 0x89, 0xd4, 0x00, 0x83, 0xcc, + 0x1e, 0x82, 0xa0, 0x01, 0x81, 0xa0, 0x01, 0x80, + 0xa0, 0x01, 0x89, 0xa0, 0x01, 0x83, 0xa0, 0x01, + 0xa3, 0x55, 0x00, 0xa3, 0x55, 0x00, 0x89, 0xaf, + 0x01, 0x81, 0xaf, 0x01, 0x80, 0xaf, 0x01, 0x89, + 0xaf, 0x01, 0x83, 0xaf, 0x01, 0xa3, 0x59, 0x00, + 0x80, 0x59, 0x00, 0xa3, 0x59, 0x00, 0x89, 0x59, + 0x00, 0x83, 0xb1, 0x03, 0x13, 0x03, 0x00, 0x1f, + 0x80, 0x00, 0x1f, 0x81, 0x00, 0x1f, 0xc2, 0x91, + 0x03, 0x13, 0x03, 0x08, 0x1f, 0x80, 0x08, 0x1f, + 0x81, 0x08, 0x1f, 0xc2, 0xb5, 0x03, 0x13, 0x03, + 0x10, 0x1f, 0x80, 0x10, 0x1f, 0x81, 0x95, 0x03, + 0x13, 0x03, 0x18, 0x1f, 0x80, 0x18, 0x1f, 0x81, + 0xb7, 0x03, 0x93, 0xb7, 0x03, 0x94, 0x20, 0x1f, + 0x80, 0x21, 0x1f, 0x80, 0x20, 0x1f, 0x81, 0x21, + 0x1f, 0x81, 0x20, 0x1f, 0xc2, 0x21, 0x1f, 0xc2, + 0x97, 0x03, 0x93, 0x97, 0x03, 0x94, 0x28, 0x1f, + 0x80, 0x29, 0x1f, 0x80, 0x28, 0x1f, 0x81, 0x29, + 0x1f, 0x81, 0x28, 0x1f, 0xc2, 0x29, 0x1f, 0xc2, + 0xb9, 0x03, 0x93, 0xb9, 0x03, 0x94, 0x30, 0x1f, + 0x80, 0x31, 0x1f, 0x80, 0x30, 0x1f, 0x81, 0x31, + 0x1f, 0x81, 0x30, 0x1f, 0xc2, 0x31, 0x1f, 0xc2, + 0x99, 0x03, 0x93, 0x99, 0x03, 0x94, 0x38, 0x1f, + 0x80, 0x39, 0x1f, 0x80, 0x38, 0x1f, 0x81, 0x39, + 0x1f, 0x81, 0x38, 0x1f, 0xc2, 0x39, 0x1f, 0xc2, + 0xbf, 0x03, 0x93, 0xbf, 0x03, 0x94, 0x40, 0x1f, + 0x80, 0x40, 0x1f, 0x81, 0x9f, 0x03, 0x13, 0x03, + 0x48, 0x1f, 0x80, 0x48, 0x1f, 0x81, 0xc5, 0x03, + 0x13, 0x03, 0x50, 0x1f, 0x80, 0x50, 0x1f, 0x81, + 0x50, 0x1f, 0xc2, 0xa5, 0x03, 0x94, 0x00, 0x00, + 0x00, 0x59, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x59, + 0x1f, 0x81, 0x00, 0x00, 0x00, 0x59, 0x1f, 0xc2, + 0xc9, 0x03, 0x93, 0xc9, 0x03, 0x94, 0x60, 0x1f, + 0x80, 0x61, 0x1f, 0x80, 0x60, 0x1f, 0x81, 0x61, + 0x1f, 0x81, 0x60, 0x1f, 0xc2, 0x61, 0x1f, 0xc2, + 0xa9, 0x03, 0x93, 0xa9, 0x03, 0x94, 0x68, 0x1f, + 0x80, 0x69, 0x1f, 0x80, 0x68, 0x1f, 0x81, 0x69, + 0x1f, 0x81, 0x68, 0x1f, 0xc2, 0x69, 0x1f, 0xc2, + 0xb1, 0x03, 0x80, 0xb5, 0x03, 0x80, 0xb7, 0x03, + 0x80, 0xb9, 0x03, 0x80, 0xbf, 0x03, 0x80, 0xc5, + 0x03, 0x80, 0xc9, 0x03, 0x80, 0x00, 0x1f, 0x45, + 0x03, 0x20, 0x1f, 0x45, 0x03, 0x60, 0x1f, 0x45, + 0x03, 0xb1, 0x03, 0x86, 0xb1, 0x03, 0x84, 0x70, + 0x1f, 0xc5, 0xb1, 0x03, 0xc5, 0xac, 0x03, 0xc5, + 0x00, 0x00, 0x00, 0xb1, 0x03, 0xc2, 0xb6, 0x1f, + 0xc5, 0x91, 0x03, 0x86, 0x91, 0x03, 0x84, 0x91, + 0x03, 0x80, 0x91, 0x03, 0xc5, 0x20, 0x93, 0x20, + 0x93, 0x20, 0xc2, 0xa8, 0x00, 0xc2, 0x74, 0x1f, + 0xc5, 0xb7, 0x03, 0xc5, 0xae, 0x03, 0xc5, 0x00, + 0x00, 0x00, 0xb7, 0x03, 0xc2, 0xc6, 0x1f, 0xc5, + 0x95, 0x03, 0x80, 0x97, 0x03, 0x80, 0x97, 0x03, + 0xc5, 0xbf, 0x1f, 0x80, 0xbf, 0x1f, 0x81, 0xbf, + 0x1f, 0xc2, 0xb9, 0x03, 0x86, 0xb9, 0x03, 0x84, + 0xca, 0x03, 0x80, 0x00, 0x03, 0xb9, 0x42, 0xca, + 0x42, 0x99, 0x06, 0x99, 0x04, 0x99, 0x00, 0xfe, + 0x1f, 0x80, 0xfe, 0x1f, 0x81, 0xfe, 0x1f, 0xc2, + 0xc5, 0x03, 0x86, 0xc5, 0x03, 0x84, 0xcb, 0x03, + 0x80, 0x00, 0x03, 0xc1, 0x13, 0xc1, 0x14, 0xc5, + 0x42, 0xcb, 0x42, 0xa5, 0x06, 0xa5, 0x04, 0xa5, + 0x00, 0xa1, 0x03, 0x94, 0xa8, 0x00, 0x80, 0x85, + 0x03, 0x60, 0x00, 0x7c, 0x1f, 0xc5, 0xc9, 0x03, + 0xc5, 0xce, 0x03, 0xc5, 0x00, 0x00, 0x00, 0xc9, + 0x03, 0xc2, 0xf6, 0x1f, 0xc5, 0x9f, 0x03, 0x80, + 0xa9, 0x03, 0x80, 0xa9, 0x03, 0xc5, 0x20, 0x94, + 0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0xb3, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x32, 0x20, 0x32, 0x20, 0x32, 0x20, + 0x00, 0x00, 0x00, 0x35, 0x20, 0x35, 0x20, 0x35, + 0x20, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00, + 0x20, 0x85, 0x3f, 0x3f, 0x3f, 0x21, 0x21, 0x3f, + 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x69, + 0x00, 0x00, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x2b, 0x3d, 0x28, 0x29, 0x6e, 0x30, 0x00, 0x2b, + 0x00, 0x12, 0x22, 0x3d, 0x00, 0x28, 0x00, 0x29, + 0x00, 0x00, 0x00, 0x61, 0x00, 0x65, 0x00, 0x6f, + 0x00, 0x78, 0x00, 0x59, 0x02, 0x68, 0x6b, 0x6c, + 0x6d, 0x6e, 0x70, 0x73, 0x74, 0x52, 0x73, 0x61, + 0x2f, 0x63, 0x61, 0x2f, 0x73, 0xb0, 0x00, 0x43, + 0x63, 0x2f, 0x6f, 0x63, 0x2f, 0x75, 0xb0, 0x00, + 0x46, 0x48, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, + 0xdf, 0x01, 0x01, 0x04, 0x24, 0x4e, 0x6f, 0x50, + 0x51, 0x52, 0x52, 0x52, 0x53, 0x4d, 0x54, 0x45, + 0x4c, 0x54, 0x4d, 0x4b, 0x00, 0xc5, 0x00, 0x42, + 0x43, 0x00, 0x65, 0x45, 0x46, 0x00, 0x4d, 0x6f, + 0xd0, 0x05, 0x46, 0x41, 0x58, 0xc0, 0x03, 0xb3, + 0x03, 0x93, 0x03, 0xa0, 0x03, 0x11, 0x22, 0x44, + 0x64, 0x65, 0x69, 0x6a, 0x31, 0xd0, 0x37, 0x31, + 0xd0, 0x39, 0x31, 0xd0, 0x31, 0x30, 0x31, 0xd0, + 0x33, 0x32, 0xd0, 0x33, 0x31, 0xd0, 0x35, 0x32, + 0xd0, 0x35, 0x33, 0xd0, 0x35, 0x34, 0xd0, 0x35, + 0x31, 0xd0, 0x36, 0x35, 0xd0, 0x36, 0x31, 0xd0, + 0x38, 0x33, 0xd0, 0x38, 0x35, 0xd0, 0x38, 0x37, + 0xd0, 0x38, 0x31, 0xd0, 0x49, 0x49, 0x49, 0x49, + 0x49, 0x49, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49, + 0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x49, + 0x58, 0x49, 0x49, 0x4c, 0x43, 0x44, 0x4d, 0x69, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76, 0x76, + 0x69, 0x76, 0x69, 0x69, 0x76, 0x69, 0x69, 0x69, + 0x69, 0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6c, + 0x63, 0x64, 0x6d, 0x30, 0xd0, 0x33, 0x90, 0x21, + 0xb8, 0x92, 0x21, 0xb8, 0x94, 0x21, 0xb8, 0xd0, + 0x21, 0xb8, 0xd4, 0x21, 0xb8, 0xd2, 0x21, 0xb8, + 0x03, 0x22, 0xb8, 0x08, 0x22, 0xb8, 0x0b, 0x22, + 0xb8, 0x23, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x25, + 0x22, 0xb8, 0x2b, 0x22, 0x2b, 0x22, 0x2b, 0x22, + 0x00, 0x00, 0x00, 0x2e, 0x22, 0x2e, 0x22, 0x2e, + 0x22, 0x00, 0x00, 0x00, 0x3c, 0x22, 0xb8, 0x43, + 0x22, 0xb8, 0x45, 0x22, 0xb8, 0x00, 0x00, 0x00, + 0x48, 0x22, 0xb8, 0x3d, 0x00, 0xb8, 0x00, 0x00, + 0x00, 0x61, 0x22, 0xb8, 0x4d, 0x22, 0xb8, 0x3c, + 0x00, 0xb8, 0x3e, 0x00, 0xb8, 0x64, 0x22, 0xb8, + 0x65, 0x22, 0xb8, 0x72, 0x22, 0xb8, 0x76, 0x22, + 0xb8, 0x7a, 0x22, 0xb8, 0x82, 0x22, 0xb8, 0x86, + 0x22, 0xb8, 0xa2, 0x22, 0xb8, 0xa8, 0x22, 0xb8, + 0xa9, 0x22, 0xb8, 0xab, 0x22, 0xb8, 0x7c, 0x22, + 0xb8, 0x91, 0x22, 0xb8, 0xb2, 0x22, 0x38, 0x03, + 0x08, 0x30, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00, + 0x32, 0x30, 0x28, 0x00, 0x31, 0x00, 0x29, 0x00, + 0x28, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29, 0x00, + 0x28, 0x32, 0x30, 0x29, 0x31, 0x00, 0x2e, 0x00, + 0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x30, + 0x2e, 0x28, 0x00, 0x61, 0x00, 0x29, 0x00, 0x41, + 0x00, 0x61, 0x00, 0x2b, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0xdd, 0x2a, 0xb8, 0x6a, 0x56, 0x00, 0x4e, + 0x00, 0x28, 0x36, 0x3f, 0x59, 0x85, 0x8c, 0xa0, + 0xba, 0x3f, 0x51, 0x00, 0x26, 0x2c, 0x43, 0x57, + 0x6c, 0xa1, 0xb6, 0xc1, 0x9b, 0x52, 0x00, 0x5e, + 0x7a, 0x7f, 0x9d, 0xa6, 0xc1, 0xce, 0xe7, 0xb6, + 0x53, 0xc8, 0x53, 0xe3, 0x53, 0xd7, 0x56, 0x1f, + 0x57, 0xeb, 0x58, 0x02, 0x59, 0x0a, 0x59, 0x15, + 0x59, 0x27, 0x59, 0x73, 0x59, 0x50, 0x5b, 0x80, + 0x5b, 0xf8, 0x5b, 0x0f, 0x5c, 0x22, 0x5c, 0x38, + 0x5c, 0x6e, 0x5c, 0x71, 0x5c, 0xdb, 0x5d, 0xe5, + 0x5d, 0xf1, 0x5d, 0xfe, 0x5d, 0x72, 0x5e, 0x7a, + 0x5e, 0x7f, 0x5e, 0xf4, 0x5e, 0xfe, 0x5e, 0x0b, + 0x5f, 0x13, 0x5f, 0x50, 0x5f, 0x61, 0x5f, 0x73, + 0x5f, 0xc3, 0x5f, 0x08, 0x62, 0x36, 0x62, 0x4b, + 0x62, 0x2f, 0x65, 0x34, 0x65, 0x87, 0x65, 0x97, + 0x65, 0xa4, 0x65, 0xb9, 0x65, 0xe0, 0x65, 0xe5, + 0x65, 0xf0, 0x66, 0x08, 0x67, 0x28, 0x67, 0x20, + 0x6b, 0x62, 0x6b, 0x79, 0x6b, 0xb3, 0x6b, 0xcb, + 0x6b, 0xd4, 0x6b, 0xdb, 0x6b, 0x0f, 0x6c, 0x14, + 0x6c, 0x34, 0x6c, 0x6b, 0x70, 0x2a, 0x72, 0x36, + 0x72, 0x3b, 0x72, 0x3f, 0x72, 0x47, 0x72, 0x59, + 0x72, 0x5b, 0x72, 0xac, 0x72, 0x84, 0x73, 0x89, + 0x73, 0xdc, 0x74, 0xe6, 0x74, 0x18, 0x75, 0x1f, + 0x75, 0x28, 0x75, 0x30, 0x75, 0x8b, 0x75, 0x92, + 0x75, 0x76, 0x76, 0x7d, 0x76, 0xae, 0x76, 0xbf, + 0x76, 0xee, 0x76, 0xdb, 0x77, 0xe2, 0x77, 0xf3, + 0x77, 0x3a, 0x79, 0xb8, 0x79, 0xbe, 0x79, 0x74, + 0x7a, 0xcb, 0x7a, 0xf9, 0x7a, 0x73, 0x7c, 0xf8, + 0x7c, 0x36, 0x7f, 0x51, 0x7f, 0x8a, 0x7f, 0xbd, + 0x7f, 0x01, 0x80, 0x0c, 0x80, 0x12, 0x80, 0x33, + 0x80, 0x7f, 0x80, 0x89, 0x80, 0xe3, 0x81, 0x00, + 0x07, 0x10, 0x19, 0x29, 0x38, 0x3c, 0x8b, 0x8f, + 0x95, 0x4d, 0x86, 0x6b, 0x86, 0x40, 0x88, 0x4c, + 0x88, 0x63, 0x88, 0x7e, 0x89, 0x8b, 0x89, 0xd2, + 0x89, 0x00, 0x8a, 0x37, 0x8c, 0x46, 0x8c, 0x55, + 0x8c, 0x78, 0x8c, 0x9d, 0x8c, 0x64, 0x8d, 0x70, + 0x8d, 0xb3, 0x8d, 0xab, 0x8e, 0xca, 0x8e, 0x9b, + 0x8f, 0xb0, 0x8f, 0xb5, 0x8f, 0x91, 0x90, 0x49, + 0x91, 0xc6, 0x91, 0xcc, 0x91, 0xd1, 0x91, 0x77, + 0x95, 0x80, 0x95, 0x1c, 0x96, 0xb6, 0x96, 0xb9, + 0x96, 0xe8, 0x96, 0x51, 0x97, 0x5e, 0x97, 0x62, + 0x97, 0x69, 0x97, 0xcb, 0x97, 0xed, 0x97, 0xf3, + 0x97, 0x01, 0x98, 0xa8, 0x98, 0xdb, 0x98, 0xdf, + 0x98, 0x96, 0x99, 0x99, 0x99, 0xac, 0x99, 0xa8, + 0x9a, 0xd8, 0x9a, 0xdf, 0x9a, 0x25, 0x9b, 0x2f, + 0x9b, 0x32, 0x9b, 0x3c, 0x9b, 0x5a, 0x9b, 0xe5, + 0x9c, 0x75, 0x9e, 0x7f, 0x9e, 0xa5, 0x9e, 0x00, + 0x16, 0x1e, 0x28, 0x2c, 0x54, 0x58, 0x69, 0x6e, + 0x7b, 0x96, 0xa5, 0xad, 0xe8, 0xf7, 0xfb, 0x12, + 0x30, 0x00, 0x00, 0x41, 0x53, 0x44, 0x53, 0x45, + 0x53, 0x4b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x4d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x4f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x51, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x53, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x55, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x57, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x59, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x5b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x5d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x5f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x61, 0x30, 0x99, 0x30, 0x64, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x68, 0x30, 0x99, + 0x30, 0x6f, 0x30, 0x99, 0x30, 0x72, 0x30, 0x99, + 0x30, 0x75, 0x30, 0x99, 0x30, 0x78, 0x30, 0x99, + 0x30, 0x7b, 0x30, 0x99, 0x30, 0x46, 0x30, 0x99, + 0x30, 0x20, 0x00, 0x99, 0x30, 0x9d, 0x30, 0x99, + 0x30, 0x88, 0x30, 0x8a, 0x30, 0xab, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xad, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x30, 0x99, + 0x30, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x30, 0x99, + 0x30, 0xc4, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00, + 0x00, 0xc8, 0x30, 0x99, 0x30, 0xcf, 0x30, 0x99, + 0x30, 0xd2, 0x30, 0x99, 0x30, 0xd5, 0x30, 0x99, + 0x30, 0xd8, 0x30, 0x99, 0x30, 0xdb, 0x30, 0x99, + 0x30, 0xa6, 0x30, 0x99, 0x30, 0xef, 0x30, 0x99, + 0x30, 0xfd, 0x30, 0x99, 0x30, 0xb3, 0x30, 0xc8, + 0x30, 0x00, 0x11, 0x00, 0x01, 0xaa, 0x02, 0xac, + 0xad, 0x03, 0x04, 0x05, 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0x1a, 0x06, 0x07, 0x08, 0x21, 0x09, + 0x11, 0x61, 0x11, 0x14, 0x11, 0x4c, 0x00, 0x01, + 0xb3, 0xb4, 0xb8, 0xba, 0xbf, 0xc3, 0xc5, 0x08, + 0xc9, 0xcb, 0x09, 0x0a, 0x0c, 0x0e, 0x0f, 0x13, + 0x15, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x22, + 0x2c, 0x33, 0x38, 0xdd, 0xde, 0x43, 0x44, 0x45, + 0x70, 0x71, 0x74, 0x7d, 0x7e, 0x80, 0x8a, 0x8d, + 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, + 0x0a, 0x4e, 0x2d, 0x4e, 0x0b, 0x4e, 0x32, 0x75, + 0x59, 0x4e, 0x19, 0x4e, 0x01, 0x4e, 0x29, 0x59, + 0x30, 0x57, 0xba, 0x4e, 0x28, 0x00, 0x29, 0x00, + 0x00, 0x11, 0x02, 0x11, 0x03, 0x11, 0x05, 0x11, + 0x06, 0x11, 0x07, 0x11, 0x09, 0x11, 0x0b, 0x11, + 0x0c, 0x11, 0x0e, 0x11, 0x0f, 0x11, 0x10, 0x11, + 0x11, 0x11, 0x12, 0x11, 0x28, 0x00, 0x00, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x02, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x05, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x09, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0e, 0x11, + 0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0c, 0x11, + 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, + 0x69, 0x11, 0x0c, 0x11, 0x65, 0x11, 0xab, 0x11, + 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, 0x69, 0x11, + 0x12, 0x11, 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, + 0x29, 0x00, 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, + 0xdb, 0x56, 0x94, 0x4e, 0x6d, 0x51, 0x03, 0x4e, + 0x6b, 0x51, 0x5d, 0x4e, 0x41, 0x53, 0x08, 0x67, + 0x6b, 0x70, 0x34, 0x6c, 0x28, 0x67, 0xd1, 0x91, + 0x1f, 0x57, 0xe5, 0x65, 0x2a, 0x68, 0x09, 0x67, + 0x3e, 0x79, 0x0d, 0x54, 0x79, 0x72, 0xa1, 0x8c, + 0x5d, 0x79, 0xb4, 0x52, 0xe3, 0x4e, 0x7c, 0x54, + 0x66, 0x5b, 0xe3, 0x76, 0x01, 0x4f, 0xc7, 0x8c, + 0x54, 0x53, 0x6d, 0x79, 0x11, 0x4f, 0xea, 0x81, + 0xf3, 0x81, 0x4f, 0x55, 0x7c, 0x5e, 0x87, 0x65, + 0x8f, 0x7b, 0x50, 0x54, 0x45, 0x32, 0x00, 0x31, + 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x11, 0x00, + 0x02, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x0c, + 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x00, 0x11, 0x00, + 0x61, 0x02, 0x61, 0x03, 0x61, 0x05, 0x61, 0x06, + 0x61, 0x07, 0x61, 0x09, 0x61, 0x0b, 0x61, 0x0c, + 0x61, 0x0e, 0x11, 0x61, 0x11, 0x00, 0x11, 0x0e, + 0x61, 0xb7, 0x00, 0x69, 0x0b, 0x11, 0x01, 0x63, + 0x00, 0x69, 0x0b, 0x11, 0x6e, 0x11, 0x00, 0x4e, + 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, 0x94, 0x4e, + 0x6d, 0x51, 0x03, 0x4e, 0x6b, 0x51, 0x5d, 0x4e, + 0x41, 0x53, 0x08, 0x67, 0x6b, 0x70, 0x34, 0x6c, + 0x28, 0x67, 0xd1, 0x91, 0x1f, 0x57, 0xe5, 0x65, + 0x2a, 0x68, 0x09, 0x67, 0x3e, 0x79, 0x0d, 0x54, + 0x79, 0x72, 0xa1, 0x8c, 0x5d, 0x79, 0xb4, 0x52, + 0xd8, 0x79, 0x37, 0x75, 0x73, 0x59, 0x69, 0x90, + 0x2a, 0x51, 0x70, 0x53, 0xe8, 0x6c, 0x05, 0x98, + 0x11, 0x4f, 0x99, 0x51, 0x63, 0x6b, 0x0a, 0x4e, + 0x2d, 0x4e, 0x0b, 0x4e, 0xe6, 0x5d, 0xf3, 0x53, + 0x3b, 0x53, 0x97, 0x5b, 0x66, 0x5b, 0xe3, 0x76, + 0x01, 0x4f, 0xc7, 0x8c, 0x54, 0x53, 0x1c, 0x59, + 0x33, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00, + 0x35, 0x30, 0x31, 0x00, 0x08, 0x67, 0x31, 0x00, + 0x30, 0x00, 0x08, 0x67, 0x48, 0x67, 0x65, 0x72, + 0x67, 0x65, 0x56, 0x4c, 0x54, 0x44, 0xa2, 0x30, + 0x00, 0x02, 0x04, 0x06, 0x08, 0x09, 0x0b, 0x0d, + 0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d, + 0x1f, 0x22, 0x24, 0x26, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3d, + 0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0xe4, + 0x4e, 0x8c, 0x54, 0xa1, 0x30, 0x01, 0x30, 0x5b, + 0x27, 0x01, 0x4a, 0x34, 0x00, 0x01, 0x52, 0x39, + 0x01, 0xa2, 0x30, 0x00, 0x5a, 0x49, 0xa4, 0x30, + 0x00, 0x27, 0x4f, 0x0c, 0xa4, 0x30, 0x00, 0x4f, + 0x1d, 0x02, 0x05, 0x4f, 0xa8, 0x30, 0x00, 0x11, + 0x07, 0x54, 0x21, 0xa8, 0x30, 0x00, 0x54, 0x03, + 0x54, 0xa4, 0x30, 0x06, 0x4f, 0x15, 0x06, 0x58, + 0x3c, 0x07, 0x00, 0x46, 0xab, 0x30, 0x00, 0x3e, + 0x18, 0x1d, 0x00, 0x42, 0x3f, 0x51, 0xac, 0x30, + 0x00, 0x41, 0x47, 0x00, 0x47, 0x32, 0xae, 0x30, + 0xac, 0x30, 0xae, 0x30, 0x00, 0x1d, 0x4e, 0xad, + 0x30, 0x00, 0x38, 0x3d, 0x4f, 0x01, 0x3e, 0x13, + 0x4f, 0xad, 0x30, 0xed, 0x30, 0xad, 0x30, 0x00, + 0x40, 0x03, 0x3c, 0x33, 0xad, 0x30, 0x00, 0x40, + 0x34, 0x4f, 0x1b, 0x3e, 0xad, 0x30, 0x00, 0x40, + 0x42, 0x16, 0x1b, 0xb0, 0x30, 0x00, 0x39, 0x30, + 0xa4, 0x30, 0x0c, 0x45, 0x3c, 0x24, 0x4f, 0x0b, + 0x47, 0x18, 0x00, 0x49, 0xaf, 0x30, 0x00, 0x3e, + 0x4d, 0x1e, 0xb1, 0x30, 0x00, 0x4b, 0x08, 0x02, + 0x3a, 0x19, 0x02, 0x4b, 0x2c, 0xa4, 0x30, 0x11, + 0x00, 0x0b, 0x47, 0xb5, 0x30, 0x00, 0x3e, 0x0c, + 0x47, 0x2b, 0xb0, 0x30, 0x07, 0x3a, 0x43, 0x00, + 0xb9, 0x30, 0x02, 0x3a, 0x08, 0x02, 0x3a, 0x0f, + 0x07, 0x43, 0x00, 0xb7, 0x30, 0x10, 0x00, 0x12, + 0x34, 0x11, 0x3c, 0x13, 0x17, 0xa4, 0x30, 0x2a, + 0x1f, 0x24, 0x2b, 0x00, 0x20, 0xbb, 0x30, 0x16, + 0x41, 0x00, 0x38, 0x0d, 0xc4, 0x30, 0x0d, 0x38, + 0x00, 0xd0, 0x30, 0x00, 0x2c, 0x1c, 0x1b, 0xa2, + 0x30, 0x32, 0x00, 0x17, 0x26, 0x49, 0xaf, 0x30, + 0x25, 0x00, 0x3c, 0xb3, 0x30, 0x21, 0x00, 0x20, + 0x38, 0xa1, 0x30, 0x34, 0x00, 0x48, 0x22, 0x28, + 0xa3, 0x30, 0x32, 0x00, 0x59, 0x25, 0xa7, 0x30, + 0x2f, 0x1c, 0x10, 0x00, 0x44, 0xd5, 0x30, 0x00, + 0x14, 0x1e, 0xaf, 0x30, 0x29, 0x00, 0x10, 0x4d, + 0x3c, 0xda, 0x30, 0xbd, 0x30, 0xb8, 0x30, 0x22, + 0x13, 0x1a, 0x20, 0x33, 0x0c, 0x22, 0x3b, 0x01, + 0x22, 0x44, 0x00, 0x21, 0x44, 0x07, 0xa4, 0x30, + 0x39, 0x00, 0x4f, 0x24, 0xc8, 0x30, 0x14, 0x23, + 0x00, 0xdb, 0x30, 0xf3, 0x30, 0xc9, 0x30, 0x14, + 0x2a, 0x00, 0x12, 0x33, 0x22, 0x12, 0x33, 0x2a, + 0xa4, 0x30, 0x3a, 0x00, 0x0b, 0x49, 0xa4, 0x30, + 0x3a, 0x00, 0x47, 0x3a, 0x1f, 0x2b, 0x3a, 0x47, + 0x0b, 0xb7, 0x30, 0x27, 0x3c, 0x00, 0x30, 0x3c, + 0xaf, 0x30, 0x30, 0x00, 0x3e, 0x44, 0xdf, 0x30, + 0xea, 0x30, 0xd0, 0x30, 0x0f, 0x1a, 0x00, 0x2c, + 0x1b, 0xe1, 0x30, 0xac, 0x30, 0xac, 0x30, 0x35, + 0x00, 0x1c, 0x47, 0x35, 0x50, 0x1c, 0x3f, 0xa2, + 0x30, 0x42, 0x5a, 0x27, 0x42, 0x5a, 0x49, 0x44, + 0x00, 0x51, 0xc3, 0x30, 0x27, 0x00, 0x05, 0x28, + 0xea, 0x30, 0xe9, 0x30, 0xd4, 0x30, 0x17, 0x00, + 0x28, 0xd6, 0x30, 0x15, 0x26, 0x00, 0x15, 0xec, + 0x30, 0xe0, 0x30, 0xb2, 0x30, 0x3a, 0x41, 0x16, + 0x00, 0x41, 0xc3, 0x30, 0x2c, 0x00, 0x05, 0x30, + 0x00, 0xb9, 0x70, 0x31, 0x00, 0x30, 0x00, 0xb9, + 0x70, 0x32, 0x00, 0x30, 0x00, 0xb9, 0x70, 0x68, + 0x50, 0x61, 0x64, 0x61, 0x41, 0x55, 0x62, 0x61, + 0x72, 0x6f, 0x56, 0x70, 0x63, 0x64, 0x6d, 0x64, + 0x00, 0x6d, 0x00, 0xb2, 0x00, 0x49, 0x00, 0x55, + 0x00, 0x73, 0x5e, 0x10, 0x62, 0x2d, 0x66, 0x8c, + 0x54, 0x27, 0x59, 0x63, 0x6b, 0x0e, 0x66, 0xbb, + 0x6c, 0x2a, 0x68, 0x0f, 0x5f, 0x1a, 0x4f, 0x3e, + 0x79, 0x70, 0x00, 0x41, 0x6e, 0x00, 0x41, 0xbc, + 0x03, 0x41, 0x6d, 0x00, 0x41, 0x6b, 0x00, 0x41, + 0x4b, 0x00, 0x42, 0x4d, 0x00, 0x42, 0x47, 0x00, + 0x42, 0x63, 0x61, 0x6c, 0x6b, 0x63, 0x61, 0x6c, + 0x70, 0x00, 0x46, 0x6e, 0x00, 0x46, 0xbc, 0x03, + 0x46, 0xbc, 0x03, 0x67, 0x6d, 0x00, 0x67, 0x6b, + 0x00, 0x67, 0x48, 0x00, 0x7a, 0x6b, 0x48, 0x7a, + 0x4d, 0x48, 0x7a, 0x47, 0x48, 0x7a, 0x54, 0x48, + 0x7a, 0xbc, 0x03, 0x13, 0x21, 0x6d, 0x00, 0x13, + 0x21, 0x64, 0x00, 0x13, 0x21, 0x6b, 0x00, 0x13, + 0x21, 0x66, 0x00, 0x6d, 0x6e, 0x00, 0x6d, 0xbc, + 0x03, 0x6d, 0x6d, 0x00, 0x6d, 0x63, 0x00, 0x6d, + 0x6b, 0x00, 0x6d, 0x63, 0x00, 0x0a, 0x0a, 0x4f, + 0x00, 0x0a, 0x4f, 0x6d, 0x00, 0xb2, 0x00, 0x63, + 0x00, 0x08, 0x0a, 0x4f, 0x0a, 0x0a, 0x50, 0x00, + 0x0a, 0x50, 0x6d, 0x00, 0xb3, 0x00, 0x6b, 0x00, + 0x6d, 0x00, 0xb3, 0x00, 0x6d, 0x00, 0x15, 0x22, + 0x73, 0x00, 0x6d, 0x00, 0x15, 0x22, 0x73, 0x00, + 0xb2, 0x00, 0x50, 0x61, 0x6b, 0x50, 0x61, 0x4d, + 0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64, + 0x72, 0x61, 0x64, 0xd1, 0x73, 0x72, 0x00, 0x61, + 0x00, 0x64, 0x00, 0x15, 0x22, 0x73, 0x00, 0xb2, + 0x00, 0x70, 0x00, 0x73, 0x6e, 0x00, 0x73, 0xbc, + 0x03, 0x73, 0x6d, 0x00, 0x73, 0x70, 0x00, 0x56, + 0x6e, 0x00, 0x56, 0xbc, 0x03, 0x56, 0x6d, 0x00, + 0x56, 0x6b, 0x00, 0x56, 0x4d, 0x00, 0x56, 0x70, + 0x00, 0x57, 0x6e, 0x00, 0x57, 0xbc, 0x03, 0x57, + 0x6d, 0x00, 0x57, 0x6b, 0x00, 0x57, 0x4d, 0x00, + 0x57, 0x6b, 0x00, 0xa9, 0x03, 0x4d, 0x00, 0xa9, + 0x03, 0x61, 0x2e, 0x6d, 0x2e, 0x42, 0x71, 0x63, + 0x63, 0x63, 0x64, 0x43, 0xd1, 0x6b, 0x67, 0x43, + 0x6f, 0x2e, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61, + 0x48, 0x50, 0x69, 0x6e, 0x4b, 0x4b, 0x4b, 0x4d, + 0x6b, 0x74, 0x6c, 0x6d, 0x6c, 0x6e, 0x6c, 0x6f, + 0x67, 0x6c, 0x78, 0x6d, 0x62, 0x6d, 0x69, 0x6c, + 0x6d, 0x6f, 0x6c, 0x50, 0x48, 0x70, 0x2e, 0x6d, + 0x2e, 0x50, 0x50, 0x4d, 0x50, 0x52, 0x73, 0x72, + 0x53, 0x76, 0x57, 0x62, 0x56, 0xd1, 0x6d, 0x41, + 0xd1, 0x6d, 0x31, 0x00, 0xe5, 0x65, 0x31, 0x00, + 0x30, 0x00, 0xe5, 0x65, 0x32, 0x00, 0x30, 0x00, + 0xe5, 0x65, 0x33, 0x00, 0x30, 0x00, 0xe5, 0x65, + 0x67, 0x61, 0x6c, 0x4a, 0x04, 0x4c, 0x04, 0x43, + 0x46, 0x51, 0x26, 0x01, 0x53, 0x01, 0x27, 0xa7, + 0x37, 0xab, 0x6b, 0x02, 0x52, 0xab, 0x48, 0x8c, + 0xf4, 0x66, 0xca, 0x8e, 0xc8, 0x8c, 0xd1, 0x6e, + 0x32, 0x4e, 0xe5, 0x53, 0x9c, 0x9f, 0x9c, 0x9f, + 0x51, 0x59, 0xd1, 0x91, 0x87, 0x55, 0x48, 0x59, + 0xf6, 0x61, 0x69, 0x76, 0x85, 0x7f, 0x3f, 0x86, + 0xba, 0x87, 0xf8, 0x88, 0x8f, 0x90, 0x02, 0x6a, + 0x1b, 0x6d, 0xd9, 0x70, 0xde, 0x73, 0x3d, 0x84, + 0x6a, 0x91, 0xf1, 0x99, 0x82, 0x4e, 0x75, 0x53, + 0x04, 0x6b, 0x1b, 0x72, 0x2d, 0x86, 0x1e, 0x9e, + 0x50, 0x5d, 0xeb, 0x6f, 0xcd, 0x85, 0x64, 0x89, + 0xc9, 0x62, 0xd8, 0x81, 0x1f, 0x88, 0xca, 0x5e, + 0x17, 0x67, 0x6a, 0x6d, 0xfc, 0x72, 0xce, 0x90, + 0x86, 0x4f, 0xb7, 0x51, 0xde, 0x52, 0xc4, 0x64, + 0xd3, 0x6a, 0x10, 0x72, 0xe7, 0x76, 0x01, 0x80, + 0x06, 0x86, 0x5c, 0x86, 0xef, 0x8d, 0x32, 0x97, + 0x6f, 0x9b, 0xfa, 0x9d, 0x8c, 0x78, 0x7f, 0x79, + 0xa0, 0x7d, 0xc9, 0x83, 0x04, 0x93, 0x7f, 0x9e, + 0xd6, 0x8a, 0xdf, 0x58, 0x04, 0x5f, 0x60, 0x7c, + 0x7e, 0x80, 0x62, 0x72, 0xca, 0x78, 0xc2, 0x8c, + 0xf7, 0x96, 0xd8, 0x58, 0x62, 0x5c, 0x13, 0x6a, + 0xda, 0x6d, 0x0f, 0x6f, 0x2f, 0x7d, 0x37, 0x7e, + 0x4b, 0x96, 0xd2, 0x52, 0x8b, 0x80, 0xdc, 0x51, + 0xcc, 0x51, 0x1c, 0x7a, 0xbe, 0x7d, 0xf1, 0x83, + 0x75, 0x96, 0x80, 0x8b, 0xcf, 0x62, 0x02, 0x6a, + 0xfe, 0x8a, 0x39, 0x4e, 0xe7, 0x5b, 0x12, 0x60, + 0x87, 0x73, 0x70, 0x75, 0x17, 0x53, 0xfb, 0x78, + 0xbf, 0x4f, 0xa9, 0x5f, 0x0d, 0x4e, 0xcc, 0x6c, + 0x78, 0x65, 0x22, 0x7d, 0xc3, 0x53, 0x5e, 0x58, + 0x01, 0x77, 0x49, 0x84, 0xaa, 0x8a, 0xba, 0x6b, + 0xb0, 0x8f, 0x88, 0x6c, 0xfe, 0x62, 0xe5, 0x82, + 0xa0, 0x63, 0x65, 0x75, 0xae, 0x4e, 0x69, 0x51, + 0xc9, 0x51, 0x81, 0x68, 0xe7, 0x7c, 0x6f, 0x82, + 0xd2, 0x8a, 0xcf, 0x91, 0xf5, 0x52, 0x42, 0x54, + 0x73, 0x59, 0xec, 0x5e, 0xc5, 0x65, 0xfe, 0x6f, + 0x2a, 0x79, 0xad, 0x95, 0x6a, 0x9a, 0x97, 0x9e, + 0xce, 0x9e, 0x9b, 0x52, 0xc6, 0x66, 0x77, 0x6b, + 0x62, 0x8f, 0x74, 0x5e, 0x90, 0x61, 0x00, 0x62, + 0x9a, 0x64, 0x23, 0x6f, 0x49, 0x71, 0x89, 0x74, + 0xca, 0x79, 0xf4, 0x7d, 0x6f, 0x80, 0x26, 0x8f, + 0xee, 0x84, 0x23, 0x90, 0x4a, 0x93, 0x17, 0x52, + 0xa3, 0x52, 0xbd, 0x54, 0xc8, 0x70, 0xc2, 0x88, + 0xaa, 0x8a, 0xc9, 0x5e, 0xf5, 0x5f, 0x7b, 0x63, + 0xae, 0x6b, 0x3e, 0x7c, 0x75, 0x73, 0xe4, 0x4e, + 0xf9, 0x56, 0xe7, 0x5b, 0xba, 0x5d, 0x1c, 0x60, + 0xb2, 0x73, 0x69, 0x74, 0x9a, 0x7f, 0x46, 0x80, + 0x34, 0x92, 0xf6, 0x96, 0x48, 0x97, 0x18, 0x98, + 0x8b, 0x4f, 0xae, 0x79, 0xb4, 0x91, 0xb8, 0x96, + 0xe1, 0x60, 0x86, 0x4e, 0xda, 0x50, 0xee, 0x5b, + 0x3f, 0x5c, 0x99, 0x65, 0x02, 0x6a, 0xce, 0x71, + 0x42, 0x76, 0xfc, 0x84, 0x7c, 0x90, 0x8d, 0x9f, + 0x88, 0x66, 0x2e, 0x96, 0x89, 0x52, 0x7b, 0x67, + 0xf3, 0x67, 0x41, 0x6d, 0x9c, 0x6e, 0x09, 0x74, + 0x59, 0x75, 0x6b, 0x78, 0x10, 0x7d, 0x5e, 0x98, + 0x6d, 0x51, 0x2e, 0x62, 0x78, 0x96, 0x2b, 0x50, + 0x19, 0x5d, 0xea, 0x6d, 0x2a, 0x8f, 0x8b, 0x5f, + 0x44, 0x61, 0x17, 0x68, 0x87, 0x73, 0x86, 0x96, + 0x29, 0x52, 0x0f, 0x54, 0x65, 0x5c, 0x13, 0x66, + 0x4e, 0x67, 0xa8, 0x68, 0xe5, 0x6c, 0x06, 0x74, + 0xe2, 0x75, 0x79, 0x7f, 0xcf, 0x88, 0xe1, 0x88, + 0xcc, 0x91, 0xe2, 0x96, 0x3f, 0x53, 0xba, 0x6e, + 0x1d, 0x54, 0xd0, 0x71, 0x98, 0x74, 0xfa, 0x85, + 0xa3, 0x96, 0x57, 0x9c, 0x9f, 0x9e, 0x97, 0x67, + 0xcb, 0x6d, 0xe8, 0x81, 0xcb, 0x7a, 0x20, 0x7b, + 0x92, 0x7c, 0xc0, 0x72, 0x99, 0x70, 0x58, 0x8b, + 0xc0, 0x4e, 0x36, 0x83, 0x3a, 0x52, 0x07, 0x52, + 0xa6, 0x5e, 0xd3, 0x62, 0xd6, 0x7c, 0x85, 0x5b, + 0x1e, 0x6d, 0xb4, 0x66, 0x3b, 0x8f, 0x4c, 0x88, + 0x4d, 0x96, 0x8b, 0x89, 0xd3, 0x5e, 0x40, 0x51, + 0xc0, 0x55, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x58, + 0x00, 0x00, 0x74, 0x66, 0x00, 0x00, 0x00, 0x00, + 0xde, 0x51, 0x2a, 0x73, 0xca, 0x76, 0x3c, 0x79, + 0x5e, 0x79, 0x65, 0x79, 0x8f, 0x79, 0x56, 0x97, + 0xbe, 0x7c, 0xbd, 0x7f, 0x00, 0x00, 0x12, 0x86, + 0x00, 0x00, 0xf8, 0x8a, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x90, 0xfd, 0x90, 0xef, 0x98, 0xfc, 0x98, + 0x28, 0x99, 0xb4, 0x9d, 0xde, 0x90, 0xb7, 0x96, + 0xae, 0x4f, 0xe7, 0x50, 0x4d, 0x51, 0xc9, 0x52, + 0xe4, 0x52, 0x51, 0x53, 0x9d, 0x55, 0x06, 0x56, + 0x68, 0x56, 0x40, 0x58, 0xa8, 0x58, 0x64, 0x5c, + 0x6e, 0x5c, 0x94, 0x60, 0x68, 0x61, 0x8e, 0x61, + 0xf2, 0x61, 0x4f, 0x65, 0xe2, 0x65, 0x91, 0x66, + 0x85, 0x68, 0x77, 0x6d, 0x1a, 0x6e, 0x22, 0x6f, + 0x6e, 0x71, 0x2b, 0x72, 0x22, 0x74, 0x91, 0x78, + 0x3e, 0x79, 0x49, 0x79, 0x48, 0x79, 0x50, 0x79, + 0x56, 0x79, 0x5d, 0x79, 0x8d, 0x79, 0x8e, 0x79, + 0x40, 0x7a, 0x81, 0x7a, 0xc0, 0x7b, 0xf4, 0x7d, + 0x09, 0x7e, 0x41, 0x7e, 0x72, 0x7f, 0x05, 0x80, + 0xed, 0x81, 0x79, 0x82, 0x79, 0x82, 0x57, 0x84, + 0x10, 0x89, 0x96, 0x89, 0x01, 0x8b, 0x39, 0x8b, + 0xd3, 0x8c, 0x08, 0x8d, 0xb6, 0x8f, 0x38, 0x90, + 0xe3, 0x96, 0xff, 0x97, 0x3b, 0x98, 0x75, 0x60, + 0xee, 0x42, 0x18, 0x82, 0x02, 0x26, 0x4e, 0xb5, + 0x51, 0x68, 0x51, 0x80, 0x4f, 0x45, 0x51, 0x80, + 0x51, 0xc7, 0x52, 0xfa, 0x52, 0x9d, 0x55, 0x55, + 0x55, 0x99, 0x55, 0xe2, 0x55, 0x5a, 0x58, 0xb3, + 0x58, 0x44, 0x59, 0x54, 0x59, 0x62, 0x5a, 0x28, + 0x5b, 0xd2, 0x5e, 0xd9, 0x5e, 0x69, 0x5f, 0xad, + 0x5f, 0xd8, 0x60, 0x4e, 0x61, 0x08, 0x61, 0x8e, + 0x61, 0x60, 0x61, 0xf2, 0x61, 0x34, 0x62, 0xc4, + 0x63, 0x1c, 0x64, 0x52, 0x64, 0x56, 0x65, 0x74, + 0x66, 0x17, 0x67, 0x1b, 0x67, 0x56, 0x67, 0x79, + 0x6b, 0xba, 0x6b, 0x41, 0x6d, 0xdb, 0x6e, 0xcb, + 0x6e, 0x22, 0x6f, 0x1e, 0x70, 0x6e, 0x71, 0xa7, + 0x77, 0x35, 0x72, 0xaf, 0x72, 0x2a, 0x73, 0x71, + 0x74, 0x06, 0x75, 0x3b, 0x75, 0x1d, 0x76, 0x1f, + 0x76, 0xca, 0x76, 0xdb, 0x76, 0xf4, 0x76, 0x4a, + 0x77, 0x40, 0x77, 0xcc, 0x78, 0xb1, 0x7a, 0xc0, + 0x7b, 0x7b, 0x7c, 0x5b, 0x7d, 0xf4, 0x7d, 0x3e, + 0x7f, 0x05, 0x80, 0x52, 0x83, 0xef, 0x83, 0x79, + 0x87, 0x41, 0x89, 0x86, 0x89, 0x96, 0x89, 0xbf, + 0x8a, 0xf8, 0x8a, 0xcb, 0x8a, 0x01, 0x8b, 0xfe, + 0x8a, 0xed, 0x8a, 0x39, 0x8b, 0x8a, 0x8b, 0x08, + 0x8d, 0x38, 0x8f, 0x72, 0x90, 0x99, 0x91, 0x76, + 0x92, 0x7c, 0x96, 0xe3, 0x96, 0x56, 0x97, 0xdb, + 0x97, 0xff, 0x97, 0x0b, 0x98, 0x3b, 0x98, 0x12, + 0x9b, 0x9c, 0x9f, 0x4a, 0x28, 0x44, 0x28, 0xd5, + 0x33, 0x9d, 0x3b, 0x18, 0x40, 0x39, 0x40, 0x49, + 0x52, 0xd0, 0x5c, 0xd3, 0x7e, 0x43, 0x9f, 0x8e, + 0x9f, 0x2a, 0xa0, 0x02, 0x66, 0x66, 0x66, 0x69, + 0x66, 0x6c, 0x66, 0x66, 0x69, 0x66, 0x66, 0x6c, + 0x7f, 0x01, 0x74, 0x73, 0x00, 0x74, 0x65, 0x05, + 0x0f, 0x11, 0x0f, 0x00, 0x0f, 0x06, 0x19, 0x11, + 0x0f, 0x08, 0xd9, 0x05, 0xb4, 0x05, 0x00, 0x00, + 0x00, 0x00, 0xf2, 0x05, 0xb7, 0x05, 0xd0, 0x05, + 0x12, 0x00, 0x03, 0x04, 0x0b, 0x0c, 0x0d, 0x18, + 0x1a, 0xe9, 0x05, 0xc1, 0x05, 0xe9, 0x05, 0xc2, + 0x05, 0x49, 0xfb, 0xc1, 0x05, 0x49, 0xfb, 0xc2, + 0x05, 0xd0, 0x05, 0xb7, 0x05, 0xd0, 0x05, 0xb8, + 0x05, 0xd0, 0x05, 0xbc, 0x05, 0xd8, 0x05, 0xbc, + 0x05, 0xde, 0x05, 0xbc, 0x05, 0xe0, 0x05, 0xbc, + 0x05, 0xe3, 0x05, 0xbc, 0x05, 0xb9, 0x05, 0x2d, + 0x03, 0x2e, 0x03, 0x2f, 0x03, 0x30, 0x03, 0x31, + 0x03, 0x1c, 0x00, 0x18, 0x06, 0x22, 0x06, 0x2b, + 0x06, 0xd0, 0x05, 0xdc, 0x05, 0x71, 0x06, 0x00, + 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x09, 0x09, + 0x09, 0x0e, 0x0e, 0x0e, 0x0e, 0x08, 0x08, 0x08, + 0x08, 0x33, 0x33, 0x33, 0x33, 0x35, 0x35, 0x35, + 0x35, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12, + 0x12, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, + 0x16, 0x1c, 0x1c, 0x1b, 0x1b, 0x1d, 0x1d, 0x17, + 0x17, 0x27, 0x27, 0x20, 0x20, 0x38, 0x38, 0x38, + 0x38, 0x3e, 0x3e, 0x3e, 0x3e, 0x42, 0x42, 0x42, + 0x42, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4f, 0x4f, 0x50, 0x50, 0x50, + 0x50, 0x4d, 0x4d, 0x4d, 0x4d, 0x61, 0x61, 0x62, + 0x62, 0x49, 0x06, 0x64, 0x64, 0x64, 0x64, 0x7e, + 0x7e, 0x7d, 0x7d, 0x7f, 0x7f, 0x2e, 0x82, 0x82, + 0x7c, 0x7c, 0x80, 0x80, 0x87, 0x87, 0x87, 0x87, + 0x00, 0x00, 0x26, 0x06, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x22, 0x00, 0x22, + 0x00, 0xa1, 0x00, 0xa1, 0x00, 0xa0, 0x00, 0xa0, + 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xaa, 0x00, 0xaa, + 0x00, 0xaa, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, + 0xcc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x26, 0x06, + 0x00, 0x06, 0x00, 0x07, 0x00, 0x1f, 0x00, 0x23, + 0x00, 0x24, 0x02, 0x06, 0x02, 0x07, 0x02, 0x08, + 0x02, 0x1f, 0x02, 0x23, 0x02, 0x24, 0x04, 0x06, + 0x04, 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x23, + 0x04, 0x24, 0x05, 0x06, 0x05, 0x1f, 0x05, 0x23, + 0x05, 0x24, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06, + 0x07, 0x1f, 0x08, 0x06, 0x08, 0x07, 0x08, 0x1f, + 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x08, 0x0d, 0x1f, + 0x0f, 0x07, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07, + 0x10, 0x08, 0x10, 0x1f, 0x11, 0x07, 0x11, 0x1f, + 0x12, 0x1f, 0x13, 0x06, 0x13, 0x1f, 0x14, 0x06, + 0x14, 0x1f, 0x1b, 0x06, 0x1b, 0x07, 0x1b, 0x08, + 0x1b, 0x1f, 0x1b, 0x23, 0x1b, 0x24, 0x1c, 0x07, + 0x1c, 0x1f, 0x1c, 0x23, 0x1c, 0x24, 0x1d, 0x01, + 0x1d, 0x06, 0x1d, 0x07, 0x1d, 0x08, 0x1d, 0x1e, + 0x1d, 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x06, + 0x1e, 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x23, + 0x1e, 0x24, 0x1f, 0x06, 0x1f, 0x07, 0x1f, 0x08, + 0x1f, 0x1f, 0x1f, 0x23, 0x1f, 0x24, 0x20, 0x06, + 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20, 0x23, + 0x20, 0x24, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x23, + 0x21, 0x24, 0x24, 0x06, 0x24, 0x07, 0x24, 0x08, + 0x24, 0x1f, 0x24, 0x23, 0x24, 0x24, 0x0a, 0x4a, + 0x0b, 0x4a, 0x23, 0x4a, 0x20, 0x00, 0x4c, 0x06, + 0x51, 0x06, 0x51, 0x06, 0xff, 0x00, 0x1f, 0x26, + 0x06, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x1f, 0x00, + 0x20, 0x00, 0x23, 0x00, 0x24, 0x02, 0x0b, 0x02, + 0x0c, 0x02, 0x1f, 0x02, 0x20, 0x02, 0x23, 0x02, + 0x24, 0x04, 0x0b, 0x04, 0x0c, 0x04, 0x1f, 0x26, + 0x06, 0x04, 0x20, 0x04, 0x23, 0x04, 0x24, 0x05, + 0x0b, 0x05, 0x0c, 0x05, 0x1f, 0x05, 0x20, 0x05, + 0x23, 0x05, 0x24, 0x1b, 0x23, 0x1b, 0x24, 0x1c, + 0x23, 0x1c, 0x24, 0x1d, 0x01, 0x1d, 0x1e, 0x1d, + 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x1f, 0x1e, + 0x23, 0x1e, 0x24, 0x1f, 0x01, 0x1f, 0x1f, 0x20, + 0x0b, 0x20, 0x0c, 0x20, 0x1f, 0x20, 0x20, 0x20, + 0x23, 0x20, 0x24, 0x23, 0x4a, 0x24, 0x0b, 0x24, + 0x0c, 0x24, 0x1f, 0x24, 0x20, 0x24, 0x23, 0x24, + 0x24, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x1f, 0x00, 0x21, 0x02, 0x06, 0x02, 0x07, 0x02, + 0x08, 0x02, 0x1f, 0x02, 0x21, 0x04, 0x06, 0x04, + 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x21, 0x05, + 0x1f, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06, 0x07, + 0x1f, 0x08, 0x06, 0x08, 0x1f, 0x0d, 0x06, 0x0d, + 0x07, 0x0d, 0x08, 0x0d, 0x1f, 0x0f, 0x07, 0x0f, + 0x08, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07, 0x10, + 0x08, 0x10, 0x1f, 0x11, 0x07, 0x12, 0x1f, 0x13, + 0x06, 0x13, 0x1f, 0x14, 0x06, 0x14, 0x1f, 0x1b, + 0x06, 0x1b, 0x07, 0x1b, 0x08, 0x1b, 0x1f, 0x1c, + 0x07, 0x1c, 0x1f, 0x1d, 0x06, 0x1d, 0x07, 0x1d, + 0x08, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x06, 0x1e, + 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x21, 0x1f, + 0x06, 0x1f, 0x07, 0x1f, 0x08, 0x1f, 0x1f, 0x20, + 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20, + 0x21, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x4a, 0x24, + 0x06, 0x24, 0x07, 0x24, 0x08, 0x24, 0x1f, 0x24, + 0x21, 0x00, 0x1f, 0x00, 0x21, 0x02, 0x1f, 0x02, + 0x21, 0x04, 0x1f, 0x04, 0x21, 0x05, 0x1f, 0x05, + 0x21, 0x0d, 0x1f, 0x0d, 0x21, 0x0e, 0x1f, 0x0e, + 0x21, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x1f, 0x20, + 0x1f, 0x20, 0x21, 0x24, 0x1f, 0x24, 0x21, 0x40, + 0x06, 0x4e, 0x06, 0x51, 0x06, 0x27, 0x06, 0x10, + 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13, + 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d, + 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05, + 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e, + 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d, + 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d, + 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x10, + 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13, + 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d, + 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05, + 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e, + 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d, + 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d, + 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x0d, + 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0c, + 0x20, 0x0d, 0x20, 0x10, 0x1e, 0x0c, 0x05, 0x0c, + 0x06, 0x0c, 0x07, 0x0d, 0x05, 0x0d, 0x06, 0x0d, + 0x07, 0x10, 0x1e, 0x11, 0x1e, 0x00, 0x24, 0x00, + 0x24, 0x2a, 0x06, 0x00, 0x02, 0x1b, 0x00, 0x03, + 0x02, 0x00, 0x03, 0x02, 0x00, 0x03, 0x1b, 0x00, + 0x04, 0x1b, 0x00, 0x1b, 0x02, 0x00, 0x1b, 0x03, + 0x00, 0x1b, 0x04, 0x02, 0x1b, 0x03, 0x02, 0x1b, + 0x03, 0x03, 0x1b, 0x20, 0x03, 0x1b, 0x1f, 0x09, + 0x03, 0x02, 0x09, 0x02, 0x03, 0x09, 0x02, 0x1f, + 0x09, 0x1b, 0x03, 0x09, 0x1b, 0x03, 0x09, 0x1b, + 0x02, 0x09, 0x1b, 0x1b, 0x09, 0x1b, 0x1b, 0x0b, + 0x03, 0x03, 0x0b, 0x03, 0x03, 0x0b, 0x1b, 0x1b, + 0x0a, 0x03, 0x1b, 0x0a, 0x03, 0x1b, 0x0a, 0x02, + 0x20, 0x0a, 0x1b, 0x04, 0x0a, 0x1b, 0x04, 0x0a, + 0x1b, 0x1b, 0x0a, 0x1b, 0x1b, 0x0c, 0x03, 0x1f, + 0x0c, 0x04, 0x1b, 0x0c, 0x04, 0x1b, 0x0d, 0x1b, + 0x03, 0x0d, 0x1b, 0x03, 0x0d, 0x1b, 0x1b, 0x0d, + 0x1b, 0x20, 0x0f, 0x02, 0x1b, 0x0f, 0x1b, 0x1b, + 0x0f, 0x1b, 0x1b, 0x0f, 0x1b, 0x1f, 0x10, 0x1b, + 0x1b, 0x10, 0x1b, 0x20, 0x10, 0x1b, 0x1f, 0x17, + 0x04, 0x1b, 0x17, 0x04, 0x1b, 0x18, 0x1b, 0x03, + 0x18, 0x1b, 0x1b, 0x1a, 0x03, 0x1b, 0x1a, 0x03, + 0x20, 0x1a, 0x03, 0x1f, 0x1a, 0x02, 0x02, 0x1a, + 0x02, 0x02, 0x1a, 0x04, 0x1b, 0x1a, 0x04, 0x1b, + 0x1a, 0x1b, 0x03, 0x1a, 0x1b, 0x03, 0x1b, 0x03, + 0x02, 0x1b, 0x03, 0x1b, 0x1b, 0x03, 0x20, 0x1b, + 0x02, 0x03, 0x1b, 0x02, 0x1b, 0x1b, 0x04, 0x02, + 0x1b, 0x04, 0x1b, 0x28, 0x06, 0x1d, 0x04, 0x06, + 0x1f, 0x1d, 0x04, 0x1f, 0x1d, 0x1d, 0x1e, 0x05, + 0x1d, 0x1e, 0x05, 0x21, 0x1e, 0x04, 0x1d, 0x1e, + 0x04, 0x1d, 0x1e, 0x04, 0x21, 0x1e, 0x1d, 0x22, + 0x1e, 0x1d, 0x21, 0x22, 0x1d, 0x1d, 0x22, 0x1d, + 0x1d, 0x00, 0x06, 0x22, 0x02, 0x04, 0x22, 0x02, + 0x04, 0x21, 0x02, 0x06, 0x22, 0x02, 0x06, 0x21, + 0x02, 0x1d, 0x22, 0x02, 0x1d, 0x21, 0x04, 0x1d, + 0x22, 0x04, 0x05, 0x21, 0x04, 0x1d, 0x21, 0x0b, + 0x06, 0x21, 0x0d, 0x05, 0x22, 0x0c, 0x05, 0x22, + 0x0e, 0x05, 0x22, 0x1c, 0x04, 0x22, 0x1c, 0x1d, + 0x22, 0x22, 0x05, 0x22, 0x22, 0x04, 0x22, 0x22, + 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1a, 0x1d, 0x22, + 0x1e, 0x05, 0x22, 0x1a, 0x1d, 0x05, 0x1c, 0x05, + 0x1d, 0x11, 0x1d, 0x22, 0x1b, 0x1d, 0x22, 0x1e, + 0x04, 0x05, 0x1d, 0x06, 0x22, 0x1c, 0x04, 0x1d, + 0x1b, 0x1d, 0x1d, 0x1c, 0x04, 0x1d, 0x1e, 0x04, + 0x05, 0x04, 0x05, 0x22, 0x05, 0x04, 0x22, 0x1d, + 0x04, 0x22, 0x19, 0x1d, 0x22, 0x00, 0x05, 0x22, + 0x1b, 0x1d, 0x1d, 0x11, 0x04, 0x1d, 0x0d, 0x1d, + 0x1d, 0x0b, 0x06, 0x22, 0x1e, 0x04, 0x22, 0x35, + 0x06, 0x00, 0x0f, 0x9d, 0x0d, 0x0f, 0x9d, 0x27, + 0x06, 0x00, 0x1d, 0x1d, 0x20, 0x00, 0x1c, 0x01, + 0x0a, 0x1e, 0x06, 0x1e, 0x08, 0x0e, 0x1d, 0x12, + 0x1e, 0x0a, 0x0c, 0x21, 0x1d, 0x12, 0x1d, 0x23, + 0x20, 0x21, 0x0c, 0x1d, 0x1e, 0x35, 0x06, 0x00, + 0x0f, 0x14, 0x27, 0x06, 0x0e, 0x1d, 0x22, 0xff, + 0x00, 0x1d, 0x1d, 0x20, 0xff, 0x12, 0x1d, 0x23, + 0x20, 0xff, 0x21, 0x0c, 0x1d, 0x1e, 0x27, 0x06, + 0x05, 0x1d, 0xff, 0x05, 0x1d, 0x00, 0x1d, 0x20, + 0x27, 0x06, 0x0a, 0xa5, 0x00, 0x1d, 0x2c, 0x00, + 0x01, 0x30, 0x02, 0x30, 0x3a, 0x00, 0x3b, 0x00, + 0x21, 0x00, 0x3f, 0x00, 0x16, 0x30, 0x17, 0x30, + 0x26, 0x20, 0x13, 0x20, 0x12, 0x01, 0x00, 0x5f, + 0x5f, 0x28, 0x29, 0x7b, 0x7d, 0x08, 0x30, 0x0c, + 0x0d, 0x08, 0x09, 0x02, 0x03, 0x00, 0x01, 0x04, + 0x05, 0x06, 0x07, 0x5b, 0x00, 0x5d, 0x00, 0x3e, + 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x5f, + 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x2c, 0x00, 0x01, + 0x30, 0x2e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x3a, + 0x00, 0x3f, 0x00, 0x21, 0x00, 0x14, 0x20, 0x28, + 0x00, 0x29, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x14, + 0x30, 0x15, 0x30, 0x23, 0x26, 0x2a, 0x2b, 0x2d, + 0x3c, 0x3e, 0x3d, 0x00, 0x5c, 0x24, 0x25, 0x40, + 0x40, 0x06, 0xff, 0x0b, 0x00, 0x0b, 0xff, 0x0c, + 0x20, 0x00, 0x4d, 0x06, 0x40, 0x06, 0xff, 0x0e, + 0x00, 0x0e, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0x10, + 0x00, 0x10, 0xff, 0x11, 0x00, 0x11, 0xff, 0x12, + 0x00, 0x12, 0x21, 0x06, 0x00, 0x01, 0x01, 0x02, + 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x05, + 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, + 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, + 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x12, + 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, + 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, + 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, + 0x18, 0x19, 0x19, 0x19, 0x19, 0x20, 0x20, 0x20, + 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, + 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, + 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, + 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x29, + 0x29, 0x22, 0x06, 0x22, 0x00, 0x22, 0x00, 0x22, + 0x01, 0x22, 0x01, 0x22, 0x03, 0x22, 0x03, 0x22, + 0x05, 0x22, 0x05, 0x21, 0x00, 0x85, 0x29, 0x01, + 0x30, 0x01, 0x0b, 0x0c, 0x00, 0xfa, 0xf1, 0xa0, + 0xa2, 0xa4, 0xa6, 0xa8, 0xe2, 0xe4, 0xe6, 0xc2, + 0xfb, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, + 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, + 0xbe, 0xc0, 0xc3, 0xc5, 0xc7, 0xc9, 0xca, 0xcb, + 0xcc, 0xcd, 0xce, 0xd1, 0xd4, 0xd7, 0xda, 0xdd, + 0xde, 0xdf, 0xe0, 0xe1, 0xe3, 0xe5, 0xe7, 0xe8, + 0xe9, 0xea, 0xeb, 0xec, 0xee, 0xf2, 0x98, 0x99, + 0x31, 0x31, 0x4f, 0x31, 0x55, 0x31, 0x5b, 0x31, + 0x61, 0x31, 0xa2, 0x00, 0xa3, 0x00, 0xac, 0x00, + 0xaf, 0x00, 0xa6, 0x00, 0xa5, 0x00, 0xa9, 0x20, + 0x00, 0x00, 0x02, 0x25, 0x90, 0x21, 0x91, 0x21, + 0x92, 0x21, 0x93, 0x21, 0xa0, 0x25, 0xcb, 0x25, + 0xd0, 0x02, 0xd1, 0x02, 0xe6, 0x00, 0x99, 0x02, + 0x53, 0x02, 0x00, 0x00, 0xa3, 0x02, 0x66, 0xab, + 0xa5, 0x02, 0xa4, 0x02, 0x56, 0x02, 0x57, 0x02, + 0x91, 0x1d, 0x58, 0x02, 0x5e, 0x02, 0xa9, 0x02, + 0x64, 0x02, 0x62, 0x02, 0x60, 0x02, 0x9b, 0x02, + 0x27, 0x01, 0x9c, 0x02, 0x67, 0x02, 0x84, 0x02, + 0xaa, 0x02, 0xab, 0x02, 0x6c, 0x02, 0x04, 0xdf, + 0x8e, 0xa7, 0x6e, 0x02, 0x05, 0xdf, 0x8e, 0x02, + 0x06, 0xdf, 0xf8, 0x00, 0x76, 0x02, 0x77, 0x02, + 0x71, 0x00, 0x7a, 0x02, 0x08, 0xdf, 0x7d, 0x02, + 0x7e, 0x02, 0x80, 0x02, 0xa8, 0x02, 0xa6, 0x02, + 0x67, 0xab, 0xa7, 0x02, 0x88, 0x02, 0x71, 0x2c, + 0x00, 0x00, 0x8f, 0x02, 0xa1, 0x02, 0xa2, 0x02, + 0x98, 0x02, 0xc0, 0x01, 0xc1, 0x01, 0xc2, 0x01, + 0x0a, 0xdf, 0x1e, 0xdf, 0x41, 0x04, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x99, 0x10, 0xba, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x9b, 0x10, 0xba, 0x10, + 0x05, 0x05, 0xa5, 0x10, 0xba, 0x10, 0x05, 0x31, + 0x11, 0x27, 0x11, 0x32, 0x11, 0x27, 0x11, 0x55, + 0x47, 0x13, 0x3e, 0x13, 0x47, 0x13, 0x57, 0x13, + 0x55, 0xb9, 0x14, 0xba, 0x14, 0xb9, 0x14, 0xb0, + 0x14, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x14, 0xbd, + 0x14, 0x55, 0x50, 0xb8, 0x15, 0xaf, 0x15, 0xb9, + 0x15, 0xaf, 0x15, 0x55, 0x35, 0x19, 0x30, 0x19, + 0x05, 0x57, 0xd1, 0x65, 0xd1, 0x58, 0xd1, 0x65, + 0xd1, 0x5f, 0xd1, 0x6e, 0xd1, 0x5f, 0xd1, 0x6f, + 0xd1, 0x5f, 0xd1, 0x70, 0xd1, 0x5f, 0xd1, 0x71, + 0xd1, 0x5f, 0xd1, 0x72, 0xd1, 0x55, 0x55, 0x55, + 0x05, 0xb9, 0xd1, 0x65, 0xd1, 0xba, 0xd1, 0x65, + 0xd1, 0xbb, 0xd1, 0x6e, 0xd1, 0xbc, 0xd1, 0x6e, + 0xd1, 0xbb, 0xd1, 0x6f, 0xd1, 0xbc, 0xd1, 0x6f, + 0xd1, 0x55, 0x55, 0x55, 0x41, 0x00, 0x61, 0x00, + 0x41, 0x00, 0x61, 0x00, 0x69, 0x00, 0x41, 0x00, + 0x61, 0x00, 0x41, 0x00, 0x43, 0x44, 0x00, 0x00, + 0x47, 0x00, 0x00, 0x4a, 0x4b, 0x00, 0x00, 0x4e, + 0x4f, 0x50, 0x51, 0x00, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, + 0x00, 0x66, 0x68, 0x00, 0x70, 0x00, 0x41, 0x00, + 0x61, 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, 0x46, + 0x47, 0x4a, 0x00, 0x53, 0x00, 0x61, 0x00, 0x41, + 0x42, 0x00, 0x44, 0x45, 0x46, 0x47, 0x00, 0x49, + 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f, 0x53, 0x00, + 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, + 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, + 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, + 0x61, 0x00, 0x31, 0x01, 0x37, 0x02, 0x91, 0x03, + 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, + 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, + 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, + 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, + 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, + 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, + 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, + 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, + 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, 0x30, 0x00, + 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, + 0x30, 0x04, 0x3a, 0x04, 0x3e, 0x04, 0x4b, 0x04, + 0x4d, 0x04, 0x4e, 0x04, 0x89, 0xa6, 0x30, 0x04, + 0xa9, 0x26, 0x28, 0xb9, 0x7f, 0x9f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a, + 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x1a, 0x1b, 0x61, 0x26, 0x25, 0x2f, + 0x7b, 0x51, 0xa6, 0xb1, 0x04, 0x27, 0x06, 0x00, + 0x01, 0x05, 0x08, 0x2a, 0x06, 0x1e, 0x08, 0x03, + 0x0d, 0x20, 0x19, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, + 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, + 0x06, 0x0c, 0x0e, 0x10, 0x44, 0x90, 0x77, 0x45, + 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06, + 0x33, 0x06, 0x17, 0x10, 0x11, 0x12, 0x13, 0x00, + 0x06, 0x0e, 0x02, 0x0f, 0x34, 0x06, 0x2a, 0x06, + 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00, 0x36, 0x06, + 0x00, 0x00, 0x3a, 0x06, 0x2d, 0x06, 0x00, 0x00, + 0x4a, 0x06, 0x00, 0x00, 0x44, 0x06, 0x00, 0x00, + 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x00, 0x00, + 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x2e, 0x06, 0x00, 0x00, + 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x00, 0x00, + 0xba, 0x06, 0x00, 0x00, 0x6f, 0x06, 0x00, 0x00, + 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x2d, 0x06, 0x37, 0x06, + 0x4a, 0x06, 0x43, 0x06, 0x00, 0x00, 0x45, 0x06, + 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x41, 0x06, + 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06, + 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00, + 0x36, 0x06, 0x38, 0x06, 0x3a, 0x06, 0x6e, 0x06, + 0x00, 0x00, 0xa1, 0x06, 0x27, 0x06, 0x00, 0x01, + 0x05, 0x08, 0x20, 0x21, 0x0b, 0x06, 0x10, 0x23, + 0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17, + 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06, + 0x0c, 0x0e, 0x10, 0x28, 0x06, 0x2c, 0x06, 0x2f, + 0x06, 0x00, 0x00, 0x48, 0x06, 0x32, 0x06, 0x2d, + 0x06, 0x37, 0x06, 0x4a, 0x06, 0x2a, 0x06, 0x1a, + 0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, + 0x0a, 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, + 0x30, 0x2e, 0x30, 0x00, 0x2c, 0x00, 0x28, 0x00, + 0x41, 0x00, 0x29, 0x00, 0x14, 0x30, 0x53, 0x00, + 0x15, 0x30, 0x43, 0x52, 0x43, 0x44, 0x57, 0x5a, + 0x41, 0x00, 0x48, 0x56, 0x4d, 0x56, 0x53, 0x44, + 0x53, 0x53, 0x50, 0x50, 0x56, 0x57, 0x43, 0x4d, + 0x43, 0x4d, 0x44, 0x4d, 0x52, 0x44, 0x4a, 0x4b, + 0x30, 0x30, 0x00, 0x68, 0x68, 0x4b, 0x62, 0x57, + 0x5b, 0xcc, 0x53, 0xc7, 0x30, 0x8c, 0x4e, 0x1a, + 0x59, 0xe3, 0x89, 0x29, 0x59, 0xa4, 0x4e, 0x20, + 0x66, 0x21, 0x71, 0x99, 0x65, 0x4d, 0x52, 0x8c, + 0x5f, 0x8d, 0x51, 0xb0, 0x65, 0x1d, 0x52, 0x42, + 0x7d, 0x1f, 0x75, 0xa9, 0x8c, 0xf0, 0x58, 0x39, + 0x54, 0x14, 0x6f, 0x95, 0x62, 0x55, 0x63, 0x00, + 0x4e, 0x09, 0x4e, 0x4a, 0x90, 0xe6, 0x5d, 0x2d, + 0x4e, 0xf3, 0x53, 0x07, 0x63, 0x70, 0x8d, 0x53, + 0x62, 0x81, 0x79, 0x7a, 0x7a, 0x08, 0x54, 0x80, + 0x6e, 0x09, 0x67, 0x08, 0x67, 0x33, 0x75, 0x72, + 0x52, 0xb6, 0x55, 0x4d, 0x91, 0x14, 0x30, 0x15, + 0x30, 0x2c, 0x67, 0x09, 0x4e, 0x8c, 0x4e, 0x89, + 0x5b, 0xb9, 0x70, 0x53, 0x62, 0xd7, 0x76, 0xdd, + 0x52, 0x57, 0x65, 0x97, 0x5f, 0xef, 0x53, 0x30, + 0x00, 0x38, 0x4e, 0x05, 0x00, 0x09, 0x22, 0x01, + 0x60, 0x4f, 0xae, 0x4f, 0xbb, 0x4f, 0x02, 0x50, + 0x7a, 0x50, 0x99, 0x50, 0xe7, 0x50, 0xcf, 0x50, + 0x9e, 0x34, 0x3a, 0x06, 0x4d, 0x51, 0x54, 0x51, + 0x64, 0x51, 0x77, 0x51, 0x1c, 0x05, 0xb9, 0x34, + 0x67, 0x51, 0x8d, 0x51, 0x4b, 0x05, 0x97, 0x51, + 0xa4, 0x51, 0xcc, 0x4e, 0xac, 0x51, 0xb5, 0x51, + 0xdf, 0x91, 0xf5, 0x51, 0x03, 0x52, 0xdf, 0x34, + 0x3b, 0x52, 0x46, 0x52, 0x72, 0x52, 0x77, 0x52, + 0x15, 0x35, 0x02, 0x00, 0x20, 0x80, 0x80, 0x00, + 0x08, 0x00, 0x00, 0xc7, 0x52, 0x00, 0x02, 0x1d, + 0x33, 0x3e, 0x3f, 0x50, 0x82, 0x8a, 0x93, 0xac, + 0xb6, 0xb8, 0xb8, 0xb8, 0x2c, 0x0a, 0x70, 0x70, + 0xca, 0x53, 0xdf, 0x53, 0x63, 0x0b, 0xeb, 0x53, + 0xf1, 0x53, 0x06, 0x54, 0x9e, 0x54, 0x38, 0x54, + 0x48, 0x54, 0x68, 0x54, 0xa2, 0x54, 0xf6, 0x54, + 0x10, 0x55, 0x53, 0x55, 0x63, 0x55, 0x84, 0x55, + 0x84, 0x55, 0x99, 0x55, 0xab, 0x55, 0xb3, 0x55, + 0xc2, 0x55, 0x16, 0x57, 0x06, 0x56, 0x17, 0x57, + 0x51, 0x56, 0x74, 0x56, 0x07, 0x52, 0xee, 0x58, + 0xce, 0x57, 0xf4, 0x57, 0x0d, 0x58, 0x8b, 0x57, + 0x32, 0x58, 0x31, 0x58, 0xac, 0x58, 0xe4, 0x14, + 0xf2, 0x58, 0xf7, 0x58, 0x06, 0x59, 0x1a, 0x59, + 0x22, 0x59, 0x62, 0x59, 0xa8, 0x16, 0xea, 0x16, + 0xec, 0x59, 0x1b, 0x5a, 0x27, 0x5a, 0xd8, 0x59, + 0x66, 0x5a, 0xee, 0x36, 0xfc, 0x36, 0x08, 0x5b, + 0x3e, 0x5b, 0x3e, 0x5b, 0xc8, 0x19, 0xc3, 0x5b, + 0xd8, 0x5b, 0xe7, 0x5b, 0xf3, 0x5b, 0x18, 0x1b, + 0xff, 0x5b, 0x06, 0x5c, 0x53, 0x5f, 0x22, 0x5c, + 0x81, 0x37, 0x60, 0x5c, 0x6e, 0x5c, 0xc0, 0x5c, + 0x8d, 0x5c, 0xe4, 0x1d, 0x43, 0x5d, 0xe6, 0x1d, + 0x6e, 0x5d, 0x6b, 0x5d, 0x7c, 0x5d, 0xe1, 0x5d, + 0xe2, 0x5d, 0x2f, 0x38, 0xfd, 0x5d, 0x28, 0x5e, + 0x3d, 0x5e, 0x69, 0x5e, 0x62, 0x38, 0x83, 0x21, + 0x7c, 0x38, 0xb0, 0x5e, 0xb3, 0x5e, 0xb6, 0x5e, + 0xca, 0x5e, 0x92, 0xa3, 0xfe, 0x5e, 0x31, 0x23, + 0x31, 0x23, 0x01, 0x82, 0x22, 0x5f, 0x22, 0x5f, + 0xc7, 0x38, 0xb8, 0x32, 0xda, 0x61, 0x62, 0x5f, + 0x6b, 0x5f, 0xe3, 0x38, 0x9a, 0x5f, 0xcd, 0x5f, + 0xd7, 0x5f, 0xf9, 0x5f, 0x81, 0x60, 0x3a, 0x39, + 0x1c, 0x39, 0x94, 0x60, 0xd4, 0x26, 0xc7, 0x60, + 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x08, + 0x00, 0x80, 0x08, 0x00, 0x00, 0x08, 0x80, 0x28, + 0x80, 0x02, 0x00, 0x00, 0x02, 0x48, 0x61, 0x00, + 0x04, 0x06, 0x04, 0x32, 0x46, 0x6a, 0x5c, 0x67, + 0x96, 0xaa, 0xae, 0xc8, 0xd3, 0x5d, 0x62, 0x00, + 0x54, 0x77, 0xf3, 0x0c, 0x2b, 0x3d, 0x63, 0xfc, + 0x62, 0x68, 0x63, 0x83, 0x63, 0xe4, 0x63, 0xf1, + 0x2b, 0x22, 0x64, 0xc5, 0x63, 0xa9, 0x63, 0x2e, + 0x3a, 0x69, 0x64, 0x7e, 0x64, 0x9d, 0x64, 0x77, + 0x64, 0x6c, 0x3a, 0x4f, 0x65, 0x6c, 0x65, 0x0a, + 0x30, 0xe3, 0x65, 0xf8, 0x66, 0x49, 0x66, 0x19, + 0x3b, 0x91, 0x66, 0x08, 0x3b, 0xe4, 0x3a, 0x92, + 0x51, 0x95, 0x51, 0x00, 0x67, 0x9c, 0x66, 0xad, + 0x80, 0xd9, 0x43, 0x17, 0x67, 0x1b, 0x67, 0x21, + 0x67, 0x5e, 0x67, 0x53, 0x67, 0xc3, 0x33, 0x49, + 0x3b, 0xfa, 0x67, 0x85, 0x67, 0x52, 0x68, 0x85, + 0x68, 0x6d, 0x34, 0x8e, 0x68, 0x1f, 0x68, 0x14, + 0x69, 0x9d, 0x3b, 0x42, 0x69, 0xa3, 0x69, 0xea, + 0x69, 0xa8, 0x6a, 0xa3, 0x36, 0xdb, 0x6a, 0x18, + 0x3c, 0x21, 0x6b, 0xa7, 0x38, 0x54, 0x6b, 0x4e, + 0x3c, 0x72, 0x6b, 0x9f, 0x6b, 0xba, 0x6b, 0xbb, + 0x6b, 0x8d, 0x3a, 0x0b, 0x1d, 0xfa, 0x3a, 0x4e, + 0x6c, 0xbc, 0x3c, 0xbf, 0x6c, 0xcd, 0x6c, 0x67, + 0x6c, 0x16, 0x6d, 0x3e, 0x6d, 0x77, 0x6d, 0x41, + 0x6d, 0x69, 0x6d, 0x78, 0x6d, 0x85, 0x6d, 0x1e, + 0x3d, 0x34, 0x6d, 0x2f, 0x6e, 0x6e, 0x6e, 0x33, + 0x3d, 0xcb, 0x6e, 0xc7, 0x6e, 0xd1, 0x3e, 0xf9, + 0x6d, 0x6e, 0x6f, 0x5e, 0x3f, 0x8e, 0x3f, 0xc6, + 0x6f, 0x39, 0x70, 0x1e, 0x70, 0x1b, 0x70, 0x96, + 0x3d, 0x4a, 0x70, 0x7d, 0x70, 0x77, 0x70, 0xad, + 0x70, 0x25, 0x05, 0x45, 0x71, 0x63, 0x42, 0x9c, + 0x71, 0xab, 0x43, 0x28, 0x72, 0x35, 0x72, 0x50, + 0x72, 0x08, 0x46, 0x80, 0x72, 0x95, 0x72, 0x35, + 0x47, 0x02, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x02, 0x02, + 0x80, 0x8a, 0x00, 0x00, 0x20, 0x00, 0x08, 0x0a, + 0x00, 0x80, 0x88, 0x80, 0x20, 0x14, 0x48, 0x7a, + 0x73, 0x8b, 0x73, 0xac, 0x3e, 0xa5, 0x73, 0xb8, + 0x3e, 0xb8, 0x3e, 0x47, 0x74, 0x5c, 0x74, 0x71, + 0x74, 0x85, 0x74, 0xca, 0x74, 0x1b, 0x3f, 0x24, + 0x75, 0x36, 0x4c, 0x3e, 0x75, 0x92, 0x4c, 0x70, + 0x75, 0x9f, 0x21, 0x10, 0x76, 0xa1, 0x4f, 0xb8, + 0x4f, 0x44, 0x50, 0xfc, 0x3f, 0x08, 0x40, 0xf4, + 0x76, 0xf3, 0x50, 0xf2, 0x50, 0x19, 0x51, 0x33, + 0x51, 0x1e, 0x77, 0x1f, 0x77, 0x1f, 0x77, 0x4a, + 0x77, 0x39, 0x40, 0x8b, 0x77, 0x46, 0x40, 0x96, + 0x40, 0x1d, 0x54, 0x4e, 0x78, 0x8c, 0x78, 0xcc, + 0x78, 0xe3, 0x40, 0x26, 0x56, 0x56, 0x79, 0x9a, + 0x56, 0xc5, 0x56, 0x8f, 0x79, 0xeb, 0x79, 0x2f, + 0x41, 0x40, 0x7a, 0x4a, 0x7a, 0x4f, 0x7a, 0x7c, + 0x59, 0xa7, 0x5a, 0xa7, 0x5a, 0xee, 0x7a, 0x02, + 0x42, 0xab, 0x5b, 0xc6, 0x7b, 0xc9, 0x7b, 0x27, + 0x42, 0x80, 0x5c, 0xd2, 0x7c, 0xa0, 0x42, 0xe8, + 0x7c, 0xe3, 0x7c, 0x00, 0x7d, 0x86, 0x5f, 0x63, + 0x7d, 0x01, 0x43, 0xc7, 0x7d, 0x02, 0x7e, 0x45, + 0x7e, 0x34, 0x43, 0x28, 0x62, 0x47, 0x62, 0x59, + 0x43, 0xd9, 0x62, 0x7a, 0x7f, 0x3e, 0x63, 0x95, + 0x7f, 0xfa, 0x7f, 0x05, 0x80, 0xda, 0x64, 0x23, + 0x65, 0x60, 0x80, 0xa8, 0x65, 0x70, 0x80, 0x5f, + 0x33, 0xd5, 0x43, 0xb2, 0x80, 0x03, 0x81, 0x0b, + 0x44, 0x3e, 0x81, 0xb5, 0x5a, 0xa7, 0x67, 0xb5, + 0x67, 0x93, 0x33, 0x9c, 0x33, 0x01, 0x82, 0x04, + 0x82, 0x9e, 0x8f, 0x6b, 0x44, 0x91, 0x82, 0x8b, + 0x82, 0x9d, 0x82, 0xb3, 0x52, 0xb1, 0x82, 0xb3, + 0x82, 0xbd, 0x82, 0xe6, 0x82, 0x3c, 0x6b, 0xe5, + 0x82, 0x1d, 0x83, 0x63, 0x83, 0xad, 0x83, 0x23, + 0x83, 0xbd, 0x83, 0xe7, 0x83, 0x57, 0x84, 0x53, + 0x83, 0xca, 0x83, 0xcc, 0x83, 0xdc, 0x83, 0x36, + 0x6c, 0x6b, 0x6d, 0x02, 0x00, 0x00, 0x20, 0x22, + 0x2a, 0xa0, 0x0a, 0x00, 0x20, 0x80, 0x28, 0x00, + 0xa8, 0x20, 0x20, 0x00, 0x02, 0x80, 0x22, 0x02, + 0x8a, 0x08, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x28, 0xd5, 0x6c, 0x2b, 0x45, 0xf1, + 0x84, 0xf3, 0x84, 0x16, 0x85, 0xca, 0x73, 0x64, + 0x85, 0x2c, 0x6f, 0x5d, 0x45, 0x61, 0x45, 0xb1, + 0x6f, 0xd2, 0x70, 0x6b, 0x45, 0x50, 0x86, 0x5c, + 0x86, 0x67, 0x86, 0x69, 0x86, 0xa9, 0x86, 0x88, + 0x86, 0x0e, 0x87, 0xe2, 0x86, 0x79, 0x87, 0x28, + 0x87, 0x6b, 0x87, 0x86, 0x87, 0xd7, 0x45, 0xe1, + 0x87, 0x01, 0x88, 0xf9, 0x45, 0x60, 0x88, 0x63, + 0x88, 0x67, 0x76, 0xd7, 0x88, 0xde, 0x88, 0x35, + 0x46, 0xfa, 0x88, 0xbb, 0x34, 0xae, 0x78, 0x66, + 0x79, 0xbe, 0x46, 0xc7, 0x46, 0xa0, 0x8a, 0xed, + 0x8a, 0x8a, 0x8b, 0x55, 0x8c, 0xa8, 0x7c, 0xab, + 0x8c, 0xc1, 0x8c, 0x1b, 0x8d, 0x77, 0x8d, 0x2f, + 0x7f, 0x04, 0x08, 0xcb, 0x8d, 0xbc, 0x8d, 0xf0, + 0x8d, 0xde, 0x08, 0xd4, 0x8e, 0x38, 0x8f, 0xd2, + 0x85, 0xed, 0x85, 0x94, 0x90, 0xf1, 0x90, 0x11, + 0x91, 0x2e, 0x87, 0x1b, 0x91, 0x38, 0x92, 0xd7, + 0x92, 0xd8, 0x92, 0x7c, 0x92, 0xf9, 0x93, 0x15, + 0x94, 0xfa, 0x8b, 0x8b, 0x95, 0x95, 0x49, 0xb7, + 0x95, 0x77, 0x8d, 0xe6, 0x49, 0xc3, 0x96, 0xb2, + 0x5d, 0x23, 0x97, 0x45, 0x91, 0x1a, 0x92, 0x6e, + 0x4a, 0x76, 0x4a, 0xe0, 0x97, 0x0a, 0x94, 0xb2, + 0x4a, 0x96, 0x94, 0x0b, 0x98, 0x0b, 0x98, 0x29, + 0x98, 0xb6, 0x95, 0xe2, 0x98, 0x33, 0x4b, 0x29, + 0x99, 0xa7, 0x99, 0xc2, 0x99, 0xfe, 0x99, 0xce, + 0x4b, 0x30, 0x9b, 0x12, 0x9b, 0x40, 0x9c, 0xfd, + 0x9c, 0xce, 0x4c, 0xed, 0x4c, 0x67, 0x9d, 0xce, + 0xa0, 0xf8, 0x4c, 0x05, 0xa1, 0x0e, 0xa2, 0x91, + 0xa2, 0xbb, 0x9e, 0x56, 0x4d, 0xf9, 0x9e, 0xfe, + 0x9e, 0x05, 0x9f, 0x0f, 0x9f, 0x16, 0x9f, 0x3b, + 0x9f, 0x00, 0xa6, 0x02, 0x88, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x28, 0x00, 0x08, 0xa0, + 0x80, 0xa0, 0x80, 0x00, 0x80, 0x80, 0x00, 0x0a, + 0x88, 0x80, 0x00, 0x80, 0x00, 0x20, 0x2a, 0x00, + 0x80, +}; + +static const uint16_t unicode_comp_table[945] = { + 0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0, + 0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982, + 0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8, + 0x02ca, 0x02cc, 0x0287, 0x228a, 0x02ce, 0x228c, 0x2290, 0x2292, + 0x228e, 0x0288, 0x0289, 0x028a, 0x2482, 0x0300, 0x0302, 0x0304, + 0x028b, 0x2480, 0x0308, 0x0984, 0x0986, 0x2458, 0x0a02, 0x0306, + 0x2298, 0x229a, 0x229e, 0x0900, 0x030a, 0x22a0, 0x030c, 0x030e, + 0x0840, 0x0310, 0x0312, 0x22a2, 0x22a6, 0x09c0, 0x22a4, 0x22a8, + 0x22aa, 0x028c, 0x028d, 0x028e, 0x0340, 0x0342, 0x0344, 0x0380, + 0x028f, 0x248e, 0x07c2, 0x0988, 0x098a, 0x2490, 0x0346, 0x22ac, + 0x0400, 0x22b0, 0x0842, 0x22b2, 0x0402, 0x22b4, 0x0440, 0x0444, + 0x22b6, 0x0442, 0x22c2, 0x22c0, 0x22c4, 0x22c6, 0x22c8, 0x0940, + 0x04c0, 0x0291, 0x22ca, 0x04c4, 0x22cc, 0x04c2, 0x22d0, 0x22ce, + 0x0292, 0x0293, 0x0294, 0x0295, 0x0540, 0x0542, 0x0a08, 0x0296, + 0x2494, 0x0544, 0x07c4, 0x098c, 0x098e, 0x06c0, 0x2492, 0x0844, + 0x2308, 0x230a, 0x0580, 0x230c, 0x0584, 0x0990, 0x0992, 0x230e, + 0x0582, 0x2312, 0x0586, 0x0588, 0x2314, 0x058c, 0x2316, 0x0998, + 0x058a, 0x231e, 0x0590, 0x2320, 0x099a, 0x058e, 0x2324, 0x2322, + 0x0299, 0x029a, 0x029b, 0x05c0, 0x05c2, 0x05c4, 0x029c, 0x24ac, + 0x05c6, 0x05c8, 0x07c6, 0x0994, 0x0996, 0x0700, 0x24aa, 0x2326, + 0x05ca, 0x232a, 0x2328, 0x2340, 0x2342, 0x2344, 0x2346, 0x05cc, + 0x234a, 0x2348, 0x234c, 0x234e, 0x2350, 0x24b8, 0x029d, 0x05ce, + 0x24be, 0x0a0c, 0x2352, 0x0600, 0x24bc, 0x24ba, 0x0640, 0x2354, + 0x0642, 0x0644, 0x2356, 0x2358, 0x02a0, 0x02a1, 0x02a2, 0x02a3, + 0x02c1, 0x02c3, 0x0a01, 0x02a4, 0x2443, 0x02a5, 0x07c1, 0x0981, + 0x0983, 0x2441, 0x2281, 0x02c5, 0x2283, 0x2285, 0x2287, 0x02c7, + 0x02c9, 0x02cb, 0x02cd, 0x02a7, 0x228b, 0x02cf, 0x228d, 0x2291, + 0x2293, 0x228f, 0x02a8, 0x02a9, 0x02aa, 0x2483, 0x0301, 0x0303, + 0x0305, 0x02ab, 0x2481, 0x0309, 0x0985, 0x0987, 0x2459, 0x0a03, + 0x0307, 0x2299, 0x229b, 0x229f, 0x0901, 0x030b, 0x22a1, 0x030d, + 0x030f, 0x0841, 0x0311, 0x0313, 0x22a3, 0x22a7, 0x09c1, 0x22a5, + 0x22a9, 0x22ab, 0x2380, 0x02ac, 0x02ad, 0x02ae, 0x0341, 0x0343, + 0x0345, 0x02af, 0x248f, 0x07c3, 0x0989, 0x098b, 0x2491, 0x0347, + 0x22ad, 0x0401, 0x0884, 0x22b1, 0x0843, 0x22b3, 0x0403, 0x22b5, + 0x0441, 0x0445, 0x22b7, 0x0443, 0x22c3, 0x22c1, 0x22c5, 0x22c7, + 0x22c9, 0x0941, 0x04c1, 0x02b1, 0x22cb, 0x04c5, 0x22cd, 0x04c3, + 0x22d1, 0x22cf, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x0541, 0x0543, + 0x0a09, 0x02b6, 0x2495, 0x0545, 0x07c5, 0x098d, 0x098f, 0x06c1, + 0x2493, 0x0845, 0x2309, 0x230b, 0x0581, 0x230d, 0x0585, 0x0991, + 0x0993, 0x230f, 0x0583, 0x2313, 0x0587, 0x0589, 0x2315, 0x058d, + 0x2317, 0x0999, 0x058b, 0x231f, 0x2381, 0x0591, 0x2321, 0x099b, + 0x058f, 0x2325, 0x2323, 0x02b9, 0x02ba, 0x02bb, 0x05c1, 0x05c3, + 0x05c5, 0x02bc, 0x24ad, 0x05c7, 0x05c9, 0x07c7, 0x0995, 0x0997, + 0x0701, 0x24ab, 0x2327, 0x05cb, 0x232b, 0x2329, 0x2341, 0x2343, + 0x2345, 0x2347, 0x05cd, 0x234b, 0x2349, 0x2382, 0x234d, 0x234f, + 0x2351, 0x24b9, 0x02bd, 0x05cf, 0x24bf, 0x0a0d, 0x2353, 0x02bf, + 0x24bd, 0x2383, 0x24bb, 0x0641, 0x2355, 0x0643, 0x0645, 0x2357, + 0x2359, 0x3101, 0x0c80, 0x2e00, 0x2446, 0x2444, 0x244a, 0x2448, + 0x0800, 0x0942, 0x0944, 0x0804, 0x2288, 0x2486, 0x2484, 0x248a, + 0x2488, 0x22ae, 0x2498, 0x2496, 0x249c, 0x249a, 0x2300, 0x0a06, + 0x2302, 0x0a04, 0x0946, 0x07ce, 0x07ca, 0x07c8, 0x07cc, 0x2447, + 0x2445, 0x244b, 0x2449, 0x0801, 0x0943, 0x0945, 0x0805, 0x2289, + 0x2487, 0x2485, 0x248b, 0x2489, 0x22af, 0x2499, 0x2497, 0x249d, + 0x249b, 0x2301, 0x0a07, 0x2303, 0x0a05, 0x0947, 0x07cf, 0x07cb, + 0x07c9, 0x07cd, 0x2450, 0x244e, 0x2454, 0x2452, 0x2451, 0x244f, + 0x2455, 0x2453, 0x2294, 0x2296, 0x2295, 0x2297, 0x2304, 0x2306, + 0x2305, 0x2307, 0x2318, 0x2319, 0x231a, 0x231b, 0x232c, 0x232d, + 0x232e, 0x232f, 0x2400, 0x24a2, 0x24a0, 0x24a6, 0x24a4, 0x24a8, + 0x24a3, 0x24a1, 0x24a7, 0x24a5, 0x24a9, 0x24b0, 0x24ae, 0x24b4, + 0x24b2, 0x24b6, 0x24b1, 0x24af, 0x24b5, 0x24b3, 0x24b7, 0x0882, + 0x0880, 0x0881, 0x0802, 0x0803, 0x229c, 0x229d, 0x0a0a, 0x0a0b, + 0x0883, 0x0b40, 0x2c8a, 0x0c81, 0x2c89, 0x2c88, 0x2540, 0x2541, + 0x2d00, 0x2e07, 0x0d00, 0x2640, 0x2641, 0x2e80, 0x0d01, 0x26c8, + 0x26c9, 0x2f00, 0x2f84, 0x0d02, 0x2f83, 0x2f82, 0x0d40, 0x26d8, + 0x26d9, 0x3186, 0x0d04, 0x2740, 0x2741, 0x3100, 0x3086, 0x0d06, + 0x3085, 0x3084, 0x0d41, 0x2840, 0x3200, 0x0d07, 0x284f, 0x2850, + 0x3280, 0x2c84, 0x2e03, 0x2857, 0x0d42, 0x2c81, 0x2c80, 0x24c0, + 0x24c1, 0x2c86, 0x2c83, 0x28c0, 0x0d43, 0x25c0, 0x25c1, 0x2940, + 0x0d44, 0x26c0, 0x26c1, 0x2e05, 0x2e02, 0x29c0, 0x0d45, 0x2f05, + 0x2f04, 0x0d80, 0x26d0, 0x26d1, 0x2f80, 0x2a40, 0x0d82, 0x26e0, + 0x26e1, 0x3080, 0x3081, 0x2ac0, 0x0d83, 0x3004, 0x3003, 0x0d81, + 0x27c0, 0x27c1, 0x3082, 0x2b40, 0x0d84, 0x2847, 0x2848, 0x3184, + 0x3181, 0x2f06, 0x0d08, 0x2f81, 0x3005, 0x0d46, 0x3083, 0x3182, + 0x0e00, 0x0e01, 0x0f40, 0x1180, 0x1182, 0x0f03, 0x0f00, 0x11c0, + 0x0f01, 0x1140, 0x1202, 0x1204, 0x0f81, 0x1240, 0x0fc0, 0x1242, + 0x0f80, 0x1244, 0x1284, 0x0f82, 0x1286, 0x1288, 0x128a, 0x12c0, + 0x1282, 0x1181, 0x1183, 0x1043, 0x1040, 0x11c1, 0x1041, 0x1141, + 0x1203, 0x1205, 0x10c1, 0x1241, 0x1000, 0x1243, 0x10c0, 0x1245, + 0x1285, 0x10c2, 0x1287, 0x1289, 0x128b, 0x12c1, 0x1283, 0x1080, + 0x1100, 0x1101, 0x1200, 0x1201, 0x1280, 0x1281, 0x1340, 0x1341, + 0x1343, 0x1342, 0x1344, 0x13c2, 0x1400, 0x13c0, 0x1440, 0x1480, + 0x14c0, 0x1540, 0x1541, 0x1740, 0x1700, 0x1741, 0x17c0, 0x1800, + 0x1802, 0x1801, 0x1840, 0x1880, 0x1900, 0x18c0, 0x18c1, 0x1901, + 0x1940, 0x1942, 0x1941, 0x1980, 0x19c0, 0x19c2, 0x19c1, 0x1c80, + 0x1cc0, 0x1dc0, 0x1f80, 0x2000, 0x2002, 0x2004, 0x2006, 0x2008, + 0x2040, 0x2080, 0x2082, 0x20c0, 0x20c1, 0x2100, 0x22b8, 0x22b9, + 0x2310, 0x2311, 0x231c, 0x231d, 0x244c, 0x2456, 0x244d, 0x2457, + 0x248c, 0x248d, 0x249e, 0x249f, 0x2500, 0x2502, 0x2504, 0x2bc0, + 0x2501, 0x2503, 0x2505, 0x2bc1, 0x2bc2, 0x2bc3, 0x2bc4, 0x2bc5, + 0x2bc6, 0x2bc7, 0x2580, 0x2582, 0x2584, 0x2bc8, 0x2581, 0x2583, + 0x2585, 0x2bc9, 0x2bca, 0x2bcb, 0x2bcc, 0x2bcd, 0x2bce, 0x2bcf, + 0x2600, 0x2602, 0x2601, 0x2603, 0x2680, 0x2682, 0x2681, 0x2683, + 0x26c2, 0x26c4, 0x26c6, 0x2c00, 0x26c3, 0x26c5, 0x26c7, 0x2c01, + 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x26ca, 0x26cc, + 0x26ce, 0x2c08, 0x26cb, 0x26cd, 0x26cf, 0x2c09, 0x2c0a, 0x2c0b, + 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x26d2, 0x26d4, 0x26d6, 0x26d3, + 0x26d5, 0x26d7, 0x26da, 0x26dc, 0x26de, 0x26db, 0x26dd, 0x26df, + 0x2700, 0x2702, 0x2701, 0x2703, 0x2780, 0x2782, 0x2781, 0x2783, + 0x2800, 0x2802, 0x2804, 0x2801, 0x2803, 0x2805, 0x2842, 0x2844, + 0x2846, 0x2849, 0x284b, 0x284d, 0x2c40, 0x284a, 0x284c, 0x284e, + 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2851, + 0x2853, 0x2855, 0x2c48, 0x2852, 0x2854, 0x2856, 0x2c49, 0x2c4a, + 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c82, 0x2e01, 0x3180, + 0x2c87, 0x2f01, 0x2f02, 0x2f03, 0x2e06, 0x3185, 0x3000, 0x3001, + 0x3002, 0x4640, 0x4641, 0x4680, 0x46c0, 0x46c2, 0x46c1, 0x4700, + 0x4740, 0x4780, 0x47c0, 0x47c2, 0x4900, 0x4940, 0x4980, 0x4982, + 0x4a00, 0x49c2, 0x4a03, 0x4a04, 0x4a40, 0x4a41, 0x4a80, 0x4a81, + 0x4ac0, 0x4ac1, 0x4bc0, 0x4bc1, 0x4b00, 0x4b01, 0x4b40, 0x4b41, + 0x4bc2, 0x4bc3, 0x4b80, 0x4b81, 0x4b82, 0x4b83, 0x4c00, 0x4c01, + 0x4c02, 0x4c03, 0x5600, 0x5440, 0x5442, 0x5444, 0x5446, 0x5448, + 0x544a, 0x544c, 0x544e, 0x5450, 0x5452, 0x5454, 0x5456, 0x5480, + 0x5482, 0x5484, 0x54c0, 0x54c1, 0x5500, 0x5501, 0x5540, 0x5541, + 0x5580, 0x5581, 0x55c0, 0x55c1, 0x5680, 0x58c0, 0x5700, 0x5702, + 0x5704, 0x5706, 0x5708, 0x570a, 0x570c, 0x570e, 0x5710, 0x5712, + 0x5714, 0x5716, 0x5740, 0x5742, 0x5744, 0x5780, 0x5781, 0x57c0, + 0x57c1, 0x5800, 0x5801, 0x5840, 0x5841, 0x5880, 0x5881, 0x5900, + 0x5901, 0x5902, 0x5903, 0x5940, 0x8f40, 0x8f42, 0x8f80, 0x8fc0, + 0x8fc1, 0x9000, 0x9001, 0x9041, 0x9040, 0x9043, 0x9080, 0x9081, + 0x90c0, +}; + +typedef enum { + UNICODE_GC_Cn, + UNICODE_GC_Lu, + UNICODE_GC_Ll, + UNICODE_GC_Lt, + UNICODE_GC_Lm, + UNICODE_GC_Lo, + UNICODE_GC_Mn, + UNICODE_GC_Mc, + UNICODE_GC_Me, + UNICODE_GC_Nd, + UNICODE_GC_Nl, + UNICODE_GC_No, + UNICODE_GC_Sm, + UNICODE_GC_Sc, + UNICODE_GC_Sk, + UNICODE_GC_So, + UNICODE_GC_Pc, + UNICODE_GC_Pd, + UNICODE_GC_Ps, + UNICODE_GC_Pe, + UNICODE_GC_Pi, + UNICODE_GC_Pf, + UNICODE_GC_Po, + UNICODE_GC_Zs, + UNICODE_GC_Zl, + UNICODE_GC_Zp, + UNICODE_GC_Cc, + UNICODE_GC_Cf, + UNICODE_GC_Cs, + UNICODE_GC_Co, + UNICODE_GC_LC, + UNICODE_GC_L, + UNICODE_GC_M, + UNICODE_GC_N, + UNICODE_GC_S, + UNICODE_GC_P, + UNICODE_GC_Z, + UNICODE_GC_C, + UNICODE_GC_COUNT, +} UnicodeGCEnum; + +static const char unicode_gc_name_table[] = + "Cn,Unassigned" "\0" + "Lu,Uppercase_Letter" "\0" + "Ll,Lowercase_Letter" "\0" + "Lt,Titlecase_Letter" "\0" + "Lm,Modifier_Letter" "\0" + "Lo,Other_Letter" "\0" + "Mn,Nonspacing_Mark" "\0" + "Mc,Spacing_Mark" "\0" + "Me,Enclosing_Mark" "\0" + "Nd,Decimal_Number,digit" "\0" + "Nl,Letter_Number" "\0" + "No,Other_Number" "\0" + "Sm,Math_Symbol" "\0" + "Sc,Currency_Symbol" "\0" + "Sk,Modifier_Symbol" "\0" + "So,Other_Symbol" "\0" + "Pc,Connector_Punctuation" "\0" + "Pd,Dash_Punctuation" "\0" + "Ps,Open_Punctuation" "\0" + "Pe,Close_Punctuation" "\0" + "Pi,Initial_Punctuation" "\0" + "Pf,Final_Punctuation" "\0" + "Po,Other_Punctuation" "\0" + "Zs,Space_Separator" "\0" + "Zl,Line_Separator" "\0" + "Zp,Paragraph_Separator" "\0" + "Cc,Control,cntrl" "\0" + "Cf,Format" "\0" + "Cs,Surrogate" "\0" + "Co,Private_Use" "\0" + "LC,Cased_Letter" "\0" + "L,Letter" "\0" + "M,Mark,Combining_Mark" "\0" + "N,Number" "\0" + "S,Symbol" "\0" + "P,Punctuation,punct" "\0" + "Z,Separator" "\0" + "C,Other" "\0" +; + +static const uint8_t unicode_gc_table[3948] = { + 0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13, + 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, + 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, + 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c, + 0xfa, 0x19, 0x17, 0x16, 0x6d, 0x0f, 0x16, 0x0e, + 0x0f, 0x05, 0x14, 0x0c, 0x1b, 0x0f, 0x0e, 0x0f, + 0x0c, 0x2b, 0x0e, 0x02, 0x36, 0x0e, 0x0b, 0x05, + 0x15, 0x4b, 0x16, 0xe1, 0x0f, 0x0c, 0xc1, 0xe2, + 0x10, 0x0c, 0xe2, 0x00, 0xff, 0x30, 0x02, 0xff, + 0x08, 0x02, 0xff, 0x27, 0xbf, 0x22, 0x21, 0x02, + 0x5f, 0x5f, 0x21, 0x22, 0x61, 0x02, 0x21, 0x02, + 0x41, 0x42, 0x21, 0x02, 0x21, 0x02, 0x9f, 0x7f, + 0x02, 0x5f, 0x5f, 0x21, 0x02, 0x5f, 0x3f, 0x02, + 0x05, 0x3f, 0x22, 0x65, 0x01, 0x03, 0x02, 0x01, + 0x03, 0x02, 0x01, 0x03, 0x02, 0xff, 0x08, 0x02, + 0xff, 0x0a, 0x02, 0x01, 0x03, 0x02, 0x5f, 0x21, + 0x02, 0xff, 0x32, 0xa2, 0x21, 0x02, 0x21, 0x22, + 0x5f, 0x41, 0x02, 0xff, 0x00, 0xe2, 0x3c, 0x05, + 0xe2, 0x13, 0xe4, 0x0a, 0x6e, 0xe4, 0x04, 0xee, + 0x06, 0x84, 0xce, 0x04, 0x0e, 0x04, 0xee, 0x09, + 0xe6, 0x68, 0x7f, 0x04, 0x0e, 0x3f, 0x20, 0x04, + 0x42, 0x16, 0x01, 0x60, 0x2e, 0x01, 0x16, 0x41, + 0x00, 0x01, 0x00, 0x21, 0x02, 0xe1, 0x09, 0x00, + 0xe1, 0x01, 0xe2, 0x1b, 0x3f, 0x02, 0x41, 0x42, + 0xff, 0x10, 0x62, 0x3f, 0x0c, 0x5f, 0x3f, 0x02, + 0xe1, 0x2b, 0xe2, 0x28, 0xff, 0x1a, 0x0f, 0x86, + 0x28, 0xff, 0x2f, 0xff, 0x06, 0x02, 0xff, 0x58, + 0x00, 0xe1, 0x1e, 0x20, 0x04, 0xb6, 0xe2, 0x21, + 0x16, 0x11, 0x20, 0x2f, 0x0d, 0x00, 0xe6, 0x25, + 0x11, 0x06, 0x16, 0x26, 0x16, 0x26, 0x16, 0x06, + 0xe0, 0x00, 0xe5, 0x13, 0x60, 0x65, 0x36, 0xe0, + 0x03, 0xbb, 0x4c, 0x36, 0x0d, 0x36, 0x2f, 0xe6, + 0x03, 0x16, 0x1b, 0x56, 0xe5, 0x18, 0x04, 0xe5, + 0x02, 0xe6, 0x0d, 0xe9, 0x02, 0x76, 0x25, 0x06, + 0xe5, 0x5b, 0x16, 0x05, 0xc6, 0x1b, 0x0f, 0xa6, + 0x24, 0x26, 0x0f, 0x66, 0x25, 0xe9, 0x02, 0x45, + 0x2f, 0x05, 0xf6, 0x06, 0x00, 0x1b, 0x05, 0x06, + 0xe5, 0x16, 0xe6, 0x13, 0x20, 0xe5, 0x51, 0xe6, + 0x03, 0x05, 0xe0, 0x06, 0xe9, 0x02, 0xe5, 0x19, + 0xe6, 0x01, 0x24, 0x0f, 0x56, 0x04, 0x20, 0x06, + 0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01, 0x04, + 0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00, 0xe5, + 0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03, 0x80, + 0xe5, 0x10, 0x0e, 0xa5, 0x00, 0x3b, 0xa0, 0xe6, + 0x00, 0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6, + 0x18, 0x07, 0xe5, 0x2e, 0x06, 0x07, 0x06, 0x05, + 0x47, 0xe6, 0x00, 0x67, 0x06, 0x27, 0x05, 0xc6, + 0xe5, 0x02, 0x26, 0x36, 0xe9, 0x02, 0x16, 0x04, + 0xe5, 0x07, 0x06, 0x27, 0x00, 0xe5, 0x00, 0x20, + 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x05, + 0x40, 0x65, 0x20, 0x06, 0x05, 0x47, 0x66, 0x20, + 0x27, 0x20, 0x27, 0x06, 0x05, 0xe0, 0x00, 0x07, + 0x60, 0x25, 0x00, 0x45, 0x26, 0x20, 0xe9, 0x02, + 0x25, 0x2d, 0xab, 0x0f, 0x0d, 0x05, 0x16, 0x06, + 0x20, 0x26, 0x07, 0x00, 0xa5, 0x60, 0x25, 0x20, + 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x25, + 0x00, 0x25, 0x20, 0x06, 0x00, 0x47, 0x26, 0x60, + 0x26, 0x20, 0x46, 0x40, 0x06, 0xc0, 0x65, 0x00, + 0x05, 0xc0, 0xe9, 0x02, 0x26, 0x45, 0x06, 0x16, + 0xe0, 0x02, 0x26, 0x07, 0x00, 0xe5, 0x01, 0x00, + 0x45, 0x00, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, + 0x00, 0x85, 0x20, 0x06, 0x05, 0x47, 0x86, 0x00, + 0x26, 0x07, 0x00, 0x27, 0x06, 0x20, 0x05, 0xe0, + 0x07, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x16, 0x0d, + 0xc0, 0x05, 0xa6, 0x00, 0x06, 0x27, 0x00, 0xe5, + 0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, + 0x00, 0x25, 0x00, 0x85, 0x20, 0x06, 0x05, 0x07, + 0x06, 0x07, 0x66, 0x20, 0x27, 0x20, 0x27, 0x06, + 0xc0, 0x26, 0x07, 0x60, 0x25, 0x00, 0x45, 0x26, + 0x20, 0xe9, 0x02, 0x0f, 0x05, 0xab, 0xe0, 0x02, + 0x06, 0x05, 0x00, 0xa5, 0x40, 0x45, 0x00, 0x65, + 0x40, 0x25, 0x00, 0x05, 0x00, 0x25, 0x40, 0x25, + 0x40, 0x45, 0x40, 0xe5, 0x04, 0x60, 0x27, 0x06, + 0x27, 0x40, 0x47, 0x00, 0x47, 0x06, 0x20, 0x05, + 0xa0, 0x07, 0xe0, 0x06, 0xe9, 0x02, 0x4b, 0xaf, + 0x0d, 0x0f, 0x80, 0x06, 0x47, 0x06, 0xe5, 0x00, + 0x00, 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x08, + 0x20, 0x06, 0x05, 0x46, 0x67, 0x00, 0x46, 0x00, + 0x66, 0xc0, 0x26, 0x00, 0x45, 0x20, 0x05, 0x20, + 0x25, 0x26, 0x20, 0xe9, 0x02, 0xc0, 0x16, 0xcb, + 0x0f, 0x05, 0x06, 0x27, 0x16, 0xe5, 0x00, 0x00, + 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x02, 0x00, + 0x85, 0x20, 0x06, 0x05, 0x07, 0x06, 0x87, 0x00, + 0x06, 0x27, 0x00, 0x27, 0x26, 0xc0, 0x27, 0xa0, + 0x25, 0x00, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x00, + 0x25, 0x07, 0xe0, 0x04, 0x26, 0x27, 0xe5, 0x01, + 0x00, 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47, + 0x66, 0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f, + 0x60, 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9, + 0x02, 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27, + 0x00, 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5, + 0x01, 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60, + 0x47, 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0, + 0xe9, 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5, + 0x28, 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04, + 0xe6, 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d, + 0x25, 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10, + 0x00, 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6, + 0x01, 0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xc6, + 0x00, 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05, + 0x4f, 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf, + 0xe9, 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06, + 0x0f, 0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5, + 0x00, 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07, + 0x86, 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6, + 0x1c, 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f, + 0x96, 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27, + 0x66, 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05, + 0xe9, 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46, + 0x05, 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05, + 0x06, 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9, + 0x02, 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01, + 0x80, 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42, + 0xe5, 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00, + 0x05, 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65, + 0x20, 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00, + 0x05, 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5, + 0x31, 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46, + 0xf6, 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef, + 0x02, 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11, + 0xe5, 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17, + 0xe5, 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56, + 0x4a, 0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07, + 0xe0, 0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0, + 0x01, 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05, + 0x00, 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c, + 0x26, 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6, + 0x03, 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20, + 0xe9, 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11, + 0x76, 0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5, + 0x1b, 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5, + 0x1a, 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02, + 0xe5, 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60, + 0x27, 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36, + 0xe9, 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03, + 0xe5, 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02, + 0x0b, 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27, + 0x06, 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07, + 0xc6, 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00, + 0xa7, 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0, + 0xe9, 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, + 0x06, 0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07, + 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87, + 0x06, 0x27, 0xe5, 0x00, 0x40, 0xe9, 0x02, 0xd6, + 0xef, 0x02, 0xe6, 0x01, 0xef, 0x01, 0x36, 0x00, + 0x26, 0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26, + 0x07, 0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06, + 0x07, 0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0, + 0x00, 0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00, + 0x27, 0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45, + 0xe9, 0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01, + 0xc0, 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00, 0xe0, + 0x00, 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6, 0x65, + 0x06, 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05, 0x80, + 0xe2, 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04, 0xe2, + 0x1a, 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80, 0x0e, + 0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00, + 0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00, + 0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, + 0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20, + 0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, + 0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61, + 0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61, + 0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e, + 0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22, + 0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1, + 0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14, + 0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01, + 0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13, + 0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17, + 0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab, + 0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12, + 0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, 0xe0, + 0x07, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04, + 0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02, + 0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c, + 0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, + 0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f, + 0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f, + 0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a, + 0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c, + 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17, + 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec, + 0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13, + 0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49, + 0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac, + 0xef, 0x3d, 0xe0, 0x11, 0xef, 0x03, 0xe0, 0x0d, + 0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, 0x80, + 0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, 0xec, + 0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, 0xef, + 0x24, 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, 0x12, + 0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, 0xec, + 0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, 0xac, + 0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, 0x61, + 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, 0xdf, + 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, 0x41, + 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, 0x3f, + 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, 0x02, + 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, 0x16, + 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, 0xc5, + 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, + 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xe6, + 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, 0x14, + 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, 0x36, + 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x96, + 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, 0x12, + 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, 0xef, + 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, 0x80, + 0x4e, 0xe0, 0x12, 0xef, 0x04, 0x60, 0x17, 0x56, + 0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, + 0x12, 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11, + 0x84, 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00, + 0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11, + 0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23, + 0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02, + 0xe5, 0x18, 0xef, 0x1c, 0xe0, 0x04, 0xe5, 0x08, + 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, 0xeb, + 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, 0x02, + 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, 0xe5, + 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, 0x8d, + 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, 0xe0, + 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, 0x84, + 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, 0xe0, + 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, 0xe6, + 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, 0xe5, + 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, 0xee, + 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, 0xff, + 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, 0x04, + 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, 0x61, + 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, 0x3f, + 0x80, 0x3f, 0x00, 0x02, 0x00, 0x02, 0x7f, 0xe0, + 0x10, 0x44, 0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06, + 0x45, 0x06, 0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26, + 0x07, 0x6f, 0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f, + 0xa0, 0xe5, 0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5, + 0x2a, 0xe7, 0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9, + 0x02, 0xa0, 0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16, + 0x25, 0x06, 0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00, + 0x36, 0xe5, 0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03, + 0x16, 0xe5, 0x15, 0x40, 0x46, 0x07, 0xe5, 0x27, + 0x06, 0x27, 0x66, 0x27, 0x26, 0x47, 0xf6, 0x05, + 0x00, 0x04, 0xe9, 0x02, 0x60, 0x36, 0x85, 0x06, + 0x04, 0xe5, 0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5, + 0x21, 0xa6, 0x27, 0x26, 0x27, 0x26, 0xe0, 0x01, + 0x45, 0x06, 0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9, + 0x02, 0x20, 0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f, + 0x05, 0x07, 0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05, + 0x46, 0x25, 0x26, 0x85, 0x26, 0x05, 0x06, 0x05, + 0xe0, 0x10, 0x25, 0x04, 0x36, 0xe5, 0x03, 0x07, + 0x26, 0x27, 0x36, 0x05, 0x24, 0x07, 0x06, 0xe0, + 0x02, 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01, + 0xc5, 0x00, 0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64, + 0xe2, 0x01, 0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5, + 0x1b, 0x27, 0x06, 0x27, 0x06, 0x27, 0x16, 0x07, + 0x06, 0x20, 0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c, + 0xe0, 0x04, 0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60, + 0xfc, 0x87, 0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80, + 0xe6, 0x20, 0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0, + 0x04, 0x82, 0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c, + 0xe5, 0x05, 0x00, 0x85, 0x00, 0x05, 0x00, 0x25, + 0x00, 0x25, 0x00, 0xe5, 0x64, 0xee, 0x09, 0xe0, + 0x08, 0xe5, 0x80, 0xe3, 0x13, 0x12, 0xef, 0x08, + 0xe5, 0x38, 0x20, 0xe5, 0x2e, 0xc0, 0x0f, 0xe0, + 0x18, 0xe5, 0x04, 0x0d, 0x4f, 0xe6, 0x08, 0xd6, + 0x12, 0x13, 0x16, 0xa0, 0xe6, 0x08, 0x16, 0x31, + 0x30, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x36, 0x12, 0x13, 0x76, 0x50, 0x56, 0x00, + 0x76, 0x11, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0x56, 0x0c, 0x11, 0x4c, 0x00, 0x16, 0x0d, 0x36, + 0x60, 0x85, 0x00, 0xe5, 0x7f, 0x20, 0x1b, 0x00, + 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16, + 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1, + 0x12, 0x12, 0x16, 0x13, 0x0e, 0x10, 0x0e, 0xe2, + 0x12, 0x12, 0x0c, 0x13, 0x0c, 0x12, 0x13, 0x16, + 0x12, 0x13, 0x36, 0xe5, 0x02, 0x04, 0xe5, 0x25, + 0x24, 0xe5, 0x17, 0x40, 0xa5, 0x20, 0xa5, 0x20, + 0xa5, 0x20, 0x45, 0x40, 0x2d, 0x0c, 0x0e, 0x0f, + 0x2d, 0x00, 0x0f, 0x6c, 0x2f, 0xe0, 0x02, 0x5b, + 0x2f, 0x20, 0xe5, 0x04, 0x00, 0xe5, 0x12, 0x00, + 0xe5, 0x0b, 0x00, 0x25, 0x00, 0xe5, 0x07, 0x20, + 0xe5, 0x06, 0xe0, 0x1a, 0xe5, 0x73, 0x80, 0x56, + 0x60, 0xeb, 0x25, 0x40, 0xef, 0x01, 0xea, 0x2d, + 0x6b, 0xef, 0x09, 0x2b, 0x4f, 0x00, 0xef, 0x05, + 0x40, 0x0f, 0xe0, 0x27, 0xef, 0x25, 0x06, 0xe0, + 0x7a, 0xe5, 0x15, 0x40, 0xe5, 0x29, 0xe0, 0x07, + 0x06, 0xeb, 0x13, 0x60, 0xe5, 0x18, 0x6b, 0xe0, + 0x01, 0xe5, 0x0c, 0x0a, 0xe5, 0x00, 0x0a, 0x80, + 0xe5, 0x1e, 0x86, 0x80, 0xe5, 0x16, 0x00, 0x16, + 0xe5, 0x1c, 0x60, 0xe5, 0x00, 0x16, 0x8a, 0xe0, + 0x22, 0xe1, 0x20, 0xe2, 0x20, 0xe5, 0x46, 0x20, + 0xe9, 0x02, 0xa0, 0xe1, 0x1c, 0x60, 0xe2, 0x1c, + 0x60, 0xe5, 0x20, 0xe0, 0x00, 0xe5, 0x2c, 0xe0, + 0x03, 0x16, 0xe1, 0x03, 0x00, 0xe1, 0x07, 0x00, + 0xc1, 0x00, 0x21, 0x00, 0xe2, 0x03, 0x00, 0xe2, + 0x07, 0x00, 0xc2, 0x00, 0x22, 0xe0, 0x3b, 0xe5, + 0x80, 0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02, + 0xe5, 0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22, + 0x00, 0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05, + 0x00, 0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20, + 0xe5, 0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f, + 0x2f, 0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01, + 0xe0, 0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b, + 0xe5, 0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80, + 0x16, 0xe0, 0x38, 0xe5, 0x30, 0x60, 0x2b, 0x25, + 0xeb, 0x08, 0x20, 0xeb, 0x26, 0x05, 0x46, 0x00, + 0x26, 0x80, 0x66, 0x65, 0x00, 0x45, 0x00, 0xe5, + 0x15, 0x20, 0x46, 0x60, 0x06, 0xeb, 0x01, 0xc0, + 0xf6, 0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16, 0xe5, + 0x15, 0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f, 0xe5, + 0x14, 0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01, 0xe5, + 0x2e, 0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb, 0x00, + 0xe5, 0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a, 0xc0, + 0x76, 0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5, 0x41, + 0xe0, 0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2, 0x2b, + 0xc0, 0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00, 0xe9, + 0x02, 0xe0, 0x80, 0x9e, 0xeb, 0x17, 0x00, 0xe5, + 0x22, 0x00, 0x26, 0x11, 0x20, 0x25, 0xe0, 0x43, + 0x46, 0xe5, 0x15, 0xeb, 0x02, 0x05, 0xe0, 0x00, + 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96, 0xe0, 0x0e, + 0xe5, 0x0a, 0x66, 0x76, 0xe0, 0x1e, 0xe5, 0x0d, + 0xcb, 0xe0, 0x0c, 0xe5, 0x0f, 0xe0, 0x01, 0x07, + 0x06, 0x07, 0xe5, 0x2d, 0xe6, 0x07, 0xd6, 0x60, + 0xeb, 0x0c, 0xe9, 0x02, 0x06, 0x25, 0x26, 0x05, + 0xe0, 0x01, 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66, + 0x27, 0x26, 0x36, 0x1b, 0x76, 0x06, 0xe0, 0x02, + 0x1b, 0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0, + 0x46, 0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00, + 0xe9, 0x02, 0x76, 0x05, 0x27, 0x05, 0xe0, 0x00, + 0xe5, 0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01, 0x26, + 0x07, 0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27, 0x65, + 0x76, 0x66, 0x16, 0x07, 0x06, 0xe9, 0x02, 0x05, + 0x16, 0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03, + 0xe5, 0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46, 0x27, + 0x06, 0x07, 0x26, 0xb6, 0x06, 0x25, 0x06, 0xe0, + 0x36, 0xc5, 0x00, 0x05, 0x00, 0x65, 0x00, 0xe5, + 0x07, 0x00, 0xe5, 0x02, 0x16, 0xa0, 0xe5, 0x27, + 0x06, 0x47, 0xe6, 0x00, 0x80, 0xe9, 0x02, 0xa0, + 0x26, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, 0x20, + 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x85, + 0x00, 0x26, 0x05, 0x27, 0x06, 0x67, 0x20, 0x27, + 0x20, 0x47, 0x20, 0x05, 0xa0, 0x07, 0x80, 0x85, + 0x27, 0x20, 0xc6, 0x40, 0x86, 0xe0, 0x80, 0x03, + 0xe5, 0x2d, 0x47, 0xe6, 0x00, 0x27, 0x46, 0x07, + 0x06, 0x65, 0x96, 0xe9, 0x02, 0x36, 0x00, 0x16, + 0x06, 0x45, 0xe0, 0x16, 0xe5, 0x28, 0x47, 0xa6, + 0x07, 0x06, 0x67, 0x26, 0x07, 0x26, 0x25, 0x16, + 0x05, 0xe0, 0x00, 0xe9, 0x02, 0xe0, 0x80, 0x1e, + 0xe5, 0x27, 0x47, 0x66, 0x20, 0x67, 0x26, 0x07, + 0x26, 0xf6, 0x0f, 0x65, 0x26, 0xe0, 0x1a, 0xe5, + 0x28, 0x47, 0xe6, 0x00, 0x27, 0x06, 0x07, 0x26, + 0x56, 0x05, 0xe0, 0x03, 0xe9, 0x02, 0xa0, 0xf6, + 0x05, 0xe0, 0x0b, 0xe5, 0x23, 0x06, 0x07, 0x06, + 0x27, 0xa6, 0x07, 0x06, 0x05, 0x16, 0xa0, 0xe9, + 0x02, 0xe0, 0x2e, 0xe5, 0x13, 0x20, 0x46, 0x27, + 0x66, 0x07, 0x86, 0x60, 0xe9, 0x02, 0x2b, 0x56, + 0x0f, 0xc5, 0xe0, 0x80, 0x31, 0xe5, 0x24, 0x47, + 0xe6, 0x01, 0x07, 0x26, 0x16, 0xe0, 0x5c, 0xe1, + 0x18, 0xe2, 0x18, 0xe9, 0x02, 0xeb, 0x01, 0xe0, + 0x04, 0xe5, 0x00, 0x20, 0x05, 0x20, 0xe5, 0x00, + 0x00, 0x25, 0x00, 0xe5, 0x10, 0xa7, 0x00, 0x27, + 0x20, 0x26, 0x07, 0x06, 0x05, 0x07, 0x05, 0x07, + 0x06, 0x56, 0xe0, 0x01, 0xe9, 0x02, 0xe0, 0x3e, + 0xe5, 0x00, 0x20, 0xe5, 0x1f, 0x47, 0x66, 0x20, + 0x26, 0x67, 0x06, 0x05, 0x16, 0x05, 0x07, 0xe0, + 0x13, 0x05, 0xe6, 0x02, 0xe5, 0x20, 0xa6, 0x07, + 0x05, 0x66, 0xf6, 0x00, 0x06, 0xe0, 0x00, 0x05, + 0xa6, 0x27, 0x46, 0xe5, 0x26, 0xe6, 0x05, 0x07, + 0x26, 0x56, 0x05, 0x96, 0xe0, 0x05, 0xe5, 0x41, + 0xc0, 0xf6, 0x02, 0xe0, 0x80, 0x6e, 0xe5, 0x01, + 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, 0x07, + 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, 0xeb, + 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, 0x0e, + 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26, 0xe0, + 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e, 0xa6, + 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05, 0x06, + 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00, 0x25, + 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00, 0x27, + 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02, 0xe0, + 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, 0xc0, + 0x26, 0x05, 0x07, 0xe5, 0x05, 0x00, 0xe5, 0x1a, + 0x27, 0x86, 0x40, 0x27, 0x06, 0x07, 0x06, 0xf6, + 0x05, 0xe9, 0x02, 0xe0, 0x4e, 0x05, 0xe0, 0x07, + 0xeb, 0x0d, 0xef, 0x00, 0x6d, 0xef, 0x09, 0xe0, + 0x05, 0x16, 0xe5, 0x83, 0x12, 0xe0, 0x5e, 0xea, + 0x67, 0x00, 0x96, 0xe0, 0x03, 0xe5, 0x80, 0x3c, + 0xe0, 0x89, 0xc4, 0xe5, 0x59, 0x36, 0xe0, 0x05, + 0xe5, 0x83, 0xa8, 0xfb, 0x08, 0x06, 0xa5, 0xe6, + 0x07, 0xe0, 0x8f, 0x22, 0xe5, 0x81, 0xbf, 0xe0, + 0xa1, 0x31, 0xe5, 0x81, 0xb1, 0xc0, 0xe5, 0x17, + 0x00, 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47, 0x00, + 0xe9, 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86, 0x16, + 0xe0, 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, 0x64, + 0x16, 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, 0xcb, + 0x00, 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, 0x82, + 0x28, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f, 0x76, + 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05, 0xe7, + 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38, 0x24, + 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0, 0x06, + 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84, 0x4e, + 0xe0, 0x22, 0xe5, 0x01, 0xe0, 0xa2, 0x5f, 0x64, + 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5, 0x80, 0x9b, + 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45, 0x20, 0x05, + 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04, + 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05, + 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f, + 0x26, 0x16, 0x7b, 0xe0, 0x91, 0xd4, 0xe6, 0x26, + 0x20, 0xe6, 0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0, + 0x34, 0xef, 0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f, + 0x20, 0xef, 0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb, + 0x00, 0xe6, 0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66, + 0xef, 0x35, 0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f, + 0xe0, 0x72, 0xeb, 0x0c, 0xe0, 0x04, 0xeb, 0x0c, + 0xe0, 0x04, 0xef, 0x4f, 0xe0, 0x01, 0xeb, 0x11, + 0xe0, 0x7f, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, + 0xc2, 0x00, 0xe2, 0x0a, 0xe1, 0x12, 0xe2, 0x12, + 0x01, 0x00, 0x21, 0x20, 0x01, 0x20, 0x21, 0x20, + 0x61, 0x00, 0xe1, 0x00, 0x62, 0x00, 0x02, 0x00, + 0xc2, 0x00, 0xe2, 0x03, 0xe1, 0x12, 0xe2, 0x12, + 0x21, 0x00, 0x61, 0x20, 0xe1, 0x00, 0x00, 0xc1, + 0x00, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x00, 0x81, + 0x00, 0x01, 0x40, 0xc1, 0x00, 0xe2, 0x12, 0xe1, + 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, + 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, + 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x14, 0x20, + 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, + 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, + 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, + 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, + 0x11, 0x0c, 0xa2, 0x3f, 0x20, 0xe9, 0x2a, 0xef, + 0x81, 0x78, 0xe6, 0x2f, 0x6f, 0xe6, 0x2a, 0xef, + 0x00, 0x06, 0xef, 0x06, 0x06, 0x2f, 0x96, 0xe0, + 0x07, 0x86, 0x00, 0xe6, 0x07, 0xe0, 0x83, 0xc8, + 0xe2, 0x02, 0x05, 0xe2, 0x0c, 0xa0, 0xa2, 0xe0, + 0x80, 0x4d, 0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6, + 0x00, 0x26, 0x00, 0x86, 0x80, 0xe4, 0x36, 0xe0, + 0x19, 0x06, 0xe0, 0x68, 0xe5, 0x25, 0x40, 0xc6, + 0xc4, 0x20, 0xe9, 0x02, 0x60, 0x05, 0x0f, 0xe0, + 0x80, 0xb8, 0xe5, 0x16, 0x06, 0xe0, 0x09, 0xe5, + 0x24, 0x66, 0xe9, 0x02, 0x80, 0x0d, 0xe0, 0x81, + 0x48, 0xe5, 0x13, 0x04, 0x66, 0xe9, 0x02, 0xe0, + 0x82, 0x5e, 0xc5, 0x00, 0x65, 0x00, 0x25, 0x00, + 0xe5, 0x07, 0x00, 0xe5, 0x80, 0x3d, 0x20, 0xeb, + 0x01, 0xc6, 0xe0, 0x21, 0xe1, 0x1a, 0xe2, 0x1a, + 0xc6, 0x04, 0x60, 0xe9, 0x02, 0x60, 0x36, 0xe0, + 0x82, 0x89, 0xeb, 0x33, 0x0f, 0x4b, 0x0d, 0x6b, + 0xe0, 0x44, 0xeb, 0x25, 0x0f, 0xeb, 0x07, 0xe0, + 0x80, 0x3a, 0x65, 0x00, 0xe5, 0x13, 0x00, 0x25, + 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5, 0x02, 0x00, + 0x65, 0x00, 0x05, 0x00, 0x05, 0xa0, 0x05, 0x60, + 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x45, 0x00, + 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, 0x05, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x25, 0x00, + 0x05, 0x20, 0x65, 0x00, 0xc5, 0x00, 0x65, 0x00, + 0x65, 0x00, 0x05, 0x00, 0xe5, 0x02, 0x00, 0xe5, + 0x09, 0x80, 0x45, 0x00, 0x85, 0x00, 0xe5, 0x09, + 0xe0, 0x2c, 0x2c, 0xe0, 0x80, 0x86, 0xef, 0x24, + 0x60, 0xef, 0x5c, 0xe0, 0x04, 0xef, 0x07, 0x20, + 0xef, 0x07, 0x00, 0xef, 0x07, 0x00, 0xef, 0x1d, + 0xe0, 0x02, 0xeb, 0x05, 0xef, 0x80, 0x19, 0xe0, + 0x30, 0xef, 0x15, 0xe0, 0x05, 0xef, 0x24, 0x60, + 0xef, 0x01, 0xc0, 0x2f, 0xe0, 0x06, 0xaf, 0xe0, + 0x80, 0x12, 0xef, 0x80, 0x73, 0x8e, 0xef, 0x82, + 0x50, 0x60, 0xef, 0x09, 0x40, 0xef, 0x05, 0x40, + 0xef, 0x6f, 0x60, 0xef, 0x57, 0xa0, 0xef, 0x04, + 0x60, 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, 0xef, + 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, 0x20, + 0xe0, 0x00, 0xef, 0x16, 0x20, 0x2f, 0xe0, 0x46, + 0xef, 0x80, 0xcc, 0xe0, 0x04, 0xef, 0x06, 0x20, + 0xef, 0x05, 0x40, 0xef, 0x01, 0xc0, 0xef, 0x26, + 0x00, 0xcf, 0xe0, 0x00, 0xef, 0x06, 0x60, 0xef, + 0x01, 0xc0, 0xef, 0x01, 0xc0, 0xef, 0x80, 0x0b, + 0x00, 0xef, 0x2f, 0xe0, 0x1d, 0xe9, 0x02, 0xe0, + 0x83, 0x7e, 0xe5, 0xc0, 0x66, 0x58, 0xe0, 0x18, + 0xe5, 0x8f, 0xb2, 0xa0, 0xe5, 0x80, 0x56, 0x20, + 0xe5, 0x95, 0xfa, 0xe0, 0x06, 0xe5, 0x9c, 0xa9, + 0xe0, 0x8b, 0x97, 0xe5, 0x81, 0x96, 0xe0, 0x85, + 0x5a, 0xe5, 0x92, 0xc3, 0x80, 0xe5, 0x8f, 0xd8, + 0xe0, 0xca, 0x9b, 0xc9, 0x1b, 0xe0, 0x16, 0xfb, + 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68, 0xe0, 0xc0, + 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76, 0x20, 0xfd, + 0xc0, 0xbf, 0x76, 0x20, +}; + +typedef enum { + UNICODE_SCRIPT_Unknown, + UNICODE_SCRIPT_Adlam, + UNICODE_SCRIPT_Ahom, + UNICODE_SCRIPT_Anatolian_Hieroglyphs, + UNICODE_SCRIPT_Arabic, + UNICODE_SCRIPT_Armenian, + UNICODE_SCRIPT_Avestan, + UNICODE_SCRIPT_Balinese, + UNICODE_SCRIPT_Bamum, + UNICODE_SCRIPT_Bassa_Vah, + UNICODE_SCRIPT_Batak, + UNICODE_SCRIPT_Bengali, + UNICODE_SCRIPT_Bhaiksuki, + UNICODE_SCRIPT_Bopomofo, + UNICODE_SCRIPT_Brahmi, + UNICODE_SCRIPT_Braille, + UNICODE_SCRIPT_Buginese, + UNICODE_SCRIPT_Buhid, + UNICODE_SCRIPT_Canadian_Aboriginal, + UNICODE_SCRIPT_Carian, + UNICODE_SCRIPT_Caucasian_Albanian, + UNICODE_SCRIPT_Chakma, + UNICODE_SCRIPT_Cham, + UNICODE_SCRIPT_Cherokee, + UNICODE_SCRIPT_Chorasmian, + UNICODE_SCRIPT_Common, + UNICODE_SCRIPT_Coptic, + UNICODE_SCRIPT_Cuneiform, + UNICODE_SCRIPT_Cypriot, + UNICODE_SCRIPT_Cyrillic, + UNICODE_SCRIPT_Cypro_Minoan, + UNICODE_SCRIPT_Deseret, + UNICODE_SCRIPT_Devanagari, + UNICODE_SCRIPT_Dives_Akuru, + UNICODE_SCRIPT_Dogra, + UNICODE_SCRIPT_Duployan, + UNICODE_SCRIPT_Egyptian_Hieroglyphs, + UNICODE_SCRIPT_Elbasan, + UNICODE_SCRIPT_Elymaic, + UNICODE_SCRIPT_Ethiopic, + UNICODE_SCRIPT_Georgian, + UNICODE_SCRIPT_Glagolitic, + UNICODE_SCRIPT_Gothic, + UNICODE_SCRIPT_Grantha, + UNICODE_SCRIPT_Greek, + UNICODE_SCRIPT_Gujarati, + UNICODE_SCRIPT_Gunjala_Gondi, + UNICODE_SCRIPT_Gurmukhi, + UNICODE_SCRIPT_Han, + UNICODE_SCRIPT_Hangul, + UNICODE_SCRIPT_Hanifi_Rohingya, + UNICODE_SCRIPT_Hanunoo, + UNICODE_SCRIPT_Hatran, + UNICODE_SCRIPT_Hebrew, + UNICODE_SCRIPT_Hiragana, + UNICODE_SCRIPT_Imperial_Aramaic, + UNICODE_SCRIPT_Inherited, + UNICODE_SCRIPT_Inscriptional_Pahlavi, + UNICODE_SCRIPT_Inscriptional_Parthian, + UNICODE_SCRIPT_Javanese, + UNICODE_SCRIPT_Kaithi, + UNICODE_SCRIPT_Kannada, + UNICODE_SCRIPT_Katakana, + UNICODE_SCRIPT_Kawi, + UNICODE_SCRIPT_Kayah_Li, + UNICODE_SCRIPT_Kharoshthi, + UNICODE_SCRIPT_Khmer, + UNICODE_SCRIPT_Khojki, + UNICODE_SCRIPT_Khitan_Small_Script, + UNICODE_SCRIPT_Khudawadi, + UNICODE_SCRIPT_Lao, + UNICODE_SCRIPT_Latin, + UNICODE_SCRIPT_Lepcha, + UNICODE_SCRIPT_Limbu, + UNICODE_SCRIPT_Linear_A, + UNICODE_SCRIPT_Linear_B, + UNICODE_SCRIPT_Lisu, + UNICODE_SCRIPT_Lycian, + UNICODE_SCRIPT_Lydian, + UNICODE_SCRIPT_Makasar, + UNICODE_SCRIPT_Mahajani, + UNICODE_SCRIPT_Malayalam, + UNICODE_SCRIPT_Mandaic, + UNICODE_SCRIPT_Manichaean, + UNICODE_SCRIPT_Marchen, + UNICODE_SCRIPT_Masaram_Gondi, + UNICODE_SCRIPT_Medefaidrin, + UNICODE_SCRIPT_Meetei_Mayek, + UNICODE_SCRIPT_Mende_Kikakui, + UNICODE_SCRIPT_Meroitic_Cursive, + UNICODE_SCRIPT_Meroitic_Hieroglyphs, + UNICODE_SCRIPT_Miao, + UNICODE_SCRIPT_Modi, + UNICODE_SCRIPT_Mongolian, + UNICODE_SCRIPT_Mro, + UNICODE_SCRIPT_Multani, + UNICODE_SCRIPT_Myanmar, + UNICODE_SCRIPT_Nabataean, + UNICODE_SCRIPT_Nag_Mundari, + UNICODE_SCRIPT_Nandinagari, + UNICODE_SCRIPT_New_Tai_Lue, + UNICODE_SCRIPT_Newa, + UNICODE_SCRIPT_Nko, + UNICODE_SCRIPT_Nushu, + UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong, + UNICODE_SCRIPT_Ogham, + UNICODE_SCRIPT_Ol_Chiki, + UNICODE_SCRIPT_Old_Hungarian, + UNICODE_SCRIPT_Old_Italic, + UNICODE_SCRIPT_Old_North_Arabian, + UNICODE_SCRIPT_Old_Permic, + UNICODE_SCRIPT_Old_Persian, + UNICODE_SCRIPT_Old_Sogdian, + UNICODE_SCRIPT_Old_South_Arabian, + UNICODE_SCRIPT_Old_Turkic, + UNICODE_SCRIPT_Old_Uyghur, + UNICODE_SCRIPT_Oriya, + UNICODE_SCRIPT_Osage, + UNICODE_SCRIPT_Osmanya, + UNICODE_SCRIPT_Pahawh_Hmong, + UNICODE_SCRIPT_Palmyrene, + UNICODE_SCRIPT_Pau_Cin_Hau, + UNICODE_SCRIPT_Phags_Pa, + UNICODE_SCRIPT_Phoenician, + UNICODE_SCRIPT_Psalter_Pahlavi, + UNICODE_SCRIPT_Rejang, + UNICODE_SCRIPT_Runic, + UNICODE_SCRIPT_Samaritan, + UNICODE_SCRIPT_Saurashtra, + UNICODE_SCRIPT_Sharada, + UNICODE_SCRIPT_Shavian, + UNICODE_SCRIPT_Siddham, + UNICODE_SCRIPT_SignWriting, + UNICODE_SCRIPT_Sinhala, + UNICODE_SCRIPT_Sogdian, + UNICODE_SCRIPT_Sora_Sompeng, + UNICODE_SCRIPT_Soyombo, + UNICODE_SCRIPT_Sundanese, + UNICODE_SCRIPT_Syloti_Nagri, + UNICODE_SCRIPT_Syriac, + UNICODE_SCRIPT_Tagalog, + UNICODE_SCRIPT_Tagbanwa, + UNICODE_SCRIPT_Tai_Le, + UNICODE_SCRIPT_Tai_Tham, + UNICODE_SCRIPT_Tai_Viet, + UNICODE_SCRIPT_Takri, + UNICODE_SCRIPT_Tamil, + UNICODE_SCRIPT_Tangut, + UNICODE_SCRIPT_Telugu, + UNICODE_SCRIPT_Thaana, + UNICODE_SCRIPT_Thai, + UNICODE_SCRIPT_Tibetan, + UNICODE_SCRIPT_Tifinagh, + UNICODE_SCRIPT_Tirhuta, + UNICODE_SCRIPT_Tangsa, + UNICODE_SCRIPT_Toto, + UNICODE_SCRIPT_Ugaritic, + UNICODE_SCRIPT_Vai, + UNICODE_SCRIPT_Vithkuqi, + UNICODE_SCRIPT_Wancho, + UNICODE_SCRIPT_Warang_Citi, + UNICODE_SCRIPT_Yezidi, + UNICODE_SCRIPT_Yi, + UNICODE_SCRIPT_Zanabazar_Square, + UNICODE_SCRIPT_COUNT, +} UnicodeScriptEnum; + +static const char unicode_script_name_table[] = + "Adlam,Adlm" "\0" + "Ahom,Ahom" "\0" + "Anatolian_Hieroglyphs,Hluw" "\0" + "Arabic,Arab" "\0" + "Armenian,Armn" "\0" + "Avestan,Avst" "\0" + "Balinese,Bali" "\0" + "Bamum,Bamu" "\0" + "Bassa_Vah,Bass" "\0" + "Batak,Batk" "\0" + "Bengali,Beng" "\0" + "Bhaiksuki,Bhks" "\0" + "Bopomofo,Bopo" "\0" + "Brahmi,Brah" "\0" + "Braille,Brai" "\0" + "Buginese,Bugi" "\0" + "Buhid,Buhd" "\0" + "Canadian_Aboriginal,Cans" "\0" + "Carian,Cari" "\0" + "Caucasian_Albanian,Aghb" "\0" + "Chakma,Cakm" "\0" + "Cham,Cham" "\0" + "Cherokee,Cher" "\0" + "Chorasmian,Chrs" "\0" + "Common,Zyyy" "\0" + "Coptic,Copt,Qaac" "\0" + "Cuneiform,Xsux" "\0" + "Cypriot,Cprt" "\0" + "Cyrillic,Cyrl" "\0" + "Cypro_Minoan,Cpmn" "\0" + "Deseret,Dsrt" "\0" + "Devanagari,Deva" "\0" + "Dives_Akuru,Diak" "\0" + "Dogra,Dogr" "\0" + "Duployan,Dupl" "\0" + "Egyptian_Hieroglyphs,Egyp" "\0" + "Elbasan,Elba" "\0" + "Elymaic,Elym" "\0" + "Ethiopic,Ethi" "\0" + "Georgian,Geor" "\0" + "Glagolitic,Glag" "\0" + "Gothic,Goth" "\0" + "Grantha,Gran" "\0" + "Greek,Grek" "\0" + "Gujarati,Gujr" "\0" + "Gunjala_Gondi,Gong" "\0" + "Gurmukhi,Guru" "\0" + "Han,Hani" "\0" + "Hangul,Hang" "\0" + "Hanifi_Rohingya,Rohg" "\0" + "Hanunoo,Hano" "\0" + "Hatran,Hatr" "\0" + "Hebrew,Hebr" "\0" + "Hiragana,Hira" "\0" + "Imperial_Aramaic,Armi" "\0" + "Inherited,Zinh,Qaai" "\0" + "Inscriptional_Pahlavi,Phli" "\0" + "Inscriptional_Parthian,Prti" "\0" + "Javanese,Java" "\0" + "Kaithi,Kthi" "\0" + "Kannada,Knda" "\0" + "Katakana,Kana" "\0" + "Kawi,Kawi" "\0" + "Kayah_Li,Kali" "\0" + "Kharoshthi,Khar" "\0" + "Khmer,Khmr" "\0" + "Khojki,Khoj" "\0" + "Khitan_Small_Script,Kits" "\0" + "Khudawadi,Sind" "\0" + "Lao,Laoo" "\0" + "Latin,Latn" "\0" + "Lepcha,Lepc" "\0" + "Limbu,Limb" "\0" + "Linear_A,Lina" "\0" + "Linear_B,Linb" "\0" + "Lisu,Lisu" "\0" + "Lycian,Lyci" "\0" + "Lydian,Lydi" "\0" + "Makasar,Maka" "\0" + "Mahajani,Mahj" "\0" + "Malayalam,Mlym" "\0" + "Mandaic,Mand" "\0" + "Manichaean,Mani" "\0" + "Marchen,Marc" "\0" + "Masaram_Gondi,Gonm" "\0" + "Medefaidrin,Medf" "\0" + "Meetei_Mayek,Mtei" "\0" + "Mende_Kikakui,Mend" "\0" + "Meroitic_Cursive,Merc" "\0" + "Meroitic_Hieroglyphs,Mero" "\0" + "Miao,Plrd" "\0" + "Modi,Modi" "\0" + "Mongolian,Mong" "\0" + "Mro,Mroo" "\0" + "Multani,Mult" "\0" + "Myanmar,Mymr" "\0" + "Nabataean,Nbat" "\0" + "Nag_Mundari,Nagm" "\0" + "Nandinagari,Nand" "\0" + "New_Tai_Lue,Talu" "\0" + "Newa,Newa" "\0" + "Nko,Nkoo" "\0" + "Nushu,Nshu" "\0" + "Nyiakeng_Puachue_Hmong,Hmnp" "\0" + "Ogham,Ogam" "\0" + "Ol_Chiki,Olck" "\0" + "Old_Hungarian,Hung" "\0" + "Old_Italic,Ital" "\0" + "Old_North_Arabian,Narb" "\0" + "Old_Permic,Perm" "\0" + "Old_Persian,Xpeo" "\0" + "Old_Sogdian,Sogo" "\0" + "Old_South_Arabian,Sarb" "\0" + "Old_Turkic,Orkh" "\0" + "Old_Uyghur,Ougr" "\0" + "Oriya,Orya" "\0" + "Osage,Osge" "\0" + "Osmanya,Osma" "\0" + "Pahawh_Hmong,Hmng" "\0" + "Palmyrene,Palm" "\0" + "Pau_Cin_Hau,Pauc" "\0" + "Phags_Pa,Phag" "\0" + "Phoenician,Phnx" "\0" + "Psalter_Pahlavi,Phlp" "\0" + "Rejang,Rjng" "\0" + "Runic,Runr" "\0" + "Samaritan,Samr" "\0" + "Saurashtra,Saur" "\0" + "Sharada,Shrd" "\0" + "Shavian,Shaw" "\0" + "Siddham,Sidd" "\0" + "SignWriting,Sgnw" "\0" + "Sinhala,Sinh" "\0" + "Sogdian,Sogd" "\0" + "Sora_Sompeng,Sora" "\0" + "Soyombo,Soyo" "\0" + "Sundanese,Sund" "\0" + "Syloti_Nagri,Sylo" "\0" + "Syriac,Syrc" "\0" + "Tagalog,Tglg" "\0" + "Tagbanwa,Tagb" "\0" + "Tai_Le,Tale" "\0" + "Tai_Tham,Lana" "\0" + "Tai_Viet,Tavt" "\0" + "Takri,Takr" "\0" + "Tamil,Taml" "\0" + "Tangut,Tang" "\0" + "Telugu,Telu" "\0" + "Thaana,Thaa" "\0" + "Thai,Thai" "\0" + "Tibetan,Tibt" "\0" + "Tifinagh,Tfng" "\0" + "Tirhuta,Tirh" "\0" + "Tangsa,Tnsa" "\0" + "Toto,Toto" "\0" + "Ugaritic,Ugar" "\0" + "Vai,Vaii" "\0" + "Vithkuqi,Vith" "\0" + "Wancho,Wcho" "\0" + "Warang_Citi,Wara" "\0" + "Yezidi,Yezi" "\0" + "Yi,Yiii" "\0" + "Zanabazar_Square,Zanb" "\0" +; + +static const uint8_t unicode_script_table[2720] = { + 0xc0, 0x19, 0x99, 0x47, 0x85, 0x19, 0x99, 0x47, + 0xae, 0x19, 0x80, 0x47, 0x8e, 0x19, 0x80, 0x47, + 0x84, 0x19, 0x96, 0x47, 0x80, 0x19, 0x9e, 0x47, + 0x80, 0x19, 0xe1, 0x60, 0x47, 0xa6, 0x19, 0x84, + 0x47, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0, + 0x0f, 0x38, 0x83, 0x2c, 0x80, 0x19, 0x82, 0x2c, + 0x01, 0x83, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x03, + 0x80, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x80, 0x19, + 0x82, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x93, 0x2c, + 0x00, 0xbe, 0x2c, 0x8d, 0x1a, 0x8f, 0x2c, 0xe0, + 0x24, 0x1d, 0x81, 0x38, 0xe0, 0x48, 0x1d, 0x00, + 0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05, + 0x00, 0xb6, 0x35, 0x07, 0x9a, 0x35, 0x03, 0x85, + 0x35, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04, + 0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x82, 0x04, + 0x80, 0x19, 0x9f, 0x04, 0x80, 0x19, 0x89, 0x04, + 0x8a, 0x38, 0x99, 0x04, 0x80, 0x38, 0xe0, 0x0b, + 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x8b, 0x00, + 0xbb, 0x8b, 0x01, 0x82, 0x8b, 0xaf, 0x04, 0xb1, + 0x95, 0x0d, 0xba, 0x66, 0x01, 0x82, 0x66, 0xad, + 0x7f, 0x01, 0x8e, 0x7f, 0x00, 0x9b, 0x52, 0x01, + 0x80, 0x52, 0x00, 0x8a, 0x8b, 0x04, 0x9e, 0x04, + 0x00, 0x81, 0x04, 0x05, 0xc9, 0x04, 0x80, 0x19, + 0x9c, 0x04, 0xd0, 0x20, 0x83, 0x38, 0x8e, 0x20, + 0x81, 0x19, 0x99, 0x20, 0x83, 0x0b, 0x00, 0x87, + 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x95, 0x0b, 0x00, + 0x86, 0x0b, 0x00, 0x80, 0x0b, 0x02, 0x83, 0x0b, + 0x01, 0x88, 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x83, + 0x0b, 0x07, 0x80, 0x0b, 0x03, 0x81, 0x0b, 0x00, + 0x84, 0x0b, 0x01, 0x98, 0x0b, 0x01, 0x82, 0x2f, + 0x00, 0x85, 0x2f, 0x03, 0x81, 0x2f, 0x01, 0x95, + 0x2f, 0x00, 0x86, 0x2f, 0x00, 0x81, 0x2f, 0x00, + 0x81, 0x2f, 0x00, 0x81, 0x2f, 0x01, 0x80, 0x2f, + 0x00, 0x84, 0x2f, 0x03, 0x81, 0x2f, 0x01, 0x82, + 0x2f, 0x02, 0x80, 0x2f, 0x06, 0x83, 0x2f, 0x00, + 0x80, 0x2f, 0x06, 0x90, 0x2f, 0x09, 0x82, 0x2d, + 0x00, 0x88, 0x2d, 0x00, 0x82, 0x2d, 0x00, 0x95, + 0x2d, 0x00, 0x86, 0x2d, 0x00, 0x81, 0x2d, 0x00, + 0x84, 0x2d, 0x01, 0x89, 0x2d, 0x00, 0x82, 0x2d, + 0x00, 0x82, 0x2d, 0x01, 0x80, 0x2d, 0x0e, 0x83, + 0x2d, 0x01, 0x8b, 0x2d, 0x06, 0x86, 0x2d, 0x00, + 0x82, 0x74, 0x00, 0x87, 0x74, 0x01, 0x81, 0x74, + 0x01, 0x95, 0x74, 0x00, 0x86, 0x74, 0x00, 0x81, + 0x74, 0x00, 0x84, 0x74, 0x01, 0x88, 0x74, 0x01, + 0x81, 0x74, 0x01, 0x82, 0x74, 0x06, 0x82, 0x74, + 0x03, 0x81, 0x74, 0x00, 0x84, 0x74, 0x01, 0x91, + 0x74, 0x09, 0x81, 0x92, 0x00, 0x85, 0x92, 0x02, + 0x82, 0x92, 0x00, 0x83, 0x92, 0x02, 0x81, 0x92, + 0x00, 0x80, 0x92, 0x00, 0x81, 0x92, 0x02, 0x81, + 0x92, 0x02, 0x82, 0x92, 0x02, 0x8b, 0x92, 0x03, + 0x84, 0x92, 0x02, 0x82, 0x92, 0x00, 0x83, 0x92, + 0x01, 0x80, 0x92, 0x05, 0x80, 0x92, 0x0d, 0x94, + 0x92, 0x04, 0x8c, 0x94, 0x00, 0x82, 0x94, 0x00, + 0x96, 0x94, 0x00, 0x8f, 0x94, 0x01, 0x88, 0x94, + 0x00, 0x82, 0x94, 0x00, 0x83, 0x94, 0x06, 0x81, + 0x94, 0x00, 0x82, 0x94, 0x01, 0x80, 0x94, 0x01, + 0x83, 0x94, 0x01, 0x89, 0x94, 0x06, 0x88, 0x94, + 0x8c, 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x96, 0x3d, + 0x00, 0x89, 0x3d, 0x00, 0x84, 0x3d, 0x01, 0x88, + 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x83, 0x3d, 0x06, + 0x81, 0x3d, 0x05, 0x81, 0x3d, 0x00, 0x83, 0x3d, + 0x01, 0x89, 0x3d, 0x00, 0x82, 0x3d, 0x0b, 0x8c, + 0x51, 0x00, 0x82, 0x51, 0x00, 0xb2, 0x51, 0x00, + 0x82, 0x51, 0x00, 0x85, 0x51, 0x03, 0x8f, 0x51, + 0x01, 0x99, 0x51, 0x00, 0x82, 0x85, 0x00, 0x91, + 0x85, 0x02, 0x97, 0x85, 0x00, 0x88, 0x85, 0x00, + 0x80, 0x85, 0x01, 0x86, 0x85, 0x02, 0x80, 0x85, + 0x03, 0x85, 0x85, 0x00, 0x80, 0x85, 0x00, 0x87, + 0x85, 0x05, 0x89, 0x85, 0x01, 0x82, 0x85, 0x0b, + 0xb9, 0x96, 0x03, 0x80, 0x19, 0x9b, 0x96, 0x24, + 0x81, 0x46, 0x00, 0x80, 0x46, 0x00, 0x84, 0x46, + 0x00, 0x97, 0x46, 0x00, 0x80, 0x46, 0x00, 0x96, + 0x46, 0x01, 0x84, 0x46, 0x00, 0x80, 0x46, 0x00, + 0x86, 0x46, 0x00, 0x89, 0x46, 0x01, 0x83, 0x46, + 0x1f, 0xc7, 0x97, 0x00, 0xa3, 0x97, 0x03, 0xa6, + 0x97, 0x00, 0xa3, 0x97, 0x00, 0x8e, 0x97, 0x00, + 0x86, 0x97, 0x83, 0x19, 0x81, 0x97, 0x24, 0xe0, + 0x3f, 0x60, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, + 0x80, 0x28, 0x01, 0xaa, 0x28, 0x80, 0x19, 0x83, + 0x28, 0xe0, 0x9f, 0x31, 0xc8, 0x27, 0x00, 0x83, + 0x27, 0x01, 0x86, 0x27, 0x00, 0x80, 0x27, 0x00, + 0x83, 0x27, 0x01, 0xa8, 0x27, 0x00, 0x83, 0x27, + 0x01, 0xa0, 0x27, 0x00, 0x83, 0x27, 0x01, 0x86, + 0x27, 0x00, 0x80, 0x27, 0x00, 0x83, 0x27, 0x01, + 0x8e, 0x27, 0x00, 0xb8, 0x27, 0x00, 0x83, 0x27, + 0x01, 0xc2, 0x27, 0x01, 0x9f, 0x27, 0x02, 0x99, + 0x27, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01, + 0xe2, 0x1f, 0x12, 0x9c, 0x69, 0x02, 0xca, 0x7e, + 0x82, 0x19, 0x8a, 0x7e, 0x06, 0x95, 0x8c, 0x08, + 0x80, 0x8c, 0x94, 0x33, 0x81, 0x19, 0x08, 0x93, + 0x11, 0x0b, 0x8c, 0x8d, 0x00, 0x82, 0x8d, 0x00, + 0x81, 0x8d, 0x0b, 0xdd, 0x42, 0x01, 0x89, 0x42, + 0x05, 0x89, 0x42, 0x05, 0x81, 0x5d, 0x81, 0x19, + 0x80, 0x5d, 0x80, 0x19, 0x93, 0x5d, 0x05, 0xd8, + 0x5d, 0x06, 0xaa, 0x5d, 0x04, 0xc5, 0x12, 0x09, + 0x9e, 0x49, 0x00, 0x8b, 0x49, 0x03, 0x8b, 0x49, + 0x03, 0x80, 0x49, 0x02, 0x8b, 0x49, 0x9d, 0x8e, + 0x01, 0x84, 0x8e, 0x0a, 0xab, 0x64, 0x03, 0x99, + 0x64, 0x05, 0x8a, 0x64, 0x02, 0x81, 0x64, 0x9f, + 0x42, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x8f, + 0x00, 0x9c, 0x8f, 0x01, 0x8a, 0x8f, 0x05, 0x89, + 0x8f, 0x05, 0x8d, 0x8f, 0x01, 0x9e, 0x38, 0x30, + 0xcc, 0x07, 0x02, 0xae, 0x07, 0x00, 0xbf, 0x89, + 0xb3, 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x48, 0x02, + 0x8e, 0x48, 0x02, 0x82, 0x48, 0xaf, 0x6a, 0x88, + 0x1d, 0x06, 0xaa, 0x28, 0x01, 0x82, 0x28, 0x87, + 0x89, 0x07, 0x82, 0x38, 0x80, 0x19, 0x8c, 0x38, + 0x80, 0x19, 0x86, 0x38, 0x83, 0x19, 0x80, 0x38, + 0x85, 0x19, 0x80, 0x38, 0x82, 0x19, 0x81, 0x38, + 0x80, 0x19, 0x04, 0xa5, 0x47, 0x84, 0x2c, 0x80, + 0x1d, 0xb0, 0x47, 0x84, 0x2c, 0x83, 0x47, 0x84, + 0x2c, 0x8c, 0x47, 0x80, 0x1d, 0xc5, 0x47, 0x80, + 0x2c, 0xbf, 0x38, 0xe0, 0x9f, 0x47, 0x95, 0x2c, + 0x01, 0x85, 0x2c, 0x01, 0xa5, 0x2c, 0x01, 0x85, + 0x2c, 0x01, 0x87, 0x2c, 0x00, 0x80, 0x2c, 0x00, + 0x80, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x9e, 0x2c, + 0x01, 0xb4, 0x2c, 0x00, 0x8e, 0x2c, 0x00, 0x8d, + 0x2c, 0x01, 0x85, 0x2c, 0x00, 0x92, 0x2c, 0x01, + 0x82, 0x2c, 0x00, 0x88, 0x2c, 0x00, 0x8b, 0x19, + 0x81, 0x38, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, + 0x47, 0x01, 0x8a, 0x19, 0x80, 0x47, 0x8e, 0x19, + 0x00, 0x8c, 0x47, 0x02, 0xa0, 0x19, 0x0e, 0xa0, + 0x38, 0x0e, 0xa5, 0x19, 0x80, 0x2c, 0x82, 0x19, + 0x81, 0x47, 0x85, 0x19, 0x80, 0x47, 0x9a, 0x19, + 0x80, 0x47, 0x90, 0x19, 0xa8, 0x47, 0x82, 0x19, + 0x03, 0xe2, 0x36, 0x19, 0x18, 0x8a, 0x19, 0x14, + 0xe3, 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, + 0x19, 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, + 0xdf, 0x29, 0x9f, 0x47, 0xe0, 0x13, 0x1a, 0x04, + 0x86, 0x1a, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, + 0x80, 0x28, 0x01, 0xb7, 0x98, 0x06, 0x81, 0x98, + 0x0d, 0x80, 0x98, 0x96, 0x27, 0x08, 0x86, 0x27, + 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, + 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, + 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d, + 0xdd, 0x19, 0x21, 0x99, 0x30, 0x00, 0xd8, 0x30, + 0x0b, 0xe0, 0x75, 0x30, 0x19, 0x8b, 0x19, 0x03, + 0x84, 0x19, 0x80, 0x30, 0x80, 0x19, 0x80, 0x30, + 0x98, 0x19, 0x88, 0x30, 0x83, 0x38, 0x81, 0x31, + 0x87, 0x19, 0x83, 0x30, 0x83, 0x19, 0x00, 0xd5, + 0x36, 0x01, 0x81, 0x38, 0x81, 0x19, 0x82, 0x36, + 0x80, 0x19, 0xd9, 0x3e, 0x81, 0x19, 0x82, 0x3e, + 0x04, 0xaa, 0x0d, 0x00, 0xdd, 0x31, 0x00, 0x8f, + 0x19, 0x9f, 0x0d, 0xa3, 0x19, 0x0b, 0x8f, 0x3e, + 0x9e, 0x31, 0x00, 0xbf, 0x19, 0x9e, 0x31, 0xd0, + 0x19, 0xae, 0x3e, 0x80, 0x19, 0xd7, 0x3e, 0xe0, + 0x47, 0x19, 0xf0, 0x09, 0x5f, 0x30, 0xbf, 0x19, + 0xf0, 0x41, 0x9f, 0x30, 0xe4, 0x2c, 0xa2, 0x02, + 0xb6, 0xa2, 0x08, 0xaf, 0x4c, 0xe0, 0xcb, 0x9d, + 0x13, 0xdf, 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19, + 0xe0, 0x05, 0x47, 0x82, 0x19, 0xbf, 0x47, 0x04, + 0x81, 0x47, 0x00, 0x80, 0x47, 0x00, 0x84, 0x47, + 0x17, 0x8d, 0x47, 0xac, 0x8a, 0x02, 0x89, 0x19, + 0x05, 0xb7, 0x7a, 0x07, 0xc5, 0x80, 0x07, 0x8b, + 0x80, 0x05, 0x9f, 0x20, 0xad, 0x40, 0x80, 0x19, + 0x80, 0x40, 0xa3, 0x7d, 0x0a, 0x80, 0x7d, 0x9c, + 0x31, 0x02, 0xcd, 0x3b, 0x00, 0x80, 0x19, 0x89, + 0x3b, 0x03, 0x81, 0x3b, 0x9e, 0x60, 0x00, 0xb6, + 0x16, 0x08, 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, + 0x83, 0x16, 0x9f, 0x60, 0xc2, 0x90, 0x17, 0x84, + 0x90, 0x96, 0x57, 0x09, 0x85, 0x27, 0x01, 0x85, + 0x27, 0x01, 0x85, 0x27, 0x08, 0x86, 0x27, 0x00, + 0x86, 0x27, 0x00, 0xaa, 0x47, 0x80, 0x19, 0x88, + 0x47, 0x80, 0x2c, 0x83, 0x47, 0x81, 0x19, 0x03, + 0xcf, 0x17, 0xad, 0x57, 0x01, 0x89, 0x57, 0x05, + 0xf0, 0x1b, 0x43, 0x31, 0x0b, 0x96, 0x31, 0x03, + 0xb0, 0x31, 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x30, + 0x01, 0xe0, 0x09, 0x30, 0x25, 0x86, 0x47, 0x0b, + 0x84, 0x05, 0x04, 0x99, 0x35, 0x00, 0x84, 0x35, + 0x00, 0x80, 0x35, 0x00, 0x81, 0x35, 0x00, 0x81, + 0x35, 0x00, 0x89, 0x35, 0xe0, 0x12, 0x04, 0x0f, + 0xe1, 0x0a, 0x04, 0x81, 0x19, 0xcf, 0x04, 0x01, + 0xb5, 0x04, 0x06, 0x80, 0x04, 0x1f, 0x8f, 0x04, + 0x8f, 0x38, 0x89, 0x19, 0x05, 0x8d, 0x38, 0x81, + 0x1d, 0xa2, 0x19, 0x00, 0x92, 0x19, 0x00, 0x83, + 0x19, 0x03, 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04, + 0x01, 0x80, 0x19, 0x00, 0x9f, 0x19, 0x99, 0x47, + 0x85, 0x19, 0x99, 0x47, 0x8a, 0x19, 0x89, 0x3e, + 0x80, 0x19, 0xac, 0x3e, 0x81, 0x19, 0x9e, 0x31, + 0x02, 0x85, 0x31, 0x01, 0x85, 0x31, 0x01, 0x85, + 0x31, 0x01, 0x82, 0x31, 0x02, 0x86, 0x19, 0x00, + 0x86, 0x19, 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4b, + 0x00, 0x99, 0x4b, 0x00, 0x92, 0x4b, 0x00, 0x81, + 0x4b, 0x00, 0x8e, 0x4b, 0x01, 0x8d, 0x4b, 0x21, + 0xe0, 0x1a, 0x4b, 0x04, 0x82, 0x19, 0x03, 0xac, + 0x19, 0x02, 0x88, 0x19, 0xce, 0x2c, 0x00, 0x8c, + 0x19, 0x02, 0x80, 0x2c, 0x2e, 0xac, 0x19, 0x80, + 0x38, 0x60, 0x21, 0x9c, 0x4d, 0x02, 0xb0, 0x13, + 0x0e, 0x80, 0x38, 0x9a, 0x19, 0x03, 0xa3, 0x6c, + 0x08, 0x82, 0x6c, 0x9a, 0x2a, 0x04, 0xaa, 0x6e, + 0x04, 0x9d, 0x9c, 0x00, 0x80, 0x9c, 0xa3, 0x6f, + 0x03, 0x8d, 0x6f, 0x29, 0xcf, 0x1f, 0xaf, 0x82, + 0x9d, 0x76, 0x01, 0x89, 0x76, 0x05, 0xa3, 0x75, + 0x03, 0xa3, 0x75, 0x03, 0xa7, 0x25, 0x07, 0xb3, + 0x14, 0x0a, 0x80, 0x14, 0x8a, 0x9e, 0x00, 0x8e, + 0x9e, 0x00, 0x86, 0x9e, 0x00, 0x81, 0x9e, 0x00, + 0x8a, 0x9e, 0x00, 0x8e, 0x9e, 0x00, 0x86, 0x9e, + 0x00, 0x81, 0x9e, 0x42, 0xe0, 0xd6, 0x4a, 0x08, + 0x95, 0x4a, 0x09, 0x87, 0x4a, 0x17, 0x85, 0x47, + 0x00, 0xa9, 0x47, 0x00, 0x88, 0x47, 0x44, 0x85, + 0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00, + 0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c, + 0x95, 0x37, 0x00, 0x88, 0x37, 0x9f, 0x78, 0x9e, + 0x61, 0x07, 0x88, 0x61, 0x2f, 0x92, 0x34, 0x00, + 0x81, 0x34, 0x04, 0x84, 0x34, 0x9b, 0x7b, 0x02, + 0x80, 0x7b, 0x99, 0x4e, 0x04, 0x80, 0x4e, 0x3f, + 0x9f, 0x5a, 0x97, 0x59, 0x03, 0x93, 0x59, 0x01, + 0xad, 0x59, 0x83, 0x41, 0x00, 0x81, 0x41, 0x04, + 0x87, 0x41, 0x00, 0x82, 0x41, 0x00, 0x9c, 0x41, + 0x01, 0x82, 0x41, 0x03, 0x89, 0x41, 0x06, 0x88, + 0x41, 0x06, 0x9f, 0x71, 0x9f, 0x6d, 0x1f, 0xa6, + 0x53, 0x03, 0x8b, 0x53, 0x08, 0xb5, 0x06, 0x02, + 0x86, 0x06, 0x95, 0x3a, 0x01, 0x87, 0x3a, 0x92, + 0x39, 0x04, 0x87, 0x39, 0x91, 0x7c, 0x06, 0x83, + 0x7c, 0x0b, 0x86, 0x7c, 0x4f, 0xc8, 0x72, 0x36, + 0xb2, 0x6b, 0x0c, 0xb2, 0x6b, 0x06, 0x85, 0x6b, + 0xa7, 0x32, 0x07, 0x89, 0x32, 0x60, 0xc5, 0x9e, + 0x04, 0x00, 0xa9, 0xa1, 0x00, 0x82, 0xa1, 0x01, + 0x81, 0xa1, 0x4a, 0x82, 0x04, 0xa7, 0x70, 0x07, + 0xa9, 0x86, 0x15, 0x99, 0x73, 0x25, 0x9b, 0x18, + 0x13, 0x96, 0x26, 0x08, 0xcd, 0x0e, 0x03, 0xa3, + 0x0e, 0x08, 0x80, 0x0e, 0xc2, 0x3c, 0x09, 0x80, + 0x3c, 0x01, 0x98, 0x87, 0x06, 0x89, 0x87, 0x05, + 0xb4, 0x15, 0x00, 0x91, 0x15, 0x07, 0xa6, 0x50, + 0x08, 0xdf, 0x81, 0x00, 0x93, 0x85, 0x0a, 0x91, + 0x43, 0x00, 0xae, 0x43, 0x3d, 0x86, 0x5f, 0x00, + 0x80, 0x5f, 0x00, 0x83, 0x5f, 0x00, 0x8e, 0x5f, + 0x00, 0x8a, 0x5f, 0x05, 0xba, 0x45, 0x04, 0x89, + 0x45, 0x05, 0x83, 0x2b, 0x00, 0x87, 0x2b, 0x01, + 0x81, 0x2b, 0x01, 0x95, 0x2b, 0x00, 0x86, 0x2b, + 0x00, 0x81, 0x2b, 0x00, 0x84, 0x2b, 0x00, 0x80, + 0x38, 0x88, 0x2b, 0x01, 0x81, 0x2b, 0x01, 0x82, + 0x2b, 0x01, 0x80, 0x2b, 0x05, 0x80, 0x2b, 0x04, + 0x86, 0x2b, 0x01, 0x86, 0x2b, 0x02, 0x84, 0x2b, + 0x60, 0x2a, 0xdb, 0x65, 0x00, 0x84, 0x65, 0x1d, + 0xc7, 0x99, 0x07, 0x89, 0x99, 0x60, 0x45, 0xb5, + 0x83, 0x01, 0xa5, 0x83, 0x21, 0xc4, 0x5c, 0x0a, + 0x89, 0x5c, 0x05, 0x8c, 0x5d, 0x12, 0xb9, 0x91, + 0x05, 0x89, 0x91, 0x35, 0x9a, 0x02, 0x01, 0x8e, + 0x02, 0x03, 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22, + 0x60, 0x03, 0xd2, 0xa0, 0x0b, 0x80, 0xa0, 0x86, + 0x21, 0x01, 0x80, 0x21, 0x01, 0x87, 0x21, 0x00, + 0x81, 0x21, 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21, + 0x01, 0x8b, 0x21, 0x08, 0x89, 0x21, 0x45, 0x87, + 0x63, 0x01, 0xad, 0x63, 0x01, 0x8a, 0x63, 0x1a, + 0xc7, 0xa3, 0x07, 0xd2, 0x88, 0x0c, 0x8f, 0x12, + 0xb8, 0x79, 0x06, 0x89, 0x20, 0x60, 0x95, 0x88, + 0x0c, 0x00, 0xac, 0x0c, 0x00, 0x8d, 0x0c, 0x09, + 0x9c, 0x0c, 0x02, 0x9f, 0x54, 0x01, 0x95, 0x54, + 0x00, 0x8d, 0x54, 0x48, 0x86, 0x55, 0x00, 0x81, + 0x55, 0x00, 0xab, 0x55, 0x02, 0x80, 0x55, 0x00, + 0x81, 0x55, 0x00, 0x88, 0x55, 0x07, 0x89, 0x55, + 0x05, 0x85, 0x2e, 0x00, 0x81, 0x2e, 0x00, 0xa4, + 0x2e, 0x00, 0x81, 0x2e, 0x00, 0x85, 0x2e, 0x06, + 0x89, 0x2e, 0x60, 0xd5, 0x98, 0x4f, 0x06, 0x90, + 0x3f, 0x00, 0xa8, 0x3f, 0x02, 0x9b, 0x3f, 0x55, + 0x80, 0x4c, 0x0e, 0xb1, 0x92, 0x0c, 0x80, 0x92, + 0xe3, 0x39, 0x1b, 0x60, 0x05, 0xe0, 0x0e, 0x1b, + 0x00, 0x84, 0x1b, 0x0a, 0xe0, 0x63, 0x1b, 0x69, + 0xeb, 0xe0, 0x02, 0x1e, 0x0c, 0xe3, 0xf5, 0x24, + 0x6f, 0x49, 0xe1, 0xe6, 0x03, 0x70, 0x11, 0x58, + 0xe1, 0xd8, 0x08, 0x06, 0x9e, 0x5e, 0x00, 0x89, + 0x5e, 0x03, 0x81, 0x5e, 0xce, 0x9a, 0x00, 0x89, + 0x9a, 0x05, 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, + 0xc5, 0x77, 0x09, 0x89, 0x77, 0x00, 0x86, 0x77, + 0x00, 0x94, 0x77, 0x04, 0x92, 0x77, 0x62, 0x4f, + 0xda, 0x56, 0x60, 0x04, 0xca, 0x5b, 0x03, 0xb8, + 0x5b, 0x06, 0x90, 0x5b, 0x3f, 0x80, 0x93, 0x80, + 0x67, 0x81, 0x30, 0x80, 0x44, 0x0a, 0x81, 0x30, + 0x0d, 0xf0, 0x07, 0x97, 0x93, 0x07, 0xe2, 0x9f, + 0x93, 0xe1, 0x75, 0x44, 0x29, 0x88, 0x93, 0x70, + 0x12, 0x86, 0x83, 0x3e, 0x00, 0x86, 0x3e, 0x00, + 0x81, 0x3e, 0x00, 0x80, 0x3e, 0xe0, 0xbe, 0x36, + 0x82, 0x3e, 0x0e, 0x80, 0x36, 0x1c, 0x82, 0x36, + 0x01, 0x80, 0x3e, 0x0d, 0x83, 0x3e, 0x07, 0xe1, + 0x2b, 0x67, 0x68, 0xa3, 0xe0, 0x0a, 0x23, 0x04, + 0x8c, 0x23, 0x02, 0x88, 0x23, 0x06, 0x89, 0x23, + 0x01, 0x83, 0x23, 0x83, 0x19, 0x70, 0x01, 0xfb, + 0xad, 0x38, 0x01, 0x96, 0x38, 0x08, 0xe0, 0x13, + 0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09, 0xa6, 0x19, + 0x01, 0xbd, 0x19, 0x82, 0x38, 0x90, 0x19, 0x87, + 0x38, 0x81, 0x19, 0x86, 0x38, 0x9d, 0x19, 0x83, + 0x38, 0xbc, 0x19, 0x14, 0xc5, 0x2c, 0x60, 0x19, + 0x93, 0x19, 0x0b, 0x93, 0x19, 0x0b, 0xd6, 0x19, + 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4, 0x19, 0x00, + 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01, 0x80, 0x19, + 0x01, 0x81, 0x19, 0x01, 0x83, 0x19, 0x00, 0x8b, + 0x19, 0x00, 0x80, 0x19, 0x00, 0x86, 0x19, 0x00, + 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01, 0x87, 0x19, + 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19, 0x00, 0x83, + 0x19, 0x00, 0x84, 0x19, 0x00, 0x80, 0x19, 0x02, + 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19, 0x01, 0xe0, + 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2, 0x2b, 0x84, + 0x0e, 0x84, 0x84, 0x00, 0x8e, 0x84, 0x63, 0xef, + 0x9e, 0x47, 0x05, 0x85, 0x47, 0x60, 0x74, 0x86, + 0x29, 0x00, 0x90, 0x29, 0x01, 0x86, 0x29, 0x00, + 0x81, 0x29, 0x00, 0x84, 0x29, 0x04, 0xbd, 0x1d, + 0x20, 0x80, 0x1d, 0x60, 0x0f, 0xac, 0x68, 0x02, + 0x8d, 0x68, 0x01, 0x89, 0x68, 0x03, 0x81, 0x68, + 0x60, 0xdf, 0x9e, 0x9b, 0x10, 0xb9, 0x9f, 0x04, + 0x80, 0x9f, 0x61, 0x6f, 0xa9, 0x62, 0x62, 0x85, + 0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81, 0x27, + 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x58, 0x01, + 0x8f, 0x58, 0x28, 0xcb, 0x01, 0x03, 0x89, 0x01, + 0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19, 0x4b, + 0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00, 0x9a, + 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, 0x01, + 0x80, 0x04, 0x00, 0x89, 0x04, 0x00, 0x83, 0x04, + 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x05, 0x80, + 0x04, 0x03, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, + 0x80, 0x04, 0x00, 0x82, 0x04, 0x00, 0x81, 0x04, + 0x00, 0x80, 0x04, 0x01, 0x80, 0x04, 0x00, 0x80, + 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, + 0x80, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, + 0x01, 0x83, 0x04, 0x00, 0x86, 0x04, 0x00, 0x83, + 0x04, 0x00, 0x83, 0x04, 0x00, 0x80, 0x04, 0x00, + 0x89, 0x04, 0x00, 0x90, 0x04, 0x04, 0x82, 0x04, + 0x00, 0x84, 0x04, 0x00, 0x90, 0x04, 0x33, 0x81, + 0x04, 0x60, 0xad, 0xab, 0x19, 0x03, 0xe0, 0x03, + 0x19, 0x0b, 0x8e, 0x19, 0x01, 0x8e, 0x19, 0x00, + 0x8e, 0x19, 0x00, 0xa4, 0x19, 0x09, 0xe0, 0x4d, + 0x19, 0x37, 0x99, 0x19, 0x80, 0x36, 0x81, 0x19, + 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06, 0x81, + 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3, 0x77, + 0x19, 0x03, 0x90, 0x19, 0x02, 0x8c, 0x19, 0x02, + 0xe0, 0x16, 0x19, 0x03, 0xde, 0x19, 0x05, 0x8b, + 0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19, 0x03, + 0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7, 0x19, + 0x07, 0x9d, 0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0, + 0xf3, 0x19, 0x0b, 0x8d, 0x19, 0x01, 0x8c, 0x19, + 0x02, 0x88, 0x19, 0x06, 0xad, 0x19, 0x00, 0x86, + 0x19, 0x07, 0x8d, 0x19, 0x03, 0x88, 0x19, 0x06, + 0x88, 0x19, 0x06, 0xe0, 0x32, 0x19, 0x00, 0xb6, + 0x19, 0x24, 0x89, 0x19, 0x63, 0xa5, 0xf0, 0x96, + 0x7f, 0x30, 0x1f, 0xef, 0xd9, 0x30, 0x05, 0xe0, + 0x7d, 0x30, 0x01, 0xf0, 0x06, 0x21, 0x30, 0x0d, + 0xf0, 0x0c, 0xd0, 0x30, 0x6b, 0xbe, 0xe1, 0xbd, + 0x30, 0x65, 0x81, 0xf0, 0x02, 0xea, 0x30, 0x04, + 0xef, 0xff, 0x30, 0x7a, 0xcb, 0xf0, 0x80, 0x19, + 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, 0x8f, 0x38, +}; + +static const uint8_t unicode_script_ext_table[828] = { + 0x82, 0xc1, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x00, + 0x00, 0x01, 0x2c, 0x1c, 0x00, 0x0c, 0x01, 0x47, + 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6e, 0x00, + 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x47, 0x00, + 0x02, 0x1d, 0x29, 0x81, 0x03, 0x00, 0x00, 0x06, + 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, 0x0d, 0x00, + 0x00, 0x06, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, + 0x00, 0x03, 0x04, 0x8b, 0x95, 0x01, 0x00, 0x00, + 0x07, 0x01, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, + 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x52, 0x53, + 0x73, 0x7c, 0x32, 0x86, 0x8b, 0x09, 0x00, 0x0a, + 0x02, 0x04, 0x8b, 0x09, 0x00, 0x09, 0x03, 0x04, + 0x95, 0xa1, 0x05, 0x00, 0x00, 0x02, 0x04, 0x8b, + 0x62, 0x00, 0x00, 0x02, 0x04, 0x32, 0x81, 0xfb, + 0x00, 0x00, 0x0d, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, + 0x3d, 0x47, 0x51, 0x74, 0x81, 0x92, 0x94, 0x99, + 0x00, 0x0c, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, 0x3d, + 0x47, 0x51, 0x74, 0x92, 0x94, 0x99, 0x10, 0x00, + 0x00, 0x14, 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b, + 0x2d, 0x2f, 0x3d, 0x50, 0x51, 0x63, 0x74, 0x45, + 0x85, 0x8a, 0x91, 0x92, 0x94, 0x99, 0x00, 0x15, + 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b, 0x2d, 0x2f, + 0x3d, 0x49, 0x50, 0x51, 0x63, 0x74, 0x45, 0x85, + 0x8a, 0x91, 0x92, 0x94, 0x99, 0x09, 0x04, 0x20, + 0x22, 0x3c, 0x50, 0x75, 0x00, 0x09, 0x03, 0x0b, + 0x15, 0x8a, 0x75, 0x00, 0x09, 0x02, 0x2f, 0x5f, + 0x75, 0x00, 0x09, 0x02, 0x2d, 0x43, 0x80, 0x75, + 0x00, 0x0d, 0x02, 0x2b, 0x92, 0x80, 0x71, 0x00, + 0x09, 0x02, 0x3d, 0x63, 0x82, 0xcf, 0x00, 0x09, + 0x03, 0x15, 0x60, 0x8e, 0x80, 0x30, 0x00, 0x00, + 0x02, 0x28, 0x47, 0x85, 0xb8, 0x00, 0x01, 0x04, + 0x11, 0x33, 0x8d, 0x8c, 0x80, 0x4a, 0x00, 0x01, + 0x02, 0x5d, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x5d, + 0x7a, 0x84, 0x49, 0x00, 0x00, 0x04, 0x0b, 0x20, + 0x2b, 0x3d, 0x00, 0x01, 0x20, 0x00, 0x04, 0x0b, + 0x20, 0x2b, 0x3d, 0x00, 0x02, 0x20, 0x2b, 0x00, + 0x01, 0x20, 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02, + 0x20, 0x81, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02, + 0x20, 0x81, 0x00, 0x06, 0x20, 0x3d, 0x51, 0x74, + 0x92, 0x94, 0x00, 0x01, 0x20, 0x01, 0x02, 0x20, + 0x81, 0x01, 0x01, 0x20, 0x00, 0x02, 0x20, 0x81, + 0x00, 0x02, 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00, + 0x02, 0x20, 0x63, 0x00, 0x02, 0x0b, 0x20, 0x01, + 0x01, 0x20, 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01, + 0x20, 0x00, 0x08, 0x0b, 0x20, 0x2b, 0x3d, 0x63, + 0x74, 0x94, 0x99, 0x00, 0x02, 0x20, 0x2b, 0x00, + 0x03, 0x20, 0x2b, 0x3d, 0x01, 0x02, 0x0b, 0x20, + 0x00, 0x01, 0x0b, 0x01, 0x02, 0x20, 0x2b, 0x00, + 0x01, 0x63, 0x80, 0x44, 0x00, 0x01, 0x01, 0x2c, + 0x35, 0x00, 0x00, 0x02, 0x1d, 0x8b, 0x00, 0x00, + 0x00, 0x01, 0x8b, 0x81, 0xb3, 0x00, 0x00, 0x02, + 0x47, 0x5d, 0x80, 0x3f, 0x00, 0x00, 0x03, 0x20, + 0x2b, 0x47, 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d, + 0x29, 0x81, 0x3c, 0x00, 0x01, 0x06, 0x0d, 0x31, + 0x30, 0x36, 0x3e, 0xa2, 0x00, 0x05, 0x0d, 0x31, + 0x30, 0x36, 0x3e, 0x01, 0x00, 0x00, 0x01, 0x30, + 0x00, 0x00, 0x09, 0x06, 0x0d, 0x31, 0x30, 0x36, + 0x3e, 0xa2, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x31, + 0x30, 0x36, 0x3e, 0x07, 0x06, 0x0d, 0x31, 0x30, + 0x36, 0x3e, 0xa2, 0x03, 0x05, 0x0d, 0x31, 0x30, + 0x36, 0x3e, 0x09, 0x00, 0x03, 0x02, 0x0d, 0x30, + 0x01, 0x00, 0x00, 0x05, 0x0d, 0x31, 0x30, 0x36, + 0x3e, 0x04, 0x02, 0x36, 0x3e, 0x00, 0x00, 0x00, + 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x03, 0x00, + 0x01, 0x03, 0x30, 0x36, 0x3e, 0x01, 0x01, 0x30, + 0x58, 0x00, 0x03, 0x02, 0x36, 0x3e, 0x02, 0x00, + 0x00, 0x02, 0x36, 0x3e, 0x59, 0x00, 0x00, 0x06, + 0x0d, 0x31, 0x30, 0x36, 0x3e, 0xa2, 0x00, 0x02, + 0x36, 0x3e, 0x80, 0x12, 0x00, 0x0f, 0x01, 0x30, + 0x1f, 0x00, 0x23, 0x01, 0x30, 0x3b, 0x00, 0x27, + 0x01, 0x30, 0x37, 0x00, 0x30, 0x01, 0x30, 0x0e, + 0x00, 0x0b, 0x01, 0x30, 0x32, 0x00, 0x00, 0x01, + 0x30, 0x57, 0x00, 0x18, 0x01, 0x30, 0x09, 0x00, + 0x04, 0x01, 0x30, 0x5f, 0x00, 0x1e, 0x01, 0x30, + 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d, 0x29, + 0x80, 0x0f, 0x00, 0x07, 0x02, 0x30, 0x47, 0x80, + 0xa7, 0x00, 0x02, 0x0e, 0x20, 0x22, 0x2d, 0x2f, + 0x43, 0x3d, 0x3c, 0x50, 0x51, 0x5c, 0x63, 0x45, + 0x91, 0x99, 0x02, 0x0d, 0x20, 0x22, 0x2d, 0x2f, + 0x43, 0x3d, 0x3c, 0x50, 0x5c, 0x63, 0x45, 0x91, + 0x99, 0x03, 0x0b, 0x20, 0x22, 0x2d, 0x2f, 0x43, + 0x3c, 0x50, 0x5c, 0x45, 0x91, 0x99, 0x80, 0x36, + 0x00, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x00, 0x00, + 0x02, 0x20, 0x92, 0x39, 0x00, 0x00, 0x03, 0x40, + 0x47, 0x60, 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10, + 0x3b, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02, 0x04, + 0x66, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, 0x95, + 0x09, 0x00, 0x00, 0x02, 0x04, 0x95, 0x46, 0x00, + 0x01, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x80, + 0x99, 0x00, 0x04, 0x06, 0x0d, 0x31, 0x30, 0x36, + 0x3e, 0xa2, 0x09, 0x00, 0x00, 0x02, 0x36, 0x3e, + 0x2c, 0x00, 0x01, 0x02, 0x36, 0x3e, 0x80, 0xdf, + 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4b, 0x00, 0x02, + 0x1c, 0x4b, 0x03, 0x00, 0x2c, 0x03, 0x1c, 0x4a, + 0x4b, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4b, 0x81, + 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87, 0x75, + 0x00, 0x00, 0x02, 0x53, 0x73, 0x87, 0x8d, 0x00, + 0x00, 0x02, 0x2b, 0x92, 0x00, 0x00, 0x00, 0x02, + 0x2b, 0x92, 0x36, 0x00, 0x01, 0x02, 0x2b, 0x92, + 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2b, 0x92, 0x00, + 0x00, 0x00, 0x02, 0x2b, 0x92, 0xc0, 0x5c, 0x4b, + 0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00, 0x11, + 0x01, 0x30, 0x9e, 0x5d, 0x00, 0x01, 0x01, 0x30, + 0xce, 0xcd, 0x2d, 0x00, +}; + +static const uint8_t unicode_prop_Hyphen_table[28] = { + 0xac, 0x80, 0xfe, 0x80, 0x44, 0xdb, 0x80, 0x52, + 0x7a, 0x80, 0x48, 0x08, 0x81, 0x4e, 0x04, 0x80, + 0x42, 0xe2, 0x80, 0x60, 0xcd, 0x66, 0x80, 0x40, + 0xa8, 0x80, 0xd6, 0x80, +}; + +static const uint8_t unicode_prop_Other_Math_table[200] = { + 0xdd, 0x80, 0x43, 0x70, 0x11, 0x80, 0x99, 0x09, + 0x81, 0x5c, 0x1f, 0x80, 0x9a, 0x82, 0x8a, 0x80, + 0x9f, 0x83, 0x97, 0x81, 0x8d, 0x81, 0xc0, 0x8c, + 0x18, 0x11, 0x1c, 0x91, 0x03, 0x01, 0x89, 0x00, + 0x14, 0x28, 0x11, 0x09, 0x02, 0x05, 0x13, 0x24, + 0xca, 0x21, 0x18, 0x08, 0x08, 0x00, 0x21, 0x0b, + 0x0b, 0x91, 0x09, 0x00, 0x06, 0x00, 0x29, 0x41, + 0x21, 0x83, 0x40, 0xa7, 0x08, 0x80, 0x97, 0x80, + 0x90, 0x80, 0x41, 0xbc, 0x81, 0x8b, 0x88, 0x24, + 0x21, 0x09, 0x14, 0x8d, 0x00, 0x01, 0x85, 0x97, + 0x81, 0xb8, 0x00, 0x80, 0x9c, 0x83, 0x88, 0x81, + 0x41, 0x55, 0x81, 0x9e, 0x89, 0x41, 0x92, 0x95, + 0xbe, 0x83, 0x9f, 0x81, 0x60, 0xd4, 0x62, 0x00, + 0x03, 0x80, 0x40, 0xd2, 0x00, 0x80, 0x60, 0xd4, + 0xc0, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, + 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, + 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, + 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x81, + 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00, 0x08, + 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, + 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, +}; + +static const uint8_t unicode_prop_Other_Alphabetic_table[428] = { + 0x43, 0x44, 0x80, 0x42, 0x69, 0x8d, 0x00, 0x01, + 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, 0x06, 0x8f, + 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, 0xa2, 0x80, + 0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a, 0x88, 0x02, + 0x03, 0x40, 0xa6, 0x8b, 0x16, 0x85, 0x93, 0xb5, + 0x09, 0x8e, 0x01, 0x22, 0x89, 0x81, 0x9c, 0x82, + 0xb9, 0x31, 0x09, 0x81, 0x89, 0x80, 0x89, 0x81, + 0x9c, 0x82, 0xb9, 0x23, 0x09, 0x0b, 0x80, 0x9d, + 0x0a, 0x80, 0x8a, 0x82, 0xb9, 0x38, 0x10, 0x81, + 0x94, 0x81, 0x95, 0x13, 0x82, 0xb9, 0x31, 0x09, + 0x81, 0x88, 0x81, 0x89, 0x81, 0x9d, 0x80, 0xba, + 0x22, 0x10, 0x82, 0x89, 0x80, 0xa7, 0x84, 0xb8, + 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9c, 0x82, + 0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x8e, + 0x80, 0x8b, 0x83, 0xb9, 0x30, 0x10, 0x82, 0x89, + 0x80, 0x89, 0x81, 0x9c, 0x82, 0xca, 0x28, 0x00, + 0x87, 0x91, 0x81, 0xbc, 0x01, 0x86, 0x91, 0x80, + 0xe2, 0x01, 0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2, + 0x92, 0x88, 0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00, + 0x0b, 0x96, 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c, + 0x8b, 0x00, 0x89, 0x83, 0x46, 0x73, 0x81, 0x9d, + 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40, + 0xbb, 0x81, 0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88, + 0x40, 0xdd, 0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9, + 0x81, 0x8a, 0x82, 0xb0, 0x84, 0xaf, 0x8e, 0xbb, + 0x82, 0x9d, 0x88, 0x09, 0xb8, 0x8a, 0xb1, 0x92, + 0x41, 0xaf, 0x8d, 0x46, 0xc0, 0xb3, 0x48, 0xf5, + 0x9f, 0x60, 0x78, 0x73, 0x87, 0xa1, 0x81, 0x41, + 0x61, 0x07, 0x80, 0x96, 0x84, 0xd7, 0x81, 0xb1, + 0x8f, 0x00, 0xb8, 0x80, 0xa5, 0x84, 0x9b, 0x8b, + 0xac, 0x83, 0xaf, 0x8b, 0xa4, 0x80, 0xc2, 0x8d, + 0x8b, 0x07, 0x81, 0xac, 0x82, 0xb1, 0x00, 0x11, + 0x0c, 0x80, 0xab, 0x24, 0x80, 0x40, 0xec, 0x87, + 0x60, 0x4f, 0x32, 0x80, 0x48, 0x56, 0x84, 0x46, + 0x85, 0x10, 0x0c, 0x83, 0x43, 0x13, 0x83, 0x41, + 0x82, 0x81, 0x41, 0x52, 0x82, 0xb4, 0x8d, 0xac, + 0x81, 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc, + 0x82, 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, + 0x8c, 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08, + 0x40, 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, + 0x81, 0x89, 0x80, 0x89, 0x81, 0x40, 0xd0, 0x8c, + 0x02, 0xe9, 0x91, 0x40, 0xec, 0x31, 0x86, 0x9c, + 0x81, 0xd1, 0x8e, 0x00, 0xe9, 0x8a, 0xe6, 0x8d, + 0x41, 0x00, 0x8c, 0x40, 0xf6, 0x28, 0x09, 0x0a, + 0x00, 0x80, 0x40, 0x8d, 0x31, 0x2b, 0x80, 0x9b, + 0x89, 0xa9, 0x20, 0x83, 0x91, 0x8a, 0xad, 0x8d, + 0x41, 0x96, 0x38, 0x86, 0xd2, 0x95, 0x80, 0x8d, + 0xf9, 0x2a, 0x00, 0x08, 0x10, 0x02, 0x80, 0xc1, + 0x20, 0x08, 0x83, 0x41, 0x5b, 0x83, 0x88, 0x08, + 0x80, 0xaf, 0x32, 0x82, 0x60, 0x50, 0x0d, 0x00, + 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, + 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, + 0xe3, 0x80, 0x48, 0xb6, 0x80, 0x47, 0xe7, 0x99, + 0x85, 0x99, 0x85, 0x99, +}; + +static const uint8_t unicode_prop_Other_Lowercase_table[69] = { + 0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88, + 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x4d, + 0x80, 0x80, 0x4c, 0x2e, 0xbe, 0x8c, 0x80, 0xa1, + 0xa4, 0x42, 0xb0, 0x80, 0x8c, 0x80, 0x8f, 0x8c, + 0x40, 0xd2, 0x8f, 0x43, 0x4f, 0x99, 0x47, 0x91, + 0x81, 0x60, 0x7a, 0x1d, 0x81, 0x40, 0xd1, 0x80, + 0x40, 0x80, 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, + 0x80, 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80, + 0x88, 0x60, 0xd8, 0x74, 0xbd, +}; + +static const uint8_t unicode_prop_Other_Uppercase_table[15] = { + 0x60, 0x21, 0x5f, 0x8f, 0x43, 0x45, 0x99, 0x61, + 0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99, +}; + +static const uint8_t unicode_prop_Other_Grapheme_Extend_table[65] = { + 0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80, + 0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe9, + 0x80, 0x91, 0x81, 0xe6, 0x80, 0x97, 0x80, 0xf6, + 0x80, 0x8e, 0x80, 0x4d, 0x54, 0x80, 0x44, 0xd5, + 0x80, 0x50, 0x20, 0x81, 0x60, 0xcf, 0x6d, 0x81, + 0x53, 0x9d, 0x80, 0x97, 0x80, 0x41, 0x57, 0x80, + 0x8b, 0x80, 0x40, 0xf0, 0x80, 0x43, 0x7f, 0x80, + 0x60, 0xb8, 0x33, 0x07, 0x84, 0x6c, 0x2e, 0xac, + 0xdf, +}; + +static const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = { + 0x43, 0x4e, 0x80, 0x4e, 0x0e, 0x81, 0x46, 0x52, + 0x81, 0x48, 0xae, 0x80, 0x50, 0xfd, 0x80, 0x60, + 0xce, 0x3a, 0x80, 0xce, 0x88, 0x6d, 0x00, 0x06, + 0x00, 0x9d, 0xdf, 0xff, 0x40, 0xef, 0x4e, 0x0f, +}; + +static const uint8_t unicode_prop_Other_ID_Start_table[11] = { + 0x58, 0x84, 0x81, 0x48, 0x90, 0x80, 0x94, 0x80, + 0x4f, 0x6b, 0x81, +}; + +static const uint8_t unicode_prop_Other_ID_Continue_table[12] = { + 0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0, + 0x88, 0x46, 0x67, 0x80, +}; + +static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[19] = { + 0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80, + 0x41, 0x7f, 0x81, 0xcf, 0x80, 0x61, 0x07, 0xd9, + 0x80, 0x8e, 0x80, +}; + +static const uint8_t unicode_prop_XID_Start1_table[31] = { + 0x43, 0x79, 0x80, 0x4a, 0xb7, 0x80, 0xfe, 0x80, + 0x60, 0x21, 0xe6, 0x81, 0x60, 0xcb, 0xc0, 0x85, + 0x41, 0x95, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x41, 0x1e, 0x81, +}; + +static const uint8_t unicode_prop_XID_Continue1_table[23] = { + 0x43, 0x79, 0x80, 0x60, 0x2d, 0x1f, 0x81, 0x60, + 0xcb, 0xc0, 0x85, 0x41, 0x95, 0x81, 0xf3, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +}; + +static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = { + 0x41, 0xc3, 0x08, 0x08, 0x81, 0xa4, 0x81, 0x4e, + 0xdc, 0xaa, 0x0a, 0x4e, 0x87, 0x3f, 0x3f, 0x87, + 0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80, +}; + +static const uint8_t unicode_prop_Changes_When_Casefolded1_table[29] = { + 0x41, 0xef, 0x80, 0x41, 0x9e, 0x80, 0x9e, 0x80, + 0x5a, 0xe4, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, + 0x80, 0xde, 0x06, 0x06, 0x80, 0x8a, 0x09, 0x81, + 0x89, 0x10, 0x81, 0x8d, 0x80, +}; + +static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[447] = { + 0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12, + 0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84, + 0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb, + 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, 0x81, 0x89, + 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, 0x07, 0x80, + 0x9e, 0x80, 0xa0, 0x82, 0x9c, 0x80, 0x42, 0x28, + 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, 0xfb, 0x08, + 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, 0x80, 0x40, + 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, 0x80, 0xa7, + 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, 0x03, 0x03, + 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, 0x26, 0x80, + 0x90, 0x80, 0x88, 0x03, 0x03, 0x03, 0x80, 0x8b, + 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, 0x46, 0x52, + 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, 0x8a, 0x80, + 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, 0xa4, 0x40, + 0xd5, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, 0x80, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xb7, 0x05, 0x00, 0x13, 0x05, 0x11, 0x02, 0x0c, + 0x11, 0x00, 0x00, 0x0c, 0x15, 0x05, 0x08, 0x8f, + 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, 0x00, + 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, 0x80, + 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, 0x01, + 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, 0x05, + 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, 0x40, + 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, 0x34, + 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, 0x82, + 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, 0x80, + 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, 0xd5, + 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, 0x80, + 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, 0x9e, + 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, 0x60, + 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x80, + 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60, + 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89, + 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xc2, + 0x00, 0x97, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb, + 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7, + 0x8c, 0x82, 0x99, 0x95, 0x94, 0x81, 0x8b, 0x80, + 0x92, 0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08, + 0x80, 0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d, + 0x0a, 0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20, + 0xa9, 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x54, + 0xb9, 0x86, 0x8d, 0x87, 0xbf, 0x85, 0x42, 0x3e, + 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, + 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, + 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, + 0x53, 0x81, 0x41, 0x23, 0x81, 0xb1, 0x48, 0x2f, + 0xbd, 0x4d, 0x91, 0x18, 0x9a, 0x01, 0x00, 0x08, + 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, + 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, + 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, 0x9f, 0x99, + 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, 0xab, 0x83, + 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, 0xfc, 0x05, + 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, 0xff, +}; + +static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = { + 0xaf, 0x89, 0x35, 0x99, 0x85, +}; + +static const uint8_t unicode_prop_Bidi_Control_table[10] = { + 0x46, 0x1b, 0x80, 0x59, 0xf0, 0x81, 0x99, 0x84, + 0xb6, 0x83, +}; + +static const uint8_t unicode_prop_Dash_table[55] = { + 0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e, + 0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85, + 0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85, + 0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80, + 0x9b, 0x80, 0x41, 0xbd, 0x80, 0x92, 0x80, 0xee, + 0x80, 0x60, 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89, + 0x80, 0x40, 0xa8, 0x80, 0x4f, 0x9e, 0x80, +}; + +static const uint8_t unicode_prop_Deprecated_table[23] = { + 0x41, 0x48, 0x80, 0x45, 0x28, 0x80, 0x49, 0x02, + 0x00, 0x80, 0x48, 0x28, 0x81, 0x48, 0xc4, 0x85, + 0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80, +}; + +static const uint8_t unicode_prop_Diacritic_table[399] = { + 0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81, + 0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b, + 0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0, + 0x80, 0xb6, 0x90, 0x80, 0x9a, 0x00, 0x01, 0x00, + 0x40, 0x85, 0x3b, 0x81, 0x40, 0x85, 0x0b, 0x0a, + 0x82, 0xc2, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0xa1, + 0x81, 0xfd, 0x87, 0xa8, 0x89, 0x8f, 0x9b, 0xbc, + 0x80, 0x8f, 0x02, 0x83, 0x9b, 0x80, 0xc9, 0x80, + 0x8f, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80, + 0x8f, 0x80, 0xae, 0x82, 0xbb, 0x80, 0x8f, 0x06, + 0x80, 0xf6, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, + 0x80, 0x8f, 0x80, 0xec, 0x81, 0x8f, 0x80, 0xfb, + 0x80, 0xfb, 0x28, 0x80, 0xea, 0x80, 0x8c, 0x84, + 0xca, 0x81, 0x9a, 0x00, 0x00, 0x03, 0x81, 0xc1, + 0x10, 0x81, 0xbd, 0x80, 0xef, 0x00, 0x81, 0xa7, + 0x0b, 0x84, 0x98, 0x30, 0x80, 0x89, 0x81, 0x42, + 0xc0, 0x82, 0x43, 0xb3, 0x81, 0x40, 0xb2, 0x8a, + 0x88, 0x80, 0x41, 0x5a, 0x82, 0x41, 0x38, 0x39, + 0x80, 0xaf, 0x8e, 0x81, 0x8a, 0xe7, 0x80, 0x8e, + 0x80, 0xa5, 0x88, 0xb5, 0x81, 0x40, 0x89, 0x81, + 0xbf, 0x85, 0xd1, 0x98, 0x18, 0x28, 0x0a, 0xb1, + 0xbe, 0xd8, 0x8b, 0xa4, 0x8a, 0x41, 0xbc, 0x00, + 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c, + 0x81, 0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80, 0x41, + 0xf9, 0x85, 0xe8, 0x83, 0xde, 0x80, 0x60, 0x75, + 0x71, 0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81, 0xd1, + 0x81, 0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81, 0x40, + 0xc9, 0x80, 0x9a, 0x91, 0xb8, 0x83, 0xa3, 0x80, + 0xde, 0x80, 0x8b, 0x80, 0xa3, 0x80, 0x40, 0x94, + 0x82, 0xc0, 0x83, 0xb2, 0x80, 0xe3, 0x84, 0x88, + 0x82, 0xff, 0x81, 0x60, 0x4f, 0x2f, 0x80, 0x43, + 0x00, 0x8f, 0x41, 0x0d, 0x00, 0x80, 0xae, 0x80, + 0xac, 0x81, 0xc2, 0x80, 0x42, 0xfb, 0x80, 0x44, + 0x9e, 0x28, 0xa9, 0x80, 0x88, 0x43, 0x29, 0x81, + 0x42, 0x3a, 0x85, 0x41, 0xd4, 0x82, 0xc5, 0x8a, + 0xb0, 0x83, 0x40, 0xbf, 0x80, 0xa8, 0x80, 0xc7, + 0x81, 0xf7, 0x81, 0xbd, 0x80, 0xcb, 0x80, 0x88, + 0x82, 0xe7, 0x81, 0x40, 0xb1, 0x81, 0xd0, 0x80, + 0x8f, 0x80, 0x97, 0x32, 0x84, 0x40, 0xcc, 0x02, + 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd, 0x80, + 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81, 0x41, + 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2, 0x80, + 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80, 0x41, + 0x01, 0x00, 0x81, 0xd0, 0x80, 0x56, 0xae, 0x8e, + 0x60, 0x36, 0x99, 0x84, 0xba, 0x86, 0x44, 0x57, + 0x90, 0xcf, 0x81, 0x60, 0x3f, 0xfd, 0x18, 0x30, + 0x81, 0x5f, 0x00, 0xad, 0x81, 0x96, 0x42, 0x1f, + 0x12, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x4e, 0x81, + 0xbd, 0x40, 0xc1, 0x86, 0x41, 0x76, 0x80, 0xbc, + 0x83, 0x45, 0xdf, 0x86, 0xec, 0x10, 0x82, +}; + +static const uint8_t unicode_prop_Extender_table[92] = { + 0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d, + 0x80, 0x41, 0xb8, 0x80, 0x43, 0x59, 0x80, 0x42, + 0xef, 0x80, 0xfe, 0x80, 0x49, 0x42, 0x80, 0xb7, + 0x80, 0x42, 0x62, 0x80, 0x41, 0x8d, 0x80, 0xc3, + 0x80, 0x53, 0x88, 0x80, 0xaa, 0x84, 0xe6, 0x81, + 0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80, 0x45, 0xf5, + 0x80, 0x43, 0xc1, 0x80, 0x95, 0x80, 0x40, 0x88, + 0x80, 0xeb, 0x80, 0x94, 0x81, 0x60, 0x54, 0x7a, + 0x80, 0x48, 0x0f, 0x81, 0x4b, 0xd9, 0x80, 0x42, + 0x67, 0x82, 0x44, 0xce, 0x80, 0x60, 0x50, 0xa8, + 0x81, 0x44, 0x9b, 0x08, 0x80, 0x60, 0x71, 0x57, + 0x81, 0x48, 0x05, 0x82, +}; + +static const uint8_t unicode_prop_Hex_Digit_table[12] = { + 0xaf, 0x89, 0x35, 0x99, 0x85, 0x60, 0xfe, 0xa8, + 0x89, 0x35, 0x99, 0x85, +}; + +static const uint8_t unicode_prop_IDS_Binary_Operator_table[5] = { + 0x60, 0x2f, 0xef, 0x09, 0x87, +}; + +static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = { + 0x60, 0x2f, 0xf1, 0x81, +}; + +static const uint8_t unicode_prop_Ideographic_table[69] = { + 0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82, + 0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff, + 0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60, + 0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44, + 0xd5, 0xa9, 0x88, 0x60, 0x24, 0x66, 0x41, 0x8b, + 0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f, 0x50, + 0x39, 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, + 0x5d, 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1, + 0x53, 0x4a, 0x84, 0x50, 0x5f, +}; + +static const uint8_t unicode_prop_Join_Control_table[4] = { + 0x60, 0x20, 0x0b, 0x81, +}; + +static const uint8_t unicode_prop_Logical_Order_Exception_table[15] = { + 0x4e, 0x3f, 0x84, 0xfa, 0x84, 0x4a, 0xef, 0x11, + 0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81, +}; + +static const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = { + 0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60, + 0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, +}; + +static const uint8_t unicode_prop_Pattern_Syntax_table[58] = { + 0xa0, 0x8e, 0x89, 0x86, 0x99, 0x18, 0x80, 0x99, + 0x83, 0xa1, 0x30, 0x00, 0x08, 0x00, 0x0b, 0x03, + 0x02, 0x80, 0x96, 0x80, 0x9e, 0x80, 0x5f, 0x17, + 0x97, 0x87, 0x8e, 0x81, 0x92, 0x80, 0x89, 0x41, + 0x30, 0x42, 0xcf, 0x40, 0x9f, 0x42, 0x75, 0x9d, + 0x44, 0x6b, 0x41, 0xff, 0xff, 0x41, 0x80, 0x13, + 0x98, 0x8e, 0x80, 0x60, 0xcd, 0x0c, 0x81, 0x41, + 0x04, 0x81, +}; + +static const uint8_t unicode_prop_Pattern_White_Space_table[11] = { + 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x5f, 0x87, + 0x81, 0x97, 0x81, +}; + +static const uint8_t unicode_prop_Quotation_Mark_table[31] = { + 0xa1, 0x03, 0x80, 0x40, 0x82, 0x80, 0x8e, 0x80, + 0x5f, 0x5b, 0x87, 0x98, 0x81, 0x4e, 0x06, 0x80, + 0x41, 0xc8, 0x83, 0x8c, 0x82, 0x60, 0xce, 0x20, + 0x83, 0x40, 0xbc, 0x03, 0x80, 0xd9, 0x81, +}; + +static const uint8_t unicode_prop_Radical_table[9] = { + 0x60, 0x2e, 0x7f, 0x99, 0x80, 0xd8, 0x8b, 0x40, + 0xd5, +}; + +static const uint8_t unicode_prop_Regional_Indicator_table[4] = { + 0x61, 0xf1, 0xe5, 0x99, +}; + +static const uint8_t unicode_prop_Sentence_Terminal_table[196] = { + 0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48, + 0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa, + 0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81, + 0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15, + 0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81, + 0x40, 0xcb, 0x04, 0x80, 0x41, 0x39, 0x81, 0x41, + 0x61, 0x83, 0x40, 0xad, 0x09, 0x81, 0x9c, 0x81, + 0x40, 0xbb, 0x81, 0xc0, 0x81, 0x43, 0xbb, 0x81, + 0x88, 0x82, 0x4d, 0xe3, 0x80, 0x8c, 0x80, 0x95, + 0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb, 0x80, + 0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80, 0x41, + 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x97, + 0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81, 0x40, + 0xf8, 0x80, 0x60, 0x52, 0x65, 0x02, 0x81, 0x40, + 0xa8, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0xc0, 0x80, + 0x4a, 0xf3, 0x81, 0x44, 0xfc, 0x84, 0xab, 0x83, + 0x40, 0xbc, 0x81, 0xf4, 0x83, 0xfe, 0x82, 0x40, + 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x08, 0x81, + 0xeb, 0x80, 0x41, 0xa0, 0x81, 0x41, 0x74, 0x0c, + 0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, + 0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41, + 0xa3, 0x81, 0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60, + 0x4b, 0x28, 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, + 0x8a, 0x80, 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05, + 0x80, 0x5d, 0xe7, 0x80, +}; + +static const uint8_t unicode_prop_Soft_Dotted_table[79] = { + 0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80, + 0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f, + 0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2, + 0x80, 0x8c, 0x02, 0x80, 0x40, 0x83, 0x80, 0x40, + 0x9c, 0x80, 0x41, 0xa4, 0x80, 0x40, 0xd5, 0x81, + 0x4b, 0x31, 0x80, 0x61, 0xa7, 0xa4, 0x81, 0xb1, + 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, + 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, + 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0x48, + 0x85, 0x80, 0x41, 0x30, 0x81, 0x99, 0x80, +}; + +static const uint8_t unicode_prop_Terminal_Punctuation_table[248] = { + 0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80, + 0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8, + 0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3, + 0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5, + 0x8e, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44, 0xf3, + 0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36, 0x81, + 0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb, 0x82, + 0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6, 0x19, + 0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83, 0x40, + 0xad, 0x08, 0x82, 0x9c, 0x81, 0x40, 0xbb, 0x84, + 0xbd, 0x81, 0x43, 0xbb, 0x81, 0x88, 0x82, 0x4d, + 0xe3, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a, + 0x81, 0x41, 0xab, 0x81, 0x60, 0x74, 0xfa, 0x81, + 0x41, 0x0c, 0x82, 0x40, 0xe2, 0x84, 0x41, 0x7d, + 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x96, 0x82, + 0x40, 0x92, 0x82, 0xfe, 0x80, 0x8f, 0x81, 0x40, + 0xf8, 0x80, 0x60, 0x52, 0x63, 0x10, 0x83, 0x40, + 0xa8, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80, + 0xc0, 0x01, 0x80, 0x44, 0x39, 0x80, 0xaf, 0x80, + 0x44, 0x85, 0x80, 0x40, 0xc6, 0x80, 0x41, 0x35, + 0x81, 0x40, 0x97, 0x85, 0xc3, 0x85, 0xd8, 0x83, + 0x43, 0xb7, 0x84, 0xab, 0x83, 0x40, 0xbc, 0x86, + 0xef, 0x83, 0xfe, 0x82, 0x40, 0x80, 0x0d, 0x80, + 0x8f, 0x81, 0xd7, 0x84, 0xeb, 0x80, 0x41, 0xa0, + 0x82, 0x8b, 0x81, 0x41, 0x65, 0x1a, 0x8e, 0xe8, + 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80, + 0x40, 0xfa, 0x81, 0xd6, 0x0b, 0x81, 0x41, 0x9d, + 0x82, 0xac, 0x80, 0x42, 0x84, 0x81, 0xc9, 0x81, + 0x45, 0x2a, 0x84, 0x60, 0x45, 0xf8, 0x81, 0x40, + 0x84, 0x80, 0xc0, 0x82, 0x89, 0x80, 0x43, 0x51, + 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83, +}; + +static const uint8_t unicode_prop_Unified_Ideograph_table[45] = { + 0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51, + 0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89, + 0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60, + 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, 0xdd, + 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e, + 0x53, 0x4a, 0x84, 0x50, 0x5f, +}; + +static const uint8_t unicode_prop_Variation_Selector_table[13] = { + 0x58, 0x0a, 0x10, 0x80, 0x60, 0xe5, 0xef, 0x8f, + 0x6d, 0x02, 0xef, 0x40, 0xef, +}; + +static const uint8_t unicode_prop_White_Space_table[22] = { + 0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80, + 0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c, + 0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80, +}; + +static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = { + 0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80, + 0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e, + 0x7d, 0x83, 0x47, 0x5c, 0x81, 0x49, 0x9b, 0x81, + 0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0, + 0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18, + 0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23, + 0x88, 0x08, 0x00, 0x39, 0x9e, 0x0b, 0x20, 0x88, + 0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81, + 0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d, + 0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d, + 0x41, 0x92, 0x95, 0x0d, 0x80, 0x8d, 0x38, 0x35, + 0x10, 0x1c, 0x01, 0x0c, 0x18, 0x02, 0x09, 0x89, + 0x29, 0x81, 0x8b, 0x92, 0x03, 0x08, 0x00, 0x08, + 0x03, 0x21, 0x2a, 0x97, 0x81, 0x8a, 0x0b, 0x18, + 0x09, 0x0b, 0xaa, 0x0f, 0x80, 0xa7, 0x20, 0x00, + 0x14, 0x22, 0x18, 0x14, 0x00, 0x40, 0xff, 0x80, + 0x42, 0x02, 0x1a, 0x08, 0x81, 0x8d, 0x09, 0x89, + 0xaa, 0x87, 0x41, 0xaa, 0x89, 0x0f, 0x60, 0xce, + 0x3c, 0x2c, 0x81, 0x40, 0xa1, 0x81, 0x91, 0x00, + 0x80, 0x9b, 0x00, 0x80, 0x9c, 0x00, 0x00, 0x08, + 0x81, 0x60, 0xd7, 0x76, 0x80, 0xb8, 0x80, 0xb8, + 0x80, 0xb8, 0x80, 0xb8, 0x80, +}; + +static const uint8_t unicode_prop_Emoji_table[239] = { + 0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f, + 0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95, + 0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81, + 0x8b, 0x80, 0x40, 0xa5, 0x80, 0x98, 0x8a, 0x1a, + 0x40, 0xc6, 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, + 0x88, 0x80, 0xb9, 0x18, 0x84, 0x88, 0x01, 0x01, + 0x09, 0x03, 0x01, 0x00, 0x09, 0x02, 0x02, 0x0f, + 0x14, 0x00, 0x04, 0x8b, 0x8a, 0x09, 0x00, 0x08, + 0x80, 0x91, 0x01, 0x81, 0x91, 0x28, 0x00, 0x0a, + 0x0c, 0x01, 0x0b, 0x81, 0x8a, 0x0c, 0x09, 0x04, + 0x08, 0x00, 0x81, 0x93, 0x0c, 0x28, 0x19, 0x03, + 0x01, 0x01, 0x28, 0x01, 0x00, 0x00, 0x05, 0x02, + 0x05, 0x80, 0x89, 0x81, 0x8e, 0x01, 0x03, 0x00, + 0x03, 0x10, 0x80, 0x8a, 0x81, 0xaf, 0x82, 0x88, + 0x80, 0x8d, 0x80, 0x8d, 0x80, 0x41, 0x73, 0x81, + 0x41, 0xce, 0x82, 0x92, 0x81, 0xb2, 0x03, 0x80, + 0x44, 0xd9, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00, + 0x80, 0x61, 0xbd, 0x69, 0x80, 0x40, 0xc9, 0x80, + 0x40, 0x9f, 0x81, 0x8b, 0x81, 0x8d, 0x01, 0x89, + 0xca, 0x99, 0x01, 0x96, 0x80, 0x93, 0x01, 0x88, + 0x94, 0x81, 0x40, 0xad, 0xa1, 0x81, 0xef, 0x09, + 0x02, 0x81, 0xd2, 0x0a, 0x80, 0x41, 0x06, 0x80, + 0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01, + 0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88, + 0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05, + 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x83, + 0x89, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, + 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80, + 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88, 0x86, 0xad, + 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86, 0x88, +}; + +static const uint8_t unicode_prop_Emoji_Component_table[28] = { + 0xa2, 0x05, 0x04, 0x89, 0x5f, 0xd2, 0x80, 0x40, + 0xd4, 0x80, 0x60, 0xdd, 0x2a, 0x80, 0x60, 0xf3, + 0xd5, 0x99, 0x41, 0xfa, 0x84, 0x45, 0xaf, 0x83, + 0x6c, 0x06, 0x6b, 0xdf, +}; + +static const uint8_t unicode_prop_Emoji_Modifier_table[4] = { + 0x61, 0xf3, 0xfa, 0x84, +}; + +static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = { + 0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f, + 0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01, + 0x82, 0xf4, 0x09, 0x8a, 0x94, 0x92, 0x10, 0x1a, + 0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8, 0x0b, + 0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12, 0x84, + 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80, + 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89, + 0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90, + 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88, +}; + +static const uint8_t unicode_prop_Emoji_Presentation_table[145] = { + 0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01, + 0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b, + 0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90, + 0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03, + 0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00, + 0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d, + 0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61, + 0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd, + 0x01, 0x89, 0xca, 0x99, 0x00, 0x97, 0x80, 0x93, + 0x01, 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0, + 0x8b, 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa, + 0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80, + 0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91, + 0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf, + 0xc5, 0x28, 0x12, 0x0a, 0x1b, 0x8a, 0x0e, 0x88, + 0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, + 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88, + 0x86, 0xad, 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86, + 0x88, +}; + +static const uint8_t unicode_prop_Extended_Pictographic_table[156] = { + 0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b, + 0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85, + 0x8e, 0x81, 0x41, 0x6e, 0x81, 0x8b, 0x80, 0xde, + 0x80, 0xc5, 0x80, 0x98, 0x8a, 0x1a, 0x40, 0xc6, + 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80, + 0xb9, 0x18, 0x28, 0x8b, 0x80, 0xf1, 0x89, 0xf5, + 0x81, 0x8a, 0x00, 0x00, 0x28, 0x10, 0x28, 0x89, + 0x81, 0x8e, 0x01, 0x03, 0x00, 0x03, 0x10, 0x80, + 0x8a, 0x84, 0xac, 0x82, 0x88, 0x80, 0x8d, 0x80, + 0x8d, 0x80, 0x41, 0x73, 0x81, 0x41, 0xce, 0x82, + 0x92, 0x81, 0xb2, 0x03, 0x80, 0x44, 0xd9, 0x80, + 0x8b, 0x80, 0x42, 0x58, 0x00, 0x80, 0x61, 0xbd, + 0x65, 0x40, 0xff, 0x8c, 0x82, 0x9e, 0x80, 0xbb, + 0x85, 0x8b, 0x81, 0x8d, 0x01, 0x89, 0x91, 0xb8, + 0x9a, 0x8e, 0x89, 0x80, 0x93, 0x01, 0x88, 0x03, + 0x88, 0x41, 0xb1, 0x84, 0x41, 0x3d, 0x87, 0x41, + 0x09, 0xaf, 0xff, 0xf3, 0x8b, 0xd4, 0xaa, 0x8b, + 0x83, 0xb7, 0x87, 0x89, 0x85, 0xa7, 0x87, 0x9d, + 0xd1, 0x8b, 0xae, 0x80, 0x89, 0x80, 0x41, 0xb8, + 0x40, 0xff, 0x43, 0xfd, +}; + +static const uint8_t unicode_prop_Default_Ignorable_Code_Point_table[51] = { + 0x40, 0xac, 0x80, 0x42, 0xa0, 0x80, 0x42, 0xcb, + 0x80, 0x4b, 0x41, 0x81, 0x46, 0x52, 0x81, 0xd4, + 0x84, 0x47, 0xfa, 0x84, 0x99, 0x84, 0xb0, 0x8f, + 0x50, 0xf3, 0x80, 0x60, 0xcc, 0x9a, 0x8f, 0x40, + 0xee, 0x80, 0x40, 0x9f, 0x80, 0xce, 0x88, 0x60, + 0xbc, 0xa6, 0x83, 0x54, 0xce, 0x87, 0x6c, 0x2e, + 0x84, 0x4f, 0xff, +}; + +typedef enum { + UNICODE_PROP_Hyphen, + UNICODE_PROP_Other_Math, + UNICODE_PROP_Other_Alphabetic, + UNICODE_PROP_Other_Lowercase, + UNICODE_PROP_Other_Uppercase, + UNICODE_PROP_Other_Grapheme_Extend, + UNICODE_PROP_Other_Default_Ignorable_Code_Point, + UNICODE_PROP_Other_ID_Start, + UNICODE_PROP_Other_ID_Continue, + UNICODE_PROP_Prepended_Concatenation_Mark, + UNICODE_PROP_ID_Continue1, + UNICODE_PROP_XID_Start1, + UNICODE_PROP_XID_Continue1, + UNICODE_PROP_Changes_When_Titlecased1, + UNICODE_PROP_Changes_When_Casefolded1, + UNICODE_PROP_Changes_When_NFKC_Casefolded1, + UNICODE_PROP_ASCII_Hex_Digit, + UNICODE_PROP_Bidi_Control, + UNICODE_PROP_Dash, + UNICODE_PROP_Deprecated, + UNICODE_PROP_Diacritic, + UNICODE_PROP_Extender, + UNICODE_PROP_Hex_Digit, + UNICODE_PROP_IDS_Binary_Operator, + UNICODE_PROP_IDS_Trinary_Operator, + UNICODE_PROP_Ideographic, + UNICODE_PROP_Join_Control, + UNICODE_PROP_Logical_Order_Exception, + UNICODE_PROP_Noncharacter_Code_Point, + UNICODE_PROP_Pattern_Syntax, + UNICODE_PROP_Pattern_White_Space, + UNICODE_PROP_Quotation_Mark, + UNICODE_PROP_Radical, + UNICODE_PROP_Regional_Indicator, + UNICODE_PROP_Sentence_Terminal, + UNICODE_PROP_Soft_Dotted, + UNICODE_PROP_Terminal_Punctuation, + UNICODE_PROP_Unified_Ideograph, + UNICODE_PROP_Variation_Selector, + UNICODE_PROP_White_Space, + UNICODE_PROP_Bidi_Mirrored, + UNICODE_PROP_Emoji, + UNICODE_PROP_Emoji_Component, + UNICODE_PROP_Emoji_Modifier, + UNICODE_PROP_Emoji_Modifier_Base, + UNICODE_PROP_Emoji_Presentation, + UNICODE_PROP_Extended_Pictographic, + UNICODE_PROP_Default_Ignorable_Code_Point, + UNICODE_PROP_ID_Start, + UNICODE_PROP_Case_Ignorable, + UNICODE_PROP_ASCII, + UNICODE_PROP_Alphabetic, + UNICODE_PROP_Any, + UNICODE_PROP_Assigned, + UNICODE_PROP_Cased, + UNICODE_PROP_Changes_When_Casefolded, + UNICODE_PROP_Changes_When_Casemapped, + UNICODE_PROP_Changes_When_Lowercased, + UNICODE_PROP_Changes_When_NFKC_Casefolded, + UNICODE_PROP_Changes_When_Titlecased, + UNICODE_PROP_Changes_When_Uppercased, + UNICODE_PROP_Grapheme_Base, + UNICODE_PROP_Grapheme_Extend, + UNICODE_PROP_ID_Continue, + UNICODE_PROP_Lowercase, + UNICODE_PROP_Math, + UNICODE_PROP_Uppercase, + UNICODE_PROP_XID_Continue, + UNICODE_PROP_XID_Start, + UNICODE_PROP_Cased1, + UNICODE_PROP_COUNT, +} UnicodePropertyEnum; + +static const char unicode_prop_name_table[] = + "ASCII_Hex_Digit,AHex" "\0" + "Bidi_Control,Bidi_C" "\0" + "Dash" "\0" + "Deprecated,Dep" "\0" + "Diacritic,Dia" "\0" + "Extender,Ext" "\0" + "Hex_Digit,Hex" "\0" + "IDS_Binary_Operator,IDSB" "\0" + "IDS_Trinary_Operator,IDST" "\0" + "Ideographic,Ideo" "\0" + "Join_Control,Join_C" "\0" + "Logical_Order_Exception,LOE" "\0" + "Noncharacter_Code_Point,NChar" "\0" + "Pattern_Syntax,Pat_Syn" "\0" + "Pattern_White_Space,Pat_WS" "\0" + "Quotation_Mark,QMark" "\0" + "Radical" "\0" + "Regional_Indicator,RI" "\0" + "Sentence_Terminal,STerm" "\0" + "Soft_Dotted,SD" "\0" + "Terminal_Punctuation,Term" "\0" + "Unified_Ideograph,UIdeo" "\0" + "Variation_Selector,VS" "\0" + "White_Space,space" "\0" + "Bidi_Mirrored,Bidi_M" "\0" + "Emoji" "\0" + "Emoji_Component,EComp" "\0" + "Emoji_Modifier,EMod" "\0" + "Emoji_Modifier_Base,EBase" "\0" + "Emoji_Presentation,EPres" "\0" + "Extended_Pictographic,ExtPict" "\0" + "Default_Ignorable_Code_Point,DI" "\0" + "ID_Start,IDS" "\0" + "Case_Ignorable,CI" "\0" + "ASCII" "\0" + "Alphabetic,Alpha" "\0" + "Any" "\0" + "Assigned" "\0" + "Cased" "\0" + "Changes_When_Casefolded,CWCF" "\0" + "Changes_When_Casemapped,CWCM" "\0" + "Changes_When_Lowercased,CWL" "\0" + "Changes_When_NFKC_Casefolded,CWKCF" "\0" + "Changes_When_Titlecased,CWT" "\0" + "Changes_When_Uppercased,CWU" "\0" + "Grapheme_Base,Gr_Base" "\0" + "Grapheme_Extend,Gr_Ext" "\0" + "ID_Continue,IDC" "\0" + "Lowercase,Lower" "\0" + "Math" "\0" + "Uppercase,Upper" "\0" + "XID_Continue,XIDC" "\0" + "XID_Start,XIDS" "\0" +; + +static const uint8_t * const unicode_prop_table[] = { + unicode_prop_Hyphen_table, + unicode_prop_Other_Math_table, + unicode_prop_Other_Alphabetic_table, + unicode_prop_Other_Lowercase_table, + unicode_prop_Other_Uppercase_table, + unicode_prop_Other_Grapheme_Extend_table, + unicode_prop_Other_Default_Ignorable_Code_Point_table, + unicode_prop_Other_ID_Start_table, + unicode_prop_Other_ID_Continue_table, + unicode_prop_Prepended_Concatenation_Mark_table, + unicode_prop_ID_Continue1_table, + unicode_prop_XID_Start1_table, + unicode_prop_XID_Continue1_table, + unicode_prop_Changes_When_Titlecased1_table, + unicode_prop_Changes_When_Casefolded1_table, + unicode_prop_Changes_When_NFKC_Casefolded1_table, + unicode_prop_ASCII_Hex_Digit_table, + unicode_prop_Bidi_Control_table, + unicode_prop_Dash_table, + unicode_prop_Deprecated_table, + unicode_prop_Diacritic_table, + unicode_prop_Extender_table, + unicode_prop_Hex_Digit_table, + unicode_prop_IDS_Binary_Operator_table, + unicode_prop_IDS_Trinary_Operator_table, + unicode_prop_Ideographic_table, + unicode_prop_Join_Control_table, + unicode_prop_Logical_Order_Exception_table, + unicode_prop_Noncharacter_Code_Point_table, + unicode_prop_Pattern_Syntax_table, + unicode_prop_Pattern_White_Space_table, + unicode_prop_Quotation_Mark_table, + unicode_prop_Radical_table, + unicode_prop_Regional_Indicator_table, + unicode_prop_Sentence_Terminal_table, + unicode_prop_Soft_Dotted_table, + unicode_prop_Terminal_Punctuation_table, + unicode_prop_Unified_Ideograph_table, + unicode_prop_Variation_Selector_table, + unicode_prop_White_Space_table, + unicode_prop_Bidi_Mirrored_table, + unicode_prop_Emoji_table, + unicode_prop_Emoji_Component_table, + unicode_prop_Emoji_Modifier_table, + unicode_prop_Emoji_Modifier_Base_table, + unicode_prop_Emoji_Presentation_table, + unicode_prop_Extended_Pictographic_table, + unicode_prop_Default_Ignorable_Code_Point_table, + unicode_prop_ID_Start_table, + unicode_prop_Case_Ignorable_table, +}; + +static const uint16_t unicode_prop_len_table[] = { + countof(unicode_prop_Hyphen_table), + countof(unicode_prop_Other_Math_table), + countof(unicode_prop_Other_Alphabetic_table), + countof(unicode_prop_Other_Lowercase_table), + countof(unicode_prop_Other_Uppercase_table), + countof(unicode_prop_Other_Grapheme_Extend_table), + countof(unicode_prop_Other_Default_Ignorable_Code_Point_table), + countof(unicode_prop_Other_ID_Start_table), + countof(unicode_prop_Other_ID_Continue_table), + countof(unicode_prop_Prepended_Concatenation_Mark_table), + countof(unicode_prop_ID_Continue1_table), + countof(unicode_prop_XID_Start1_table), + countof(unicode_prop_XID_Continue1_table), + countof(unicode_prop_Changes_When_Titlecased1_table), + countof(unicode_prop_Changes_When_Casefolded1_table), + countof(unicode_prop_Changes_When_NFKC_Casefolded1_table), + countof(unicode_prop_ASCII_Hex_Digit_table), + countof(unicode_prop_Bidi_Control_table), + countof(unicode_prop_Dash_table), + countof(unicode_prop_Deprecated_table), + countof(unicode_prop_Diacritic_table), + countof(unicode_prop_Extender_table), + countof(unicode_prop_Hex_Digit_table), + countof(unicode_prop_IDS_Binary_Operator_table), + countof(unicode_prop_IDS_Trinary_Operator_table), + countof(unicode_prop_Ideographic_table), + countof(unicode_prop_Join_Control_table), + countof(unicode_prop_Logical_Order_Exception_table), + countof(unicode_prop_Noncharacter_Code_Point_table), + countof(unicode_prop_Pattern_Syntax_table), + countof(unicode_prop_Pattern_White_Space_table), + countof(unicode_prop_Quotation_Mark_table), + countof(unicode_prop_Radical_table), + countof(unicode_prop_Regional_Indicator_table), + countof(unicode_prop_Sentence_Terminal_table), + countof(unicode_prop_Soft_Dotted_table), + countof(unicode_prop_Terminal_Punctuation_table), + countof(unicode_prop_Unified_Ideograph_table), + countof(unicode_prop_Variation_Selector_table), + countof(unicode_prop_White_Space_table), + countof(unicode_prop_Bidi_Mirrored_table), + countof(unicode_prop_Emoji_table), + countof(unicode_prop_Emoji_Component_table), + countof(unicode_prop_Emoji_Modifier_table), + countof(unicode_prop_Emoji_Modifier_Base_table), + countof(unicode_prop_Emoji_Presentation_table), + countof(unicode_prop_Extended_Pictographic_table), + countof(unicode_prop_Default_Ignorable_Code_Point_table), + countof(unicode_prop_ID_Start_table), + countof(unicode_prop_Case_Ignorable_table), +}; + +#endif /* CONFIG_ALL_UNICODE */ diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode.c b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode.c similarity index 82% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode.c rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode.c index 63c12a07..0712a6c0 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode.c +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode.c @@ -43,11 +43,111 @@ enum { RUN_TYPE_UF_D1_EXT, RUN_TYPE_U_EXT, RUN_TYPE_LF_EXT, - RUN_TYPE_U_EXT2, - RUN_TYPE_L_EXT2, - RUN_TYPE_U_EXT3, + RUN_TYPE_UF_EXT2, + RUN_TYPE_LF_EXT2, + RUN_TYPE_UF_EXT3, }; +static int lre_case_conv1(uint32_t c, int conv_type) +{ + uint32_t res[LRE_CC_RES_LEN_MAX]; + lre_case_conv(res, c, conv_type); + return res[0]; +} + +/* case conversion using the table entry 'idx' with value 'v' */ +static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v) +{ + uint32_t code, data, type, a, is_lower; + is_lower = (conv_type != 0); + type = (v >> (32 - 17 - 7 - 4)) & 0xf; + data = ((v & 0xf) << 8) | case_conv_table2[idx]; + code = v >> (32 - 17); + switch(type) { + case RUN_TYPE_U: + case RUN_TYPE_L: + case RUN_TYPE_UF: + case RUN_TYPE_LF: + if (conv_type == (type & 1) || + (type >= RUN_TYPE_UF && conv_type == 2)) { + c = c - code + (case_conv_table1[data] >> (32 - 17)); + } + break; + case RUN_TYPE_UL: + a = c - code; + if ((a & 1) != (1 - is_lower)) + break; + c = (a ^ 1) + code; + break; + case RUN_TYPE_LSU: + a = c - code; + if (a == 1) { + c += 2 * is_lower - 1; + } else if (a == (1 - is_lower) * 2) { + c += (2 * is_lower - 1) * 2; + } + break; + case RUN_TYPE_U2L_399_EXT2: + if (!is_lower) { + res[0] = c - code + case_conv_ext[data >> 6]; + res[1] = 0x399; + return 2; + } else { + c = c - code + case_conv_ext[data & 0x3f]; + } + break; + case RUN_TYPE_UF_D20: + if (conv_type == 1) + break; + c = data + (conv_type == 2) * 0x20; + break; + case RUN_TYPE_UF_D1_EXT: + if (conv_type == 1) + break; + c = case_conv_ext[data] + (conv_type == 2); + break; + case RUN_TYPE_U_EXT: + case RUN_TYPE_LF_EXT: + if (is_lower != (type - RUN_TYPE_U_EXT)) + break; + c = case_conv_ext[data]; + break; + case RUN_TYPE_LF_EXT2: + if (!is_lower) + break; + res[0] = c - code + case_conv_ext[data >> 6]; + res[1] = case_conv_ext[data & 0x3f]; + return 2; + case RUN_TYPE_UF_EXT2: + if (conv_type == 1) + break; + res[0] = c - code + case_conv_ext[data >> 6]; + res[1] = case_conv_ext[data & 0x3f]; + if (conv_type == 2) { + /* convert to lower */ + res[0] = lre_case_conv1(res[0], 1); + res[1] = lre_case_conv1(res[1], 1); + } + return 2; + default: + case RUN_TYPE_UF_EXT3: + if (conv_type == 1) + break; + res[0] = case_conv_ext[data >> 8]; + res[1] = case_conv_ext[(data >> 4) & 0xf]; + res[2] = case_conv_ext[data & 0xf]; + if (conv_type == 2) { + /* convert to lower */ + res[0] = lre_case_conv1(res[0], 1); + res[1] = lre_case_conv1(res[1], 1); + res[2] = lre_case_conv1(res[2], 1); + } + return 3; + } + res[0] = c; + return 1; +} + /* conv_type: 0 = to upper 1 = to lower @@ -66,10 +166,9 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) } } } else { - uint32_t v, code, data, type, len, a, is_lower; + uint32_t v, code, len; int idx, idx_min, idx_max; - is_lower = (conv_type != 0); idx_min = 0; idx_max = countof(case_conv_table1) - 1; while (idx_min <= idx_max) { @@ -82,74 +181,7 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) } else if (c >= code + len) { idx_min = idx + 1; } else { - type = (v >> (32 - 17 - 7 - 4)) & 0xf; - data = ((v & 0xf) << 8) | case_conv_table2[idx]; - switch(type) { - case RUN_TYPE_U: - case RUN_TYPE_L: - case RUN_TYPE_UF: - case RUN_TYPE_LF: - if (conv_type == (type & 1) || - (type >= RUN_TYPE_UF && conv_type == 2)) { - c = c - code + (case_conv_table1[data] >> (32 - 17)); - } - break; - case RUN_TYPE_UL: - a = c - code; - if ((a & 1) != (1 - is_lower)) - break; - c = (a ^ 1) + code; - break; - case RUN_TYPE_LSU: - a = c - code; - if (a == 1) { - c += 2 * is_lower - 1; - } else if (a == (1 - is_lower) * 2) { - c += (2 * is_lower - 1) * 2; - } - break; - case RUN_TYPE_U2L_399_EXT2: - if (!is_lower) { - res[0] = c - code + case_conv_ext[data >> 6]; - res[1] = 0x399; - return 2; - } else { - c = c - code + case_conv_ext[data & 0x3f]; - } - break; - case RUN_TYPE_UF_D20: - if (conv_type == 1) - break; - c = data + (conv_type == 2) * 0x20; - break; - case RUN_TYPE_UF_D1_EXT: - if (conv_type == 1) - break; - c = case_conv_ext[data] + (conv_type == 2); - break; - case RUN_TYPE_U_EXT: - case RUN_TYPE_LF_EXT: - if (is_lower != (type - RUN_TYPE_U_EXT)) - break; - c = case_conv_ext[data]; - break; - case RUN_TYPE_U_EXT2: - case RUN_TYPE_L_EXT2: - if (conv_type != (type - RUN_TYPE_U_EXT2)) - break; - res[0] = c - code + case_conv_ext[data >> 6]; - res[1] = case_conv_ext[data & 0x3f]; - return 2; - default: - case RUN_TYPE_U_EXT3: - if (conv_type != 0) - break; - res[0] = case_conv_ext[data >> 8]; - res[1] = case_conv_ext[(data >> 4) & 0xf]; - res[2] = case_conv_ext[data & 0xf]; - return 3; - } - break; + return lre_case_conv_entry(res, c, conv_type, idx, v); } } } @@ -157,6 +189,77 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) return 1; } +static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_unicode) +{ + uint32_t res[LRE_CC_RES_LEN_MAX]; + int len; + + if (is_unicode) { + len = lre_case_conv_entry(res, c, 2, idx, v); + if (len == 1) { + c = res[0]; + } else { + /* handle the few specific multi-character cases (see + unicode_gen.c:dump_case_folding_special_cases()) */ + if (c == 0xfb06) { + c = 0xfb05; + } else if (c == 0x01fd3) { + c = 0x390; + } else if (c == 0x01fe3) { + c = 0x3b0; + } + } + } else { + if (likely(c < 128)) { + if (c >= 'a' && c <= 'z') + c = c - 'a' + 'A'; + } else { + /* legacy regexp: to upper case if single char >= 128 */ + len = lre_case_conv_entry(res, c, FALSE, idx, v); + if (len == 1 && res[0] >= 128) + c = res[0]; + } + } + return c; +} + +/* JS regexp specific rules for case folding */ +int lre_canonicalize(uint32_t c, BOOL is_unicode) +{ + if (c < 128) { + /* fast case */ + if (is_unicode) { + if (c >= 'A' && c <= 'Z') { + c = c - 'A' + 'a'; + } + } else { + if (c >= 'a' && c <= 'z') { + c = c - 'a' + 'A'; + } + } + } else { + uint32_t v, code, len; + int idx, idx_min, idx_max; + + idx_min = 0; + idx_max = countof(case_conv_table1) - 1; + while (idx_min <= idx_max) { + idx = (unsigned)(idx_max + idx_min) / 2; + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + if (c < code) { + idx_max = idx - 1; + } else if (c >= code + len) { + idx_min = idx + 1; + } else { + return lre_case_folding_entry(c, idx, v, is_unicode); + } + } + } + return c; +} + static uint32_t get_le24(const uint8_t *ptr) { #if defined(__x86__) || defined(__x86_64__) @@ -1179,11 +1282,11 @@ static int unicode_case1(CharRange *cr, int case_mask) #define MR(x) (1 << RUN_TYPE_ ## x) const uint32_t tab_run_mask[3] = { MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) | - MR(UF_D1_EXT) | MR(U_EXT) | MR(U_EXT2) | MR(U_EXT3), + MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3), - MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(L_EXT2), + MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2), - MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT), + MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3), }; #undef MR uint32_t mask, v, code, type, len, i, idx; @@ -1236,7 +1339,136 @@ static int unicode_case1(CharRange *cr, int case_mask) } return 0; } - + +static int point_cmp(const void *p1, const void *p2, void *arg) +{ + uint32_t v1 = *(uint32_t *)p1; + uint32_t v2 = *(uint32_t *)p2; + return (v1 > v2) - (v1 < v2); +} + +static void cr_sort_and_remove_overlap(CharRange *cr) +{ + uint32_t start, end, start1, end1, i, j; + + /* the resulting ranges are not necessarily sorted and may overlap */ + rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL); + j = 0; + for(i = 0; i < cr->len; ) { + start = cr->points[i]; + end = cr->points[i + 1]; + i += 2; + while (i < cr->len) { + start1 = cr->points[i]; + end1 = cr->points[i + 1]; + if (start1 > end) { + /* |------| + * |-------| */ + break; + } else if (end1 <= end) { + /* |------| + * |--| */ + i += 2; + } else { + /* |------| + * |-------| */ + end = end1; + i += 2; + } + } + cr->points[j] = start; + cr->points[j + 1] = end; + j += 2; + } + cr->len = j; +} + +/* canonicalize a character set using the JS regex case folding rules + (see lre_canonicalize()) */ +int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode) +{ + CharRange cr_inter, cr_mask, cr_result, cr_sub; + uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d; + + cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func); + cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func); + cr_init(&cr_result, cr->mem_opaque, cr->realloc_func); + cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func); + + if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U)) + goto fail; + if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER)) + goto fail; + + if (cr_invert(&cr_mask)) + goto fail; + if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER)) + goto fail; + + /* cr_inter = cr & cr_mask */ + /* cr_sub = cr & ~cr_mask */ + + /* use the case conversion table to compute the result */ + d_start = -1; + d_end = -1; + idx = 0; + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + for(i = 0; i < cr_inter.len; i += 2) { + start = cr_inter.points[i]; + end = cr_inter.points[i + 1]; + + for(c = start; c < end; c++) { + for(;;) { + if (c >= code && c < code + len) + break; + idx++; + assert(idx < countof(case_conv_table1)); + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + } + d = lre_case_folding_entry(c, idx, v, is_unicode); + /* try to merge with the current interval */ + if (d_start == -1) { + d_start = d; + d_end = d + 1; + } else if (d_end == d) { + d_end++; + } else { + cr_add_interval(&cr_result, d_start, d_end); + d_start = d; + d_end = d + 1; + } + } + } + if (d_start != -1) { + if (cr_add_interval(&cr_result, d_start, d_end)) + goto fail; + } + + /* the resulting ranges are not necessarily sorted and may overlap */ + cr_sort_and_remove_overlap(&cr_result); + + /* or with the character not affected by the case folding */ + cr->len = 0; + if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION)) + goto fail; + + cr_free(&cr_inter); + cr_free(&cr_mask); + cr_free(&cr_result); + cr_free(&cr_sub); + return 0; + fail: + cr_free(&cr_inter); + cr_free(&cr_mask); + cr_free(&cr_result); + cr_free(&cr_sub); + return -1; +} + typedef enum { POP_GC, POP_PROP, diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode.h similarity index 97% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode.h index cfa600a5..8abacb01 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/libunicode.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/libunicode.h @@ -41,6 +41,7 @@ typedef enum { } UnicodeNormalizationEnum; int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); +int lre_canonicalize(uint32_t c, BOOL is_unicode); LRE_BOOL lre_is_cased(uint32_t c); LRE_BOOL lre_is_case_ignorable(uint32_t c); @@ -101,6 +102,8 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, int cr_invert(CharRange *cr); +int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode); + #ifdef CONFIG_ALL_UNICODE LRE_BOOL lre_is_id_start(uint32_t c); diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/list.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/list.h similarity index 96% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/list.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/list.h index 0a1bc5a4..5c182340 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/list.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/list.h @@ -36,8 +36,7 @@ struct list_head { #define LIST_HEAD_INIT(el) { &(el), &(el) } /* return the pointer of type 'type *' containing 'el' as field 'member' */ -#define list_entry(el, type, member) \ - ((type *)((uint8_t *)(el) - offsetof(type, member))) +#define list_entry(el, type, member) container_of(el, type, member) static inline void init_list_head(struct list_head *head) { diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjs.c b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjs.c similarity index 97% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjs.c rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjs.c index d56b8433..77b5cfbc 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjs.c +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjs.c @@ -140,19 +140,19 @@ static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr, } /* default memory allocation functions with memory limitation */ -static inline size_t js_trace_malloc_usable_size(void *ptr) +static size_t js_trace_malloc_usable_size(const void *ptr) { #if defined(__APPLE__) return malloc_size(ptr); #elif defined(_WIN32) - return _msize(ptr); + return _msize((void *)ptr); #elif defined(EMSCRIPTEN) return 0; #elif defined(__linux__) - return malloc_usable_size(ptr); + return malloc_usable_size((void *)ptr); #else /* change this to `return 0;` if compilation fails */ - return malloc_usable_size(ptr); + return malloc_usable_size((void *)ptr); #endif } @@ -264,18 +264,7 @@ static const JSMallocFunctions trace_mf = { js_trace_malloc, js_trace_free, js_trace_realloc, -#if defined(__APPLE__) - malloc_size, -#elif defined(_WIN32) - (size_t (*)(const void *))_msize, -#elif defined(EMSCRIPTEN) - NULL, -#elif defined(__linux__) - (size_t (*)(const void *))malloc_usable_size, -#else - /* change this to `NULL,` if compilation fails */ - malloc_usable_size, -#endif + js_trace_malloc_usable_size, }; #define PROG_NAME "qjs" @@ -454,8 +443,10 @@ int main(int argc, char **argv) } } +#ifdef CONFIG_BIGNUM if (load_jscalc) bignum_ext = 1; +#endif if (trace_memory) { js_trace_malloc_init(&trace_data); diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjsc.c b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjsc.c similarity index 99% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjsc.c rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjsc.c index b9f1e4cd..f8e60b3e 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/qjsc.c +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjsc.c @@ -76,9 +76,7 @@ static const FeatureEntry feature_list[] = { { "promise", "Promise" }, #define FE_MODULE_LOADER 9 { "module-loader", NULL }, -#ifdef CONFIG_BIGNUM { "bigint", "BigInt" }, -#endif }; void namelist_add(namelist_t *lp, const char *name, const char *short_name, @@ -332,6 +330,7 @@ static const char main_c_template1[] = static const char main_c_template2[] = " js_std_loop(ctx);\n" + " js_std_free_handlers(rt);\n" " JS_FreeContext(ctx);\n" " JS_FreeRuntime(rt);\n" " return 0;\n" @@ -345,8 +344,8 @@ void help(void) "usage: " PROG_NAME " [options] [files]\n" "\n" "options are:\n" - "-c only output bytecode in a C file\n" - "-e output main() and bytecode in a C file (default = executable output)\n" + "-c only output bytecode to a C file\n" + "-e output main() and bytecode to a C file (default = executable output)\n" "-o output set the output filename\n" "-N cname set the C name of the generated data\n" "-m compile as Javascript module (default=autodetect)\n" diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjscalc.js b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjscalc.js new file mode 100644 index 00000000..b1ad1e89 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/qjscalc.js @@ -0,0 +1,2657 @@ +/* + * QuickJS Javascript Calculator + * + * Copyright (c) 2017-2020 Fabrice Bellard + * + * 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"; +"use math"; + +var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series, Matrix; + +(function(global) { + global.Integer = global.BigInt; + global.Float = global.BigFloat; + global.algebraicMode = true; + + /* add non enumerable properties */ + function add_props(obj, props) { + var i, val, prop, tab, desc; + tab = Reflect.ownKeys(props); + for(i = 0; i < tab.length; i++) { + prop = tab[i]; + desc = Object.getOwnPropertyDescriptor(props, prop); + desc.enumerable = false; + if ("value" in desc) { + if (typeof desc.value !== "function") { + desc.writable = false; + desc.configurable = false; + } + } else { + /* getter/setter */ + desc.configurable = false; + } + Object.defineProperty(obj, prop, desc); + } + } + + /* same as proto[Symbol.operatorSet] = Operators.create(..op_list) + but allow shortcuts: left: [], right: [] or both + */ + function operators_set(proto, ...op_list) + { + var new_op_list, i, a, j, b, k, obj, tab; + var fields = [ "left", "right" ]; + new_op_list = []; + for(i = 0; i < op_list.length; i++) { + a = op_list[i]; + if (a.left || a.right) { + tab = [ a.left, a.right ]; + delete a.left; + delete a.right; + for(k = 0; k < 2; k++) { + obj = tab[k]; + if (obj) { + if (!Array.isArray(obj)) { + obj = [ obj ]; + } + for(j = 0; j < obj.length; j++) { + b = {}; + Object.assign(b, a); + b[fields[k]] = obj[j]; + new_op_list.push(b); + } + } + } + } else { + new_op_list.push(a); + } + } + proto[Symbol.operatorSet] = + Operators.create.call(null, ...new_op_list); + } + + /* Integer */ + + function generic_pow(a, b) { + var r, is_neg, i; + if (!Integer.isInteger(b)) { + return exp(log(a) * b); + } + if (Array.isArray(a) && !(a instanceof Polynomial || + a instanceof Series)) { + r = idn(Matrix.check_square(a)); + } else { + r = 1; + } + if (b == 0) + return r; + is_neg = false; + if (b < 0) { + is_neg = true; + b = -b; + } + r = a; + for(i = Integer.floorLog2(b) - 1; i >= 0; i--) { + r *= r; + if ((b >> i) & 1) + r *= a; + } + if (is_neg) { + if (typeof r.inverse != "function") + throw "negative powers are not supported for this type"; + r = r.inverse(); + } + return r; + } + + var small_primes = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499 ]; + + function miller_rabin_test(n, t) { + var d, r, s, i, j, a; + d = n - 1; + s = 0; + while ((d & 1) == 0) { + d >>= 1; + s++; + } + if (small_primes.length < t) + t = small_primes.length; + loop: for(j = 0; j < t; j++) { + a = small_primes[j]; + r = Integer.pmod(a, d, n); + if (r == 1 || r == (n - 1)) + continue; + for(i = 1; i < s; i++) { + r = (r * r) % n; + if (r == 1) + return false; + if (r == (n - 1)) + continue loop; + } + return false; /* n is composite */ + } + return true; /* n is probably prime with probability (1-0.5^t) */ + } + + function fact_rec(a, b) { /* assumes a <= b */ + var i, r; + if ((b - a) <= 5) { + r = a; + for(i = a + 1; i <= b; i++) + r *= i; + return r; + } else { + /* to avoid a quadratic running time it is better to + multiply numbers of similar size */ + i = (a + b) >> 1; + return fact_rec(a, i) * fact_rec(i + 1, b); + } + } + + /* math mode specific quirk to overload the integer division and power */ + Operators.updateBigIntOperators( + { + "/"(a, b) { + if (algebraicMode) { + return Fraction.toFraction(a, b); + } else { + return Float(a) / Float(b); + } + }, + "**"(a, b) { + if (algebraicMode) { + return generic_pow(a, b); + } else { + return Float(a) ** Float(b); + } + } + }); + + add_props(Integer, { + isInteger(a) { + /* integers are represented either as bigint or as number */ + return typeof a === "bigint" || + (typeof a === "number" && Number.isSafeInteger(a)); + }, + gcd(a, b) { + var r; + while (b != 0) { + r = a % b; + a = b; + b = r; + } + return a; + }, + fact(n) { + return n <= 0 ? 1 : fact_rec(1, n); + }, + /* binomial coefficient */ + comb(n, k) { + if (k < 0 || k > n) + return 0; + if (k > n - k) + k = n - k; + if (k == 0) + return 1; + return Integer.tdiv(fact_rec(n - k + 1, n), fact_rec(1, k)); + }, + /* inverse of x modulo y */ + invmod(x, y) { + var q, u, v, a, c, t; + u = x; + v = y; + c = 1; + a = 0; + while (u != 0) { + t = Integer.fdivrem(v, u); + q = t[0]; + v = u; + u = t[1]; + t = c; + c = a - q * c; + a = t; + } + /* v = gcd(x, y) */ + if (v != 1) + throw RangeError("not invertible"); + return a % y; + }, + /* return a ^ b modulo m */ + pmod(a, b, m) { + var r; + if (b == 0) + return 1; + if (b < 0) { + a = Integer.invmod(a, m); + b = -b; + } + r = 1; + for(;;) { + if (b & 1) { + r = (r * a) % m; + } + b >>= 1; + if (b == 0) + break; + a = (a * a) % m; + } + return r; + }, + + /* return true if n is prime (or probably prime with + probability 1-0.5^t) */ + isPrime(n, t) { + var i, d, n1; + if (!Integer.isInteger(n)) + throw TypeError("invalid type"); + if (n <= 1) + return false; + n1 = small_primes.length; + /* XXX: need Integer.sqrt() */ + for(i = 0; i < n1; i++) { + d = small_primes[i]; + if (d == n) + return true; + if (d > n) + return false; + if ((n % d) == 0) + return false; + } + if (n < d * d) + return true; + if (typeof t == "undefined") + t = 64; + return miller_rabin_test(n, t); + }, + nextPrime(n) { + if (!Integer.isInteger(n)) + throw TypeError("invalid type"); + if (n < 1) + n = 1; + for(;;) { + n++; + if (Integer.isPrime(n)) + return n; + } + }, + factor(n) { + var r, d; + if (!Integer.isInteger(n)) + throw TypeError("invalid type"); + r = []; + if (abs(n) <= 1) { + r.push(n); + return r; + } + if (n < 0) { + r.push(-1); + n = -n; + } + + while ((n % 2) == 0) { + n >>= 1; + r.push(2); + } + + d = 3; + while (n != 1) { + if (Integer.isPrime(n)) { + r.push(n); + break; + } + /* we are sure there is at least one divisor, so one test */ + for(;;) { + if ((n % d) == 0) + break; + d += 2; + } + for(;;) { + r.push(d); + n = Integer.tdiv(n, d); + if ((n % d) != 0) + break; + } + } + return r; + }, + }); + + add_props(Integer.prototype, { + inverse() { + return 1 / this; + }, + norm2() { + return this * this; + }, + abs() { + var v = this; + if (v < 0) + v = -v; + return v; + }, + conj() { + return this; + }, + arg() { + if (this >= 0) + return 0; + else + return Float.PI; + }, + exp() { + if (this == 0) + return 1; + else + return Float.exp(this); + }, + log() { + if (this == 1) + return 0; + else + return Float(this).log(); + }, + }); + + /* Fraction */ + + Fraction = function Fraction(a, b) + { + var d, r, obj; + + if (new.target) + throw TypeError("not a constructor"); + if (a instanceof Fraction) + return a; + if (!Integer.isInteger(a)) + throw TypeError("integer expected"); + if (typeof b === "undefined") { + b = 1; + } else { + if (!Integer.isInteger(b)) + throw TypeError("integer expected"); + if (b == 0) + throw RangeError("division by zero"); + d = Integer.gcd(a, b); + if (d != 1) { + a = Integer.tdiv(a, d); + b = Integer.tdiv(b, d); + } + + /* the fractions are normalized with den > 0 */ + if (b < 0) { + a = -a; + b = -b; + } + } + obj = Object.create(Fraction.prototype); + obj.num = a; + obj.den = b; + return obj; + } + + function fraction_add(a, b) { + a = Fraction(a); + b = Fraction(b); + return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den); + } + function fraction_sub(a, b) { + a = Fraction(a); + b = Fraction(b); + return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den); + } + function fraction_mul(a, b) { + a = Fraction(a); + b = Fraction(b); + return Fraction.toFraction(a.num * b.num, a.den * b.den); + } + function fraction_div(a, b) { + a = Fraction(a); + b = Fraction(b); + return Fraction.toFraction(a.num * b.den, a.den * b.num); + } + function fraction_mod(a, b) { + var a1 = Fraction(a); + var b1 = Fraction(b); + return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b; + } + function fraction_eq(a, b) { + a = Fraction(a); + b = Fraction(b); + /* we assume the fractions are normalized */ + return (a.num == b.num && a.den == b.den); + } + function fraction_lt(a, b) { + a = Fraction(a); + b = Fraction(b); + return (a.num * b.den < b.num * a.den); + } + + /* operators are needed for fractions */ + function float_add(a, b) { + return Float(a) + Float(b); + } + function float_sub(a, b) { + return Float(a) - Float(b); + } + function float_mul(a, b) { + return Float(a) * Float(b); + } + function float_div(a, b) { + return Float(a) / Float(b); + } + function float_mod(a, b) { + return Float(a) % Float(b); + } + function float_pow(a, b) { + return Float(a) ** Float(b); + } + function float_eq(a, b) { + /* XXX: may be better to use infinite precision for the comparison */ + return Float(a) === Float(b); + } + function float_lt(a, b) { + a = Float(a); + b = Float(b); + /* XXX: may be better to use infinite precision for the comparison */ + if (Float.isNaN(a) || Float.isNaN(b)) + return undefined; + else + return a < b; + } + + operators_set(Fraction.prototype, + { + "+": fraction_add, + "-": fraction_sub, + "*": fraction_mul, + "/": fraction_div, + "%": fraction_mod, + "**": generic_pow, + "==": fraction_eq, + "<": fraction_lt, + "pos"(a) { + return a; + }, + "neg"(a) { + return Fraction(-a.num, a.den); + }, + }, + { + left: [Number, BigInt], + right: [Number, BigInt], + "+": fraction_add, + "-": fraction_sub, + "*": fraction_mul, + "/": fraction_div, + "%": fraction_mod, + "**": generic_pow, + "==": fraction_eq, + "<": fraction_lt, + }, + { + left: Float, + right: Float, + "+": float_add, + "-": float_sub, + "*": float_mul, + "/": float_div, + "%": float_mod, + "**": float_pow, + "==": float_eq, + "<": float_lt, + }); + + add_props(Fraction, { + /* (internal use) simplify 'a' to an integer when possible */ + toFraction(a, b) { + var r = Fraction(a, b); + if (algebraicMode && r.den == 1) + return r.num; + else + return r; + }, + }); + + add_props(Fraction.prototype, { + [Symbol.toPrimitive](hint) { + if (hint === "string") { + return this.toString(); + } else { + return Float(this.num) / this.den; + } + }, + inverse() { + return Fraction(this.den, this.num); + }, + toString() { + return this.num + "/" + this.den; + }, + norm2() { + return this * this; + }, + abs() { + if (this.num < 0) + return -this; + else + return this; + }, + conj() { + return this; + }, + arg() { + if (this.num >= 0) + return 0; + else + return Float.PI; + }, + exp() { + return Float.exp(Float(this)); + }, + log() { + return Float(this).log(); + }, + }); + + /* Number (Float64) */ + + add_props(Number.prototype, { + inverse() { + return 1 / this; + }, + norm2() { + return this * this; + }, + abs() { + return Math.abs(this); + }, + conj() { + return this; + }, + arg() { + if (this >= 0) + return 0; + else + return Float.PI; + }, + exp() { + return Float.exp(this); + }, + log() { + if (this < 0) { + return Complex(this).log(); + } else { + return Float.log(this); + } + }, + }); + + /* Float */ + + var const_tab = []; + + /* we cache the constants for small precisions */ + function get_const(n) { + var t, c, p; + t = const_tab[n]; + p = BigFloatEnv.prec; + if (t && t.prec == p) { + return t.val; + } else { + switch(n) { + case 0: c = Float.exp(1); break; + case 1: c = Float.log(10); break; +// case 2: c = Float.log(2); break; + case 3: c = 1/Float.log(2); break; + case 4: c = 1/Float.log(10); break; +// case 5: c = Float.atan(1) * 4; break; + case 6: c = Float.sqrt(0.5); break; + case 7: c = Float.sqrt(2); break; + } + if (p <= 1024) { + const_tab[n] = { prec: p, val: c }; + } + return c; + } + } + + add_props(Float, { + isFloat(a) { + return typeof a === "number" || typeof a === "bigfloat"; + }, + bestappr(u, b) { + var num1, num0, den1, den0, u, num, den, n; + + if (typeof b === "undefined") + throw TypeError("second argument expected"); + num1 = 1; + num0 = 0; + den1 = 0; + den0 = 1; + for(;;) { + n = Integer(Float.floor(u)); + num = n * num1 + num0; + den = n * den1 + den0; + if (den > b) + break; + u = 1.0 / (u - n); + num0 = num1; + num1 = num; + den0 = den1; + den1 = den; + } + return Fraction(num1, den1); + }, + /* similar constants as Math.x */ + get E() { return get_const(0); }, + get LN10() { return get_const(1); }, +// get LN2() { return get_const(2); }, + get LOG2E() { return get_const(3); }, + get LOG10E() { return get_const(4); }, +// get PI() { return get_const(5); }, + get SQRT1_2() { return get_const(6); }, + get SQRT2() { return get_const(7); }, + }); + + add_props(Float.prototype, { + inverse() { + return 1.0 / this; + }, + norm2() { + return this * this; + }, + abs() { + return Float.abs(this); + }, + conj() { + return this; + }, + arg() { + if (this >= 0) + return 0; + else + return Float.PI; + }, + exp() { + return Float.exp(this); + }, + log() { + if (this < 0) { + return Complex(this).log(); + } else { + return Float.log(this); + } + }, + }); + + /* Complex */ + + Complex = function Complex(re, im) + { + var obj; + if (new.target) + throw TypeError("not a constructor"); + if (re instanceof Complex) + return re; + if (typeof im === "undefined") { + im = 0; + } + obj = Object.create(Complex.prototype); + obj.re = re; + obj.im = im; + return obj; + } + + + function complex_add(a, b) { + a = Complex(a); + b = Complex(b); + return Complex.toComplex(a.re + b.re, a.im + b.im); + } + function complex_sub(a, b) { + a = Complex(a); + b = Complex(b); + return Complex.toComplex(a.re - b.re, a.im - b.im); + } + function complex_mul(a, b) { + a = Complex(a); + b = Complex(b); + return Complex.toComplex(a.re * b.re - a.im * b.im, + a.re * b.im + a.im * b.re); + } + function complex_div(a, b) { + a = Complex(a); + b = Complex(b); + return a * b.inverse(); + } + function complex_eq(a, b) { + a = Complex(a); + b = Complex(b); + return a.re == b.re && a.im == b.im; + } + + operators_set(Complex.prototype, + { + "+": complex_add, + "-": complex_sub, + "*": complex_mul, + "/": complex_div, + "**": generic_pow, + "==": complex_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + return Complex(-a.re, -a.im); + } + }, + { + left: [Number, BigInt, Float, Fraction], + right: [Number, BigInt, Float, Fraction], + "+": complex_add, + "-": complex_sub, + "*": complex_mul, + "/": complex_div, + "**": generic_pow, + "==": complex_eq, + }); + + add_props(Complex, { + /* simplify to real number when possible */ + toComplex(re, im) { + if (algebraicMode && im == 0) + return re; + else + return Complex(re, im); + }, + }); + + add_props(Complex.prototype, { + inverse() { + var c = this.norm2(); + return Complex(this.re / c, -this.im / c); + }, + toString() { + var v, s = "", a = this; + if (a.re != 0) + s += a.re.toString(); + if (a.im == 1) { + if (s != "") + s += "+"; + s += "I"; + } else if (a.im == -1) { + s += "-I"; + } else { + v = a.im.toString(); + if (v[0] != "-" && s != "") + s += "+"; + s += v + "*I"; + } + return s; + }, + norm2() { + return this.re * this.re + this.im * this.im; + }, + abs() { + return Float.sqrt(norm2(this)); + }, + conj() { + return Complex(this.re, -this.im); + }, + arg() { + return Float.atan2(this.im, this.re); + }, + exp() { + var arg = this.im, r = this.re.exp(); + return Complex(r * cos(arg), r * sin(arg)); + }, + log() { + return Complex(abs(this).log(), atan2(this.im, this.re)); + }, + }); + + /* Mod */ + + Mod = function Mod(a, m) { + var obj, t; + if (new.target) + throw TypeError("not a constructor"); + obj = Object.create(Mod.prototype); + if (Integer.isInteger(m)) { + if (m <= 0) + throw RangeError("the modulo cannot be <= 0"); + if (Integer.isInteger(a)) { + a %= m; + } else if (a instanceof Fraction) { + return Mod(a.num, m) / a.den; + } else { + throw TypeError("invalid types"); + } + } else { + throw TypeError("invalid types"); + } + obj.res = a; + obj.mod = m; + return obj; + }; + + function mod_add(a, b) { + if (!(a instanceof Mod)) { + return Mod(a + b.res, b.mod); + } else if (!(b instanceof Mod)) { + return Mod(a.res + b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return Mod(a.res + b.res, a.mod); + } + } + function mod_sub(a, b) { + if (!(a instanceof Mod)) { + return Mod(a - b.res, b.mod); + } else if (!(b instanceof Mod)) { + return Mod(a.res - b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return Mod(a.res - b.res, a.mod); + } + } + function mod_mul(a, b) { + if (!(a instanceof Mod)) { + return Mod(a * b.res, b.mod); + } else if (!(b instanceof Mod)) { + return Mod(a.res * b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return Mod(a.res * b.res, a.mod); + } + } + function mod_div(a, b) { + if (!(b instanceof Mod)) + b = Mod(b, a.mod); + return mod_mul(a, b.inverse()); + } + function mod_eq(a, b) { + return (a.mod == b.mod && a.res == b.res); + } + + operators_set(Mod.prototype, + { + "+": mod_add, + "-": mod_sub, + "*": mod_mul, + "/": mod_div, + "**": generic_pow, + "==": mod_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + return Mod(-a.res, a.mod); + } + }, + { + left: [Number, BigInt, Float, Fraction], + right: [Number, BigInt, Float, Fraction], + "+": mod_add, + "-": mod_sub, + "*": mod_mul, + "/": mod_div, + "**": generic_pow, + }); + + add_props(Mod.prototype, { + inverse() { + var a = this, m = a.mod; + if (Integer.isInteger(m)) { + return Mod(Integer.invmod(a.res, m), m); + } else { + throw TypeError("unsupported type"); + } + }, + toString() { + return "Mod(" + this.res + "," + this.mod + ")"; + }, + }); + + /* Polynomial */ + + function polynomial_is_scalar(a) + { + if (typeof a === "number" || + typeof a === "bigint" || + typeof a === "bigfloat") + return true; + if (a instanceof Fraction || + a instanceof Complex || + a instanceof Mod) + return true; + return false; + } + + Polynomial = function Polynomial(a) + { + if (new.target) + throw TypeError("not a constructor"); + if (a instanceof Polynomial) { + return a; + } else if (Array.isArray(a)) { + if (a.length == 0) + a = [ 0 ]; + Object.setPrototypeOf(a, Polynomial.prototype); + return a.trim(); + } else if (polynomial_is_scalar(a)) { + a = [a]; + Object.setPrototypeOf(a, Polynomial.prototype); + return a; + } else { + throw TypeError("invalid type"); + } + } + + function number_need_paren(c) + { + return !(Integer.isInteger(c) || + Float.isFloat(c) || + c instanceof Fraction || + (c instanceof Complex && c.re == 0)); + } + + /* string for c*X^i */ + function monomial_toString(c, i) + { + var str1; + if (i == 0) { + str1 = c.toString(); + } else { + if (c == 1) { + str1 = ""; + } else if (c == -1) { + str1 = "-"; + } else { + if (number_need_paren(c)) { + str1 = "(" + c + ")"; + } else { + str1 = String(c); + } + str1 += "*"; + } + str1 += "X"; + if (i != 1) { + str1 += "^" + i; + } + } + return str1; + } + + /* find one complex root of 'p' starting from z at precision eps using + at most max_it iterations. Return null if could not find root. */ + function poly_root_laguerre1(p, z, max_it) + { + var p1, p2, i, z0, z1, z2, d, t0, t1, d1, d2, e, el, zl; + + d = p.deg(); + if (d == 1) { + /* monomial case */ + return -p[0] / p[1]; + } + /* trivial zero */ + if (p[0] == 0) + return 0.0; + + p1 = p.deriv(); + p2 = p1.deriv(); + el = 0.0; + zl = 0.0; + for(i = 0; i < max_it; i++) { + z0 = p.apply(z); + if (z0 == 0) + return z; /* simple exit case */ + + /* Ward stopping criteria */ + e = abs(z - zl); +// print("e", i, e); + if (i >= 2 && e >= el) { + if (abs(zl) < 1e-4) { + if (e < 1e-7) + return zl; + } else { + if (e < abs(zl) * 1e-3) + return zl; + } + } + el = e; + zl = z; + + z1 = p1.apply(z); + z2 = p2.apply(z); + t0 = (d - 1) * z1; + t0 = t0 * t0; + t1 = d * (d - 1) * z0 * z2; + t0 = sqrt(t0 - t1); + d1 = z1 + t0; + d2 = z1 - t0; + if (norm2(d2) > norm2(d1)) + d1 = d2; + if (d1 == 0) + return null; + z = z - d * z0 / d1; + } + return null; + } + + function poly_roots(p) + { + var d, i, roots, j, z, eps; + var start_points = [ 0.1, -1.4, 1.7 ]; + + if (!(p instanceof Polynomial)) + throw TypeError("polynomial expected"); + d = p.deg(); + if (d <= 0) + return []; + eps = 2.0 ^ (-BigFloatEnv.prec); + roots = []; + for(i = 0; i < d; i++) { + /* XXX: should select another start point if error */ + for(j = 0; j < 3; j++) { + z = poly_root_laguerre1(p, start_points[j], 100); + if (z !== null) + break; + } + if (j == 3) + throw RangeError("error in root finding algorithm"); + roots[i] = z; + p = Polynomial.divrem(p, X - z)[0]; + } + return roots; + } + + add_props(Polynomial.prototype, { + trim() { + var a = this, i; + i = a.length; + while (i > 1 && a[i - 1] == 0) + i--; + a.length = i; + return a; + }, + conj() { + var r, i, n, a; + a = this; + n = a.length; + r = []; + for(i = 0; i < n; i++) + r[i] = a[i].conj(); + return Polynomial(r); + }, + inverse() { + return RationalFunction(Polynomial([1]), this); + }, + toString() { + var i, str, str1, c, a = this; + if (a.length == 1) { + return a[0].toString(); + } + str=""; + for(i = a.length - 1; i >= 0; i--) { + c = a[i]; + if (c == 0 || + (c instanceof Mod) && c.res == 0) + continue; + str1 = monomial_toString(c, i); + if (str1[0] != "-") { + if (str != "") + str += "+"; + } + str += str1; + } + return str; + }, + deg() { + if (this.length == 1 && this[0] == 0) + return -Infinity; + else + return this.length - 1; + }, + apply(b) { + var i, n, r, a = this; + n = a.length - 1; + r = a[n]; + while (n > 0) { + n--; + r = r * b + a[n]; + } + return r; + }, + deriv() { + var a = this, n, r, i; + n = a.length; + if (n == 1) { + return Polynomial(0); + } else { + r = []; + for(i = 1; i < n; i++) { + r[i - 1] = i * a[i]; + } + return Polynomial(r); + } + }, + integ() { + var a = this, n, r, i; + n = a.length; + r = [0]; + for(i = 0; i < n; i++) { + r[i + 1] = a[i] / (i + 1); + } + return Polynomial(r); + }, + norm2() { + var a = this, n, r, i; + n = a.length; + r = 0; + for(i = 0; i < n; i++) { + r += a[i].norm2(); + } + return r; + }, + }); + + + function polynomial_add(a, b) { + var tmp, r, i, n1, n2; + a = Polynomial(a); + b = Polynomial(b); + if (a.length < b.length) { + tmp = a; + a = b; + b = tmp; + } + n1 = b.length; + n2 = a.length; + r = []; + for(i = 0; i < n1; i++) + r[i] = a[i] + b[i]; + for(i = n1; i < n2; i++) + r[i] = a[i]; + return Polynomial(r); + } + function polynomial_sub(a, b) { + return polynomial_add(a, -b); + } + function polynomial_mul(a, b) { + var i, j, n1, n2, n, r; + a = Polynomial(a); + b = Polynomial(b); + n1 = a.length; + n2 = b.length; + n = n1 + n2 - 1; + r = []; + for(i = 0; i < n; i++) + r[i] = 0; + for(i = 0; i < n1; i++) { + for(j = 0; j < n2; j++) { + r[i + j] += a[i] * b[j]; + } + } + return Polynomial(r); + } + function polynomial_div_scalar(a, b) { + return a * (1 / b); + } + function polynomial_div(a, b) + { + return RationalFunction(Polynomial(a), + Polynomial(b)); + } + function polynomial_mod(a, b) { + return Polynomial.divrem(a, b)[1]; + } + function polynomial_eq(a, b) { + var n, i; + n = a.length; + if (n != b.length) + return false; + for(i = 0; i < n; i++) { + if (a[i] != b[i]) + return false; + } + return true; + } + + operators_set(Polynomial.prototype, + { + "+": polynomial_add, + "-": polynomial_sub, + "*": polynomial_mul, + "/": polynomial_div, + "**": generic_pow, + "==": polynomial_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + var r, i, n, a; + n = a.length; + r = []; + for(i = 0; i < n; i++) + r[i] = -a[i]; + return Polynomial(r); + }, + }, + { + left: [Number, BigInt, Float, Fraction, Complex, Mod], + "+": polynomial_add, + "-": polynomial_sub, + "*": polynomial_mul, + "/": polynomial_div, + "**": generic_pow, /* XXX: only for integer */ + }, + { + right: [Number, BigInt, Float, Fraction, Complex, Mod], + "+": polynomial_add, + "-": polynomial_sub, + "*": polynomial_mul, + "/": polynomial_div_scalar, + "**": generic_pow, /* XXX: only for integer */ + }); + + add_props(Polynomial, { + divrem(a, b) { + var n1, n2, i, j, q, r, n, c; + if (b.deg() < 0) + throw RangeError("division by zero"); + n1 = a.length; + n2 = b.length; + if (n1 < n2) + return [Polynomial([0]), a]; + r = Array.prototype.dup.call(a); + q = []; + n2--; + n = n1 - n2; + for(i = 0; i < n; i++) + q[i] = 0; + for(i = n - 1; i >= 0; i--) { + c = r[i + n2]; + if (c != 0) { + c = c / b[n2]; + r[i + n2] = 0; + for(j = 0; j < n2; j++) { + r[i + j] -= b[j] * c; + } + q[i] = c; + } + } + return [Polynomial(q), Polynomial(r)]; + }, + gcd(a, b) { + var t; + while (b.deg() >= 0) { + t = Polynomial.divrem(a, b); + a = b; + b = t[1]; + } + /* convert to monic form */ + return a / a[a.length - 1]; + }, + invmod(x, y) { + var q, u, v, a, c, t; + u = x; + v = y; + c = Polynomial([1]); + a = Polynomial([0]); + while (u.deg() >= 0) { + t = Polynomial.divrem(v, u); + q = t[0]; + v = u; + u = t[1]; + t = c; + c = a - q * c; + a = t; + } + /* v = gcd(x, y) */ + if (v.deg() > 0) + throw RangeError("not invertible"); + return Polynomial.divrem(a, y)[1]; + }, + roots(p) { + return poly_roots(p); + } + }); + + /* Polynomial Modulo Q */ + + PolyMod = function PolyMod(a, m) { + var obj, t; + if (new.target) + throw TypeError("not a constructor"); + obj = Object.create(PolyMod.prototype); + if (m instanceof Polynomial) { + if (m.deg() <= 0) + throw RangeError("the modulo cannot have a degree <= 0"); + if (a instanceof RationalFunction) { + return PolyMod(a.num, m) / a.den; + } else { + a = Polynomial(a); + t = Polynomial.divrem(a, m); + a = t[1]; + } + } else { + throw TypeError("invalid types"); + } + obj.res = a; + obj.mod = m; + return obj; + }; + + function polymod_add(a, b) { + if (!(a instanceof PolyMod)) { + return PolyMod(a + b.res, b.mod); + } else if (!(b instanceof PolyMod)) { + return PolyMod(a.res + b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return PolyMod(a.res + b.res, a.mod); + } + } + function polymod_sub(a, b) { + return polymod_add(a, -b); + } + function polymod_mul(a, b) { + if (!(a instanceof PolyMod)) { + return PolyMod(a * b.res, b.mod); + } else if (!(b instanceof PolyMod)) { + return PolyMod(a.res * b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return PolyMod(a.res * b.res, a.mod); + } + } + function polymod_div(a, b) { + if (!(b instanceof PolyMod)) + b = PolyMod(b, a.mod); + return polymod_mul(a, b.inverse()); + } + function polymod_eq(a, b) { + return (a.mod == b.mod && a.res == b.res); + } + + operators_set(PolyMod.prototype, + { + "+": polymod_add, + "-": polymod_sub, + "*": polymod_mul, + "/": polymod_div, + "**": generic_pow, + "==": polymod_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + return PolyMod(-a.res, a.mod); + }, + }, + { + left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + "+": polymod_add, + "-": polymod_sub, + "*": polymod_mul, + "/": polymod_div, + "**": generic_pow, /* XXX: only for integer */ + }); + + add_props(PolyMod.prototype, { + inverse() { + var a = this, m = a.mod; + if (m instanceof Polynomial) { + return PolyMod(Polynomial.invmod(a.res, m), m); + } else { + throw TypeError("unsupported type"); + } + }, + toString() { + return "PolyMod(" + this.res + "," + this.mod + ")"; + }, + }); + + /* Rational function */ + + RationalFunction = function RationalFunction(a, b) + { + var t, r, d, obj; + if (new.target) + throw TypeError("not a constructor"); + if (!(a instanceof Polynomial) || + !(b instanceof Polynomial)) + throw TypeError("polynomial expected"); + t = Polynomial.divrem(a, b); + r = t[1]; + if (r.deg() < 0) + return t[0]; /* no need for a fraction */ + d = Polynomial.gcd(b, r); + if (d.deg() > 0) { + a = Polynomial.divrem(a, d)[0]; + b = Polynomial.divrem(b, d)[0]; + } + obj = Object.create(RationalFunction.prototype); + obj.num = a; + obj.den = b; + return obj; + } + + add_props(RationalFunction.prototype, { + inverse() { + return RationalFunction(this.den, this.num); + }, + conj() { + return RationalFunction(this.num.conj(), this.den.conj()); + }, + toString() { + var str; + if (this.num.deg() <= 0 && + !number_need_paren(this.num[0])) + str = this.num.toString(); + else + str = "(" + this.num.toString() + ")"; + str += "/(" + this.den.toString() + ")" + return str; + }, + apply(b) { + return this.num.apply(b) / this.den.apply(b); + }, + deriv() { + var n = this.num, d = this.den; + return RationalFunction(n.deriv() * d - n * d.deriv(), d * d); + }, + }); + + function ratfunc_add(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den); + } + function ratfunc_sub(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den); + } + function ratfunc_mul(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + return RationalFunction(a.num * b.num, a.den * b.den); + } + function ratfunc_div(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + return RationalFunction(a.num * b.den, a.den * b.num); + } + function ratfunc_eq(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + /* we assume the fractions are normalized */ + return (a.num == b.num && a.den == b.den); + } + + operators_set(RationalFunction.prototype, + { + "+": ratfunc_add, + "-": ratfunc_sub, + "*": ratfunc_mul, + "/": ratfunc_div, + "**": generic_pow, + "==": ratfunc_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + return RationalFunction(-this.num, this.den); + }, + }, + { + left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + "+": ratfunc_add, + "-": ratfunc_sub, + "*": ratfunc_mul, + "/": ratfunc_div, + "**": generic_pow, /* should only be used with integers */ + }); + + add_props(RationalFunction, { + /* This function always return a RationalFunction object even + if it could simplified to a polynomial, so it is not + equivalent to RationalFunction(a) */ + toRationalFunction(a) { + var obj; + if (a instanceof RationalFunction) { + return a; + } else { + obj = Object.create(RationalFunction.prototype); + obj.num = Polynomial(a); + obj.den = Polynomial(1); + return obj; + } + }, + }); + + /* Power series */ + + /* 'a' is an array */ + function get_emin(a) { + var i, n; + n = a.length; + for(i = 0; i < n; i++) { + if (a[i] != 0) + return i; + } + return n; + }; + + function series_is_scalar_or_polynomial(a) + { + return polynomial_is_scalar(a) || + (a instanceof Polynomial); + } + + /* n is the maximum number of terms if 'a' is not a serie */ + Series = function Series(a, n) { + var emin, r, i; + + if (a instanceof Series) { + return a; + } else if (series_is_scalar_or_polynomial(a)) { + if (n <= 0) { + /* XXX: should still use the polynomial degree */ + return Series.zero(0, 0); + } else { + a = Polynomial(a); + emin = get_emin(a); + r = Series.zero(n, emin); + n = Math.min(a.length - emin, n); + for(i = 0; i < n; i++) + r[i] = a[i + emin]; + return r; + } + } else if (a instanceof RationalFunction) { + return Series(a.num, n) / a.den; + } else { + throw TypeError("invalid type"); + } + }; + + function series_add(v1, v2) { + var tmp, d, emin, n, r, i, j, v2_emin, c1, c2; + if (!(v1 instanceof Series)) { + tmp = v1; + v1 = v2; + v2 = tmp; + } + d = v1.emin + v1.length; + if (series_is_scalar_or_polynomial(v2)) { + v2 = Polynomial(v2); + if (d <= 0) + return v1; + v2_emin = 0; + } else if (v2 instanceof RationalFunction) { + /* compute the emin of the rational fonction */ + i = get_emin(v2.num) - get_emin(v2.den); + if (d <= i) + return v1; + /* compute the serie with the required terms */ + v2 = Series(v2, d - i); + v2_emin = v2.emin; + } else { + v2_emin = v2.emin; + d = Math.min(d, v2_emin + v2.length); + } + emin = Math.min(v1.emin, v2_emin); + n = d - emin; + r = Series.zero(n, emin); + /* XXX: slow */ + for(i = emin; i < d; i++) { + j = i - v1.emin; + if (j >= 0 && j < v1.length) + c1 = v1[j]; + else + c1 = 0; + j = i - v2_emin; + if (j >= 0 && j < v2.length) + c2 = v2[j]; + else + c2 = 0; + r[i - emin] = c1 + c2; + } + return r.trim(); + } + function series_sub(a, b) { + return series_add(a, -b); + } + function series_mul(v1, v2) { + var n, i, j, r, n, emin, n1, n2, k; + if (!(v1 instanceof Series)) + v1 = Series(v1, v2.length); + else if (!(v2 instanceof Series)) + v2 = Series(v2, v1.length); + emin = v1.emin + v2.emin; + n = Math.min(v1.length, v2.length); + n1 = v1.length; + n2 = v2.length; + r = Series.zero(n, emin); + for(i = 0; i < n1; i++) { + k = Math.min(n2, n - i); + for(j = 0; j < k; j++) { + r[i + j] += v1[i] * v2[j]; + } + } + return r.trim(); + } + function series_div(v1, v2) { + if (!(v2 instanceof Series)) + v2 = Series(v2, v1.length); + return series_mul(v1, v2.inverse()); + } + function series_pow(a, b) { + if (Integer.isInteger(b)) { + return generic_pow(a, b); + } else { + if (!(a instanceof Series)) + a = Series(a, b.length); + return exp(log(a) * b); + } + } + function series_eq(a, b) { + var n, i; + if (a.emin != b.emin) + return false; + n = a.length; + if (n != b.length) + return false; + for(i = 0; i < n; i++) { + if (a[i] != b[i]) + return false; + } + return true; + } + + operators_set(Series.prototype, + { + "+": series_add, + "-": series_sub, + "*": series_mul, + "/": series_div, + "**": series_pow, + "==": series_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + var obj, n, i; + n = a.length; + obj = Series.zero(a.length, a.emin); + for(i = 0; i < n; i++) { + obj[i] = -a[i]; + } + return obj; + }, + }, + { + left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + "+": series_add, + "-": series_sub, + "*": series_mul, + "/": series_div, + "**": series_pow, + }); + + add_props(Series.prototype, { + conj() { + var obj, n, i; + n = this.length; + obj = Series.zero(this.length, this.emin); + for(i = 0; i < n; i++) { + obj[i] = this[i].conj(); + } + return obj; + }, + inverse() { + var r, n, i, j, sum, v1 = this; + n = v1.length; + if (n == 0) + throw RangeError("division by zero"); + r = Series.zero(n, -v1.emin); + r[0] = 1 / v1[0]; + for(i = 1; i < n; i++) { + sum = 0; + for(j = 1; j <= i; j++) { + sum += v1[j] * r[i - j]; + } + r[i] = -sum * r[0]; + } + return r; + }, + /* remove leading zero terms */ + trim() { + var i, j, n, r, v1 = this; + n = v1.length; + i = 0; + while (i < n && v1[i] == 0) + i++; + if (i == 0) + return v1; + for(j = i; j < n; j++) + v1[j - i] = v1[j]; + v1.length = n - i; + v1.__proto__.emin += i; + return v1; + }, + toString() { + var i, j, str, str1, c, a = this, emin, n; + str=""; + emin = this.emin; + n = this.length; + for(j = 0; j < n; j++) { + i = j + emin; + c = a[j]; + if (c != 0) { + str1 = monomial_toString(c, i); + if (str1[0] != "-") { + if (str != "") + str += "+"; + } + str += str1; + } + } + if (str != "") + str += "+"; + str += "O(" + monomial_toString(1, n + emin) + ")"; + return str; + }, + apply(b) { + var i, n, r, a = this; + n = a.length; + if (n == 0) + return 0; + r = a[--n]; + while (n > 0) { + n--; + r = r * b + a[n]; + } + if (a.emin != 0) + r *= b ^ a.emin; + return r; + }, + deriv() { + var a = this, n = a.length, emin = a.emin, r, i, j; + if (n == 0 && emin == 0) { + return Series.zero(0, 0); + } else { + r = Series.zero(n, emin - 1); + for(i = 0; i < n; i++) { + j = emin + i; + if (j == 0) + r[i] = 0; + else + r[i] = j * a[i]; + } + return r.trim(); + } + }, + integ() { + var a = this, n = a.length, emin = a.emin, i, j, r; + r = Series.zero(n, emin + 1); + for(i = 0; i < n; i++) { + j = emin + i; + if (j == -1) { + if (a[i] != 0) + throw RangeError("cannot represent integ(1/X)"); + } else { + r[i] = a[i] / (j + 1); + } + } + return r.trim(); + }, + exp() { + var c, i, r, n, a = this; + if (a.emin < 0) + throw RangeError("negative exponent in exp"); + n = a.emin + a.length; + if (a.emin > 0 || a[0] == 0) { + c = 1; + } else { + c = global.exp(a[0]); + a -= a[0]; + } + r = Series.zero(n, 0); + for(i = 0; i < n; i++) { + r[i] = c / fact(i); + } + return r.apply(a); + }, + log() { + var a = this, r; + if (a.emin != 0) + throw RangeError("log argument must have a non zero constant term"); + r = integ(deriv(a) / a); + /* add the constant term */ + r += global.log(a[0]); + return r; + }, + }); + + add_props(Series, { + /* new series of length n and first exponent emin */ + zero(n, emin) { + var r, i, obj; + + r = []; + for(i = 0; i < n; i++) + r[i] = 0; + /* we return an array and store emin in its prototype */ + obj = Object.create(Series.prototype); + obj.emin = emin; + Object.setPrototypeOf(r, obj); + return r; + }, + O(a) { + function ErrorO() { + return TypeError("invalid O() argument"); + } + var n; + if (series_is_scalar_or_polynomial(a)) { + a = Polynomial(a); + n = a.deg(); + if (n < 0) + throw ErrorO(); + } else if (a instanceof RationalFunction) { + if (a.num.deg() != 0) + throw ErrorO(); + n = a.den.deg(); + if (n < 0) + throw ErrorO(); + n = -n; + } else + throw ErrorO(); + return Series.zero(0, n); + }, + }); + + /* Array (Matrix) */ + + Matrix = function Matrix(h, w) { + var i, j, r, rl; + if (typeof w === "undefined") + w = h; + r = []; + for(i = 0; i < h; i++) { + rl = []; + for(j = 0; j < w; j++) + rl[j] = 0; + r[i] = rl; + } + return r; + }; + + add_props(Matrix, { + idn(n) { + var r, i; + r = Matrix(n, n); + for(i = 0; i < n; i++) + r[i][i] = 1; + return r; + }, + diag(a) { + var r, i, n; + n = a.length; + r = Matrix(n, n); + for(i = 0; i < n; i++) + r[i][i] = a[i]; + return r; + }, + hilbert(n) { + var i, j, r; + r = Matrix(n); + for(i = 0; i < n; i++) { + for(j = 0; j < n; j++) { + r[i][j] = 1 / (1 + i + j); + } + } + return r; + }, + trans(a) { + var h, w, r, i, j; + if (!Array.isArray(a)) + throw TypeError("matrix expected"); + h = a.length; + if (!Array.isArray(a[0])) { + w = 1; + r = Matrix(w, h); + for(i = 0; i < h; i++) { + r[0][i] = a[i]; + } + } else { + w = a[0].length; + r = Matrix(w, h); + for(i = 0; i < h; i++) { + for(j = 0; j < w; j++) { + r[j][i] = a[i][j]; + } + } + } + return r; + }, + check_square(a) { + var a, n; + if (!Array.isArray(a)) + throw TypeError("array expected"); + n = a.length; + if (!Array.isArray(a[0]) || n != a[0].length) + throw TypeError("square matrix expected"); + return n; + }, + trace(a) { + var n, r, i; + n = Matrix.check_square(a); + r = a[0][0]; + for(i = 1; i < n; i++) { + r += a[i][i]; + } + return r; + }, + charpoly(a) { + var n, p, c, i, j, coef; + n = Matrix.check_square(a); + p = []; + for(i = 0; i < n + 1; i++) + p[i] = 0; + p[n] = 1; + c = Matrix.idn(n); + for(i = 0; i < n; i++) { + c = c * a; + coef = -trace(c) / (i + 1); + p[n - i - 1] = coef; + for(j = 0; j < n; j++) + c[j][j] += coef; + } + return Polynomial(p); + }, + eigenvals(a) { + return Polynomial.roots(Matrix.charpoly(a)); + }, + det(a) { + var n, i, j, k, s, src, v, c; + + n = Matrix.check_square(a); + s = 1; + src = a.dup(); + for(i=0;i= 2) { @@ -758,6 +759,9 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val, if (get_bool_option(ctx, &backtrace_barrier, options_obj, "backtrace_barrier")) return JS_EXCEPTION; + if (get_bool_option(ctx, &is_async, options_obj, + "async")) + return JS_EXCEPTION; } str = JS_ToCStringLen(ctx, &len, argv[0]); @@ -770,6 +774,8 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val, flags = JS_EVAL_TYPE_GLOBAL; if (backtrace_barrier) flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER; + if (is_async) + flags |= JS_EVAL_FLAG_ASYNC; ret = JS_Eval(ctx, str, len, "", flags); JS_FreeCString(ctx, str); if (!ts->recv_pipe && --ts->eval_script_recurse == 0) { @@ -1970,6 +1976,13 @@ static int64_t get_time_ms(void) clock_gettime(CLOCK_MONOTONIC, &ts); return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000); } + +static int64_t get_time_ns(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; +} #else /* more portable, but does not work if the date is updated */ static int64_t get_time_ms(void) @@ -1978,8 +1991,21 @@ static int64_t get_time_ms(void) gettimeofday(&tv, NULL); return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); } + +static int64_t get_time_ns(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000000000 + (tv.tv_usec * 1000); +} #endif +static JSValue js_os_now(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + return JS_NewFloat64(ctx, (double)get_time_ns() / 1e6); +} + static void unlink_timer(JSRuntime *rt, JSOSTimer *th) { if (th->link.prev) { @@ -2062,6 +2088,38 @@ static JSClassDef js_os_timer_class = { .gc_mark = js_os_timer_mark, }; +/* return a promise */ +static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + int64_t delay; + JSOSTimer *th; + JSValue promise, resolving_funcs[2]; + + if (JS_ToInt64(ctx, &delay, argv[0])) + return JS_EXCEPTION; + promise = JS_NewPromiseCapability(ctx, resolving_funcs); + if (JS_IsException(promise)) + return JS_EXCEPTION; + + th = js_mallocz(ctx, sizeof(*th)); + if (!th) { + JS_FreeValue(ctx, promise); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return JS_EXCEPTION; + } + th->has_object = FALSE; + th->timeout = get_time_ms() + delay; + th->func = JS_DupValue(ctx, resolving_funcs[0]); + list_add_tail(&th->link, &ts->os_timers); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return promise; +} + static void call_handler(JSContext *ctx, JSValueConst func) { JSValue ret, func1; @@ -3030,6 +3088,13 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, goto done; } +/* getpid() -> pid */ +static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + return JS_NewInt32(ctx, getpid()); +} + /* waitpid(pid, block) -> [pid, status] */ static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) @@ -3274,6 +3339,7 @@ static void *worker_func(void *opaque) JSRuntime *rt; JSThreadState *ts; JSContext *ctx; + JSValue promise; rt = JS_NewRuntime(); if (rt == NULL) { @@ -3300,8 +3366,11 @@ static void *worker_func(void *opaque) js_std_add_helpers(ctx, -1, NULL); - if (!JS_RunModule(ctx, args->basename, args->filename)) + promise = JS_LoadModule(ctx, args->basename, args->filename); + if (JS_IsException(promise)) js_std_dump_error(ctx); + /* XXX: check */ + JS_FreeValue(ctx, promise); free(args->filename); free(args->basename); free(args); @@ -3621,8 +3690,10 @@ static const JSCFunctionListEntry js_os_funcs[] = { OS_FLAG(SIGTTIN), OS_FLAG(SIGTTOU), #endif + JS_CFUNC_DEF("now", 0, js_os_now ), JS_CFUNC_DEF("setTimeout", 2, js_os_setTimeout ), JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ), + JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ), JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ), JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ), JS_CFUNC_DEF("chdir", 0, js_os_chdir ), @@ -3650,6 +3721,7 @@ static const JSCFunctionListEntry js_os_funcs[] = { JS_CFUNC_DEF("symlink", 2, js_os_symlink ), JS_CFUNC_DEF("readlink", 1, js_os_readlink ), JS_CFUNC_DEF("exec", 1, js_os_exec ), + JS_CFUNC_DEF("getpid", 0, js_os_getpid ), JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ), OS_FLAG(WNOHANG), JS_CFUNC_DEF("pipe", 0, js_os_pipe ), diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs-libc.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs-libc.h similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs-libc.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs-libc.h diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs-opcode.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs-opcode.h similarity index 95% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs-opcode.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs-opcode.h index c731a14a..6d2d6e9f 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs-opcode.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs-opcode.h @@ -172,6 +172,7 @@ DEF(set_loc_uninitialized, 3, 0, 0, loc) DEF( get_loc_check, 3, 0, 1, loc) DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ DEF( put_loc_check_init, 3, 1, 0, loc) +DEF(get_loc_checkthis, 3, 0, 1, loc) DEF(get_var_ref_check, 3, 0, 1, var_ref) DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ DEF(put_var_ref_check_init, 3, 1, 0, var_ref) @@ -182,6 +183,7 @@ DEF( goto, 5, 0, 0, label) /* must come after if_true */ DEF( catch, 5, 0, 1, label) DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */ DEF( ret, 1, 1, 0, none) /* used to return from the finally block */ +DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */ DEF( to_object, 1, 1, 1, none) //DEF( to_string, 1, 1, 1, none) @@ -208,7 +210,6 @@ DEF( for_of_next, 2, 3, 5, u8) DEF(iterator_check_object, 1, 1, 1, none) DEF(iterator_get_value_done, 1, 1, 2, none) DEF( iterator_close, 1, 3, 0, none) -DEF(iterator_close_return, 1, 4, 4, none) DEF( iterator_next, 1, 4, 4, none) DEF( iterator_call, 2, 4, 5, u8) DEF( initial_yield, 1, 0, 0, none) @@ -256,6 +257,7 @@ DEF( and, 1, 2, 1, none) DEF( xor, 1, 2, 1, none) DEF( or, 1, 2, 1, none) DEF(is_undefined_or_null, 1, 1, 1, none) +DEF( private_in, 1, 2, 1, none) #ifdef CONFIG_BIGNUM DEF( mul_pow10, 1, 2, 1, none) DEF( math_mod, 1, 2, 1, none) @@ -270,6 +272,8 @@ def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */ +/* the following opcodes must be in the same order as the 'with_x' and + get_var_undef, get_var and put_var opcodes */ def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ @@ -277,10 +281,13 @@ def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ +def(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */ def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */ def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */ -def(scope_put_private_field, 7, 1, 1, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ - +def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ +def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */ +def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */ +def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */ def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs.c b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs.c similarity index 94% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs.c rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs.c index 22ff4b99..bfd8b7a0 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs.c +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs.c @@ -44,9 +44,7 @@ #include "list.h" #include "quickjs.h" #include "libregexp.h" -#ifdef CONFIG_BIGNUM #include "libbf.h" -#endif #define OPTIMIZE 1 #define SHORT_OPCODES 1 @@ -80,7 +78,7 @@ /* dump object free */ -// #define DUMP_FREE 1 +//#define DUMP_FREE //#define DUMP_CLOSURE /* dump the bytecode of the compiled functions: combination of bits 1: dump pass 3 final byte code @@ -89,6 +87,7 @@ 8: dump stdlib functions 16: dump bytecode in hex 32: dump line number table + 64: dump compute_stack_size */ //#define DUMP_BYTECODE (1) /* dump the occurence of the automatic GC */ @@ -144,15 +143,13 @@ enum { JS_CLASS_UINT16_ARRAY, /* u.array (typed_array) */ JS_CLASS_INT32_ARRAY, /* u.array (typed_array) */ JS_CLASS_UINT32_ARRAY, /* u.array (typed_array) */ -#ifdef CONFIG_BIGNUM JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */ JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */ -#endif JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */ JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */ JS_CLASS_DATAVIEW, /* u.typed_array */ -#ifdef CONFIG_BIGNUM JS_CLASS_BIG_INT, /* u.object_data */ +#ifdef CONFIG_BIGNUM JS_CLASS_BIG_FLOAT, /* u.object_data */ JS_CLASS_FLOAT_ENV, /* u.float_env */ JS_CLASS_BIG_DECIMAL, /* u.object_data */ @@ -200,7 +197,7 @@ typedef enum JSErrorEnum { JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */ } JSErrorEnum; -#define JS_MAX_LOCAL_VARS 65536 +#define JS_MAX_LOCAL_VARS 65535 #define JS_STACK_SIZE_MAX 65534 #define JS_STRING_LEN_MAX ((1 << 30) - 1) @@ -218,7 +215,6 @@ typedef enum { typedef enum OPCodeEnum OPCodeEnum; -#ifdef CONFIG_BIGNUM /* function pointers are used for numeric operations so that it is possible to remove some numeric types */ typedef struct { @@ -236,7 +232,6 @@ typedef struct { int64_t exponent); int (*mul_pow10)(JSContext *ctx, JSValue *sp); } JSNumericOperations; -#endif struct JSRuntime { JSMallocFunctions mf; @@ -288,7 +283,9 @@ struct JSRuntime { JSModuleNormalizeFunc *module_normalize_func; JSModuleLoaderFunc *module_loader_func; void *module_loader_opaque; - + /* timestamp for internal use in module evaluation */ + int64_t module_async_evaluation_next_timestamp; + BOOL can_block : 8; /* TRUE if Atomics.wait can block */ /* used to allocate, free and clone SharedArrayBuffers */ JSSharedArrayBufferFunctions sab_funcs; @@ -298,9 +295,9 @@ struct JSRuntime { int shape_hash_size; int shape_hash_count; /* number of hashed shapes */ JSShape **shape_hash; -#ifdef CONFIG_BIGNUM bf_context_t bf_ctx; JSNumericOperations bigint_ops; +#ifdef CONFIG_BIGNUM JSNumericOperations bigfloat_ops; JSNumericOperations bigdecimal_ops; uint32_t operator_count; @@ -321,17 +318,18 @@ struct JSClass { #define JS_MODE_STRICT (1 << 0) #define JS_MODE_STRIP (1 << 1) #define JS_MODE_MATH (1 << 2) +#define JS_MODE_ASYNC (1 << 3) /* async function */ typedef struct JSStackFrame { struct JSStackFrame *prev_frame; /* NULL if first stack frame */ JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */ JSValue *arg_buf; /* arguments */ JSValue *var_buf; /* variables */ - struct list_head var_ref_list; /* list of JSVarRef.link */ + struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */ const uint8_t *cur_pc; /* only used in bytecode functions : PC of the instruction after the call */ int arg_count; - int js_mode; /* 0 or JS_MODE_MATH for C functions */ + int js_mode; /* for C functions, only JS_MODE_MATH may be set */ /* only used in generators. Current stack pointer value. NULL if the function is running. */ JSValue *cur_sp; @@ -364,11 +362,6 @@ typedef struct JSVarRef { struct { int __gc_ref_count; /* corresponds to header.ref_count */ uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ - - /* 0 : the JSVarRef is on the stack. header.link is an element - of JSStackFrame.var_ref_list. - 1 : the JSVarRef is detached. header.link has the normal meanning - */ uint8_t is_detached : 1; uint8_t is_arg : 1; uint16_t var_idx; /* index of the corresponding function variable on @@ -377,16 +370,15 @@ typedef struct JSVarRef { }; JSValue *pvalue; /* pointer to the value, either on the stack or to 'value' */ - JSValue value; /* used when the variable is no longer on the stack */ + union { + JSValue value; /* used when is_detached = TRUE */ + struct { + struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */ + struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */ + }; /* used when is_detached = FALSE */ + }; } JSVarRef; -#ifdef CONFIG_BIGNUM -typedef struct JSFloatEnv { - limb_t prec; - bf_flags_t flags; - unsigned int status; -} JSFloatEnv; - /* the same structure is used for big integers and big floats. Big integers are never infinite or NaNs */ typedef struct JSBigFloat { @@ -394,6 +386,13 @@ typedef struct JSBigFloat { bf_t num; } JSBigFloat; +#ifdef CONFIG_BIGNUM +typedef struct JSFloatEnv { + limb_t prec; + bf_flags_t flags; + unsigned int status; +} JSFloatEnv; + typedef struct JSBigDecimal { JSRefCountHeader header; /* must come first, 32-bit */ bfdec_t num; @@ -437,15 +436,14 @@ struct JSContext { JSValue global_var_obj; /* contains the global let/const definitions */ uint64_t random_state; -#ifdef CONFIG_BIGNUM bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */ +#ifdef CONFIG_BIGNUM JSFloatEnv fp_env; /* global FP environment */ BOOL bignum_ext : 8; /* enable math mode */ BOOL allow_operator_overloading : 8; #endif /* when the counter reaches zero, JSRutime.interrupt_handler is called */ int interrupt_counter; - BOOL is_error_property_enabled; struct list_head loaded_modules; /* list of JSModuleDef.link */ @@ -558,6 +556,7 @@ typedef struct JSVarDef { uint8_t is_const : 1; uint8_t is_lexical : 1; uint8_t is_captured : 1; + uint8_t is_static_private : 1; /* only used during private class field parsing */ uint8_t var_kind : 4; /* see JSVarKindEnum */ /* only used during compilation: function pool index for lexical variables with var_kind = @@ -598,6 +597,7 @@ typedef struct JSFunctionBytecode { uint8_t has_debug : 1; uint8_t backtrace_barrier : 1; /* stop backtrace on this function */ uint8_t read_only_bytecode : 1; + uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */ /* XXX: 4 bits available */ uint8_t *byte_code_buf; /* (self pointer) */ int byte_code_len; @@ -638,9 +638,11 @@ typedef enum JSIteratorKindEnum { typedef struct JSForInIterator { JSValue obj; - BOOL is_array; - uint32_t array_length; uint32_t idx; + uint32_t atom_count; + uint8_t in_prototype_chain; + uint8_t is_array; + JSPropertyEnum *tab_atom; /* is_array = FALSE */ } JSForInIterator; typedef struct JSRegExp { @@ -674,21 +676,16 @@ typedef struct JSTypedArray { } JSTypedArray; typedef struct JSAsyncFunctionState { - JSValue this_val; /* 'this' generator argument */ + JSGCObjectHeader header; + JSValue this_val; /* 'this' argument */ int argc; /* number of function arguments */ BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */ + BOOL is_completed; /* TRUE if the function has returned. The stack + frame is no longer valid */ + JSValue resolving_funcs[2]; /* only used in JS async functions */ JSStackFrame frame; } JSAsyncFunctionState; -/* XXX: could use an object instead to avoid the - JS_TAG_ASYNC_FUNCTION tag for the GC */ -typedef struct JSAsyncFunctionData { - JSGCObjectHeader header; /* must come first */ - JSValue resolving_funcs[2]; - BOOL is_active; /* true if the async function state is valid */ - JSAsyncFunctionState func_state; -} JSAsyncFunctionData; - typedef enum { /* binary operators */ JS_OVOP_ADD, @@ -770,6 +767,15 @@ typedef struct JSImportEntry { int req_module_idx; /* in req_module_entries */ } JSImportEntry; +typedef enum { + JS_MODULE_STATUS_UNLINKED, + JS_MODULE_STATUS_LINKING, + JS_MODULE_STATUS_LINKED, + JS_MODULE_STATUS_EVALUATING, + JS_MODULE_STATUS_EVALUATING_ASYNC, + JS_MODULE_STATUS_EVALUATED, +} JSModuleStatus; + struct JSModuleDef { JSRefCountHeader header; /* must come first, 32-bit */ JSAtom module_name; @@ -794,11 +800,24 @@ struct JSModuleDef { JSValue module_ns; JSValue func_obj; /* only used for JS modules */ JSModuleInitFunc *init_func; /* only used for C modules */ + BOOL has_tla : 8; /* true if func_obj contains await */ BOOL resolved : 8; BOOL func_created : 8; - BOOL instantiated : 8; - BOOL evaluated : 8; - BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */ + JSModuleStatus status : 8; + /* temp use during js_module_link() & js_module_evaluate() */ + int dfs_index, dfs_ancestor_index; + JSModuleDef *stack_prev; + /* temp use during js_module_evaluate() */ + JSModuleDef **async_parent_modules; + int async_parent_modules_count; + int async_parent_modules_size; + int pending_async_dependencies; + BOOL async_evaluation; + int64_t async_evaluation_timestamp; + JSModuleDef *cycle_root; + JSValue promise; /* corresponds to spec field: capability */ + JSValue resolving_funcs[2]; /* corresponds to spec field: capability */ + /* true if evaluation yielded an exception. It is saved in eval_exception */ BOOL eval_has_exception : 8; @@ -906,7 +925,7 @@ struct JSObject { struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */ struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */ struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */ - struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */ + struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */ struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */ struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */ struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */ @@ -1117,6 +1136,18 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val); static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val); static JSProperty *add_property(JSContext *ctx, JSObject *p, JSAtom prop, int prop_flags); +static JSValue JS_NewBigInt(JSContext *ctx); +static inline bf_t *JS_GetBigInt(JSValueConst val) +{ + JSBigFloat *p = JS_VALUE_GET_PTR(val); + return &p->num; +} +static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, + BOOL convert_to_safe_integer); +static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val); +static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); +static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val); +static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf); #ifdef CONFIG_BIGNUM static void js_float_env_finalizer(JSRuntime *rt, JSValue val); static JSValue JS_NewBigFloat(JSContext *ctx); @@ -1131,18 +1162,6 @@ static inline bfdec_t *JS_GetBigDecimal(JSValueConst val) JSBigDecimal *p = JS_VALUE_GET_PTR(val); return &p->num; } -static JSValue JS_NewBigInt(JSContext *ctx); -static inline bf_t *JS_GetBigInt(JSValueConst val) -{ - JSBigFloat *p = JS_VALUE_GET_PTR(val); - return &p->num; -} -static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, - BOOL convert_to_safe_integer); -static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val); -static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); -static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val); -static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf); static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val); static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, BOOL allow_null_or_undefined); @@ -1173,11 +1192,17 @@ static JSValue js_typed_array_constructor(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int classid); +static JSValue js_typed_array_constructor_ta(JSContext *ctx, + JSValueConst new_target, + JSValueConst src_obj, + int classid); static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p); static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p); static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx); static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx, BOOL is_arg); +static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); +static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, @@ -1203,6 +1228,8 @@ static __exception int perform_promise_then(JSContext *ctx, JSValueConst *cap_resolving_funcs); static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); +static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv); static int js_string_compare(JSContext *ctx, const JSString *p1, const JSString *p2); static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val); @@ -1214,8 +1241,6 @@ static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val); static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, JSObject *p, JSAtom prop); static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc); -static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s, - JS_MarkFunc *mark_func); static void JS_AddIntrinsicBasicObjects(JSContext *ctx); static void js_free_shape(JSRuntime *rt, JSShape *sh); static void js_free_shape_null(JSRuntime *rt, JSShape *sh); @@ -1243,13 +1268,14 @@ static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val); static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, JSGCObjectTypeEnum type); static void remove_gc_object(JSGCObjectHeader *h); -static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s); static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag); +static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int is_map); static const JSClassExoticMethods js_arguments_exotic_methods; static const JSClassExoticMethods js_string_exotic_methods; @@ -1311,14 +1337,12 @@ void *js_mallocz_rt(JSRuntime *rt, size_t size) return memset(ptr, 0, size); } -#ifdef CONFIG_BIGNUM /* called by libbf */ static void *js_bf_realloc(void *opaque, void *ptr, size_t size) { JSRuntime *rt = opaque; return js_realloc_rt(rt, ptr, size); } -#endif /* CONFIG_BIGNUM */ /* Throw out of memory in case of error */ void *js_malloc(JSContext *ctx, size_t size) @@ -1469,15 +1493,13 @@ static JSClassShortDef const js_std_class_def[] = { { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT16_ARRAY */ { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT32_ARRAY */ { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT32_ARRAY */ -#ifdef CONFIG_BIGNUM { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_INT64_ARRAY */ { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_UINT64_ARRAY */ -#endif { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT32_ARRAY */ { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT64_ARRAY */ { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_DATAVIEW */ -#ifdef CONFIG_BIGNUM { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */ +#ifdef CONFIG_BIGNUM { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */ { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */ { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */ @@ -1512,7 +1534,6 @@ static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab, return 0; } -#ifdef CONFIG_BIGNUM static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx) { return JS_ThrowTypeError(ctx, "unsupported operation"); @@ -1568,8 +1589,6 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops) ops->mul_pow10 = invalid_mul_pow10; } -#endif /* CONFIG_BIGNUM */ - #if !defined(CONFIG_STACK_CHECK) /* no stack limitation */ static inline uintptr_t js_get_stack_pointer(void) @@ -1617,9 +1636,9 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) rt->malloc_state = ms; rt->malloc_gc_threshold = 256 * 1024; -#ifdef CONFIG_BIGNUM bf_context_init(&rt->bf_ctx, js_bf_realloc, rt); set_dummy_numeric_ops(&rt->bigint_ops); +#ifdef CONFIG_BIGNUM set_dummy_numeric_ops(&rt->bigfloat_ops); set_dummy_numeric_ops(&rt->bigdecimal_ops); #endif @@ -1674,19 +1693,19 @@ void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque) } /* default memory allocation functions with memory limitation */ -static inline size_t js_def_malloc_usable_size(void *ptr) +static size_t js_def_malloc_usable_size(const void *ptr) { #if defined(__APPLE__) return malloc_size(ptr); #elif defined(_WIN32) - return _msize(ptr); + return _msize((void *)ptr); #elif defined(EMSCRIPTEN) return 0; #elif defined(__linux__) - return malloc_usable_size(ptr); + return malloc_usable_size((void *)ptr); #else /* change this to `return 0;` if compilation fails */ - return malloc_usable_size(ptr); + return malloc_usable_size((void *)ptr); #endif } @@ -1750,18 +1769,7 @@ static const JSMallocFunctions def_malloc_funcs = { js_def_malloc, js_def_free, js_def_realloc, -#if defined(__APPLE__) - malloc_size, -#elif defined(_WIN32) - (size_t (*)(const void *))_msize, -#elif defined(EMSCRIPTEN) - NULL, -#elif defined(__linux__) - (size_t (*)(const void *))malloc_usable_size, -#else - /* change this to `NULL,` if compilation fails */ - malloc_usable_size, -#endif + js_def_malloc_usable_size, }; JSRuntime *JS_NewRuntime(void) @@ -1991,9 +1999,7 @@ void JS_FreeRuntime(JSRuntime *rt) } js_free_rt(rt, rt->class_array); -#ifdef CONFIG_BIGNUM bf_context_end(&rt->bf_ctx); -#endif #ifdef DUMP_LEAKS /* only the atoms defined in JS_InitAtoms() should be left */ @@ -2131,8 +2137,8 @@ JSContext *JS_NewContextRaw(JSRuntime *rt) } ctx->rt = rt; list_add_tail(&ctx->link, &rt->context_list); -#ifdef CONFIG_BIGNUM ctx->bf_ctx = &rt->bf_ctx; +#ifdef CONFIG_BIGNUM ctx->fp_env.prec = 113; ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL; #endif @@ -2165,9 +2171,7 @@ JSContext *JS_NewContext(JSRuntime *rt) JS_AddIntrinsicMapSet(ctx); JS_AddIntrinsicTypedArrays(ctx); JS_AddIntrinsicPromise(ctx); -#ifdef CONFIG_BIGNUM JS_AddIntrinsicBigInt(ctx); -#endif return ctx; } @@ -2208,7 +2212,6 @@ JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id) typedef enum JSFreeModuleEnum { JS_FREE_MODULE_ALL, JS_FREE_MODULE_NOT_RESOLVED, - JS_FREE_MODULE_NOT_EVALUATED, } JSFreeModuleEnum; /* XXX: would be more efficient with separate module lists */ @@ -2218,8 +2221,7 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag) list_for_each_safe(el, el1, &ctx->loaded_modules) { JSModuleDef *m = list_entry(el, JSModuleDef, link); if (flag == JS_FREE_MODULE_ALL || - (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved) || - (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated)) { + (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) { js_free_module_def(ctx, m); } } @@ -2375,6 +2377,11 @@ static inline BOOL is_math_mode(JSContext *ctx) JSStackFrame *sf = ctx->rt->current_stack_frame; return (sf && (sf->js_mode & JS_MODE_MATH)); } +#else +static inline BOOL is_math_mode(JSContext *ctx) +{ + return FALSE; +} #endif /* JSAtom support */ @@ -3369,16 +3376,25 @@ static inline BOOL JS_IsEmptyString(JSValueConst v) /* JSClass support */ +#ifdef CONFIG_ATOMICS +static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + /* a new class ID is allocated if *pclass_id != 0 */ JSClassID JS_NewClassID(JSClassID *pclass_id) { JSClassID class_id; - /* XXX: make it thread safe */ +#ifdef CONFIG_ATOMICS + pthread_mutex_lock(&js_class_id_mutex); +#endif class_id = *pclass_id; if (class_id == 0) { class_id = js_class_id_alloc++; *pclass_id = class_id; } +#ifdef CONFIG_ATOMICS + pthread_mutex_unlock(&js_class_id_mutex); +#endif return class_id; } @@ -4074,7 +4090,7 @@ void JS_FreeCString(JSContext *ctx, const char *ptr) if (!ptr) return; /* purposely removing constness */ - p = (JSString *)(void *)(ptr - offsetof(JSString, u)); + p = container_of(ptr, JSString, u); JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); } @@ -4453,6 +4469,7 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, JSShapeProperty *pr; void *sh_alloc; intptr_t h; + JSShape *old_sh; sh = *psh; new_size = max_int(count, sh->prop_size * 3 / 2); @@ -4468,19 +4485,21 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, new_hash_size = sh->prop_hash_mask + 1; while (new_hash_size < new_size) new_hash_size = 2 * new_hash_size; + /* resize the property shapes. Using js_realloc() is not possible in + case the GC runs during the allocation */ + old_sh = sh; + sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); + if (!sh_alloc) + return -1; + sh = get_shape_from_alloc(sh_alloc, new_hash_size); + list_del(&old_sh->header.link); + /* copy all the shape properties */ + memcpy(sh, old_sh, + sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count); + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); + if (new_hash_size != (sh->prop_hash_mask + 1)) { - JSShape *old_sh; /* resize the hash table and the properties */ - old_sh = sh; - sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); - if (!sh_alloc) - return -1; - sh = get_shape_from_alloc(sh_alloc, new_hash_size); - list_del(&old_sh->header.link); - /* copy all the fields and the properties */ - memcpy(sh, old_sh, - sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count); - list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); new_hash_mask = new_hash_size - 1; sh->prop_hash_mask = new_hash_mask; memset(prop_hash_end(sh) - new_hash_size, 0, @@ -4492,20 +4511,12 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, prop_hash_end(sh)[-h - 1] = i + 1; } } - js_free(ctx, get_alloc_from_shape(old_sh)); } else { - /* only resize the properties */ - list_del(&sh->header.link); - sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh), - get_shape_size(new_hash_size, new_size)); - if (unlikely(!sh_alloc)) { - /* insert again in the GC list */ - list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); - return -1; - } - sh = get_shape_from_alloc(sh_alloc, new_hash_size); - list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); + /* just copy the previous hash table */ + memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size, + sizeof(prop_hash_end(sh)[0]) * new_hash_size); } + js_free(ctx, get_alloc_from_shape(old_sh)); *psh = sh; sh->prop_size = new_size; return 0; @@ -4782,10 +4793,8 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas case JS_CLASS_UINT16_ARRAY: case JS_CLASS_INT32_ARRAY: case JS_CLASS_UINT32_ARRAY: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: -#endif case JS_CLASS_FLOAT32_ARRAY: case JS_CLASS_FLOAT64_ARRAY: p->is_exotic = 1; @@ -4802,8 +4811,8 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas case JS_CLASS_BOOLEAN: case JS_CLASS_SYMBOL: case JS_CLASS_DATE: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif @@ -4865,8 +4874,8 @@ static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj) case JS_CLASS_BOOLEAN: case JS_CLASS_SYMBOL: case JS_CLASS_DATE: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif @@ -4889,8 +4898,8 @@ static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val) case JS_CLASS_BOOLEAN: case JS_CLASS_SYMBOL: case JS_CLASS_DATE: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif @@ -5237,10 +5246,12 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref) if (--var_ref->header.ref_count == 0) { if (var_ref->is_detached) { JS_FreeValueRT(rt, var_ref->value); - remove_gc_object(&var_ref->header); } else { - list_del(&var_ref->header.link); /* still on the stack */ + list_del(&var_ref->var_ref_link); /* still on the stack */ + if (var_ref->async_func) + async_func_free(rt, var_ref->async_func); } + remove_gc_object(&var_ref->header); js_free_rt(rt, var_ref); } } @@ -5338,7 +5349,7 @@ static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, if (var_refs) { for(i = 0; i < b->closure_var_count; i++) { JSVarRef *var_ref = var_refs[i]; - if (var_ref && var_ref->is_detached) { + if (var_ref) { mark_func(rt, &var_ref->header); } } @@ -5380,7 +5391,15 @@ static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); JSForInIterator *it = p->u.for_in_iterator; + int i; + JS_FreeValueRT(rt, it->obj); + if (!it->is_array) { + for(i = 0; i < it->atom_count; i++) { + JS_FreeAtomRT(rt, it->tab_atom[i].atom); + } + js_free_rt(rt, it->tab_atom); + } js_free_rt(rt, it); } @@ -5448,6 +5467,9 @@ static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp) case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: free_function_bytecode(rt, (JSFunctionBytecode *)gp); break; + case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: + __async_func_free(rt, (JSAsyncFunctionState *)gp); + break; default: abort(); } @@ -5489,7 +5511,7 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v) switch(tag) { case JS_TAG_STRING: - { + { JSString *p = JS_VALUE_GET_STRING(v); if (p->atom_type) { JS_FreeAtomStruct(rt, p); @@ -5517,15 +5539,17 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v) case JS_TAG_MODULE: abort(); /* never freed here */ break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *bf = JS_VALUE_GET_PTR(v); bf_delete(&bf->num); js_free_rt(rt, bf); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: { JSBigDecimal *bf = JS_VALUE_GET_PTR(v); @@ -5604,11 +5628,9 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, if (pr->u.getset.setter) mark_func(rt, &pr->u.getset.setter->header); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - if (pr->u.var_ref->is_detached) { - /* Note: the tag does not matter - provided it is a GC object */ - mark_func(rt, &pr->u.var_ref->header); - } + /* Note: the tag does not matter + provided it is a GC object */ + mark_func(rt, &pr->u.var_ref->header); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { js_autoinit_mark(rt, pr, mark_func); } @@ -5642,16 +5664,32 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, case JS_GC_OBJ_TYPE_VAR_REF: { JSVarRef *var_ref = (JSVarRef *)gp; - /* only detached variable referenced are taken into account */ - assert(var_ref->is_detached); - JS_MarkValue(rt, *var_ref->pvalue, mark_func); + if (var_ref->is_detached) { + JS_MarkValue(rt, *var_ref->pvalue, mark_func); + } else if (var_ref->async_func) { + mark_func(rt, &var_ref->async_func->header); + } } break; case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: { - JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp; - if (s->is_active) - async_func_mark(rt, &s->func_state, mark_func); + JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp; + JSStackFrame *sf = &s->frame; + JSValue *sp; + + if (!s->is_completed) { + JS_MarkValue(rt, sf->cur_func, mark_func); + JS_MarkValue(rt, s->this_val, mark_func); + /* sf->cur_sp = NULL if the function is running */ + if (sf->cur_sp) { + /* if the function is running, cur_sp is not known so we + cannot mark the stack. Marking the variables is not needed + because a running function cannot be part of a removable + cycle */ + for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) + JS_MarkValue(rt, *sp, mark_func); + } + } JS_MarkValue(rt, s->resolving_funcs[0], mark_func); JS_MarkValue(rt, s->resolving_funcs[1], mark_func); } @@ -5759,12 +5797,13 @@ static void gc_free_cycles(JSRuntime *rt) if (el == &rt->tmp_obj_list) break; p = list_entry(el, JSGCObjectHeader, link); - /* Only need to free the GC object associated with JS - values. The rest will be automatically removed because they - must be referenced by them. */ + /* Only need to free the GC object associated with JS values + or async functions. The rest will be automatically removed + because they must be referenced by them. */ switch(p->gc_obj_type) { case JS_GC_OBJ_TYPE_JS_OBJECT: case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: + case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: #ifdef DUMP_GC_FREE if (!header_done) { printf("Freeing cycles:\n"); @@ -5786,7 +5825,8 @@ static void gc_free_cycles(JSRuntime *rt) list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) { p = list_entry(el, JSGCObjectHeader, link); assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || - p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); + p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE || + p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION); js_free_rt(rt, p); } @@ -5888,13 +5928,13 @@ static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp) case JS_TAG_STRING: compute_jsstring_size(JS_VALUE_GET_STRING(val), hp); break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: case JS_TAG_BIG_DECIMAL: +#endif /* should track JSBigFloat usage */ break; -#endif } } @@ -6018,8 +6058,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) case JS_CLASS_BOOLEAN: /* u.object_data */ case JS_CLASS_SYMBOL: /* u.object_data */ case JS_CLASS_DATE: /* u.object_data */ -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: /* u.object_data */ +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: /* u.object_data */ case JS_CLASS_BIG_DECIMAL: /* u.object_data */ #endif @@ -6111,10 +6151,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) case JS_CLASS_UINT16_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_INT32_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_UINT32_ARRAY: /* u.typed_array / u.array */ -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */ -#endif case JS_CLASS_FLOAT32_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_FLOAT64_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_DATAVIEW: /* u.typed_array */ @@ -6241,10 +6279,10 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) if (obj_classes[0]) fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none"); for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) { - if (obj_classes[class_id]) { + if (obj_classes[class_id] && class_id < rt->class_count) { char buf[ATOM_GET_STR_BUF_SIZE]; fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id, - JS_AtomGetStrRT(rt, buf, sizeof(buf), js_std_class_def[class_id - 1].class_name)); + JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name)); } } if (obj_classes[JS_CLASS_INIT_COUNT]) @@ -6875,10 +6913,10 @@ int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val) static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val) { switch(JS_VALUE_GET_NORM_TAG(val)) { -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: val = ctx->class_proto[JS_CLASS_BIG_INT]; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: val = ctx->class_proto[JS_CLASS_BIG_FLOAT]; break; @@ -7313,6 +7351,8 @@ static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj, return 0; } +/* add a private brand field to 'home_obj' if not already present and + if obj is != null add a private brand to it */ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) { JSObject *p, *p1; @@ -7328,10 +7368,10 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) p = JS_VALUE_GET_OBJ(home_obj); prs = find_own_property(&pr, p, JS_ATOM_Private_brand); if (!prs) { + /* if the brand is not present, add it */ brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE); if (JS_IsException(brand)) return -1; - /* if the brand is not present, add it */ pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E); if (!pr) { JS_FreeValue(ctx, brand); @@ -7343,20 +7383,27 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) } brand_atom = js_symbol_to_atom(ctx, brand); - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { - JS_ThrowTypeErrorNotAnObject(ctx); + if (JS_IsObject(obj)) { + p1 = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p1, brand_atom); + if (unlikely(prs)) { + JS_FreeAtom(ctx, brand_atom); + JS_ThrowTypeError(ctx, "private method is already present"); + return -1; + } + pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E); + JS_FreeAtom(ctx, brand_atom); + if (!pr) + return -1; + pr->u.value = JS_UNDEFINED; + } else { JS_FreeAtom(ctx, brand_atom); - return -1; } - p1 = JS_VALUE_GET_OBJ(obj); - pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E); - JS_FreeAtom(ctx, brand_atom); - if (!pr) - return -1; - pr->u.value = JS_UNDEFINED; return 0; } +/* return a boolean telling if the brand of the home object of 'func' + is present on 'obj' or -1 in case of exception */ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) { JSObject *p, *p1, *home_obj; @@ -7365,11 +7412,8 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) JSValueConst brand; /* get the home object of 'func' */ - if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) { - not_obj: - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } + if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) + goto not_obj; p1 = JS_VALUE_GET_OBJ(func); if (!js_class_has_bytecode(p1->class_id)) goto not_obj; @@ -7387,15 +7431,14 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) goto not_obj; /* get the brand array of 'obj' */ - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) - goto not_obj; - p = JS_VALUE_GET_OBJ(obj); - prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand)); - if (!prs) { - JS_ThrowTypeError(ctx, "invalid brand on object"); + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { + not_obj: + JS_ThrowTypeErrorNotAnObject(ctx); return -1; } - return 0; + p = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand)); + return (prs != NULL); } static uint32_t js_string_obj_get_length(JSContext *ctx, @@ -7852,39 +7895,45 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj, if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { JSObject *p; - uint32_t idx, len; + uint32_t idx; /* fast path for array access */ p = JS_VALUE_GET_OBJ(this_obj); idx = JS_VALUE_GET_INT(prop); - len = (uint32_t)p->u.array.count; - if (unlikely(idx >= len)) - goto slow_path; switch(p->class_id) { case JS_CLASS_ARRAY: case JS_CLASS_ARGUMENTS: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_DupValue(ctx, p->u.array.u.values[idx]); case JS_CLASS_INT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]); case JS_CLASS_UINT8C_ARRAY: case JS_CLASS_UINT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]); case JS_CLASS_INT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]); case JS_CLASS_UINT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]); case JS_CLASS_INT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]); case JS_CLASS_UINT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]); -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); case JS_CLASS_BIG_UINT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); -#endif case JS_CLASS_FLOAT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]); case JS_CLASS_FLOAT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]); default: goto slow_path; @@ -8302,126 +8351,45 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p, return TRUE; } -static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) +/* Allocate a new fast array. Its 'length' property is set to zero. It + maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit + integer. WARNING: the content of the array is not initialized. */ +static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len) { - JS_FreeValue(ctx, desc->getter); - JS_FreeValue(ctx, desc->setter); - JS_FreeValue(ctx, desc->value); -} - -/* generic (and slower) version of JS_SetProperty() for - * Reflect.set(). 'obj' must be an object. */ -static int JS_SetPropertyGeneric(JSContext *ctx, - JSValueConst obj, JSAtom prop, - JSValue val, JSValueConst this_obj, - int flags) -{ - int ret; - JSPropertyDescriptor desc; - JSValue obj1; + JSValue arr; JSObject *p; - obj1 = JS_DupValue(ctx, obj); - for(;;) { - p = JS_VALUE_GET_OBJ(obj1); - if (p->is_exotic) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->set_property) { - ret = em->set_property(ctx, obj1, prop, - val, this_obj, flags); - JS_FreeValue(ctx, obj1); - JS_FreeValue(ctx, val); - return ret; - } - } - - ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (ret < 0) { - JS_FreeValue(ctx, obj1); - JS_FreeValue(ctx, val); - return ret; - } - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JSObject *setter; - if (JS_IsUndefined(desc.setter)) - setter = NULL; - else - setter = JS_VALUE_GET_OBJ(desc.setter); - ret = call_setter(ctx, setter, this_obj, val, flags); - JS_FreeValue(ctx, desc.getter); - JS_FreeValue(ctx, desc.setter); - JS_FreeValue(ctx, obj1); - return ret; - } else { - JS_FreeValue(ctx, desc.value); - if (!(desc.flags & JS_PROP_WRITABLE)) { - JS_FreeValue(ctx, obj1); - goto read_only_error; - } - } - break; - } - /* Note: at this point 'obj1' cannot be a proxy. XXX: may have - to check recursion */ - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsNull(obj1)) - break; - } - JS_FreeValue(ctx, obj1); - - if (!JS_IsObject(this_obj)) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object"); - } - - p = JS_VALUE_GET_OBJ(this_obj); - - /* modify the property in this_obj if it already exists */ - ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (ret < 0) { - JS_FreeValue(ctx, val); - return ret; - } - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JS_FreeValue(ctx, desc.getter); - JS_FreeValue(ctx, desc.setter); - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); - } else { - JS_FreeValue(ctx, desc.value); - if (!(desc.flags & JS_PROP_WRITABLE) || - p->class_id == JS_CLASS_MODULE_NS) { - read_only_error: - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorReadOnly(ctx, flags, prop); - } + if (len > INT32_MAX) + return JS_ThrowRangeError(ctx, "invalid array length"); + arr = JS_NewArray(ctx); + if (JS_IsException(arr)) + return arr; + if (len > 0) { + p = JS_VALUE_GET_OBJ(arr); + if (expand_fast_array(ctx, p, len) < 0) { + JS_FreeValue(ctx, arr); + return JS_EXCEPTION; } - ret = JS_DefineProperty(ctx, this_obj, prop, val, - JS_UNDEFINED, JS_UNDEFINED, - JS_PROP_HAS_VALUE); - JS_FreeValue(ctx, val); - return ret; + p->u.array.count = len; } + return arr; +} - ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, - flags | - JS_PROP_HAS_VALUE | - JS_PROP_HAS_ENUMERABLE | - JS_PROP_HAS_WRITABLE | - JS_PROP_HAS_CONFIGURABLE | - JS_PROP_C_W_E); - JS_FreeValue(ctx, val); - return ret; +static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) +{ + JS_FreeValue(ctx, desc->getter); + JS_FreeValue(ctx, desc->setter); + JS_FreeValue(ctx, desc->value); } /* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD, JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set, - the new property is not added and an error is raised. */ -int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, int flags) + the new property is not added and an error is raised. 'this_obj' is + the receiver. If obj != this_obj, then obj must be an object + (Reflect.set case). */ +int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, + JSAtom prop, JSValue val, JSValueConst this_obj, int flags) { JSObject *p, *p1; JSShapeProperty *prs; @@ -8434,25 +8402,37 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, #endif tag = JS_VALUE_GET_TAG(this_obj); if (unlikely(tag != JS_TAG_OBJECT)) { - switch(tag) { - case JS_TAG_NULL: - JS_FreeValue(ctx, val); - JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); - return -1; - case JS_TAG_UNDEFINED: - JS_FreeValue(ctx, val); - JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); - return -1; - default: - /* even on a primitive type we can have setters on the prototype */ + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { p = NULL; - p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, this_obj)); + p1 = JS_VALUE_GET_OBJ(obj); goto prototype_lookup; + } else { + switch(tag) { + case JS_TAG_NULL: + JS_FreeValue(ctx, val); + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); + return -1; + case JS_TAG_UNDEFINED: + JS_FreeValue(ctx, val); + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); + return -1; + default: + /* even on a primitive type we can have setters on the prototype */ + p = NULL; + p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj)); + goto prototype_lookup; + } } + } else { + p = JS_VALUE_GET_OBJ(this_obj); + p1 = JS_VALUE_GET_OBJ(obj); + if (unlikely(p != p1)) + goto retry2; } - p = JS_VALUE_GET_OBJ(this_obj); -retry: - prs = find_own_property(&pr, p, prop); + + /* fast path if obj == this_obj */ + retry: + prs = find_own_property(&pr, p1, prop); if (prs) { if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE | JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) { @@ -8484,8 +8464,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, goto read_only_prop; } } - - p1 = p; + for(;;) { if (p1->is_exotic) { if (p1->fast_array) { @@ -8509,11 +8488,19 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return -1; } typed_array_oob: - val = JS_ToNumberFree(ctx, val); - JS_FreeValue(ctx, val); - if (JS_IsException(val)) - return -1; - return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); + /* must convert the argument even if out of bound access */ + if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY || + p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) { + int64_t v; + if (JS_ToBigInt64Free(ctx, &v, val)) + return -1; + } else { + val = JS_ToNumberFree(ctx, val); + JS_FreeValue(ctx, val); + if (JS_IsException(val)) + return -1; + } + return TRUE; } } } else { @@ -8585,9 +8572,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return -1; goto retry2; } else if (!(prs->flags & JS_PROP_WRITABLE)) { - read_only_prop: - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorReadOnly(ctx, flags, prop); + goto read_only_prop; } } } @@ -8608,16 +8593,56 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); } - if (p->is_exotic) { - if (p->class_id == JS_CLASS_ARRAY && p->fast_array && - __JS_AtomIsTaggedInt(prop)) { - uint32_t idx = __JS_AtomToUInt32(prop); - if (idx == p->u.array.count) { - /* fast case */ - return add_fast_array_element(ctx, p, val, flags); + if (likely(p == JS_VALUE_GET_OBJ(obj))) { + if (p->is_exotic) { + if (p->class_id == JS_CLASS_ARRAY && p->fast_array && + __JS_AtomIsTaggedInt(prop)) { + uint32_t idx = __JS_AtomToUInt32(prop); + if (idx == p->u.array.count) { + /* fast case */ + return add_fast_array_element(ctx, p, val, flags); + } else { + goto generic_create_prop; + } } else { goto generic_create_prop; } + } else { + pr = add_property(ctx, p, prop, JS_PROP_C_W_E); + if (unlikely(!pr)) { + JS_FreeValue(ctx, val); + return -1; + } + pr->u.value = val; + return TRUE; + } + } else { + /* generic case: modify the property in this_obj if it already exists */ + ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); + if (ret < 0) { + JS_FreeValue(ctx, val); + return ret; + } + if (ret) { + if (desc.flags & JS_PROP_GETSET) { + JS_FreeValue(ctx, desc.getter); + JS_FreeValue(ctx, desc.setter); + JS_FreeValue(ctx, val); + return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); + } else { + JS_FreeValue(ctx, desc.value); + if (!(desc.flags & JS_PROP_WRITABLE) || + p->class_id == JS_CLASS_MODULE_NS) { + read_only_prop: + JS_FreeValue(ctx, val); + return JS_ThrowTypeErrorReadOnly(ctx, flags, prop); + } + } + ret = JS_DefineProperty(ctx, this_obj, prop, val, + JS_UNDEFINED, JS_UNDEFINED, + JS_PROP_HAS_VALUE); + JS_FreeValue(ctx, val); + return ret; } else { generic_create_prop: ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, @@ -8631,14 +8656,6 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return ret; } } - - pr = add_property(ctx, p, prop, JS_PROP_C_W_E); - if (unlikely(!pr)) { - JS_FreeValue(ctx, val); - return -1; - } - pr->u.value = val; - return TRUE; } /* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */ @@ -8723,7 +8740,6 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, goto ta_out_of_bound; p->u.array.u.uint32_ptr[idx] = v; break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: /* XXX: need specific conversion function */ @@ -8736,7 +8752,6 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, p->u.array.u.uint64_ptr[idx] = v; } break; -#endif case JS_CLASS_FLOAT32_ARRAY: if (JS_ToFloat64Free(ctx, &d, val)) return -1; @@ -8749,7 +8764,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, return -1; if (unlikely(idx >= (uint32_t)p->u.array.count)) { ta_out_of_bound: - return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); + return TRUE; } p->u.array.u.double_ptr[idx] = d; break; @@ -8767,7 +8782,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, JS_FreeValue(ctx, val); return -1; } - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags); JS_FreeAtom(ctx, atom); return ret; } @@ -8807,7 +8822,7 @@ int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, JSAtom atom; int ret; atom = JS_NewAtom(ctx, prop); - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW); JS_FreeAtom(ctx, atom); return ret; } @@ -9147,15 +9162,19 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, spaces. */ if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue)) goto not_configurable; + } else { + /* update the reference */ + set_value(ctx, pr->u.var_ref->pvalue, + JS_DupValue(ctx, val)); } - /* update the reference */ - set_value(ctx, pr->u.var_ref->pvalue, - JS_DupValue(ctx, val)); } /* if writable is set to false, no longer a reference (for mapped arguments) */ if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) { JSValue val1; + if (p->class_id == JS_CLASS_MODULE_NS) { + return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false"); + } if (js_shape_prepare_update(ctx, p, &prs)) return -1; val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue); @@ -9264,7 +9283,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, } idx = __JS_AtomToUInt32(prop); /* if the typed array is detached, p->u.array.count = 0 */ - if (idx >= typed_array_get_length(ctx, p)) { + if (idx >= p->u.array.count) { typed_array_oob: return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array"); } @@ -9658,7 +9677,7 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val, flags = JS_PROP_THROW_STRICT; if (is_strict_mode(ctx)) flags |= JS_PROP_NO_ADD; - return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags); + return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, ctx->global_obj, flags); } /* return -1, FALSE or TRUE. return FALSE if not configurable or @@ -9935,9 +9954,10 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val) JS_FreeValue(ctx, val); return ret; } -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); BOOL ret; @@ -9945,6 +9965,7 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val) JS_FreeValue(ctx, val); return ret; } +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: { JSBigDecimal *p = JS_VALUE_GET_PTR(val); @@ -10014,12 +10035,13 @@ static inline int to_digit(int c) } /* XXX: remove */ -static double js_strtod(const char *p, int radix, BOOL is_float) +static double js_strtod(const char *str, int radix, BOOL is_float) { double d; int c; if (!is_float || radix != 10) { + const char *p = str; uint64_t n_max, n; int int_exp, is_neg; @@ -10046,6 +10068,8 @@ static double js_strtod(const char *p, int radix, BOOL is_float) if (n <= n_max) { n = n * radix + c; } else { + if (radix == 10) + goto strtod_case; int_exp++; } p++; @@ -10057,7 +10081,8 @@ static double js_strtod(const char *p, int radix, BOOL is_float) if (is_neg) d = -d; } else { - d = strtod(p, NULL); + strtod_case: + d = strtod(str, NULL); } return d; } @@ -10075,15 +10100,16 @@ static double js_strtod(const char *p, int radix, BOOL is_float) #define ATOD_TYPE_MASK (3 << 7) #define ATOD_TYPE_FLOAT64 (0 << 7) #define ATOD_TYPE_BIG_INT (1 << 7) +#ifdef CONFIG_BIGNUM #define ATOD_TYPE_BIG_FLOAT (2 << 7) #define ATOD_TYPE_BIG_DECIMAL (3 << 7) /* assume bigint mode: floats are parsed as integers if no decimal point nor exponent */ #define ATOD_MODE_BIGINT (1 << 9) +#endif /* accept -0x1 */ #define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10) -#ifdef CONFIG_BIGNUM static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, int radix, int flags, slimb_t *pexponent) { @@ -10099,10 +10125,15 @@ static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, JS_FreeValue(ctx, val); return JS_ThrowOutOfMemory(ctx); } +#ifdef CONFIG_BIGNUM val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0); +#else + val = JS_CompactBigInt1(ctx, val, FALSE); +#endif return val; } +#ifdef CONFIG_BIGNUM static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf, int radix, int flags, slimb_t *pexponent) { @@ -10148,7 +10179,6 @@ static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf, } return val; } - #endif /* return an exception in case of memory error. Return JS_NAN if @@ -10223,8 +10253,11 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, } else { no_radix_prefix: if (!(flags & ATOD_INT_ONLY) && - (atod_type == ATOD_TYPE_FLOAT64 || - atod_type == ATOD_TYPE_BIG_FLOAT) && + (atod_type == ATOD_TYPE_FLOAT64 +#ifdef CONFIG_BIGNUM + || atod_type == ATOD_TYPE_BIG_FLOAT +#endif + ) && strstart(p, "Infinity", &p)) { #ifdef CONFIG_BIGNUM if (atod_type == ATOD_TYPE_BIG_FLOAT) { @@ -10304,36 +10337,40 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, } buf[j] = '\0'; -#ifdef CONFIG_BIGNUM if (flags & ATOD_ACCEPT_SUFFIX) { if (*p == 'n') { p++; atod_type = ATOD_TYPE_BIG_INT; - } else if (*p == 'l') { + } else +#ifdef CONFIG_BIGNUM + if (*p == 'l') { p++; atod_type = ATOD_TYPE_BIG_FLOAT; } else if (*p == 'm') { p++; atod_type = ATOD_TYPE_BIG_DECIMAL; - } else { - if (flags & ATOD_MODE_BIGINT) { - if (!is_float) - atod_type = ATOD_TYPE_BIG_INT; - if (has_legacy_octal) - goto fail; - } else { - if (is_float && radix != 10) - goto fail; - } + } else if (flags & ATOD_MODE_BIGINT) { + if (!is_float) + atod_type = ATOD_TYPE_BIG_INT; + if (has_legacy_octal) + goto fail; + } else +#endif + { + if (is_float && radix != 10) + goto fail; } } else { if (atod_type == ATOD_TYPE_FLOAT64) { +#ifdef CONFIG_BIGNUM if (flags & ATOD_MODE_BIGINT) { if (!is_float) atod_type = ATOD_TYPE_BIG_INT; if (has_legacy_octal) goto fail; - } else { + } else +#endif + { if (is_float && radix != 10) goto fail; } @@ -10354,6 +10391,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, goto fail; val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL); break; +#ifdef CONFIG_BIGNUM case ATOD_TYPE_BIG_FLOAT: if (has_legacy_octal) goto fail; @@ -10365,19 +10403,10 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, goto fail; val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL); break; +#endif default: abort(); } -#else - { - double d; - (void)has_legacy_octal; - if (is_float && radix != 10) - goto fail; - d = js_strtod(buf, radix, is_float); - val = JS_NewFloat64(ctx, d); - } -#endif done: if (buf_allocated) @@ -10415,18 +10444,18 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_DECIMAL: + case JS_TAG_BIG_INT: if (flag != TON_FLAG_NUMERIC) { JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number"); + return JS_ThrowTypeError(ctx, "cannot convert bigint to number"); } ret = val; break; - case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM + case JS_TAG_BIG_DECIMAL: if (flag != TON_FLAG_NUMERIC) { JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert bigint to number"); + return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number"); } ret = val; break; @@ -10528,9 +10557,10 @@ static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, case JS_TAG_FLOAT64: d = JS_VALUE_GET_FLOAT64(val); break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); /* XXX: there can be a double rounding issue with some @@ -10540,7 +10570,6 @@ static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, JS_FreeValue(ctx, val); } break; -#endif default: abort(); } @@ -10608,6 +10637,10 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) BOOL is_nan; a = JS_ToBigFloat(ctx, &a_s, val); + if (!a) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } if (!bf_is_finite(a)) { is_nan = bf_is_nan(a); if (is_nan) @@ -11008,9 +11041,10 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, len = v; } break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); bf_t a; @@ -11025,7 +11059,6 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, goto fail; } break; -#endif default: if (JS_TAG_IS_FLOAT64(tag)) { double d; @@ -11129,13 +11162,13 @@ static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val) u.d = JS_VALUE_GET_FLOAT64(val); return (u.u64 >> 63); } -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); /* Note: integer zeros are not necessarily positive */ return p->num.sign && !bf_is_zero(&p->num); } +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); @@ -11154,8 +11187,6 @@ static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val) } } -#ifdef CONFIG_BIGNUM - static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix) { JSValue ret; @@ -11185,6 +11216,8 @@ static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val) return js_bigint_to_string1(ctx, val, 10); } +#ifdef CONFIG_BIGNUM + static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix, limb_t prec, bf_flags_t flags) { @@ -11197,6 +11230,10 @@ static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix, if (JS_IsException(val)) return val; a = JS_ToBigFloat(ctx, &a_s, val); + if (!a) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } saved_sign = a->sign; if (a->expn == BF_EXP_ZERO) a->sign = 0; @@ -11253,6 +11290,8 @@ static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val, int saved_sign; a = JS_ToBigDecimal(ctx, val); + if (!a) + return JS_EXCEPTION; saved_sign = a->sign; if (a->expn == BF_EXP_ZERO) a->sign = 0; @@ -11585,9 +11624,9 @@ JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToProperty case JS_TAG_FLOAT64: return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0, JS_DTOA_VAR_FORMAT); -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: return ctx->rt->bigint_ops.to_string(ctx, val); +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: return ctx->rt->bigfloat_ops.to_string(ctx, val); case JS_TAG_BIG_DECIMAL: @@ -11748,10 +11787,8 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) case JS_CLASS_UINT16_ARRAY: case JS_CLASS_INT32_ARRAY: case JS_CLASS_UINT32_ARRAY: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: -#endif case JS_CLASS_FLOAT32_ARRAY: case JS_CLASS_FLOAT64_ARRAY: { @@ -11878,7 +11915,6 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, case JS_TAG_FLOAT64: printf("%.14g", JS_VALUE_GET_FLOAT64(val)); break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); @@ -11889,6 +11925,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, bf_realloc(&rt->bf_ctx, str, 0); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); @@ -11990,8 +12027,6 @@ static double js_pow(double a, double b) } } -#ifdef CONFIG_BIGNUM - JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v) { JSValue val; @@ -12036,70 +12071,6 @@ JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) return val; } -/* if the returned bigfloat is allocated it is equal to - 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return - NULL in case of error. */ -static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val) -{ - uint32_t tag; - bf_t *r; - JSBigFloat *p; - - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - r = buf; - bf_init(ctx->bf_ctx, r); - if (bf_set_si(r, JS_VALUE_GET_INT(val))) - goto fail; - break; - case JS_TAG_FLOAT64: - r = buf; - bf_init(ctx->bf_ctx, r); - if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) { - fail: - bf_delete(r); - return NULL; - } - break; - case JS_TAG_BIG_INT: - case JS_TAG_BIG_FLOAT: - p = JS_VALUE_GET_PTR(val); - r = &p->num; - break; - case JS_TAG_UNDEFINED: - default: - r = buf; - bf_init(ctx->bf_ctx, r); - bf_set_nan(r); - break; - } - return r; -} - -/* return NULL if invalid type */ -static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val) -{ - uint32_t tag; - JSBigDecimal *p; - bfdec_t *r; - - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_BIG_DECIMAL: - p = JS_VALUE_GET_PTR(val); - r = &p->num; - break; - default: - JS_ThrowTypeError(ctx, "bigdecimal expected"); - r = NULL; - break; - } - return r; -} - /* return NaN if bad bigint literal */ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) { @@ -12117,8 +12088,10 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) val = JS_NewBigInt64(ctx, 0); } else { flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT; +#ifdef CONFIG_BIGNUM if (is_math_mode(ctx)) flags |= ATOD_MODE_BIGINT; +#endif val = js_atof(ctx, p, &p, 0, flags); p += skip_spaces(p); if (!JS_IsException(val)) { @@ -12179,6 +12152,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) p = JS_VALUE_GET_PTR(val); r = &p->num; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: if (!is_math_mode(ctx)) goto fail; @@ -12191,6 +12165,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) bf_rint(r, BF_RNDZ); JS_FreeValue(ctx, val); break; +#endif case JS_TAG_STRING: val = JS_StringToBigIntErr(ctx, val); if (JS_IsException(val)) @@ -12251,7 +12226,7 @@ static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf) } else { JSBigFloat *p = (JSBigFloat *)((uint8_t *)a - offsetof(JSBigFloat, num)); - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_FLOAT, p)); + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_INT, p)); } } @@ -12286,6 +12261,129 @@ static JSBigFloat *js_new_bf(JSContext *ctx) return p; } +static JSValue JS_NewBigInt(JSContext *ctx) +{ + JSBigFloat *p; + p = js_malloc(ctx, sizeof(*p)); + if (!p) + return JS_EXCEPTION; + p->header.ref_count = 1; + bf_init(ctx->bf_ctx, &p->num); + return JS_MKPTR(JS_TAG_BIG_INT, p); +} + +static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, + BOOL convert_to_safe_integer) +{ + int64_t v; + bf_t *a; + + if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT) + return val; /* fail safe */ + a = JS_GetBigInt(val); + if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 && + v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) { + JS_FreeValue(ctx, val); + return JS_NewInt64(ctx, v); + } else if (a->expn == BF_EXP_ZERO && a->sign) { + JSBigFloat *p = JS_VALUE_GET_PTR(val); + assert(p->header.ref_count == 1); + a->sign = 0; + } + return val; +} + +/* Convert the big int to a safe integer if in math mode. normalize + the zero representation. Could also be used to convert the bigint + to a short bigint value. The reference count of the value must be + 1. Cannot fail */ +static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val) +{ + return JS_CompactBigInt1(ctx, val, is_math_mode(ctx)); +} + +static JSValue throw_bf_exception(JSContext *ctx, int status) +{ + const char *str; + if (status & BF_ST_MEM_ERROR) + return JS_ThrowOutOfMemory(ctx); + if (status & BF_ST_DIVIDE_ZERO) { + str = "division by zero"; + } else if (status & BF_ST_INVALID_OP) { + str = "invalid operation"; + } else { + str = "integer overflow"; + } + return JS_ThrowRangeError(ctx, "%s", str); +} + +/* if the returned bigfloat is allocated it is equal to + 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return + NULL in case of error. */ +static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val) +{ + uint32_t tag; + bf_t *r; + JSBigFloat *p; + + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + r = buf; + bf_init(ctx->bf_ctx, r); + if (bf_set_si(r, JS_VALUE_GET_INT(val))) + goto fail; + break; + case JS_TAG_FLOAT64: + r = buf; + bf_init(ctx->bf_ctx, r); + if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) { + fail: + bf_delete(r); + return NULL; + } + break; + case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM + case JS_TAG_BIG_FLOAT: +#endif + p = JS_VALUE_GET_PTR(val); + r = &p->num; + break; + case JS_TAG_UNDEFINED: + default: + r = buf; + bf_init(ctx->bf_ctx, r); + bf_set_nan(r); + break; + } + return r; +} + +#ifdef CONFIG_BIGNUM +/* return NULL if invalid type */ +static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val) +{ + uint32_t tag; + JSBigDecimal *p; + bfdec_t *r; + + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_BIG_DECIMAL: + p = JS_VALUE_GET_PTR(val); + r = &p->num; + break; + default: + JS_ThrowTypeError(ctx, "bigdecimal expected"); + r = NULL; + break; + } + return r; +} + static JSValue JS_NewBigFloat(JSContext *ctx) { JSBigFloat *p; @@ -12308,47 +12406,6 @@ static JSValue JS_NewBigDecimal(JSContext *ctx) return JS_MKPTR(JS_TAG_BIG_DECIMAL, p); } -static JSValue JS_NewBigInt(JSContext *ctx) -{ - JSBigFloat *p; - p = js_malloc(ctx, sizeof(*p)); - if (!p) - return JS_EXCEPTION; - p->header.ref_count = 1; - bf_init(ctx->bf_ctx, &p->num); - return JS_MKPTR(JS_TAG_BIG_INT, p); -} - -static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, - BOOL convert_to_safe_integer) -{ - int64_t v; - bf_t *a; - - if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT) - return val; /* fail safe */ - a = JS_GetBigInt(val); - if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 && - v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) { - JS_FreeValue(ctx, val); - return JS_NewInt64(ctx, v); - } else if (a->expn == BF_EXP_ZERO && a->sign) { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - assert(p->header.ref_count == 1); - a->sign = 0; - } - return val; -} - -/* Convert the big int to a safe integer if in math mode. normalize - the zero representation. Could also be used to convert the bigint - to a short bigint value. The reference count of the value must be - 1. Cannot fail */ -static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val) -{ - return JS_CompactBigInt1(ctx, val, is_math_mode(ctx)); -} - /* must be kept in sync with JSOverloadableOperatorEnum */ /* XXX: use atoms ? */ static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = { @@ -12672,46 +12729,37 @@ static __exception int js_call_unary_op_fallback(JSContext *ctx, return -1; } -static JSValue throw_bf_exception(JSContext *ctx, int status) -{ - const char *str; - if (status & BF_ST_MEM_ERROR) - return JS_ThrowOutOfMemory(ctx); - if (status & BF_ST_DIVIDE_ZERO) { - str = "division by zero"; - } else if (status & BF_ST_INVALID_OP) { - str = "invalid operation"; - } else { - str = "integer overflow"; - } - return JS_ThrowRangeError(ctx, "%s", str); -} - -static int js_unary_arith_bigint(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1) +static int js_unary_arith_bigfloat(JSContext *ctx, + JSValue *pres, OPCodeEnum op, JSValue op1) { bf_t a_s, *r, *a; int ret, v; JSValue res; if (op == OP_plus && !is_math_mode(ctx)) { - JS_ThrowTypeError(ctx, "bigint argument with unary +"); + JS_ThrowTypeError(ctx, "bigfloat argument with unary +"); JS_FreeValue(ctx, op1); return -1; } - res = JS_NewBigInt(ctx); + + res = JS_NewBigFloat(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); return -1; } - r = JS_GetBigInt(res); - a = JS_ToBigInt(ctx, &a_s, op1); + r = JS_GetBigFloat(res); + a = JS_ToBigFloat(ctx, &a_s, op1); + if (!a) { + JS_FreeValue(ctx, res); + JS_FreeValue(ctx, op1); + return -1; + } ret = 0; switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; - ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); + ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags); break; case OP_plus: ret = bf_set(r, a); @@ -12720,66 +12768,65 @@ static int js_unary_arith_bigint(JSContext *ctx, ret = bf_set(r, a); bf_neg(r); break; - case OP_not: - ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ); - bf_neg(r); - break; default: abort(); } - JS_FreeBigInt(ctx, a, &a_s); + if (a == &a_s) + bf_delete(a); JS_FreeValue(ctx, op1); - if (unlikely(ret)) { + if (unlikely(ret & BF_ST_MEM_ERROR)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } - res = JS_CompactBigInt(ctx, res); *pres = res; return 0; } -static int js_unary_arith_bigfloat(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1) +static int js_unary_arith_bigdecimal(JSContext *ctx, + JSValue *pres, OPCodeEnum op, JSValue op1) { - bf_t a_s, *r, *a; + bfdec_t *r, *a; int ret, v; JSValue res; if (op == OP_plus && !is_math_mode(ctx)) { - JS_ThrowTypeError(ctx, "bigfloat argument with unary +"); + JS_ThrowTypeError(ctx, "bigdecimal argument with unary +"); JS_FreeValue(ctx, op1); return -1; } - res = JS_NewBigFloat(ctx); + res = JS_NewBigDecimal(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); return -1; } - r = JS_GetBigFloat(res); - a = JS_ToBigFloat(ctx, &a_s, op1); + r = JS_GetBigDecimal(res); + a = JS_ToBigDecimal(ctx, op1); + if (!a) { + JS_FreeValue(ctx, res); + JS_FreeValue(ctx, op1); + return -1; + } ret = 0; switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; - ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags); + ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); break; case OP_plus: - ret = bf_set(r, a); + ret = bfdec_set(r, a); break; case OP_neg: - ret = bf_set(r, a); - bf_neg(r); + ret = bfdec_set(r, a); + bfdec_neg(r); break; default: abort(); } - if (a == &a_s) - bf_delete(a); JS_FreeValue(ctx, op1); - if (unlikely(ret & BF_ST_MEM_ERROR)) { + if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; @@ -12788,49 +12835,61 @@ static int js_unary_arith_bigfloat(JSContext *ctx, return 0; } -static int js_unary_arith_bigdecimal(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1) +#endif /* CONFIG_BIGNUM */ + +static int js_unary_arith_bigint(JSContext *ctx, + JSValue *pres, OPCodeEnum op, JSValue op1) { - bfdec_t *r, *a; + bf_t a_s, *r, *a; int ret, v; JSValue res; if (op == OP_plus && !is_math_mode(ctx)) { - JS_ThrowTypeError(ctx, "bigdecimal argument with unary +"); + JS_ThrowTypeError(ctx, "bigint argument with unary +"); JS_FreeValue(ctx, op1); return -1; } - - res = JS_NewBigDecimal(ctx); + res = JS_NewBigInt(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); return -1; } - r = JS_GetBigDecimal(res); - a = JS_ToBigDecimal(ctx, op1); + r = JS_GetBigInt(res); + a = JS_ToBigInt(ctx, &a_s, op1); + if (!a) { + JS_FreeValue(ctx, res); + JS_FreeValue(ctx, op1); + return -1; + } ret = 0; switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; - ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); + ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); break; case OP_plus: - ret = bfdec_set(r, a); + ret = bf_set(r, a); break; case OP_neg: - ret = bfdec_set(r, a); - bfdec_neg(r); + ret = bf_set(r, a); + bf_neg(r); + break; + case OP_not: + ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ); + bf_neg(r); break; default: abort(); } + JS_FreeBigInt(ctx, a, &a_s); JS_FreeValue(ctx, op1); if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } + res = JS_CompactBigInt(ctx, res); *pres = res; return 0; } @@ -12839,16 +12898,18 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { - JSValue op1, val; - int v, ret; + JSValue op1; + int v; uint32_t tag; op1 = sp[-1]; /* fast path for float64 */ if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) goto handle_float64; +#ifdef CONFIG_BIGNUM if (JS_IsObject(op1)) { - ret = js_call_unary_op_fallback(ctx, &val, op1, op); + JSValue val; + int ret = js_call_unary_op_fallback(ctx, &val, op1, op); if (ret < 0) return -1; if (ret) { @@ -12857,7 +12918,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, return 0; } } - +#endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) goto exception; @@ -12894,6 +12955,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1)) goto exception; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1)) goto exception; @@ -12902,6 +12964,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1)) goto exception; break; +#endif default: handle_float64: { @@ -12952,12 +13015,13 @@ static __exception int js_post_inc_slow(JSContext *ctx, static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) { - JSValue op1, val; - int ret; + JSValue op1; op1 = sp[-1]; +#ifdef CONFIG_BIGNUM if (JS_IsObject(op1)) { - ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not); + JSValue val; + int ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not); if (ret < 0) return -1; if (ret) { @@ -12966,7 +13030,7 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) return 0; } } - +#endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) goto exception; @@ -12985,67 +13049,6 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) return -1; } -static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, - JSValue *pres, JSValue op1, JSValue op2) -{ - bf_t a_s, b_s, *r, *a, *b; - int ret; - JSValue res; - - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) { - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return -1; - } - r = JS_GetBigFloat(res); - a = JS_ToBigFloat(ctx, &a_s, op1); - b = JS_ToBigFloat(ctx, &b_s, op2); - bf_init(ctx->bf_ctx, r); - switch(op) { - case OP_add: - ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_sub: - ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_mul: - ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_div: - ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_math_mod: - /* Euclidian remainder */ - ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, - BF_DIVREM_EUCLIDIAN); - break; - case OP_mod: - ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, - BF_RNDZ); - break; - case OP_pow: - ret = bf_pow(r, a, b, ctx->fp_env.prec, - ctx->fp_env.flags | BF_POW_JS_QUIRKS); - break; - default: - abort(); - } - if (a == &a_s) - bf_delete(a); - if (b == &b_s) - bf_delete(b); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (unlikely(ret & BF_ST_MEM_ERROR)) { - JS_FreeValue(ctx, res); - throw_bf_exception(ctx, ret); - return -1; - } - *pres = res; - return 0; -} - static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, JSValue *pres, JSValue op1, JSValue op2) { @@ -13087,11 +13090,13 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, goto math_mode_div_pow; } break; +#ifdef CONFIG_BIGNUM case OP_math_mod: /* Euclidian remainder */ ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP; break; +#endif case OP_mod: ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ) & BF_ST_INVALID_OP; @@ -13102,6 +13107,7 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, ret = BF_ST_INVALID_OP; } else { math_mode_div_pow: +#ifdef CONFIG_BIGNUM JS_FreeValue(ctx, res); ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op); if (ret != 0) { @@ -13142,6 +13148,9 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, } *pres = res; return 0; +#else + abort(); +#endif } } else { ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS); @@ -13201,6 +13210,79 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, return -1; } +#ifdef CONFIG_BIGNUM +static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, + JSValue *pres, JSValue op1, JSValue op2) +{ + bf_t a_s, b_s, *r, *a, *b; + int ret; + JSValue res; + + res = JS_NewBigFloat(ctx); + if (JS_IsException(res)) + goto fail; + r = JS_GetBigFloat(res); + a = JS_ToBigFloat(ctx, &a_s, op1); + if (!a) { + JS_FreeValue(ctx, res); + goto fail; + } + b = JS_ToBigFloat(ctx, &b_s, op2); + if (!b) { + if (a == &a_s) + bf_delete(a); + JS_FreeValue(ctx, res); + goto fail; + } + bf_init(ctx->bf_ctx, r); + switch(op) { + case OP_add: + ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); + break; + case OP_sub: + ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); + break; + case OP_mul: + ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); + break; + case OP_div: + ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); + break; + case OP_math_mod: + /* Euclidian remainder */ + ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, + BF_DIVREM_EUCLIDIAN); + break; + case OP_mod: + ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, + BF_RNDZ); + break; + case OP_pow: + ret = bf_pow(r, a, b, ctx->fp_env.prec, + ctx->fp_env.flags | BF_POW_JS_QUIRKS); + break; + default: + abort(); + } + if (a == &a_s) + bf_delete(a); + if (b == &b_s) + bf_delete(b); + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + if (unlikely(ret & BF_ST_MEM_ERROR)) { + JS_FreeValue(ctx, res); + throw_bf_exception(ctx, ret); + return -1; + } + *pres = res; + return 0; + fail: + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + return -1; +} + /* b must be a positive integer */ static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b) { @@ -13287,13 +13369,13 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, JS_FreeValue(ctx, op2); return -1; } +#endif /* CONFIG_BIGNUM */ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { - JSValue op1, op2, res; + JSValue op1, op2; uint32_t tag1, tag2; - int ret; double d1, d2; op1 = sp[-2]; @@ -13307,12 +13389,14 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s goto handle_float64; } +#ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { - ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); + JSValue res; + int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); if (ret != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); @@ -13324,6 +13408,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s } } } +#endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { @@ -13362,6 +13447,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s goto handle_bigint; sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2); return 0; +#ifdef CONFIG_BIGNUM case OP_math_mod: if (unlikely(v2 == 0)) { throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO); @@ -13375,6 +13461,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s v += v2; } break; +#endif case OP_mod: if (v1 < 0 || v2 <= 0) { sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2)); @@ -13395,13 +13482,17 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s abort(); } sp[-2] = JS_NewInt64(ctx, v); - } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { + } else +#ifdef CONFIG_BIGNUM + if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; - } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { + } else +#endif + if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { handle_bigint: if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; @@ -13430,6 +13521,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s case OP_mod: dr = fmod(d1, d2); break; +#ifdef CONFIG_BIGNUM case OP_math_mod: d2 = fabs(d2); dr = fmod(d1, d2); @@ -13437,6 +13529,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s if (dr < 0) dr += d2; break; +#endif case OP_pow: dr = js_pow(d1, d2); break; @@ -13454,9 +13547,8 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) { - JSValue op1, op2, res; + JSValue op1, op2; uint32_t tag1, tag2; - int ret; op1 = sp[-2]; op2 = sp[-1]; @@ -13473,6 +13565,7 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) } if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) { +#ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED && @@ -13480,8 +13573,9 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED && tag1 != JS_TAG_STRING))) { - ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add, - FALSE, HINT_NONE); + JSValue res; + int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add, + FALSE, HINT_NONE); if (ret != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); @@ -13493,7 +13587,7 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) } } } - +#endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -13536,13 +13630,17 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) v2 = JS_VALUE_GET_INT(op2); v = (int64_t)v1 + (int64_t)v2; sp[-2] = JS_NewInt64(ctx, v); - } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { + } else +#ifdef CONFIG_BIGNUM + if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) goto exception; } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) goto exception; - } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { + } else +#endif + if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { handle_bigint: if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) goto exception; @@ -13570,8 +13668,7 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { - JSValue op1, op2, res; - int ret; + JSValue op1, op2; uint32_t tag1, tag2; uint32_t v1, v2, r; @@ -13580,12 +13677,14 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); +#ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { - ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); + JSValue res; + int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); if (ret != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); @@ -13597,6 +13696,7 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, } } } +#endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { @@ -13707,6 +13807,7 @@ static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op, return res; } +#ifdef CONFIG_BIGNUM static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, JSValue op1, JSValue op2) { @@ -13726,8 +13827,8 @@ static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, JS_FreeValue(ctx, op1); return -1; } - a = JS_ToBigDecimal(ctx, op1); - b = JS_ToBigDecimal(ctx, op2); + a = JS_ToBigDecimal(ctx, op1); /* cannot fail */ + b = JS_ToBigDecimal(ctx, op2); /* cannot fail */ switch(op) { case OP_lt: @@ -13752,11 +13853,12 @@ static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, JS_FreeValue(ctx, op2); return res; } +#endif /* !CONFIG_BIGNUM */ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { - JSValue op1, op2, ret; + JSValue op1, op2; int res; uint32_t tag1, tag2; @@ -13764,11 +13866,13 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, op2 = sp[-1]; tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); +#ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { + JSValue ret; res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op, FALSE, HINT_NUMBER); if (res != 0) { @@ -13782,6 +13886,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, } } } +#endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -13856,6 +13961,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); +#ifdef CONFIG_BIGNUM if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2); if (res < 0) @@ -13864,7 +13970,9 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2); if (res < 0) goto exception; - } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { + } else +#endif + if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2); if (res < 0) goto exception; @@ -13912,14 +14020,20 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, static BOOL tag_is_number(uint32_t tag) { return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT || - tag == JS_TAG_FLOAT64 || tag == JS_TAG_BIG_FLOAT || - tag == JS_TAG_BIG_DECIMAL); + tag == JS_TAG_FLOAT64 +#ifdef CONFIG_BIGNUM + || tag == JS_TAG_BIG_FLOAT || tag == JS_TAG_BIG_DECIMAL +#endif + ); } static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, BOOL is_neq) { - JSValue op1, op2, ret; + JSValue op1, op2; +#ifdef CONFIG_BIGNUM + JSValue ret; +#endif int res; uint32_t tag1, tag2; @@ -13947,7 +14061,9 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, d2 = JS_VALUE_GET_INT(op2); } res = (d1 == d2); - } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { + } else +#ifdef CONFIG_BIGNUM + if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2); if (res < 0) goto exception; @@ -13955,12 +14071,15 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2); if (res < 0) goto exception; - } else { + } else +#endif + { res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2); if (res < 0) goto exception; } } else if (tag1 == tag2) { +#ifdef CONFIG_BIGNUM if (tag1 == JS_TAG_OBJECT) { /* try the fallback operator */ res = js_call_binary_op_fallback(ctx, &ret, op1, op2, @@ -13977,6 +14096,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, } } } +#endif res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) || (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) { @@ -14024,7 +14144,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) || (tag2 == JS_TAG_OBJECT && (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) { - +#ifdef CONFIG_BIGNUM /* try the fallback operator */ res = js_call_binary_op_fallback(ctx, &ret, op1, op2, is_neq ? OP_neq : OP_eq, @@ -14039,7 +14159,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, return 0; } } - +#endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -14111,6 +14231,7 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) return -1; } +#ifdef CONFIG_BIGNUM static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, int64_t exponent) { @@ -14145,8 +14266,10 @@ static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp) op1 = sp[-2]; op2 = sp[-1]; a = JS_ToBigFloat(ctx, &a_s, op1); - if (!a) + if (!a) { + JS_FreeValue(ctx, res); return -1; + } if (JS_IsBigInt(ctx, op2)) { ret = JS_ToBigInt64(ctx, &e, op2); } else { @@ -14167,395 +14290,7 @@ static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp) sp[-2] = res; return 0; } - -#else /* !CONFIG_BIGNUM */ - -static JSValue JS_ThrowUnsupportedBigint(JSContext *ctx) -{ - return JS_ThrowTypeError(ctx, "bigint is not supported"); -} - -JSValue JS_NewBigInt64(JSContext *ctx, int64_t v) -{ - return JS_ThrowUnsupportedBigint(ctx); -} - -JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) -{ - return JS_ThrowUnsupportedBigint(ctx); -} - -int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val) -{ - JS_ThrowUnsupportedBigint(ctx); - *pres = 0; - return -1; -} - -static no_inline __exception int js_unary_arith_slow(JSContext *ctx, - JSValue *sp, - OPCodeEnum op) -{ - JSValue op1; - double d; - - op1 = sp[-1]; - if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) { - sp[-1] = JS_UNDEFINED; - return -1; - } - switch(op) { - case OP_inc: - d++; - break; - case OP_dec: - d--; - break; - case OP_plus: - break; - case OP_neg: - d = -d; - break; - default: - abort(); - } - sp[-1] = JS_NewFloat64(ctx, d); - return 0; -} - -/* specific case necessary for correct return value semantics */ -static __exception int js_post_inc_slow(JSContext *ctx, - JSValue *sp, OPCodeEnum op) -{ - JSValue op1; - double d, r; - - op1 = sp[-1]; - if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) { - sp[-1] = JS_UNDEFINED; - return -1; - } - r = d + 2 * (op - OP_post_dec) - 1; - sp[0] = JS_NewFloat64(ctx, r); - sp[-1] = JS_NewFloat64(ctx, d); - return 0; -} - -static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp, - OPCodeEnum op) -{ - JSValue op1, op2; - double d1, d2, r; - - op1 = sp[-2]; - op2 = sp[-1]; - if (unlikely(JS_ToFloat64Free(ctx, &d1, op1))) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (unlikely(JS_ToFloat64Free(ctx, &d2, op2))) { - goto exception; - } - switch(op) { - case OP_sub: - r = d1 - d2; - break; - case OP_mul: - r = d1 * d2; - break; - case OP_div: - r = d1 / d2; - break; - case OP_mod: - r = fmod(d1, d2); - break; - case OP_pow: - r = js_pow(d1, d2); - break; - default: - abort(); - } - sp[-2] = JS_NewFloat64(ctx, r); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - uint32_t tag1, tag2; - - op1 = sp[-2]; - op2 = sp[-1]; - tag1 = JS_VALUE_GET_TAG(op1); - tag2 = JS_VALUE_GET_TAG(op2); - if ((tag1 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag1)) && - (tag2 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag2))) { - goto add_numbers; - } else { - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - tag1 = JS_VALUE_GET_TAG(op1); - tag2 = JS_VALUE_GET_TAG(op2); - if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) { - sp[-2] = JS_ConcatString(ctx, op1, op2); - if (JS_IsException(sp[-2])) - goto exception; - } else { - double d1, d2; - add_numbers: - if (JS_ToFloat64Free(ctx, &d1, op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (JS_ToFloat64Free(ctx, &d2, op2)) - goto exception; - sp[-2] = JS_NewFloat64(ctx, d1 + d2); - } - } - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline __exception int js_binary_logic_slow(JSContext *ctx, - JSValue *sp, - OPCodeEnum op) -{ - JSValue op1, op2; - uint32_t v1, v2, r; - - op1 = sp[-2]; - op2 = sp[-1]; - if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2))) - goto exception; - switch(op) { - case OP_shl: - r = v1 << (v2 & 0x1f); - break; - case OP_sar: - r = (int)v1 >> (v2 & 0x1f); - break; - case OP_and: - r = v1 & v2; - break; - case OP_or: - r = v1 | v2; - break; - case OP_xor: - r = v1 ^ v2; - break; - default: - abort(); - } - sp[-2] = JS_NewInt32(ctx, r); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) -{ - int32_t v1; - - if (unlikely(JS_ToInt32Free(ctx, &v1, sp[-1]))) { - sp[-1] = JS_UNDEFINED; - return -1; - } - sp[-1] = JS_NewInt32(ctx, ~v1); - return 0; -} - -static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, - OPCodeEnum op) -{ - JSValue op1, op2; - int res; - - op1 = sp[-2]; - op2 = sp[-1]; - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING && - JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) { - JSString *p1, *p2; - p1 = JS_VALUE_GET_STRING(op1); - p2 = JS_VALUE_GET_STRING(op2); - res = js_string_compare(ctx, p1, p2); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - switch(op) { - case OP_lt: - res = (res < 0); - break; - case OP_lte: - res = (res <= 0); - break; - case OP_gt: - res = (res > 0); - break; - default: - case OP_gte: - res = (res >= 0); - break; - } - } else { - double d1, d2; - if (JS_ToFloat64Free(ctx, &d1, op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (JS_ToFloat64Free(ctx, &d2, op2)) - goto exception; - switch(op) { - case OP_lt: - res = (d1 < d2); /* if NaN return false */ - break; - case OP_lte: - res = (d1 <= d2); /* if NaN return false */ - break; - case OP_gt: - res = (d1 > d2); /* if NaN return false */ - break; - default: - case OP_gte: - res = (d1 >= d2); /* if NaN return false */ - break; - } - } - sp[-2] = JS_NewBool(ctx, res); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, - BOOL is_neq) -{ - JSValue op1, op2; - int tag1, tag2; - BOOL res; - - op1 = sp[-2]; - op2 = sp[-1]; - redo: - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - if (tag1 == tag2 || - (tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) || - (tag2 == JS_TAG_INT && tag1 == JS_TAG_FLOAT64)) { - res = js_strict_eq(ctx, op1, op2); - } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) || - (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) { - res = TRUE; - } else if ((tag1 == JS_TAG_STRING && (tag2 == JS_TAG_INT || - tag2 == JS_TAG_FLOAT64)) || - (tag2 == JS_TAG_STRING && (tag1 == JS_TAG_INT || - tag1 == JS_TAG_FLOAT64))) { - double d1; - double d2; - if (JS_ToFloat64Free(ctx, &d1, op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (JS_ToFloat64Free(ctx, &d2, op2)) - goto exception; - res = (d1 == d2); - } else if (tag1 == JS_TAG_BOOL) { - op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1)); - goto redo; - } else if (tag2 == JS_TAG_BOOL) { - op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2)); - goto redo; - } else if (tag1 == JS_TAG_OBJECT && - (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64 || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) { - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - goto redo; - } else if (tag2 == JS_TAG_OBJECT && - (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64 || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL)) { - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - goto redo; - } else { - /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */ - if ((JS_IsHTMLDDA(ctx, op1) && - (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || - (JS_IsHTMLDDA(ctx, op2) && - (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { - res = TRUE; - } else { - res = FALSE; - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - } - sp[-2] = JS_NewBool(ctx, res ^ is_neq); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - uint32_t v1, v2, r; - - op1 = sp[-2]; - op2 = sp[-1]; - if (unlikely(JS_ToUint32Free(ctx, &v1, op1))) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (unlikely(JS_ToUint32Free(ctx, &v2, op2))) - goto exception; - r = v1 >> (v2 & 0x1f); - sp[-2] = JS_NewUint32(ctx, r); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -#endif /* !CONFIG_BIGNUM */ +#endif /* XXX: Should take JSValueConst arguments */ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, @@ -14649,7 +14384,6 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, res = (d1 == d2); /* if NaN return false and +0 == -0 */ } goto done_no_free; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: { bf_t a_s, *a, b_s, *b; @@ -14657,8 +14391,8 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, res = FALSE; break; } - a = JS_ToBigFloat(ctx, &a_s, op1); - b = JS_ToBigFloat(ctx, &b_s, op2); + a = JS_ToBigFloat(ctx, &a_s, op1); /* cannot fail */ + b = JS_ToBigFloat(ctx, &b_s, op2); /* cannot fail */ res = bf_cmp_eq(a, b); if (a == &a_s) bf_delete(a); @@ -14666,6 +14400,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, bf_delete(b); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p1, *p2; @@ -14770,6 +14505,43 @@ static __exception int js_operator_in(JSContext *ctx, JSValue *sp) return 0; } +static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp) +{ + JSValue op1, op2; + int ret; + + op1 = sp[-2]; /* object */ + op2 = sp[-1]; /* field name or method function */ + + if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) { + JS_ThrowTypeError(ctx, "invalid 'in' operand"); + return -1; + } + if (JS_IsObject(op2)) { + /* method: use the brand */ + ret = JS_CheckBrand(ctx, op1, op2); + if (ret < 0) + return -1; + } else { + JSAtom atom; + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + /* field */ + atom = JS_ValueToAtom(ctx, op2); + if (unlikely(atom == JS_ATOM_NULL)) + return -1; + p = JS_VALUE_GET_OBJ(op1); + prs = find_own_property(&pr, p, atom); + JS_FreeAtom(ctx, atom); + ret = (prs != NULL); + } + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + sp[-2] = JS_NewBool(ctx, ret); + return 0; +} + static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj, JSAtom atom) { @@ -14811,10 +14583,10 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) tag = JS_VALUE_GET_NORM_TAG(op1); switch(tag) { -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: atom = JS_ATOM_bigint; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: atom = JS_ATOM_bigfloat; break; @@ -15068,10 +14840,10 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst * static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) { - JSObject *p; + JSObject *p, *p1; JSPropertyEnum *tab_atom; int i; - JSValue enum_obj, obj1; + JSValue enum_obj; JSForInIterator *it; uint32_t tag, tab_atom_count; @@ -15094,14 +14866,65 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) it->is_array = FALSE; it->obj = obj; it->idx = 0; - p = JS_VALUE_GET_OBJ(enum_obj); - p->u.for_in_iterator = it; + it->tab_atom = NULL; + it->atom_count = 0; + it->in_prototype_chain = FALSE; + p1 = JS_VALUE_GET_OBJ(enum_obj); + p1->u.for_in_iterator = it; if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) return enum_obj; - /* fast path: assume no enumerable properties in the prototype chain */ - obj1 = JS_DupValue(ctx, obj); + p = JS_VALUE_GET_OBJ(obj); + if (p->fast_array) { + JSShape *sh; + JSShapeProperty *prs; + /* check that there are no enumerable normal fields */ + sh = p->shape; + for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { + if (prs->flags & JS_PROP_ENUMERABLE) + goto normal_case; + } + /* for fast arrays, we only store the number of elements */ + it->is_array = TRUE; + it->atom_count = p->u.array.count; + } else { + normal_case: + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, + JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { + JS_FreeValue(ctx, enum_obj); + return JS_EXCEPTION; + } + it->tab_atom = tab_atom; + it->atom_count = tab_atom_count; + } + return enum_obj; +} + +/* obj -> enum_obj */ +static __exception int js_for_in_start(JSContext *ctx, JSValue *sp) +{ + sp[-1] = build_for_in_iterator(ctx, sp[-1]); + if (JS_IsException(sp[-1])) + return -1; + return 0; +} + +/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */ +static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx, + JSValueConst enum_obj) +{ + JSObject *p; + JSForInIterator *it; + JSPropertyEnum *tab_atom; + uint32_t tab_atom_count, i; + JSValue obj1; + + p = JS_VALUE_GET_OBJ(enum_obj); + it = p->u.for_in_iterator; + + /* check if there are enumerable properties in the prototype chain (fast path) */ + obj1 = JS_DupValue(ctx, it->obj); for(;;) { obj1 = JS_GetPrototypeFree(ctx, obj1); if (JS_IsNull(obj1)) @@ -15125,75 +14948,29 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) goto fail; } } - - p = JS_VALUE_GET_OBJ(obj); - - if (p->fast_array) { - JSShape *sh; - JSShapeProperty *prs; - /* check that there are no enumerable normal fields */ - sh = p->shape; - for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { - if (prs->flags & JS_PROP_ENUMERABLE) - goto normal_case; - } - /* for fast arrays, we only store the number of elements */ - it->is_array = TRUE; - it->array_length = p->u.array.count; - } else { - normal_case: - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, - JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) - goto fail; - for(i = 0; i < tab_atom_count; i++) { - JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0); - } - js_free_prop_enum(ctx, tab_atom, tab_atom_count); - } - return enum_obj; + JS_FreeValue(ctx, obj1); + return 1; slow_path: - /* non enumerable properties hide the enumerables ones in the - prototype chain */ - obj1 = JS_DupValue(ctx, obj); - for(;;) { + /* add the visited properties, even if they are not enumerable */ + if (it->is_array) { if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, - JS_VALUE_GET_OBJ(obj1), + JS_VALUE_GET_OBJ(it->obj), JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { - JS_FreeValue(ctx, obj1); goto fail; } - for(i = 0; i < tab_atom_count; i++) { - JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL, - (tab_atom[i].is_enumerable ? - JS_PROP_ENUMERABLE : 0)); - } - js_free_prop_enum(ctx, tab_atom, tab_atom_count); - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsNull(obj1)) - break; - if (JS_IsException(obj1)) - goto fail; - /* must check for timeout to avoid infinite loop */ - if (js_poll_interrupts(ctx)) { - JS_FreeValue(ctx, obj1); + it->is_array = FALSE; + it->tab_atom = tab_atom; + it->atom_count = tab_atom_count; + } + + for(i = 0; i < it->atom_count; i++) { + if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0) goto fail; - } } - return enum_obj; - - fail: - JS_FreeValue(ctx, enum_obj); - return JS_EXCEPTION; -} - -/* obj -> enum_obj */ -static __exception int js_for_in_start(JSContext *ctx, JSValue *sp) -{ - sp[-1] = build_for_in_iterator(ctx, sp[-1]); - if (JS_IsException(sp[-1])) - return -1; return 0; + fail: + return -1; } /* enum_obj -> enum_obj value done */ @@ -15203,6 +14980,8 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) JSObject *p; JSAtom prop; JSForInIterator *it; + JSPropertyEnum *tab_atom; + uint32_t tab_atom_count; int ret; enum_obj = sp[-1]; @@ -15215,28 +14994,68 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) it = p->u.for_in_iterator; for(;;) { - if (it->is_array) { - if (it->idx >= it->array_length) - goto done; - prop = __JS_AtomFromUInt32(it->idx); - it->idx++; + if (it->idx >= it->atom_count) { + if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj)) + goto done; /* not an object */ + /* no more property in the current object: look in the prototype */ + if (!it->in_prototype_chain) { + ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj); + if (ret < 0) + return -1; + if (ret) + goto done; + it->in_prototype_chain = TRUE; + } + it->obj = JS_GetPrototypeFree(ctx, it->obj); + if (JS_IsException(it->obj)) + return -1; + if (JS_IsNull(it->obj)) + goto done; /* no more prototype */ + + /* must check for timeout to avoid infinite loop */ + if (js_poll_interrupts(ctx)) + return -1; + + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, + JS_VALUE_GET_OBJ(it->obj), + JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { + return -1; + } + js_free_prop_enum(ctx, it->tab_atom, it->atom_count); + it->tab_atom = tab_atom; + it->atom_count = tab_atom_count; + it->idx = 0; } else { - JSShape *sh = p->shape; - JSShapeProperty *prs; - if (it->idx >= sh->prop_count) - goto done; - prs = get_shape_prop(sh) + it->idx; - prop = prs->atom; - it->idx++; - if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE)) - continue; + if (it->is_array) { + prop = __JS_AtomFromUInt32(it->idx); + it->idx++; + } else { + BOOL is_enumerable; + prop = it->tab_atom[it->idx].atom; + is_enumerable = it->tab_atom[it->idx].is_enumerable; + it->idx++; + if (it->in_prototype_chain) { + /* slow case: we are in the prototype chain */ + ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop); + if (ret < 0) + return ret; + if (ret) + continue; /* already visited */ + /* add to the visited property list */ + if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL, + JS_PROP_ENUMERABLE) < 0) + return -1; + } + if (!is_enumerable) + continue; + } + /* check if the property was deleted */ + ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop); + if (ret < 0) + return ret; + if (ret) + break; } - /* check if the property was deleted */ - ret = JS_HasProperty(ctx, it->obj, prop); - if (ret < 0) - return ret; - if (ret) - break; } /* return the property */ sp[0] = JS_AtomToValue(ctx, prop); @@ -15722,7 +15541,7 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, struct list_head *el; list_for_each(el, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, header.link); + var_ref = list_entry(el, JSVarRef, var_ref_link); if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) { var_ref->header.ref_count++; return var_ref; @@ -15733,15 +15552,29 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, if (!var_ref) return NULL; var_ref->header.ref_count = 1; + add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); var_ref->is_detached = FALSE; var_ref->is_arg = is_arg; var_ref->var_idx = var_idx; - list_add_tail(&var_ref->header.link, &sf->var_ref_list); + list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list); + if (sf->js_mode & JS_MODE_ASYNC) { + /* The stack frame is detached and may be destroyed at any + time so its reference count must be increased. Calling + close_var_refs() when destroying the stack frame is not + possible because it would change the graph between the GC + objects. Another solution could be to temporarily detach + the JSVarRef of async functions during the GC. It would + have the advantage of allowing the release of unused stack + frames in a cycle. */ + var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame); + var_ref->async_func->header.ref_count++; + } else { + var_ref->async_func = NULL; + } if (is_arg) var_ref->pvalue = &sf->arg_buf[var_idx]; else var_ref->pvalue = &sf->var_buf[var_idx]; - var_ref->value = JS_UNDEFINED; return var_ref; } @@ -15972,7 +15805,10 @@ static void close_var_refs(JSRuntime *rt, JSStackFrame *sf) int var_idx; list_for_each_safe(el, el1, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, header.link); + var_ref = list_entry(el, JSVarRef, var_ref_link); + /* no need to unlink var_ref->var_ref_link as the list is never used afterwards */ + if (var_ref->async_func) + async_func_free(rt, var_ref->async_func); var_idx = var_ref->var_idx; if (var_ref->is_arg) var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]); @@ -15981,7 +15817,6 @@ static void close_var_refs(JSRuntime *rt, JSStackFrame *sf) var_ref->pvalue = &var_ref->value; /* the reference is no longer to a local variable */ var_ref->is_detached = TRUE; - add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); } } @@ -15992,14 +15827,15 @@ static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_ int var_idx = idx; list_for_each_safe(el, el1, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, header.link); + var_ref = list_entry(el, JSVarRef, var_ref_link); if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) { + list_del(&var_ref->var_ref_link); + if (var_ref->async_func) + async_func_free(ctx->rt, var_ref->async_func); var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]); var_ref->pvalue = &var_ref->value; - list_del(&var_ref->header.link); /* the reference is no longer to a local variable */ var_ref->is_detached = TRUE; - add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); } } } @@ -16190,9 +16026,10 @@ typedef enum { OP_SPECIAL_OBJECT_IMPORT_META, } OPSpecialObjectEnum; -#define FUNC_RET_AWAIT 0 -#define FUNC_RET_YIELD 1 -#define FUNC_RET_YIELD_STAR 2 +#define FUNC_RET_AWAIT 0 +#define FUNC_RET_YIELD 1 +#define FUNC_RET_YIELD_STAR 2 +#define FUNC_RET_INITIAL_YIELD 3 /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, @@ -16754,8 +16591,15 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } BREAK; CASE(OP_check_brand): - if (JS_CheckBrand(ctx, sp[-2], sp[-1]) < 0) - goto exception; + { + int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]); + if (ret < 0) + goto exception; + if (!ret) { + JS_ThrowTypeError(ctx, "invalid brand on object"); + goto exception; + } + } BREAK; CASE(OP_add_brand): if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0) @@ -17177,6 +17021,19 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sp++; } BREAK; + CASE(OP_get_loc_checkthis): + { + int idx; + idx = get_u16(pc); + pc += 2; + if (unlikely(JS_IsUninitialized(var_buf[idx]))) { + JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE); + goto exception; + } + sp[0] = JS_DupValue(ctx, var_buf[idx]); + sp++; + } + BREAK; CASE(OP_put_loc_check): { int idx; @@ -17446,26 +17303,21 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } sp--; BREAK; - CASE(OP_iterator_close_return): + CASE(OP_nip_catch): { JSValue ret_val; - /* iter_obj next catch_offset ... ret_val -> - ret_eval iter_obj next catch_offset */ + /* catch_offset ... ret_val -> ret_eval */ ret_val = *--sp; while (sp > stack_buf && JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) { JS_FreeValue(ctx, *--sp); } - if (unlikely(sp < stack_buf + 3)) { - JS_ThrowInternalError(ctx, "iterator_close_return"); + if (unlikely(sp == stack_buf)) { + JS_ThrowInternalError(ctx, "nip_catch"); JS_FreeValue(ctx, ret_val); goto exception; } - sp[0] = sp[-1]; - sp[-1] = sp[-2]; - sp[-2] = sp[-3]; - sp[-3] = ret_val; - sp++; + sp[-1] = ret_val; } BREAK; @@ -17566,7 +17418,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, atom = get_u32(pc); pc += 4; - ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], + ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2], JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-2]); sp -= 2; @@ -17865,8 +17717,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, atom = JS_ValueToAtom(ctx, sp[-2]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; - ret = JS_SetPropertyGeneric(ctx, sp[-3], atom, sp[-1], sp[-4], - JS_PROP_THROW_STRICT); + ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4], + JS_PROP_THROW_STRICT); JS_FreeAtom(ctx, atom); JS_FreeValue(ctx, sp[-4]); JS_FreeValue(ctx, sp[-3]); @@ -18415,6 +18267,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, goto exception; sp--; BREAK; + CASE(OP_private_in): + if (js_operator_private_in(ctx, sp)) + goto exception; + sp--; + BREAK; CASE(OP_instanceof): if (js_operator_instanceof(ctx, sp)) goto exception; @@ -18545,7 +18402,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, break; case OP_with_put_var: /* XXX: check if strict mode */ - ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], + ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj, JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-1]); sp -= 2; @@ -18601,9 +18458,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR); goto done_generator; CASE(OP_return_async): - CASE(OP_initial_yield): ret_val = JS_UNDEFINED; goto done_generator; + CASE(OP_initial_yield): + ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD); + goto done_generator; CASE(OP_nop): BREAK; @@ -18885,26 +18744,35 @@ static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, } /* JSAsyncFunctionState (used by generator and async functions) */ -static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s, - JSValueConst func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv) +static JSAsyncFunctionState *async_func_init(JSContext *ctx, + JSValueConst func_obj, JSValueConst this_obj, + int argc, JSValueConst *argv) { + JSAsyncFunctionState *s; JSObject *p; JSFunctionBytecode *b; JSStackFrame *sf; int local_count, i, arg_buf_len, n; + s = js_mallocz(ctx, sizeof(*s)); + if (!s) + return NULL; + s->header.ref_count = 1; + add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION); + sf = &s->frame; init_list_head(&sf->var_ref_list); p = JS_VALUE_GET_OBJ(func_obj); b = p->u.func.function_bytecode; - sf->js_mode = b->js_mode; + sf->js_mode = b->js_mode | JS_MODE_ASYNC; sf->cur_pc = b->byte_code_buf; arg_buf_len = max_int(b->arg_count, argc); local_count = arg_buf_len + b->var_count + b->stack_size; sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1)); - if (!sf->arg_buf) - return -1; + if (!sf->arg_buf) { + js_free(ctx, s); + return NULL; + } sf->cur_func = JS_DupValue(ctx, func_obj); s->this_val = JS_DupValue(ctx, this_obj); s->argc = argc; @@ -18916,38 +18784,17 @@ static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s, n = arg_buf_len + b->var_count; for(i = argc; i < n; i++) sf->arg_buf[i] = JS_UNDEFINED; - return 0; -} - -static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s, - JS_MarkFunc *mark_func) -{ - JSStackFrame *sf; - JSValue *sp; - - sf = &s->frame; - JS_MarkValue(rt, sf->cur_func, mark_func); - JS_MarkValue(rt, s->this_val, mark_func); - if (sf->cur_sp) { - /* if the function is running, cur_sp is not known so we - cannot mark the stack. Marking the variables is not needed - because a running function cannot be part of a removable - cycle */ - for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) - JS_MarkValue(rt, *sp, mark_func); - } + s->resolving_funcs[0] = JS_UNDEFINED; + s->resolving_funcs[1] = JS_UNDEFINED; + s->is_completed = FALSE; + return s; } -static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) +static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s) { - JSStackFrame *sf; + JSStackFrame *sf = &s->frame; JSValue *sp; - sf = &s->frame; - - /* close the closure variables. */ - close_var_refs(rt, sf); - if (sf->arg_buf) { /* cannot free the function if it is running */ assert(sf->cur_sp != NULL); @@ -18955,6 +18802,7 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) JS_FreeValueRT(rt, *sp); } js_free_rt(rt, sf->arg_buf); + sf->arg_buf = NULL; } JS_FreeValueRT(rt, sf->cur_func); JS_FreeValueRT(rt, s->this_val); @@ -18962,17 +18810,66 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s) { - JSValue func_obj; + JSRuntime *rt = ctx->rt; + JSStackFrame *sf = &s->frame; + JSValue func_obj, ret; - if (js_check_stack_overflow(ctx->rt, 0)) - return JS_ThrowStackOverflow(ctx); + assert(!s->is_completed); + if (js_check_stack_overflow(ctx->rt, 0)) { + ret = JS_ThrowStackOverflow(ctx); + } else { + /* the tag does not matter provided it is not an object */ + func_obj = JS_MKPTR(JS_TAG_INT, s); + ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, + s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR); + } + if (JS_IsException(ret) || JS_IsUndefined(ret)) { + if (JS_IsUndefined(ret)) { + ret = sf->cur_sp[-1]; + sf->cur_sp[-1] = JS_UNDEFINED; + } + /* end of execution */ + s->is_completed = TRUE; - /* the tag does not matter provided it is not an object */ - func_obj = JS_MKPTR(JS_TAG_INT, s); - return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, - s->argc, s->frame.arg_buf, JS_CALL_FLAG_GENERATOR); + /* close the closure variables. */ + close_var_refs(rt, sf); + + async_func_free_frame(rt, s); + } + return ret; +} + +static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) +{ + /* cannot close the closure variables here because it would + potentially modify the object graph */ + if (!s->is_completed) { + async_func_free_frame(rt, s); + } + + JS_FreeValueRT(rt, s->resolving_funcs[0]); + JS_FreeValueRT(rt, s->resolving_funcs[1]); + + remove_gc_object(&s->header); + if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) { + list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list); + } else { + js_free_rt(rt, s); + } } +static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) +{ + if (--s->header.ref_count == 0) { + if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) { + list_del(&s->header.link); + list_add(&s->header.link, &rt->gc_zero_ref_count_list); + if (rt->gc_phase == JS_GC_PHASE_NONE) { + free_zero_refcount(rt); + } + } + } +} /* Generators */ @@ -18986,14 +18883,17 @@ typedef enum JSGeneratorStateEnum { typedef struct JSGeneratorData { JSGeneratorStateEnum state; - JSAsyncFunctionState func_state; + JSAsyncFunctionState *func_state; } JSGeneratorData; static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s) { if (s->state == JS_GENERATOR_STATE_COMPLETED) return; - async_func_free(rt, &s->func_state); + if (s->func_state) { + async_func_free(rt, s->func_state); + s->func_state = NULL; + } s->state = JS_GENERATOR_STATE_COMPLETED; } @@ -19018,9 +18918,9 @@ static void js_generator_mark(JSRuntime *rt, JSValueConst val, JSObject *p = JS_VALUE_GET_OBJ(val); JSGeneratorData *s = p->u.generator_data; - if (!s || s->state == JS_GENERATOR_STATE_COMPLETED) + if (!s || !s->func_state) return; - async_func_mark(rt, &s->func_state, mark_func); + mark_func(rt, &s->func_state->header); } /* XXX: use enum */ @@ -19039,7 +18939,7 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, *pdone = TRUE; if (!s) return JS_ThrowTypeError(ctx, "not a generator"); - sf = &s->func_state.frame; + sf = &s->func_state->frame; switch(s->state) { default: case JS_GENERATOR_STATE_SUSPENDED_START: @@ -19057,23 +18957,23 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, if (magic == GEN_MAGIC_THROW && s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) { JS_Throw(ctx, ret); - s->func_state.throw_flag = TRUE; + s->func_state->throw_flag = TRUE; } else { sf->cur_sp[-1] = ret; sf->cur_sp[0] = JS_NewInt32(ctx, magic); sf->cur_sp++; exec_no_arg: - s->func_state.throw_flag = FALSE; + s->func_state->throw_flag = FALSE; } s->state = JS_GENERATOR_STATE_EXECUTING; - func_ret = async_func_resume(ctx, &s->func_state); + func_ret = async_func_resume(ctx, s->func_state); s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD; - if (JS_IsException(func_ret)) { - /* finalize the execution in case of exception */ + if (s->func_state->is_completed) { + /* finalize the execution in case of exception or normal return */ free_generator_stack(ctx, s); return func_ret; - } - if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) { + } else { + assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); /* get the returned yield value at the top of the stack */ ret = sf->cur_sp[-1]; sf->cur_sp[-1] = JS_UNDEFINED; @@ -19084,12 +18984,6 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, } else { *pdone = FALSE; } - } else { - /* end of iterator */ - ret = sf->cur_sp[-1]; - sf->cur_sp[-1] = JS_UNDEFINED; - JS_FreeValue(ctx, func_ret); - free_generator_stack(ctx, s); } break; case JS_GENERATOR_STATE_COMPLETED: @@ -19127,13 +19021,14 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, if (!s) return JS_EXCEPTION; s->state = JS_GENERATOR_STATE_SUSPENDED_START; - if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { + s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); + if (!s->func_state) { s->state = JS_GENERATOR_STATE_COMPLETED; goto fail; } /* execute the function up to 'OP_initial_yield' */ - func_ret = async_func_resume(ctx, &s->func_state); + func_ret = async_func_resume(ctx, s->func_state); if (JS_IsException(func_ret)) goto fail; JS_FreeValue(ctx, func_ret); @@ -19151,36 +19046,12 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, /* AsyncFunction */ -static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s) -{ - if (s->is_active) { - async_func_free(rt, &s->func_state); - s->is_active = FALSE; - } -} - -static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s) -{ - js_async_function_terminate(rt, s); - JS_FreeValueRT(rt, s->resolving_funcs[0]); - JS_FreeValueRT(rt, s->resolving_funcs[1]); - remove_gc_object(&s->header); - js_free_rt(rt, s); -} - -static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s) -{ - if (--s->header.ref_count == 0) { - js_async_function_free0(rt, s); - } -} - static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); - JSAsyncFunctionData *s = p->u.async_function_data; + JSAsyncFunctionState *s = p->u.async_function_data; if (s) { - js_async_function_free(rt, s); + async_func_free(rt, s); } } @@ -19188,14 +19059,14 @@ static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); - JSAsyncFunctionData *s = p->u.async_function_data; + JSAsyncFunctionState *s = p->u.async_function_data; if (s) { mark_func(rt, &s->header); } } static int js_async_function_resolve_create(JSContext *ctx, - JSAsyncFunctionData *s, + JSAsyncFunctionState *s, JSValue *resolving_funcs) { int i; @@ -19217,60 +19088,58 @@ static int js_async_function_resolve_create(JSContext *ctx, return 0; } -static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s) +static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s) { JSValue func_ret, ret2; - func_ret = async_func_resume(ctx, &s->func_state); - if (JS_IsException(func_ret)) { - JSValue error; - fail: - error = JS_GetException(ctx); - ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED, - 1, (JSValueConst *)&error); - JS_FreeValue(ctx, error); - js_async_function_terminate(ctx->rt, s); - JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ - } else { - JSValue value; - value = s->func_state.frame.cur_sp[-1]; - s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; - if (JS_IsUndefined(func_ret)) { - /* function returned */ - ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED, - 1, (JSValueConst *)&value); + func_ret = async_func_resume(ctx, s); + if (s->is_completed) { + if (JS_IsException(func_ret)) { + JSValue error; + fail: + error = JS_GetException(ctx); + ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED, + 1, (JSValueConst *)&error); + JS_FreeValue(ctx, error); JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ - JS_FreeValue(ctx, value); - js_async_function_terminate(ctx->rt, s); } else { - JSValue promise, resolving_funcs[2], resolving_funcs1[2]; - int i, res; + /* normal return */ + ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&func_ret); + JS_FreeValue(ctx, func_ret); + JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ + } + } else { + JSValue value, promise, resolving_funcs[2], resolving_funcs1[2]; + int i, res; - /* await */ - JS_FreeValue(ctx, func_ret); /* not used */ - promise = js_promise_resolve(ctx, ctx->promise_ctor, - 1, (JSValueConst *)&value, 0); - JS_FreeValue(ctx, value); - if (JS_IsException(promise)) - goto fail; - if (js_async_function_resolve_create(ctx, s, resolving_funcs)) { - JS_FreeValue(ctx, promise); - goto fail; - } + value = s->frame.cur_sp[-1]; + s->frame.cur_sp[-1] = JS_UNDEFINED; - /* Note: no need to create 'thrownawayCapability' as in - the spec */ - for(i = 0; i < 2; i++) - resolving_funcs1[i] = JS_UNDEFINED; - res = perform_promise_then(ctx, promise, - (JSValueConst *)resolving_funcs, - (JSValueConst *)resolving_funcs1); + /* await */ + JS_FreeValue(ctx, func_ret); /* not used */ + promise = js_promise_resolve(ctx, ctx->promise_ctor, + 1, (JSValueConst *)&value, 0); + JS_FreeValue(ctx, value); + if (JS_IsException(promise)) + goto fail; + if (js_async_function_resolve_create(ctx, s, resolving_funcs)) { JS_FreeValue(ctx, promise); - for(i = 0; i < 2; i++) - JS_FreeValue(ctx, resolving_funcs[i]); - if (res) - goto fail; + goto fail; } + + /* Note: no need to create 'thrownawayCapability' as in + the spec */ + for(i = 0; i < 2; i++) + resolving_funcs1[i] = JS_UNDEFINED; + res = perform_promise_then(ctx, promise, + (JSValueConst *)resolving_funcs, + (JSValueConst *)resolving_funcs1); + JS_FreeValue(ctx, promise); + for(i = 0; i < 2; i++) + JS_FreeValue(ctx, resolving_funcs[i]); + if (res) + goto fail; } } @@ -19281,7 +19150,7 @@ static JSValue js_async_function_resolve_call(JSContext *ctx, int flags) { JSObject *p = JS_VALUE_GET_OBJ(func_obj); - JSAsyncFunctionData *s = p->u.async_function_data; + JSAsyncFunctionState *s = p->u.async_function_data; BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE; JSValueConst arg; @@ -19289,12 +19158,12 @@ static JSValue js_async_function_resolve_call(JSContext *ctx, arg = argv[0]; else arg = JS_UNDEFINED; - s->func_state.throw_flag = is_reject; + s->throw_flag = is_reject; if (is_reject) { JS_Throw(ctx, JS_DupValue(ctx, arg)); } else { /* return value of await */ - s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg); + s->frame.cur_sp[-1] = JS_DupValue(ctx, arg); } js_async_function_resume(ctx, s); return JS_UNDEFINED; @@ -19305,32 +19174,21 @@ static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj, int argc, JSValueConst *argv, int flags) { JSValue promise; - JSAsyncFunctionData *s; + JSAsyncFunctionState *s; - s = js_mallocz(ctx, sizeof(*s)); + s = async_func_init(ctx, func_obj, this_obj, argc, argv); if (!s) return JS_EXCEPTION; - s->header.ref_count = 1; - add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION); - s->is_active = FALSE; - s->resolving_funcs[0] = JS_UNDEFINED; - s->resolving_funcs[1] = JS_UNDEFINED; promise = JS_NewPromiseCapability(ctx, s->resolving_funcs); - if (JS_IsException(promise)) - goto fail; - - if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { - fail: - JS_FreeValue(ctx, promise); - js_async_function_free(ctx->rt, s); + if (JS_IsException(promise)) { + async_func_free(ctx->rt, s); return JS_EXCEPTION; } - s->is_active = TRUE; js_async_function_resume(ctx, s); - - js_async_function_free(ctx->rt, s); + + async_func_free(ctx->rt, s); return promise; } @@ -19359,7 +19217,8 @@ typedef struct JSAsyncGeneratorRequest { typedef struct JSAsyncGeneratorData { JSObject *generator; /* back pointer to the object (const) */ JSAsyncGeneratorStateEnum state; - JSAsyncFunctionState func_state; + /* func_state is NULL is state AWAITING_RETURN and COMPLETED */ + JSAsyncFunctionState *func_state; struct list_head queue; /* list of JSAsyncGeneratorRequest.link */ } JSAsyncGeneratorData; @@ -19377,10 +19236,8 @@ static void js_async_generator_free(JSRuntime *rt, JS_FreeValueRT(rt, req->resolving_funcs[1]); js_free_rt(rt, req); } - if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED && - s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) { - async_func_free(rt, &s->func_state); - } + if (s->func_state) + async_func_free(rt, s->func_state); js_free_rt(rt, s); } @@ -19407,9 +19264,8 @@ static void js_async_generator_mark(JSRuntime *rt, JSValueConst val, JS_MarkValue(rt, req->resolving_funcs[0], mark_func); JS_MarkValue(rt, req->resolving_funcs[1], mark_func); } - if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED && - s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) { - async_func_mark(rt, &s->func_state, mark_func); + if (s->func_state) { + mark_func(rt, &s->func_state->header); } } } @@ -19519,7 +19375,8 @@ static void js_async_generator_complete(JSContext *ctx, { if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) { s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; - async_func_free(ctx->rt, &s->func_state); + async_func_free(ctx->rt, s->func_state); + s->func_state = NULL; } } @@ -19530,10 +19387,19 @@ static int js_async_generator_completed_return(JSContext *ctx, JSValue promise, resolving_funcs[2], resolving_funcs1[2]; int res; - promise = js_promise_resolve(ctx, ctx->promise_ctor, - 1, (JSValueConst *)&value, 0); - if (JS_IsException(promise)) - return -1; + // Can fail looking up JS_ATOM_constructor when is_reject==0. + promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value, + /*is_reject*/0); + // A poisoned .constructor property is observable and the resulting + // exception should be delivered to the catch handler. + if (JS_IsException(promise)) { + JSValue err = JS_GetException(ctx); + promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err, + /*is_reject*/1); + JS_FreeValue(ctx, err); + if (JS_IsException(promise)) + return -1; + } if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator), resolving_funcs1, @@ -19581,7 +19447,6 @@ static void js_async_generator_resume_next(JSContext *ctx, } else if (next->completion_type == GEN_MAGIC_RETURN) { s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN; js_async_generator_completed_return(ctx, s, next->result); - goto done; } else { js_async_generator_reject(ctx, s, next->result); } @@ -19592,30 +19457,38 @@ static void js_async_generator_resume_next(JSContext *ctx, if (next->completion_type == GEN_MAGIC_THROW && s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) { JS_Throw(ctx, value); - s->func_state.throw_flag = TRUE; + s->func_state->throw_flag = TRUE; } else { /* 'yield' returns a value. 'yield *' also returns a value in case the 'throw' method is called */ - s->func_state.frame.cur_sp[-1] = value; - s->func_state.frame.cur_sp[0] = + s->func_state->frame.cur_sp[-1] = value; + s->func_state->frame.cur_sp[0] = JS_NewInt32(ctx, next->completion_type); - s->func_state.frame.cur_sp++; + s->func_state->frame.cur_sp++; exec_no_arg: - s->func_state.throw_flag = FALSE; + s->func_state->throw_flag = FALSE; } s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING; resume_exec: - func_ret = async_func_resume(ctx, &s->func_state); - if (JS_IsException(func_ret)) { - value = JS_GetException(ctx); - js_async_generator_complete(ctx, s); - js_async_generator_reject(ctx, s, value); - JS_FreeValue(ctx, value); - } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) { - int func_ret_code; - value = s->func_state.frame.cur_sp[-1]; - s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; + func_ret = async_func_resume(ctx, s->func_state); + if (s->func_state->is_completed) { + if (JS_IsException(func_ret)) { + value = JS_GetException(ctx); + js_async_generator_complete(ctx, s); + js_async_generator_reject(ctx, s, value); + JS_FreeValue(ctx, value); + } else { + /* end of function */ + js_async_generator_complete(ctx, s); + js_async_generator_resolve(ctx, s, func_ret, TRUE); + JS_FreeValue(ctx, func_ret); + } + } else { + int func_ret_code, ret; + assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); func_ret_code = JS_VALUE_GET_INT(func_ret); + value = s->func_state->frame.cur_sp[-1]; + s->func_state->frame.cur_sp[-1] = JS_UNDEFINED; switch(func_ret_code) { case FUNC_RET_YIELD: case FUNC_RET_YIELD_STAR: @@ -19627,20 +19500,17 @@ static void js_async_generator_resume_next(JSContext *ctx, JS_FreeValue(ctx, value); break; case FUNC_RET_AWAIT: - js_async_generator_await(ctx, s, value); + ret = js_async_generator_await(ctx, s, value); JS_FreeValue(ctx, value); + if (ret < 0) { + /* exception: throw it */ + s->func_state->throw_flag = TRUE; + goto resume_exec; + } goto done; default: abort(); } - } else { - assert(JS_IsUndefined(func_ret)); - /* end of function */ - value = s->func_state.frame.cur_sp[-1]; - s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; - js_async_generator_complete(ctx, s); - js_async_generator_resolve(ctx, s, value, TRUE); - JS_FreeValue(ctx, value); } break; default: @@ -19674,12 +19544,12 @@ static JSValue js_async_generator_resolve_function(JSContext *ctx, } else { /* restart function execution after await() */ assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING); - s->func_state.throw_flag = is_reject; + s->func_state->throw_flag = is_reject; if (is_reject) { JS_Throw(ctx, JS_DupValue(ctx, arg)); } else { /* return value of await */ - s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg); + s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg); } js_async_generator_resume_next(ctx, s); } @@ -19743,14 +19613,12 @@ static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst fun return JS_EXCEPTION; s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START; init_list_head(&s->queue); - if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { - s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; + s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); + if (!s->func_state) goto fail; - } - /* execute the function up to 'OP_initial_yield' (no yield nor await are possible) */ - func_ret = async_func_resume(ctx, &s->func_state); + func_ret = async_func_resume(ctx, s->func_state); if (JS_IsException(func_ret)) goto fail; JS_FreeValue(ctx, func_ret); @@ -19936,6 +19804,7 @@ typedef enum JSParseFunctionEnum { JS_PARSE_FUNC_GETTER, JS_PARSE_FUNC_SETTER, JS_PARSE_FUNC_METHOD, + JS_PARSE_FUNC_CLASS_STATIC_INIT, JS_PARSE_FUNC_CLASS_CONSTRUCTOR, JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR, } JSParseFunctionEnum; @@ -20055,6 +19924,7 @@ typedef struct JSFunctionDef { int source_len; JSModuleDef *module; /* != NULL when parsing a module */ + BOOL has_await; /* TRUE if await is used (used in module eval) */ } JSFunctionDef; typedef struct JSToken { @@ -20143,11 +20013,9 @@ static __exception int next_token(JSParseState *s); static void free_token(JSParseState *s, JSToken *token) { switch(token->val) { -#ifdef CONFIG_BIGNUM case TOK_NUMBER: JS_FreeValue(s->ctx, token->u.num.val); break; -#endif case TOK_STRING: case TOK_TEMPLATE: JS_FreeValue(s->ctx, token->u.str.str); @@ -20607,6 +20475,48 @@ static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize, return 0; } +/* convert a TOK_IDENT to a keyword when needed */ +static void update_token_ident(JSParseState *s) +{ + if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD || + (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD && + (s->cur_func->js_mode & JS_MODE_STRICT)) || + (s->token.u.ident.atom == JS_ATOM_yield && + ((s->cur_func->func_kind & JS_FUNC_GENERATOR) || + (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && + !s->cur_func->in_function_body && s->cur_func->parent && + (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) || + (s->token.u.ident.atom == JS_ATOM_await && + (s->is_module || + (s->cur_func->func_kind & JS_FUNC_ASYNC) || + s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT || + (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && + !s->cur_func->in_function_body && s->cur_func->parent && + ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) || + s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) { + if (s->token.u.ident.has_escape) { + s->token.u.ident.is_reserved = TRUE; + s->token.val = TOK_IDENT; + } else { + /* The keywords atoms are pre allocated */ + s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD; + } + } +} + +/* if the current token is an identifier or keyword, reparse it + according to the current function type */ +static void reparse_ident_token(JSParseState *s) +{ + if (s->token.val == TOK_IDENT || + (s->token.val >= TOK_FIRST_KEYWORD && + s->token.val <= TOK_LAST_KEYWORD)) { + s->token.val = TOK_IDENT; + s->token.u.ident.is_reserved = FALSE; + update_token_ident(s); + } +} + /* 'c' is the first character. Return JS_ATOM_NULL in case of error */ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, BOOL *pident_has_escape, int c, BOOL is_private) @@ -20813,30 +20723,8 @@ static __exception int next_token(JSParseState *s) s->token.u.ident.atom = atom; s->token.u.ident.has_escape = ident_has_escape; s->token.u.ident.is_reserved = FALSE; - if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD || - (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD && - (s->cur_func->js_mode & JS_MODE_STRICT)) || - (s->token.u.ident.atom == JS_ATOM_yield && - ((s->cur_func->func_kind & JS_FUNC_GENERATOR) || - (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && - !s->cur_func->in_function_body && s->cur_func->parent && - (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) || - (s->token.u.ident.atom == JS_ATOM_await && - (s->is_module || - (((s->cur_func->func_kind & JS_FUNC_ASYNC) || - (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && - !s->cur_func->in_function_body && s->cur_func->parent && - (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) { - if (ident_has_escape) { - s->token.u.ident.is_reserved = TRUE; - s->token.val = TOK_IDENT; - } else { - /* The keywords atoms are pre allocated */ - s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD; - } - } else { - s->token.val = TOK_IDENT; - } + s->token.val = TOK_IDENT; + update_token_ident(s); break; case '#': /* private name */ @@ -20893,8 +20781,8 @@ static __exception int next_token(JSParseState *s) int flags, radix; flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL | ATOD_ACCEPT_UNDERSCORES; -#ifdef CONFIG_BIGNUM flags |= ATOD_ACCEPT_SUFFIX; +#ifdef CONFIG_BIGNUM if (s->cur_func->js_mode & JS_MODE_MATH) { flags |= ATOD_MODE_BIGINT; if (s->cur_func->js_mode & JS_MODE_MATH) @@ -21483,6 +21371,31 @@ static int peek_token(JSParseState *s, BOOL no_line_terminator) return simple_next_token(&p, no_line_terminator); } +static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end) +{ + const uint8_t *p = *pp; + int c; + + if (p[0] == '#' && p[1] == '!') { + p += 2; + while (p < buf_end) { + if (*p == '\n' || *p == '\r') { + break; + } else if (*p >= 0x80) { + c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); + if (c == CP_LS || c == CP_PS) { + break; + } else if (c == -1) { + p++; /* skip invalid UTF-8 */ + } + } else { + p++; + } + } + *pp = p; + } +} + /* return true if 'input' contains the source of a module (heuristic). 'input' must be a zero terminated. @@ -21493,6 +21406,8 @@ BOOL JS_DetectModule(const char *input, size_t input_len) { const uint8_t *p = (const uint8_t *)input; int tok; + + skip_shebang(&p, p + input_len); switch(simple_next_token(&p, FALSE)) { case TOK_IMPORT: tok = simple_next_token(&p, FALSE); @@ -21605,6 +21520,14 @@ static int new_label(JSParseState *s) return new_label_fd(s->cur_func, -1); } +/* don't update the last opcode and don't emit line number info */ +static void emit_label_raw(JSParseState *s, int label) +{ + emit_u8(s, OP_label); + emit_u32(s, label); + s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size; +} + /* return the label ID offset */ static int emit_label(JSParseState *s, int label) { @@ -22103,7 +22026,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, /* add a private field variable in the current scope */ static int add_private_class_field(JSParseState *s, JSFunctionDef *fd, - JSAtom name, JSVarKindEnum var_kind) + JSAtom name, JSVarKindEnum var_kind, BOOL is_static) { JSContext *ctx = s->ctx; JSVarDef *vd; @@ -22115,6 +22038,7 @@ static int add_private_class_field(JSParseState *s, JSFunctionDef *fd, vd = &fd->vars[idx]; vd->is_lexical = 1; vd->is_const = 1; + vd->is_static_private = is_static; return idx; } @@ -22860,8 +22784,9 @@ static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name) typedef struct { JSFunctionDef *fields_init_fd; int computed_fields_count; - BOOL has_brand; + BOOL need_brand; int brand_push_pos; + BOOL is_static; } ClassFieldsDef; static __exception int emit_class_init_start(JSParseState *s, @@ -22875,48 +22800,34 @@ static __exception int emit_class_init_start(JSParseState *s, s->cur_func = cf->fields_init_fd; - /* XXX: would be better to add the code only if needed, maybe in a - later pass */ - emit_op(s, OP_push_false); /* will be patched later */ - cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos; - label_add_brand = emit_goto(s, OP_if_false, -1); - - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_home_object); - emit_u16(s, 0); - - emit_op(s, OP_add_brand); - - emit_label(s, label_add_brand); - - s->cur_func = s->cur_func->parent; - return 0; -} - -static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf) -{ - if (!cf->has_brand) { - /* define the brand field in 'this' of the initializer */ - if (!cf->fields_init_fd) { - if (emit_class_init_start(s, cf)) - return -1; - } - /* patch the start of the function to enable the OP_add_brand code */ - cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true; + if (!cf->is_static) { + /* add the brand to the newly created instance */ + /* XXX: would be better to add the code only if needed, maybe in a + later pass */ + emit_op(s, OP_push_false); /* will be patched later */ + cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos; + label_add_brand = emit_goto(s, OP_if_false, -1); - cf->has_brand = TRUE; + emit_op(s, OP_scope_get_var); + emit_atom(s, JS_ATOM_this); + emit_u16(s, 0); + + emit_op(s, OP_scope_get_var); + emit_atom(s, JS_ATOM_home_object); + emit_u16(s, 0); + + emit_op(s, OP_add_brand); + + emit_label(s, label_add_brand); } + s->cur_func = s->cur_func->parent; return 0; } static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf) { int cpool_idx; - + s->cur_func = cf->fields_init_fd; emit_op(s, OP_return_undef); s->cur_func = s->cur_func->parent; @@ -22943,7 +22854,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, const uint8_t *class_start_ptr = s->token.ptr; const uint8_t *start_ptr; ClassFieldsDef class_fields[2]; - + /* classes are parsed and executed in strict mode */ saved_js_mode = fd->js_mode; fd->js_mode |= JS_MODE_STRICT; @@ -23016,7 +22927,8 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, ClassFieldsDef *cf = &class_fields[i]; cf->fields_init_fd = NULL; cf->computed_fields_count = 0; - cf->has_brand = FALSE; + cf->need_brand = FALSE; + cf->is_static = i; } ctor_fd = NULL; @@ -23031,6 +22943,41 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, if (is_static) { if (next_token(s)) goto fail; + if (s->token.val == '{') { + ClassFieldsDef *cf = &class_fields[is_static]; + JSFunctionDef *init; + if (!cf->fields_init_fd) { + if (emit_class_init_start(s, cf)) + goto fail; + } + s->cur_func = cf->fields_init_fd; + /* XXX: could try to avoid creating a new function and + reuse 'fields_init_fd' with a specific 'var' + scope */ + // stack is now: + if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT, + JS_FUNC_NORMAL, JS_ATOM_NULL, + s->token.ptr, s->token.line_num, + JS_PARSE_EXPORT_NONE, &init) < 0) { + goto fail; + } + // stack is now: fclosure + push_scope(s); + emit_op(s, OP_scope_get_var); + emit_atom(s, JS_ATOM_this); + emit_u16(s, 0); + // stack is now: fclosure this + emit_op(s, OP_swap); + // stack is now: this fclosure + emit_op(s, OP_call_method); + emit_u16(s, 0); + // stack is now: returnvalue + emit_op(s, OP_drop); + // stack is now: + pop_scope(s); + s->cur_func = s->cur_func->parent; + continue; + } /* allow "static" field name */ if (s->token.val == ';' || s->token.val == '=') { is_static = FALSE; @@ -23061,24 +23008,26 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, JSFunctionDef *method_fd; if (is_private) { - int idx, var_kind; + int idx, var_kind, is_static1; idx = find_private_class_field(ctx, fd, name, fd->scope_level); if (idx >= 0) { var_kind = fd->vars[idx].var_kind; + is_static1 = fd->vars[idx].is_static_private; if (var_kind == JS_VAR_PRIVATE_FIELD || var_kind == JS_VAR_PRIVATE_METHOD || var_kind == JS_VAR_PRIVATE_GETTER_SETTER || - var_kind == (JS_VAR_PRIVATE_GETTER + is_set)) { + var_kind == (JS_VAR_PRIVATE_GETTER + is_set) || + (var_kind == (JS_VAR_PRIVATE_GETTER + 1 - is_set) && + is_static != is_static1)) { goto private_field_already_defined; } fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER; } else { if (add_private_class_field(s, fd, name, - JS_VAR_PRIVATE_GETTER + is_set) < 0) + JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0) goto fail; } - if (add_brand(s, &class_fields[is_static]) < 0) - goto fail; + class_fields[is_static].need_brand = TRUE; } if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set, @@ -23100,7 +23049,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; emit_atom(s, setter_name); ret = add_private_class_field(s, fd, setter_name, - JS_VAR_PRIVATE_SETTER); + JS_VAR_PRIVATE_SETTER, is_static); JS_FreeAtom(ctx, setter_name); if (ret < 0) goto fail; @@ -23135,7 +23084,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto private_field_already_defined; } if (add_private_class_field(s, fd, name, - JS_VAR_PRIVATE_FIELD) < 0) + JS_VAR_PRIVATE_FIELD, is_static) < 0) goto fail; emit_op(s, OP_private_symbol); emit_atom(s, name); @@ -23225,8 +23174,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR; } if (is_private) { - if (add_brand(s, &class_fields[is_static]) < 0) - goto fail; + class_fields[is_static].need_brand = TRUE; } if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, s->token.line_num, JS_PARSE_EXPORT_NONE, &method_fd)) goto fail; @@ -23242,7 +23190,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; } if (add_private_class_field(s, fd, name, - JS_VAR_PRIVATE_METHOD) < 0) + JS_VAR_PRIVATE_METHOD, is_static) < 0) goto fail; emit_op(s, OP_set_home_object); emit_op(s, OP_set_name); @@ -23292,12 +23240,29 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, if (next_token(s)) goto fail; - /* store the function to initialize the fields to that it can be - referenced by the constructor */ { ClassFieldsDef *cf = &class_fields[0]; int var_idx; + + if (cf->need_brand) { + /* add a private brand to the prototype */ + emit_op(s, OP_dup); + emit_op(s, OP_null); + emit_op(s, OP_swap); + emit_op(s, OP_add_brand); + + /* define the brand field in 'this' of the initializer */ + if (!cf->fields_init_fd) { + if (emit_class_init_start(s, cf)) + goto fail; + } + /* patch the start of the function to enable the + OP_add_brand_instance code */ + cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true; + } + /* store the function to initialize the fields to that it can be + referenced by the constructor */ var_idx = define_var(s, fd, JS_ATOM_class_fields_init, JS_VAR_DEF_CONST); if (var_idx < 0) @@ -23315,16 +23280,13 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, /* drop the prototype */ emit_op(s, OP_drop); - /* initialize the static fields */ - if (class_fields[1].fields_init_fd != NULL) { - ClassFieldsDef *cf = &class_fields[1]; + if (class_fields[1].need_brand) { + /* add a private brand to the class */ emit_op(s, OP_dup); - emit_class_init_end(s, cf); - emit_op(s, OP_call_method); - emit_u16(s, 0); - emit_op(s, OP_drop); + emit_op(s, OP_dup); + emit_op(s, OP_add_brand); } - + if (class_name != JS_ATOM_NULL) { /* store the class name in the scoped class name variable (it is independent from the class statement variable @@ -23334,6 +23296,17 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_atom(s, class_name); emit_u16(s, fd->scope_level); } + + /* initialize the static fields */ + if (class_fields[1].fields_init_fd != NULL) { + ClassFieldsDef *cf = &class_fields[1]; + emit_op(s, OP_dup); + emit_class_init_end(s, cf); + emit_op(s, OP_call_method); + emit_u16(s, 0); + emit_op(s, OP_drop); + } + pop_scope(s); pop_scope(s); @@ -24518,8 +24491,10 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) return -1; } name = JS_DupAtom(s->ctx, s->token.u.ident.atom); - if (next_token(s)) /* update line number before emitting code */ + if (next_token(s)) { /* update line number before emitting code */ + JS_FreeAtom(s->ctx, name); return -1; + } do_get_var: emit_op(s, OP_scope_get_var); emit_u32(s, name); @@ -24666,6 +24641,25 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2; drop_count = 2; break; + case OP_get_field_opt_chain: + { + int opt_chain_label, next_label; + opt_chain_label = get_u32(fd->byte_code.buf + + fd->last_opcode_pos + 1 + 4 + 1); + /* keep the object on the stack */ + fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2; + fd->byte_code.size = fd->last_opcode_pos + 1 + 4; + next_label = emit_goto(s, OP_goto, -1); + emit_label(s, opt_chain_label); + /* need an additional undefined value for the + case where the optional field does not + exists */ + emit_op(s, OP_undefined); + emit_label(s, next_label); + drop_count = 2; + opcode = OP_get_field; + } + break; case OP_scope_get_private_field: /* keep the object on the stack */ fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2; @@ -24676,6 +24670,25 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2; drop_count = 2; break; + case OP_get_array_el_opt_chain: + { + int opt_chain_label, next_label; + opt_chain_label = get_u32(fd->byte_code.buf + + fd->last_opcode_pos + 1 + 1); + /* keep the object on the stack */ + fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2; + fd->byte_code.size = fd->last_opcode_pos + 1; + next_label = emit_goto(s, OP_goto, -1); + emit_label(s, opt_chain_label); + /* need an additional undefined value for the + case where the optional field does not + exists */ + emit_op(s, OP_undefined); + emit_label(s, next_label); + drop_count = 2; + opcode = OP_get_array_el; + } + break; case OP_scope_get_var: { JSAtom name; @@ -24958,8 +24971,23 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) break; } } - if (optional_chaining_label >= 0) - emit_label(s, optional_chaining_label); + if (optional_chaining_label >= 0) { + JSFunctionDef *fd = s->cur_func; + int opcode; + emit_label_raw(s, optional_chaining_label); + /* modify the last opcode so that it is an indicator of an + optional chain */ + opcode = get_prev_opcode(fd); + if (opcode == OP_get_field || opcode == OP_get_array_el) { + if (opcode == OP_get_field) + opcode = OP_get_field_opt_chain; + else + opcode = OP_get_array_el_opt_chain; + fd->byte_code.buf[fd->last_opcode_pos] = opcode; + } else { + fd->last_opcode_pos = -1; + } + } return 0; } @@ -24975,27 +25003,57 @@ static __exception int js_parse_delete(JSParseState *s) return -1; switch(opcode = get_prev_opcode(fd)) { case OP_get_field: + case OP_get_field_opt_chain: { JSValue val; - int ret; - + int ret, opt_chain_label, next_label; + if (opcode == OP_get_field_opt_chain) { + opt_chain_label = get_u32(fd->byte_code.buf + + fd->last_opcode_pos + 1 + 4 + 1); + } else { + opt_chain_label = -1; + } name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); fd->byte_code.size = fd->last_opcode_pos; - fd->last_opcode_pos = -1; val = JS_AtomToValue(s->ctx, name); ret = emit_push_const(s, val, 1); JS_FreeValue(s->ctx, val); JS_FreeAtom(s->ctx, name); if (ret) return ret; + emit_op(s, OP_delete); + if (opt_chain_label >= 0) { + next_label = emit_goto(s, OP_goto, -1); + emit_label(s, opt_chain_label); + /* if the optional chain is not taken, return 'true' */ + emit_op(s, OP_drop); + emit_op(s, OP_push_true); + emit_label(s, next_label); + } + fd->last_opcode_pos = -1; } - goto do_delete; + break; case OP_get_array_el: fd->byte_code.size = fd->last_opcode_pos; fd->last_opcode_pos = -1; - do_delete: emit_op(s, OP_delete); break; + case OP_get_array_el_opt_chain: + { + int opt_chain_label, next_label; + opt_chain_label = get_u32(fd->byte_code.buf + + fd->last_opcode_pos + 1 + 1); + fd->byte_code.size = fd->last_opcode_pos; + emit_op(s, OP_delete); + next_label = emit_goto(s, OP_goto, -1); + emit_label(s, opt_chain_label); + /* if the optional chain is not taken, return 'true' */ + emit_op(s, OP_drop); + emit_op(s, OP_push_true); + emit_label(s, next_label); + fd->last_opcode_pos = -1; + } + break; case OP_scope_get_var: /* 'delete this': this is not a reference */ name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); @@ -25010,6 +25068,8 @@ static __exception int js_parse_delete(JSParseState *s) case OP_scope_get_private_field: return js_parse_error(s, "cannot delete a private class field"); case OP_get_super_value: + fd->byte_code.size = fd->last_opcode_pos; + fd->last_opcode_pos = -1; emit_op(s, OP_throw_error); emit_atom(s, JS_ATOM_NULL); emit_u8(s, JS_THROW_ERROR_DELETE_SUPER); @@ -25109,6 +25169,7 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags) return -1; if (js_parse_unary(s, PF_POW_FORBIDDEN)) return -1; + s->cur_func->has_await = TRUE; emit_op(s, OP_await); parse_flags = 0; break; @@ -25180,9 +25241,32 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level, if (level == 0) { return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) | PF_POW_ALLOWED); + } else if (s->token.val == TOK_PRIVATE_NAME && + (parse_flags & PF_IN_ACCEPTED) && level == 4 && + peek_token(s, FALSE) == TOK_IN) { + JSAtom atom; + + atom = JS_DupAtom(s->ctx, s->token.u.ident.atom); + if (next_token(s)) + goto fail_private_in; + if (s->token.val != TOK_IN) + goto fail_private_in; + if (next_token(s)) + goto fail_private_in; + if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC)) { + fail_private_in: + JS_FreeAtom(s->ctx, atom); + return -1; + } + emit_op(s, OP_scope_in_private_field); + emit_atom(s, atom); + emit_u16(s, s->cur_func->scope_level); + JS_FreeAtom(s->ctx, atom); + return 0; + } else { + if (js_parse_expr_binary(s, level - 1, parse_flags)) + return -1; } - if (js_parse_expr_binary(s, level - 1, parse_flags)) - return -1; for(;;) { op = s->token.val; switch(level) { @@ -25482,7 +25566,6 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) /* OP_async_yield_star takes the value as parameter */ emit_op(s, OP_get_field); emit_atom(s, JS_ATOM_value); - emit_op(s, OP_await); emit_op(s, OP_async_yield_star); } else { /* OP_yield_star takes (value, done) as parameter */ @@ -25776,61 +25859,61 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont) static void emit_return(JSParseState *s, BOOL hasval) { BlockEnv *top; - int drop_count; - drop_count = 0; + if (s->cur_func->func_kind != JS_FUNC_NORMAL) { + if (!hasval) { + /* no value: direct return in case of async generator */ + emit_op(s, OP_undefined); + hasval = TRUE; + } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { + /* the await must be done before handling the "finally" in + case it raises an exception */ + emit_op(s, OP_await); + } + } + top = s->cur_func->top_break; while (top != NULL) { - /* XXX: emit the appropriate OP_leave_scope opcodes? Probably not - required as all local variables will be closed upon returning - from JS_CallInternal, but not in the same order. */ - if (top->has_iterator) { - /* with 'yield', the exact number of OP_drop to emit is - unknown, so we use a specific operation to look for - the catch offset */ + if (top->has_iterator || top->label_finally != -1) { if (!hasval) { emit_op(s, OP_undefined); hasval = TRUE; } - emit_op(s, OP_iterator_close_return); - if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { - int label_next, label_next2; - - emit_op(s, OP_drop); /* catch offset */ - emit_op(s, OP_drop); /* next */ - emit_op(s, OP_get_field2); - emit_atom(s, JS_ATOM_return); - /* stack: iter_obj return_func */ - emit_op(s, OP_dup); - emit_op(s, OP_is_undefined_or_null); - label_next = emit_goto(s, OP_if_true, -1); - emit_op(s, OP_call_method); - emit_u16(s, 0); - emit_op(s, OP_iterator_check_object); - emit_op(s, OP_await); - label_next2 = emit_goto(s, OP_goto, -1); - emit_label(s, label_next); - emit_op(s, OP_drop); - emit_label(s, label_next2); - emit_op(s, OP_drop); + /* Remove the stack elements up to and including the catch + offset. When 'yield' is used in an expression we have + no easy way to count them, so we use this specific + instruction instead. */ + emit_op(s, OP_nip_catch); + /* stack: iter_obj next ret_val */ + if (top->has_iterator) { + if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { + int label_next, label_next2; + emit_op(s, OP_nip); /* next */ + emit_op(s, OP_swap); + emit_op(s, OP_get_field2); + emit_atom(s, JS_ATOM_return); + /* stack: iter_obj return_func */ + emit_op(s, OP_dup); + emit_op(s, OP_is_undefined_or_null); + label_next = emit_goto(s, OP_if_true, -1); + emit_op(s, OP_call_method); + emit_u16(s, 0); + emit_op(s, OP_iterator_check_object); + emit_op(s, OP_await); + label_next2 = emit_goto(s, OP_goto, -1); + emit_label(s, label_next); + emit_op(s, OP_drop); + emit_label(s, label_next2); + emit_op(s, OP_drop); + } else { + emit_op(s, OP_rot3r); + emit_op(s, OP_undefined); /* dummy catch offset */ + emit_op(s, OP_iterator_close); + } } else { - emit_op(s, OP_iterator_close); + /* execute the "finally" block */ + emit_goto(s, OP_gosub, top->label_finally); } - drop_count = -3; - } - drop_count += top->drop_count; - if (top->label_finally != -1) { - while(drop_count) { - /* must keep the stack top if hasval */ - emit_op(s, hasval ? OP_nip : OP_drop); - drop_count--; - } - if (!hasval) { - /* must push return value to keep same stack size */ - emit_op(s, OP_undefined); - hasval = TRUE; - } - emit_goto(s, OP_gosub, top->label_finally); } top = top->prev; } @@ -25847,20 +25930,15 @@ static void emit_return(JSParseState *s, BOOL hasval) label_return = -1; } - /* XXX: if this is not initialized, should throw the - ReferenceError in the caller realm */ - emit_op(s, OP_scope_get_var); + /* The error should be raised in the caller context, so we use + a specific opcode */ + emit_op(s, OP_scope_get_var_checkthis); emit_atom(s, JS_ATOM_this); emit_u16(s, 0); emit_label(s, label_return); emit_op(s, OP_return); } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) { - if (!hasval) { - emit_op(s, OP_undefined); - } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { - emit_op(s, OP_await); - } emit_op(s, OP_return_async); } else { emit_op(s, hasval ? OP_return : OP_return_undef); @@ -26127,6 +26205,9 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, emit_atom(s, var_name); emit_u16(s, fd->scope_level); } + } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) && + peek_token(s, FALSE) == TOK_OF) { + return js_parse_error(s, "'for of' expression cannot start with 'async'"); } else { int skip_bits; if ((s->token.val == '[' || s->token.val == '{') @@ -26343,6 +26424,10 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, js_parse_error(s, "return not in a function"); goto fail; } + if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) { + js_parse_error(s, "return in a static initializer block"); + goto fail; + } if (next_token(s)) goto fail; if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) { @@ -26511,6 +26596,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, is_async = TRUE; if (next_token(s)) goto fail; + s->cur_func->has_await = TRUE; } if (js_parse_expect(s, '(')) goto fail; @@ -27041,6 +27127,9 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name) m->func_obj = JS_UNDEFINED; m->eval_exception = JS_UNDEFINED; m->meta_obj = JS_UNDEFINED; + m->promise = JS_UNDEFINED; + m->resolving_funcs[0] = JS_UNDEFINED; + m->resolving_funcs[1] = JS_UNDEFINED; list_add_tail(&m->link, &ctx->loaded_modules); return m; } @@ -27062,6 +27151,9 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkValue(rt, m->func_obj, mark_func); JS_MarkValue(rt, m->eval_exception, mark_func); JS_MarkValue(rt, m->meta_obj, mark_func); + JS_MarkValue(rt, m->promise, mark_func); + JS_MarkValue(rt, m->resolving_funcs[0], mark_func); + JS_MarkValue(rt, m->resolving_funcs[1], mark_func); } static void js_free_module_def(JSContext *ctx, JSModuleDef *m) @@ -27092,11 +27184,15 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m) JS_FreeAtom(ctx, mi->import_name); } js_free(ctx, m->import_entries); + js_free(ctx, m->async_parent_modules); JS_FreeValue(ctx, m->module_ns); JS_FreeValue(ctx, m->func_obj); JS_FreeValue(ctx, m->eval_exception); JS_FreeValue(ctx, m->meta_obj); + JS_FreeValue(ctx, m->promise); + JS_FreeValue(ctx, m->resolving_funcs[0]); + JS_FreeValue(ctx, m->resolving_funcs[1]); list_del(&m->link); js_free(ctx, m); } @@ -27952,7 +28048,8 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) /* Prepare a module to be executed by resolving all the imported variables. */ -static int js_link_module(JSContext *ctx, JSModuleDef *m) +static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, + JSModuleDef **pstack_top, int index) { int i; JSImportEntry *mi; @@ -27962,21 +28059,47 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m) BOOL is_c_module; JSValue ret_val; - if (m->instantiated) - return 0; - m->instantiated = TRUE; - + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; + } + #ifdef DUMP_MODULE_RESOLVE { char buf1[ATOM_GET_STR_BUF_SIZE]; - printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); + printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); } #endif + if (m->status == JS_MODULE_STATUS_LINKING || + m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED) + return index; + + assert(m->status == JS_MODULE_STATUS_UNLINKED); + m->status = JS_MODULE_STATUS_LINKING; + m->dfs_index = index; + m->dfs_ancestor_index = index; + index++; + /* push 'm' on stack */ + m->stack_prev = *pstack_top; + *pstack_top = m; + for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; - if (js_link_module(ctx, rme->module) < 0) + m1 = rme->module; + index = js_inner_module_linking(ctx, m1, pstack_top, index); + if (index < 0) goto fail; + assert(m1->status == JS_MODULE_STATUS_LINKING || + m1->status == JS_MODULE_STATUS_LINKED || + m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m1->status == JS_MODULE_STATUS_EVALUATED); + if (m1->status == JS_MODULE_STATUS_LINKING) { + m->dfs_ancestor_index = min_int(m->dfs_ancestor_index, + m1->dfs_ancestor_index); + } } #ifdef DUMP_MODULE_RESOLVE @@ -28102,14 +28225,59 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m) JS_FreeValue(ctx, ret_val); } + assert(m->dfs_ancestor_index <= m->dfs_index); + if (m->dfs_index == m->dfs_ancestor_index) { + for(;;) { + /* pop m1 from stack */ + m1 = *pstack_top; + *pstack_top = m1->stack_prev; + m1->status = JS_MODULE_STATUS_LINKED; + if (m1 == m) + break; + } + } + #ifdef DUMP_MODULE_RESOLVE - printf("done instantiate\n"); + printf("js_inner_module_linking done\n"); #endif - return 0; + return index; fail: return -1; } +/* Prepare a module to be executed by resolving all the imported + variables. */ +static int js_link_module(JSContext *ctx, JSModuleDef *m) +{ + JSModuleDef *stack_top, *m1; + +#ifdef DUMP_MODULE_RESOLVE + { + char buf1[ATOM_GET_STR_BUF_SIZE]; + printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); + } +#endif + assert(m->status == JS_MODULE_STATUS_UNLINKED || + m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + stack_top = NULL; + if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) { + while (stack_top != NULL) { + m1 = stack_top; + assert(m1->status == JS_MODULE_STATUS_LINKING); + m1->status = JS_MODULE_STATUS_UNLINKED; + stack_top = m1->stack_prev; + } + return -1; + } + assert(stack_top == NULL); + assert(m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + return 0; +} + /* return JS_ATOM_NULL if the name cannot be found. Only works with not striped bytecode functions. */ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) @@ -28118,8 +28286,8 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) JSFunctionBytecode *b; JSObject *p; /* XXX: currently we just use the filename of the englobing - function. It does not work for eval(). Need to add a - ScriptOrModule info in JSFunctionBytecode */ + function from the debug info. May need to add a ScriptOrModule + info in JSFunctionBytecode. */ sf = ctx->rt->current_stack_frame; if (!sf) return JS_ATOM_NULL; @@ -28128,15 +28296,23 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) if (!sf) return JS_ATOM_NULL; } - if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT) - return JS_ATOM_NULL; - p = JS_VALUE_GET_OBJ(sf->cur_func); - if (!js_class_has_bytecode(p->class_id)) - return JS_ATOM_NULL; - b = p->u.func.function_bytecode; - if (!b->has_debug) - return JS_ATOM_NULL; - return JS_DupAtom(ctx, b->debug.filename); + for(;;) { + if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT) + return JS_ATOM_NULL; + p = JS_VALUE_GET_OBJ(sf->cur_func); + if (!js_class_has_bytecode(p->class_id)) + return JS_ATOM_NULL; + b = p->u.func.function_bytecode; + if (!b->is_direct_or_indirect_eval) { + if (!b->has_debug) + return JS_ATOM_NULL; + return JS_DupAtom(ctx, b->debug.filename); + } else { + sf = sf->prev_frame; + if (!sf) + return JS_ATOM_NULL; + } + } } JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m) @@ -28179,29 +28355,110 @@ static JSValue js_import_meta(JSContext *ctx) return JS_GetImportMeta(ctx, m); } -/* used by os.Worker() and import() */ -JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, - const char *filename) +static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m) +{ + return JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); +} + +static JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSValueConst *resolving_funcs = (JSValueConst *)func_data; + JSValueConst error; + JSValue ret; + + /* XXX: check if the test is necessary */ + if (argc >= 1) + error = argv[0]; + else + error = JS_UNDEFINED; + ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, + 1, &error); + JS_FreeValue(ctx, ret); + return JS_UNDEFINED; +} + +static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) { + JSValueConst *resolving_funcs = (JSValueConst *)func_data; + JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]); + JSValue ret, ns; + + /* return the module namespace */ + ns = js_get_module_ns(ctx, m); + if (JS_IsException(ns)) { + JSValue err = JS_GetException(ctx); + js_load_module_rejected(ctx, JS_UNDEFINED, 1, (JSValueConst *)&err, 0, func_data); + return JS_UNDEFINED; + } + ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&ns); + JS_FreeValue(ctx, ret); + JS_FreeValue(ctx, ns); + return JS_UNDEFINED; +} + +static void JS_LoadModuleInternal(JSContext *ctx, const char *basename, + const char *filename, + JSValueConst *resolving_funcs) +{ + JSValue evaluate_promise; JSModuleDef *m; - JSValue ret, func_obj; + JSValue ret, err, func_obj, evaluate_resolving_funcs[2]; + JSValueConst func_data[3]; m = js_host_resolve_imported_module(ctx, basename, filename); if (!m) - return NULL; + goto fail; if (js_resolve_module(ctx, m) < 0) { js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED); - return NULL; + goto fail; } /* Evaluate the module code */ - func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); - ret = JS_EvalFunction(ctx, func_obj); - if (JS_IsException(ret)) - return NULL; + func_obj = JS_NewModuleValue(ctx, m); + evaluate_promise = JS_EvalFunction(ctx, func_obj); + if (JS_IsException(evaluate_promise)) { + fail: + err = JS_GetException(ctx); + ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, + 1, (JSValueConst *)&err); + JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ + JS_FreeValue(ctx, err); + return; + } + + func_obj = JS_NewModuleValue(ctx, m); + func_data[0] = resolving_funcs[0]; + func_data[1] = resolving_funcs[1]; + func_data[2] = func_obj; + evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data); + evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data); + JS_FreeValue(ctx, func_obj); + ret = js_promise_then(ctx, evaluate_promise, 2, (JSValueConst *)evaluate_resolving_funcs); JS_FreeValue(ctx, ret); - return m; + JS_FreeValue(ctx, evaluate_resolving_funcs[0]); + JS_FreeValue(ctx, evaluate_resolving_funcs[1]); + JS_FreeValue(ctx, evaluate_promise); +} + +/* Return a promise or an exception in case of memory error. Used by + os.Worker() */ +JSValue JS_LoadModule(JSContext *ctx, const char *basename, + const char *filename) +{ + JSValue promise, resolving_funcs[2]; + + promise = JS_NewPromiseCapability(ctx, resolving_funcs); + if (JS_IsException(promise)) + return JS_EXCEPTION; + JS_LoadModuleInternal(ctx, basename, filename, + (JSValueConst *)resolving_funcs); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return promise; } static JSValue js_dynamic_import_job(JSContext *ctx, @@ -28210,9 +28467,8 @@ static JSValue js_dynamic_import_job(JSContext *ctx, JSValueConst *resolving_funcs = argv; JSValueConst basename_val = argv[2]; JSValueConst specifier = argv[3]; - JSModuleDef *m; const char *basename = NULL, *filename; - JSValue ret, err, ns; + JSValue ret, err; if (!JS_IsString(basename_val)) { JS_ThrowTypeError(ctx, "no function filename for import()"); @@ -28226,24 +28482,12 @@ static JSValue js_dynamic_import_job(JSContext *ctx, if (!filename) goto exception; - m = JS_RunModule(ctx, basename, filename); + JS_LoadModuleInternal(ctx, basename, filename, + resolving_funcs); JS_FreeCString(ctx, filename); - if (!m) - goto exception; - - /* return the module namespace */ - ns = js_get_module_ns(ctx, m); - if (JS_IsException(ns)) - goto exception; - - ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, - 1, (JSValueConst *)&ns); - JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ - JS_FreeValue(ctx, ns); JS_FreeCString(ctx, basename); return JS_UNDEFINED; exception: - err = JS_GetException(ctx); ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, (JSValueConst *)&err); @@ -28279,6 +28523,8 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) args[2] = basename_val; args[3] = specifier; + /* cannot run JS_LoadModuleInternal synchronously because it would + cause an unexpected recursion in js_evaluate_module() */ JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args); JS_FreeValue(ctx, basename_val); @@ -28287,60 +28533,397 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) return promise; } -/* Run the function of the module and of all its requested - modules. */ -static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) +static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m) +{ + m->status = JS_MODULE_STATUS_EVALUATED; + if (!JS_IsUndefined(m->promise)) { + JSValue value, ret_val; + assert(m->cycle_root == m); + value = JS_UNDEFINED; + ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&value); + JS_FreeValue(ctx, ret_val); + } +} + +typedef struct { + JSModuleDef **tab; + int count; + int size; +} ExecModuleList; + +/* XXX: slow. Could use a linked list instead of ExecModuleList */ +static BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m) +{ + int i; + for(i = 0; i < exec_list->count; i++) { + if (exec_list->tab[i] == m) + return TRUE; + } + return FALSE; +} + +static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module, + ExecModuleList *exec_list) +{ + int i; + + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; + } + for(i = 0; i < module->async_parent_modules_count; i++) { + JSModuleDef *m = module->async_parent_modules[i]; + if (!find_in_exec_module_list(exec_list, m) && + !m->cycle_root->eval_has_exception) { + assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC); + assert(!m->eval_has_exception); + assert(m->async_evaluation); + assert(m->pending_async_dependencies > 0); + m->pending_async_dependencies--; + if (m->pending_async_dependencies == 0) { + if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) { + return -1; + } + exec_list->tab[exec_list->count++] = m; + if (!m->has_tla) { + if (gather_available_ancestors(ctx, m, exec_list)) + return -1; + } + } + } + } + return 0; +} + +static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque) +{ + JSModuleDef *m1 = *(JSModuleDef **)p1; + JSModuleDef *m2 = *(JSModuleDef **)p2; + return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) - + (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp); +} + +static int js_execute_async_module(JSContext *ctx, JSModuleDef *m); +static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m, + JSValue *pvalue); + +static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]); + JSValueConst error = argv[0]; + int i; + + if (js_check_stack_overflow(ctx->rt, 0)) + return JS_ThrowStackOverflow(ctx); + + if (module->status == JS_MODULE_STATUS_EVALUATED) { + assert(module->eval_has_exception); + return JS_UNDEFINED; + } + + assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC); + assert(!module->eval_has_exception); + assert(module->async_evaluation); + + module->eval_has_exception = TRUE; + module->eval_exception = JS_DupValue(ctx, error); + module->status = JS_MODULE_STATUS_EVALUATED; + + for(i = 0; i < module->async_parent_modules_count; i++) { + JSModuleDef *m = module->async_parent_modules[i]; + JSValue m_obj = JS_NewModuleValue(ctx, m); + js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0, + &m_obj); + JS_FreeValue(ctx, m_obj); + } + + if (!JS_IsUndefined(module->promise)) { + JSValue ret_val; + assert(module->cycle_root == module); + ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED, + 1, &error); + JS_FreeValue(ctx, ret_val); + } + return JS_UNDEFINED; +} + +static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]); + ExecModuleList exec_list_s, *exec_list = &exec_list_s; + int i; + + if (module->status == JS_MODULE_STATUS_EVALUATED) { + assert(module->eval_has_exception); + return JS_UNDEFINED; + } + assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC); + assert(!module->eval_has_exception); + assert(module->async_evaluation); + module->async_evaluation = FALSE; + js_set_module_evaluated(ctx, module); + + exec_list->tab = NULL; + exec_list->count = 0; + exec_list->size = 0; + + if (gather_available_ancestors(ctx, module, exec_list) < 0) { + js_free(ctx, exec_list->tab); + return JS_EXCEPTION; + } + + /* sort by increasing async_evaluation timestamp */ + rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]), + exec_module_list_cmp, NULL); + + for(i = 0; i < exec_list->count; i++) { + JSModuleDef *m = exec_list->tab[i]; + if (m->status == JS_MODULE_STATUS_EVALUATED) { + assert(m->eval_has_exception); + } else if (m->has_tla) { + js_execute_async_module(ctx, m); + } else { + JSValue error; + if (js_execute_sync_module(ctx, m, &error) < 0) { + JSValue m_obj = JS_NewModuleValue(ctx, m); + js_async_module_execution_rejected(ctx, JS_UNDEFINED, + 1, (JSValueConst *)&error, 0, + &m_obj); + JS_FreeValue(ctx, m_obj); + JS_FreeValue(ctx, error); + } else { + js_set_module_evaluated(ctx, m); + } + } + } + js_free(ctx, exec_list->tab); + return JS_UNDEFINED; +} + +static int js_execute_async_module(JSContext *ctx, JSModuleDef *m) +{ + JSValue promise, m_obj; + JSValue resolve_funcs[2], ret_val; + promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0); + if (JS_IsException(promise)) + return -1; + m_obj = JS_NewModuleValue(ctx, m); + resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, (JSValueConst *)&m_obj); + resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, (JSValueConst *)&m_obj); + ret_val = js_promise_then(ctx, promise, 2, (JSValueConst *)resolve_funcs); + JS_FreeValue(ctx, ret_val); + JS_FreeValue(ctx, m_obj); + JS_FreeValue(ctx, resolve_funcs[0]); + JS_FreeValue(ctx, resolve_funcs[1]); + JS_FreeValue(ctx, promise); + return 0; +} + +/* return < 0 in case of exception. *pvalue contains the exception. */ +static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m, + JSValue *pvalue) +{ + if (m->init_func) { + /* C module init : no asynchronous execution */ + if (m->init_func(ctx, m) < 0) + goto fail; + } else { + JSValue promise; + JSPromiseStateEnum state; + + promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0); + if (JS_IsException(promise)) + goto fail; + state = JS_PromiseState(ctx, promise); + if (state == JS_PROMISE_FULFILLED) { + JS_FreeValue(ctx, promise); + } else if (state == JS_PROMISE_REJECTED) { + *pvalue = JS_PromiseResult(ctx, promise); + JS_FreeValue(ctx, promise); + return -1; + } else { + JS_FreeValue(ctx, promise); + JS_ThrowTypeError(ctx, "promise is pending"); + fail: + *pvalue = JS_GetException(ctx); + return -1; + } + } + *pvalue = JS_UNDEFINED; + return 0; +} + +/* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1, + exception) */ +static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m, + int index, JSModuleDef **pstack_top, + JSValue *pvalue) { JSModuleDef *m1; int i; - JSValue ret_val; - if (m->eval_mark) - return JS_UNDEFINED; /* avoid cycles */ + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + *pvalue = JS_GetException(ctx); + return -1; + } + +#ifdef DUMP_MODULE_RESOLVE + { + char buf1[ATOM_GET_STR_BUF_SIZE]; + printf("js_inner_module_evaluation '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); + } +#endif - if (m->evaluated) { - /* if the module was already evaluated, rethrow the exception - it raised */ + if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED) { if (m->eval_has_exception) { - return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception)); + *pvalue = JS_DupValue(ctx, m->eval_exception); + return -1; } else { - return JS_UNDEFINED; + *pvalue = JS_UNDEFINED; + return index; } } + if (m->status == JS_MODULE_STATUS_EVALUATING) { + *pvalue = JS_UNDEFINED; + return index; + } + assert(m->status == JS_MODULE_STATUS_LINKED); - m->eval_mark = TRUE; - + m->status = JS_MODULE_STATUS_EVALUATING; + m->dfs_index = index; + m->dfs_ancestor_index = index; + m->pending_async_dependencies = 0; + index++; + /* push 'm' on stack */ + m->stack_prev = *pstack_top; + *pstack_top = m; + for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; m1 = rme->module; - if (!m1->eval_mark) { - ret_val = js_evaluate_module(ctx, m1); - if (JS_IsException(ret_val)) { - m->eval_mark = FALSE; - return ret_val; + index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue); + if (index < 0) + return -1; + assert(m1->status == JS_MODULE_STATUS_EVALUATING || + m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m1->status == JS_MODULE_STATUS_EVALUATED); + if (m1->status == JS_MODULE_STATUS_EVALUATING) { + m->dfs_ancestor_index = min_int(m->dfs_ancestor_index, + m1->dfs_ancestor_index); + } else { + m1 = m1->cycle_root; + assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m1->status == JS_MODULE_STATUS_EVALUATED); + if (m1->eval_has_exception) { + *pvalue = JS_DupValue(ctx, m1->eval_exception); + return -1; } - JS_FreeValue(ctx, ret_val); + } + if (m1->async_evaluation) { + m->pending_async_dependencies++; + if (js_resize_array(ctx, (void **)&m1->async_parent_modules, sizeof(m1->async_parent_modules[0]), &m1->async_parent_modules_size, m1->async_parent_modules_count + 1)) { + *pvalue = JS_GetException(ctx); + return -1; + } + m1->async_parent_modules[m1->async_parent_modules_count++] = m; } } - if (m->init_func) { - /* C module init */ - if (m->init_func(ctx, m) < 0) - ret_val = JS_EXCEPTION; - else - ret_val = JS_UNDEFINED; + if (m->pending_async_dependencies > 0) { + assert(!m->async_evaluation); + m->async_evaluation = TRUE; + m->async_evaluation_timestamp = + ctx->rt->module_async_evaluation_next_timestamp++; + } else if (m->has_tla) { + assert(!m->async_evaluation); + m->async_evaluation = TRUE; + m->async_evaluation_timestamp = + ctx->rt->module_async_evaluation_next_timestamp++; + js_execute_async_module(ctx, m); } else { - ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL); - m->func_obj = JS_UNDEFINED; + if (js_execute_sync_module(ctx, m, pvalue) < 0) + return -1; + } + + assert(m->dfs_ancestor_index <= m->dfs_index); + if (m->dfs_index == m->dfs_ancestor_index) { + for(;;) { + /* pop m1 from stack */ + m1 = *pstack_top; + *pstack_top = m1->stack_prev; + if (!m1->async_evaluation) { + m1->status = JS_MODULE_STATUS_EVALUATED; + } else { + m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC; + } + /* spec bug: cycle_root must be assigned before the test */ + m1->cycle_root = m; + if (m1 == m) + break; + } } - if (JS_IsException(ret_val)) { - /* save the thrown exception value */ - m->eval_has_exception = TRUE; - m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception); + *pvalue = JS_UNDEFINED; + return index; +} + +/* Run the function of the module and of all its requested + modules. Return a promise or an exception. */ +static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) +{ + JSModuleDef *m1, *stack_top; + JSValue ret_val, result; + + assert(m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED) { + m = m->cycle_root; + } + /* a promise may be created only on the cycle_root of a cycle */ + if (!JS_IsUndefined(m->promise)) + return JS_DupValue(ctx, m->promise); + m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs); + if (JS_IsException(m->promise)) + return JS_EXCEPTION; + + stack_top = NULL; + if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) { + while (stack_top != NULL) { + m1 = stack_top; + assert(m1->status == JS_MODULE_STATUS_EVALUATING); + m1->status = JS_MODULE_STATUS_EVALUATED; + m1->eval_has_exception = TRUE; + m1->eval_exception = JS_DupValue(ctx, result); + m1->cycle_root = m; /* spec bug: should be present */ + stack_top = m1->stack_prev; + } + JS_FreeValue(ctx, result); + assert(m->status == JS_MODULE_STATUS_EVALUATED); + assert(m->eval_has_exception); + ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED, + 1, (JSValueConst *)&m->eval_exception); + JS_FreeValue(ctx, ret_val); + } else { + assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + assert(!m->eval_has_exception); + if (!m->async_evaluation) { + JSValue value; + assert(m->status == JS_MODULE_STATUS_EVALUATED); + value = JS_UNDEFINED; + ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&value); + JS_FreeValue(ctx, ret_val); + } + assert(stack_top == NULL); } - m->eval_mark = FALSE; - m->evaluated = TRUE; - return ret_val; + return JS_DupValue(ctx, m->promise); } static __exception JSAtom js_parse_from_clause(JSParseState *s) @@ -29694,6 +30277,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, case OP_scope_get_ref: dbuf_putc(bc, OP_undefined); /* fall thru */ + case OP_scope_get_var_checkthis: case OP_scope_get_var_undef: case OP_scope_get_var: case OP_scope_put_var: @@ -29719,7 +30303,12 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, } } else { if (s->vars[var_idx].is_lexical) { - dbuf_putc(bc, OP_get_loc_check); + if (op == OP_scope_get_var_checkthis) { + /* only used for 'this' return in derived class constructors */ + dbuf_putc(bc, OP_get_loc_checkthis); + } else { + dbuf_putc(bc, OP_get_loc_check); + } } else { dbuf_putc(bc, OP_get_loc); } @@ -30176,12 +30765,17 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s, /* obj func value */ dbuf_putc(bc, OP_call_method); dbuf_put_u16(bc, 1); + dbuf_putc(bc, OP_drop); } break; default: abort(); } break; + case OP_scope_in_private_field: + get_loc_or_ref(bc, is_ref, idx); + dbuf_putc(bc, OP_private_in); + break; default: abort(); } @@ -30300,12 +30894,13 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) is_arg_scope = (scope_idx == ARG_SCOPE_END); if (!is_arg_scope) { /* add unscoped variables */ + /* XXX: propagate is_const and var_kind too ? */ for(i = 0; i < fd->arg_count; i++) { vd = &fd->args[i]; if (vd->var_name != JS_ATOM_NULL) { get_closure_var(ctx, s, fd, - TRUE, i, vd->var_name, FALSE, FALSE, - JS_VAR_NORMAL); + TRUE, i, vd->var_name, FALSE, + vd->is_lexical, JS_VAR_NORMAL); } } for(i = 0; i < fd->var_count; i++) { @@ -30315,8 +30910,8 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) vd->var_name != JS_ATOM__ret_ && vd->var_name != JS_ATOM_NULL) { get_closure_var(ctx, s, fd, - FALSE, i, vd->var_name, FALSE, FALSE, - JS_VAR_NORMAL); + FALSE, i, vd->var_name, FALSE, + vd->is_lexical, JS_VAR_NORMAL); } } } else { @@ -30325,8 +30920,8 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) /* do not close top level last result */ if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) { get_closure_var(ctx, s, fd, - FALSE, i, vd->var_name, FALSE, FALSE, - JS_VAR_NORMAL); + FALSE, i, vd->var_name, FALSE, + vd->is_lexical, JS_VAR_NORMAL); } } } @@ -30858,6 +31453,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) dbuf_putc(&bc_out, op); dbuf_put_u16(&bc_out, s->scopes[scope].first + 1); break; + case OP_scope_get_var_checkthis: case OP_scope_get_var_undef: case OP_scope_get_var: case OP_scope_put_var: @@ -30887,6 +31483,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) case OP_scope_get_private_field: case OP_scope_get_private_field2: case OP_scope_put_private_field: + case OP_scope_in_private_field: { int ret; var_name = get_u32(bc_buf + pos + 1); @@ -31098,6 +31695,17 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) case OP_set_class_name: /* only used during parsing */ break; + + case OP_get_field_opt_chain: /* equivalent to OP_get_field */ + { + JSAtom name = get_u32(bc_buf + pos + 1); + dbuf_putc(&bc_out, OP_get_field); + dbuf_put_u32(&bc_out, name); + } + break; + case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */ + dbuf_putc(&bc_out, OP_get_array_el); + break; default: no_change: @@ -32230,6 +32838,7 @@ typedef struct StackSizeState { int bc_len; int stack_len_max; uint16_t *stack_level_tab; + int32_t *catch_pos_tab; int *pc_stack; int pc_stack_len; int pc_stack_size; @@ -32237,7 +32846,7 @@ typedef struct StackSizeState { /* 'op' is only used for error indication */ static __exception int ss_check(JSContext *ctx, StackSizeState *s, - int pos, int op, int stack_len) + int pos, int op, int stack_len, int catch_pos) { if ((unsigned)pos >= s->bc_len) { JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos); @@ -32253,9 +32862,13 @@ static __exception int ss_check(JSContext *ctx, StackSizeState *s, if (s->stack_level_tab[pos] != 0xffff) { /* already explored: check that the stack size is consistent */ if (s->stack_level_tab[pos] != stack_len) { - JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)", + JS_ThrowInternalError(ctx, "inconsistent stack size: %d %d (pc=%d)", s->stack_level_tab[pos], stack_len, pos); return -1; + } else if (s->catch_pos_tab[pos] != catch_pos) { + JS_ThrowInternalError(ctx, "inconsistent catch position: %d %d (pc=%d)", + s->catch_pos_tab[pos], catch_pos, pos); + return -1; } else { return 0; } @@ -32263,7 +32876,8 @@ static __exception int ss_check(JSContext *ctx, StackSizeState *s, /* mark as explored and store the stack size */ s->stack_level_tab[pos] = stack_len; - + s->catch_pos_tab[pos] = catch_pos; + /* queue the new PC to explore */ if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]), &s->pc_stack_size, s->pc_stack_len + 1)) @@ -32277,7 +32891,7 @@ static __exception int compute_stack_size(JSContext *ctx, int *pstack_size) { StackSizeState s_s, *s = &s_s; - int i, diff, n_pop, pos_next, stack_len, pos, op; + int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level; const JSOpCode *oi; const uint8_t *bc_buf; @@ -32290,24 +32904,33 @@ static __exception int compute_stack_size(JSContext *ctx, return -1; for(i = 0; i < s->bc_len; i++) s->stack_level_tab[i] = 0xffff; - s->stack_len_max = 0; s->pc_stack = NULL; + s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) * + s->bc_len); + if (!s->catch_pos_tab) + goto fail; + + s->stack_len_max = 0; s->pc_stack_len = 0; s->pc_stack_size = 0; /* breadth-first graph exploration */ - if (ss_check(ctx, s, 0, OP_invalid, 0)) + if (ss_check(ctx, s, 0, OP_invalid, 0, -1)) goto fail; while (s->pc_stack_len > 0) { pos = s->pc_stack[--s->pc_stack_len]; stack_len = s->stack_level_tab[pos]; + catch_pos = s->catch_pos_tab[pos]; op = bc_buf[pos]; if (op == 0 || op >= OP_COUNT) { JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos); goto fail; } oi = &short_opcode_info(op); +#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64) + printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos); +#endif pos_next = pos + oi->size; if (pos_next > s->bc_len) { JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos); @@ -32363,55 +32986,104 @@ static __exception int compute_stack_size(JSContext *ctx, case OP_if_true8: case OP_if_false8: diff = (int8_t)bc_buf[pos + 1]; - if (ss_check(ctx, s, pos + 1 + diff, op, stack_len)) + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos)) goto fail; break; #endif case OP_if_true: case OP_if_false: - case OP_catch: diff = get_u32(bc_buf + pos + 1); - if (ss_check(ctx, s, pos + 1 + diff, op, stack_len)) + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos)) goto fail; break; case OP_gosub: diff = get_u32(bc_buf + pos + 1); - if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1)) + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos)) goto fail; break; case OP_with_get_var: case OP_with_delete_var: diff = get_u32(bc_buf + pos + 5); - if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1)) + if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos)) goto fail; break; case OP_with_make_ref: case OP_with_get_ref: case OP_with_get_ref_undef: diff = get_u32(bc_buf + pos + 5); - if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2)) + if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos)) goto fail; break; case OP_with_put_var: diff = get_u32(bc_buf + pos + 5); - if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1)) + if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos)) goto fail; break; - + case OP_catch: + diff = get_u32(bc_buf + pos + 1); + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos)) + goto fail; + catch_pos = pos; + break; + case OP_for_of_start: + case OP_for_await_of_start: + catch_pos = pos; + break; + /* we assume the catch offset entry is only removed with + some op codes */ + case OP_drop: + catch_level = stack_len; + goto check_catch; + case OP_nip: + catch_level = stack_len - 1; + goto check_catch; + case OP_nip1: + catch_level = stack_len - 1; + goto check_catch; + case OP_iterator_close: + catch_level = stack_len + 2; + check_catch: + /* Note: for for_of_start/for_await_of_start we consider + the catch offset is on the first stack entry instead of + the thirst */ + if (catch_pos >= 0) { + int level; + level = s->stack_level_tab[catch_pos]; + if (bc_buf[catch_pos] != OP_catch) + level++; /* for_of_start, for_wait_of_start */ + /* catch_level = stack_level before op_catch is executed ? */ + if (catch_level == level) { + catch_pos = s->catch_pos_tab[catch_pos]; + } + } + break; + case OP_nip_catch: + if (catch_pos < 0) { + JS_ThrowInternalError(ctx, "nip_catch: no catch op (pc=%d)", pos); + goto fail; + } + stack_len = s->stack_level_tab[catch_pos]; + if (bc_buf[catch_pos] != OP_catch) + stack_len++; /* for_of_start, for_wait_of_start */ + stack_len++; /* no stack overflow is possible by construction */ + catch_pos = s->catch_pos_tab[catch_pos]; + break; default: break; } - if (ss_check(ctx, s, pos_next, op, stack_len)) + if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos)) goto fail; done_insn: ; } - js_free(ctx, s->stack_level_tab); js_free(ctx, s->pc_stack); + js_free(ctx, s->catch_pos_tab); + js_free(ctx, s->stack_level_tab); *pstack_size = s->stack_len_max; return 0; fail: - js_free(ctx, s->stack_level_tab); js_free(ctx, s->pc_stack); + js_free(ctx, s->catch_pos_tab); + js_free(ctx, s->stack_level_tab); *pstack_size = 0; return -1; } @@ -32656,6 +33328,8 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->super_allowed = fd->super_allowed; b->arguments_allowed = fd->arguments_allowed; b->backtrace_barrier = fd->backtrace_barrier; + b->is_direct_or_indirect_eval = (fd->eval_type == JS_EVAL_TYPE_DIRECT || + fd->eval_type == JS_EVAL_TYPE_INDIRECT); b->realm = JS_DupContext(ctx); add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); @@ -32938,8 +33612,9 @@ static __exception int js_parse_function_decl2(JSParseState *s, func_type == JS_PARSE_FUNC_EXPR && (func_kind & JS_FUNC_GENERATOR)) || (s->token.u.ident.atom == JS_ATOM_await && - func_type == JS_PARSE_FUNC_EXPR && - (func_kind & JS_FUNC_ASYNC))) { + ((func_type == JS_PARSE_FUNC_EXPR && + (func_kind & JS_FUNC_ASYNC)) || + func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) { return js_parse_error_reserved_identifier(s); } } @@ -33033,7 +33708,8 @@ static __exception int js_parse_function_decl2(JSParseState *s, func_type == JS_PARSE_FUNC_SETTER || func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR || func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR); - fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW); + fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW && + func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT); fd->has_this_binding = fd->has_arguments_binding; fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR); if (func_type == JS_PARSE_FUNC_ARROW) { @@ -33041,6 +33717,11 @@ static __exception int js_parse_function_decl2(JSParseState *s, fd->super_call_allowed = fd->parent->super_call_allowed; fd->super_allowed = fd->parent->super_allowed; fd->arguments_allowed = fd->parent->arguments_allowed; + } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) { + fd->new_target_allowed = TRUE; // although new.target === undefined + fd->super_call_allowed = FALSE; + fd->super_allowed = TRUE; + fd->arguments_allowed = FALSE; } else { fd->new_target_allowed = TRUE; fd->super_call_allowed = fd->is_derived_class_constructor; @@ -33078,7 +33759,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (add_arg(ctx, fd, name) < 0) goto fail; fd->defined_arg_count = 1; - } else { + } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) { if (s->token.val == '(') { int skip_bits; /* if there is an '=' inside the parameter list, we @@ -33299,8 +33980,10 @@ static __exception int js_parse_function_decl2(JSParseState *s, } } - if (js_parse_expect(s, '{')) - goto fail; + if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) { + if (js_parse_expect(s, '{')) + goto fail; + } if (js_parse_directives(s)) goto fail; @@ -33330,9 +34013,15 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (js_is_live_code(s)) { emit_return(s, FALSE); } -done: + done: s->cur_func = fd->parent; + /* Reparse identifiers after the function is terminated so that + the token is parsed in the englobing function. It could be done + by just using next_token() here for normal functions, but it is + necessary for arrow functions with an expression body. */ + reparse_ident_token(s); + /* create the function object */ { int idx; @@ -33487,9 +34176,9 @@ static __exception int js_parse_program(JSParseState *s) emit_op(s, OP_get_loc); emit_u16(s, fd->eval_ret_idx); - emit_op(s, OP_return); + emit_return(s, TRUE); } else { - emit_op(s, OP_return_undef); + emit_return(s, FALSE); } return 0; @@ -33532,7 +34221,6 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj, ret_val = js_evaluate_module(ctx, m); if (JS_IsException(ret_val)) { fail: - js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED); return JS_EXCEPTION; } } else { @@ -33547,31 +34235,6 @@ JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj) return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL); } -static void skip_shebang(JSParseState *s) -{ - const uint8_t *p = s->buf_ptr; - int c; - - if (p[0] == '#' && p[1] == '!') { - p += 2; - while (p < s->buf_end) { - if (*p == '\n' || *p == '\r') { - break; - } else if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if (c == CP_LS || c == CP_PS) { - break; - } else if (c == -1) { - p++; /* skip invalid UTF-8 */ - } - } else { - p++; - } - } - s->buf_ptr = p; - } -} - /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, const char *input, size_t input_len, @@ -33587,7 +34250,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, JSModuleDef *m; js_parse_init(ctx, s, input, input_len, filename); - skip_shebang(s); + skip_shebang(&s->buf_ptr, s->buf_end); eval_type = flags & JS_EVAL_TYPE_MASK; m = NULL; @@ -33645,6 +34308,10 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, goto fail; } fd->module = m; + if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) { + fd->in_function_body = TRUE; + fd->func_kind = JS_FUNC_ASYNC; + } s->is_module = (m != NULL); s->allow_html_comments = !s->is_module; @@ -33659,6 +34326,9 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, goto fail1; } + if (m != NULL) + m->has_tla = fd->has_await; + /* create the function object and all the enclosed functions */ fun_obj = js_create_function(ctx, fd); if (JS_IsException(fun_obj)) @@ -33668,7 +34338,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, m->func_obj = fun_obj; if (js_resolve_module(ctx, m) < 0) goto fail1; - fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); + fun_obj = JS_NewModuleValue(ctx, m); } if (flags & JS_EVAL_FLAG_COMPILE_ONLY) { ret_val = fun_obj; @@ -34151,7 +34821,6 @@ static void JS_WriteString(BCWriterState *s, JSString *p) } } -#ifdef CONFIG_BIGNUM static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) { uint32_t tag, tag1; @@ -34166,12 +34835,14 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) case JS_TAG_BIG_INT: tag1 = BC_TAG_BIG_INT; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: tag1 = BC_TAG_BIG_FLOAT; break; case JS_TAG_BIG_DECIMAL: tag1 = BC_TAG_BIG_DECIMAL; break; +#endif default: abort(); } @@ -34286,7 +34957,6 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) } return 0; } -#endif /* CONFIG_BIGNUM */ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj); @@ -34309,6 +34979,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_set_flags(&flags, &idx, b->arguments_allowed, 1); bc_set_flags(&flags, &idx, b->has_debug, 1); bc_set_flags(&flags, &idx, b->backtrace_barrier, 1); + bc_set_flags(&flags, &idx, b->is_direct_or_indirect_eval, 1); assert(idx <= 16); bc_put_u16(s, flags); bc_put_u8(s, b->js_mode); @@ -34414,6 +35085,8 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj) bc_put_atom(s, mi->import_name); bc_put_leb128(s, mi->req_module_idx); } + + bc_put_u8(s, m->has_tla); if (JS_WriteObjectRec(s, m->func_obj)) goto fail; @@ -34643,8 +35316,8 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) case JS_CLASS_NUMBER: case JS_CLASS_STRING: case JS_CLASS_BOOLEAN: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif @@ -34666,14 +35339,14 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) goto fail; } break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: case JS_TAG_BIG_DECIMAL: +#endif if (JS_WriteBigNum(s, obj)) goto fail; break; -#endif default: invalid_tag: JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag); @@ -35065,7 +35738,6 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b, return 0; } -#ifdef CONFIG_BIGNUM static JSValue JS_ReadBigNum(BCReaderState *s, int tag) { JSValue obj = JS_UNDEFINED; @@ -35085,12 +35757,14 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) case BC_TAG_BIG_INT: obj = JS_MKPTR(JS_TAG_BIG_INT, p); break; +#ifdef CONFIG_BIGNUM case BC_TAG_BIG_FLOAT: obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p); break; case BC_TAG_BIG_DECIMAL: obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p); break; +#endif default: abort(); } @@ -35197,7 +35871,6 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) JS_FreeValue(s->ctx, obj); return JS_EXCEPTION; } -#endif /* CONFIG_BIGNUM */ static JSValue JS_ReadObjectRec(BCReaderState *s); @@ -35247,6 +35920,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) bc.arguments_allowed = bc_get_flags(v16, &idx, 1); bc.has_debug = bc_get_flags(v16, &idx, 1); bc.backtrace_barrier = bc_get_flags(v16, &idx, 1); + bc.is_direct_or_indirect_eval = bc_get_flags(v16, &idx, 1); bc.read_only_bytecode = s->is_rom_data; if (bc_get_u8(s, &v8)) goto fail; @@ -35425,7 +36099,7 @@ static JSValue JS_ReadModule(BCReaderState *s) m = js_new_module_def(ctx, module_name); if (!m) goto fail; - obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); + obj = JS_NewModuleValue(ctx, m); if (bc_get_leb128_int(s, &m->req_module_entries_count)) goto fail; if (m->req_module_entries_count != 0) { @@ -35498,6 +36172,10 @@ static JSValue JS_ReadModule(BCReaderState *s) } } + if (bc_get_u8(s, &v8)) + goto fail; + m->has_tla = (v8 != 0); + m->func_obj = JS_ReadObjectRec(s); if (JS_IsException(m->func_obj)) goto fail; @@ -35822,13 +36500,13 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) case BC_TAG_OBJECT_VALUE: obj = JS_ReadObjectValue(s); break; -#ifdef CONFIG_BIGNUM case BC_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case BC_TAG_BIG_FLOAT: case BC_TAG_BIG_DECIMAL: +#endif obj = JS_ReadBigNum(s, tag); break; -#endif case BC_TAG_OBJECT_REFERENCE: { uint32_t val; @@ -36260,10 +36938,10 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val) case JS_TAG_OBJECT: case JS_TAG_EXCEPTION: return JS_DupValue(ctx, val); -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT); goto set_value; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT); goto set_value; @@ -36882,6 +37560,32 @@ static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val, return JS_NewBool(ctx, ret); } +static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue obj; + JSAtom atom; + JSObject *p; + BOOL ret; + + obj = JS_ToObject(ctx, argv[0]); + if (JS_IsException(obj)) + return obj; + atom = JS_ValueToAtom(ctx, argv[1]); + if (unlikely(atom == JS_ATOM_NULL)) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + p = JS_VALUE_GET_OBJ(obj); + ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom); + JS_FreeAtom(ctx, atom); + JS_FreeValue(ctx, obj); + if (ret < 0) + return JS_EXCEPTION; + else + return JS_NewBool(ctx, ret); +} + static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -37429,6 +38133,7 @@ static const JSCFunctionListEntry js_object_funcs[] = { JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ), JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ), JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ), + JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 0 ), JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ), JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ), JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ), @@ -37454,6 +38159,7 @@ static const JSCFunctionListEntry js_object_funcs[] = { //JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ), //JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ), JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ), + JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ), }; static const JSCFunctionListEntry js_object_proto_funcs[] = { @@ -37858,7 +38564,8 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic) { JSValue obj, msg, proto; - JSValueConst message; + JSValueConst message, options; + int arg_index; if (JS_IsUndefined(new_target)) new_target = JS_GetActiveFunction(ctx); @@ -37884,12 +38591,9 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, JS_FreeValue(ctx, proto); if (JS_IsException(obj)) return obj; - if (magic == JS_AGGREGATE_ERROR) { - message = argv[1]; - } else { - message = argv[0]; - } + arg_index = (magic == JS_AGGREGATE_ERROR); + message = argv[arg_index++]; if (!JS_IsUndefined(message)) { msg = JS_ToString(ctx, message); if (unlikely(JS_IsException(msg))) @@ -37898,6 +38602,22 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); } + if (arg_index < argc) { + options = argv[arg_index]; + if (JS_IsObject(options)) { + int present = JS_HasProperty(ctx, options, JS_ATOM_cause); + if (present < 0) + goto exception; + if (present) { + JSValue cause = JS_GetProperty(ctx, options, JS_ATOM_cause); + if (JS_IsException(cause)) + goto exception; + JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + } + } + } + if (magic == JS_AGGREGATE_ERROR) { JSValue error_list = iterator_to_array(ctx, argv[0]); if (JS_IsException(error_list)) @@ -37973,12 +38693,20 @@ static int JS_CopySubArray(JSContext *ctx, JSValueConst obj, int64_t to_pos, int64_t from_pos, int64_t count, int dir) { - int64_t i, from, to; + JSObject *p; + int64_t i, from, to, len; JSValue val; int fromPresent; - /* XXX: should special case fast arrays */ - for (i = 0; i < count; i++) { + p = NULL; + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { + p = JS_VALUE_GET_OBJ(obj); + if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) { + p = NULL; + } + } + + for (i = 0; i < count; ) { if (dir < 0) { from = from_pos + count - i - 1; to = to_pos + count - i - 1; @@ -37986,16 +38714,43 @@ static int JS_CopySubArray(JSContext *ctx, from = from_pos + i; to = to_pos + i; } - fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val); - if (fromPresent < 0) - goto exception; - - if (fromPresent) { - if (JS_SetPropertyInt64(ctx, obj, to, val) < 0) - goto exception; + if (p && p->fast_array && + from >= 0 && from < (len = p->u.array.count) && + to >= 0 && to < len) { + int64_t l, j; + /* Fast path for fast arrays. Since we don't look at the + prototype chain, we can optimize only the cases where + all the elements are present in the array. */ + l = count - i; + if (dir < 0) { + l = min_int64(l, from + 1); + l = min_int64(l, to + 1); + for(j = 0; j < l; j++) { + set_value(ctx, &p->u.array.u.values[to - j], + JS_DupValue(ctx, p->u.array.u.values[from - j])); + } + } else { + l = min_int64(l, len - from); + l = min_int64(l, len - to); + for(j = 0; j < l; j++) { + set_value(ctx, &p->u.array.u.values[to + j], + JS_DupValue(ctx, p->u.array.u.values[from + j])); + } + } + i += l; } else { - if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0) + fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val); + if (fromPresent < 0) goto exception; + + if (fromPresent) { + if (JS_SetPropertyInt64(ctx, obj, to, val) < 0) + goto exception; + } else { + if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0) + goto exception; + } + i++; } } return 0; @@ -38256,6 +39011,106 @@ static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj) return JS_IsArray(ctx, obj); } +static JSValue js_array_at(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue obj, ret; + int64_t len, idx; + JSValue *arrp; + uint32_t count; + + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + if (JS_ToInt64Sat(ctx, &idx, argv[0])) + goto exception; + + if (idx < 0) + idx = len + idx; + if (idx < 0 || idx >= len) { + ret = JS_UNDEFINED; + } else if (js_get_fast_array(ctx, obj, &arrp, &count) && idx < count) { + ret = JS_DupValue(ctx, arrp[idx]); + } else { + int present = JS_TryGetPropertyInt64(ctx, obj, idx, &ret); + if (present < 0) + goto exception; + if (!present) + ret = JS_UNDEFINED; + } + JS_FreeValue(ctx, obj); + return ret; + exception: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_array_with(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, obj, ret, *arrp, *pval; + JSObject *p; + int64_t i, len, idx; + uint32_t count32; + + ret = JS_EXCEPTION; + arr = JS_UNDEFINED; + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + if (JS_ToInt64Sat(ctx, &idx, argv[0])) + goto exception; + + if (idx < 0) + idx = len + idx; + + if (idx < 0 || idx >= len) { + JS_ThrowRangeError(ctx, "out of bound"); + goto exception; + } + + arr = js_allocate_fast_array(ctx, len); + if (JS_IsException(arr)) + goto exception; + + p = JS_VALUE_GET_OBJ(arr); + i = 0; + pval = p->u.array.u.values; + if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { + for (; i < idx; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + *pval = JS_DupValue(ctx, argv[1]); + for (i++, pval++; i < len; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + } else { + for (; i < idx; i++, pval++) + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) + goto fill_and_fail; + *pval = JS_DupValue(ctx, argv[1]); + for (i++, pval++; i < len; i++, pval++) { + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) { + fill_and_fail: + for (; i < len; i++, pval++) + *pval = JS_UNDEFINED; + goto exception; + } + } + } + + if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0) + goto exception; + + ret = arr; + arr = JS_UNDEFINED; + +exception: + JS_FreeValue(ctx, arr); + JS_FreeValue(ctx, obj); + return ret; +} + static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -38754,13 +39609,21 @@ static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +enum { + special_find, + special_findIndex, + special_findLast, + special_findLastIndex, +}; + static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int findIndex) + int argc, JSValueConst *argv, int mode) { JSValueConst func, this_arg; JSValueConst args[3]; JSValue obj, val, index_val, res; - int64_t len, k; + int64_t len, k, end; + int dir; index_val = JS_UNDEFINED; val = JS_UNDEFINED; @@ -38776,7 +39639,18 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, if (argc > 1) this_arg = argv[1]; - for(k = 0; k < len; k++) { + if (mode == special_findLast || mode == special_findLastIndex) { + k = len - 1; + dir = -1; + end = -1; + } else { + k = 0; + dir = 1; + end = len; + } + + // TODO(bnoordhuis) add fast path for fast arrays + for(; k != end; k += dir) { index_val = JS_NewInt64(ctx, k); if (JS_IsException(index_val)) goto exception; @@ -38790,7 +39664,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, if (JS_IsException(res)) goto exception; if (JS_ToBoolFree(ctx, res)) { - if (findIndex) { + if (mode == special_findIndex || mode == special_findLastIndex) { JS_FreeValue(ctx, val); JS_FreeValue(ctx, obj); return index_val; @@ -38804,7 +39678,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, index_val); } JS_FreeValue(ctx, obj); - if (findIndex) + if (mode == special_findIndex || mode == special_findLastIndex) return JS_NewInt32(ctx, -1); else return JS_UNDEFINED; @@ -38957,64 +39831,27 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val, int64_t len, from, newLen; obj = JS_ToObject(ctx, this_val); - - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - JSObject *p = JS_VALUE_GET_OBJ(obj); - if (p->class_id != JS_CLASS_ARRAY || - !p->fast_array || !p->extensible) - goto generic_case; - /* length must be writable */ - if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) - goto generic_case; - /* check the length */ - if (unlikely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT)) - goto generic_case; - len = JS_VALUE_GET_INT(p->prop[0].u.value); - /* we don't support holes */ - if (unlikely(len != p->u.array.count)) - goto generic_case; - newLen = len + argc; - if (unlikely(newLen > INT32_MAX)) - goto generic_case; - if (newLen > p->u.array.u1.size) { - if (expand_fast_array(ctx, p, newLen)) - goto exception; - } - if (unshift && argc > 0) { - memmove(p->u.array.u.values + argc, p->u.array.u.values, - len * sizeof(p->u.array.u.values[0])); - from = 0; - } else { - from = len; - } - for(i = 0; i < argc; i++) { - p->u.array.u.values[from + i] = JS_DupValue(ctx, argv[i]); - } - p->u.array.count = newLen; - p->prop[0].u.value = JS_NewInt32(ctx, newLen); - } else { - generic_case: - if (js_get_length64(ctx, &len, obj)) - goto exception; - newLen = len + argc; - if (newLen > MAX_SAFE_INTEGER) { - JS_ThrowTypeError(ctx, "Array loo long"); + if (js_get_length64(ctx, &len, obj)) + goto exception; + newLen = len + argc; + if (newLen > MAX_SAFE_INTEGER) { + JS_ThrowTypeError(ctx, "Array loo long"); + goto exception; + } + from = len; + if (unshift && argc > 0) { + if (JS_CopySubArray(ctx, obj, argc, 0, len, -1)) goto exception; - } - from = len; - if (unshift && argc > 0) { - if (JS_CopySubArray(ctx, obj, argc, 0, len, -1)) - goto exception; - from = 0; - } - for(i = 0; i < argc; i++) { - if (JS_SetPropertyInt64(ctx, obj, from + i, - JS_DupValue(ctx, argv[i])) < 0) - goto exception; - } - if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0) + from = 0; + } + for(i = 0; i < argc; i++) { + if (JS_SetPropertyInt64(ctx, obj, from + i, + JS_DupValue(ctx, argv[i])) < 0) goto exception; } + if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0) + goto exception; + JS_FreeValue(ctx, obj); return JS_NewInt64(ctx, newLen); @@ -39092,6 +39929,61 @@ static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +// Note: a.toReversed() is a.slice().reverse() with the twist that a.slice() +// leaves holes in sparse arrays intact whereas a.toReversed() replaces them +// with undefined, thus in effect creating a dense array. +// Does not use Array[@@species], always returns a base Array. +static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, obj, ret, *arrp, *pval; + JSObject *p; + int64_t i, len; + uint32_t count32; + + ret = JS_EXCEPTION; + arr = JS_UNDEFINED; + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + arr = js_allocate_fast_array(ctx, len); + if (JS_IsException(arr)) + goto exception; + + if (len > 0) { + p = JS_VALUE_GET_OBJ(arr); + + i = len - 1; + pval = p->u.array.u.values; + if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { + for (; i >= 0; i--, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + } else { + // Query order is observable; test262 expects descending order. + for (; i >= 0; i--, pval++) { + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) { + // Exception; initialize remaining elements. + for (; i >= 0; i--, pval++) + *pval = JS_UNDEFINED; + goto exception; + } + } + } + + if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0) + goto exception; + } + + ret = arr; + arr = JS_UNDEFINED; + +exception: + JS_FreeValue(ctx, arr); + JS_FreeValue(ctx, obj); + return ret; +} + static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int splice) { @@ -39199,6 +40091,92 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, obj, ret, *arrp, *pval, *last; + JSObject *p; + int64_t i, j, len, newlen, start, add, del; + uint32_t count32; + + pval = NULL; + last = NULL; + ret = JS_EXCEPTION; + arr = JS_UNDEFINED; + + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + start = 0; + if (argc > 0) + if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len)) + goto exception; + + del = 0; + if (argc > 0) + del = len - start; + if (argc > 1) + if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0)) + goto exception; + + add = 0; + if (argc > 2) + add = argc - 2; + + newlen = len + add - del; + if (newlen > MAX_SAFE_INTEGER) { + JS_ThrowTypeError(ctx, "invalid array length"); + goto exception; + } + + arr = js_allocate_fast_array(ctx, newlen); + if (JS_IsException(arr)) + goto exception; + + if (newlen <= 0) + goto done; + + p = JS_VALUE_GET_OBJ(arr); + pval = &p->u.array.u.values[0]; + last = &p->u.array.u.values[newlen]; + + if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { + for (i = 0; i < start; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + for (j = 0; j < add; j++, pval++) + *pval = JS_DupValue(ctx, argv[2 + j]); + for (i += del; i < len; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + } else { + for (i = 0; i < start; i++, pval++) + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) + goto exception; + for (j = 0; j < add; j++, pval++) + *pval = JS_DupValue(ctx, argv[2 + j]); + for (i += del; i < len; i++, pval++) + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) + goto exception; + } + + assert(pval == last); + + if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, newlen)) < 0) + goto exception; + +done: + ret = arr; + arr = JS_UNDEFINED; + +exception: + while (pval != last) + *pval++ = JS_UNDEFINED; + + JS_FreeValue(ctx, arr); + JS_FreeValue(ctx, obj); + return ret; +} + static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -39502,6 +40480,68 @@ static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +// Note: a.toSorted() is a.slice().sort() with the twist that a.slice() +// leaves holes in sparse arrays intact whereas a.toSorted() replaces them +// with undefined, thus in effect creating a dense array. +// Does not use Array[@@species], always returns a base Array. +static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, obj, ret, *arrp, *pval; + JSObject *p; + int64_t i, len; + uint32_t count32; + int ok; + + ok = JS_IsUndefined(argv[0]) || JS_IsFunction(ctx, argv[0]); + if (!ok) + return JS_ThrowTypeError(ctx, "not a function"); + + ret = JS_EXCEPTION; + arr = JS_UNDEFINED; + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + arr = js_allocate_fast_array(ctx, len); + if (JS_IsException(arr)) + goto exception; + + if (len > 0) { + p = JS_VALUE_GET_OBJ(arr); + i = 0; + pval = p->u.array.u.values; + if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { + for (; i < len; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + } else { + for (; i < len; i++, pval++) { + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) { + for (; i < len; i++, pval++) + *pval = JS_UNDEFINED; + goto exception; + } + } + } + + if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0) + goto exception; + } + + ret = js_array_sort(ctx, arr, argc, argv); + if (JS_IsException(ret)) + goto exception; + JS_FreeValue(ctx, ret); + + ret = arr; + arr = JS_UNDEFINED; + +exception: + JS_FreeValue(ctx, arr); + JS_FreeValue(ctx, obj); + return ret; +} + typedef struct JSArrayIteratorData { JSValue obj; JSIteratorKindEnum kind; @@ -39654,6 +40694,8 @@ static const JSCFunctionListEntry js_iterator_proto_funcs[] = { }; static const JSCFunctionListEntry js_array_proto_funcs[] = { + JS_CFUNC_DEF("at", 1, js_array_at ), + JS_CFUNC_DEF("with", 2, js_array_with ), JS_CFUNC_DEF("concat", 1, js_array_concat ), JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ), JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ), @@ -39663,8 +40705,10 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ), JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ), JS_CFUNC_DEF("fill", 1, js_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, 0 ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, 1 ), + JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, special_find ), + JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, special_findIndex ), + JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, special_findLast ), + JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, special_findLastIndex ), JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ), JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ), JS_CFUNC_DEF("includes", 1, js_array_includes ), @@ -39676,9 +40720,12 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ), JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ), JS_CFUNC_DEF("reverse", 0, js_array_reverse ), + JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ), JS_CFUNC_DEF("sort", 1, js_array_sort ), + JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ), JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ), JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ), + JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ), JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ), JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ), JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ), @@ -39706,9 +40753,10 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, if (JS_IsException(val)) return val; switch(JS_VALUE_GET_TAG(val)) { -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); double d; @@ -39717,6 +40765,7 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, val = __JS_NewFloat64(ctx, d); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: val = JS_ToStringFree(ctx, val); if (JS_IsException(val)) @@ -40351,7 +41400,7 @@ static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val, } static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) + int argc, JSValueConst *argv, int is_at) { JSValue val, ret; JSString *p; @@ -40365,8 +41414,13 @@ static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, val); return JS_EXCEPTION; } + if (idx < 0 && is_at) + idx += p->len; if (idx < 0 || idx >= p->len) { - ret = js_new_string8(ctx, NULL, 0); + if (is_at) + ret = JS_UNDEFINED; + else + ret = js_new_string8(ctx, NULL, 0); } else { if (p->is_wide_char) c = p->u.str16[idx]; @@ -40479,6 +41533,84 @@ static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode) return index; } +/* return the position of the first invalid character in the string or + -1 if none */ +static int js_string_find_invalid_codepoint(JSString *p) +{ + int i, c; + if (!p->is_wide_char) + return -1; + for(i = 0; i < p->len; i++) { + c = p->u.str16[i]; + if (c >= 0xD800 && c <= 0xDFFF) { + if (c >= 0xDC00 || (i + 1) >= p->len) + return i; + c = p->u.str16[i + 1]; + if (c < 0xDC00 || c > 0xDFFF) + return i; + i++; + } + } + return -1; +} + +static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue str; + JSString *p; + BOOL ret; + + str = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(str)) + return JS_EXCEPTION; + p = JS_VALUE_GET_STRING(str); + ret = (js_string_find_invalid_codepoint(p) < 0); + JS_FreeValue(ctx, str); + return JS_NewBool(ctx, ret); +} + +static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue str, ret; + JSString *p; + int c, i; + + str = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(str)) + return JS_EXCEPTION; + + p = JS_VALUE_GET_STRING(str); + /* avoid reallocating the string if it is well-formed */ + i = js_string_find_invalid_codepoint(p); + if (i < 0) + return str; + + ret = js_new_string16(ctx, p->u.str16, p->len); + JS_FreeValue(ctx, str); + if (JS_IsException(ret)) + return JS_EXCEPTION; + + p = JS_VALUE_GET_STRING(ret); + for (; i < p->len; i++) { + c = p->u.str16[i]; + if (c >= 0xD800 && c <= 0xDFFF) { + if (c >= 0xDC00 || (i + 1) >= p->len) { + p->u.str16[i] = 0xFFFD; + } else { + c = p->u.str16[i + 1]; + if (c < 0xDC00 || c > 0xDFFF) { + p->u.str16[i] = 0xFFFD; + } else { + i++; + } + } + } + } + return ret; +} + static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int lastIndexOf) { @@ -41291,26 +42423,6 @@ static BOOL test_final_sigma(JSString *p, int sigma_pos) return !lre_is_cased(c1); } -static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue a, b; - int cmp; - - a = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(a)) - return JS_EXCEPTION; - b = JS_ToString(ctx, argv[0]); - if (JS_IsException(b)) { - JS_FreeValue(ctx, a); - return JS_EXCEPTION; - } - cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b)); - JS_FreeValue(ctx, a); - JS_FreeValue(ctx, b); - return JS_NewInt32(ctx, cmp); -} - static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int to_lower) { @@ -41396,23 +42508,38 @@ static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len) return JS_EXCEPTION; } +static int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf, + JSValueConst val, + UnicodeNormalizationEnum n_type) +{ + int buf_len, out_len; + uint32_t *buf, *out_buf; + + buf_len = JS_ToUTF32String(ctx, &buf, val); + if (buf_len < 0) + return -1; + out_len = unicode_normalize(&out_buf, buf, buf_len, n_type, + ctx->rt, (DynBufReallocFunc *)js_realloc_rt); + js_free(ctx, buf); + if (out_len < 0) + return -1; + *pout_buf = out_buf; + return out_len; +} + static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { const char *form, *p; size_t form_len; - int is_compat, buf_len, out_len; + int is_compat, out_len; UnicodeNormalizationEnum n_type; JSValue val; - uint32_t *buf, *out_buf; + uint32_t *out_buf; val = JS_ToStringCheckObject(ctx, this_val); if (JS_IsException(val)) return val; - buf_len = JS_ToUTF32String(ctx, &buf, val); - JS_FreeValue(ctx, val); - if (buf_len < 0) - return JS_EXCEPTION; if (argc == 0 || JS_IsUndefined(argv[0])) { n_type = UNICODE_NFC; @@ -41438,22 +42565,96 @@ static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val, JS_FreeCString(ctx, form); JS_ThrowRangeError(ctx, "bad normalization form"); fail1: - js_free(ctx, buf); + JS_FreeValue(ctx, val); return JS_EXCEPTION; } JS_FreeCString(ctx, form); } - out_len = unicode_normalize(&out_buf, buf, buf_len, n_type, - ctx->rt, (DynBufReallocFunc *)js_realloc_rt); - js_free(ctx, buf); + out_len = js_string_normalize1(ctx, &out_buf, val, n_type); + JS_FreeValue(ctx, val); if (out_len < 0) return JS_EXCEPTION; val = JS_NewUTF32String(ctx, out_buf, out_len); js_free(ctx, out_buf); return val; } -#endif /* CONFIG_ALL_UNICODE */ + +/* return < 0, 0 or > 0 */ +static int js_UTF32_compare(const uint32_t *buf1, int buf1_len, + const uint32_t *buf2, int buf2_len) +{ + int i, len, c, res; + len = min_int(buf1_len, buf2_len); + for(i = 0; i < len; i++) { + /* Note: range is limited so a subtraction is valid */ + c = buf1[i] - buf2[i]; + if (c != 0) + return c; + } + if (buf1_len == buf2_len) + res = 0; + else if (buf1_len < buf2_len) + res = -1; + else + res = 1; + return res; +} + +static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue a, b; + int cmp, a_len, b_len; + uint32_t *a_buf, *b_buf; + + a = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(a)) + return JS_EXCEPTION; + b = JS_ToString(ctx, argv[0]); + if (JS_IsException(b)) { + JS_FreeValue(ctx, a); + return JS_EXCEPTION; + } + a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFC); + JS_FreeValue(ctx, a); + if (a_len < 0) { + JS_FreeValue(ctx, b); + return JS_EXCEPTION; + } + + b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFC); + JS_FreeValue(ctx, b); + if (b_len < 0) { + js_free(ctx, a_buf); + return JS_EXCEPTION; + } + cmp = js_UTF32_compare(a_buf, a_len, b_buf, b_len); + js_free(ctx, a_buf); + js_free(ctx, b_buf); + return JS_NewInt32(ctx, cmp); +} +#else /* CONFIG_ALL_UNICODE */ +static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue a, b; + int cmp; + + a = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(a)) + return JS_EXCEPTION; + b = JS_ToString(ctx, argv[0]); + if (JS_IsException(b)) { + JS_FreeValue(ctx, a); + return JS_EXCEPTION; + } + cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b)); + JS_FreeValue(ctx, a); + JS_FreeValue(ctx, b); + return JS_NewInt32(ctx, cmp); +} +#endif /* !CONFIG_ALL_UNICODE */ /* also used for String.prototype.valueOf */ static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val, @@ -41625,10 +42826,13 @@ static const JSCFunctionListEntry js_string_funcs[] = { static const JSCFunctionListEntry js_string_proto_funcs[] = { JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ), + JS_CFUNC_MAGIC_DEF("at", 1, js_string_charAt, 1 ), JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ), - JS_CFUNC_DEF("charAt", 1, js_string_charAt ), + JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, 0 ), JS_CFUNC_DEF("concat", 1, js_string_concat ), JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ), + JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ), + JS_CFUNC_DEF("toWellFormed", 0, js_string_toWellFormed ), JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ), JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ), JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ), @@ -41961,40 +43165,13 @@ static const JSCFunctionListEntry js_math_obj[] = { /* Date */ -#if 0 -/* OS dependent: return the UTC time in ms since 1970. */ -static JSValue js___date_now(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int64_t d; - struct timeval tv; - gettimeofday(&tv, NULL); - d = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); - return JS_NewInt64(ctx, d); -} -#endif - -/* OS dependent: return the UTC time in microseconds since 1970. */ -static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int64_t d; - struct timeval tv; - gettimeofday(&tv, NULL); - d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; - return JS_NewInt64(ctx, d); -} - /* OS dependent. d = argv[0] is in ms from 1970. Return the difference between UTC time and local time 'd' in minutes */ -static int getTimezoneOffset(int64_t time) { -#if defined(_WIN32) - /* XXX: TODO */ - return 0; -#else +static int getTimezoneOffset(int64_t time) +{ time_t ti; - struct tm tm; - + int res; + time /= 1000; /* convert to seconds */ if (sizeof(time_t) == 4) { /* on 32-bit systems, we need to clamp the time value to the @@ -42017,9 +43194,27 @@ static int getTimezoneOffset(int64_t time) { } } ti = time; - localtime_r(&ti, &tm); - return -tm.tm_gmtoff / 60; +#if defined(_WIN32) + { + struct tm *tm; + time_t gm_ti, loc_ti; + + tm = gmtime(&ti); + gm_ti = mktime(tm); + + tm = localtime(&ti); + loc_ti = mktime(tm); + + res = (gm_ti - loc_ti) / 60; + } +#else + { + struct tm tm; + localtime_r(&ti, &tm); + res = -tm.tm_gmtoff / 60; + } #endif + return res; } #if 0 @@ -42096,6 +43291,9 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */ for (i = 0; i < len; i++) { switch(str[i]) { + case 'd': + mask = LRE_FLAG_INDICES; + break; case 'g': mask = LRE_FLAG_GLOBAL; break; @@ -42439,6 +43637,11 @@ static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val) if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) return JS_ThrowTypeErrorNotAnObject(ctx); + res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "hasIndices")); + if (res < 0) + goto exception; + if (res) + *p++ = 'd'; res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global)); if (res < 0) goto exception; @@ -42518,25 +43721,32 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, { JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); JSString *str; - JSValue str_val, obj, val, groups = JS_UNDEFINED; + JSValue t, ret, str_val, obj, val, groups; + JSValue indices, indices_groups; uint8_t *re_bytecode; - int ret; uint8_t **capture, *str_buf; - int capture_count, shift, i, re_flags; + int rc, capture_count, shift, i, re_flags; int64_t last_index; const char *group_name_ptr; if (!re) return JS_EXCEPTION; + str_val = JS_ToString(ctx, argv[0]); if (JS_IsException(str_val)) - return str_val; - val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex); - if (JS_IsException(val) || - JS_ToLengthFree(ctx, &last_index, val)) { - JS_FreeValue(ctx, str_val); return JS_EXCEPTION; - } + + ret = JS_EXCEPTION; + obj = JS_NULL; + groups = JS_UNDEFINED; + indices = JS_UNDEFINED; + indices_groups = JS_UNDEFINED; + capture = NULL; + + val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex); + if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val)) + goto fail; + re_bytecode = re->bytecode->u.str8; re_flags = lre_get_flags(re_bytecode); if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) { @@ -42544,27 +43754,23 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, } str = JS_VALUE_GET_STRING(str_val); capture_count = lre_get_capture_count(re_bytecode); - capture = NULL; if (capture_count > 0) { capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2); - if (!capture) { - JS_FreeValue(ctx, str_val); - return JS_EXCEPTION; - } + if (!capture) + goto fail; } shift = str->is_wide_char; str_buf = str->u.str8; if (last_index > str->len) { - ret = 2; + rc = 2; } else { - ret = lre_exec(capture, re_bytecode, - str_buf, last_index, str->len, - shift, ctx); + rc = lre_exec(capture, re_bytecode, + str_buf, last_index, str->len, + shift, ctx); } - obj = JS_NULL; - if (ret != 1) { - if (ret >= 0) { - if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) { + if (rc != 1) { + if (rc >= 0) { + if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) { if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) goto fail; @@ -42573,7 +43779,6 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, JS_ThrowInternalError(ctx, "out of memory in regexp execution"); goto fail; } - JS_FreeValue(ctx, str_val); } else { int prop_flags; if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) { @@ -42591,52 +43796,124 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, if (JS_IsException(groups)) goto fail; } + if (re_flags & LRE_FLAG_INDICES) { + indices = JS_NewArray(ctx); + if (JS_IsException(indices)) + goto fail; + if (group_name_ptr) { + indices_groups = JS_NewObjectProto(ctx, JS_NULL); + if (JS_IsException(indices_groups)) + goto fail; + } + } for(i = 0; i < capture_count; i++) { - int start, end; + const char *name = NULL; + uint8_t **match = &capture[2 * i]; + int start = -1; + int end = -1; JSValue val; - if (capture[2 * i] == NULL || - capture[2 * i + 1] == NULL) { + + if (group_name_ptr && i > 0) { + if (*group_name_ptr) name = group_name_ptr; + group_name_ptr += strlen(group_name_ptr) + 1; + } + + if (match[0] && match[1]) { + start = (match[0] - str_buf) >> shift; + end = (match[1] - str_buf) >> shift; + } + + if (!JS_IsUndefined(indices)) { val = JS_UNDEFINED; - } else { - start = (capture[2 * i] - str_buf) >> shift; - end = (capture[2 * i + 1] - str_buf) >> shift; + if (start != -1) { + val = JS_NewArray(ctx); + if (JS_IsException(val)) + goto fail; + if (JS_DefinePropertyValueUint32(ctx, val, 0, + JS_NewInt32(ctx, start), + prop_flags) < 0) { + JS_FreeValue(ctx, val); + goto fail; + } + if (JS_DefinePropertyValueUint32(ctx, val, 1, + JS_NewInt32(ctx, end), + prop_flags) < 0) { + JS_FreeValue(ctx, val); + goto fail; + } + } + if (name && !JS_IsUndefined(indices_groups)) { + val = JS_DupValue(ctx, val); + if (JS_DefinePropertyValueStr(ctx, indices_groups, + name, val, prop_flags) < 0) { + JS_FreeValue(ctx, val); + goto fail; + } + } + if (JS_DefinePropertyValueUint32(ctx, indices, i, val, + prop_flags) < 0) { + goto fail; + } + } + + val = JS_UNDEFINED; + if (start != -1) { val = js_sub_string(ctx, str, start, end); if (JS_IsException(val)) goto fail; } - if (group_name_ptr && i > 0) { - if (*group_name_ptr) { - if (JS_DefinePropertyValueStr(ctx, groups, group_name_ptr, - JS_DupValue(ctx, val), - prop_flags) < 0) { - JS_FreeValue(ctx, val); - goto fail; - } + + if (name) { + if (JS_DefinePropertyValueStr(ctx, groups, name, + JS_DupValue(ctx, val), + prop_flags) < 0) { + JS_FreeValue(ctx, val); + goto fail; } - group_name_ptr += strlen(group_name_ptr) + 1; } + if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0) goto fail; } + + t = groups, groups = JS_UNDEFINED; if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups, - groups, prop_flags) < 0) + t, prop_flags) < 0) { goto fail; - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, - JS_NewInt32(ctx, (capture[0] - str_buf) >> shift), prop_flags) < 0) + } + + t = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift); + if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, t, prop_flags) < 0) goto fail; - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, str_val, prop_flags) < 0) - goto fail1; + + t = str_val, str_val = JS_UNDEFINED; + if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, t, prop_flags) < 0) + goto fail; + + if (!JS_IsUndefined(indices)) { + t = indices_groups, indices_groups = JS_UNDEFINED; + if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups, + t, prop_flags) < 0) { + goto fail; + } + t = indices, indices = JS_UNDEFINED; + if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices, + t, prop_flags) < 0) { + goto fail; + } + } } - js_free(ctx, capture); - return obj; + ret = obj; + obj = JS_UNDEFINED; fail: - JS_FreeValue(ctx, groups); + JS_FreeValue(ctx, indices_groups); + JS_FreeValue(ctx, indices); JS_FreeValue(ctx, str_val); -fail1: + JS_FreeValue(ctx, groups); JS_FreeValue(ctx, obj); js_free(ctx, capture); - return JS_EXCEPTION; + return ret; } /* delete portions of a string that match a given regex */ @@ -42788,7 +44065,7 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, { // [Symbol.match](str) JSValueConst rx = this_val; - JSValue A, S, result, matchStr; + JSValue A, S, flags, result, matchStr; int global, n, fullUnicode, isEmpty; JSString *p; @@ -42796,16 +44073,23 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, return JS_ThrowTypeErrorNotAnObject(ctx); A = JS_UNDEFINED; + flags = JS_UNDEFINED; result = JS_UNDEFINED; matchStr = JS_UNDEFINED; S = JS_ToString(ctx, argv[0]); if (JS_IsException(S)) goto exception; - global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global)); - if (global < 0) + flags = JS_GetProperty(ctx, rx, JS_ATOM_flags); + if (JS_IsException(flags)) goto exception; + flags = JS_ToStringFree(ctx, flags); + if (JS_IsException(flags)) + goto exception; + p = JS_VALUE_GET_STRING(flags); + // TODO(bnoordhuis) query 'u' flag the same way? + global = (-1 != string_indexof_char(p, 'g', 0)); if (!global) { A = JS_RegExpExec(ctx, rx, S); } else { @@ -42849,12 +44133,14 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, } } JS_FreeValue(ctx, result); + JS_FreeValue(ctx, flags); JS_FreeValue(ctx, S); return A; exception: JS_FreeValue(ctx, A); JS_FreeValue(ctx, result); + JS_FreeValue(ctx, flags); JS_FreeValue(ctx, S); return JS_EXCEPTION; } @@ -43097,8 +44383,8 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, // [Symbol.replace](str, rep) JSValueConst rx = this_val, rep = argv[1]; JSValueConst args[6]; - JSValue str, rep_val, matched, tab, rep_str, namedCaptures, res; - JSString *sp, *rp; + JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res; + JSString *p, *sp, *rp; StringBuffer b_s, *b = &b_s; ValueBuffer v_b, *results = &v_b; int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode; @@ -43114,6 +44400,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, rep_val = JS_UNDEFINED; matched = JS_UNDEFINED; tab = JS_UNDEFINED; + flags = JS_UNDEFINED; rep_str = JS_UNDEFINED; namedCaptures = JS_UNDEFINED; @@ -43130,10 +44417,18 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, goto exception; rp = JS_VALUE_GET_STRING(rep_val); } - fullUnicode = 0; - is_global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global)); - if (is_global < 0) + + flags = JS_GetProperty(ctx, rx, JS_ATOM_flags); + if (JS_IsException(flags)) goto exception; + flags = JS_ToStringFree(ctx, flags); + if (JS_IsException(flags)) + goto exception; + p = JS_VALUE_GET_STRING(flags); + + // TODO(bnoordhuis) query 'u' flag the same way? + fullUnicode = 0; + is_global = (-1 != string_indexof_char(p, 'g', 0)); if (is_global) { fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode)); if (fullUnicode < 0) @@ -43267,6 +44562,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, value_buffer_free(results); JS_FreeValue(ctx, rep_val); JS_FreeValue(ctx, matched); + JS_FreeValue(ctx, flags); JS_FreeValue(ctx, tab); JS_FreeValue(ctx, rep_str); JS_FreeValue(ctx, namedCaptures); @@ -43467,12 +44763,13 @@ static const JSCFunctionListEntry js_regexp_funcs[] = { static const JSCFunctionListEntry js_regexp_proto_funcs[] = { JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ), JS_CGETSET_DEF("source", js_regexp_get_source, NULL ), - JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, 1 ), - JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, 2 ), - JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, 4 ), - JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, 8 ), - JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, 16 ), - JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, 32 ), + JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, LRE_FLAG_GLOBAL ), + JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, LRE_FLAG_IGNORECASE ), + JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ), + JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ), + JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, LRE_FLAG_UTF16 ), + JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ), + JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ), JS_CFUNC_DEF("exec", 1, js_regexp_exec ), JS_CFUNC_DEF("compile", 2, js_regexp_compile ), JS_CFUNC_DEF("test", 1, js_regexp_test ), @@ -43809,10 +45106,8 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, JSValue v; JSValueConst args[2]; - if (JS_IsObject(val) -#ifdef CONFIG_BIGNUM - || JS_IsBigInt(ctx, val) /* XXX: probably useless */ -#endif + if (JS_IsObject(val) || + JS_IsBigInt(ctx, val) /* XXX: probably useless */ ) { JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON); if (JS_IsException(f)) @@ -43850,9 +45145,7 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, #endif case JS_TAG_BOOL: case JS_TAG_NULL: -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: -#endif case JS_TAG_EXCEPTION: return val; default: @@ -43903,15 +45196,16 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, ret = string_buffer_concat_value(jsc->b, p->u.object_data); JS_FreeValue(ctx, val); return ret; - } + } else #ifdef CONFIG_BIGNUM - else if (cl == JS_CLASS_BIG_FLOAT) { + if (cl == JS_CLASS_BIG_FLOAT) { return string_buffer_concat_value_free(jsc->b, val); - } else if (cl == JS_CLASS_BIG_INT) { + } else +#endif + if (cl == JS_CLASS_BIG_INT) { JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify"); goto exception; } -#endif v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val); if (JS_IsException(v)) goto exception; @@ -44041,11 +45335,9 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, case JS_TAG_NULL: concat_value: return string_buffer_concat_value_free(jsc->b, val); -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify"); goto exception; -#endif default: JS_FreeValue(ctx, val); return 0; @@ -44335,8 +45627,8 @@ static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val, atom = JS_ValueToAtom(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION; - ret = JS_SetPropertyGeneric(ctx, obj, atom, - JS_DupValue(ctx, val), receiver, 0); + ret = JS_SetPropertyInternal(ctx, obj, atom, + JS_DupValue(ctx, val), receiver, 0); JS_FreeAtom(ctx, atom); if (ret < 0) return JS_EXCEPTION; @@ -44683,9 +45975,9 @@ static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom, if (!s) return -1; if (JS_IsUndefined(method)) { - return JS_SetPropertyGeneric(ctx, s->target, atom, - JS_DupValue(ctx, value), receiver, - flags); + return JS_SetPropertyInternal(ctx, s->target, atom, + JS_DupValue(ctx, value), receiver, + flags); } atom_val = JS_AtomToValue(ctx, atom); if (JS_IsException(atom_val)) { @@ -45218,6 +46510,10 @@ static int js_proxy_isArray(JSContext *ctx, JSValueConst obj) JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY); if (!s) return FALSE; + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; + } if (s->is_revoked) { JS_ThrowTypeErrorRevokedProxy(ctx); return -1; @@ -45943,6 +47239,123 @@ static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val, return JS_UNDEFINED; } +static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int is_map) +{ + JSValueConst cb, args[2]; + JSValue res, iter, next, groups, key, v, prop; + JSAtom key_atom = JS_ATOM_NULL; + int64_t idx; + BOOL done; + + // "is function?" check must be observed before argv[0] is accessed + cb = argv[1]; + if (check_function(ctx, cb)) + return JS_EXCEPTION; + + iter = JS_GetIterator(ctx, argv[0], /*is_async*/FALSE); + if (JS_IsException(iter)) + return JS_EXCEPTION; + + key = JS_UNDEFINED; + key_atom = JS_ATOM_NULL; + v = JS_UNDEFINED; + prop = JS_UNDEFINED; + groups = JS_UNDEFINED; + + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + + if (is_map) { + groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0); + } else { + groups = JS_NewObjectProto(ctx, JS_NULL); + } + if (JS_IsException(groups)) + goto exception; + + for (idx = 0; ; idx++) { + if (idx >= MAX_SAFE_INTEGER) { + JS_ThrowTypeError(ctx, "too many elements"); + goto iterator_close_exception; + } + v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(v)) + goto exception; + if (done) + break; // v is JS_UNDEFINED + + args[0] = v; + args[1] = JS_NewInt64(ctx, idx); + key = JS_Call(ctx, cb, ctx->global_obj, 2, args); + if (JS_IsException(key)) + goto iterator_close_exception; + + if (is_map) { + prop = js_map_get(ctx, groups, 1, (JSValueConst *)&key, 0); + } else { + key_atom = JS_ValueToAtom(ctx, key); + JS_FreeValue(ctx, key); + key = JS_UNDEFINED; + if (key_atom == JS_ATOM_NULL) + goto iterator_close_exception; + prop = JS_GetProperty(ctx, groups, key_atom); + } + if (JS_IsException(prop)) + goto exception; + + if (JS_IsUndefined(prop)) { + prop = JS_NewArray(ctx); + if (JS_IsException(prop)) + goto exception; + if (is_map) { + args[0] = key; + args[1] = prop; + res = js_map_set(ctx, groups, 2, args, 0); + if (JS_IsException(res)) + goto exception; + JS_FreeValue(ctx, res); + } else { + prop = JS_DupValue(ctx, prop); + if (JS_DefinePropertyValue(ctx, groups, key_atom, prop, + JS_PROP_C_W_E) < 0) { + goto exception; + } + } + } + res = js_array_push(ctx, prop, 1, (JSValueConst *)&v, /*unshift*/0); + if (JS_IsException(res)) + goto exception; + // res is an int64 + + JS_FreeValue(ctx, prop); + JS_FreeValue(ctx, key); + JS_FreeAtom(ctx, key_atom); + JS_FreeValue(ctx, v); + prop = JS_UNDEFINED; + key = JS_UNDEFINED; + key_atom = JS_ATOM_NULL; + v = JS_UNDEFINED; + } + + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return groups; + + iterator_close_exception: + JS_IteratorClose(ctx, iter, TRUE); + exception: + JS_FreeAtom(ctx, key_atom); + JS_FreeValue(ctx, prop); + JS_FreeValue(ctx, key); + JS_FreeValue(ctx, v); + JS_FreeValue(ctx, groups); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return JS_EXCEPTION; +} + static void js_map_finalizer(JSRuntime *rt, JSValue val) { JSObject *p; @@ -46123,6 +47536,7 @@ static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val, } static const JSCFunctionListEntry js_map_funcs[] = { + JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 1 ), JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), }; @@ -46243,12 +47657,6 @@ static const JSCFunctionListEntry js_generator_proto_funcs[] = { /* Promise */ -typedef enum JSPromiseStateEnum { - JS_PROMISE_PENDING, - JS_PROMISE_FULFILLED, - JS_PROMISE_REJECTED, -} JSPromiseStateEnum; - typedef struct JSPromiseData { JSPromiseStateEnum promise_state; /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */ @@ -46273,6 +47681,22 @@ typedef struct JSPromiseReactionData { JSValue handler; } JSPromiseReactionData; +JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise) +{ + JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); + if (!s) + return -1; + return s->promise_state; +} + +JSValue JS_PromiseResult(JSContext *ctx, JSValue promise) +{ + JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); + if (!s) + return JS_UNDEFINED; + return JS_DupValue(ctx, s->promise_result); +} + static int js_create_resolving_functions(JSContext *ctx, JSValue *args, JSValueConst promise); @@ -46718,17 +48142,14 @@ static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, return result_promise; } -#if 0 -static JSValue js_promise___newPromiseCapability(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_promise_withResolvers(JSContext *ctx, + JSValueConst this_val, + int argc, JSValueConst *argv) { JSValue result_promise, resolving_funcs[2], obj; - JSValueConst ctor; - ctor = argv[0]; - if (!JS_IsObject(ctor)) + if (!JS_IsObject(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); - result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor); + result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); if (JS_IsException(result_promise)) return result_promise; obj = JS_NewObject(ctx); @@ -46743,7 +48164,6 @@ static JSValue js_promise___newPromiseCapability(JSContext *ctx, JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E); return obj; } -#endif static __exception int remainingElementsCount_add(JSContext *ctx, JSValueConst resolve_element_env, @@ -47233,7 +48653,7 @@ static const JSCFunctionListEntry js_promise_funcs[] = { JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ), JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ), JS_CFUNC_DEF("race", 1, js_promise_race ), - //JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ), + JS_CFUNC_DEF("withResolvers", 0, js_promise_withResolvers ), JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL), }; @@ -47844,12 +49264,6 @@ static const JSCFunctionListEntry js_global_funcs[] = { JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ), JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ), JS_PROP_UNDEFINED_DEF("undefined", 0 ), - - /* for the 'Date' implementation */ - JS_CFUNC_DEF("__date_clock", 0, js___date_clock ), - //JS_CFUNC_DEF("__date_now", 0, js___date_now ), - //JS_CFUNC_DEF("__date_getTimezoneOffset", 1, js___date_getTimezoneOffset ), - //JS_CFUNC_DEF("__date_create", 3, js___date_create ), }; /* Date */ @@ -48055,20 +49469,19 @@ static JSValue set_date_field(JSContext *ctx, JSValueConst this_val, res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0); if (res < 0) return JS_EXCEPTION; + + // Argument coercion is observable and must be done unconditionally. + n = min_int(argc, end_field - first_field); + for(i = 0; i < n; i++) { + if (JS_ToFloat64(ctx, &a, argv[i])) + return JS_EXCEPTION; + if (!isfinite(a)) + res = FALSE; + fields[first_field + i] = trunc(a); + } if (res && argc > 0) { - n = end_field - first_field; - if (argc < n) - n = argc; - for(i = 0; i < n; i++) { - if (JS_ToFloat64(ctx, &a, argv[i])) - return JS_EXCEPTION; - if (!isfinite(a)) - goto done; - fields[first_field + i] = trunc(a); - } d = set_date_fields(fields, is_local); } -done: return JS_SetThisTimeValue(ctx, this_val, d); } @@ -48178,7 +49591,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val, break; case 3: pos += snprintf(buf + pos, sizeof(buf) - pos, - "%02d:%02d:%02d %cM", (h + 1) % 12 - 1, m, s, + "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s, (h < 12) ? 'A' : 'P'); break; } @@ -48339,8 +49752,11 @@ static int string_get_signed_digits(JSString *sp, int *pp, int64_t *pval) { p++; res = string_get_digits(sp, &p, pval); - if (res == 0 && sgn == '-') + if (res == 0 && sgn == '-') { + if (*pval == 0) + return -1; // reject negative zero *pval = -*pval; + } *pp = p; return res; } @@ -49091,6 +50507,7 @@ void JS_AddIntrinsicOperators(JSContext *ctx) js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]); js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]); } +#endif /* CONFIG_BIGNUM */ /* BigInt */ @@ -49108,11 +50525,17 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) case JS_TAG_BIG_INT: break; case JS_TAG_FLOAT64: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { bf_t *a, a_s; a = JS_ToBigFloat(ctx, &a_s, val); + if (!a) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } if (!bf_is_finite(a)) { JS_FreeValue(ctx, val); val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint"); @@ -49142,11 +50565,13 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) bf_delete(a); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: val = JS_ToStringFree(ctx, val); if (JS_IsException(val)) break; goto redo; +#endif case JS_TAG_STRING: val = JS_StringToBigIntErr(ctx, val); break; @@ -49219,6 +50644,7 @@ static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val, return js_thisBigIntValue(ctx, this_val); } +#ifdef CONFIG_BIGNUM static JSValue js_bigint_div(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) @@ -49347,6 +50773,7 @@ static JSValue js_bigint_op1(JSContext *ctx, JS_FreeBigInt(ctx, a, &a_s); return JS_NewBigInt64(ctx, res); } +#endif static JSValue js_bigint_asUintN(JSContext *ctx, JSValueConst this_val, @@ -49391,6 +50818,7 @@ static JSValue js_bigint_asUintN(JSContext *ctx, static const JSCFunctionListEntry js_bigint_funcs[] = { JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ), JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ), +#ifdef CONFIG_BIGNUM /* QuickJS extensions */ JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ), JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ), @@ -49404,6 +50832,7 @@ static const JSCFunctionListEntry js_bigint_funcs[] = { JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ), JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ), JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ), +#endif }; static const JSCFunctionListEntry js_bigint_proto_funcs[] = { @@ -49422,7 +50851,7 @@ void JS_AddIntrinsicBigInt(JSContext *ctx) rt->bigint_ops.unary_arith = js_unary_arith_bigint; rt->bigint_ops.binary_arith = js_binary_arith_bigint; rt->bigint_ops.compare = js_compare_bigfloat; - + ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT], js_bigint_proto_funcs, @@ -49433,6 +50862,8 @@ void JS_AddIntrinsicBigInt(JSContext *ctx) countof(js_bigint_funcs)); } +#ifdef CONFIG_BIGNUM + /* BigFloat */ static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val) @@ -49906,6 +51337,10 @@ static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val, if (JS_IsException(op1)) return op1; a = JS_ToBigFloat(ctx, &a_s, op1); + if (!a) { + JS_FreeValue(ctx, op1); + return JS_EXCEPTION; + } fe = &ctx->fp_env; if (argc > 1) { fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV); @@ -50004,7 +51439,11 @@ static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val, return op2; } a = JS_ToBigFloat(ctx, &a_s, op1); + if (!a) + goto fail1; b = JS_ToBigFloat(ctx, &b_s, op2); + if (!b) + goto fail2; fe = &ctx->fp_env; if (argc > 2) { fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV); @@ -50014,10 +51453,12 @@ static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val, res = JS_NewBigFloat(ctx); if (JS_IsException(res)) { fail: - if (a == &a_s) - bf_delete(a); if (b == &b_s) bf_delete(b); + fail2: + if (a == &a_s) + bf_delete(a); + fail1: JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); return JS_EXCEPTION; @@ -50966,8 +52407,22 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) /* XXX: create auto_initializer */ { /* initialize Array.prototype[Symbol.unscopables] */ - char const unscopables[] = "copyWithin" "\0" "entries" "\0" "fill" "\0" "find" "\0" - "findIndex" "\0" "flat" "\0" "flatMap" "\0" "includes" "\0" "keys" "\0" "values" "\0"; + char const unscopables[] = + "copyWithin" "\0" + "entries" "\0" + "fill" "\0" + "find" "\0" + "findIndex" "\0" + "findLast" "\0" + "findLastIndex" "\0" + "flat" "\0" + "flatMap" "\0" + "includes" "\0" + "keys" "\0" + "toReversed" "\0" + "toSorted" "\0" + "toSpliced" "\0" + "values" "\0"; const char *p = unscopables; obj1 = JS_NewObjectProto(ctx, JS_NULL); for(p = unscopables; *p; p += strlen(p) + 1) { @@ -51091,9 +52546,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = { 0, 0, 0, 1, 1, 2, 2, -#ifdef CONFIG_BIGNUM 3, 3, /* BigInt64Array, BigUint64Array */ -#endif 2, 3 }; @@ -51188,12 +52641,12 @@ JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, } JSValue JS_NewUInt8Array(JSContext *ctx, JSValueConst arrayBuffer, int offset, int length) -{ - JSValue offsetValue = JS_NewInt32(ctx, offset); - JSValue lengthValue = JS_NewInt32(ctx, length); - JSValue args[] = {arrayBuffer, offsetValue, lengthValue}; - return js_typed_array_constructor(ctx, arrayBuffer, 3, args, JS_CLASS_UINT8_ARRAY); -} + { + JSValue offsetValue = JS_NewInt32(ctx, offset); + JSValue lengthValue = JS_NewInt32(ctx, length); + JSValue args[] = {arrayBuffer, offsetValue, lengthValue}; + return js_typed_array_constructor(ctx, arrayBuffer, 3, args, JS_CLASS_UINT8_ARRAY); + } /* create a new ArrayBuffer of length 'len' and copy 'buf' to it */ JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len) @@ -51231,11 +52684,26 @@ static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); JSArrayBuffer *abuf = p->u.array_buffer; + struct list_head *el, *el1; + if (abuf) { /* The ArrayBuffer finalizer may be called before the typed array finalizers using it, so abuf->array_list is not necessarily empty. */ - // assert(list_empty(&abuf->array_list)); + list_for_each_safe(el, el1, &abuf->array_list) { + JSTypedArray *ta; + JSObject *p1; + + ta = list_entry(el, JSTypedArray, link); + ta->link.prev = NULL; + ta->link.next = NULL; + p1 = ta->obj; + /* Note: the typed array length and offset fields are not modified */ + if (p1->class_id != JS_CLASS_DATAVIEW) { + p1->u.array.count = 0; + p1->u.array.u.ptr = NULL; + } + } if (abuf->shared && rt->sab_funcs.sab_free) { rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data); } else { @@ -51662,6 +53130,69 @@ static JSValue js_typed_array_set_internal(JSContext *ctx, return JS_EXCEPTION; } +static JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSObject *p; + int64_t idx, len; + + p = get_typed_array(ctx, this_val, 0); + if (!p) + return JS_EXCEPTION; + + if (typed_array_is_detached(ctx, p)) { + JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + return JS_EXCEPTION; + } + + if (JS_ToInt64Sat(ctx, &idx, argv[0])) + return JS_EXCEPTION; + + len = p->u.array.count; + if (idx < 0) + idx = len + idx; + if (idx < 0 || idx >= len) + return JS_UNDEFINED; + return JS_GetPropertyInt64(ctx, this_val, idx); +} + +static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, val; + JSObject *p; + int64_t idx, len; + + p = get_typed_array(ctx, this_val, /*is_dataview*/0); + if (!p) + return JS_EXCEPTION; + + if (JS_ToInt64Sat(ctx, &idx, argv[0])) + return JS_EXCEPTION; + + len = p->u.array.count; + if (idx < 0) + idx = len + idx; + if (idx < 0 || idx >= len) + return JS_ThrowRangeError(ctx, "out of bound"); + + val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER); + if (JS_IsException(val)) + return JS_EXCEPTION; + + arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val, + p->class_id); + if (JS_IsException(arr)) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } + if (JS_SetPropertyInt64(ctx, arr, idx, val) < 0) { + JS_FreeValue(ctx, arr); + return JS_EXCEPTION; + } + return arr; +} + static JSValue js_typed_array_set(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) @@ -51951,14 +53482,10 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, if (JS_ToUint32(ctx, &v, argv[0])) return JS_EXCEPTION; v64 = v; - } else -#ifdef CONFIG_BIGNUM - if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) { + } else if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) { if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0])) return JS_EXCEPTION; - } else -#endif - { + } else { double d; if (JS_ToFloat64(ctx, &d, argv[0])) return JS_EXCEPTION; @@ -52020,12 +53547,13 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, } static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int findIndex) + int argc, JSValueConst *argv, int mode) { JSValueConst func, this_arg; JSValueConst args[3]; JSValue val, index_val, res; - int len, k; + int len, k, end; + int dir; val = JS_UNDEFINED; len = js_typed_array_get_length_internal(ctx, this_val); @@ -52040,7 +53568,17 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, if (argc > 1) this_arg = argv[1]; - for(k = 0; k < len; k++) { + if (mode == special_findLast || mode == special_findLastIndex) { + k = len - 1; + dir = -1; + end = -1; + } else { + k = 0; + dir = 1; + end = len; + } + + for(; k != end; k += dir) { index_val = JS_NewInt32(ctx, k); val = JS_GetPropertyValue(ctx, this_val, index_val); if (JS_IsException(val)) @@ -52052,7 +53590,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, if (JS_IsException(res)) goto exception; if (JS_ToBoolFree(ctx, res)) { - if (findIndex) { + if (mode == special_findIndex || mode == special_findLastIndex) { JS_FreeValue(ctx, val); return index_val; } else { @@ -52061,7 +53599,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, } JS_FreeValue(ctx, val); } - if (findIndex) + if (mode == special_findIndex || mode == special_findLastIndex) return JS_NewInt32(ctx, -1); else return JS_UNDEFINED; @@ -52145,9 +53683,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, d = JS_VALUE_GET_FLOAT64(argv[0]); v64 = d; is_int = (v64 == d); - } else -#ifdef CONFIG_BIGNUM - if (tag == JS_TAG_BIG_INT) { + } else if (tag == JS_TAG_BIG_INT) { JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]); if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) { @@ -52161,9 +53697,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, } d = 0; is_bigint = 1; - } else -#endif - { + } else { goto done; } @@ -52280,7 +53814,6 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, } } break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: if (is_bigint || (is_math_mode(ctx) && is_int && v64 >= -MAX_SAFE_INTEGER && @@ -52304,7 +53837,6 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, } } break; -#endif } done: @@ -52439,6 +53971,24 @@ static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val, return JS_DupValue(ctx, this_val); } +static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, ret; + JSObject *p; + + p = get_typed_array(ctx, this_val, /*is_dataview*/0); + if (!p) + return JS_EXCEPTION; + arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val, + p->class_id); + if (JS_IsException(arr)) + return JS_EXCEPTION; + ret = js_typed_array_reverse(ctx, arr, argc, argv); + JS_FreeValue(ctx, arr); + return ret; +} + static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -52585,7 +54135,6 @@ static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) { return (y < x) - (y > x); } -#ifdef CONFIG_BIGNUM static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) { int64_t x = *(const int64_t *)a; int64_t y = *(const int64_t *)b; @@ -52597,7 +54146,6 @@ static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) { uint64_t y = *(const uint64_t *)b; return (y < x) - (y > x); } -#endif static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) { return js_cmp_doubles(*(const float *)a, *(const float *)b); @@ -52631,7 +54179,6 @@ static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) { return JS_NewUint32(ctx, *(const uint32_t *)a); } -#ifdef CONFIG_BIGNUM static JSValue js_TA_get_int64(JSContext *ctx, const void *a) { return JS_NewBigInt64(ctx, *(int64_t *)a); } @@ -52639,7 +54186,6 @@ static JSValue js_TA_get_int64(JSContext *ctx, const void *a) { static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) { return JS_NewBigUint64(ctx, *(uint64_t *)a); } -#endif static JSValue js_TA_get_float32(JSContext *ctx, const void *a) { return __JS_NewFloat64(ctx, *(const float *)a); @@ -52651,7 +54197,7 @@ static JSValue js_TA_get_float64(JSContext *ctx, const void *a) { struct TA_sort_context { JSContext *ctx; - int exception; + int exception; /* 1 = exception, 2 = detached typed array */ JSValueConst arr; JSValueConst cmp; JSValue (*getfun)(JSContext *ctx, const void *a); @@ -52669,6 +54215,8 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) { cmp = 0; if (!psc->exception) { + /* Note: the typed array can be detached without causing an + error */ a_idx = *(uint32_t *)a; b_idx = *(uint32_t *)b; argv[0] = psc->getfun(ctx, psc->array_ptr + @@ -52696,8 +54244,9 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) { /* make sort stable: compare array offsets */ cmp = (a_idx > b_idx) - (a_idx < b_idx); } - if (validate_typed_array(ctx, psc->arr) < 0) { - psc->exception = 1; + if (unlikely(typed_array_is_detached(ctx, + JS_VALUE_GET_PTR(psc->arr)))) { + psc->exception = 2; } done: JS_FreeValue(ctx, (JSValue)argv[0]); @@ -52721,11 +54270,11 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, tsc.arr = this_val; tsc.cmp = argv[0]; + if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp)) + return JS_EXCEPTION; len = js_typed_array_get_length_internal(ctx, this_val); if (len < 0) return JS_EXCEPTION; - if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp)) - return JS_EXCEPTION; if (len > 1) { p = JS_VALUE_GET_OBJ(this_val); @@ -52755,7 +54304,6 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, tsc.getfun = js_TA_get_uint32; cmpfun = js_TA_cmp_uint32; break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: tsc.getfun = js_TA_get_int64; cmpfun = js_TA_cmp_int64; @@ -52764,7 +54312,6 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, tsc.getfun = js_TA_get_uint64; cmpfun = js_TA_cmp_uint64; break; -#endif case JS_CLASS_FLOAT32_ARRAY: tsc.getfun = js_TA_get_float32; cmpfun = js_TA_cmp_float32; @@ -52793,44 +54340,48 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, tsc.elt_size = elt_size; rqsort(array_idx, len, sizeof(array_idx[0]), js_TA_cmp_generic, &tsc); - if (tsc.exception) - goto fail; - array_tmp = js_malloc(ctx, len * elt_size); - if (!array_tmp) { - fail: - js_free(ctx, array_idx); - return JS_EXCEPTION; - } - memcpy(array_tmp, array_ptr, len * elt_size); - switch(elt_size) { - case 1: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j]; - } - break; - case 2: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j]; - } - break; - case 4: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j]; + if (tsc.exception) { + if (tsc.exception == 1) + goto fail; + /* detached typed array during the sort: no error */ + } else { + array_tmp = js_malloc(ctx, len * elt_size); + if (!array_tmp) { + fail: + js_free(ctx, array_idx); + return JS_EXCEPTION; } - break; - case 8: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j]; + memcpy(array_tmp, array_ptr, len * elt_size); + switch(elt_size) { + case 1: + for(i = 0; i < len; i++) { + j = array_idx[i]; + ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j]; + } + break; + case 2: + for(i = 0; i < len; i++) { + j = array_idx[i]; + ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j]; + } + break; + case 4: + for(i = 0; i < len; i++) { + j = array_idx[i]; + ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j]; + } + break; + case 8: + for(i = 0; i < len; i++) { + j = array_idx[i]; + ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j]; + } + break; + default: + abort(); } - break; - default: - abort(); + js_free(ctx, array_tmp); } - js_free(ctx, array_tmp); js_free(ctx, array_idx); } else { rqsort(array_ptr, len, elt_size, cmpfun, &tsc); @@ -52841,6 +54392,24 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, return JS_DupValue(ctx, this_val); } +static JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, ret; + JSObject *p; + + p = get_typed_array(ctx, this_val, /*is_dataview*/0); + if (!p) + return JS_EXCEPTION; + arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val, + p->class_id); + if (JS_IsException(arr)) + return JS_EXCEPTION; + ret = js_typed_array_sort(ctx, arr, argc, argv); + JS_FreeValue(ctx, arr); + return ret; +} + static const JSCFunctionListEntry js_typed_array_base_funcs[] = { JS_CFUNC_DEF("from", 1, js_typed_array_from ), JS_CFUNC_DEF("of", 0, js_typed_array_of ), @@ -52852,6 +54421,8 @@ static const JSCFunctionListEntry js_typed_array_base_funcs[] = { static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = { JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ), + JS_CFUNC_DEF("at", 1, js_typed_array_at ), + JS_CFUNC_DEF("with", 2, js_typed_array_with ), JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ), JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ), JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ), @@ -52870,12 +54441,16 @@ static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ), JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ), JS_CFUNC_DEF("fill", 1, js_typed_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, 0 ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, 1 ), + JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, special_find ), + JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, special_findIndex ), + JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, special_findLast ), + JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, special_findLastIndex ), JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ), + JS_CFUNC_DEF("toReversed", 0, js_typed_array_toReversed ), JS_CFUNC_DEF("slice", 2, js_typed_array_slice ), JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ), JS_CFUNC_DEF("sort", 1, js_typed_array_sort ), + JS_CFUNC_DEF("toSorted", 1, js_typed_array_toSorted ), JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ), JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ), JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ), @@ -53022,7 +54597,7 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx, { JSObject *p, *src_buffer; JSTypedArray *ta; - JSValue ctor, obj, buffer; + JSValue obj, buffer; uint32_t len, i; int size_log2; JSArrayBuffer *src_abuf, *abuf; @@ -53039,19 +54614,9 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx, len = p->u.array.count; src_buffer = ta->buffer; src_abuf = src_buffer->u.array_buffer; - if (!src_abuf->shared) { - ctor = JS_SpeciesConstructor(ctx, JS_MKPTR(JS_TAG_OBJECT, src_buffer), - JS_UNDEFINED); - if (JS_IsException(ctor)) - goto fail; - } else { - /* force ArrayBuffer default constructor */ - ctor = JS_UNDEFINED; - } size_log2 = typed_array_size_log2(classid); - buffer = js_array_buffer_constructor1(ctx, ctor, + buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED, (uint64_t)len << size_log2); - JS_FreeValue(ctx, ctor); if (JS_IsException(buffer)) goto fail; /* necessary because it could have been detached */ @@ -53157,7 +54722,7 @@ static void js_typed_array_finalizer(JSRuntime *rt, JSValue val) if (ta) { /* during the GC the finalizers are called in an arbitrary order so the ArrayBuffer finalizer may have been called */ - if (JS_IsLiveObject(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) { + if (ta->link.next) { list_del(&ta->link); } JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); @@ -53289,7 +54854,6 @@ static JSValue js_dataview_getValue(JSContext *ctx, if (is_swap) v = bswap32(v); return JS_NewUint32(ctx, v); -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: { uint64_t v; @@ -53308,7 +54872,6 @@ static JSValue js_dataview_getValue(JSContext *ctx, return JS_NewBigUint64(ctx, v); } break; -#endif case JS_CLASS_FLOAT32_ARRAY: { union { @@ -53362,14 +54925,10 @@ static JSValue js_dataview_setValue(JSContext *ctx, if (class_id <= JS_CLASS_UINT32_ARRAY) { if (JS_ToUint32(ctx, &v, val)) return JS_EXCEPTION; - } else -#ifdef CONFIG_BIGNUM - if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) { + } else if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) { if (JS_ToBigInt64(ctx, (int64_t *)&v64, val)) return JS_EXCEPTION; - } else -#endif - { + } else { double d; if (JS_ToFloat64(ctx, &d, val)) return JS_EXCEPTION; @@ -53417,10 +54976,8 @@ static JSValue js_dataview_setValue(JSContext *ctx, v = bswap32(v); put_u32(ptr, v); break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: -#endif case JS_CLASS_FLOAT64_ARRAY: if (is_swap) v64 = bswap64(v64); @@ -53442,10 +54999,8 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ), JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ), JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ), -#ifdef CONFIG_BIGNUM JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ), JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ), -#endif JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ), JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ), JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ), @@ -53454,10 +55009,8 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ), JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ), JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ), -#ifdef CONFIG_BIGNUM JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ), JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ), -#endif JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ), JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ), @@ -53494,20 +55047,12 @@ static void *js_atomics_get_ptr(JSContext *ctx, if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) goto fail; p = JS_VALUE_GET_OBJ(obj); -#ifdef CONFIG_BIGNUM if (is_waitable) err = (p->class_id != JS_CLASS_INT32_ARRAY && p->class_id != JS_CLASS_BIG_INT64_ARRAY); else err = !(p->class_id >= JS_CLASS_INT8_ARRAY && p->class_id <= JS_CLASS_BIG_UINT64_ARRAY); -#else - if (is_waitable) - err = (p->class_id != JS_CLASS_INT32_ARRAY); - else - err = !(p->class_id >= JS_CLASS_INT8_ARRAY && - p->class_id <= JS_CLASS_UINT32_ARRAY); -#endif if (err) { fail: JS_ThrowTypeError(ctx, "integer TypedArray expected"); @@ -53549,11 +55094,7 @@ static JSValue js_atomics_op(JSContext *ctx, int argc, JSValueConst *argv, int op) { int size_log2; -#ifdef CONFIG_BIGNUM uint64_t v, a, rep_val; -#else - uint32_t v, a, rep_val; -#endif void *ptr; JSValue ret; JSClassID class_id; @@ -53567,7 +55108,6 @@ static JSValue js_atomics_op(JSContext *ctx, if (op == ATOMICS_OP_LOAD) { v = 0; } else { -#ifdef CONFIG_BIGNUM if (size_log2 == 3) { int64_t v64; if (JS_ToBigInt64(ctx, &v64, argv[2])) @@ -53578,9 +55118,7 @@ static JSValue js_atomics_op(JSContext *ctx, return JS_EXCEPTION; rep_val = v64; } - } else -#endif - { + } else { uint32_t v32; if (JS_ToUint32(ctx, &v32, argv[2])) return JS_EXCEPTION; @@ -53597,7 +55135,6 @@ static JSValue js_atomics_op(JSContext *ctx, switch(op | (size_log2 << 3)) { -#ifdef CONFIG_BIGNUM #define OP(op_name, func_name) \ case ATOMICS_OP_ ## op_name | (0 << 3): \ a = func_name((_Atomic(uint8_t) *)ptr, v); \ @@ -53611,18 +55148,7 @@ static JSValue js_atomics_op(JSContext *ctx, case ATOMICS_OP_ ## op_name | (3 << 3): \ a = func_name((_Atomic(uint64_t) *)ptr, v); \ break; -#else -#define OP(op_name, func_name) \ - case ATOMICS_OP_ ## op_name | (0 << 3): \ - a = func_name((_Atomic(uint8_t) *)ptr, v); \ - break; \ - case ATOMICS_OP_ ## op_name | (1 << 3): \ - a = func_name((_Atomic(uint16_t) *)ptr, v); \ - break; \ - case ATOMICS_OP_ ## op_name | (2 << 3): \ - a = func_name((_Atomic(uint32_t) *)ptr, v); \ - break; -#endif + OP(ADD, atomic_fetch_add) OP(AND, atomic_fetch_and) OP(OR, atomic_fetch_or) @@ -53640,11 +55166,9 @@ static JSValue js_atomics_op(JSContext *ctx, case ATOMICS_OP_LOAD | (2 << 3): a = atomic_load((_Atomic(uint32_t) *)ptr); break; -#ifdef CONFIG_BIGNUM case ATOMICS_OP_LOAD | (3 << 3): a = atomic_load((_Atomic(uint64_t) *)ptr); break; -#endif case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3): { @@ -53667,7 +55191,6 @@ static JSValue js_atomics_op(JSContext *ctx, a = v1; } break; -#ifdef CONFIG_BIGNUM case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3): { uint64_t v1 = v; @@ -53675,7 +55198,6 @@ static JSValue js_atomics_op(JSContext *ctx, a = v1; } break; -#endif default: abort(); } @@ -53700,14 +55222,12 @@ static JSValue js_atomics_op(JSContext *ctx, case JS_CLASS_UINT32_ARRAY: ret = JS_NewUint32(ctx, a); break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: ret = JS_NewBigInt64(ctx, a); break; case JS_CLASS_BIG_UINT64_ARRAY: ret = JS_NewBigUint64(ctx, a); break; -#endif default: abort(); } @@ -53727,7 +55247,6 @@ static JSValue js_atomics_store(JSContext *ctx, argv[0], argv[1], 0); if (!ptr) return JS_EXCEPTION; -#ifdef CONFIG_BIGNUM if (size_log2 == 3) { int64_t v64; ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2])); @@ -53740,9 +55259,7 @@ static JSValue js_atomics_store(JSContext *ctx, if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); atomic_store((_Atomic(uint64_t) *)ptr, v64); - } else -#endif - { + } else { uint32_t v; /* XXX: spec, would be simpler to return the written value */ ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2])); @@ -53778,11 +55295,7 @@ static JSValue js_atomics_isLockFree(JSContext *ctx, int v, ret; if (JS_ToInt32Sat(ctx, &v, argv[0])) return JS_EXCEPTION; - ret = (v == 1 || v == 2 || v == 4 -#ifdef CONFIG_BIGNUM - || v == 8 -#endif - ); + ret = (v == 1 || v == 2 || v == 4 || v == 8); return JS_NewBool(ctx, ret); } @@ -53814,13 +55327,10 @@ static JSValue js_atomics_wait(JSContext *ctx, argv[0], argv[1], 2); if (!ptr) return JS_EXCEPTION; -#ifdef CONFIG_BIGNUM if (size_log2 == 3) { if (JS_ToBigInt64(ctx, &v, argv[2])) return JS_EXCEPTION; - } else -#endif - { + } else { if (JS_ToInt32(ctx, &v32, argv[2])) return JS_EXCEPTION; v = v32; diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs.h similarity index 98% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs.h index 85f51cf2..de908c70 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/quickjs.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/quickjs.h @@ -27,12 +27,6 @@ #include #include -#include - -// NDK Logging -#define LOG_TAG "android-js-engine-qjs" - -#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__); #ifdef __cplusplus extern "C" { @@ -313,6 +307,9 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) /* don't include the stack frames before this eval in the Error() backtraces */ #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) +/* allow top-level await in normal script. JS_Eval() returns a + promise. Only allowed with JS_EVAL_TYPE_GLOBAL */ +#define JS_EVAL_FLAG_ASYNC (1 << 7) typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); @@ -739,13 +736,13 @@ JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx); -int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, +int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, + JSAtom prop, JSValue val, JSValueConst this_obj, int flags); static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val) { - return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW); + return JS_SetPropertyInternal(ctx, this_obj, prop, val, this_obj, JS_PROP_THROW); } int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx, JSValue val); @@ -838,7 +835,15 @@ typedef struct { void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf); +typedef enum JSPromiseStateEnum { + JS_PROMISE_PENDING, + JS_PROMISE_FULFILLED, + JS_PROMISE_REJECTED, +} JSPromiseStateEnum; + JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); +JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise); +JSValue JS_PromiseResult(JSContext *ctx, JSValue promise); /* is_handled = TRUE means that the rejection is handled */ typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, @@ -909,8 +914,8 @@ int JS_ResolveModule(JSContext *ctx, JSValueConst obj); /* only exported for os.Worker() */ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); /* only exported for os.Worker() */ -JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, - const char *filename); +JSValue JS_LoadModule(JSContext *ctx, const char *basename, + const char *filename); /* C function definition */ typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/readme.txt b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/readme.txt similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/readme.txt rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/readme.txt diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/release.sh b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/release.sh similarity index 85% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/release.sh rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/release.sh index 26fba1b0..6b1b496c 100755 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/release.sh +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/release.sh @@ -8,12 +8,12 @@ version=`cat VERSION` if [ "$1" = "-h" ] ; then echo "release.sh [release_list]" echo "" - echo "release_list: extras binary win_binary quickjs" + echo "release_list: extras binary win_binary cosmo_binary quickjs" exit 1 fi -release_list="extras binary win_binary quickjs" +release_list="extras binary win_binary cosmo_binary quickjs" if [ "$1" != "" ] ; then release_list="$1" @@ -84,6 +84,28 @@ cp $dlldir/libwinpthread-1.dll $outdir fi +#################################################" +# Cosmopolitan binary release + +if echo $release_list | grep -w -q cosmo_binary ; then + +export PATH=$PATH:$HOME/cosmocc/bin + +d="quickjs-cosmo-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir + +make clean +make CONFIG_COSMO=y -j4 qjs run-test262 +cp qjs run-test262 $outdir +cp readme-cosmo.txt $outdir/readme.txt + +( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . ) + +fi + #################################################" # Linux binary release diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/repl.js b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/repl.js new file mode 100644 index 00000000..62714a99 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/repl.js @@ -0,0 +1,1590 @@ +/* + * QuickJS Read Eval Print Loop + * + * Copyright (c) 2017-2020 Fabrice Bellard + * Copyright (c) 2017-2020 Charlie Gordon + * + * 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 strip"; + +import * as std from "std"; +import * as os from "os"; + +(function(g) { + /* add 'os' and 'std' bindings */ + g.os = os; + g.std = std; + + /* close global objects */ + var Object = g.Object; + var String = g.String; + var Array = g.Array; + var Date = g.Date; + var Math = g.Math; + var isFinite = g.isFinite; + var parseFloat = g.parseFloat; + + /* XXX: use preprocessor ? */ + var config_numcalc = (typeof os.open === "undefined"); + var has_jscalc = (typeof Fraction === "function"); + var has_bignum = (typeof BigFloat === "function"); + + var colors = { + none: "\x1b[0m", + black: "\x1b[30m", + red: "\x1b[31m", + green: "\x1b[32m", + yellow: "\x1b[33m", + blue: "\x1b[34m", + magenta: "\x1b[35m", + cyan: "\x1b[36m", + white: "\x1b[37m", + gray: "\x1b[30;1m", + grey: "\x1b[30;1m", + bright_red: "\x1b[31;1m", + bright_green: "\x1b[32;1m", + bright_yellow: "\x1b[33;1m", + bright_blue: "\x1b[34;1m", + bright_magenta: "\x1b[35;1m", + bright_cyan: "\x1b[36;1m", + bright_white: "\x1b[37;1m", + }; + + var styles; + if (config_numcalc) { + styles = { + 'default': 'black', + 'comment': 'white', + 'string': 'green', + 'regex': 'cyan', + 'number': 'green', + 'keyword': 'blue', + 'function': 'gray', + 'type': 'bright_magenta', + 'identifier': 'yellow', + 'error': 'bright_red', + 'result': 'black', + 'error_msg': 'bright_red', + }; + } else { + styles = { + 'default': 'bright_green', + 'comment': 'white', + 'string': 'bright_cyan', + 'regex': 'cyan', + 'number': 'green', + 'keyword': 'bright_white', + 'function': 'bright_yellow', + 'type': 'bright_magenta', + 'identifier': 'bright_green', + 'error': 'red', + 'result': 'bright_white', + 'error_msg': 'bright_red', + }; + } + + var history = []; + var clip_board = ""; + var prec; + var expBits; + var log2_10; + + var pstate = ""; + var prompt = ""; + var plen = 0; + var ps1; + if (config_numcalc) + ps1 = "> "; + else + ps1 = "qjs > "; + var ps2 = " ... "; + var utf8 = true; + var show_time = false; + var show_colors = true; + var eval_start_time; + var eval_time = 0; + + var mexpr = ""; + var level = 0; + var cmd = ""; + var cursor_pos = 0; + var last_cmd = ""; + var last_cursor_pos = 0; + var history_index; + var this_fun, last_fun; + var quote_flag = false; + + var utf8_state = 0; + var utf8_val = 0; + + var term_fd; + var term_read_buf; + var term_width; + /* current X position of the cursor in the terminal */ + var term_cursor_x = 0; + + function termInit() { + var tab; + term_fd = std.in.fileno(); + + /* get the terminal size */ + term_width = 80; + if (os.isatty(term_fd)) { + if (os.ttyGetWinSize) { + tab = os.ttyGetWinSize(term_fd); + if (tab) + term_width = tab[0]; + } + if (os.ttySetRaw) { + /* set the TTY to raw mode */ + os.ttySetRaw(term_fd); + } + } + + /* install a Ctrl-C signal handler */ + os.signal(os.SIGINT, sigint_handler); + + /* install a handler to read stdin */ + term_read_buf = new Uint8Array(64); + os.setReadHandler(term_fd, term_read_handler); + } + + function sigint_handler() { + /* send Ctrl-C to readline */ + handle_byte(3); + } + + function term_read_handler() { + var l, i; + l = os.read(term_fd, term_read_buf.buffer, 0, term_read_buf.length); + for(i = 0; i < l; i++) + handle_byte(term_read_buf[i]); + } + + function handle_byte(c) { + if (!utf8) { + handle_char(c); + } else if (utf8_state !== 0 && (c >= 0x80 && c < 0xc0)) { + utf8_val = (utf8_val << 6) | (c & 0x3F); + utf8_state--; + if (utf8_state === 0) { + handle_char(utf8_val); + } + } else if (c >= 0xc0 && c < 0xf8) { + utf8_state = 1 + (c >= 0xe0) + (c >= 0xf0); + utf8_val = c & ((1 << (6 - utf8_state)) - 1); + } else { + utf8_state = 0; + handle_char(c); + } + } + + function is_alpha(c) { + return typeof c === "string" && + ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); + } + + function is_digit(c) { + return typeof c === "string" && (c >= '0' && c <= '9'); + } + + function is_word(c) { + return typeof c === "string" && + (is_alpha(c) || is_digit(c) || c == '_' || c == '$'); + } + + function ucs_length(str) { + var len, c, i, str_len = str.length; + len = 0; + /* we never count the trailing surrogate to have the + following property: ucs_length(str) = + ucs_length(str.substring(0, a)) + ucs_length(str.substring(a, + str.length)) for 0 <= a <= str.length */ + for(i = 0; i < str_len; i++) { + c = str.charCodeAt(i); + if (c < 0xdc00 || c >= 0xe000) + len++; + } + return len; + } + + function is_trailing_surrogate(c) { + var d; + if (typeof c !== "string") + return false; + d = c.codePointAt(0); /* can be NaN if empty string */ + return d >= 0xdc00 && d < 0xe000; + } + + function is_balanced(a, b) { + switch (a + b) { + case "()": + case "[]": + case "{}": + return true; + } + return false; + } + + function print_color_text(str, start, style_names) { + var i, j; + for (j = start; j < str.length;) { + var style = style_names[i = j]; + while (++j < str.length && style_names[j] == style) + continue; + std.puts(colors[styles[style] || 'default']); + std.puts(str.substring(i, j)); + std.puts(colors['none']); + } + } + + function print_csi(n, code) { + std.puts("\x1b[" + ((n != 1) ? n : "") + code); + } + + /* XXX: handle double-width characters */ + function move_cursor(delta) { + var i, l; + if (delta > 0) { + while (delta != 0) { + if (term_cursor_x == (term_width - 1)) { + std.puts("\n"); /* translated to CRLF */ + term_cursor_x = 0; + delta--; + } else { + l = Math.min(term_width - 1 - term_cursor_x, delta); + print_csi(l, "C"); /* right */ + delta -= l; + term_cursor_x += l; + } + } + } else { + delta = -delta; + while (delta != 0) { + if (term_cursor_x == 0) { + print_csi(1, "A"); /* up */ + print_csi(term_width - 1, "C"); /* right */ + delta--; + term_cursor_x = term_width - 1; + } else { + l = Math.min(delta, term_cursor_x); + print_csi(l, "D"); /* left */ + delta -= l; + term_cursor_x -= l; + } + } + } + } + + function update() { + var i, cmd_len; + /* cursor_pos is the position in 16 bit characters inside the + UTF-16 string 'cmd' */ + if (cmd != last_cmd) { + if (!show_colors && last_cmd.substring(0, last_cursor_pos) == cmd.substring(0, last_cursor_pos)) { + /* optimize common case */ + std.puts(cmd.substring(last_cursor_pos)); + } else { + /* goto the start of the line */ + move_cursor(-ucs_length(last_cmd.substring(0, last_cursor_pos))); + if (show_colors) { + var str = mexpr ? mexpr + '\n' + cmd : cmd; + var start = str.length - cmd.length; + var colorstate = colorize_js(str); + print_color_text(str, start, colorstate[2]); + } else { + std.puts(cmd); + } + } + term_cursor_x = (term_cursor_x + ucs_length(cmd)) % term_width; + if (term_cursor_x == 0) { + /* show the cursor on the next line */ + std.puts(" \x08"); + } + /* remove the trailing characters */ + std.puts("\x1b[J"); + last_cmd = cmd; + last_cursor_pos = cmd.length; + } + if (cursor_pos > last_cursor_pos) { + move_cursor(ucs_length(cmd.substring(last_cursor_pos, cursor_pos))); + } else if (cursor_pos < last_cursor_pos) { + move_cursor(-ucs_length(cmd.substring(cursor_pos, last_cursor_pos))); + } + last_cursor_pos = cursor_pos; + std.out.flush(); + } + + /* editing commands */ + function insert(str) { + if (str) { + cmd = cmd.substring(0, cursor_pos) + str + cmd.substring(cursor_pos); + cursor_pos += str.length; + } + } + + function quoted_insert() { + quote_flag = true; + } + + function abort() { + cmd = ""; + cursor_pos = 0; + return -2; + } + + function alert() { + } + + function beginning_of_line() { + cursor_pos = 0; + } + + function end_of_line() { + cursor_pos = cmd.length; + } + + function forward_char() { + if (cursor_pos < cmd.length) { + cursor_pos++; + while (is_trailing_surrogate(cmd.charAt(cursor_pos))) + cursor_pos++; + } + } + + function backward_char() { + if (cursor_pos > 0) { + cursor_pos--; + while (is_trailing_surrogate(cmd.charAt(cursor_pos))) + cursor_pos--; + } + } + + function skip_word_forward(pos) { + while (pos < cmd.length && !is_word(cmd.charAt(pos))) + pos++; + while (pos < cmd.length && is_word(cmd.charAt(pos))) + pos++; + return pos; + } + + function skip_word_backward(pos) { + while (pos > 0 && !is_word(cmd.charAt(pos - 1))) + pos--; + while (pos > 0 && is_word(cmd.charAt(pos - 1))) + pos--; + return pos; + } + + function forward_word() { + cursor_pos = skip_word_forward(cursor_pos); + } + + function backward_word() { + cursor_pos = skip_word_backward(cursor_pos); + } + + function accept_line() { + std.puts("\n"); + history_add(cmd); + return -1; + } + + function history_add(str) { + if (str) { + history.push(str); + } + history_index = history.length; + } + + function previous_history() { + if (history_index > 0) { + if (history_index == history.length) { + history.push(cmd); + } + history_index--; + cmd = history[history_index]; + cursor_pos = cmd.length; + } + } + + function next_history() { + if (history_index < history.length - 1) { + history_index++; + cmd = history[history_index]; + cursor_pos = cmd.length; + } + } + + function history_search(dir) { + var pos = cursor_pos; + for (var i = 1; i <= history.length; i++) { + var index = (history.length + i * dir + history_index) % history.length; + if (history[index].substring(0, pos) == cmd.substring(0, pos)) { + history_index = index; + cmd = history[index]; + return; + } + } + } + + function history_search_backward() { + return history_search(-1); + } + + function history_search_forward() { + return history_search(1); + } + + function delete_char_dir(dir) { + var start, end; + + start = cursor_pos; + if (dir < 0) { + start--; + while (is_trailing_surrogate(cmd.charAt(start))) + start--; + } + end = start + 1; + while (is_trailing_surrogate(cmd.charAt(end))) + end++; + + if (start >= 0 && start < cmd.length) { + if (last_fun === kill_region) { + kill_region(start, end, dir); + } else { + cmd = cmd.substring(0, start) + cmd.substring(end); + cursor_pos = start; + } + } + } + + function delete_char() { + delete_char_dir(1); + } + + function control_d() { + if (cmd.length == 0) { + std.puts("\n"); + return -3; /* exit read eval print loop */ + } else { + delete_char_dir(1); + } + } + + function backward_delete_char() { + delete_char_dir(-1); + } + + function transpose_chars() { + var pos = cursor_pos; + if (cmd.length > 1 && pos > 0) { + if (pos == cmd.length) + pos--; + cmd = cmd.substring(0, pos - 1) + cmd.substring(pos, pos + 1) + + cmd.substring(pos - 1, pos) + cmd.substring(pos + 1); + cursor_pos = pos + 1; + } + } + + function transpose_words() { + var p1 = skip_word_backward(cursor_pos); + var p2 = skip_word_forward(p1); + var p4 = skip_word_forward(cursor_pos); + var p3 = skip_word_backward(p4); + + if (p1 < p2 && p2 <= cursor_pos && cursor_pos <= p3 && p3 < p4) { + cmd = cmd.substring(0, p1) + cmd.substring(p3, p4) + + cmd.substring(p2, p3) + cmd.substring(p1, p2); + cursor_pos = p4; + } + } + + function upcase_word() { + var end = skip_word_forward(cursor_pos); + cmd = cmd.substring(0, cursor_pos) + + cmd.substring(cursor_pos, end).toUpperCase() + + cmd.substring(end); + } + + function downcase_word() { + var end = skip_word_forward(cursor_pos); + cmd = cmd.substring(0, cursor_pos) + + cmd.substring(cursor_pos, end).toLowerCase() + + cmd.substring(end); + } + + function kill_region(start, end, dir) { + var s = cmd.substring(start, end); + if (last_fun !== kill_region) + clip_board = s; + else if (dir < 0) + clip_board = s + clip_board; + else + clip_board = clip_board + s; + + cmd = cmd.substring(0, start) + cmd.substring(end); + if (cursor_pos > end) + cursor_pos -= end - start; + else if (cursor_pos > start) + cursor_pos = start; + this_fun = kill_region; + } + + function kill_line() { + kill_region(cursor_pos, cmd.length, 1); + } + + function backward_kill_line() { + kill_region(0, cursor_pos, -1); + } + + function kill_word() { + kill_region(cursor_pos, skip_word_forward(cursor_pos), 1); + } + + function backward_kill_word() { + kill_region(skip_word_backward(cursor_pos), cursor_pos, -1); + } + + function yank() { + insert(clip_board); + } + + function control_c() { + if (last_fun === control_c) { + std.puts("\n"); + std.exit(0); + } else { + std.puts("\n(Press Ctrl-C again to quit)\n"); + readline_print_prompt(); + } + } + + function reset() { + cmd = ""; + cursor_pos = 0; + } + + function get_context_word(line, pos) { + var s = ""; + while (pos > 0 && is_word(line[pos - 1])) { + pos--; + s = line[pos] + s; + } + return s; + } + function get_context_object(line, pos) { + var obj, base, c; + if (pos <= 0 || " ~!%^&*(-+={[|:;,<>?/".indexOf(line[pos - 1]) >= 0) + return g; + if (pos >= 2 && line[pos - 1] === ".") { + pos--; + obj = {}; + switch (c = line[pos - 1]) { + case '\'': + case '\"': + return "a"; + case ']': + return []; + case '}': + return {}; + case '/': + return / /; + default: + if (is_word(c)) { + base = get_context_word(line, pos); + if (["true", "false", "null", "this"].includes(base) || !isNaN(+base)) + return eval(base); + obj = get_context_object(line, pos - base.length); + if (obj === null || obj === void 0) + return obj; + if (obj === g && obj[base] === void 0) + return eval(base); + else + return obj[base]; + } + return {}; + } + } + return void 0; + } + + function get_completions(line, pos) { + var s, obj, ctx_obj, r, i, j, paren; + + s = get_context_word(line, pos); + ctx_obj = get_context_object(line, pos - s.length); + r = []; + /* enumerate properties from object and its prototype chain, + add non-numeric regular properties with s as e prefix + */ + for (i = 0, obj = ctx_obj; i < 10 && obj !== null && obj !== void 0; i++) { + var props = Object.getOwnPropertyNames(obj); + /* add non-numeric regular properties */ + for (j = 0; j < props.length; j++) { + var prop = props[j]; + if (typeof prop == "string" && ""+(+prop) != prop && prop.startsWith(s)) + r.push(prop); + } + obj = Object.getPrototypeOf(obj); + } + if (r.length > 1) { + /* sort list with internal names last and remove duplicates */ + function symcmp(a, b) { + if (a[0] != b[0]) { + if (a[0] == '_') + return 1; + if (b[0] == '_') + return -1; + } + if (a < b) + return -1; + if (a > b) + return +1; + return 0; + } + r.sort(symcmp); + for(i = j = 1; i < r.length; i++) { + if (r[i] != r[i - 1]) + r[j++] = r[i]; + } + r.length = j; + } + /* 'tab' = list of completions, 'pos' = cursor position inside + the completions */ + return { tab: r, pos: s.length, ctx: ctx_obj }; + } + + function completion() { + var tab, res, s, i, j, len, t, max_width, col, n_cols, row, n_rows; + res = get_completions(cmd, cursor_pos); + tab = res.tab; + if (tab.length === 0) + return; + s = tab[0]; + len = s.length; + /* add the chars which are identical in all the completions */ + for(i = 1; i < tab.length; i++) { + t = tab[i]; + for(j = 0; j < len; j++) { + if (t[j] !== s[j]) { + len = j; + break; + } + } + } + for(i = res.pos; i < len; i++) { + insert(s[i]); + } + if (last_fun === completion && tab.length == 1) { + /* append parentheses to function names */ + var m = res.ctx[tab[0]]; + if (typeof m == "function") { + insert('('); + if (m.length == 0) + insert(')'); + } else if (typeof m == "object") { + insert('.'); + } + } + /* show the possible completions */ + if (last_fun === completion && tab.length >= 2) { + max_width = 0; + for(i = 0; i < tab.length; i++) + max_width = Math.max(max_width, tab[i].length); + max_width += 2; + n_cols = Math.max(1, Math.floor((term_width + 1) / max_width)); + n_rows = Math.ceil(tab.length / n_cols); + std.puts("\n"); + /* display the sorted list column-wise */ + for (row = 0; row < n_rows; row++) { + for (col = 0; col < n_cols; col++) { + i = col * n_rows + row; + if (i >= tab.length) + break; + s = tab[i]; + if (col != n_cols - 1) + s = s.padEnd(max_width); + std.puts(s); + } + std.puts("\n"); + } + /* show a new prompt */ + readline_print_prompt(); + } + } + + var commands = { /* command table */ + "\x01": beginning_of_line, /* ^A - bol */ + "\x02": backward_char, /* ^B - backward-char */ + "\x03": control_c, /* ^C - abort */ + "\x04": control_d, /* ^D - delete-char or exit */ + "\x05": end_of_line, /* ^E - eol */ + "\x06": forward_char, /* ^F - forward-char */ + "\x07": abort, /* ^G - bell */ + "\x08": backward_delete_char, /* ^H - backspace */ + "\x09": completion, /* ^I - history-search-backward */ + "\x0a": accept_line, /* ^J - newline */ + "\x0b": kill_line, /* ^K - delete to end of line */ + "\x0d": accept_line, /* ^M - enter */ + "\x0e": next_history, /* ^N - down */ + "\x10": previous_history, /* ^P - up */ + "\x11": quoted_insert, /* ^Q - quoted-insert */ + "\x12": alert, /* ^R - reverse-search */ + "\x13": alert, /* ^S - search */ + "\x14": transpose_chars, /* ^T - transpose */ + "\x18": reset, /* ^X - cancel */ + "\x19": yank, /* ^Y - yank */ + "\x1bOA": previous_history, /* ^[OA - up */ + "\x1bOB": next_history, /* ^[OB - down */ + "\x1bOC": forward_char, /* ^[OC - right */ + "\x1bOD": backward_char, /* ^[OD - left */ + "\x1bOF": forward_word, /* ^[OF - ctrl-right */ + "\x1bOH": backward_word, /* ^[OH - ctrl-left */ + "\x1b[1;5C": forward_word, /* ^[[1;5C - ctrl-right */ + "\x1b[1;5D": backward_word, /* ^[[1;5D - ctrl-left */ + "\x1b[1~": beginning_of_line, /* ^[[1~ - bol */ + "\x1b[3~": delete_char, /* ^[[3~ - delete */ + "\x1b[4~": end_of_line, /* ^[[4~ - eol */ + "\x1b[5~": history_search_backward,/* ^[[5~ - page up */ + "\x1b[6~": history_search_forward, /* ^[[5~ - page down */ + "\x1b[A": previous_history, /* ^[[A - up */ + "\x1b[B": next_history, /* ^[[B - down */ + "\x1b[C": forward_char, /* ^[[C - right */ + "\x1b[D": backward_char, /* ^[[D - left */ + "\x1b[F": end_of_line, /* ^[[F - end */ + "\x1b[H": beginning_of_line, /* ^[[H - home */ + "\x1b\x7f": backward_kill_word, /* M-C-? - backward_kill_word */ + "\x1bb": backward_word, /* M-b - backward_word */ + "\x1bd": kill_word, /* M-d - kill_word */ + "\x1bf": forward_word, /* M-f - backward_word */ + "\x1bk": backward_kill_line, /* M-k - backward_kill_line */ + "\x1bl": downcase_word, /* M-l - downcase_word */ + "\x1bt": transpose_words, /* M-t - transpose_words */ + "\x1bu": upcase_word, /* M-u - upcase_word */ + "\x7f": backward_delete_char, /* ^? - delete */ + }; + + function dupstr(str, count) { + var res = ""; + while (count-- > 0) + res += str; + return res; + } + + var readline_keys; + var readline_state; + var readline_cb; + + function readline_print_prompt() + { + std.puts(prompt); + term_cursor_x = ucs_length(prompt) % term_width; + last_cmd = ""; + last_cursor_pos = 0; + } + + function readline_start(defstr, cb) { + cmd = defstr || ""; + cursor_pos = cmd.length; + history_index = history.length; + readline_cb = cb; + + prompt = pstate; + + if (mexpr) { + prompt += dupstr(" ", plen - prompt.length); + prompt += ps2; + } else { + if (show_time) { + var t = eval_time / 1000; + prompt += t.toFixed(6) + " "; + } + plen = prompt.length; + prompt += ps1; + } + readline_print_prompt(); + update(); + readline_state = 0; + } + + function handle_char(c1) { + var c; + c = String.fromCodePoint(c1); + switch(readline_state) { + case 0: + if (c == '\x1b') { /* '^[' - ESC */ + readline_keys = c; + readline_state = 1; + } else { + handle_key(c); + } + break; + case 1: /* '^[ */ + readline_keys += c; + if (c == '[') { + readline_state = 2; + } else if (c == 'O') { + readline_state = 3; + } else { + handle_key(readline_keys); + readline_state = 0; + } + break; + case 2: /* '^[[' - CSI */ + readline_keys += c; + if (!(c == ';' || (c >= '0' && c <= '9'))) { + handle_key(readline_keys); + readline_state = 0; + } + break; + case 3: /* '^[O' - ESC2 */ + readline_keys += c; + handle_key(readline_keys); + readline_state = 0; + break; + } + } + + function handle_key(keys) { + var fun; + + if (quote_flag) { + if (ucs_length(keys) === 1) + insert(keys); + quote_flag = false; + } else if (fun = commands[keys]) { + this_fun = fun; + switch (fun(keys)) { + case -1: + readline_cb(cmd); + return; + case -2: + readline_cb(null); + return; + case -3: + /* uninstall a Ctrl-C signal handler */ + os.signal(os.SIGINT, null); + /* uninstall the stdin read handler */ + os.setReadHandler(term_fd, null); + return; + } + last_fun = this_fun; + } else if (ucs_length(keys) === 1 && keys >= ' ') { + insert(keys); + last_fun = insert; + } else { + alert(); /* beep! */ + } + + cursor_pos = (cursor_pos < 0) ? 0 : + (cursor_pos > cmd.length) ? cmd.length : cursor_pos; + update(); + } + + var hex_mode = false; + var eval_mode = "std"; + + function number_to_string(a, radix) { + var s; + if (!isFinite(a)) { + /* NaN, Infinite */ + return a.toString(); + } else { + if (a == 0) { + if (1 / a < 0) + s = "-0"; + else + s = "0"; + } else { + if (radix == 16 && a === Math.floor(a)) { + var s; + if (a < 0) { + a = -a; + s = "-"; + } else { + s = ""; + } + s += "0x" + a.toString(16); + } else { + s = a.toString(); + } + } + return s; + } + } + + function bigfloat_to_string(a, radix) { + var s; + if (!BigFloat.isFinite(a)) { + /* NaN, Infinite */ + if (eval_mode !== "math") { + return "BigFloat(" + a.toString() + ")"; + } else { + return a.toString(); + } + } else { + if (a == 0) { + if (1 / a < 0) + s = "-0"; + else + s = "0"; + } else { + if (radix == 16) { + var s; + if (a < 0) { + a = -a; + s = "-"; + } else { + s = ""; + } + s += "0x" + a.toString(16); + } else { + s = a.toString(); + } + } + if (typeof a === "bigfloat" && eval_mode !== "math") { + s += "l"; + } else if (eval_mode !== "std" && s.indexOf(".") < 0 && + ((radix == 16 && s.indexOf("p") < 0) || + (radix == 10 && s.indexOf("e") < 0))) { + /* add a decimal point so that the floating point type + is visible */ + s += ".0"; + } + return s; + } + } + + function bigint_to_string(a, radix) { + var s; + if (radix == 16) { + var s; + if (a < 0) { + a = -a; + s = "-"; + } else { + s = ""; + } + s += "0x" + a.toString(16); + } else { + s = a.toString(); + } + if (eval_mode === "std") + s += "n"; + return s; + } + + function print(a) { + var stack = []; + + function print_rec(a) { + var n, i, keys, key, type, s; + + type = typeof(a); + if (type === "object") { + if (a === null) { + std.puts(a); + } else if (stack.indexOf(a) >= 0) { + std.puts("[circular]"); + } else if (has_jscalc && (a instanceof Fraction || + a instanceof Complex || + a instanceof Mod || + a instanceof Polynomial || + a instanceof PolyMod || + a instanceof RationalFunction || + a instanceof Series)) { + std.puts(a.toString()); + } else { + stack.push(a); + if (Array.isArray(a)) { + n = a.length; + std.puts("[ "); + for(i = 0; i < n; i++) { + if (i !== 0) + std.puts(", "); + if (i in a) { + print_rec(a[i]); + } else { + std.puts(""); + } + if (i > 20) { + std.puts("..."); + break; + } + } + std.puts(" ]"); + } else if (Object.__getClass(a) === "RegExp") { + std.puts(a.toString()); + } else { + keys = Object.keys(a); + n = keys.length; + std.puts("{ "); + for(i = 0; i < n; i++) { + if (i !== 0) + std.puts(", "); + key = keys[i]; + std.puts(key, ": "); + print_rec(a[key]); + } + std.puts(" }"); + } + stack.pop(a); + } + } else if (type === "string") { + s = a.__quote(); + if (s.length > 79) + s = s.substring(0, 75) + "...\""; + std.puts(s); + } else if (type === "number") { + std.puts(number_to_string(a, hex_mode ? 16 : 10)); + } else if (type === "bigint") { + std.puts(bigint_to_string(a, hex_mode ? 16 : 10)); + } else if (type === "bigfloat") { + std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10)); + } else if (type === "bigdecimal") { + std.puts(a.toString() + "m"); + } else if (type === "symbol") { + std.puts(String(a)); + } else if (type === "function") { + std.puts("function " + a.name + "()"); + } else { + std.puts(a); + } + } + print_rec(a); + } + + function extract_directive(a) { + var pos; + if (a[0] !== '\\') + return ""; + for (pos = 1; pos < a.length; pos++) { + if (!is_alpha(a[pos])) + break; + } + return a.substring(1, pos); + } + + /* return true if the string after cmd can be evaluted as JS */ + function handle_directive(cmd, expr) { + var param, prec1, expBits1; + + if (cmd === "h" || cmd === "?" || cmd == "help") { + help(); + } else if (cmd === "load") { + var filename = expr.substring(cmd.length + 1).trim(); + if (filename.lastIndexOf(".") <= filename.lastIndexOf("/")) + filename += ".js"; + std.loadScript(filename); + return false; + } else if (cmd === "x") { + hex_mode = true; + } else if (cmd === "d") { + hex_mode = false; + } else if (cmd === "t") { + show_time = !show_time; + } else if (has_bignum && cmd === "p") { + param = expr.substring(cmd.length + 1).trim().split(" "); + if (param.length === 1 && param[0] === "") { + std.puts("BigFloat precision=" + prec + " bits (~" + + Math.floor(prec / log2_10) + + " digits), exponent size=" + expBits + " bits\n"); + } else if (param[0] === "f16") { + prec = 11; + expBits = 5; + } else if (param[0] === "f32") { + prec = 24; + expBits = 8; + } else if (param[0] === "f64") { + prec = 53; + expBits = 11; + } else if (param[0] === "f128") { + prec = 113; + expBits = 15; + } else { + prec1 = parseInt(param[0]); + if (param.length >= 2) + expBits1 = parseInt(param[1]); + else + expBits1 = BigFloatEnv.expBitsMax; + if (Number.isNaN(prec1) || + prec1 < BigFloatEnv.precMin || + prec1 > BigFloatEnv.precMax) { + std.puts("Invalid precision\n"); + return false; + } + if (Number.isNaN(expBits1) || + expBits1 < BigFloatEnv.expBitsMin || + expBits1 > BigFloatEnv.expBitsMax) { + std.puts("Invalid exponent bits\n"); + return false; + } + prec = prec1; + expBits = expBits1; + } + return false; + } else if (has_bignum && cmd === "digits") { + param = expr.substring(cmd.length + 1).trim(); + prec1 = Math.ceil(parseFloat(param) * log2_10); + if (prec1 < BigFloatEnv.precMin || + prec1 > BigFloatEnv.precMax) { + std.puts("Invalid precision\n"); + return false; + } + prec = prec1; + expBits = BigFloatEnv.expBitsMax; + return false; + } else if (has_bignum && cmd === "mode") { + param = expr.substring(cmd.length + 1).trim(); + if (param === "") { + std.puts("Running mode=" + eval_mode + "\n"); + } else if (param === "std" || param === "math") { + eval_mode = param; + } else { + std.puts("Invalid mode\n"); + } + return false; + } else if (cmd === "clear") { + std.puts("\x1b[H\x1b[J"); + } else if (cmd === "q") { + std.exit(0); + } else if (has_jscalc && cmd === "a") { + algebraicMode = true; + } else if (has_jscalc && cmd === "n") { + algebraicMode = false; + } else { + std.puts("Unknown directive: " + cmd + "\n"); + return false; + } + return true; + } + + if (config_numcalc) { + /* called by the GUI */ + g.execCmd = function (cmd) { + switch(cmd) { + case "dec": + hex_mode = false; + break; + case "hex": + hex_mode = true; + break; + case "num": + algebraicMode = false; + break; + case "alg": + algebraicMode = true; + break; + } + } + } + + function help() { + function sel(n) { + return n ? "*": " "; + } + std.puts("\\h this help\n" + + "\\x " + sel(hex_mode) + "hexadecimal number display\n" + + "\\d " + sel(!hex_mode) + "decimal number display\n" + + "\\t " + sel(show_time) + "toggle timing display\n" + + "\\clear clear the terminal\n"); + if (has_jscalc) { + std.puts("\\a " + sel(algebraicMode) + "algebraic mode\n" + + "\\n " + sel(!algebraicMode) + "numeric mode\n"); + } + if (has_bignum) { + std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" + + "\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n"); + if (!has_jscalc) { + std.puts("\\mode [std|math] change the running mode (current = " + eval_mode + ")\n"); + } + } + if (!config_numcalc) { + std.puts("\\q exit\n"); + } + } + + function cmd_start() { + if (!config_numcalc) { + if (has_jscalc) + std.puts('QJSCalc - Type "\\h" for help\n'); + else + std.puts('QuickJS - Type "\\h" for help\n'); + } + if (has_bignum) { + log2_10 = Math.log(10) / Math.log(2); + prec = 113; + expBits = 15; + if (has_jscalc) { + eval_mode = "math"; + /* XXX: numeric mode should always be the default ? */ + g.algebraicMode = config_numcalc; + } + } + + cmd_readline_start(); + } + + function cmd_readline_start() { + readline_start(dupstr(" ", level), readline_handle_cmd); + } + + function readline_handle_cmd(expr) { + if (!handle_cmd(expr)) { + cmd_readline_start(); + } + } + + /* return true if async termination */ + function handle_cmd(expr) { + var colorstate, cmd; + + if (expr === null) { + expr = ""; + return false; + } + if (expr === "?") { + help(); + return false; + } + cmd = extract_directive(expr); + if (cmd.length > 0) { + if (!handle_directive(cmd, expr)) { + return false; + } + expr = expr.substring(cmd.length + 1); + } + if (expr === "") + return false; + + if (mexpr) + expr = mexpr + '\n' + expr; + colorstate = colorize_js(expr); + pstate = colorstate[0]; + level = colorstate[1]; + if (pstate) { + mexpr = expr; + return false; + } + mexpr = ""; + + if (has_bignum) { + /* XXX: async is not supported in this case */ + BigFloatEnv.setPrec(eval_and_print_start.bind(null, expr, false), + prec, expBits); + } else { + eval_and_print_start(expr, true); + } + return true; + } + + function eval_and_print_start(expr, is_async) { + var result; + + try { + if (eval_mode === "math") + expr = '"use math"; void 0;' + expr; + eval_start_time = os.now(); + /* eval as a script */ + result = std.evalScript(expr, { backtrace_barrier: true, async: is_async }); + if (is_async) { + /* result is a promise */ + result.then(print_eval_result, print_eval_error); + } else { + print_eval_result(result); + } + } catch (error) { + print_eval_error(error); + } + } + + function print_eval_result(result) { + eval_time = os.now() - eval_start_time; + std.puts(colors[styles.result]); + print(result); + std.puts("\n"); + std.puts(colors.none); + /* set the last result */ + g._ = result; + + handle_cmd_end(); + } + + function print_eval_error(error) { + std.puts(colors[styles.error_msg]); + if (error instanceof Error) { + console.log(error); + if (error.stack) { + std.puts(error.stack); + } + } else { + std.puts("Throw: "); + console.log(error); + } + std.puts(colors.none); + + handle_cmd_end(); + } + + function handle_cmd_end() { + level = 0; + /* run the garbage collector after each command */ + std.gc(); + cmd_readline_start(); + } + + function colorize_js(str) { + var i, c, start, n = str.length; + var style, state = "", level = 0; + var primary, can_regex = 1; + var r = []; + + function push_state(c) { state += c; } + function last_state(c) { return state.substring(state.length - 1); } + function pop_state(c) { + var c = last_state(); + state = state.substring(0, state.length - 1); + return c; + } + + function parse_block_comment() { + style = 'comment'; + push_state('/'); + for (i++; i < n - 1; i++) { + if (str[i] == '*' && str[i + 1] == '/') { + i += 2; + pop_state('/'); + break; + } + } + } + + function parse_line_comment() { + style = 'comment'; + for (i++; i < n; i++) { + if (str[i] == '\n') { + break; + } + } + } + + function parse_string(delim) { + style = 'string'; + push_state(delim); + while (i < n) { + c = str[i++]; + if (c == '\n') { + style = 'error'; + continue; + } + if (c == '\\') { + if (i >= n) + break; + i++; + } else + if (c == delim) { + pop_state(); + break; + } + } + } + + function parse_regex() { + style = 'regex'; + push_state('/'); + while (i < n) { + c = str[i++]; + if (c == '\n') { + style = 'error'; + continue; + } + if (c == '\\') { + if (i < n) { + i++; + } + continue; + } + if (last_state() == '[') { + if (c == ']') { + pop_state() + } + // ECMA 5: ignore '/' inside char classes + continue; + } + if (c == '[') { + push_state('['); + if (str[i] == '[' || str[i] == ']') + i++; + continue; + } + if (c == '/') { + pop_state(); + while (i < n && is_word(str[i])) + i++; + break; + } + } + } + + function parse_number() { + style = 'number'; + while (i < n && (is_word(str[i]) || (str[i] == '.' && (i == n - 1 || str[i + 1] != '.')))) { + i++; + } + } + + var js_keywords = "|" + + "break|case|catch|continue|debugger|default|delete|do|" + + "else|finally|for|function|if|in|instanceof|new|" + + "return|switch|this|throw|try|typeof|while|with|" + + "class|const|enum|import|export|extends|super|" + + "implements|interface|let|package|private|protected|" + + "public|static|yield|" + + "undefined|null|true|false|Infinity|NaN|" + + "eval|arguments|" + + "await|"; + + var js_no_regex = "|this|super|undefined|null|true|false|Infinity|NaN|arguments|"; + var js_types = "|void|var|"; + + function parse_identifier() { + can_regex = 1; + + while (i < n && is_word(str[i])) + i++; + + var w = '|' + str.substring(start, i) + '|'; + + if (js_keywords.indexOf(w) >= 0) { + style = 'keyword'; + if (js_no_regex.indexOf(w) >= 0) + can_regex = 0; + return; + } + + var i1 = i; + while (i1 < n && str[i1] == ' ') + i1++; + + if (i1 < n && str[i1] == '(') { + style = 'function'; + return; + } + + if (js_types.indexOf(w) >= 0) { + style = 'type'; + return; + } + + style = 'identifier'; + can_regex = 0; + } + + function set_style(from, to) { + while (r.length < from) + r.push('default'); + while (r.length < to) + r.push(style); + } + + for (i = 0; i < n;) { + style = null; + start = i; + switch (c = str[i++]) { + case ' ': + case '\t': + case '\r': + case '\n': + continue; + case '+': + case '-': + if (i < n && str[i] == c) { + i++; + continue; + } + can_regex = 1; + continue; + case '/': + if (i < n && str[i] == '*') { // block comment + parse_block_comment(); + break; + } + if (i < n && str[i] == '/') { // line comment + parse_line_comment(); + break; + } + if (can_regex) { + parse_regex(); + can_regex = 0; + break; + } + can_regex = 1; + continue; + case '\'': + case '\"': + case '`': + parse_string(c); + can_regex = 0; + break; + case '(': + case '[': + case '{': + can_regex = 1; + level++; + push_state(c); + continue; + case ')': + case ']': + case '}': + can_regex = 0; + if (level > 0 && is_balanced(last_state(), c)) { + level--; + pop_state(); + continue; + } + style = 'error'; + break; + default: + if (is_digit(c)) { + parse_number(); + can_regex = 0; + break; + } + if (is_word(c) || c == '$') { + parse_identifier(); + break; + } + can_regex = 1; + continue; + } + if (style) + set_style(start, i); + } + set_style(n, n); + return [ state, level, r ]; + } + + termInit(); + + cmd_start(); + +})(globalThis); diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/run-test262.c b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/run-test262.c similarity index 96% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/run-test262.c rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/run-test262.c index 2092caca..bf905bda 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/run-test262.c +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/run-test262.c @@ -1174,7 +1174,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, { JSValue res_val, exception_val; int ret, error_line, pos, pos_line; - BOOL is_error, has_error_line; + BOOL is_error, has_error_line, ret_promise; const char *error_name; pos = skip_comments(buf, 1, &pos_line); @@ -1183,12 +1183,19 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, exception_val = JS_UNDEFINED; error_name = NULL; + /* a module evaluation returns a promise */ + ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0); async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */ - + res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); - if (is_async && !JS_IsException(res_val)) { - JS_FreeValue(ctx, res_val); + if ((is_async || ret_promise) && !JS_IsException(res_val)) { + JSValue promise = JS_UNDEFINED; + if (ret_promise) { + promise = res_val; + } else { + JS_FreeValue(ctx, res_val); + } for(;;) { JSContext *ctx1; ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); @@ -1196,15 +1203,27 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, res_val = JS_EXCEPTION; break; } else if (ret == 0) { - /* test if the test called $DONE() once */ - if (async_done != 1) { - res_val = JS_ThrowTypeError(ctx, "$DONE() not called"); + if (is_async) { + /* test if the test called $DONE() once */ + if (async_done != 1) { + res_val = JS_ThrowTypeError(ctx, "$DONE() not called"); + } else { + res_val = JS_UNDEFINED; + } } else { - res_val = JS_UNDEFINED; + /* check that the returned promise is fulfilled */ + JSPromiseStateEnum state = JS_PromiseState(ctx, promise); + if (state == JS_PROMISE_FULFILLED) + res_val = JS_UNDEFINED; + else if (state == JS_PROMISE_REJECTED) + res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise)); + else + res_val = JS_ThrowTypeError(ctx, "promise is pending"); } break; } } + JS_FreeValue(ctx, promise); } if (JS_IsException(res_val)) { @@ -1498,7 +1517,7 @@ void update_stats(JSRuntime *rt, const char *filename) { #undef update } -int run_test_buf(const char *filename, char *harness, namelist_t *ip, +int run_test_buf(const char *filename, const char *harness, namelist_t *ip, char *buf, size_t buf_len, const char* error_type, int eval_flags, BOOL is_negative, BOOL is_async, BOOL can_block) @@ -1582,6 +1601,8 @@ int run_test(const char *filename, int index) if (p) { snprintf(harnessbuf, sizeof(harnessbuf), "%.*s%s", (int)(p - filename), filename, "harness"); + } else { + pstrcpy(harnessbuf, sizeof(harnessbuf), ""); } harness = harnessbuf; } @@ -1669,6 +1690,8 @@ int run_test(const char *filename, int index) if (p) { snprintf(harnessbuf, sizeof(harnessbuf), "%.*s%s", (int)(p - filename), filename, "test/harness"); + } else { + pstrcpy(harnessbuf, sizeof(harnessbuf), ""); } harness = harnessbuf; } @@ -1835,17 +1858,32 @@ int run_test262_harness_test(const char *filename, BOOL is_module) js_std_dump_error(ctx); ret_code = 1; } else { - JS_FreeValue(ctx, res_val); + JSValue promise = JS_UNDEFINED; + if (is_module) { + promise = res_val; + } else { + JS_FreeValue(ctx, res_val); + } for(;;) { JSContext *ctx1; ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); if (ret < 0) { - js_std_dump_error(ctx1); - ret_code = 1; + js_std_dump_error(ctx1); + ret_code = 1; } else if (ret == 0) { - break; + break; + } + } + /* dump the error if the module returned an error. */ + if (is_module) { + JSPromiseStateEnum state = JS_PromiseState(ctx, promise); + if (state == JS_PROMISE_REJECTED) { + JS_Throw(ctx, JS_PromiseResult(ctx, promise)); + js_std_dump_error(ctx); + ret_code = 1; } } + JS_FreeValue(ctx, promise); } free(buf); #ifdef CONFIG_AGENT diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262.conf b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262.conf similarity index 84% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262.conf rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262.conf index 6fbb5793..fd9862e8 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262.conf +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262.conf @@ -47,16 +47,25 @@ testdir=test262/test # Standard language features and proposed extensions # list the features that are included # skipped features are tagged as such to avoid warnings +# Keep this list alpha-sorted (:sort i in vim) +__getter__ +__proto__ +__setter__ AggregateError align-detached-buffer-semantics-with-web-reality arbitrary-module-namespace-names=skip -Array.prototype.at=skip +array-find-from-last +array-grouping +Array.fromAsync=skip +Array.prototype.at Array.prototype.flat Array.prototype.flatMap Array.prototype.flatten +Array.prototype.includes Array.prototype.values ArrayBuffer +arraybuffer-transfer=skip arrow-function async-functions async-iteration @@ -64,12 +73,15 @@ Atomics Atomics.waitAsync=skip BigInt caller +change-array-by-copy class class-fields-private +class-fields-private-in class-fields-public class-methods-private -class-static-fields-public +class-static-block class-static-fields-private +class-static-fields-public class-static-methods-private cleanupSome=skip coalesce-expression @@ -85,14 +97,17 @@ DataView.prototype.getInt8 DataView.prototype.getUint16 DataView.prototype.getUint32 DataView.prototype.setUint8 +decorators=skip default-parameters destructuring-assignment destructuring-binding dynamic-import +error-cause +exponentiation export-star-as-namespace-from-module FinalizationGroup=skip -FinalizationRegistry=skip FinalizationRegistry.prototype.cleanupSome=skip +FinalizationRegistry=skip Float32Array Float64Array for-in-order @@ -101,11 +116,16 @@ generators globalThis hashbang host-gc-required=skip +import-assertions=skip +import-attributes=skip import.meta Int16Array Int32Array Int8Array IsHTMLDDA +iterator-helpers=skip +json-modules=skip +json-parse-with-source=skip json-superset legacy-regexp=skip let @@ -116,10 +136,12 @@ numeric-separator-literal object-rest object-spread Object.fromEntries +Object.hasOwn Object.is optional-catch-binding optional-chaining Promise +promise-with-resolvers Promise.allSettled Promise.any Promise.prototype.finally @@ -130,20 +152,27 @@ Reflect.construct Reflect.set Reflect.setPrototypeOf regexp-dotall +regexp-duplicate-named-groups=skip regexp-lookbehind -regexp-match-indices=skip +regexp-match-indices regexp-named-groups regexp-unicode-property-escapes +regexp-v-flag=skip +resizable-arraybuffer=skip rest-parameters Set +set-methods=skip +ShadowRealm=skip SharedArrayBuffer string-trimming String.fromCodePoint +String.prototype.at String.prototype.endsWith String.prototype.includes -String.prototype.at=skip +String.prototype.isWellFormed String.prototype.matchAll String.prototype.replaceAll +String.prototype.toWellFormed String.prototype.trimEnd String.prototype.trimStart super @@ -162,11 +191,13 @@ Symbol.split Symbol.toPrimitive Symbol.toStringTag Symbol.unscopables +symbols-as-weakmap-keys=skip tail-call-optimization=skip template -top-level-await=skip +Temporal=skip +top-level-await TypedArray -TypedArray.prototype.at=skip +TypedArray.prototype.at u180e Uint16Array Uint32Array @@ -176,9 +207,6 @@ WeakMap WeakRef=skip WeakSet well-formed-json-stringify -__getter__ -__proto__ -__setter__ [exclude] # list excluded tests and directories here diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262_errors.txt b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262_errors.txt new file mode 100644 index 00000000..edf5372a --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262_errors.txt @@ -0,0 +1,8 @@ +test262/test/annexB/language/eval-code/direct/script-decl-lex-collision-in-sloppy-mode.js:13: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all +test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: Test262Error: Expected a DummyError but got a TypeError +test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError +test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: Test262Error: Expected a DummyError but got a TypeError +test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError +test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: unexpected error type: Test262: This statement should not be evaluated. +test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: strict mode: unexpected error type: Test262: This statement should not be evaluated. +test262/test/language/global-code/script-decl-lex-var-declared-via-eval-sloppy.js:13: Test262Error: variable Expected a SyntaxError to be thrown but no exception was thrown at all diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262o.conf b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262o.conf similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262o.conf rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262o.conf diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262o_errors.txt b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262o_errors.txt similarity index 100% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/test262o_errors.txt rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/test262o_errors.txt diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/unicode_download.sh b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/unicode_download.sh similarity index 75% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/unicode_download.sh rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/unicode_download.sh index 87bb2956..35daf0ef 100755 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/unicode_download.sh +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/unicode_download.sh @@ -1,7 +1,7 @@ #!/bin/sh set -e -url="ftp://ftp.unicode.org/Public/13.0.0/ucd" +url="ftp://ftp.unicode.org/Public/15.0.0/ucd" emoji_url="${url}/emoji/emoji-data.txt" files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \ @@ -11,9 +11,9 @@ PropertyValueAliases.txt" mkdir -p unicode -#for f in $files; do -# g="${url}/${f}" -# wget $g -O unicode/$f -#done +for f in $files; do + g="${url}/${f}" + wget $g -O unicode/$f +done wget $emoji_url -O unicode/emoji-data.txt diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/unicode_gen.c b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/unicode_gen.c similarity index 93% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/unicode_gen.c rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/unicode_gen.c index f18aaa0a..54da2c15 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/unicode_gen.c +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/unicode_gen.c @@ -42,6 +42,7 @@ //#define DUMP_TABLE_SIZE //#define DUMP_CC_TABLE //#define DUMP_DECOMP_TABLE +//#define DUMP_CASE_FOLDING_SPECIAL_CASES /* Ideas: - Generalize run length encoding + index for all tables @@ -217,15 +218,16 @@ static const char *unicode_prop_short_name[] = { #undef DEF }; -#undef UNICODE_SPROP_LIST +#undef UNICODE_PROP_LIST typedef struct { /* case conv */ uint8_t u_len; uint8_t l_len; - int u_data[CC_LEN_MAX]; - int l_data[CC_LEN_MAX]; - int f_code; + uint8_t f_len; + int u_data[CC_LEN_MAX]; /* to upper case */ + int l_data[CC_LEN_MAX]; /* to lower case */ + int f_data[CC_LEN_MAX]; /* to case folding */ uint8_t combining_class; uint8_t is_compat:1; @@ -499,7 +501,7 @@ void parse_case_folding(CCInfo *tab, const char *filename) FILE *f; char line[1024]; const char *p; - int code; + int code, status; CCInfo *ci; f = fopen(filename, "rb"); @@ -530,14 +532,28 @@ void parse_case_folding(CCInfo *tab, const char *filename) /* locale dependent casing */ while (isspace(*p)) p++; - if (*p != 'C' && *p != 'S') + status = *p; + if (status != 'C' && status != 'S' && status != 'F') continue; p = get_field(line, 2); - assert(p != 0); - assert(ci->f_code == 0); - ci->f_code = strtoul(p, NULL, 16); - assert(ci->f_code != 0 && ci->f_code != code); + assert(p != NULL); + if (status == 'S') { + /* we always select the simple case folding and assume it + * comes after the full case folding case */ + assert(ci->f_len >= 2); + ci->f_len = 0; + } else { + assert(ci->f_len == 0); + } + for(;;) { + while (isspace(*p)) + p++; + if (*p == ';') + break; + assert(ci->l_len < CC_LEN_MAX); + ci->f_data[ci->f_len++] = strtoul(p, (char **)&p, 16); + } } fclose(f); @@ -864,19 +880,21 @@ void dump_cc_info(CCInfo *ci, int i) for(j = 0; j < ci->l_len; j++) printf(" %05x", ci->l_data[j]); } - if (ci->f_code != 0) { - printf(" F: %05x", ci->f_code); + if (ci->f_len != 0) { + printf(" F:"); + for(j = 0; j < ci->f_len; j++) + printf(" %05x", ci->f_data[j]); } printf("\n"); } -void dump_data(CCInfo *tab) +void dump_unicode_data(CCInfo *tab) { int i; CCInfo *ci; for(i = 0; i <= CHARCODE_MAX; i++) { ci = &tab[i]; - if (ci->u_len != 0 || ci->l_len != 0 || ci->f_code != 0) { + if (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0) { dump_cc_info(ci, i); } } @@ -886,8 +904,8 @@ BOOL is_complicated_case(const CCInfo *ci) { return (ci->u_len > 1 || ci->l_len > 1 || (ci->u_len > 0 && ci->l_len > 0) || - (ci->f_code != 0) != ci->l_len || - (ci->f_code != 0 && ci->l_data[0] != ci->f_code)); + (ci->f_len != ci->l_len) || + (memcmp(ci->f_data, ci->l_data, ci->f_len * sizeof(ci->f_data[0])) != 0)); } #ifndef USE_TEST @@ -903,9 +921,9 @@ enum { RUN_TYPE_UF_D1_EXT, RUN_TYPE_U_EXT, RUN_TYPE_LF_EXT, - RUN_TYPE_U_EXT2, - RUN_TYPE_L_EXT2, - RUN_TYPE_U_EXT3, + RUN_TYPE_UF_EXT2, + RUN_TYPE_LF_EXT2, + RUN_TYPE_UF_EXT3, }; #endif @@ -921,9 +939,9 @@ const char *run_type_str[] = { "UF_D1_EXT", "U_EXT", "LF_EXT", - "U_EXT2", - "L_EXT2", - "U_EXT3", + "UF_EXT2", + "LF_EXT2", + "UF_EXT3", }; typedef struct { @@ -936,6 +954,13 @@ typedef struct { int data_index; /* 'data' coming from the table */ } TableEntry; +static int simple_to_lower(CCInfo *tab, int c) +{ + if (tab[c].l_len != 1) + return c; + return tab[c].l_data[0]; +} + /* code (17), len (7), type (4) */ void find_run_type(TableEntry *te, CCInfo *tab, int code) @@ -949,15 +974,15 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code) te->code = code; if (ci->l_len == 1 && ci->l_data[0] == code + 2 && - ci->f_code == ci->l_data[0] && + ci->f_len == 1 && ci->f_data[0] == ci->l_data[0] && ci->u_len == 0 && ci1->l_len == 1 && ci1->l_data[0] == code + 2 && - ci1->f_code == ci1->l_data[0] && + ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0] && ci1->u_len == 1 && ci1->u_data[0] == code && ci2->l_len == 0 && - ci2->f_code == 0 && + ci2->f_len == 0 && ci2->u_len == 1 && ci2->u_data[0] == code) { te->len = 3; te->data = 0; @@ -972,7 +997,7 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code) if (ci1->u_len != 1 || ci1->u_data[0] != ci->u_data[0] + len || ci1->l_len != 0 || - ci1->f_code != ci1->u_data[0]) + ci1->f_len != 1 || ci1->f_data[0] != ci1->u_data[0]) break; len++; } @@ -983,21 +1008,25 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code) return; } - if (ci->u_len == 2 && ci->u_data[1] == 0x399 && - ci->f_code == 0 && ci->l_len == 0) { + if (ci->l_len == 0 && + ci->u_len == 2 && ci->u_data[1] == 0x399 && + ci->f_len == 2 && ci->f_data[1] == 0x3B9 && + ci->f_data[0] == simple_to_lower(tab, ci->u_data[0])) { len = 1; while (code + len <= CHARCODE_MAX) { ci1 = &tab[code + len]; if (!(ci1->u_len == 2 && - ci1->u_data[1] == 0x399 && + ci1->u_data[1] == ci->u_data[1] && ci1->u_data[0] == ci->u_data[0] + len && - ci1->f_code == 0 && + ci1->f_len == 2 && + ci1->f_data[1] == ci->f_data[1] && + ci1->f_data[0] == ci->f_data[0] + len && ci1->l_len == 0)) break; len++; } te->len = len; - te->type = RUN_TYPE_U_EXT2; + te->type = RUN_TYPE_UF_EXT2; te->ext_data[0] = ci->u_data[0]; te->ext_data[1] = ci->u_data[1]; te->ext_len = 2; @@ -1005,7 +1034,8 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code) } if (ci->u_len == 2 && ci->u_data[1] == 0x399 && - ci->l_len == 1 && ci->f_code == ci->l_data[0]) { + ci->l_len == 1 && + ci->f_len == 1 && ci->f_data[0] == ci->l_data[0]) { len = 1; while (code + len <= CHARCODE_MAX) { ci1 = &tab[code + len]; @@ -1014,7 +1044,7 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code) ci1->u_data[0] == ci->u_data[0] + len && ci1->l_len == 1 && ci1->l_data[0] == ci->l_data[0] + len && - ci1->f_code == ci1->l_data[0])) + ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0])) break; len++; } @@ -1026,13 +1056,13 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code) return; } - if (ci->l_len == 1 && ci->u_len == 0 && ci->f_code == 0) { + if (ci->l_len == 1 && ci->u_len == 0 && ci->f_len == 0) { len = 1; while (code + len <= CHARCODE_MAX) { ci1 = &tab[code + len]; if (!(ci1->l_len == 1 && ci1->l_data[0] == ci->l_data[0] + len && - ci1->u_len == 0 && ci1->f_code == 0)) + ci1->u_len == 0 && ci1->f_len == 0)) break; len++; } @@ -1045,32 +1075,39 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code) if (ci->l_len == 0 && ci->u_len == 1 && ci->u_data[0] < 0x1000 && - ci->f_code == ci->u_data[0] + 0x20) { + ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 0x20) { te->len = 1; te->type = RUN_TYPE_UF_D20; te->data = ci->u_data[0]; } else if (ci->l_len == 0 && - ci->u_len == 1 && - ci->f_code == ci->u_data[0] + 1) { + ci->u_len == 1 && + ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 1) { te->len = 1; te->type = RUN_TYPE_UF_D1_EXT; te->ext_data[0] = ci->u_data[0]; te->ext_len = 1; - } else if (ci->l_len == 2 && ci->u_len == 0 && ci->f_code == 0) { + } else if (ci->l_len == 2 && ci->u_len == 0 && ci->f_len == 2 && + ci->l_data[0] == ci->f_data[0] && + ci->l_data[1] == ci->f_data[1]) { te->len = 1; - te->type = RUN_TYPE_L_EXT2; + te->type = RUN_TYPE_LF_EXT2; te->ext_data[0] = ci->l_data[0]; te->ext_data[1] = ci->l_data[1]; te->ext_len = 2; - } else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_code == 0) { + } else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 2 && + ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) && + ci->f_data[1] == simple_to_lower(tab, ci->u_data[1])) { te->len = 1; - te->type = RUN_TYPE_U_EXT2; + te->type = RUN_TYPE_UF_EXT2; te->ext_data[0] = ci->u_data[0]; te->ext_data[1] = ci->u_data[1]; te->ext_len = 2; - } else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_code == 0) { + } else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 3 && + ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) && + ci->f_data[1] == simple_to_lower(tab, ci->u_data[1]) && + ci->f_data[2] == simple_to_lower(tab, ci->u_data[2])) { te->len = 1; - te->type = RUN_TYPE_U_EXT3; + te->type = RUN_TYPE_UF_EXT3; te->ext_data[0] = ci->u_data[0]; te->ext_data[1] = ci->u_data[1]; te->ext_data[2] = ci->u_data[2]; @@ -1188,7 +1225,7 @@ void build_conv_table(CCInfo *tab) te = conv_table; for(code = 0; code <= CHARCODE_MAX; code++) { ci = &tab[code]; - if (ci->u_len == 0 && ci->l_len == 0 && ci->f_code == 0) + if (ci->u_len == 0 && ci->l_len == 0 && ci->f_len == 0) continue; assert(te - conv_table < countof(conv_table)); find_run_type(te, tab, code); @@ -1244,7 +1281,7 @@ void build_conv_table(CCInfo *tab) /* find the data index for ext_data */ for(i = 0; i < conv_table_len; i++) { te = &conv_table[i]; - if (te->type == RUN_TYPE_U_EXT3) { + if (te->type == RUN_TYPE_UF_EXT3) { int p, v; v = 0; for(j = 0; j < 3; j++) { @@ -1258,8 +1295,8 @@ void build_conv_table(CCInfo *tab) for(i = 0; i < conv_table_len; i++) { te = &conv_table[i]; - if (te->type == RUN_TYPE_L_EXT2 || - te->type == RUN_TYPE_U_EXT2 || + if (te->type == RUN_TYPE_LF_EXT2 || + te->type == RUN_TYPE_UF_EXT2 || te->type == RUN_TYPE_U2L_399_EXT2) { int p, v; v = 0; @@ -1322,6 +1359,54 @@ void dump_case_conv_table(FILE *f) fprintf(f, "\n};\n\n"); } + +static CCInfo *global_tab; + +static int sp_cc_cmp(const void *p1, const void *p2) +{ + CCInfo *c1 = &global_tab[*(const int *)p1]; + CCInfo *c2 = &global_tab[*(const int *)p2]; + if (c1->f_len < c2->f_len) { + return -1; + } else if (c2->f_len < c1->f_len) { + return 1; + } else { + return memcmp(c1->f_data, c2->f_data, sizeof(c1->f_data[0]) * c1->f_len); + } +} + +/* dump the case special cases (multi character results which are + identical and need specific handling in lre_canonicalize() */ +void dump_case_folding_special_cases(CCInfo *tab) +{ + int i, len, j; + int *perm; + + perm = malloc(sizeof(perm[0]) * (CHARCODE_MAX + 1)); + for(i = 0; i <= CHARCODE_MAX; i++) + perm[i] = i; + global_tab = tab; + qsort(perm, CHARCODE_MAX + 1, sizeof(perm[0]), sp_cc_cmp); + for(i = 0; i <= CHARCODE_MAX;) { + if (tab[perm[i]].f_len <= 1) { + i++; + } else { + len = 1; + while ((i + len) <= CHARCODE_MAX && !sp_cc_cmp(&perm[i], &perm[i + len])) + len++; + + if (len > 1) { + for(j = i; j < i + len; j++) + dump_cc_info(&tab[perm[j]], perm[j]); + } + i += len; + } + } + free(perm); + global_tab = NULL; +} + + int tabcmp(const int *tab1, const int *tab2, int n) { int i; @@ -1348,7 +1433,7 @@ void compute_internal_props(void) for(i = 0; i <= CHARCODE_MAX; i++) { CCInfo *ci = &unicode_db[i]; - has_ul = (ci->u_len != 0 || ci->l_len != 0 || ci->f_code != 0); + has_ul = (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0); if (has_ul) { assert(get_prop(i, PROP_Cased)); } else { @@ -1363,10 +1448,10 @@ void compute_internal_props(void) set_prop(i, PROP_Changes_When_Titlecased1, get_prop(i, PROP_Changes_When_Titlecased) ^ (ci->u_len != 0)); set_prop(i, PROP_Changes_When_Casefolded1, - get_prop(i, PROP_Changes_When_Casefolded) ^ (ci->f_code != 0)); + get_prop(i, PROP_Changes_When_Casefolded) ^ (ci->f_len != 0)); /* XXX: reduce table size (438 bytes) */ set_prop(i, PROP_Changes_When_NFKC_Casefolded1, - get_prop(i, PROP_Changes_When_NFKC_Casefolded) ^ (ci->f_code != 0)); + get_prop(i, PROP_Changes_When_NFKC_Casefolded) ^ (ci->f_len != 0)); #if 0 /* TEST */ #define M(x) (1U << GCAT_ ## x) @@ -1797,8 +1882,10 @@ void check_case_conv(void) ci->u_len = 1; ci->u_data[0] = code; } - if (ci->f_code == 0) - ci->f_code = code; + if (ci->f_len == 0) { + ci->f_len = 1; + ci->f_data[0] = code; + } error = 0; l = check_conv(res, code, 0); @@ -1812,7 +1899,7 @@ void check_case_conv(void) error++; } l = check_conv(res, code, 2); - if (l != 1 || res[0] != ci->f_code) { + if (l != ci->f_len || tabcmp((int *)res, ci->f_data, l)) { printf("ERROR: F\n"); error++; } @@ -3007,11 +3094,12 @@ int main(int argc, char **argv) unicode_db_path); parse_prop_list(filename); - // dump_data(unicode_db); - + // dump_unicode_data(unicode_db); build_conv_table(unicode_db); - - // dump_table(); + +#ifdef DUMP_CASE_FOLDING_SPECIAL_CASES + dump_case_folding_special_cases(unicode_db); +#endif if (!outfilename) { #ifdef USE_TEST diff --git a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/unicode_gen_def.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/unicode_gen_def.h similarity index 97% rename from packages/android-engine/android-js-engine/src/main/cpp/quickjs/unicode_gen_def.h rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/unicode_gen_def.h index 47b0e391..e7c2464e 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/quickjs/unicode_gen_def.h +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/quickjs/unicode_gen_def.h @@ -72,6 +72,7 @@ DEF(Coptic, "Copt,Qaac") DEF(Cuneiform, "Xsux") DEF(Cypriot, "Cprt") DEF(Cyrillic, "Cyrl") +DEF(Cypro_Minoan, "Cpmn") DEF(Deseret, "Dsrt") DEF(Devanagari, "Deva") DEF(Dives_Akuru, "Diak") @@ -104,6 +105,7 @@ DEF(Javanese, "Java") DEF(Kaithi, "Kthi") DEF(Kannada, "Knda") DEF(Katakana, "Kana") +DEF(Kawi, "Kawi") DEF(Kayah_Li, "Kali") DEF(Kharoshthi, "Khar") DEF(Khmer, "Khmr") @@ -138,6 +140,7 @@ DEF(Mro, "Mroo") DEF(Multani, "Mult") DEF(Myanmar, "Mymr") DEF(Nabataean, "Nbat") +DEF(Nag_Mundari, "Nagm") DEF(Nandinagari, "Nand") DEF(New_Tai_Lue, "Talu") DEF(Newa, "Newa") @@ -154,6 +157,7 @@ DEF(Old_Persian, "Xpeo") DEF(Old_Sogdian, "Sogo") DEF(Old_South_Arabian, "Sarb") DEF(Old_Turkic, "Orkh") +DEF(Old_Uyghur, "Ougr") DEF(Oriya, "Orya") DEF(Osage, "Osge") DEF(Osmanya, "Osma") @@ -192,8 +196,11 @@ DEF(Thai, "Thai") DEF(Tibetan, "Tibt") DEF(Tifinagh, "Tfng") DEF(Tirhuta, "Tirh") +DEF(Tangsa, "Tnsa") +DEF(Toto, "Toto") DEF(Ugaritic, "Ugar") DEF(Vai, "Vaii") +DEF(Vithkuqi, "Vith") DEF(Wancho, "Wcho") DEF(Warang_Citi, "Wara") DEF(Yezidi, "Yezi") diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/runner.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/runner.cpp new file mode 100644 index 00000000..68f1744d --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/runner.cpp @@ -0,0 +1,112 @@ +#include "runner.hpp" + +#include + +#include "capacitor.hpp" + +Runner::Runner(NativeInterface *native) { + this->native = native; + this->rt = JS_NewRuntime(); + JS_SetCanBlock(rt, 0); + JS_SetMaxStackSize(rt, 0); + + this->log_debug("created runner"); +} + +Runner::~Runner() { + this->log_debug("destroying runner"); + + if (!this->contexts.empty()) { + auto itr = this->contexts.begin(); + while (itr != this->contexts.end()) { + itr = this->destroy_context(itr); + } + } + + this->contexts.clear(); + + this->log_debug("freeing runtime"); + + JS_FreeRuntime(this->rt); + this->rt = nullptr; + + this->log_debug("destroyed runner"); +} + +bool Runner::has_active_timers() { + bool active = false; + + for (const auto &kv : this->contexts) { + if (kv.second->has_timers()) { + active = true; + } + } + + return active; +} + +bool Runner::has_pending_jobs() { return JS_IsJobPending(this->rt) || this->has_active_timers(); } + +void Runner::execute_pending_jobs() { + if (this->rt == nullptr) { + return; + } + + JSContext *job_ctx; + + while (JS_IsJobPending(this->rt) || this->has_active_timers()) { + int const status = JS_ExecutePendingJob(this->rt, &job_ctx); + if (status <= 0) { + if (status < 0) { + auto exception_val = JS_GetException(job_ctx); + auto err_message = JS_GetPropertyStr(job_ctx, exception_val, "message"); + const char *err_str = JS_ToCString(job_ctx, err_message); + + this->log_debug(std::string(err_str)); + + JS_FreeValue(job_ctx, exception_val); + JS_FreeCString(job_ctx, err_str); + JS_FreeValue(job_ctx, err_message); + } + } + + for (const auto &kv : this->contexts) { + if (kv.second->has_timers()) { + kv.second->run_timers(); + } + } + } +} + +Context *Runner::create_context(std::string name, CapacitorInterface *cap_api) { + auto *context = new Context(name, this->rt, this->native, cap_api); + this->contexts.insert_or_assign(name, context); + + return context; +} + +void Runner::destroy_context(std::string name) { + try { + this->log_debug("try to destroy context " + name); + auto *context = this->contexts.at(name); + delete context; + + this->contexts.erase(name); + } catch (std::exception &ex) { + this->log_debug("could not destroy context " + name); + } +} + +std::unordered_map::iterator Runner::destroy_context(std::unordered_map::iterator itr) { + try { + this->log_debug("try to destroy context " + itr->first); + auto *context = this->contexts.at(itr->first); + delete context; + + return this->contexts.erase(itr); + } catch (std::exception &ex) { + return itr; + } +} + +void Runner::log_debug(const std::string &msg) { this->native->logger(DEBUG, "Runner", msg); } diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/runner.hpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/runner.hpp new file mode 100644 index 00000000..26a97d1d --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/src/runner.hpp @@ -0,0 +1,35 @@ +#ifndef CAPACITOR_BACKGROUND_RUNNER_RUNNER_H +#define CAPACITOR_BACKGROUND_RUNNER_RUNNER_H + +#include +#include +#include +#include + +#include "./quickjs/quickjs.h" +#include "context.hpp" +#include "native.hpp" + +class Runner { + public: + JSRuntime *rt; + std::unordered_map contexts; + NativeInterface *native; + + Runner(NativeInterface *native); + ~Runner(); + + bool has_pending_jobs(); + void execute_pending_jobs(); + + Context *create_context(std::string name, CapacitorInterface *cap_api); + void destroy_context(std::string name); + std::unordered_map::iterator destroy_context(std::unordered_map::iterator delete_itr); + + void log_debug(const std::string &msg); + + private: + bool has_active_timers(); +}; + +#endif // CAPACITOR_BACKGROUND_RUNNER_RUNNER_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/CMakeLists.txt b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/CMakeLists.txt new file mode 100644 index 00000000..65204cd5 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/CMakeLists.txt @@ -0,0 +1,61 @@ +cmake_minimum_required(VERSION 3.22.1) + +set(UUID_USING_CXX20_SPAN off) + +Include(FetchContent) + +FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.0.1 +) + +FetchContent_MakeAvailable(Catch2) + +find_package(OpenSSL REQUIRED) +find_package(cpr CONFIG REQUIRED) +find_package(unofficial-sodium CONFIG REQUIRED) +find_package(fmt CONFIG REQUIRED) +find_package(nlohmann_json CONFIG REQUIRED) +find_package(stduuid CONFIG REQUIRED) + +add_executable( + EngineTests + src/native_engine/engine.cpp + src/native_engine/value.cpp + src/native_engine/errors.cpp + src/native_engine/native_interface.cpp + src/engine_tests.cpp +) + +add_executable( + ContextTests + src/native_engine/engine.cpp + src/native_engine/value.cpp + src/native_engine/errors.cpp + src/native_engine/native_interface.cpp + src/context_tests.cpp +) + +target_compile_features(EngineTests PRIVATE cxx_std_20) +target_link_libraries(EngineTests PRIVATE JSEngine) +target_link_libraries(EngineTests PRIVATE Catch2::Catch2WithMain) +target_link_libraries(EngineTests PRIVATE unofficial-sodium::sodium unofficial-sodium::sodium_config_public) +target_link_libraries(EngineTests PRIVATE fmt::fmt) +target_link_libraries(EngineTests PRIVATE stduuid) +target_link_libraries(EngineTests PRIVATE cpr::cpr) +target_link_libraries(EngineTests PRIVATE /opt/homebrew/Cellar/openssl@3/3.1.4/lib/libcrypto.a) +target_link_libraries(EngineTests PRIVATE /opt/homebrew/Cellar/openssl@3/3.1.4/lib/libssl.a) + +target_compile_features(ContextTests PRIVATE cxx_std_20) +target_link_libraries(ContextTests PRIVATE JSEngine) +target_link_libraries(ContextTests PRIVATE unofficial-sodium::sodium unofficial-sodium::sodium_config_public) +target_link_libraries(ContextTests PRIVATE Catch2::Catch2WithMain) +target_link_libraries(ContextTests PRIVATE fmt::fmt) +target_link_libraries(ContextTests PRIVATE stduuid) +target_link_libraries(ContextTests PRIVATE cpr::cpr) +target_link_libraries(ContextTests PRIVATE /opt/homebrew/Cellar/openssl@3/3.1.4/lib/libcrypto.a) +target_link_libraries(ContextTests PRIVATE /opt/homebrew/Cellar/openssl@3/3.1.4/lib/libssl.a) + +add_test(NAME EngineTests COMMAND EngineTests) +add_test(NAME ContextTests COMMAND ContextTests) \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/context_tests.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/context_tests.cpp new file mode 100644 index 00000000..0120b96a --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/context_tests.cpp @@ -0,0 +1,487 @@ +#include + +#include +#include +#include +#include + +using json = nlohmann::json; + +#include "native_engine/engine.hpp" + +TEST_CASE("test null eval", "[context]") { + std::string context_name = "io.ionic.android_js_engine"; + auto engine = new Engine(); + engine->create_context(context_name); + + auto value = engine->execute(context_name, "undefined"); + REQUIRE(value->is_null_or_undefined()); + + value = engine->execute(context_name, "const test = null; test;"); + REQUIRE(value->is_null_or_undefined()); + + delete engine; +} + +TEST_CASE("test bool eval", "[context]") { + std::string context_name = "io.ionic.android_js_engine"; + auto engine = new Engine(); + engine->create_context(context_name); + + auto value = engine->execute(context_name, "let test = (1 == 1); test;"); + REQUIRE(value->get_bool_value()); + + value = engine->execute(context_name, "test = (100 == 200); test;"); + REQUIRE(!value->get_bool_value()); + + delete engine; +} + +TEST_CASE("test integer eval", "[context]") { + std::string context_name = "io.ionic.android_js_engine"; + auto engine = new Engine(); + engine->create_context(context_name); + + auto value = engine->execute(context_name, "1 + 2;"); + REQUIRE(value->get_int_value() == 3); + + delete engine; +} + +TEST_CASE("test float eval", "[context]") { + std::string context_name = "io.ionic.android_js_engine"; + auto engine = new Engine(); + engine->create_context(context_name); + + auto value = engine->execute(context_name, "10.8 + 2.77;"); + REQUIRE(value->get_float_value() == 13.57f); + + delete engine; +} + +TEST_CASE("test string eval", "[context]") { + std::string context_name = "io.ionic.android_js_engine"; + auto engine = new Engine(); + engine->create_context(context_name); + + auto value = engine->execute(context_name, "'hello' + ' ' + 'world';"); + REQUIRE(value->get_string_value() == "hello world"); + + delete engine; +} + +TEST_CASE("test console api", "[context]") { + std::string context_name = "io.ionic.android_js_engine"; + auto engine = new Engine(); + engine->create_context(context_name); + + engine->execute(context_name, "console.log('hello world');"); + engine->execute(context_name, "console.info('this message is for informational purposes');"); + engine->execute(context_name, "console.warn('this is a warning message');"); + engine->execute(context_name, "console.error('a problem has occurred');"); + engine->execute(context_name, "console.debug('this is a debugging statement');"); + + delete engine; +} + +TEST_CASE("test event listeners", "[context]") { + auto engine = new Engine(); + + auto test_thead = std::thread([engine] { + std::promise future1; + std::promise future2; + std::promise future3; + std::promise future4; + + std::function func_1 = [&future1](json args) { + future1.set_value(1); + return nullptr; + }; + + std::function func_2 = [&future2](json args) { + future2.set_value(1); + return nullptr; + }; + + std::function func_3 = [&future3](json args) { + future3.set_value(args); + return nullptr; + }; + + std::function func_4 = [&future4](json args) { + future4.set_value(1); + return nullptr; + }; + + std::string context_name = "io.ionic.android_js_engine"; + engine->create_context(context_name); + engine->register_function(context_name, "successCallback", func_1); + engine->register_function(context_name, "altSuccessCallback", func_2); + engine->register_function(context_name, "successCallbackDetails", func_3); + engine->register_function(context_name, "successCallbackFunction", func_4); + + // setting a basic event listener + engine->execute(context_name, "addEventListener('myEvent', () => { successCallback(); });"); + engine->dispatch_event(context_name, "myEvent", nullptr); + + REQUIRE(future1.get_future().get() == 1); + + engine->execute(context_name, "addEventListener('myEvent', () => { altSuccessCallback(); });"); + engine->dispatch_event(context_name, "myEvent", nullptr); + + REQUIRE(future2.get_future().get() == 1); + + // basic event listener with details + engine->execute(context_name, "addEventListener('myEventDetails', (details) => { successCallbackDetails(details); });"); + + json details; + details["name"] = "John Doe"; + + engine->dispatch_event(context_name, "myEventDetails", details); + + auto value = future3.get_future().get(); + + REQUIRE(value["name"] == "John Doe"); + + // basic event listener with registered global function as callback arg + engine->execute(context_name, "addEventListener('myEventCallback', (resolve) => { resolve() });"); + + json args; + json callbacks; + + callbacks["resolve"] = "__cbr::successCallbackFunction"; + args["callbacks"] = callbacks; + + engine->dispatch_event(context_name, "myEventCallback", args); + + REQUIRE(future4.get_future().get() == 1); + + engine->stop(); + }); + + engine->start(); + test_thead.join(); + + delete engine; +} + +TEST_CASE("test error handling", "[context]") { + auto engine = new Engine(); + + auto test_thead = std::thread([engine] { + std::string context_name = "io.ionic.android_js_engine"; + engine->create_context(context_name); + + try { + engine->execute(context_name, "() => { throw new Error('this method has an error'); }();"); + REQUIRE(false); + } catch (JavaScriptException& ex) { + std::string error_message = ex.what(); + REQUIRE(error_message.find("JS Exception") != std::string::npos); + } + + try { + engine->execute(context_name, "addEventListener("); + REQUIRE(false); + } catch (JavaScriptException& ex) { + std::string error_message = ex.what(); + REQUIRE(error_message.find("JS Exception") != std::string::npos); + } + + try { + engine->execute(context_name, "addEventListener('myThrowingEvent', () => { throw new Error('this event throws an error') })"); + engine->dispatch_event(context_name, "myThrowingEvent", nullptr); + } catch (JavaScriptException& ex) { + std::string error_message = ex.what(); + REQUIRE(error_message.find("JS Exception") != std::string::npos); + } + + // test handling C++ exceptions + std::promise future; + + std::function func = [&future](json args) { + throw std::invalid_argument("a problem occurred in C++"); + return nullptr; + }; + + try { + engine->register_function(context_name, "exceptionCallback", func); + engine->execute(context_name, "addEventListener('myThrowingJVMEvent', () => { exceptionCallback(); })"); + engine->dispatch_event(context_name, "myThrowingJVMEvent", nullptr); + } catch (JavaScriptException& ex) { + std::string error_message = ex.what(); + REQUIRE(error_message.find("JS Exception") != std::string::npos); + } + + engine->stop(); + }); + + engine->start(); + test_thead.join(); + + delete engine; +} + +TEST_CASE("test set timeout", "[context]") { + auto engine = new Engine(); + + auto test_thread = std::thread([engine] { + std::string context_name = "io.ionic.android_js_engine"; + engine->create_context(context_name); + + std::promise promise1; + std::promise promise2; + + std::function func_1 = [&promise1](json args) { + promise1.set_value(1); + return nullptr; + }; + + std::function func_2 = [&promise2](json args) { + promise2.set_value(1); + return nullptr; + }; + + engine->register_function(context_name, "timeoutCallback", func_1); + engine->register_function(context_name, "cancelTimeoutCallback", func_2); + + auto ret = engine->execute(context_name, "setTimeout(() => { timeoutCallback(); }, 2000)"); + auto timer_id = ret->get_int_value(); + + REQUIRE(timer_id > 0); + + auto future1 = promise1.get_future(); + + auto status = future1.wait_for(std::chrono::seconds(3)); + if (status == std::future_status::timeout) { + FAIL("timer did not fire"); + } + + REQUIRE(future1.get() == 1); + + ret = engine->execute(context_name, "setTimeout(() => { cancelTimeoutCallback() }, 4000)"); + timer_id = ret->get_int_value(); + + REQUIRE(timer_id > 0); + + engine->execute(context_name, fmt::format("clearTimeout({});", timer_id)); + + auto future2 = promise2.get_future(); + + status = future2.wait_for(std::chrono::seconds(5)); + if (status == std::future_status::timeout) { + SUCCEED("timer did not fire after canceled"); + } else { + FAIL("timer was not canceled"); + } + + engine->stop(); + }); + + engine->start(); + test_thread.join(); + + delete engine; +} + +TEST_CASE("test set interval", "[context]") { + auto engine = new Engine(); + + auto test_thread = std::thread([engine] { + std::string context_name = "io.ionic.android_js_engine"; + engine->create_context(context_name); + + std::promise promise1; + std::promise promise2; + + int calls = 0; + + std::function func_1 = [&calls](json args) { + calls++; + return nullptr; + }; + + engine->register_function(context_name, "intervalCallback", func_1); + auto ret = engine->execute(context_name, "setInterval(() => { intervalCallback() }, 2000)"); + auto timer_id = ret->get_int_value(); + + REQUIRE(timer_id > 0); + + auto future1 = promise1.get_future(); + auto status = future1.wait_for(std::chrono::seconds(9)); + if (status == std::future_status::timeout) { + REQUIRE(calls == 4); + } else { + FAIL("???"); + } + + engine->execute(context_name, fmt::format("clearInterval({});", timer_id)); + + auto future2 = promise2.get_future(); + status = future2.wait_for(std::chrono::seconds(3)); + if (status == std::future_status::timeout) { + REQUIRE(calls == 4); + } else { + FAIL("???"); + } + + engine->stop(); + }); + + engine->start(); + test_thread.join(); + + delete engine; +} + +TEST_CASE("test fetch", "[context]") { + auto engine = new Engine(); + + auto test_thread = std::thread([engine] { + std::string context_name = "io.ionic.android_js_engine"; + engine->create_context(context_name); + + std::promise success_promise; + std::promise options_success_promise; + std::promise failure_promise; + + std::function callback_1 = [&success_promise](json args) { + success_promise.set_value(args); + return nullptr; + }; + + std::function callback_2 = [&options_success_promise](json args) { + options_success_promise.set_value(args); + return nullptr; + }; + + std::function callback_3 = [&failure_promise](json args) { + failure_promise.set_value(args); + return nullptr; + }; + + engine->register_function(context_name, "successCallback", callback_1); + engine->register_function(context_name, "successCallback2", callback_2); + engine->register_function(context_name, "failureCallback", callback_3); + + std::string basic_fetch_example = + "fetch('https://jsonplaceholder.typicode.com/todos/1')" + ".then(response => response.json())" + ".then(json => { successCallback(json); })" + ".catch(err => { console.error(err); });"; + + engine->execute(context_name, basic_fetch_example); + + auto future1 = success_promise.get_future(); + auto status = future1.wait_for(std::chrono::seconds(5)); + if (status == std::future_status::timeout) { + FAIL("could not get request"); + } + + auto response_data = future1.get(); + auto title = response_data["title"].template get(); + REQUIRE(title == "delectus aut autem"); + + std::string basic_fetch_options_example = + "fetch('https://jsonplaceholder.typicode.com/posts', {" + "method: 'POST'," + "body: JSON.stringify({" + "title: 'foo'," + "body: 'bar'," + "userId: 1," + "})," + "headers: {" + "'Content-type': 'application/json; charset=UTF-8'," + "}" + "})" + ".catch(err => { console.error(err); })" + ".then(response => response.json())" + ".then(json => { successCallback2(json); })"; + + engine->execute(context_name, basic_fetch_options_example); + + auto future2 = options_success_promise.get_future(); + status = future2.wait_for(std::chrono::seconds(5)); + if (status == std::future_status::timeout) { + FAIL("could not get request"); + } + + response_data = future2.get(); + auto body = response_data["body"].template get(); + REQUIRE(body == "bar"); + + std::string fetch_failure_example = + "fetch('https://blablabla.fake/todos/1')" + ".catch(err => { console.error(err); failureCallback(err); });"; + + engine->execute(context_name, fetch_failure_example); + + auto future3 = failure_promise.get_future(); + status = future3.wait_for(std::chrono::seconds(3)); + if (status == std::future_status::timeout) { + FAIL("request failure was not caught"); + } + + response_data = future3.get(); + SUCCEED(response_data.dump()); + + engine->stop(); + }); + + engine->start(); + test_thread.join(); + + delete engine; +} + +TEST_CASE("test crypto", "[context]") { + auto engine = new Engine(); + + std::string context_name = "io.ionic.android_js_engine"; + engine->create_context(context_name); + + auto value = engine->execute(context_name, "const array = new Uint32Array(10); crypto.getRandomValues(array); array;"); + auto json_object = value->get_json_object(); + auto obj = json_object.get>(); + + REQUIRE(obj.size() == 10); + + value = engine->execute(context_name, "crypto.randomUUID();"); + auto random_string = value->get_string_value(); + + REQUIRE(random_string.length() == 36); + + delete engine; +} + +TEST_CASE("test text encoder", "[context]") { + auto engine = new Engine(); + + std::string context_name = "io.ionic.android_js_engine"; + engine->create_context(context_name); + + auto value = engine->execute(context_name, "const encoder = new TextEncoder(); encoder.encode('€');"); + auto json_object = value->get_json_object(); + auto obj = json_object.get>(); + + REQUIRE(obj["0"] == 226); + REQUIRE(obj["1"] == 130); + REQUIRE(obj["2"] == 172); + + delete engine; +} + +TEST_CASE("test text decoder", "[context]") { + auto engine = new Engine(); + + std::string context_name = "io.ionic.android_js_engine"; + engine->create_context(context_name); + + auto value = engine->execute(context_name, "const win1251decoder = new TextDecoder(\"windows-1251\"); win1251decoder.decode(new Uint8Array([ 207, 240, 232, 226, 229, 242, 44, 32, 236, 232, 240, 33]));"); + REQUIRE(value->get_string_value() == "Привет, мир!"); + + // value = engine->execute(context_name, "const decoder = new TextDecoder(); decoder.decode(new Uint8Array([240, 160, 174, 183]));"); + // REQUIRE(value->get_string_value() == "\UD842\UDFB7"); + + delete engine; +} \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/engine_tests.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/engine_tests.cpp new file mode 100644 index 00000000..4b044ca7 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/engine_tests.cpp @@ -0,0 +1,64 @@ +#include + +#include +#include + +#include "native_engine/engine.hpp" + +int get_random_number() { + std::random_device rnd_device; + std::default_random_engine rnd_engine(rnd_device()); + std::uniform_int_distribution uniform_dist(20, 40); + + return uniform_dist(rnd_engine); +} + +TEST_CASE("runner create and destroy", "[test]") { + auto engine = new Engine(); + + auto stop_thread = std::thread([engine] { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + engine->stop(); + }); + + engine->start(); + stop_thread.join(); + + delete engine; +} + +TEST_CASE("runner context create and destroy", "[runner]") { + auto engine = new Engine(); + + auto stop_thread = std::thread([engine] { + std::string context_name = "io.ionic.android_js_engine"; + engine->create_context(context_name); + engine->stop(); + }); + + engine->start(); + stop_thread.join(); + + delete engine; +} + +TEST_CASE("runner create and destroy multiple contexts", "[runner]") { + auto engine = new Engine(); + + auto spawn_thread = std::thread([engine] { + int rnd = get_random_number(); + + for (int i = 0; i < rnd; i++) { + auto context_name = fmt::format("context #{}", i + 1); + engine->create_context(context_name); + } + + fmt::println("Created {} contexts", rnd); + engine->stop(); + }); + + engine->start(); + spawn_thread.join(); + + delete engine; +} \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/engine.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/engine.cpp new file mode 100644 index 00000000..b471f6e1 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/engine.cpp @@ -0,0 +1,84 @@ +#include "engine.hpp" + +#include + +#include "native_interface.hpp" + +Engine::Engine() { + auto native = new Native(); + this->runner = new Runner(native); +} + +Engine::~Engine() { delete this->runner; } + +void Engine::create_context(const std::string& name) { this->runner->create_context(name); } + +void Engine::destroy_context(const std::string& name) { this->runner->destroy_context(name); } + +Value* Engine::execute(const std::string& name, const std::string& code) { + auto context = this->runner->contexts[name]; + if (context == nullptr) { + throw std::invalid_argument("context not found"); + } + auto ret = context->evaluate(code, true); + + if (JS_IsException(ret)) { + JSValue const exception = JS_GetException(context->qjs_context); + + JSValue const err_message = JS_GetPropertyStr(context->qjs_context, exception, "message"); + const char* err_message_c_str = JS_ToCString(context->qjs_context, err_message); + std::string err_message_str = std::string(err_message_c_str); + + JS_FreeValue(context->qjs_context, exception); + JS_FreeValue(context->qjs_context, err_message); + JS_FreeCString(context->qjs_context, err_message_c_str); + + throw JavaScriptException(err_message_str.c_str()); + } + + auto json_c_string = JS_ToCString(context->qjs_context, ret); + auto json_string = std::string(json_c_string); + + JS_FreeCString(context->qjs_context, json_c_string); + JS_FreeValue(context->qjs_context, ret); + + return new Value(json_string); +} + +void Engine::start() { this->runner->start(); } + +void Engine::stop() { this->runner->stop(); } + +void Engine::register_function(const std::string& context_name, const std::string& func_name, std::function func) { + auto context = this->runner->contexts[context_name]; + if (context == nullptr) { + throw std::invalid_argument("context not found"); + } + + std::any wrapped_function = func; + + context->register_function(func_name, wrapped_function); +} + +Value* Engine::dispatch_event(const std::string& name, const std::string& event, nlohmann::json args) { + auto context = this->runner->contexts[name]; + if (context == nullptr) { + throw std::invalid_argument("context not found"); + } + + // JSON to JSValue + JSValue js_object; + + if (args != nullptr) { + auto json_string = args.dump(); + js_object = JS_ParseJSON(context->qjs_context, json_string.c_str(), json_string.length(), ""); + } else { + js_object = JS_NewObject(context->qjs_context); + } + + context->dispatch_event(event, js_object); + + JS_FreeValue(context->qjs_context, js_object); + + return nullptr; +} \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/engine.hpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/engine.hpp new file mode 100644 index 00000000..3345f775 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/engine.hpp @@ -0,0 +1,27 @@ +#ifndef ENGINE_H +#define ENGINE_H + +#include "../../../src/context.hpp" +#include "../../../src/runner.hpp" +#include "errors.hpp" +#include "value.hpp" + +class Engine { + public: + Runner* runner; + + std::thread thread; + + Engine(); + ~Engine(); + + void create_context(const std::string& name); + void destroy_context(const std::string& name); + Value* execute(const std::string& name, const std::string& code); + Value* dispatch_event(const std::string& name, const std::string& event, nlohmann::json args); + void register_function(const std::string& context_name, const std::string& func_name, std::function func); + void start(); + void stop(); +}; + +#endif // ENGINE_H \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/errors.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/errors.cpp new file mode 100644 index 00000000..cb544424 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/errors.cpp @@ -0,0 +1,14 @@ +#include "errors.hpp" + +JavaScriptException::JavaScriptException(const char* js_exception) { + this->js_exception = js_exception; + this->message = "JS Exception: " + std::string(js_exception); +} + +FetchException::FetchException(const char* fetch_exception) { + this->fetch_exception = fetch_exception; + this->message = "Fetch Exception: " + std::string(fetch_exception); +} + +const char* JavaScriptException::what() const throw() { return this->message.c_str(); } +const char* FetchException::what() const throw() { return this->message.c_str(); } \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/errors.hpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/errors.hpp new file mode 100644 index 00000000..c120e352 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/errors.hpp @@ -0,0 +1,27 @@ +#ifndef ERRORS_H +#define ERRORS_H + +#include +#include + +class JavaScriptException : public std::exception { + public: + JavaScriptException(const char* js_exception); + const char* what() const throw(); + + private: + const char* js_exception; + std::string message; +}; + +class FetchException : public std::exception { + public: + FetchException(const char* fetch_exception); + const char* what() const throw(); + + private: + const char* fetch_exception; + std::string message; +}; + +#endif // ERRORS_H \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/native_interface.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/native_interface.cpp new file mode 100644 index 00000000..7eed7876 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/native_interface.cpp @@ -0,0 +1,152 @@ +#define BOOST_NETWORK_ENABLE_HTTPS + +#include "native_interface.hpp" + +#include +#include +#include + +#include +#include +#include + +Native::Native() { + if (sodium_init() < 0) { + this->logger(LoggerLevel::WARN, "[NATIVE SYSTEM]", "libsodium could not be initialized"); + } + + this->logger_str[LoggerLevel::INFO] = "INFO"; + this->logger_str[LoggerLevel::DEBUG] = "DEBUG"; + this->logger_str[LoggerLevel::WARN] = "WARN"; + this->logger_str[LoggerLevel::ERROR] = "ERR"; +} + +Native::~Native() {} + +void Native::logger(LoggerLevel level, const std::string& tag, const std::string& messages) { fmt::println("{0} [{1}] {2}", this->logger_str[level], tag, messages); } + +void Native::register_native_function(const std::string& func_name, std::any func_obj) { + auto unwrapped_func_obj = std::any_cast>(func_obj); + this->functions[func_name] = unwrapped_func_obj; +} + +bool Native::has_native_function(const std::string& func_name) { return this->functions.find(func_name) != this->functions.end(); } + +JSValue Native::invoke_native_function(const std::string& func_name, JSContext* ctx, JSValue args) { + JSValue js_ret = JS_UNDEFINED; + nlohmann::json arg_json; + + auto func = functions.at(func_name); + + if (!JS_IsNull(args) && !JS_IsUndefined(args)) { + auto arg_json_js = JS_JSONStringify(ctx, args, JS_UNDEFINED, JS_UNDEFINED); + auto arg_c_json = JS_ToCString(ctx, arg_json_js); + + arg_json = nlohmann::json::parse(std::string(arg_c_json)); + + JS_FreeCString(ctx, arg_c_json); + JS_FreeValue(ctx, arg_json_js); + } + + try { + auto json_ret = func(arg_json); + + if (json_ret != nullptr && !json_ret.empty()) { + auto json_str = json_ret.dump(); + js_ret = JS_ParseJSON(ctx, json_str.c_str(), json_str.length(), ""); + } + + return js_ret; + } catch (std::exception& ex) { + auto exception = JS_NewError(ctx); + JS_SetPropertyStr(ctx, exception, "message", JS_NewString(ctx, ex.what())); + + return JS_Throw(ctx, exception); + } +} + +std::string Native::crypto_get_random_uuid() { + // WARNING: Just for testing purposes only + std::random_device rnd_device; + uuids::basic_uuid_random_generator generator{rnd_device}; + + uuids::uuid id = generator(); + + return uuids::to_string(id); +} + +std::vector Native::crypto_get_random(size_t size) { + uint8_t* random_buf = new uint8_t[size]; + randombytes_buf(random_buf, size); + + return std::vector(random_buf, random_buf + int(size)); +} + +int Native::get_random_hash() { + int hash = std::hash{}(crypto_get_random_uuid()); + return abs(hash); +} + +NativeResponse Native::fetch(NativeRequest native_request) { + NativeResponse native_response; + + try { + cpr::Response res; + + cpr::Header headers = cpr::Header{{}}; + for (const auto& kv : native_request.headers) { + headers[kv.first] = kv.second; + } + + if (native_request.method == "GET") { + res = cpr::Get(cpr::Url(native_request.url.c_str()), headers); + } else if (native_request.method == "POST") { + res = cpr::Post(cpr::Url(native_request.url.c_str()), cpr::Body(std::string(native_request.body.begin(), native_request.body.end())), headers); + } else { + throw new FetchException("invalid HTTP Method"); + } + + auto body_data = res.text.data(); + + if (res.status_code == 0) { + native_response.ok = false; + native_response.status = res.status_code; + native_response.url = native_request.url; + native_response.error = "invalid network request"; + + } else { + native_response.ok = true; + native_response.status = res.status_code; + native_response.url = native_request.url; + native_response.data = std::vector(&body_data[0], &body_data[res.text.length()]); + } + } catch (std::exception& ex) { + native_response.ok = false; + native_response.status = 500; + native_response.error = std::string(ex.what()); + } + + // httplib::Client client(fmt::format("{}//{}", url->get_protocol(), url->get_host())); + // client.set_ca_cert_path("/opt/homebrew/etc/openssl@3/cert.pem"); + // auto path = url->get_pathname(); + + // if (auto res = client.Get(std::string(path))) { + // auto body_data = res->body.data(); + + // response.status = res->status; + // response.data = std::vector(&body_data[0], &body_data[res->body.length()]); + // response.url = request.url; + // response.ok = true; + // } else { + // response.ok = false; + // response.status = res->status; + // auto error_message = httplib::to_string(res.error()); + // response.error = error_message; + // } + + return native_response; +} + +std::string Native::byte_array_to_str(uint8_t* arr, size_t size, const std::string& encoding) { return std::string((char*)arr); } + +std::vector Native::string_to_byte_array(std::string str) { return std::vector(str.begin(), str.end()); } \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/native_interface.hpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/native_interface.hpp new file mode 100644 index 00000000..2289321c --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/native_interface.hpp @@ -0,0 +1,33 @@ +#ifndef NATIVE_INTERFACE_H +#define NATIVE_INTERFACE_H + +#include + +#include +#include + +#include "../../../src/native.hpp" +#include "errors.hpp" + +class Native : public NativeInterface { + public: + Native(); + ~Native(); + + virtual void logger(LoggerLevel level, const std::string& tag, const std::string& messages); + virtual void register_native_function(const std::string& func_name, std::any func_obj); + virtual bool has_native_function(const std::string& func_name); + virtual JSValue invoke_native_function(const std::string& func_name, JSContext* ctx, JSValue args); + virtual std::string crypto_get_random_uuid(); + std::vector crypto_get_random(size_t size); + virtual int get_random_hash(); + virtual NativeResponse fetch(NativeRequest request); + virtual std::string byte_array_to_str(uint8_t* arr, size_t size, const std::string& encoding); + virtual std::vector string_to_byte_array(std::string str); + + private: + std::unordered_map logger_str; + std::unordered_map> functions; +}; + +#endif // NATIVE_INTERFACE_H \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/value.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/value.cpp new file mode 100644 index 00000000..917b99fa --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/value.cpp @@ -0,0 +1,68 @@ +#include "value.hpp" + +using json = nlohmann::json; + +Value::Value(const std::string& input_json) { this->json_str = input_json; } + +int Value::get_int_value() { + auto val = this->get_js_number(); + if (val == NULL) { + return NULL; + } + + return (int)val; +} + +float Value::get_float_value() { return this->get_js_number(); } + +std::string Value::get_string_value() { + if (this->check_if_null_or_undefined()) { + return NULL; + } + + return this->json_str; +} + +bool Value::is_null_or_undefined() { return this->check_if_null_or_undefined(); } + +bool Value::get_bool_value() { + if (this->check_if_null_or_undefined()) { + return NULL; + } + + if (this->json_str == "false" || this->json_str == "0" || this->json_str.empty()) { + return false; + } + + return true; +} + +double Value::get_js_number() { + if (this->check_if_null_or_undefined()) { + return NULL; + } + + return std::stod(this->json_str); +} + +json Value::get_json_object() { + auto json_obj = json::parse(this->json_str); + + if (this->check_if_null_or_undefined()) { + return nullptr; + } + + if (!json_obj.is_object()) { + return nullptr; + } + + return json_obj; +} + +bool Value::check_if_null_or_undefined() { + if (this->json_str == "undefined" || this->json_str == "null") { + return true; + } + + return false; +} \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/value.hpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/value.hpp new file mode 100644 index 00000000..f8650754 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/tests/src/native_engine/value.hpp @@ -0,0 +1,31 @@ +#ifndef VALUE_H +#define VALUE_H + +#include +#include +#include +#include + +class Value { + public: + Value(const std::string& input_json); + ~Value(); + + int get_int_value(); + bool get_bool_value(); + float get_float_value(); + std::string get_string_value(); + + nlohmann::json get_json_array(); + nlohmann::json get_json_object(); + + bool is_null_or_undefined(); + + private: + std::string json_str; + + bool check_if_null_or_undefined(); + double get_js_number(); +}; + +#endif // VALUE_H \ No newline at end of file diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/vcpkg-configuration.json b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/vcpkg-configuration.json new file mode 100644 index 00000000..fa4c3bac --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/vcpkg-configuration.json @@ -0,0 +1,14 @@ +{ + "default-registry": { + "kind": "git", + "baseline": "7a6f366cefd27210f6a8309aed10c31104436509", + "repository": "https://github.com/microsoft/vcpkg" + }, + "registries": [ + { + "kind": "artifact", + "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", + "name": "microsoft" + } + ] +} diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/vcpkg.json b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/vcpkg.json new file mode 100644 index 00000000..0b59b65e --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/js-engine/vcpkg.json @@ -0,0 +1,10 @@ +{ + "dependencies": [ + "cpr", + "fmt", + "libsodium", + "nlohmann-json", + "openssl", + "stduuid" + ] +} diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_android_interface.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_android_interface.cpp new file mode 100644 index 00000000..3c6b9a06 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_android_interface.cpp @@ -0,0 +1,342 @@ +#include "native_android_interface.h" + +#include + +#include "java_errors.h" + +void write_to_logcat(android_LogPriority priority, const char *tag, const char *message) { __android_log_write(priority, tag, message); } + +NativeAndroidInterface::NativeAndroidInterface(JNIEnv *env) { this->java = new Java(env); } + +NativeAndroidInterface::~NativeAndroidInterface() { delete this->java; } + +void NativeAndroidInterface::logger(LoggerLevel level, const std::string &tag, const std::string &messages) { + android_LogPriority priority = ANDROID_LOG_DEFAULT; + + switch (level) { + case LoggerLevel::INFO: + priority = ANDROID_LOG_INFO; + break; + case LoggerLevel::DEBUG: + priority = ANDROID_LOG_DEBUG; + break; + case LoggerLevel::ERROR: + priority = ANDROID_LOG_ERROR; + break; + case LoggerLevel::WARN: + priority = ANDROID_LOG_WARN; + break; + } + + write_to_logcat(priority, tag.c_str(), messages.c_str()); +} + +void NativeAndroidInterface::register_native_function(const std::string &func_name, std::any func_obj) { + auto unwrapped_func_obj = std::any_cast(func_obj); + this->registered_functions.insert_or_assign(func_name, unwrapped_func_obj); +} + +bool NativeAndroidInterface::has_native_function(const std::string &func_name) { return this->registered_functions.find(func_name) != this->registered_functions.end(); } + +JSValue NativeAndroidInterface::invoke_native_function(const std::string &func_name, JSContext *ctx, JSValue args) { + auto java_function_obj = this->registered_functions.at(func_name); + + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto java_function_class = env->GetObjectClass(java_function_obj); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + auto java_method = env->GetMethodID(java_function_class, "run", "()V"); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + if (!JS_IsNull(args) && !JS_IsUndefined(args)) { + std::string json_string; + + if (JS_IsError(ctx, args)) { + auto error_object = JS_NewObject(ctx); + + auto error_name = JS_GetPropertyStr(ctx, args, "name"); + auto error_message = JS_GetPropertyStr(ctx, args, "message"); + + JS_SetPropertyStr(ctx, error_object, "name", error_name); + JS_SetPropertyStr(ctx, error_object, "message", error_message); + + auto json_string_obj = JS_JSONStringify(ctx, error_object, JS_UNDEFINED, JS_UNDEFINED); + auto json_c_string = JS_ToCString(ctx, json_string_obj); + + json_string = std::string(json_c_string); + + JS_FreeCString(ctx, json_c_string); + JS_FreeValue(ctx, json_string_obj); + JS_FreeValue(ctx, error_object); + } else { + auto json_string_obj = JS_JSONStringify(ctx, args, JS_UNDEFINED, JS_UNDEFINED); + auto json_c_str = JS_ToCString(ctx, json_string_obj); + + json_string = std::string(json_c_str); + + JS_FreeCString(ctx, json_c_str); + JS_FreeValue(ctx, json_string_obj); + } + + jstring json_j_string = env->NewStringUTF(json_string.c_str()); + + // create a JSONObject + jclass json_object_class = env->FindClass("org/json/JSONObject"); + jmethodID json_object_constructor = env->GetMethodID(json_object_class, "", "(Ljava/lang/String;)V"); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + jobject json_object = env->NewObject(json_object_class, json_object_constructor, json_j_string); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + jfieldID args_field = env->GetFieldID(java_function_class, "jsFunctionArgs", "Lorg/json/JSONObject;"); + env->SetObjectField(java_function_obj, args_field, json_object); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + } + + env->CallVoidMethod(java_function_obj, java_method); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + return JS_UNDEFINED; +} + +std::string NativeAndroidInterface::crypto_get_random_uuid() { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto *str = (jstring)env->CallStaticObjectMethod(this->java->web_api_class, this->java->web_api_cryptoRandomUUID_method); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + const auto *c_str = env->GetStringUTFChars(str, nullptr); + + std::string return_string(c_str); + env->ReleaseStringUTFChars(str, c_str); + + return return_string; +} + +std::vector NativeAndroidInterface::crypto_get_random(size_t size) { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto random_vector = std::vector(size); + + auto random_bytes = static_cast(env->CallStaticObjectMethod(this->java->web_api_class, this->java->web_api_cryptoGetRandom_method, size)); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + auto random = env->GetByteArrayElements(random_bytes, nullptr); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + for (int i = 0; i < size; i++) { + random_vector[i] = random[i]; + } + + env->ReleaseByteArrayElements(random_bytes, random, 0); + + return random_vector; +} + +int NativeAndroidInterface::get_random_hash() { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + const int unique = env->CallStaticIntMethod(this->java->web_api_class, this->java->web_api_randomHashCode_method); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + return unique; +} + +jobject NativeAndroidInterface::native_request_to_native_js_fetch_options(JNIEnv *env, NativeRequest request) { + auto http_method_j = env->NewStringUTF(request.method.c_str()); + jbyteArray byte_array = nullptr; + + if (!request.body.empty()) { + byte_array = env->NewByteArray(request.body.size()); + env->SetByteArrayRegion(byte_array, 0, request.body.size(), reinterpret_cast(request.body.data())); + } + + // creating HashMap + jclass hash_map_class = env->FindClass("java/util/HashMap"); + jmethodID hash_map_constructor = env->GetMethodID(hash_map_class, "", "(I)V"); + jobject headers_j = env->NewObject(hash_map_class, hash_map_constructor, (jsize)request.headers.size()); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + jmethodID hash_map_put = env->GetMethodID(hash_map_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + for (const auto &kv : request.headers) { + auto key_j = env->NewStringUTF(kv.first.c_str()); + auto value_j = env->NewStringUTF(kv.second.c_str()); + + env->CallObjectMethod(headers_j, hash_map_put, key_j, value_j); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + } + + env->DeleteLocalRef(hash_map_class); + + // create native js fetch option + jobject fetch_options_j = env->NewObject(this->java->native_js_fetch_options_class, this->java->native_js_fetch_options_constructor, http_method_j, headers_j, byte_array); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + auto return_fetch_options_j = env->NewGlobalRef(fetch_options_j); + + env->DeleteLocalRef(fetch_options_j); + + return return_fetch_options_j; +} + +NativeResponse NativeAndroidInterface::native_js_response_to_native_response(JNIEnv *env, jobject native_js_response) { + NativeResponse response; + + auto j_ok = env->GetBooleanField(native_js_response, this->java->native_js_response_ok_field); + auto j_status = env->GetIntField(native_js_response, this->java->native_js_response_status_field); + auto *j_url = (jstring)env->GetObjectField(native_js_response, this->java->native_js_response_url_field); + auto *j_data = static_cast(env->GetObjectField(native_js_response, this->java->native_js_response_data_field)); + auto *j_err = (jstring)env->GetObjectField(native_js_response, this->java->native_js_response_error_field); + + response.status = (int)j_status; + response.ok = (bool)j_ok; + response.url = env->GetStringUTFChars(j_url, 0); + + if (j_data != nullptr) { + auto length = env->GetArrayLength(j_data); + auto data_arr = env->GetByteArrayElements(j_data, 0); + + std::vector buffer(length); + + for (int i = 0; i < length; i++) { + buffer[i] = data_arr[i]; + } + + env->ReleaseByteArrayElements(j_data, data_arr, 0); + + response.data = buffer; + } + + if (j_err != nullptr) { + response.error = env->GetStringUTFChars(j_err, 0); + } + + return response; +} + +NativeResponse NativeAndroidInterface::fetch(NativeRequest request) { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + NativeResponse native_response; + + jstring url = env->NewStringUTF(request.url.c_str()); + jobject fetch_options = this->native_request_to_native_js_fetch_options(env, request); + + jobject response = env->CallStaticObjectMethod(this->java->web_api_class, this->java->web_api_fetch_method, url, fetch_options); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + native_response = this->native_js_response_to_native_response(env, response); + + return native_response; +} + +std::string NativeAndroidInterface::byte_array_to_str(uint8_t *arr, size_t size, const std::string &encoding) { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto *j_encoding = env->NewStringUTF(encoding.c_str()); + jbyteArray byte_array = env->NewByteArray(size); + + env->SetByteArrayRegion(byte_array, 0, size, reinterpret_cast(arr)); + + auto *str_j = (jstring)env->CallStaticObjectMethod(this->java->web_api_class, this->java->web_api_byteArrayToString_method, byte_array, j_encoding); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + const char *c_str = env->GetStringUTFChars(str_j, nullptr); + + auto str = std::string(c_str); + + env->ReleaseStringUTFChars(str_j, c_str); + + return str; +} + +std::vector NativeAndroidInterface::string_to_byte_array(std::string str) { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + jstring j_string = env->NewStringUTF(str.c_str()); + auto *byte_array = static_cast(env->CallStaticObjectMethod(this->java->web_api_class, this->java->web_api_stringToByteArray_method, j_string)); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + auto length = env->GetArrayLength(byte_array); + auto arr = env->GetByteArrayElements(byte_array, 0); + + auto vector_bytes = std::vector(length); + for (int i = 0; i < length; i++) { + vector_bytes[i] = arr[i]; + } + + env->ReleaseByteArrayElements(byte_array, arr, 0); + + return vector_bytes; +} diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_android_interface.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_android_interface.h new file mode 100644 index 00000000..d0f28588 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_android_interface.h @@ -0,0 +1,33 @@ +#ifndef ANDROID_JS_ENGINE_NATIVE_ANDROID_INTERFACE_H +#define ANDROID_JS_ENGINE_NATIVE_ANDROID_INTERFACE_H + +#include +#include "./js-engine/src/native.hpp" +#include "java.h" + +class NativeAndroidInterface : public NativeInterface { +public: + NativeAndroidInterface(JNIEnv *env); + ~NativeAndroidInterface(); + + virtual void logger(LoggerLevel level, const std::string& tag, const std::string& messages); + virtual void register_native_function(const std::string& func_name, std::any func_obj); + virtual bool has_native_function(const std::string& func_name); + virtual JSValue invoke_native_function(const std::string& func_name, JSContext* ctx, JSValue args); + virtual std::string crypto_get_random_uuid(); + virtual std::vector crypto_get_random(size_t size); + virtual int get_random_hash(); + virtual NativeResponse fetch(NativeRequest request); + virtual std::string byte_array_to_str(uint8_t* arr, size_t size, const std::string& encoding); + virtual std::vector string_to_byte_array(std::string str); + + std::unordered_map registered_functions; + +private: + Java *java; + jobject native_request_to_native_js_fetch_options(JNIEnv *env, NativeRequest request); + NativeResponse native_js_response_to_native_response(JNIEnv *env, jobject native_js_response); +}; + + +#endif //ANDROID_JS_ENGINE_NATIVE_ANDROID_INTERFACE_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_capacitor_interface.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_capacitor_interface.cpp new file mode 100644 index 00000000..d46f6604 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_capacitor_interface.cpp @@ -0,0 +1,199 @@ +#include "native_capacitor_interface.h" + +#include "java_errors.h" +#include "js-engine/src/capacitor-api/api_device.h" + +NativeCapacitorInterface::NativeCapacitorInterface(JNIEnv *env, jobject api) { + this->java = new Java(env); + this->api = api; +} + +NativeCapacitorInterface::~NativeCapacitorInterface() { + auto *env = this->java->getEnv(); + if (env == nullptr) { + return; + } + + env->DeleteGlobalRef(this->api); + this->api = nullptr; +} + +// Device API +std::string NativeCapacitorInterface::device_api_getBatteryStatus() { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto *device = env->GetObjectField(this->api, this->java->capacitor_api_device_field); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + auto *json_str_j = (jstring)env->CallObjectMethod(device, this->java->capacitor_api_device_getBatteryStatus_method); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + const auto *json_str_c = env->GetStringUTFChars(json_str_j, nullptr); + std::string json_str(json_str_c); + + env->ReleaseStringUTFChars(json_str_j, json_str_c); + + return json_str; +} + +std::string NativeCapacitorInterface::device_api_getNetworkStatus() { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto *device = env->GetObjectField(this->api, this->java->capacitor_api_device_field); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + auto *json_str_j = (jstring)env->CallObjectMethod(device, this->java->capacitor_api_device_getNetworkStatus_method); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + const auto *json_str_c = env->GetStringUTFChars(json_str_j, nullptr); + std::string json_str(json_str_c); + + env->ReleaseStringUTFChars(json_str_j, json_str_c); + + return json_str; +} + +// KV API +void NativeCapacitorInterface::kv_api_set(std::string key, std::string json_value) { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto *kv = env->GetObjectField(this->api, this->java->capacitor_api_kv_field); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + jstring key_j_str = env->NewStringUTF(key.c_str()); + jstring value_j_str = env->NewStringUTF(json_value.c_str()); + + env->CallVoidMethod(kv, this->java->capacitor_api_kv_set_method, key_j_str, value_j_str); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } +} + +std::string NativeCapacitorInterface::kv_api_get(std::string key) { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto *kv = env->GetObjectField(this->api, this->java->capacitor_api_kv_field); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + jstring key_j_str = env->NewStringUTF(key.c_str()); + + auto *value_j_str = (jstring)env->CallObjectMethod(kv, this->java->capacitor_api_kv_get_method, key_j_str); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + if (value_j_str == nullptr) { + return ""; + } + + const auto *value_c_str = env->GetStringUTFChars(value_j_str, nullptr); + auto value = std::string(value_c_str); + env->ReleaseStringUTFChars(value_j_str, value_c_str); + + return value; +} + +void NativeCapacitorInterface::kv_api_remove(std::string key) { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto *kv = env->GetObjectField(this->api, this->java->capacitor_api_kv_field); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + jstring key_j_str = env->NewStringUTF(key.c_str()); + + env->CallVoidMethod(kv, this->java->capacitor_api_kv_remove_method, key_j_str); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } +} + +// Notifications API +void NativeCapacitorInterface::notifications_api_schedule(std::string options_json) { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto *notification = env->GetObjectField(this->api, this->java->capacitor_api_notification_field); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + auto *options_j_str = env->NewStringUTF(options_json.c_str()); + + env->CallVoidMethod(notification, this->java->capacitor_api_notifications_schedule_method, options_j_str); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } +} + +std::string NativeCapacitorInterface::geolocation_api_getCurrentPosition() { + auto *env = this->java->getEnv(); + if (env == nullptr) { + throw new NativeInterfaceException("JVM environment is null"); + } + + auto *geolocation = env->GetObjectField(this->api, this->java->capacitor_api_geolocation_field); + auto jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + auto value_j_str = (jstring)env->CallObjectMethod(geolocation, this->java->capacitor_api_geolocation_getCurrentPosition_method); + jvm_exception = get_jvm_exception(env); + if (jvm_exception != nullptr) { + throw *jvm_exception; + } + + if (value_j_str == nullptr) { + return ""; + } + + const auto *c_json_str = env->GetStringUTFChars(value_j_str, nullptr); + + auto json = std::string(c_json_str); + env->ReleaseStringUTFChars(value_j_str, c_json_str); + + return json; +} diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_capacitor_interface.h b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_capacitor_interface.h new file mode 100644 index 00000000..71e4f92c --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_capacitor_interface.h @@ -0,0 +1,29 @@ +#ifndef ANDROID_JS_ENGINE_NATIVE_CAPACITOR_INTERFACE_H +#define ANDROID_JS_ENGINE_NATIVE_CAPACITOR_INTERFACE_H + +#include "./js-engine/src/capacitor.hpp" +#include "java.h" + +#include + +class NativeCapacitorInterface : public CapacitorInterface { +public: + NativeCapacitorInterface(JNIEnv *env, jobject api); + ~NativeCapacitorInterface(); + + jobject api; + Java *java; + + virtual std::string device_api_getBatteryStatus(); + virtual std::string device_api_getNetworkStatus(); + + virtual std::string geolocation_api_getCurrentPosition(); + + virtual void kv_api_set(std::string key, std::string json_value); + virtual std::string kv_api_get(std::string key); + virtual void kv_api_remove(std::string key); + + virtual void notifications_api_schedule(std::string options_json); +}; + +#endif //ANDROID_JS_ENGINE_NATIVE_CAPACITOR_INTERFACE_H diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_context.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_context.cpp new file mode 100644 index 00000000..dc0ee4cf --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_context.cpp @@ -0,0 +1,74 @@ +#include + +#include "./js-engine/src/context.hpp" +#include "./js-engine/src/errors.hpp" +#include "./js-engine/src/runner.hpp" +#include "java_errors.h" +#include "native_capacitor_interface.h" + +extern "C" JNIEXPORT jlong JNICALL Java_io_ionic_android_1js_1engine_Context_createRunnerContext(JNIEnv *env, jobject thiz, jlong runner_ptr, jstring name, jobject cap_api) { + auto *runner = (Runner *)runner_ptr; + + auto *api_global = env->NewGlobalRef(cap_api); + auto *cap_native = new NativeCapacitorInterface(env, api_global); + + return (jlong)(long)runner->create_context(env->GetStringUTFChars(name, nullptr), cap_native); +} +extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Context_destroyRunnerContext(JNIEnv *env, jobject thiz, jlong runner_ptr, jlong ptr) { + auto *runner = (Runner *)runner_ptr; + auto *context = (Context *)ptr; + + runner->destroy_context(context->name); +} +extern "C" JNIEXPORT jstring JNICALL Java_io_ionic_android_1js_1engine_Context_evaluate(JNIEnv *env, jobject thiz, jlong ptr, jstring code, jboolean ret_value) { + auto *context = (Context *)ptr; + + const char *code_c_str = env->GetStringUTFChars(code, nullptr); + auto value = context->evaluate(code_c_str, (bool)ret_value); + + // check for thrown exception in js context + auto exception = get_js_exception(context->qjs_context); + if (throw_js_error_in_jvm(env, context->qjs_context, exception)) { + return nullptr; + } + + const char *json_c_str = JS_ToCString(context->qjs_context, value); + auto *json_j_str = env->NewStringUTF(json_c_str); + + JS_FreeCString(context->qjs_context, json_c_str); + JS_FreeValue(context->qjs_context, value); + + return json_j_str; +} +extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Context_registerGlobalFunction(JNIEnv *env, jobject thiz, jlong ptr, jstring function_name, jobject function) { + auto *context = (Context *)ptr; + + const auto *function_name_c_str = env->GetStringUTFChars(function_name, nullptr); + + std::any wrapped_function = env->NewGlobalRef(function); + context->register_function(function_name_c_str, wrapped_function); + + env->ReleaseStringUTFChars(function_name, function_name_c_str); +} +extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Context_dispatchEvent(JNIEnv *env, jobject thiz, jlong ptr, jstring event, jstring details) { + auto *context = (Context *)ptr; + + const char *event_c_str = env->GetStringUTFChars(event, nullptr); + const char *details_json_c_str = env->GetStringUTFChars(details, nullptr); + + auto details_obj = JS_ParseJSON(context->qjs_context, details_json_c_str, strlen(details_json_c_str), "

"); + + auto value = context->dispatch_event(event_c_str, details_obj); + JS_FreeValue(context->qjs_context, details_obj); + + env->ReleaseStringUTFChars(event, event_c_str); + env->ReleaseStringUTFChars(details, details_json_c_str); + + // check for thrown exception in js context + auto exception = get_js_exception(context->qjs_context); + if (throw_js_error_in_jvm(env, context->qjs_context, exception)) { + return; + } + + JS_FreeValue(context->qjs_context, value); +} diff --git a/packages/android-engine/android-js-engine/src/main/cpp/native_runner.cpp b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_runner.cpp similarity index 52% rename from packages/android-engine/android-js-engine/src/main/cpp/native_runner.cpp rename to packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_runner.cpp index a5313167..184b262f 100644 --- a/packages/android-engine/android-js-engine/src/main/cpp/native_runner.cpp +++ b/packages/android-js-engine/AndroidJSEngine/src/main/cpp/native_runner.cpp @@ -1,18 +1,21 @@ #include -#include "runner.h" - +#include "./js-engine/src/runner.hpp" +#include "native_android_interface.h" extern "C" JNIEXPORT jlong JNICALL Java_io_ionic_android_1js_1engine_Runner_initRunner(JNIEnv *env, jobject thiz) { - auto *runner = new Runner(); + auto *native = new NativeAndroidInterface(env); + auto *runner = new Runner(native); + return (jlong)(long)runner; } -extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Runner_startRunner(JNIEnv *env, jobject thiz, jlong ptr) { +extern "C" JNIEXPORT jboolean JNICALL Java_io_ionic_android_1js_1engine_Runner_hasPendingJobs(JNIEnv *env, jobject thiz, jlong ptr) { auto *runner = (Runner *)ptr; - runner->start(); + return runner->has_pending_jobs(); } -extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Runner_stopRunner(JNIEnv *env, jobject thiz, jlong ptr) { + +extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Runner_executePendingJobs(JNIEnv *env, jobject thiz, jlong ptr) { auto *runner = (Runner *)ptr; - runner->stop(); + runner->execute_pending_jobs(); } extern "C" JNIEXPORT void JNICALL Java_io_ionic_android_1js_1engine_Runner_destroyRunner(JNIEnv *env, jobject thiz, jlong ptr) { auto *runner = (Runner *)ptr; diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/Context.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/Context.kt new file mode 100644 index 00000000..731a3c4c --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/Context.kt @@ -0,0 +1,77 @@ +package io.ionic.android_js_engine + +import org.json.JSONObject + +class Context(name: String, runnerPtr: Long, capAPI: NativeCapacitorAPI?) { + val name: String + private val runnerPtr: Long + + private var ptr: Long? = null + + init { + System.loadLibrary("android_js_engine") + this.name = name + this.runnerPtr = runnerPtr + this.ptr = createRunnerContext(runnerPtr, name, capAPI) + } + + private external fun createRunnerContext( + runnerPtr: Long, + name: String, + capAPI: NativeCapacitorAPI?, + ): Long + + private external fun destroyRunnerContext( + runnerPtr: Long, + ptr: Long, + ) + + private external fun evaluate( + ptr: Long, + code: String, + retValue: Boolean, + ): String + + private external fun registerGlobalFunction( + ptr: Long, + functionName: String, + function: NativeJSFunction, + ) + + private external fun dispatchEvent( + ptr: Long, + event: String, + details: String, + ) + + fun execute( + code: String, + returnValue: Boolean = false, + ): NativeJSValue { + val contextPtr = this.ptr ?: throw EngineErrors.ContextException("pointer is nil") + val jsonString = this.evaluate(contextPtr, code, returnValue) + + return NativeJSValue(jsonString) + } + + fun registerFunction( + jsFunctionName: String, + func: NativeJSFunction, + ) { + val contextPtr = this.ptr ?: throw EngineErrors.ContextException("pointer is nil") + this.registerGlobalFunction(contextPtr, jsFunctionName, func) + } + + fun dispatchEvent( + event: String, + details: JSONObject, + ) { + val ptr = this.ptr ?: throw EngineErrors.ContextException("pointer is nil") + this.dispatchEvent(ptr, event, details.toString(0)) + } + + internal fun destroy() { + val contextPtr = this.ptr ?: throw EngineErrors.ContextException("pointer is nil") + destroyRunnerContext(runnerPtr, contextPtr) + } +} diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/EngineErrors.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/EngineErrors.kt similarity index 99% rename from packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/EngineErrors.kt rename to packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/EngineErrors.kt index cbeaf884..eaa35cca 100644 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/EngineErrors.kt +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/EngineErrors.kt @@ -2,6 +2,8 @@ package io.ionic.android_js_engine sealed class EngineErrors(message: String) : Exception(message) { data class JavaScriptException(val details: String) : EngineErrors("JS exception: $details") + data class RunnerException(val details: String) : EngineErrors("Runner exception: $details") + data class ContextException(val details: String) : EngineErrors("Context exception: $details") } diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeCapacitorAPI.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeCapacitorAPI.kt new file mode 100644 index 00000000..bf26c7d0 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeCapacitorAPI.kt @@ -0,0 +1,29 @@ +package io.ionic.android_js_engine + +import io.ionic.android_js_engine.capacitor_api.DeviceAPI +import io.ionic.android_js_engine.capacitor_api.GeolocationAPI +import io.ionic.android_js_engine.capacitor_api.KVAPI +import io.ionic.android_js_engine.capacitor_api.NotificationsAPI + +class NativeCapacitorAPI { + private var kv: KVAPI? = null + private var device: DeviceAPI? = null + private var notifications: NotificationsAPI? = null + private var geolocation: GeolocationAPI? = null + + fun initNotificationsAPI(api: NotificationsAPI) { + this.notifications = api + } + + fun initDeviceAPI(api: DeviceAPI) { + this.device = api + } + + fun initGeolocationAPI(api: GeolocationAPI) { + this.geolocation = api + } + + fun initKVAPI(api: KVAPI) { + this.kv = api + } +} diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSFetchOptions.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSFetchOptions.kt new file mode 100644 index 00000000..45324562 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSFetchOptions.kt @@ -0,0 +1,13 @@ +package io.ionic.android_js_engine + +class NativeJSFetchOptions(method: String, requestHeaders: HashMap, body: ByteArray?) { + public val httpMethod: String + public val headers: HashMap + public var body: ByteArray? = null + + init { + this.httpMethod = method + this.body = body + this.headers = requestHeaders + } +} diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSFunction.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSFunction.kt new file mode 100644 index 00000000..e55b9830 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSFunction.kt @@ -0,0 +1,15 @@ +package io.ionic.android_js_engine + +import org.json.JSONObject + +open class NativeJSFunction(jsFunctionName: String, jsFunctionArgs: JSONObject? = null) : Runnable { + var jsFunctionArgs: JSONObject? = null + var jsFunctionName: String + + init { + this.jsFunctionName = jsFunctionName + this.jsFunctionArgs = jsFunctionArgs + } + + override fun run() {} +} diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSResponse.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSResponse.kt similarity index 79% rename from packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSResponse.kt rename to packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSResponse.kt index 24926cd4..b3da2437 100644 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSResponse.kt +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSResponse.kt @@ -1,6 +1,6 @@ package io.ionic.android_js_engine -class JSResponse(statusCode: Int, url: String, data: ByteArray?, error: String?) { +class NativeJSResponse(statusCode: Int, url: String, data: ByteArray?, error: String?) { public var ok: Boolean public var status: Int public var url: String diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSValue.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSValue.kt similarity index 75% rename from packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSValue.kt rename to packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSValue.kt index 14b8e64c..59fabf73 100644 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/JSValue.kt +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeJSValue.kt @@ -3,7 +3,7 @@ package io.ionic.android_js_engine import org.json.JSONArray import org.json.JSONObject -class JSValue(jsonString: String) { +class NativeJSValue(jsonString: String) { private val json: String init { @@ -31,24 +31,22 @@ class JSValue(jsonString: String) { fun getBoolValue(): Boolean? { if (checkIfNullOrUndefined()) return null - if (this.json == "false" || this.json == "0" || this.json.isEmpty()) { - return false - } - - return true + return !(this.json == "false" || this.json == "0" || this.json.isEmpty()) } fun getJSONArray(): JSONArray? { try { return JSONArray(this.json) - } catch (`_`: java.lang.Exception) {} + } catch (`_`: java.lang.Exception) { + } return null } fun getJSONObject(): JSONObject? { try { return JSONObject(this.json) - } catch (`_`: java.lang.Exception) {} + } catch (`_`: java.lang.Exception) { + } return null } @@ -59,10 +57,6 @@ class JSValue(jsonString: String) { } private fun checkIfNullOrUndefined(): Boolean { - if (this.json == "undefined" || this.json == "null") { - return true - } - - return false + return this.json == "undefined" || this.json == "null" } } diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeLib.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeLib.kt new file mode 100644 index 00000000..8f9ff391 --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeLib.kt @@ -0,0 +1,16 @@ +package io.ionic.android_js_engine + +class NativeLib { + /** + * A native method that is implemented by the 'android_js_engine' native library, + * which is packaged with this application. + */ + external fun stringFromJNI(): String + + companion object { + // Used to load the 'android_js_engine' library on application startup. + init { + System.loadLibrary("android_js_engine") + } + } +} diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/WebAPI.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeWebAPI.kt similarity index 82% rename from packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/WebAPI.kt rename to packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeWebAPI.kt index 2dcdb50d..63ae49ba 100644 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/WebAPI.kt +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/NativeWebAPI.kt @@ -1,5 +1,6 @@ package io.ionic.android_js_engine +import android.util.Log import java.io.BufferedInputStream import java.io.BufferedOutputStream import java.net.HttpURLConnection @@ -9,7 +10,7 @@ import java.security.SecureRandom import java.util.UUID import kotlin.math.abs -class WebAPI { +class NativeWebAPI { companion object { @JvmStatic fun cryptoRandomUUID(): String { @@ -38,7 +39,10 @@ class WebAPI { } @JvmStatic - fun byteArrayToString(arr: ByteArray, encoding: String): String { + fun byteArrayToString( + arr: ByteArray, + encoding: String, + ): String { val enc = getCharset(encoding) return arr.toString(enc) } @@ -61,7 +65,10 @@ class WebAPI { } @JvmStatic - fun fetch(urlStr: String, options: JSFetchOptions?): JSResponse { + fun fetch( + urlStr: String, + options: NativeJSFetchOptions?, + ): NativeJSResponse { val url = URL(urlStr) val connection = url.openConnection() as HttpURLConnection @@ -86,10 +93,10 @@ class WebAPI { val input = BufferedInputStream(connection.inputStream) val bodyBytes = input.readBytes() - return JSResponse(connection.responseCode, connection.url.toString(), bodyBytes, null) + return NativeJSResponse(connection.responseCode, connection.url.toString(), bodyBytes, null) } catch (ex: Exception) { - print(ex.message) - return JSResponse(-1, urlStr, null, ex.message) + Log.e("KOTLIN FETCH ERROR", ex.toString()) + return NativeJSResponse(-1, urlStr, null, ex.message) } finally { connection.disconnect() } diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/Runner.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/Runner.kt similarity index 61% rename from packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/Runner.kt rename to packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/Runner.kt index e5d07ed3..ef6c9364 100644 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/Runner.kt +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/Runner.kt @@ -1,14 +1,8 @@ package io.ionic.android_js_engine -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch - class Runner { private val contexts: HashMap = HashMap() - private var ptr: Long? = null - private var job: Job? = null init { System.loadLibrary("android_js_engine") @@ -17,55 +11,69 @@ class Runner { } private external fun initRunner(): Long - private external fun startRunner(ptr: Long) - private external fun stopRunner(ptr: Long) + + private external fun hasPendingJobs(ptr: Long): Boolean + + private external fun executePendingJobs(ptr: Long) + private external fun destroyRunner(ptr: Long) - fun createContext(name: String): Context { + fun createContext( + name: String, + capAPI: NativeCapacitorAPI? = null, + ): Context { val runnerPtr = this.ptr ?: throw EngineErrors.RunnerException("pointer is nil") - if (contexts.containsKey(name)) { + if (hasContext(name)) { throw EngineErrors.RunnerException("context with name $name already exists") } - val context = Context(name, runnerPtr) + val context = Context(name, runnerPtr, capAPI) contexts[name] = context return context } + fun hasContext(name: String): Boolean { + return contexts.containsKey(name) + } + + fun getContext(name: String): Context? { + if (!hasContext(name)) { + return null + } + + return contexts[name] + } + fun destroyContext(name: String) { val runnerPtr = this.ptr ?: throw EngineErrors.RunnerException("pointer is nil") - val context = contexts[name] ?: return + val context = contexts[name] ?: throw EngineErrors.RunnerException("could not find context named: $name") context.destroy() this.contexts.remove(name) } - fun start() { - val runnerPtr = this.ptr ?: throw EngineErrors.RunnerException("pointer is nil") - this.job = GlobalScope.launch { - startRunner(runnerPtr) - print("Runner Stopped") + fun waitForJobs() { + while (hasPendingJobs()) { + executePendingJobs() } - Thread.sleep(20) } - fun stop() { + fun hasPendingJobs(): Boolean { val runnerPtr = this.ptr ?: throw EngineErrors.RunnerException("pointer is nil") - this.stopRunner(runnerPtr) - if (this.job != null) { - this.job?.cancel() - this.job = null - } + return hasPendingJobs(runnerPtr) } - fun destroy() { + fun executePendingJobs() { val runnerPtr = this.ptr ?: throw EngineErrors.RunnerException("pointer is nil") + executePendingJobs(runnerPtr) + } - this.stop() + fun destroy() { + val runnerPtr = this.ptr ?: throw EngineErrors.RunnerException("pointer is nil") if (this.contexts.isNotEmpty()) { val allKeys = mutableListOf() diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/DeviceAPI.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/DeviceAPI.kt similarity index 65% rename from packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/DeviceAPI.kt rename to packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/DeviceAPI.kt index 21863255..43c22327 100644 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/DeviceAPI.kt +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/DeviceAPI.kt @@ -1,6 +1,7 @@ -package io.ionic.android_js_engine.api +package io.ionic.android_js_engine.capacitor_api interface DeviceAPI { fun getBatteryStatus(): String + fun getNetworkStatus(): String } diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/GeolocationAPI.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/GeolocationAPI.kt similarity index 58% rename from packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/GeolocationAPI.kt rename to packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/GeolocationAPI.kt index 67e8ee7f..b7420b0c 100644 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/GeolocationAPI.kt +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/GeolocationAPI.kt @@ -1,4 +1,4 @@ -package io.ionic.android_js_engine.api +package io.ionic.android_js_engine.capacitor_api interface GeolocationAPI { fun getCurrentPosition(): String? diff --git a/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/KVAPI.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/KVAPI.kt new file mode 100644 index 00000000..4fd2ee2b --- /dev/null +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/KVAPI.kt @@ -0,0 +1,12 @@ +package io.ionic.android_js_engine.capacitor_api + +interface KVAPI { + fun set( + key: String, + value: String, + ) + + fun get(key: String): String? + + fun remove(key: String) +} diff --git a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/NotificationsAPI.kt b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/NotificationsAPI.kt similarity index 58% rename from packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/NotificationsAPI.kt rename to packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/NotificationsAPI.kt index 44eff3d1..60b655c0 100644 --- a/packages/android-engine/android-js-engine/src/main/java/io/ionic/android_js_engine/api/NotificationsAPI.kt +++ b/packages/android-js-engine/AndroidJSEngine/src/main/java/io/ionic/android_js_engine/capacitor_api/NotificationsAPI.kt @@ -1,4 +1,4 @@ -package io.ionic.android_js_engine.api +package io.ionic.android_js_engine.capacitor_api interface NotificationsAPI { fun schedule(jsonString: String) diff --git a/packages/android-engine/app/.gitignore b/packages/android-js-engine/app/.gitignore similarity index 100% rename from packages/android-engine/app/.gitignore rename to packages/android-js-engine/app/.gitignore diff --git a/packages/android-engine/app/build.gradle b/packages/android-js-engine/app/build.gradle similarity index 61% rename from packages/android-engine/app/build.gradle rename to packages/android-js-engine/app/build.gradle index 795e8529..d4672179 100644 --- a/packages/android-engine/app/build.gradle +++ b/packages/android-js-engine/app/build.gradle @@ -1,21 +1,16 @@ -buildscript { - repositories { - google() - mavenCentral() - } +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - android { - namespace 'io.ionic.backgroundrunner' - compileSdk 33 + namespace 'io.ionic.android_js_engine_testproject' + compileSdk 34 defaultConfig { - applicationId "io.ionic.backgroundrunner" + applicationId "io.ionic.android_js_engine_testproject" minSdk 24 - targetSdk 33 + targetSdk 34 versionCode 1 versionName "1.0" @@ -37,16 +32,11 @@ android { } } -repositories { - google() - mavenCentral() -} - dependencies { - implementation project(path: ':android-js-engine') - implementation 'androidx.core:core-ktx:1.10.1' + implementation project(path: ':AndroidJSEngine') + implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.google.android.material:material:1.9.0' + implementation 'com.google.android.material:material:1.11.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/packages/android-engine/app/proguard-rules.pro b/packages/android-js-engine/app/proguard-rules.pro similarity index 100% rename from packages/android-engine/app/proguard-rules.pro rename to packages/android-js-engine/app/proguard-rules.pro diff --git a/packages/android-engine/app/src/androidTest/java/io/ionic/backgroundrunner/ContextTests.kt b/packages/android-js-engine/app/src/androidTest/java/io/ionic/android_js_engine_testproject/ContextTest.kt similarity index 83% rename from packages/android-engine/app/src/androidTest/java/io/ionic/backgroundrunner/ContextTests.kt rename to packages/android-js-engine/app/src/androidTest/java/io/ionic/android_js_engine_testproject/ContextTest.kt index 7e5903f6..2610126d 100644 --- a/packages/android-engine/app/src/androidTest/java/io/ionic/backgroundrunner/ContextTests.kt +++ b/packages/android-js-engine/app/src/androidTest/java/io/ionic/android_js_engine_testproject/ContextTest.kt @@ -1,22 +1,18 @@ -package io.ionic.backgroundrunner +package io.ionic.android_js_engine_testproject -import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.ionic.android_js_engine.JSFunction import io.ionic.android_js_engine.Runner -import junit.framework.TestCase.assertTrue -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertFalse -import junit.framework.TestCase.assertNotNull +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.ionic.android_js_engine.NativeJSFunction import org.json.JSONObject -import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith +import org.junit.Assert.* import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit import java.util.concurrent.TimeoutException @RunWith(AndroidJUnit4::class) -class ContextTests { +class ContextTest { @Test fun testNullEval() { val runner = Runner() @@ -99,7 +95,7 @@ class ContextTests { val future3 = CompletableFuture() val future4 = CompletableFuture() - class SuccessCallback1 : JSFunction(jsName = "successCallback") { + class SuccessCallback1 : NativeJSFunction(jsFunctionName = "successCallback") { public var calls: Int = 0 override fun run() { super.run() @@ -109,7 +105,7 @@ class ContextTests { } } - class SuccessCallback2: JSFunction(jsName = "altSuccessCallback") { + class SuccessCallback2: NativeJSFunction(jsFunctionName = "altSuccessCallback") { public var calls: Int = 0 override fun run() { @@ -120,18 +116,18 @@ class ContextTests { } } - class SuccessCallback3 : JSFunction(jsName = "successCallbackDetails") { + class SuccessCallback3 : NativeJSFunction(jsFunctionName = "successCallbackDetails") { public var calls: Int = 0 override fun run() { super.run() calls++ - future3.complete(args) + future3.complete(jsFunctionArgs) } } - class SuccessCallback4 : JSFunction(jsName = "successCallbackFunction") { + class SuccessCallback4 : NativeJSFunction(jsFunctionName = "successCallbackFunction") { public var calls: Int = 0 override fun run() { super.run() @@ -209,7 +205,7 @@ class ContextTests { assertTrue(localizedMessage.contains("JS exception")) - val throwingEventEx = assertThrows(java.lang.Exception::class.java) { + val throwingEventEx = assertThrows(Exception::class.java) { context.execute("addEventListener('myThrowingEvent', () => { throw new Error('this event throws an error') })") context.dispatchEvent("myThrowingEvent", JSONObject()) } @@ -218,7 +214,7 @@ class ContextTests { assertTrue(localizedMessage.contains("JS exception")) // testing handling JVM exceptions - class ExceptionCallback : JSFunction(jsName = "exceptionCallback") { + class ExceptionCallback : NativeJSFunction(jsFunctionName = "exceptionCallback") { override fun run() { super.run() throw Exception("this is a problem from the JVM") @@ -243,14 +239,13 @@ class ContextTests { @Test fun testAPI_SetTimeout() { val runner = Runner() - runner.start() val context = runner.createContext("io.ionic.android_js_engine") val timeoutFuture1 = CompletableFuture() val timeoutFuture2 = CompletableFuture() - class TimeoutCallback1 : JSFunction(jsName = "timeoutCallback") { + class TimeoutCallback1 : NativeJSFunction(jsFunctionName = "timeoutCallback") { public var calls: Int = 0 override fun run() { super.run() @@ -260,7 +255,7 @@ class ContextTests { } } - class TimeoutCallback2 : JSFunction(jsName = "cancelTimeoutCallback") { + class TimeoutCallback2 : NativeJSFunction(jsFunctionName = "cancelTimeoutCallback") { public var calls: Int = 0 override fun run() { super.run() @@ -280,6 +275,8 @@ class ContextTests { var timerId = value.getIntValue() ?: 0 assertTrue(timerId > 0) + + runner.waitForJobs() assertEquals(1, timeoutFuture1.get(3, TimeUnit.SECONDS)) value = context.execute("setTimeout(() => { cancelTimeoutCallback() }, 4000)", true) @@ -288,25 +285,24 @@ class ContextTests { context.execute("clearTimeout(${value.getIntValue()});") try { + runner.waitForJobs() assertEquals(0, timeoutFuture2.get(3, TimeUnit.SECONDS)) } catch (ex: TimeoutException) { assertTrue(true) } - runner.stop() runner.destroy() } @Test fun testAPI_SetInterval() { val runner = Runner() - runner.start() val context = runner.createContext("io.ionic.android_js_engine") var calls = 0; - class IntervalCallback : JSFunction(jsName = "intervalCallback") { + class IntervalCallback : NativeJSFunction(jsFunctionName = "intervalCallback") { override fun run() { super.run() calls++ @@ -320,15 +316,17 @@ class ContextTests { val value = context.execute("setInterval(() => { intervalCallback() }, 2000)", true) assertTrue((value.getIntValue() ?: 0) > 0) - Thread.sleep(8000) - assertEquals(4, calls) + Thread { + Thread.sleep(9000) + assertEquals(4, calls) - context.execute("clearInterval(${value.getIntValue()});") + context.execute("clearInterval(${value.getIntValue()});") - Thread.sleep(3000) - assertEquals(4, calls) + Thread.sleep(3000) + assertEquals(4, calls) + }.start() - runner.stop() + runner.waitForJobs() runner.destroy() } @@ -379,7 +377,6 @@ class ContextTests { @Test fun testAPI_Fetch() { val runner = Runner() - runner.start() val context = runner.createContext("io.ionic.android_js_engine") @@ -387,14 +384,14 @@ class ContextTests { val future2 = CompletableFuture() val future3 = CompletableFuture() - class SuccessCallback : JSFunction(jsName = "successCallback") { + class SuccessCallback : NativeJSFunction(jsFunctionName = "successCallback") { override fun run() { super.run() - future1.complete(this.args) + future1.complete(this.jsFunctionArgs) } } - class FailureCallback : JSFunction(jsName = "failureCallback") { + class FailureCallback : NativeJSFunction(jsFunctionName = "failureCallback") { public var calls: Int = 0 override fun run() { super.run() @@ -403,10 +400,10 @@ class ContextTests { } } - class OptionsSuccessCallback : JSFunction(jsName = "successCallback2") { + class OptionsSuccessCallback : NativeJSFunction(jsFunctionName = "successCallback2") { override fun run() { super.run() - future3.complete(this.args) + future3.complete(this.jsFunctionArgs) } } @@ -469,31 +466,58 @@ class ContextTests { """.trimIndent() context.execute(basicFetchExample) - + runner.waitForJobs() val jsonResponse1 = future1.get(5, TimeUnit.SECONDS); assertEquals("delectus aut autem", jsonResponse1?.getString("title")) - context.execute(basicFetchWithTextResponseExample) +// context.execute(basicFetchWithTextResponseExample) - context.execute(basicFetchWithArrayBufferResponseExample) +// context.execute(basicFetchWithArrayBufferResponseExample) // context.execute(basicFetchWithBlobResponseExample) context.execute(fetchFailureExample) - + runner.waitForJobs() assertEquals(1, future2.get(5, TimeUnit.SECONDS)) context.execute(fetchWithOptionsExample) - + runner.waitForJobs() val jsonResponse2 = future3.get(5, TimeUnit.SECONDS) assertEquals("bar", jsonResponse2?.getString("body")) - runner.stop() + val fetchMultiple = """ + const p1 = fetch('https://jsonplaceholder.typicode.com/posts', { + method: 'POST', + body: JSON.stringify({ + title: 'foo', + body: 'bar', + userId: 1, + }), + headers: { + 'Content-type': 'application/json; charset=UTF-8', + } + }) + .catch(err => { console.error(err); }) + .then(response => response.json()) + .then(json => { console.log(JSON.stringify(json)); }); + + const p2 = fetch('https://jsonplaceholder.typicode.com/todos/1') + .catch(err => { console.error(err); }) + .then(response => response.json()) + .then(json => { console.log(JSON.stringify(json)); }); + + Promise.all([p1, p2]).then(() => { console.log("done!"); }); + + + """.trimIndent() + + context.execute(fetchMultiple) + runner.waitForJobs() runner.destroy() } -// @Test + // @Test // fun testAPI_Blob() { // val runner = Runner() // val context = runner.createContext("io.ionic.android_js_engine") diff --git a/packages/android-engine/app/src/androidTest/java/io/ionic/backgroundrunner/RunnerTests.kt b/packages/android-js-engine/app/src/androidTest/java/io/ionic/android_js_engine_testproject/RunnerTest.kt similarity index 82% rename from packages/android-engine/app/src/androidTest/java/io/ionic/backgroundrunner/RunnerTests.kt rename to packages/android-js-engine/app/src/androidTest/java/io/ionic/android_js_engine_testproject/RunnerTest.kt index c31c8455..44129d89 100644 --- a/packages/android-engine/app/src/androidTest/java/io/ionic/backgroundrunner/RunnerTests.kt +++ b/packages/android-js-engine/app/src/androidTest/java/io/ionic/android_js_engine_testproject/RunnerTest.kt @@ -1,29 +1,31 @@ -package io.ionic.backgroundrunner +package io.ionic.android_js_engine_testproject +import android.util.Log import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.ionic.android_js_engine.JSFunction +import io.ionic.android_js_engine.NativeJSFunction import io.ionic.android_js_engine.Runner import junit.framework.TestCase + import org.junit.Test import org.junit.runner.RunWith + import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit + @RunWith(AndroidJUnit4::class) -class RunnerTests { +class RunnerTest { @Test fun testRunnerCreateDestroy() { val runner = Runner() - runner.start() - - runner.stop() + Thread.sleep(120) runner.destroy() } @Test fun testContextCreateDestroy() { val runner = Runner() - runner.start() + Thread.sleep(120) val context = runner.createContext("io.ionic.android_js_engine") @@ -33,13 +35,12 @@ class RunnerTests { @Test fun testMultipleContexts() { val runner = Runner() - runner.start() val count = (20..40).random() val timeoutFuture = CompletableFuture() - class TimeoutCallback : JSFunction(jsName = "timeoutCallback") { + class TimeoutCallback : NativeJSFunction(jsFunctionName = "timeoutCallback") { public var calls: Int = 0 override fun run() { super.run() @@ -59,6 +60,7 @@ class RunnerTests { context.execute("setTimeout(() => { timeoutCallback(); }, 2000)", false) } + runner.waitForJobs() TestCase.assertEquals(count, timeoutFuture.get(5, TimeUnit.SECONDS)) runner.destroy() diff --git a/packages/android-engine/app/src/main/AndroidManifest.xml b/packages/android-js-engine/app/src/main/AndroidManifest.xml similarity index 90% rename from packages/android-engine/app/src/main/AndroidManifest.xml rename to packages/android-js-engine/app/src/main/AndroidManifest.xml index 6ae41189..64b0143b 100644 --- a/packages/android-engine/app/src/main/AndroidManifest.xml +++ b/packages/android-js-engine/app/src/main/AndroidManifest.xml @@ -12,9 +12,7 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.CapacitorBackgroundRunner" + android:theme="@style/Theme.AndroidJSEngineTestProject" tools:targetApi="31" /> - - \ No newline at end of file diff --git a/packages/android-engine/app/src/main/res/drawable/ic_launcher_background.xml b/packages/android-js-engine/app/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from packages/android-engine/app/src/main/res/drawable/ic_launcher_background.xml rename to packages/android-js-engine/app/src/main/res/drawable/ic_launcher_background.xml diff --git a/packages/android-engine/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/packages/android-js-engine/app/src/main/res/drawable/ic_launcher_foreground.xml similarity index 100% rename from packages/android-engine/app/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to packages/android-js-engine/app/src/main/res/drawable/ic_launcher_foreground.xml diff --git a/packages/android-engine/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/packages/android-js-engine/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to packages/android-js-engine/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/packages/android-engine/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/packages/android-js-engine/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to packages/android-js-engine/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/packages/android-engine/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/packages/android-js-engine/app/src/main/res/mipmap-hdpi/ic_launcher.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-hdpi/ic_launcher.webp rename to packages/android-js-engine/app/src/main/res/mipmap-hdpi/ic_launcher.webp diff --git a/packages/android-engine/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/packages/android-js-engine/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp rename to packages/android-js-engine/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp diff --git a/packages/android-engine/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/packages/android-js-engine/app/src/main/res/mipmap-mdpi/ic_launcher.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-mdpi/ic_launcher.webp rename to packages/android-js-engine/app/src/main/res/mipmap-mdpi/ic_launcher.webp diff --git a/packages/android-engine/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/packages/android-js-engine/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp rename to packages/android-js-engine/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp diff --git a/packages/android-engine/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/packages/android-js-engine/app/src/main/res/mipmap-xhdpi/ic_launcher.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-xhdpi/ic_launcher.webp rename to packages/android-js-engine/app/src/main/res/mipmap-xhdpi/ic_launcher.webp diff --git a/packages/android-engine/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/packages/android-js-engine/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp rename to packages/android-js-engine/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp diff --git a/packages/android-engine/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/packages/android-js-engine/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp rename to packages/android-js-engine/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp diff --git a/packages/android-engine/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/packages/android-js-engine/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp rename to packages/android-js-engine/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp diff --git a/packages/android-engine/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/packages/android-js-engine/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp rename to packages/android-js-engine/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp diff --git a/packages/android-engine/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/packages/android-js-engine/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp similarity index 100% rename from packages/android-engine/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp rename to packages/android-js-engine/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp diff --git a/packages/android-engine/app/src/main/res/values-night/themes.xml b/packages/android-js-engine/app/src/main/res/values-night/themes.xml similarity index 86% rename from packages/android-engine/app/src/main/res/values-night/themes.xml rename to packages/android-js-engine/app/src/main/res/values-night/themes.xml index ac249378..3836b3f7 100644 --- a/packages/android-engine/app/src/main/res/values-night/themes.xml +++ b/packages/android-js-engine/app/src/main/res/values-night/themes.xml @@ -1,6 +1,6 @@ -