From 6953e757d11f14e806f7d5ea637040fe3dc90321 Mon Sep 17 00:00:00 2001 From: John Turpish Date: Thu, 14 Dec 2023 17:16:53 -0500 Subject: [PATCH] Partial CAR requests. Entity scope fits nicely. Fixes #91 --- .github/workflows/library.yml | 44 +-- .github/workflows/tour.yml | 10 +- .github/workflows/ut.yml | 37 +++ CMakeLists.txt | 4 +- .../chrome/browser/BUILD.gn.patch | 23 ++ .../chrome/browser/about_flags.cc.patch | 38 +++ ...me_autocomplete_scheme_classifier.cc.patch | 50 ++++ .../chrome_content_browser_client.cc.patch | 63 ++++ .../chrome/browser/flag-metadata.json.patch | 16 + .../chrome/browser/flag_descriptions.cc.patch | 16 + .../chrome/browser/flag_descriptions.h.patch | 24 ++ .../common/chrome_content_client.cc.patch | 17 ++ .../components/cbor/reader.cc.patch | 44 +++ .../components/cbor/reader.h.patch | 26 ++ .../components/cbor/reader_unittest.cc.patch | 47 +++ .../components/cbor/values.cc.patch | 145 +++++++++ .../components/cbor/values.h.patch | 79 +++++ .../components/cbor/writer.cc.patch | 14 + .../components/cbor/writer_unittest.cc.patch | 36 +++ .../clipboard_recent_content_generic.cc.patch | 13 + .../net/dns/dns_config_service_linux.cc.patch | 18 ++ .../weborigin/scheme_registry.cc.patch | 13 + .../122.0.6182.0/url/BUILD.gn.patch | 32 ++ .../122.0.6182.0/url/url_canon.h.patch | 28 ++ .../122.0.6182.0/url/url_canon_ipfs.cc | 55 ++++ .../122.0.6182.0/url/url_util.cc.patch | 17 ++ cmake/chromium.py | 4 +- cmake/patch.py | 2 +- component/block_http_request.cc | 8 +- component/chromium_ipfs_context.cc | 4 +- component/chromium_ipfs_context.h | 4 +- component/inter_request_state.cc | 4 +- ...{121.0.6129.1.patch => 122.0.6182.0.patch} | 55 ++-- doc/design_notes.md | 2 +- library/include/ipfs_client/block_storage.h | 12 +- library/include/ipfs_client/cid.h | 8 +- library/include/ipfs_client/context_api.h | 4 +- .../include/ipfs_client/gw/gateway_request.h | 2 + library/include/ipfs_client/gw/requestor.h | 10 +- library/include/ipfs_client/ipfs_request.h | 2 +- library/include/ipfs_client/ipld/dag_node.h | 40 ++- .../ipfs_client/ipld/resolution_state.h | 36 +++ library/include/ipfs_client/multi_hash.h | 3 + .../ipfs_client/{dag_block.h => pb_dag.h} | 23 +- library/include/ipfs_client/response.h | 4 +- library/include/ipfs_client/test_context.h | 150 ++++++++++ .../libp2p/basic/varint_prefix_reader.hpp | 63 ---- library/include/libp2p/common/hexutil.hpp | 106 ------- library/include/libp2p/crypto/common.hpp | 56 ---- library/include/libp2p/crypto/error.hpp | 92 ------ library/include/libp2p/crypto/hasher.hpp | 55 ---- library/include/libp2p/crypto/sha/sha256.hpp | 48 --- library/include/libp2p/multi/hash_type.hpp | 30 -- .../multibase_codec/multibase_codec_impl.hpp | 29 -- library/include/libp2p/multi/multihash.hpp | 160 ---------- library/include/libp2p/peer/peer_id.hpp | 123 -------- library/include/vocab/byte.h | 6 + library/include/vocab/raw_ptr.h | 2 +- library/include/vocab/slash_delimited.h | 15 +- library/src/ipfs_client/all_inclusive.cc | 114 -------- library/src/ipfs_client/car.cc | 132 +++++++++ library/src/ipfs_client/car.h | 26 ++ library/src/ipfs_client/car_unittest.cc | 70 +++++ library/src/ipfs_client/cid.cc | 23 +- .../ipfs_client/gw/block_request_splitter.cc | 35 +-- .../gw/block_request_splitter_unittest.cc | 8 +- .../gw/dnslink_requestor_unittest.cc | 2 +- .../ipfs_client/gw/gateway_http_requestor.cc | 7 +- .../gw/gateway_http_requestor_unittest.cc | 4 +- library/src/ipfs_client/gw/gateway_request.cc | 49 +++- .../gw/gateway_request_unittest.cc | 107 +++++++ library/src/ipfs_client/gw/requestor.cc | 47 +-- library/src/ipfs_client/gw/requestor_pool.cc | 3 + .../ipfs_client/gw/requestor_pool_unittest.cc | 2 +- .../src/ipfs_client/gw/requestor_unittest.cc | 2 + library/src/ipfs_client/ipld/chunk.cc | 11 +- library/src/ipfs_client/ipld/chunk.h | 2 +- library/src/ipfs_client/ipld/dag_cbor_node.cc | 49 +--- library/src/ipfs_client/ipld/dag_cbor_node.h | 3 +- .../ipld/dag_cbor_node_unittest.cc | 4 +- library/src/ipfs_client/ipld/dag_json_node.cc | 44 +-- library/src/ipfs_client/ipld/dag_json_node.h | 8 +- .../ipld/dag_json_node_unittest.cc | 4 +- library/src/ipfs_client/ipld/dag_node.cc | 140 ++++++++- .../src/ipfs_client/ipld/directory_shard.cc | 48 ++- .../src/ipfs_client/ipld/directory_shard.h | 6 +- library/src/ipfs_client/ipld/ipns_name.cc | 28 +- library/src/ipfs_client/ipld/ipns_name.h | 5 +- .../src/ipfs_client/ipld/resolution_state.cc | 36 +++ library/src/ipfs_client/ipld/root.cc | 50 ++-- library/src/ipfs_client/ipld/root.h | 4 +- .../src/ipfs_client/ipld/small_directory.cc | 77 +---- .../src/ipfs_client/ipld/small_directory.h | 2 +- library/src/ipfs_client/ipld/symlink.cc | 30 +- library/src/ipfs_client/ipld/symlink.h | 4 +- .../src/ipfs_client/ipld/symlink_unittest.cc | 48 +-- library/src/ipfs_client/ipld/unixfs_file.cc | 22 +- library/src/ipfs_client/ipld/unixfs_file.h | 2 +- library/src/ipfs_client/ipns_record.cc | 19 +- .../src/ipfs_client/ipns_record_unittest.cc | 4 +- library/src/ipfs_client/multi_hash.cc | 23 +- library/src/ipfs_client/orchestrator.cc | 23 +- .../src/ipfs_client/orchestrator_unittest.cc | 17 +- .../ipfs_client/{dag_block.cc => pb_dag.cc} | 54 ++-- ...g_block_unittest.cc => pb_dag_unittest.cc} | 12 +- .../ipfs_client/test_context.cc} | 274 ++++++++---------- library/src/libp2p/crypto/provider.h | 28 -- .../multi/multibase_codec/codecs/base58.cc | 187 ------------ .../multibase_codec/multibase_codec_impl.cc | 127 -------- .../multibase_codec_impl_unittest.cc | 22 -- library/src/libp2p/multi/uvarint.cc | 12 +- library/src/vocab/byte_view.cc | 1 + library/src/vocab/slash_delimited.cc | 53 ++++ ...HvbMqn8G2yWHgaBC4AfiwL9kj96jwCcNbkuKiEsFzu | 2 - ...Bnw8L44WWYq3EQXSwFFoRJnEEoDB4Ht9kLhuiVGxmF | 2 - ...xKnTV7SLbFBPGAsWsH731WuTC829FCoFoqu4hPJydm | 2 - ...EgMrExwSsE8DCjZjahYfHUfkSWRhtqSkQUh4Fk3udD | 3 - ...YYo6CEL8S6PqN8LjJYMso8uDVfnoVHXU8eFT87z3od | 2 - ...ENUYYwCycXw1Unj6rfTeRpe5S54T46qxiEYKRgmfJe | 2 - ...D24KQvDcgyJ8McU2qz57jvN5itbkbNv6EpcZqeQeHb | 14 - ...9FK6BDBniiySNoHWqFNJgojxuZUfZ7eqsHGr7reDwZ | 26 -- ...omv5dZ3qGDkuoGNrtr1UZFSx9K5mBWnvJbts9tKZXo | 14 - ...fW5oZ6XJD2FFj8tUFGZ75ampxUQnUgqVy5zS5aSgLv | Bin 152 -> 0 bytes ...skzFYtigsDBAKuHjtiX1azEUtCtrbXcPi9TK6ES4cX | 6 - ...f27ftwm6vzdilb4l7rka7tb6golom6rurvdtq3dcoy | Bin 0 -> 8501 bytes ...s2jminmh2tmvorbevhw7wo35qjn22jqy3gadkz6fiy | Bin 0 -> 12584 bytes ...fg2f5v7k4gsvazw7iwsjehpq77o54vd4kwdd3fud3y | Bin 0 -> 356 bytes test_data/cars/carv2-basic.car | Bin 0 -> 715 bytes test_data/include/mock_api.h | 7 +- 129 files changed, 2201 insertions(+), 2064 deletions(-) create mode 100644 .github/workflows/ut.yml create mode 100644 chromium_edits/122.0.6182.0/chrome/browser/BUILD.gn.patch create mode 100644 chromium_edits/122.0.6182.0/chrome/browser/about_flags.cc.patch create mode 100644 chromium_edits/122.0.6182.0/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc.patch create mode 100644 chromium_edits/122.0.6182.0/chrome/browser/chrome_content_browser_client.cc.patch create mode 100644 chromium_edits/122.0.6182.0/chrome/browser/flag-metadata.json.patch create mode 100644 chromium_edits/122.0.6182.0/chrome/browser/flag_descriptions.cc.patch create mode 100644 chromium_edits/122.0.6182.0/chrome/browser/flag_descriptions.h.patch create mode 100644 chromium_edits/122.0.6182.0/chrome/common/chrome_content_client.cc.patch create mode 100644 chromium_edits/122.0.6182.0/components/cbor/reader.cc.patch create mode 100644 chromium_edits/122.0.6182.0/components/cbor/reader.h.patch create mode 100644 chromium_edits/122.0.6182.0/components/cbor/reader_unittest.cc.patch create mode 100644 chromium_edits/122.0.6182.0/components/cbor/values.cc.patch create mode 100644 chromium_edits/122.0.6182.0/components/cbor/values.h.patch create mode 100644 chromium_edits/122.0.6182.0/components/cbor/writer.cc.patch create mode 100644 chromium_edits/122.0.6182.0/components/cbor/writer_unittest.cc.patch create mode 100644 chromium_edits/122.0.6182.0/components/open_from_clipboard/clipboard_recent_content_generic.cc.patch create mode 100644 chromium_edits/122.0.6182.0/net/dns/dns_config_service_linux.cc.patch create mode 100644 chromium_edits/122.0.6182.0/third_party/blink/renderer/platform/weborigin/scheme_registry.cc.patch create mode 100644 chromium_edits/122.0.6182.0/url/BUILD.gn.patch create mode 100644 chromium_edits/122.0.6182.0/url/url_canon.h.patch create mode 100644 chromium_edits/122.0.6182.0/url/url_canon_ipfs.cc create mode 100644 chromium_edits/122.0.6182.0/url/url_util.cc.patch rename component/patches/{121.0.6129.1.patch => 122.0.6182.0.patch} (95%) create mode 100644 library/include/ipfs_client/ipld/resolution_state.h rename library/include/ipfs_client/{dag_block.h => pb_dag.h} (88%) create mode 100644 library/include/ipfs_client/test_context.h delete mode 100644 library/include/libp2p/basic/varint_prefix_reader.hpp delete mode 100644 library/include/libp2p/common/hexutil.hpp delete mode 100644 library/include/libp2p/crypto/common.hpp delete mode 100644 library/include/libp2p/crypto/error.hpp delete mode 100644 library/include/libp2p/crypto/hasher.hpp delete mode 100644 library/include/libp2p/crypto/sha/sha256.hpp delete mode 100644 library/include/libp2p/multi/hash_type.hpp delete mode 100644 library/include/libp2p/multi/multibase_codec/multibase_codec_impl.hpp delete mode 100644 library/include/libp2p/multi/multihash.hpp delete mode 100644 library/include/libp2p/peer/peer_id.hpp delete mode 100644 library/src/ipfs_client/all_inclusive.cc create mode 100644 library/src/ipfs_client/car.cc create mode 100644 library/src/ipfs_client/car.h create mode 100644 library/src/ipfs_client/car_unittest.cc create mode 100644 library/src/ipfs_client/gw/gateway_request_unittest.cc create mode 100644 library/src/ipfs_client/ipld/resolution_state.cc rename library/src/ipfs_client/{dag_block.cc => pb_dag.cc} (75%) rename library/src/ipfs_client/{dag_block_unittest.cc => pb_dag_unittest.cc} (92%) rename library/{include/ipfs_client/all_inclusive.h => src/ipfs_client/test_context.cc} (60%) delete mode 100644 library/src/libp2p/crypto/provider.h delete mode 100644 library/src/libp2p/multi/multibase_codec/codecs/base58.cc delete mode 100644 library/src/libp2p/multi/multibase_codec/multibase_codec_impl.cc delete mode 100644 library/src/libp2p/multi/multibase_codec/multibase_codec_impl_unittest.cc delete mode 100644 test_data/blocks/QmNUHvbMqn8G2yWHgaBC4AfiwL9kj96jwCcNbkuKiEsFzu delete mode 100644 test_data/blocks/QmNVBnw8L44WWYq3EQXSwFFoRJnEEoDB4Ht9kLhuiVGxmF delete mode 100644 test_data/blocks/QmNsxKnTV7SLbFBPGAsWsH731WuTC829FCoFoqu4hPJydm delete mode 100644 test_data/blocks/QmNwEgMrExwSsE8DCjZjahYfHUfkSWRhtqSkQUh4Fk3udD delete mode 100644 test_data/blocks/QmNwYYo6CEL8S6PqN8LjJYMso8uDVfnoVHXU8eFT87z3od delete mode 100644 test_data/blocks/QmP1ENUYYwCycXw1Unj6rfTeRpe5S54T46qxiEYKRgmfJe delete mode 100644 test_data/blocks/QmQQD24KQvDcgyJ8McU2qz57jvN5itbkbNv6EpcZqeQeHb delete mode 100644 test_data/blocks/QmR39FK6BDBniiySNoHWqFNJgojxuZUfZ7eqsHGr7reDwZ delete mode 100644 test_data/blocks/QmRComv5dZ3qGDkuoGNrtr1UZFSx9K5mBWnvJbts9tKZXo delete mode 100644 test_data/blocks/QmX6fW5oZ6XJD2FFj8tUFGZ75ampxUQnUgqVy5zS5aSgLv delete mode 100644 test_data/blocks/QmeVskzFYtigsDBAKuHjtiX1azEUtCtrbXcPi9TK6ES4cX create mode 100644 test_data/blocks/bafybeibn4fxqlm2tf27ftwm6vzdilb4l7rka7tb6golom6rurvdtq3dcoy create mode 100644 test_data/blocks/bafybeiht5cxfaq43s2jminmh2tmvorbevhw7wo35qjn22jqy3gadkz6fiy create mode 100644 test_data/cars/bafybeifyeyhzmhj5fg2f5v7k4gsvazw7iwsjehpq77o54vd4kwdd3fud3y create mode 100644 test_data/cars/carv2-basic.car diff --git a/.github/workflows/library.yml b/.github/workflows/library.yml index bd391e07..b28249cd 100644 --- a/.github/workflows/library.yml +++ b/.github/workflows/library.yml @@ -3,50 +3,14 @@ on: pull_request: release: types: [created] -permissions: - contents: write jobs: test: - name: Run Tests & Publish Coverage Report - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install --yes cmake ninja-build lcov binutils doxygen graphviz libc6{,-dev} valgrind - npm install -g @marp-team/marp-cli - - name: Configure - shell: bash - run: | - mkdir build - cmake \ - -G Ninja \ - -S . \ - -B build \ - -D CMAKE_BUILD_TYPE=Debug - - name: Run Tests - shell: bash - run: cmake --build build --config Debug --target run_tests - - name: Generate Coverage Report - shell: bash - run: cmake --build build --config Debug --target cov - - name: Upload coverage reports to Codecov.com - uses: codecov/codecov-action@v3 - with: - files: build/library/cov.info - - name: Run Doxygen - run: | - cmake --build build --config Debug --target doc - ls -lrth build/doc/html - - name: UpDoc - uses: JamesIves/github-pages-deploy-action@v4 - with: - folder: build/doc/html + uses: little-bear-labs/ipfs-chromium/.github/workflows/ut.yml@flows + tour: + uses: little-bear-labs/ipfs-chromium/.github/workflows/tour.yml@flows build: name: ${{ matrix.config.name }} - needs: test + needs: [test, tour] runs-on: ${{ matrix.config.os }} strategy: fail-fast: true diff --git a/.github/workflows/tour.yml b/.github/workflows/tour.yml index 0c8b9923..f712526f 100644 --- a/.github/workflows/tour.yml +++ b/.github/workflows/tour.yml @@ -1,5 +1,7 @@ name: Tour de IPFS -on: push +on: + push: + workflow_call: jobs: tour: name: Build clitester and exercize various ipfs_client features @@ -73,6 +75,10 @@ jobs: fi } url_case ipfs bafkqacdjmrsw45djor4q ff483d1ff591898a9942916050d2ca3f + true the block itself md5s to b92348005af4ae4795e6f312844fb359, but the response is an HTML preview page url_case ipfs baguqeerah2nswg7r2pvlpbnsz5y4c4pr4wsgbzixdl632w5qxvedqzryf54q 7750fd7b0928f007e1d181763c0dbdb5 - killall python3 + + url_case ipns en.wikipedia-on-ipfs.org/I/HFE_Too_Slow_1.JPG.webp 8238a73ddb12e56f8f3879cc91d2739e + url_case ipfs bafybeieb33pqideyl5ncd33kho622thym5rqv6sujrmelcuhkjlf2hdpu4/Big%20Buck%20Bunny.webm 06d51286e56badb4455594ebed6daba2 + killall python3 2>/dev/null || true diff --git a/.github/workflows/ut.yml b/.github/workflows/ut.yml new file mode 100644 index 00000000..72564395 --- /dev/null +++ b/.github/workflows/ut.yml @@ -0,0 +1,37 @@ +name: Unit Testing +on: + push: + workflow_call: +permissions: + contents: write +jobs: + test: + name: Run Tests & Publish Coverage Report + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install --yes cmake ninja-build lcov binutils doxygen graphviz libc6{,-dev} valgrind + npm install -g @marp-team/marp-cli + - name: Configure + shell: bash + run: | + mkdir build + cmake \ + -G Ninja \ + -S . \ + -B build \ + -D CMAKE_BUILD_TYPE=Debug + - name: Run Tests + shell: bash + run: cmake --build build --config Debug --target run_tests + - name: Generate Coverage Report + shell: bash + run: cmake --build build --config Debug --target cov + - name: Upload coverage reports to Codecov.com + uses: codecov/codecov-action@v3 + with: + files: build/library/cov.info diff --git a/CMakeLists.txt b/CMakeLists.txt index 767c9d1a..1d5e2df8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ set(CHROMIUM_SOURCE_TREE "${CMAKE_CURRENT_BINARY_DIR}/chromium/src" CACHE PATH "Path to chromium/src. If DOWNLOAD_CHROMIUM=TRUE, and it does not exist, it will be created." ) set(CHROMIUM_PROFILE "${CMAKE_BUILD_TYPE}" CACHE STRING "The profile of the current Chromium build.") -set(CXX_VERSION "17" CACHE STRING "The numeric part (year % 100) of the version of the C++ standard to be used. Must be at least 17 (for C++17). Must be one CMake knows about.") +set(CXX_VERSION "20" CACHE STRING "The numeric part (year % 100) of the version of the C++ standard to be used. Must be at least 20 (for C++20). Must be one CMake knows about.") if(DOWNLOAD_CHROMIUM) set(default_dt "${CMAKE_CURRENT_BINARY_DIR}/depot_tools") else() @@ -28,7 +28,7 @@ set(TEST_BY_DEFAULT FALSE CACHE BOOL "Update unit tests as part of the 'all' def set(USE_DOXYGEN TRUE CACHE BOOL "If we should attempt to use Doxygen to generate documentation.") #End of user-configuration cache variables. -if(CXX_VERSION GREATER_EQUAL 17) +if(CXX_VERSION GREATER_EQUAL 20) message(STATUS "Building for C++${CXX_VERSION}") else() message(FATAL_ERROR "Unsupported CXX_VERSION: ${CXX_VERSION}") diff --git a/chromium_edits/122.0.6182.0/chrome/browser/BUILD.gn.patch b/chromium_edits/122.0.6182.0/chrome/browser/BUILD.gn.patch new file mode 100644 index 00000000..361a5a1c --- /dev/null +++ b/chromium_edits/122.0.6182.0/chrome/browser/BUILD.gn.patch @@ -0,0 +1,23 @@ +diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn +index 0fb94c9b9b67e..df25995c80baa 100644 +--- a/chrome/browser/BUILD.gn ++++ b/chrome/browser/BUILD.gn +@@ -40,6 +40,7 @@ import("//rlz/buildflags/buildflags.gni") + import("//sandbox/features.gni") + import("//testing/libfuzzer/fuzzer_test.gni") + import("//third_party/blink/public/public_features.gni") ++import("//third_party/ipfs_client/args.gni") + import("//third_party/protobuf/proto_library.gni") + import("//third_party/webrtc/webrtc.gni") + import("//third_party/widevine/cdm/widevine.gni") +@@ -2596,6 +2597,10 @@ static_library("browser") { + ] + } + ++ if (enable_ipfs) { ++ deps += [ "//components/ipfs" ] ++ } ++ + if (is_chromeos_ash) { + deps += [ "//chrome/browser/screen_ai:screen_ai_dlc_installer" ] + } diff --git a/chromium_edits/122.0.6182.0/chrome/browser/about_flags.cc.patch b/chromium_edits/122.0.6182.0/chrome/browser/about_flags.cc.patch new file mode 100644 index 00000000..addab35d --- /dev/null +++ b/chromium_edits/122.0.6182.0/chrome/browser/about_flags.cc.patch @@ -0,0 +1,38 @@ +diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc +index 52ecc40da0226..42d45b977471e 100644 +--- a/chrome/browser/about_flags.cc ++++ b/chrome/browser/about_flags.cc +@@ -213,6 +213,7 @@ + #include "third_party/blink/public/common/features_generated.h" + #include "third_party/blink/public/common/forcedark/forcedark_switches.h" + #include "third_party/blink/public/common/switches.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + #include "ui/accessibility/accessibility_features.h" + #include "ui/accessibility/accessibility_switches.h" + #include "ui/base/ui_base_features.h" +@@ -313,6 +314,10 @@ + #include "extensions/common/switches.h" + #endif // BUILDFLAG(ENABLE_EXTENSIONS) + ++#if BUILDFLAG(ENABLE_IPFS) ++#include "components/ipfs/ipfs_features.h" ++#endif ++ + #if BUILDFLAG(ENABLE_PDF) + #include "pdf/pdf_features.h" + #endif +@@ -9851,6 +9856,14 @@ const FeatureEntry kFeatureEntries[] = { + flag_descriptions::kOmitCorsClientCertDescription, kOsAll, + FEATURE_VALUE_TYPE(network::features::kOmitCorsClientCert)}, + ++#if BUILDFLAG(ENABLE_IPFS) ++ {"enable-ipfs", ++ flag_descriptions::kEnableIpfsName, ++ flag_descriptions::kEnableIpfsDescription, ++ kOsMac | kOsWin | kOsLinux,//TODO: These are the only variants currently getting built, but that is not likely to remain the case ++ FEATURE_VALUE_TYPE(ipfs::kEnableIpfs)}, ++#endif ++ + {"use-idna2008-non-transitional", + flag_descriptions::kUseIDNA2008NonTransitionalName, + flag_descriptions::kUseIDNA2008NonTransitionalDescription, kOsAll, diff --git a/chromium_edits/122.0.6182.0/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc.patch b/chromium_edits/122.0.6182.0/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc.patch new file mode 100644 index 00000000..4d172311 --- /dev/null +++ b/chromium_edits/122.0.6182.0/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc.patch @@ -0,0 +1,50 @@ +diff --git a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc +index 4c88614c68c25..f8bb12a3b0c2e 100644 +--- a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc ++++ b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc +@@ -10,6 +10,8 @@ + #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" + #include "chrome/browser/external_protocol/external_protocol_handler.h" + #include "chrome/browser/profiles/profile.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" ++ + #if BUILDFLAG(IS_ANDROID) + #include "chrome/browser/profiles/profile_android.h" + #endif +@@ -18,6 +20,9 @@ + #include "chrome/browser/ui/android/omnibox/jni_headers/ChromeAutocompleteSchemeClassifier_jni.h" + #endif + #include "components/custom_handlers/protocol_handler_registry.h" ++#if BUILDFLAG(ENABLE_IPFS) ++#include "components/ipfs/ipfs_features.h" ++#endif + #include "content/public/common/url_constants.h" + #include "url/url_util.h" + +@@ -55,12 +60,20 @@ ChromeAutocompleteSchemeClassifier::GetInputTypeForScheme( + if (scheme.empty()) { + return metrics::OmniboxInputType::EMPTY; + } +- if (base::IsStringASCII(scheme) && +- (ProfileIOData::IsHandledProtocol(scheme) || +- base::EqualsCaseInsensitiveASCII(scheme, content::kViewSourceScheme) || +- base::EqualsCaseInsensitiveASCII(scheme, url::kJavaScriptScheme) || +- base::EqualsCaseInsensitiveASCII(scheme, url::kDataScheme))) { +- return metrics::OmniboxInputType::URL; ++ if (base::IsStringASCII(scheme)) { ++ if (ProfileIOData::IsHandledProtocol(scheme) || ++ base::EqualsCaseInsensitiveASCII(scheme, content::kViewSourceScheme) || ++ base::EqualsCaseInsensitiveASCII(scheme, url::kJavaScriptScheme) || ++ base::EqualsCaseInsensitiveASCII(scheme, url::kDataScheme)) { ++ return metrics::OmniboxInputType::URL; ++ } ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs) && ++ (base::EqualsCaseInsensitiveASCII(scheme, "ipfs") || base::EqualsCaseInsensitiveASCII(scheme, "ipns")) ++ ) { ++ return metrics::OmniboxInputType::URL; ++ } ++#endif + } + + // Also check for schemes registered via registerProtocolHandler(), which diff --git a/chromium_edits/122.0.6182.0/chrome/browser/chrome_content_browser_client.cc.patch b/chromium_edits/122.0.6182.0/chrome/browser/chrome_content_browser_client.cc.patch new file mode 100644 index 00000000..f212961c --- /dev/null +++ b/chromium_edits/122.0.6182.0/chrome/browser/chrome_content_browser_client.cc.patch @@ -0,0 +1,63 @@ +diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc +index a9b87ac2fcd74..987686c621664 100644 +--- a/chrome/browser/chrome_content_browser_client.cc ++++ b/chrome/browser/chrome_content_browser_client.cc +@@ -377,6 +377,7 @@ + #include "third_party/blink/public/common/switches.h" + #include "third_party/blink/public/mojom/browsing_topics/browsing_topics.mojom.h" + #include "third_party/blink/public/public_buildflags.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + #include "third_party/widevine/cdm/buildflags.h" + #include "ui/base/clipboard/clipboard_format_type.h" + #include "ui/base/l10n/l10n_util.h" +@@ -499,6 +500,12 @@ + #include "chrome/browser/fuchsia/chrome_browser_main_parts_fuchsia.h" + #endif + ++#if BUILDFLAG(ENABLE_IPFS) ++#include "components/ipfs/interceptor.h" ++#include "components/ipfs/ipfs_features.h" ++#include "components/ipfs/url_loader_factory.h" ++#endif ++ + #if BUILDFLAG(IS_CHROMEOS) + #include "base/debug/leak_annotations.h" + #include "chrome/browser/apps/app_service/app_install/app_install_navigation_throttle.h" +@@ -6157,12 +6164,23 @@ void ChromeContentBrowserClient:: + const absl::optional& request_initiator_origin, + NonNetworkURLLoaderFactoryMap* factories) { + #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(ENABLE_EXTENSIONS) || \ +- !BUILDFLAG(IS_ANDROID) ++ !BUILDFLAG(IS_ANDROID) || BUILDFLAG(ENABLE_IPFS) + content::RenderFrameHost* frame_host = + RenderFrameHost::FromID(render_process_id, render_frame_id); + WebContents* web_contents = WebContents::FromRenderFrameHost(frame_host); + #endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(ENABLE_EXTENSIONS) || \ +- // !BUILDFLAG(IS_ANDROID) ++ // !BUILDFLAG(IS_ANDROID) || BUILDFLAG(ENABLE_IPFS) ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ network::mojom::URLLoaderFactory* default_factory = g_browser_process->system_network_context_manager()->GetURLLoaderFactory(); ++ ipfs::IpfsURLLoaderFactory::Create( ++ factories, ++ web_contents->GetBrowserContext(), ++ default_factory, ++ GetSystemNetworkContext() ++ ); ++ } ++#endif // BUILDFLAG(ENABLE_IPFS) + + #if BUILDFLAG(IS_CHROMEOS_ASH) + if (web_contents) { +@@ -6304,6 +6322,11 @@ ChromeContentBrowserClient::WillCreateURLLoaderRequestInterceptors( + scoped_refptr navigation_response_task_runner) { + std::vector> + interceptors; ++#if BUILDFLAG(ENABLE_IPFS) ++ if (base::FeatureList::IsEnabled(ipfs::kEnableIpfs)) { ++ interceptors.push_back(std::make_unique(g_browser_process->system_network_context_manager()->GetURLLoaderFactory(), GetSystemNetworkContext())); ++ } ++#endif + #if BUILDFLAG(ENABLE_OFFLINE_PAGES) + interceptors.push_back( + std::make_unique( diff --git a/chromium_edits/122.0.6182.0/chrome/browser/flag-metadata.json.patch b/chromium_edits/122.0.6182.0/chrome/browser/flag-metadata.json.patch new file mode 100644 index 00000000..b1fe0af9 --- /dev/null +++ b/chromium_edits/122.0.6182.0/chrome/browser/flag-metadata.json.patch @@ -0,0 +1,16 @@ +diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json +index 5e02e86a700cb..1f06bded184bf 100644 +--- a/chrome/browser/flag-metadata.json ++++ b/chrome/browser/flag-metadata.json +@@ -2956,6 +2956,11 @@ + "owners": [ "hanxi@chromium.org", "wychen@chromium.org" ], + "expiry_milestone": 130 + }, ++ { ++ "name": "enable-ipfs", ++ "owners": [ "//components/ipfs/OWNERS" ], ++ "expiry_milestone": 150 ++ }, + { + "name": "enable-isolated-sandboxed-iframes", + "owners": [ "wjmaclean@chromium.org", "alexmos@chromium.org", "creis@chromium.org" ], diff --git a/chromium_edits/122.0.6182.0/chrome/browser/flag_descriptions.cc.patch b/chromium_edits/122.0.6182.0/chrome/browser/flag_descriptions.cc.patch new file mode 100644 index 00000000..15c80675 --- /dev/null +++ b/chromium_edits/122.0.6182.0/chrome/browser/flag_descriptions.cc.patch @@ -0,0 +1,16 @@ +diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc +index d6073d3514930..f80f1330f9865 100644 +--- a/chrome/browser/flag_descriptions.cc ++++ b/chrome/browser/flag_descriptions.cc +@@ -288,6 +288,11 @@ const char kEnableBenchmarkingDescription[] = + "after 3 restarts. On the third restart, the flag will appear to be off " + "but the effect is still active."; + ++#if BUILDFLAG(ENABLE_IPFS) ++extern const char kEnableIpfsName[] = "Enable IPFS"; ++extern const char kEnableIpfsDescription[] = "Enable ipfs:// and ipns:// URLs"; ++#endif ++ + const char kPreloadingOnPerformancePageName[] = + "Preloading Settings on Performance Page"; + const char kPreloadingOnPerformancePageDescription[] = diff --git a/chromium_edits/122.0.6182.0/chrome/browser/flag_descriptions.h.patch b/chromium_edits/122.0.6182.0/chrome/browser/flag_descriptions.h.patch new file mode 100644 index 00000000..f5e7ba0e --- /dev/null +++ b/chromium_edits/122.0.6182.0/chrome/browser/flag_descriptions.h.patch @@ -0,0 +1,24 @@ +diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h +index 4df49302f94b5..f7d3b65112d8b 100644 +--- a/chrome/browser/flag_descriptions.h ++++ b/chrome/browser/flag_descriptions.h +@@ -23,6 +23,7 @@ + #include "pdf/buildflags.h" + #include "printing/buildflags/buildflags.h" + #include "third_party/blink/public/common/buildflags.h" ++#include "third_party/ipfs_client/ipfs_buildflags.h" + + // This file declares strings used in chrome://flags. These messages are not + // translated, because instead of end-users they target Chromium developers and +@@ -179,6 +180,11 @@ extern const char kDownloadWarningImprovementsDescription[]; + extern const char kEnableBenchmarkingName[]; + extern const char kEnableBenchmarkingDescription[]; + ++#if BUILDFLAG(ENABLE_IPFS) ++extern const char kEnableIpfsName[]; ++extern const char kEnableIpfsDescription[]; ++#endif ++ + #if BUILDFLAG(USE_FONTATIONS_BACKEND) + extern const char kFontationsFontBackendName[]; + extern const char kFontationsFontBackendDescription[]; diff --git a/chromium_edits/122.0.6182.0/chrome/common/chrome_content_client.cc.patch b/chromium_edits/122.0.6182.0/chrome/common/chrome_content_client.cc.patch new file mode 100644 index 00000000..5bd09f16 --- /dev/null +++ b/chromium_edits/122.0.6182.0/chrome/common/chrome_content_client.cc.patch @@ -0,0 +1,17 @@ +diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc +index 246ec9c5c911f..5d66d133a7907 100644 +--- a/chrome/common/chrome_content_client.cc ++++ b/chrome/common/chrome_content_client.cc +@@ -296,6 +296,12 @@ void ChromeContentClient::AddAdditionalSchemes(Schemes* schemes) { + #if BUILDFLAG(IS_ANDROID) + schemes->local_schemes.push_back(url::kContentScheme); + #endif ++ for ( const char* ip_s : {"ipfs", "ipns"} ) { ++ schemes->standard_schemes.push_back(ip_s); ++ schemes->cors_enabled_schemes.push_back(ip_s); ++ schemes->secure_schemes.push_back(ip_s); ++ schemes->csp_bypassing_schemes.push_back(ip_s); ++ } + } + + std::u16string ChromeContentClient::GetLocalizedString(int message_id) { diff --git a/chromium_edits/122.0.6182.0/components/cbor/reader.cc.patch b/chromium_edits/122.0.6182.0/components/cbor/reader.cc.patch new file mode 100644 index 00000000..aed86452 --- /dev/null +++ b/chromium_edits/122.0.6182.0/components/cbor/reader.cc.patch @@ -0,0 +1,44 @@ +diff --git a/components/cbor/reader.cc b/components/cbor/reader.cc +index 306ba52fa4944..6b13b3a679a65 100644 +--- a/components/cbor/reader.cc ++++ b/components/cbor/reader.cc +@@ -22,7 +22,7 @@ + namespace cbor { + + namespace constants { +-const char kUnsupportedMajorType[] = "Unsupported major type."; ++const char kUnsupportedMajorType[] = "Unsupported major type operation."; + } + + namespace { +@@ -156,7 +156,11 @@ absl::optional Reader::DecodeCompleteDataItem(const Config& config, + case Value::Type::FLOAT_VALUE: + // Floating point values also go here since they are also type 7. + return DecodeToSimpleValueOrFloat(*header, config); +- case Value::Type::TAG: // We explicitly don't support TAG. ++ case Value::Type::TAG: ++ if (config.parse_tags) { ++ return ReadTagContent(*header, config, max_nesting_level); ++ } ++ break; + case Value::Type::NONE: + case Value::Type::INVALID_UTF8: + break; +@@ -347,6 +351,17 @@ absl::optional Reader::ReadByteStringContent( + return Value(std::move(cbor_byte_string)); + } + ++absl::optional Reader::ReadTagContent( ++ const Reader::DataItemHeader& header, ++ const Config& config, ++ int max_nesting_level) { ++ auto tagged_content = DecodeCompleteDataItem(config, max_nesting_level); ++ if (tagged_content.has_value()) { ++ tagged_content.value().SetTag(header.value); ++ } ++ return tagged_content; ++} ++ + absl::optional Reader::ReadArrayContent( + const Reader::DataItemHeader& header, + const Config& config, diff --git a/chromium_edits/122.0.6182.0/components/cbor/reader.h.patch b/chromium_edits/122.0.6182.0/components/cbor/reader.h.patch new file mode 100644 index 00000000..fb821165 --- /dev/null +++ b/chromium_edits/122.0.6182.0/components/cbor/reader.h.patch @@ -0,0 +1,26 @@ +diff --git a/components/cbor/reader.h b/components/cbor/reader.h +index f0b43a5517528..a57e277a1bc66 100644 +--- a/components/cbor/reader.h ++++ b/components/cbor/reader.h +@@ -130,6 +130,11 @@ class CBOR_EXPORT Reader { + // during decoding will set raise the `UNSUPPORTED_FLOATING_POINT_VALUE` + // error. + bool allow_floating_point = false; ++ ++ // If the parser encounters a TAG element, should it be parsed out and ++ // the tag value saved (true), or should the entire node and its content ++ // be discarded (false) ++ bool parse_tags = false; + }; + + Reader(const Reader&) = delete; +@@ -204,6 +209,9 @@ class CBOR_EXPORT Reader { + absl::optional ReadMapContent(const DataItemHeader& header, + const Config& config, + int max_nesting_level); ++ absl::optional ReadTagContent(const DataItemHeader& header, ++ const Config& config, ++ int max_nesting_level); + absl::optional ReadByte(); + absl::optional> ReadBytes(uint64_t num_bytes); + bool IsKeyInOrder(const Value& new_key, diff --git a/chromium_edits/122.0.6182.0/components/cbor/reader_unittest.cc.patch b/chromium_edits/122.0.6182.0/components/cbor/reader_unittest.cc.patch new file mode 100644 index 00000000..3f657dc3 --- /dev/null +++ b/chromium_edits/122.0.6182.0/components/cbor/reader_unittest.cc.patch @@ -0,0 +1,47 @@ +diff --git a/components/cbor/reader_unittest.cc b/components/cbor/reader_unittest.cc +index 83d44a48d6dfa..a6ec5299b3241 100644 +--- a/components/cbor/reader_unittest.cc ++++ b/components/cbor/reader_unittest.cc +@@ -1451,5 +1451,42 @@ TEST(CBORReaderTest, AllowInvalidUTF8) { + EXPECT_FALSE(cbor); + EXPECT_EQ(Reader::DecoderError::INVALID_UTF8, error); + } ++TEST(CBORReaderTest, RejectsTagUnderDefaultConfig) { ++ static const uint8_t kTaggedCbor[] = { ++ 0xd8, 0x2a, 0x58, 0x25, 0x00, 0x01, 0x71, 0x12, 0x20, 0x69, 0xea, 0x07, ++ 0x40, 0xf9, 0x80, 0x7a, 0x28, 0xf4, 0xd9, 0x32, 0xc6, 0x2e, 0x7c, 0x1c, ++ 0x83, 0xbe, 0x05, 0x5e, 0x55, 0x07, 0x2c, 0x90, 0x26, 0x6a, 0xb3, 0xe7, ++ 0x9d, 0xf6, 0x3a, 0x36, 0x5b ++ }; ++ Reader::Config config; ++ absl::optional cbor = Reader::Read(kTaggedCbor, config); ++ EXPECT_FALSE(cbor.has_value()); ++} ++TEST(CBORReaderTest, ReadsTagWhenConfiguredToDoSo) { ++ static const uint8_t kTaggedCbor[] = { ++ 0xd8, 0x2a, 0x58, 0x25, 0x00, 0x01, 0x71, 0x12, 0x20, 0x69, 0xea, 0x07, ++ 0x40, 0xf9, 0x80, 0x7a, 0x28, 0xf4, 0xd9, 0x32, 0xc6, 0x2e, 0x7c, 0x1c, ++ 0x83, 0xbe, 0x05, 0x5e, 0x55, 0x07, 0x2c, 0x90, 0x26, 0x6a, 0xb3, 0xe7, ++ 0x9d, 0xf6, 0x3a, 0x36, 0x5b ++ }; ++ Reader::Config config; ++ config.parse_tags = true; ++ absl::optional cbor = Reader::Read(kTaggedCbor, config); ++ EXPECT_TRUE(cbor.has_value()); ++ auto& v = cbor.value(); ++ EXPECT_TRUE(v.has_tag()); ++ EXPECT_EQ(v.GetTag(),42UL); ++ EXPECT_TRUE(v.is_bytestring()); ++ EXPECT_EQ(v.type(), Value::Type::BYTE_STRING); ++ auto& bytes = v.GetBytestring(); ++ EXPECT_EQ(bytes.size(), 37UL); ++ EXPECT_EQ(bytes.at(0), 0x00);//identity multibase (e.g. not base-encoded, bytes are themselves) ++ EXPECT_EQ(bytes.at(1), 0x01);//CID version 1 ++ EXPECT_EQ(bytes.at(2), 0x71);//codec = dag-cbor ++ EXPECT_EQ(bytes.at(3), 0x12);//multihash = 18 = sha2-256 ++ EXPECT_EQ(bytes.at(4), 0x20);//hash length = 32 bytes ++ EXPECT_EQ(bytes.at(5), 0x69);//first byte of hash digest ++ EXPECT_EQ(bytes.at(36),0x5b);//last byte of hash digest ++} + + } // namespace cbor diff --git a/chromium_edits/122.0.6182.0/components/cbor/values.cc.patch b/chromium_edits/122.0.6182.0/components/cbor/values.cc.patch new file mode 100644 index 00000000..ddbab2b3 --- /dev/null +++ b/chromium_edits/122.0.6182.0/components/cbor/values.cc.patch @@ -0,0 +1,145 @@ +diff --git a/components/cbor/values.cc b/components/cbor/values.cc +index 02498209c820e..34055aef24cfe 100644 +--- a/components/cbor/values.cc ++++ b/components/cbor/values.cc +@@ -66,32 +66,34 @@ Value::Value(Type type) : type_(type) { + NOTREACHED(); + } + +-Value::Value(SimpleValue in_simple) +- : type_(Type::SIMPLE_VALUE), simple_value_(in_simple) { ++Value::Value(SimpleValue in_simple, uint64_t tag) ++ : type_(Type::SIMPLE_VALUE), simple_value_(in_simple), tag_(tag) { + CHECK(static_cast(in_simple) >= 20 && static_cast(in_simple) <= 23); + } + +-Value::Value(bool boolean_value) : type_(Type::SIMPLE_VALUE) { ++Value::Value(bool boolean_value, uint64_t tag) : type_(Type::SIMPLE_VALUE), tag_(tag) { + simple_value_ = boolean_value ? Value::SimpleValue::TRUE_VALUE + : Value::SimpleValue::FALSE_VALUE; + } + +-Value::Value(double float_value) +- : type_(Type::FLOAT_VALUE), float_value_(float_value) {} ++Value::Value(double float_value, uint64_t tag) ++ : type_(Type::FLOAT_VALUE), float_value_(float_value), tag_(tag) {} + +-Value::Value(int integer_value) +- : Value(base::checked_cast(integer_value)) {} ++Value::Value(int integer_value, uint64_t tag) ++ : Value(base::checked_cast(integer_value), tag) {} + +-Value::Value(int64_t integer_value) : integer_value_(integer_value) { ++Value::Value(int64_t integer_value, uint64_t tag) : integer_value_(integer_value), tag_(tag) { + type_ = integer_value >= 0 ? Type::UNSIGNED : Type::NEGATIVE; + } + +-Value::Value(base::span in_bytes) ++Value::Value(base::span in_bytes, uint64_t tag) + : type_(Type::BYTE_STRING), +- bytestring_value_(in_bytes.begin(), in_bytes.end()) {} ++ bytestring_value_(in_bytes.begin(), in_bytes.end()), ++ tag_(tag) ++ {} + +-Value::Value(base::span in_bytes, Type type) +- : type_(type), bytestring_value_(in_bytes.begin(), in_bytes.end()) { ++Value::Value(base::span in_bytes, Type type, uint64_t tag) ++ : type_(type), bytestring_value_(in_bytes.begin(), in_bytes.end()), tag_(tag) { + DCHECK(type_ == Type::BYTE_STRING || type_ == Type::INVALID_UTF8); + } + +@@ -117,7 +119,8 @@ Value::Value(std::string&& in_string, Type type) noexcept : type_(type) { + } + } + +-Value::Value(base::StringPiece in_string, Type type) : type_(type) { ++Value::Value(base::StringPiece in_string, Type type, uint64_t tag) ++: type_(type), tag_(tag) { + switch (type_) { + case Type::STRING: + new (&string_value_) std::string(); +@@ -133,16 +136,18 @@ Value::Value(base::StringPiece in_string, Type type) : type_(type) { + } + } + +-Value::Value(const ArrayValue& in_array) : type_(Type::ARRAY), array_value_() { ++Value::Value(const ArrayValue& in_array, uint64_t tag) ++: type_(Type::ARRAY), array_value_(), tag_(tag) { + array_value_.reserve(in_array.size()); + for (const auto& val : in_array) + array_value_.emplace_back(val.Clone()); + } + +-Value::Value(ArrayValue&& in_array) noexcept +- : type_(Type::ARRAY), array_value_(std::move(in_array)) {} ++Value::Value(ArrayValue&& in_array, uint64_t tag) noexcept ++ : type_(Type::ARRAY), array_value_(std::move(in_array)), tag_(tag) {} + +-Value::Value(const MapValue& in_map) : type_(Type::MAP), map_value_() { ++Value::Value(const MapValue& in_map, uint64_t tag) ++: type_(Type::MAP), map_value_(), tag_(tag) { + map_value_.reserve(in_map.size()); + for (const auto& it : in_map) + map_value_.emplace_hint(map_value_.end(), it.first.Clone(), +@@ -168,31 +173,36 @@ Value Value::Clone() const { + case Type::NONE: + return Value(); + case Type::INVALID_UTF8: +- return Value(bytestring_value_, Type::INVALID_UTF8); ++ return Value(bytestring_value_, Type::INVALID_UTF8, tag_); + case Type::UNSIGNED: + case Type::NEGATIVE: +- return Value(integer_value_); ++ return Value(integer_value_, tag_); + case Type::BYTE_STRING: +- return Value(bytestring_value_); ++ return Value(bytestring_value_, tag_); + case Type::STRING: +- return Value(string_value_); ++ return Value(string_value_, Type::STRING, tag_); + case Type::ARRAY: +- return Value(array_value_); ++ return Value(array_value_, tag_); + case Type::MAP: +- return Value(map_value_); ++ return Value(map_value_, tag_); + case Type::TAG: + NOTREACHED() << constants::kUnsupportedMajorType; + return Value(); + case Type::SIMPLE_VALUE: +- return Value(simple_value_); ++ return Value(simple_value_, tag_); + case Type::FLOAT_VALUE: +- return Value(float_value_); ++ return Value(float_value_, tag_); + } + + NOTREACHED(); + return Value(); + } + ++Value& Value::SetTag(uint64_t tag) noexcept { ++ tag_ = tag; ++ return *this; ++} ++ + Value::SimpleValue Value::GetSimpleValue() const { + CHECK(is_simple()); + return simple_value_; +@@ -258,9 +268,14 @@ const Value::BinaryValue& Value::GetInvalidUTF8() const { + return bytestring_value_; + } + ++uint64_t Value::GetTag() const { ++ CHECK(has_tag()); ++ return tag_; ++} ++ + void Value::InternalMoveConstructFrom(Value&& that) { + type_ = that.type_; +- ++ tag_ = that.tag_; + switch (type_) { + case Type::UNSIGNED: + case Type::NEGATIVE: diff --git a/chromium_edits/122.0.6182.0/components/cbor/values.h.patch b/chromium_edits/122.0.6182.0/components/cbor/values.h.patch new file mode 100644 index 00000000..ca39df01 --- /dev/null +++ b/chromium_edits/122.0.6182.0/components/cbor/values.h.patch @@ -0,0 +1,79 @@ +diff --git a/components/cbor/values.h b/components/cbor/values.h +index d81ef5607c55a..10216a8dcdc57 100644 +--- a/components/cbor/values.h ++++ b/components/cbor/values.h +@@ -127,28 +127,29 @@ class CBOR_EXPORT Value { + + explicit Value(Type type); + +- explicit Value(SimpleValue in_simple); +- explicit Value(bool boolean_value); +- explicit Value(double in_float); ++ explicit Value(SimpleValue in_simple, uint64_t tag = NO_TAG); ++ explicit Value(bool boolean_value, uint64_t tag = NO_TAG); ++ explicit Value(double in_float, uint64_t tag = NO_TAG); + +- explicit Value(int integer_value); +- explicit Value(int64_t integer_value); ++ explicit Value(int integer_value, uint64_t tag = NO_TAG); ++ explicit Value(int64_t integer_value, uint64_t tag = NO_TAG); + explicit Value(uint64_t integer_value) = delete; + +- explicit Value(base::span in_bytes); ++ explicit Value(base::span in_bytes, uint64_t tag = NO_TAG); + explicit Value(BinaryValue&& in_bytes) noexcept; + + explicit Value(const char* in_string, Type type = Type::STRING); + explicit Value(std::string&& in_string, Type type = Type::STRING) noexcept; +- explicit Value(base::StringPiece in_string, Type type = Type::STRING); ++ explicit Value(base::StringPiece in_string, Type type = Type::STRING, uint64_t tag = NO_TAG); + +- explicit Value(const ArrayValue& in_array); +- explicit Value(ArrayValue&& in_array) noexcept; ++ explicit Value(const ArrayValue& in_array, uint64_t tag = NO_TAG); ++ explicit Value(ArrayValue&& in_array, uint64_t tag = NO_TAG) noexcept; + +- explicit Value(const MapValue& in_map); ++ explicit Value(const MapValue& in_map, uint64_t tag = NO_TAG); + explicit Value(MapValue&& in_map) noexcept; + + Value& operator=(Value&& that) noexcept; ++ Value& SetTag(uint64_t) noexcept; + + Value(const Value&) = delete; + Value& operator=(const Value&) = delete; +@@ -179,6 +180,7 @@ class CBOR_EXPORT Value { + bool is_string() const { return type() == Type::STRING; } + bool is_array() const { return type() == Type::ARRAY; } + bool is_map() const { return type() == Type::MAP; } ++ bool has_tag() const { return tag_ != NO_TAG; } + + // These will all fatally assert if the type doesn't match. + SimpleValue GetSimpleValue() const; +@@ -194,12 +196,13 @@ class CBOR_EXPORT Value { + const ArrayValue& GetArray() const; + const MapValue& GetMap() const; + const BinaryValue& GetInvalidUTF8() const; ++ uint64_t GetTag() const; + + private: + friend class Reader; + // This constructor allows INVALID_UTF8 values to be created, which only + // |Reader| and InvalidUTF8StringValueForTesting() may do. +- Value(base::span in_bytes, Type type); ++ Value(base::span in_bytes, Type type, uint64_t tag = NO_TAG); + + Type type_; + +@@ -213,6 +216,11 @@ class CBOR_EXPORT Value { + MapValue map_value_; + }; + ++ //This value specified as Invalid, ++ // used here to represent absence of TAG ++ constexpr static uint64_t NO_TAG = 0xFFFF; ++ uint64_t tag_ = NO_TAG; ++ + void InternalMoveConstructFrom(Value&& that); + void InternalCleanup(); + }; diff --git a/chromium_edits/122.0.6182.0/components/cbor/writer.cc.patch b/chromium_edits/122.0.6182.0/components/cbor/writer.cc.patch new file mode 100644 index 00000000..21fe28ce --- /dev/null +++ b/chromium_edits/122.0.6182.0/components/cbor/writer.cc.patch @@ -0,0 +1,14 @@ +diff --git a/components/cbor/writer.cc b/components/cbor/writer.cc +index bb22754d36a07..aae4027836377 100644 +--- a/components/cbor/writer.cc ++++ b/components/cbor/writer.cc +@@ -47,6 +47,9 @@ bool Writer::EncodeCBOR(const Value& node, + if (max_nesting_level < 0) + return false; + ++ if (node.has_tag()) { ++ StartItem(Value::Type::TAG, node.GetTag()); ++ } + switch (node.type()) { + case Value::Type::NONE: { + StartItem(Value::Type::BYTE_STRING, 0); diff --git a/chromium_edits/122.0.6182.0/components/cbor/writer_unittest.cc.patch b/chromium_edits/122.0.6182.0/components/cbor/writer_unittest.cc.patch new file mode 100644 index 00000000..240fee83 --- /dev/null +++ b/chromium_edits/122.0.6182.0/components/cbor/writer_unittest.cc.patch @@ -0,0 +1,36 @@ +diff --git a/components/cbor/writer_unittest.cc b/components/cbor/writer_unittest.cc +index e3bffe20734bc..0ed569ae164a0 100644 +--- a/components/cbor/writer_unittest.cc ++++ b/components/cbor/writer_unittest.cc +@@ -522,4 +522,31 @@ TEST(CBORWriterTest, OverlyNestedCBOR) { + EXPECT_FALSE(Writer::Write(Value(map), 4).has_value()); + } + ++TEST(CBORWriterTest, CanWriteTag) { ++ std::array content{ ++ 0x00, 0x01, 0x71, 0x12, 0x20, ++ 0x69, 0xea, 0x07, 0x40, 0xf9, ++ 0x80, 0x7a, 0x28, 0xf4, 0xd9, ++ 0x32, 0xc6, 0x2e, 0x7c, 0x1c, ++ 0x83, 0xbe, 0x05, 0x5e, 0x55, ++ 0x07, 0x2c, 0x90, 0x26, 0x6a, ++ 0xb3, 0xe7, 0x9d, 0xf6, 0x3a, ++ 0x36, 0x5b ++ }; ++ Value to_write(content); ++ to_write.SetTag(42); ++ auto result = Writer::Write(to_write); ++ EXPECT_TRUE(result.has_value()); ++ auto& bytes = result.value(); ++ EXPECT_EQ(bytes.size(), 41UL); ++ EXPECT_EQ(bytes.at(0), 0xd8); ++ EXPECT_EQ(bytes.at(1), 0x2a); ++ EXPECT_EQ(bytes.at(2), 0x58); ++ EXPECT_EQ(bytes.at(3), 0x25); ++ for (auto i = 0UL; i < content.size(); ++i) { ++ ASSERT_LT(i + 4UL, bytes.size()); ++ ASSERT_EQ(content.at(i), bytes.at(i+4UL)); ++ } ++} ++ + } // namespace cbor diff --git a/chromium_edits/122.0.6182.0/components/open_from_clipboard/clipboard_recent_content_generic.cc.patch b/chromium_edits/122.0.6182.0/components/open_from_clipboard/clipboard_recent_content_generic.cc.patch new file mode 100644 index 00000000..891b53df --- /dev/null +++ b/chromium_edits/122.0.6182.0/components/open_from_clipboard/clipboard_recent_content_generic.cc.patch @@ -0,0 +1,13 @@ +diff --git a/components/open_from_clipboard/clipboard_recent_content_generic.cc b/components/open_from_clipboard/clipboard_recent_content_generic.cc +index 4dcafecbc66c6..d205209c08162 100644 +--- a/components/open_from_clipboard/clipboard_recent_content_generic.cc ++++ b/components/open_from_clipboard/clipboard_recent_content_generic.cc +@@ -20,7 +20,7 @@ + namespace { + // Schemes appropriate for suggestion by ClipboardRecentContent. + const char* kAuthorizedSchemes[] = { +- url::kAboutScheme, url::kDataScheme, url::kHttpScheme, url::kHttpsScheme, ++ url::kAboutScheme, url::kDataScheme, url::kHttpScheme, url::kHttpsScheme, "ipfs", "ipns" + // TODO(mpearson): add support for chrome:// URLs. Right now the scheme + // for that lives in content and is accessible via + // GetEmbedderRepresentationOfAboutScheme() or content::kChromeUIScheme diff --git a/chromium_edits/122.0.6182.0/net/dns/dns_config_service_linux.cc.patch b/chromium_edits/122.0.6182.0/net/dns/dns_config_service_linux.cc.patch new file mode 100644 index 00000000..a5e9863f --- /dev/null +++ b/chromium_edits/122.0.6182.0/net/dns/dns_config_service_linux.cc.patch @@ -0,0 +1,18 @@ +diff --git a/net/dns/dns_config_service_linux.cc b/net/dns/dns_config_service_linux.cc +index 5273da5190277..12b28b86a4c00 100644 +--- a/net/dns/dns_config_service_linux.cc ++++ b/net/dns/dns_config_service_linux.cc +@@ -272,11 +272,11 @@ bool IsNsswitchConfigCompatible( + // Ignore any entries after `kDns` because Chrome will fallback to the + // system resolver if a result was not found in DNS. + return true; +- ++ case NsswitchReader::Service::kResolve: ++ break; + case NsswitchReader::Service::kMdns: + case NsswitchReader::Service::kMdns4: + case NsswitchReader::Service::kMdns6: +- case NsswitchReader::Service::kResolve: + case NsswitchReader::Service::kNis: + RecordIncompatibleNsswitchReason( + IncompatibleNsswitchReason::kIncompatibleService, diff --git a/chromium_edits/122.0.6182.0/third_party/blink/renderer/platform/weborigin/scheme_registry.cc.patch b/chromium_edits/122.0.6182.0/third_party/blink/renderer/platform/weborigin/scheme_registry.cc.patch new file mode 100644 index 00000000..119d72b2 --- /dev/null +++ b/chromium_edits/122.0.6182.0/third_party/blink/renderer/platform/weborigin/scheme_registry.cc.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/blink/renderer/platform/weborigin/scheme_registry.cc b/third_party/blink/renderer/platform/weborigin/scheme_registry.cc +index 4eadf46ea0c24..d62fc7fb14e01 100644 +--- a/third_party/blink/renderer/platform/weborigin/scheme_registry.cc ++++ b/third_party/blink/renderer/platform/weborigin/scheme_registry.cc +@@ -67,7 +67,7 @@ class URLSchemesRegistry final { + // is considered secure. Additional checks are performed to ensure that + // other http pages are filtered out. + service_worker_schemes({"http", "https"}), +- fetch_api_schemes({"http", "https"}), ++ fetch_api_schemes({"http", "https", "ipfs", "ipns"}), + allowed_in_referrer_schemes({"http", "https"}) { + for (auto& scheme : url::GetCorsEnabledSchemes()) + cors_enabled_schemes.insert(scheme.c_str()); diff --git a/chromium_edits/122.0.6182.0/url/BUILD.gn.patch b/chromium_edits/122.0.6182.0/url/BUILD.gn.patch new file mode 100644 index 00000000..63fb8f8b --- /dev/null +++ b/chromium_edits/122.0.6182.0/url/BUILD.gn.patch @@ -0,0 +1,32 @@ +diff --git a/url/BUILD.gn b/url/BUILD.gn +index c525c166979d6..ce2b1ae43c0a7 100644 +--- a/url/BUILD.gn ++++ b/url/BUILD.gn +@@ -5,6 +5,7 @@ + import("//build/buildflag_header.gni") + import("//testing/libfuzzer/fuzzer_test.gni") + import("//testing/test.gni") ++import("//third_party/ipfs_client/args.gni") + import("features.gni") + + import("//build/config/cronet/config.gni") +@@ -67,6 +68,7 @@ component("url") { + public_deps = [ + "//base", + "//build:robolectric_buildflags", ++ "//third_party/ipfs_client:ipfs_buildflags", + ] + + configs += [ "//build/config/compiler:wexit_time_destructors" ] +@@ -89,6 +91,11 @@ component("url") { + public_configs = [ "//third_party/jdk" ] + } + ++ if (enable_ipfs) { ++ sources += [ "url_canon_ipfs.cc" ] ++ deps += [ "//third_party/ipfs_client:ipfs_client" ] ++ } ++ + if (is_win) { + # Don't conflict with Windows' "url.dll". + output_name = "url_lib" diff --git a/chromium_edits/122.0.6182.0/url/url_canon.h.patch b/chromium_edits/122.0.6182.0/url/url_canon.h.patch new file mode 100644 index 00000000..24ae1ba4 --- /dev/null +++ b/chromium_edits/122.0.6182.0/url/url_canon.h.patch @@ -0,0 +1,28 @@ +diff --git a/url/url_canon.h b/url/url_canon.h +index d3a7fabf09fa8..06db17242248f 100644 +--- a/url/url_canon.h ++++ b/url/url_canon.h +@@ -697,6 +697,23 @@ bool CanonicalizeMailtoURL(const char16_t* spec, + CanonOutput* output, + Parsed* new_parsed); + ++COMPONENT_EXPORT(URL) ++bool CanonicalizeIpfsURL(const char* spec, ++ int spec_len, ++ const Parsed& parsed, ++ SchemeType scheme_type, ++ CharsetConverter* query_converter, ++ CanonOutput* output, ++ Parsed* new_parsed); ++COMPONENT_EXPORT(URL) ++bool CanonicalizeIpfsURL(const char16_t* spec, ++ int spec_len, ++ const Parsed& parsed, ++ SchemeType scheme_type, ++ CharsetConverter* query_converter, ++ CanonOutput* output, ++ Parsed* new_parsed); ++ + // Part replacer -------------------------------------------------------------- + + // Internal structure used for storing separate strings for each component. diff --git a/chromium_edits/122.0.6182.0/url/url_canon_ipfs.cc b/chromium_edits/122.0.6182.0/url/url_canon_ipfs.cc new file mode 100644 index 00000000..9511e3f5 --- /dev/null +++ b/chromium_edits/122.0.6182.0/url/url_canon_ipfs.cc @@ -0,0 +1,55 @@ +#include "url_canon_internal.h" + +#include +#include + +#include + +bool url::CanonicalizeIpfsURL(const char* spec, + int spec_len, + const Parsed& parsed, + SchemeType scheme_type, + CharsetConverter* charset_converter, + CanonOutput* output, + Parsed* output_parsed) { + if ( spec_len < 1 || !spec ) { + return false; + } + if ( parsed.host.len < 1 ) { + return false; + } + std::string_view cid_str{ spec + parsed.host.begin, static_cast(parsed.host.len) }; + auto cid = ipfs::Cid(cid_str); + if ( !cid.valid() ) { + cid = ipfs::id_cid::forText( std::string{cid_str} + " is not a valid CID." ); + } + auto as_str = cid.to_string(); + if ( as_str.empty() ) { + return false; + } + std::string stdurl{ spec, static_cast(parsed.host.begin) }; + stdurl.append( as_str ); + stdurl.append( spec + parsed.host.end(), spec_len - parsed.host.end() ); + spec = stdurl.data(); + spec_len = static_cast(stdurl.size()); + Parsed parsed_input; + ParseStandardURL(spec, spec_len, &parsed_input); + return CanonicalizeStandardURL( + spec, spec_len, + parsed_input, + scheme_type, + charset_converter, + output, output_parsed + ); +} +bool url::CanonicalizeIpfsURL(const char16_t* spec, + int spec_len, + const Parsed& parsed, + SchemeType scheme_type, + CharsetConverter* query_converter, + CanonOutput* output, + Parsed* new_parsed) { + RawCanonOutput<2048> as8; + ConvertUTF16ToUTF8(spec, spec_len, &as8); + return CanonicalizeIpfsURL(as8.data(), as8.length(), parsed, scheme_type, query_converter, output, new_parsed); +} diff --git a/chromium_edits/122.0.6182.0/url/url_util.cc.patch b/chromium_edits/122.0.6182.0/url/url_util.cc.patch new file mode 100644 index 00000000..0332e847 --- /dev/null +++ b/chromium_edits/122.0.6182.0/url/url_util.cc.patch @@ -0,0 +1,17 @@ +diff --git a/url/url_util.cc b/url/url_util.cc +index 9258cfcfada47..daf10e4c3b741 100644 +--- a/url/url_util.cc ++++ b/url/url_util.cc +@@ -277,6 +277,12 @@ bool DoCanonicalize(const CHAR* spec, + charset_converter, output, + output_parsed); + ++ } else if (DoCompareSchemeComponent(spec, scheme, "ipfs")) { ++ // Switch multibase away from case-sensitive ones before continuing canonicalization. ++ ParseStandardURL(spec, spec_len, &parsed_input); ++ success = CanonicalizeIpfsURL(spec, spec_len, parsed_input, scheme_type, ++ charset_converter, output, output_parsed); ++ + } else if (DoIsStandard(spec, scheme, &scheme_type)) { + // All "normal" URLs. + ParseStandardURL(spec, spec_len, &parsed_input); diff --git a/cmake/chromium.py b/cmake/chromium.py index 544aa8d1..0cd38b36 100755 --- a/cmake/chromium.py +++ b/cmake/chromium.py @@ -6,7 +6,7 @@ from glob import glob from os import environ, makedirs, remove -from os.path import dirname, getmtime, isdir, isfile, join, pathsep, relpath, splitext +from os.path import basename, dirname, getmtime, isdir, isfile, join, pathsep, relpath, splitext from shutil import copyfile, which from sys import argv, executable, stderr @@ -156,7 +156,7 @@ def copy_missing_and_changed_files(source, target): if not isdir(t): makedirs(t) continue - if s.endswith('_unittest.cc') or 'inclusive' in s: + if s.endswith('_unittest.cc') or basename(s).startswith('test_'): continue ext = splitext(s)[-1] if ext in ignore_exts: diff --git a/cmake/patch.py b/cmake/patch.py index bd2a54fc..8f791d30 100755 --- a/cmake/patch.py +++ b/cmake/patch.py @@ -185,7 +185,7 @@ def electron_version(self, branch='main'): def unavailable(self): avail = list(map(as_int, self.available())) version_set = {} - fudge = 59886 + fudge = 59888 def check(version, version_set, s): i = as_int(version) by = (fudge,0) diff --git a/component/block_http_request.cc b/component/block_http_request.cc index 0ee82eb7..67e32592 100644 --- a/component/block_http_request.cc +++ b/component/block_http_request.cc @@ -46,8 +46,12 @@ void Self::send(raw_ptr loader_factory) { auto bound = base::BindOnce(&Self::OnResponse, base::Unretained(this), shared_from_this()); DCHECK(loader_factory); - loader_->DownloadToString(loader_factory, std::move(bound), - gw::BLOCK_RESPONSE_BUFFER_SIZE); + if (auto sz = inf_.max_response_size) { + loader_->DownloadToString(loader_factory, std::move(bound), sz.value()); + } else { + loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(loader_factory, + std::move(bound)); + } } void Self::OnResponse(std::shared_ptr, std::unique_ptr body) { diff --git a/component/chromium_ipfs_context.cc b/component/chromium_ipfs_context.cc index dfee88b1..4a853033 100644 --- a/component/chromium_ipfs_context.cc +++ b/component/chromium_ipfs_context.cc @@ -84,8 +84,8 @@ void Self::SendHttpRequest(HttpRequestDescription req_inf, auto ptr = std::make_shared(req_inf, cb); ptr->send(loader_factory_); } -bool Self::verify_key_signature(SigningKeyType t, - ByteView signature, +bool Self::VerifyKeySignature(SigningKeyType t, + ByteView signature, ByteView data, ByteView key_bytes) const { return crypto_api::VerifySignature(static_cast(t), signature, diff --git a/component/chromium_ipfs_context.h b/component/chromium_ipfs_context.h index 6c4cbbdd..f43bed83 100644 --- a/component/chromium_ipfs_context.h +++ b/component/chromium_ipfs_context.h @@ -40,8 +40,8 @@ class ChromiumIpfsContext final : public ContextApi { DnsTextCompleteCallback) override; void SendHttpRequest(HttpRequestDescription req_inf, HttpCompleteCallback cb) const override; - bool verify_key_signature(SigningKeyType, - ByteView signature, + bool VerifyKeySignature(SigningKeyType, + ByteView signature, ByteView data, ByteView key_bytes) const override; diff --git a/component/inter_request_state.cc b/component/inter_request_state.cc index 91a3b0c2..759b6d73 100644 --- a/component/inter_request_state.cc +++ b/component/inter_request_state.cc @@ -62,4 +62,6 @@ void Self::set_network_context(raw_ptr val) { network_context_ = val; } Self::InterRequestState(base::FilePath p) : disk_path_{p} {} -Self::~InterRequestState() noexcept {} +Self::~InterRequestState() noexcept { + network_context_ = nullptr; +} diff --git a/component/patches/121.0.6129.1.patch b/component/patches/122.0.6182.0.patch similarity index 95% rename from component/patches/121.0.6129.1.patch rename to component/patches/122.0.6182.0.patch index 22104048..87ae89c8 100644 --- a/component/patches/121.0.6129.1.patch +++ b/component/patches/122.0.6182.0.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn -index d2ece5b728926..3c4d51064b946 100644 +index a188528a9e262..4b945eb891895 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn @@ -40,6 +40,7 @@ import("//rlz/buildflags/buildflags.gni") @@ -10,7 +10,7 @@ index d2ece5b728926..3c4d51064b946 100644 import("//third_party/protobuf/proto_library.gni") import("//third_party/webrtc/webrtc.gni") import("//third_party/widevine/cdm/widevine.gni") -@@ -2651,6 +2652,10 @@ static_library("browser") { +@@ -2604,6 +2605,10 @@ static_library("browser") { ] } @@ -22,10 +22,10 @@ index d2ece5b728926..3c4d51064b946 100644 deps += [ "//chrome/browser/screen_ai:screen_ai_dlc_installer" ] } diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc -index 68fa04fbffc20..1b6b5e306dac7 100644 +index a7907d8b188d8..68a96934ccf48 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc -@@ -209,6 +209,7 @@ +@@ -213,6 +213,7 @@ #include "third_party/blink/public/common/features_generated.h" #include "third_party/blink/public/common/forcedark/forcedark_switches.h" #include "third_party/blink/public/common/switches.h" @@ -33,7 +33,7 @@ index 68fa04fbffc20..1b6b5e306dac7 100644 #include "ui/accessibility/accessibility_features.h" #include "ui/accessibility/accessibility_switches.h" #include "ui/base/ui_base_features.h" -@@ -309,6 +310,10 @@ +@@ -308,6 +309,10 @@ #include "extensions/common/switches.h" #endif // BUILDFLAG(ENABLE_EXTENSIONS) @@ -44,7 +44,7 @@ index 68fa04fbffc20..1b6b5e306dac7 100644 #if BUILDFLAG(ENABLE_PDF) #include "pdf/pdf_features.h" #endif -@@ -9888,6 +9893,14 @@ const FeatureEntry kFeatureEntries[] = { +@@ -9731,6 +9736,14 @@ const FeatureEntry kFeatureEntries[] = { flag_descriptions::kOmitCorsClientCertDescription, kOsAll, FEATURE_VALUE_TYPE(network::features::kOmitCorsClientCert)}, @@ -110,19 +110,10 @@ index 4c88614c68c25..f8bb12a3b0c2e 100644 // Also check for schemes registered via registerProtocolHandler(), which diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc -index b833f2cd54253..07a71010c48a6 100644 +index d3d67d83a514e..a7f34d6dde492 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc -@@ -232,6 +232,8 @@ - #include "components/error_page/common/localized_error.h" - #include "components/error_page/content/browser/net_error_auto_reloader.h" - #include "components/google/core/common/google_switches.h" -+#include "components/ipfs/interceptor.h" -+#include "components/ipfs/url_loader_factory.h" - #include "components/keep_alive_registry/keep_alive_types.h" - #include "components/keep_alive_registry/scoped_keep_alive.h" - #include "components/language/core/browser/pref_names.h" -@@ -372,6 +374,7 @@ +@@ -378,6 +378,7 @@ #include "third_party/blink/public/common/switches.h" #include "third_party/blink/public/mojom/browsing_topics/browsing_topics.mojom.h" #include "third_party/blink/public/public_buildflags.h" @@ -130,7 +121,7 @@ index b833f2cd54253..07a71010c48a6 100644 #include "third_party/widevine/cdm/buildflags.h" #include "ui/base/clipboard/clipboard_format_type.h" #include "ui/base/l10n/l10n_util.h" -@@ -495,6 +498,12 @@ +@@ -500,6 +501,12 @@ #include "chrome/browser/fuchsia/chrome_browser_main_parts_fuchsia.h" #endif @@ -142,8 +133,8 @@ index b833f2cd54253..07a71010c48a6 100644 + #if BUILDFLAG(IS_CHROMEOS) #include "base/debug/leak_annotations.h" - #include "chrome/browser/apps/intent_helper/chromeos_disabled_apps_throttle.h" -@@ -6167,12 +6176,23 @@ void ChromeContentBrowserClient:: + #include "chrome/browser/apps/app_service/app_install/app_install_navigation_throttle.h" +@@ -6084,12 +6091,23 @@ void ChromeContentBrowserClient:: const absl::optional& request_initiator_origin, NonNetworkURLLoaderFactoryMap* factories) { #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(ENABLE_EXTENSIONS) || \ @@ -169,7 +160,7 @@ index b833f2cd54253..07a71010c48a6 100644 #if BUILDFLAG(IS_CHROMEOS_ASH) if (web_contents) { -@@ -6314,6 +6334,11 @@ ChromeContentBrowserClient::WillCreateURLLoaderRequestInterceptors( +@@ -6231,6 +6249,11 @@ ChromeContentBrowserClient::WillCreateURLLoaderRequestInterceptors( scoped_refptr navigation_response_task_runner) { std::vector> interceptors; @@ -182,10 +173,10 @@ index b833f2cd54253..07a71010c48a6 100644 interceptors.push_back( std::make_unique( diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json -index 07e463a9bc282..72c84781e6087 100644 +index 0b51e78fcb8b9..9571b2c92c57f 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json -@@ -2865,6 +2865,11 @@ +@@ -2948,6 +2948,11 @@ "owners": [ "hanxi@chromium.org", "wychen@chromium.org" ], "expiry_milestone": 130 }, @@ -198,10 +189,10 @@ index 07e463a9bc282..72c84781e6087 100644 "name": "enable-isolated-sandboxed-iframes", "owners": [ "wjmaclean@chromium.org", "alexmos@chromium.org", "creis@chromium.org" ], diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc -index 48e9016fb159b..b951a676a44af 100644 +index b2992e30f9811..f92d8a322b634 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc -@@ -274,6 +274,11 @@ const char kEnableBenchmarkingDescription[] = +@@ -288,6 +288,11 @@ const char kEnableBenchmarkingDescription[] = "after 3 restarts. On the third restart, the flag will appear to be off " "but the effect is still active."; @@ -214,10 +205,10 @@ index 48e9016fb159b..b951a676a44af 100644 "Preloading Settings on Performance Page"; const char kPreloadingOnPerformancePageDescription[] = diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h -index 0f7403c147adf..5222f9b39d3c2 100644 +index ad76d832395a1..438facecff519 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h -@@ -22,6 +22,7 @@ +@@ -23,6 +23,7 @@ #include "pdf/buildflags.h" #include "printing/buildflags/buildflags.h" #include "third_party/blink/public/common/buildflags.h" @@ -225,7 +216,7 @@ index 0f7403c147adf..5222f9b39d3c2 100644 // This file declares strings used in chrome://flags. These messages are not // translated, because instead of end-users they target Chromium developers and -@@ -172,6 +173,11 @@ extern const char kDownloadWarningImprovementsDescription[]; +@@ -179,6 +180,11 @@ extern const char kDownloadWarningImprovementsDescription[]; extern const char kEnableBenchmarkingName[]; extern const char kEnableBenchmarkingDescription[]; @@ -722,10 +713,10 @@ index c525c166979d6..ce2b1ae43c0a7 100644 # Don't conflict with Windows' "url.dll". output_name = "url_lib" diff --git a/url/url_canon.h b/url/url_canon.h -index d3a7fabf09fa8..06db17242248f 100644 +index 913b3685c6fec..3c3c55e580564 100644 --- a/url/url_canon.h +++ b/url/url_canon.h -@@ -697,6 +697,23 @@ bool CanonicalizeMailtoURL(const char16_t* spec, +@@ -792,6 +792,23 @@ bool CanonicalizeMailtoURL(const char16_t* spec, CanonOutput* output, Parsed* new_parsed); @@ -751,10 +742,10 @@ index d3a7fabf09fa8..06db17242248f 100644 // Internal structure used for storing separate strings for each component. diff --git a/url/url_canon_ipfs.cc b/url/url_canon_ipfs.cc new file mode 100644 -index 0000000000000..da3a5f032b5e8 +index 0000000000000..9511e3f5e6f5c --- /dev/null +++ b/url/url_canon_ipfs.cc -@@ -0,0 +1,72 @@ +@@ -0,0 +1,55 @@ +#include "url_canon_internal.h" + +#include diff --git a/doc/design_notes.md b/doc/design_notes.md index 414a0561..c01011ec 100644 --- a/doc/design_notes.md +++ b/doc/design_notes.md @@ -9,7 +9,7 @@ The term can mean a few different things. There are essentially 3 layers of what 1. Immediate object storage * These are in-memory collections of parsed, conveniently-laid-out objects written for-purpose * There are 2: - 1. `BlockStorage` contains the most recently-accessed blocks (as `ipfs::Block`), and a mapping of CID string representation[^1] to them. + 1. `BlockStorage` contains the most recently-accessed blocks (as `ipfs::PbDag`), and a mapping of CID string representation[^1] to them. - When a new entry is being saved, it may overwrite an existing entry if that one hasn't been accessed for 5 minutes. - If there's no stale entry convenient, it may instead expand memory usage and create an entirely new entry. 2. `IpnsNames` diff --git a/library/include/ipfs_client/block_storage.h b/library/include/ipfs_client/block_storage.h index 26f48ed8..525bae46 100644 --- a/library/include/ipfs_client/block_storage.h +++ b/library/include/ipfs_client/block_storage.h @@ -1,7 +1,7 @@ #ifndef IPFS_BLOCKS_H_ #define IPFS_BLOCKS_H_ -#include "dag_block.h" +#include "pb_dag.h" #include "vocab/flat_mapset.h" #include @@ -44,7 +44,7 @@ class BlockStorage { Cid const& cid, std::string headers, std::string const& body, - Block&& block); + PbDag&& block); /*! * \name Store (Convenience) @@ -53,7 +53,7 @@ class BlockStorage { * const&,Block&&) */ ///@{ - bool Store(std::string headers, std::string const& body, Block&& block); + bool Store(std::string headers, std::string const& body, PbDag&& block); bool Store(std::string const& cid, std::string headers, std::string body); bool Store(std::string cid_str, Cid const& cid, @@ -62,7 +62,7 @@ class BlockStorage { bool Store(Cid const& cid, std::string headers, std::string const& body, - Block&&); + PbDag&&); ///@} /*! @@ -73,7 +73,7 @@ class BlockStorage { * \return Non-owning pointer if found, nullptr * otherwise */ - Block const* Get(std::string const& cid); + PbDag const* Get(std::string const& cid); /*! * \brief Get HTTP headers associated with the block @@ -124,7 +124,7 @@ class BlockStorage { ~Record() noexcept; std::time_t last_access = 0L; std::string cid_str = {}; - Block block = {}; + PbDag block = {}; std::string headers = {}; }; std::list records_ = std::list(0xFFUL); diff --git a/library/include/ipfs_client/cid.h b/library/include/ipfs_client/cid.h index 2119d381..d957d23e 100644 --- a/library/include/ipfs_client/cid.h +++ b/library/include/ipfs_client/cid.h @@ -14,12 +14,12 @@ class Cid { MultiCodec codec_ = MultiCodec::INVALID; MultiHash hash_; - void assign(ByteView); - public: + Cid() = default; Cid(MultiCodec, MultiHash); explicit Cid(std::string_view); explicit Cid(ByteView); + bool ReadStart(ByteView&); bool valid() const; MultiCodec codec() const { return codec_; } @@ -28,6 +28,10 @@ class Cid { HashType hash_type() const; std::string to_string() const; + + constexpr static std::size_t MinSerializedLength = + 1 /*cid version*/ + 1 /*codec*/ + 1 /*hash type*/ + + 1 /*hash len, could be zero*/; }; } // namespace ipfs diff --git a/library/include/ipfs_client/context_api.h b/library/include/ipfs_client/context_api.h index 39da0755..da524bb9 100644 --- a/library/include/ipfs_client/context_api.h +++ b/library/include/ipfs_client/context_api.h @@ -70,8 +70,8 @@ class ContextApi : public std::enable_shared_from_this { using SigningKeyType = ::ipfs::SigningKeyType; using ByteView = ::ipfs::ByteView; - virtual bool verify_key_signature(SigningKeyType, - ByteView signature, + virtual bool VerifyKeySignature(SigningKeyType, + ByteView signature, ByteView data, ByteView key_bytes) const = 0; diff --git a/library/include/ipfs_client/gw/gateway_request.h b/library/include/ipfs_client/gw/gateway_request.h index f25b6d69..efded265 100644 --- a/library/include/ipfs_client/gw/gateway_request.h +++ b/library/include/ipfs_client/gw/gateway_request.h @@ -59,9 +59,11 @@ class GatewayRequest { std::optional describe_http() const; std::string debug_string() const; void orchestrator(std::shared_ptr const&); + bool RespondSuccessfully(std::string_view, std::shared_ptr const& api); void Hook(std::function); + bool PartiallyRedundant() const; static std::shared_ptr fromIpfsPath(SlashDelimited); }; diff --git a/library/include/ipfs_client/gw/requestor.h b/library/include/ipfs_client/gw/requestor.h index f71b6070..634c3673 100644 --- a/library/include/ipfs_client/gw/requestor.h +++ b/library/include/ipfs_client/gw/requestor.h @@ -15,7 +15,6 @@ struct Response; namespace ipfs::gw { class GatewayRequest; -class RequestPool; using RequestPtr = std::shared_ptr; class Requestor : public std::enable_shared_from_this { @@ -31,14 +30,7 @@ class Requestor : public std::enable_shared_from_this { MAYBE_LATER = 'M' }; virtual HandleOutcome handle(RequestPtr) = 0; - virtual void iterate_nodes( - GatewayRequest const& req, - Response const& res, - std::function)>) const; - - void receive_response(RequestPtr, ipfs::Response const&) const; - void success(RequestPtr, std::string_view body) const; - void failure(RequestPtr) const; + void definitive_failure(RequestPtr) const; void forward(RequestPtr) const; diff --git a/library/include/ipfs_client/ipfs_request.h b/library/include/ipfs_client/ipfs_request.h index 8b765518..eda8bdfa 100644 --- a/library/include/ipfs_client/ipfs_request.h +++ b/library/include/ipfs_client/ipfs_request.h @@ -20,7 +20,7 @@ class IpfsRequest { public: IpfsRequest(std::string path, Finisher); - SlashDelimited path() const { return std::string_view{path_}; } + SlashDelimited path() const { return SlashDelimited{path_}; } void finish(Response& r); void till_next(std::size_t); bool ready_after(); diff --git a/library/include/ipfs_client/ipld/dag_node.h b/library/include/ipfs_client/ipld/dag_node.h index e349151a..1c66f4fd 100644 --- a/library/include/ipfs_client/ipld/dag_node.h +++ b/library/include/ipfs_client/ipld/dag_node.h @@ -2,6 +2,7 @@ #define IPFS_DAG_NODE_H_ #include "link.h" +#include "resolution_state.h" #include #include @@ -18,7 +19,7 @@ #include namespace ipfs { -class Block; +class PbDag; class ContextApi; struct ValidatedIpns; } // namespace ipfs @@ -27,12 +28,16 @@ struct ContentIdentifier; } namespace ipfs::ipld { -class DagNode; using NodePtr = std::shared_ptr; class DirShard; struct MoreDataNeeded { + MoreDataNeeded(std::string one) : ipfs_abs_paths_{{one}} {} + template + MoreDataNeeded(Range const& many) + : ipfs_abs_paths_(many.begin(), many.end()) {} std::vector ipfs_abs_paths_; + bool insist_on_car = false; }; enum class ProvenAbsent {}; struct PathChange { @@ -45,20 +50,41 @@ using ResolveResult = * @brief A block, an IPNS record, etc. */ class DagNode : public std::enable_shared_from_this { + Link* FindChild(std::string_view); + static void Descend(ResolutionState&); + protected: std::vector> links_; std::shared_ptr api_; + ///< When the next path element is what's needed, and it should already be a + ///< link known about... + ResolveResult CallChild(ResolutionState&); + + ///< As before, but it might be possible to create on the fly if not known + ResolveResult CallChild(ResolutionState&, + std::function gen_child); + + ///< When the child's name is not the next element in the path, but it must be + ///< known about. e.g. index.html for a path ending in a directory + ResolveResult CallChild(ResolutionState&, std::string_view link_key); + + ///< Add the link if not present, then CallChild(ResolutionState) + ResolveResult CallChild(ResolutionState&, + std::string_view link_key, + std::string_view block_key); + public: - using BlockLookup = std::function; - virtual ResolveResult resolve(SlashDelimited path, - BlockLookup, - std::string& up_to_here) = 0; + virtual ResolveResult resolve(ResolutionState& params) = 0; + ResolveResult resolve(SlashDelimited initial_path, BlockLookup); + static NodePtr fromBytes(std::shared_ptr const& api, + Cid const&, + ByteView bytes); static NodePtr fromBytes(std::shared_ptr const& api, Cid const&, std::string_view bytes); - static NodePtr fromBlock(Block const&); + static NodePtr fromBlock(PbDag const&); static NodePtr fromIpnsRecord(ValidatedIpns const&); virtual ~DagNode() noexcept {} diff --git a/library/include/ipfs_client/ipld/resolution_state.h b/library/include/ipfs_client/ipld/resolution_state.h new file mode 100644 index 00000000..82e330ce --- /dev/null +++ b/library/include/ipfs_client/ipld/resolution_state.h @@ -0,0 +1,36 @@ +#ifndef IPFS_RESOLUTION_STATE_H_ +#define IPFS_RESOLUTION_STATE_H_ + +#include + +#include +#include + +namespace ipfs { +class ContextApi; +} + +namespace ipfs::ipld { +class DagNode; +using NodePtr = std::shared_ptr; +using BlockLookup = std::function; + +class ResolutionState { + friend class DagNode; + std::string resolved_path_components; + SlashDelimited unresolved_path; + BlockLookup get_available_block; + + public: + SlashDelimited MyPath() const; + SlashDelimited PathToResolve() const; + bool IsFinalComponent() const; + std::string NextComponent(ContextApi const*) const; + NodePtr GetBlock(std::string const& block_key) const; + + ResolutionState WithPath(std::string_view) const; + ResolutionState RestartResolvedPath() const; +}; +} // namespace ipfs::ipld + +#endif // IPFS_RESOLUTION_STATE_H_ diff --git a/library/include/ipfs_client/multi_hash.h b/library/include/ipfs_client/multi_hash.h index 8d0a06a3..6ed78f5e 100644 --- a/library/include/ipfs_client/multi_hash.h +++ b/library/include/ipfs_client/multi_hash.h @@ -16,6 +16,9 @@ class MultiHash { MultiHash() = default; explicit MultiHash(ByteView); explicit MultiHash(HashType, ByteView digest); + + bool ReadPrefix(ByteView&); + bool valid() const; HashType type() const { return type_; } ByteView digest() const { return hash_; } diff --git a/library/include/ipfs_client/dag_block.h b/library/include/ipfs_client/pb_dag.h similarity index 88% rename from library/include/ipfs_client/dag_block.h rename to library/include/ipfs_client/pb_dag.h index 722b9d1d..97b4a855 100644 --- a/library/include/ipfs_client/dag_block.h +++ b/library/include/ipfs_client/pb_dag.h @@ -1,5 +1,5 @@ -#ifndef IPFS_DAG_BLOCK_H_ -#define IPFS_DAG_BLOCK_H_ +#ifndef IPFS_PB_DAG_H_ +#define IPFS_PB_DAG_H_ #if __has_include() #include @@ -29,14 +29,14 @@ class ContextApi; * Or it could be something else, like DAG-CBOR * But this class really only handles the first 2 so far. */ -class Block { +class PbDag { public: /*! * \brief Initialize from stream * \param cid - The Content IDentifier * \param stream - Stream from which one can read the bytes of the block */ - Block(Cid const& cid, std::istream& stream); + PbDag(Cid const& cid, std::istream& stream); /*! * \brief Initialize from block of bytes @@ -45,14 +45,15 @@ class Block { * \note It's not really a string - certainly not text in any way. * It's just a container of arbitrary bytes. */ - Block(Cid const& cid, std::string_view bytes); + PbDag(Cid const& cid, ByteView bytes); + PbDag(Cid const& cid, std::string_view bytes); - Block(Block const&); - Block& operator=(Block const&) = default; + PbDag(PbDag const&); + PbDag& operator=(PbDag const&) = default; - Block(); ///< Construct an invalid block + PbDag(); ///< Construct an invalid block - ~Block() noexcept; + ~PbDag() noexcept; bool valid() const; ///< Check if the block appears valid @@ -128,6 +129,6 @@ class Block { } // namespace ipfs -std::ostream& operator<<(std::ostream&, ipfs::Block::Type); +std::ostream& operator<<(std::ostream&, ipfs::PbDag::Type); -#endif // IPFS_DAG_BLOCK_H_ +#endif // IPFS_PB_DAG_H_ diff --git a/library/include/ipfs_client/response.h b/library/include/ipfs_client/response.h index 40cd2730..3c277994 100644 --- a/library/include/ipfs_client/response.h +++ b/library/include/ipfs_client/response.h @@ -1,9 +1,11 @@ #ifndef IPFS_RESPONSE_H_ #define IPFS_RESPONSE_H_ -#include +#include +#include #include +#include namespace ipfs { diff --git a/library/include/ipfs_client/test_context.h b/library/include/ipfs_client/test_context.h new file mode 100644 index 00000000..c85b8792 --- /dev/null +++ b/library/include/ipfs_client/test_context.h @@ -0,0 +1,150 @@ +#ifndef IPFS_ALL_INCLUSIVE_CONTEXT_H_ +#define IPFS_ALL_INCLUSIVE_CONTEXT_H_ + +#ifdef _MSC_VER +// #warning "AllInclusiveContext has not been ported to Windows." +#else + +#include "gw/default_requestor.h" + +#include "context_api.h" +#include "dag_cbor_value.h" +#include "gateways.h" +#include "json_cbor_adapter.h" +#include "orchestrator.h" + +#include + +#include + +#include + +#if ! __has_include() +#warning "One needs access to Boost to use this header" +#elif !__has_include() +#warning "One needs c-ares available to use this header." +#elif !HAS_JSON_CBOR_ADAPTER +#warning "One needs access to nlohmann/json to use this header" +#else + +#define HAS_ALL_INCLUSIVE 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google::protobuf { +constexpr LogLevel LOGLEVEL_DEBUG = static_cast(-1); +constexpr LogLevel LOGLEVEL_TRACE = static_cast(-2); +} // namespace google::protobuf + +class HttpSession; + +namespace ipfs { + +// LCOV_EXCL_START + +class AllInclusiveContext final : public ContextApi { + void SendHttpRequest(HttpRequestDescription, + HttpCompleteCallback) const override; + struct DnsCbs { + DnsTextResultsCallback r; + DnsTextCompleteCallback c; + }; + std::map> pending_dns_; + void SendDnsTextRequest(std::string, + DnsTextResultsCallback, + DnsTextCompleteCallback) override; + std::string MimeType(std::string extension, + std::string_view, + std::string const&) const override { + // TODO implement real mime type detection + return "text/" + extension; + } + std::string UnescapeUrlComponent(std::string_view url_comp) const override { + std::string rv{url_comp}; + auto xval = [](char c) { + if (c <= '9') { + return c - '0'; + } + if (c <= 'Z') { + return c - 'A'; + } + return c - 'a'; + }; + for (auto i = 0UL; i + 1UL < rv.size(); ++i) { + if (rv[i] != '%') { + continue; + } + auto a = rv[i + 1UL]; + if (rv[i + 1UL] == '%') { + rv.erase(i, 1UL); + continue; + } + if (i + 2UL >= rv.size()) { + break; + } + if (!std::isxdigit(a)) { + continue; + } + auto b = rv[i + 2UL]; + if (std::isxdigit(b)) { + rv[i] = xval(a) * 16 + xval(b); + rv.erase(i + 1UL, 2); + } + } + return rv; + } + std::unique_ptr ParseCbor(ByteView bytes) const override { + auto data = nlohmann::json::from_cbor( + bytes, false, true, nlohmann::detail::cbor_tag_handler_t::store); + return std::make_unique(data); + } + std::unique_ptr ParseJson( + std::string_view j_str) const override { + auto data = nlohmann::json::parse(j_str); + std::ostringstream oss; + oss << std::setw(2) << data; + GOOGLE_LOG(DEBUG) << "Parsed " << j_str.size() + << " bytes of JSON string and got " << oss.str(); + return std::make_unique(data); + } + bool VerifyKeySignature(SigningKeyType, + ByteView, + ByteView, + ByteView) const override { + GOOGLE_LOG(ERROR) << "TODO\n"; + return true; + } + boost::asio::io_context& io_; + boost::asio::ssl::context mutable ssl_ctx_ = + boost::asio::ssl::context{boost::asio::ssl::context::tls_client}; + // boost::asio::ssl::context{boost::asio::ssl::context::tlsv13_client}; + ares_channel_t* ares_channel_ = nullptr; + void CAresProcess(); + + public: + AllInclusiveContext(boost::asio::io_context& io); + ~AllInclusiveContext() noexcept override; + void DnsResults(std::string&, ares_txt_reply&); +}; +inline std::shared_ptr start_default( + boost::asio::io_context& io) { + auto api = std::make_shared(io); + auto gl = Gateways::DefaultGateways(); + auto rtor = gw::default_requestor(gl, {}, api); + auto orc = std::make_shared(rtor, api); + return orc; +} + +} // namespace ipfs + +#endif // boost + +#endif //_MSC_VER +#endif // IPFS_ALL_INCLUSIVE_CONTEXT_H_ diff --git a/library/include/libp2p/basic/varint_prefix_reader.hpp b/library/include/libp2p/basic/varint_prefix_reader.hpp deleted file mode 100644 index 70f48488..00000000 --- a/library/include/libp2p/basic/varint_prefix_reader.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_VARINT_PREFIX_READER_HPP -#define LIBP2P_VARINT_PREFIX_READER_HPP - -#include - -namespace libp2p::basic { - -/// Collects and interprets varint from incoming data, -/// Reader is stateful, see varint_prefix_reader_test.cpp for usage examples -class VarintPrefixReader { - public: - /// Current state - enum State { - /// Needs more bytes - kUnderflow, - - /// Varint is ready, value() is ultimate - kReady, - - /// Overflow of uint64_t, too many bytes with high bit set - kOverflow, - - /// consume() called when state is kReady - kError - }; - - /// Returns state - State state() const { return state_; } - - /// Returns current value, called when state() == kReady - uint64_t value() const { return value_; } - - /// Resets reader's state - void reset(); - - /// Consumes one byte from wire, returns reader's state - /// (or kError if called when state() == kReady) - State consume(uint8_t byte); - - /// Consumes bytes from buffer. - /// On success, modifies buffer (cuts off first bytes which were consumed), - /// returns reader's state - /// (or kError if called when state() == kReady) - State consume(ipfs::ByteView& buffer); - - private: - /// Current value accumulated - uint64_t value_ = 0; - - /// Current reader's state - State state_ = kUnderflow; - - /// Bytes got at the moment, this controls overflow of value_ - uint8_t got_bytes_ = 0; -}; -} // namespace libp2p::basic - -#endif // LIBP2P_VARINT_PREFIX_READER_HPP diff --git a/library/include/libp2p/common/hexutil.hpp b/library/include/libp2p/common/hexutil.hpp deleted file mode 100644 index 6dc63ecb..00000000 --- a/library/include/libp2p/common/hexutil.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_HEXUTIL_HPP -#define LIBP2P_HEXUTIL_HPP - -#include "vocab/byte_view.h" -#include "vocab/expected.h" - -#include -#include - -namespace libp2p::common { - -/** - * @brief error codes for exceptions that may occur during unhexing - */ -enum class UnhexError { NOT_ENOUGH_INPUT = 1, NON_HEX_INPUT, UNKNOWN }; - -/** - * @brief Converts an integer to an uppercase hex representation - */ -std::string int_to_hex(uint64_t n, size_t fixed_width = 2) noexcept; - -/** - * @brief Converts bytes to uppercase hex representation - * @param array bytes - * @param len length of bytes - * @return hexstring - */ -std::string hex_upper(ipfs::ByteView bytes) noexcept; - -/** - * @brief Converts bytes to hex representation - * @param array bytes - * @param len length of bytes - * @return hexstring - */ -std::string hex_lower(ipfs::ByteView bytes) noexcept; - -/** - * @brief Converts hex representation to bytes - * @param array individual chars - * @param len length of chars - * @return result containing array of bytes if input string is hex encoded and - * has even length - * - * @note reads both uppercase and lowercase hexstrings - * - * @see - * https://www.boost.org/doc/libs/1_51_0/libs/algorithm/doc/html/the_boost_algorithm_library/Misc/hex.html - */ -ipfs::expected, UnhexError> unhex(std::string_view hex); - -/** - * Creates unsigned bytes span out of string, debug purpose helper - * @param str String - * @return Span - */ -inline ipfs::ByteView sv2span(const std::string_view& str) { - return ipfs::ByteView((ipfs::Byte*)str.data(), // NOLINT - str.size()); // NOLINT -} - -/** - * sv2span() identity overload, for uniformity - * @param s Span - * @return s - */ -inline ipfs::ByteView sv2span(const ipfs::ByteView& s) { - return s; -} - -/** - * Makes printable string out of bytes, for diagnostic purposes - * @tparam Bytes Bytes or char sequence - * @param str Input - * @return String - */ -template -inline std::string dumpBin(const Bytes& str) { - std::string ret; - ret.reserve(str.size() + 2); - bool non_printable_detected = false; - for (auto c : str) { - if (std::isprint(c) != 0) { - ret.push_back((char)c); // NOLINT - } else { - ret.push_back('?'); - non_printable_detected = true; - } - } - if (non_printable_detected) { - ret.reserve(ret.size() * 3); - ret += " ("; - ret += hex_lower(sv2span(str)); - ret += ')'; - } - return ret; -} - -} // namespace libp2p::common - -#endif // LIBP2P_HEXUTIL_HPP diff --git a/library/include/libp2p/crypto/common.hpp b/library/include/libp2p/crypto/common.hpp deleted file mode 100644 index fd4158b8..00000000 --- a/library/include/libp2p/crypto/common.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_CRYPTO_COMMON_HPP -#define LIBP2P_CRYPTO_COMMON_HPP - -#include -#include -#include - -namespace libp2p::crypto::common { - /** - * @struct AesSecret provides key and iv for AES cipher - * @tparam KeySize key size - * @tparam IvSize iv size - */ - template - struct AesSecret { - std::array key; - std::array iv; - }; - - /** - * Values for AES-128 - */ - using Aes128Secret = AesSecret<16, 16>; - - /** - * Values for AES-256 - */ - using Aes256Secret = AesSecret<32, 16>; - - /** - * Supported hash types - */ - enum class HashType { SHA1, SHA256, SHA512 }; - - /** - * Supported types of RSA keys - */ - enum class RSAKeyType { RSA1024, RSA2048, RSA4096 }; - - /** - * Supported ECDH curves - */ - enum class CurveType { P256, P384, P521 }; - - /** - * Supported cipher types - */ - enum class CipherType { AES128, AES256 }; -} // namespace libp2p::crypto::common - -#endif // LIBP2P_CRYPTO_COMMON_HPP diff --git a/library/include/libp2p/crypto/error.hpp b/library/include/libp2p/crypto/error.hpp deleted file mode 100644 index 5067ba85..00000000 --- a/library/include/libp2p/crypto/error.hpp +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_CRYPTO_ERROR_HPP -#define LIBP2P_CRYPTO_ERROR_HPP - -#include - -namespace libp2p::crypto { -enum class CryptoProviderError { - INVALID_KEY_TYPE = 1, ///< failed to unmarshal key type, wrong value - UNKNOWN_KEY_TYPE, ///< failed to unmarshal key - FAILED_UNMARSHAL_DATA, ///< protobuf error, failed to unmarshal data - SIGNATURE_GENERATION_FAILED, ///< general signature creation failure - SIGNATURE_VERIFICATION_FAILED, ///< general signature verification failure -}; - -enum class OpenSslError { - FAILED_INITIALIZE_CONTEXT = 1, ///< failed to initialize context - FAILED_INITIALIZE_OPERATION, ///< failed to initialize operation - FAILED_ENCRYPT_UPDATE, ///< failed to update encryption - FAILED_DECRYPT_UPDATE, ///< failed to update decryption - FAILED_ENCRYPT_FINALIZE, ///< failed to finalize encryption - FAILED_DECRYPT_FINALIZE, ///< failed to finalize decryption - WRONG_IV_SIZE, ///< wrong iv size - WRONG_KEY_SIZE, ///< wrong key size - STREAM_FINALIZED, ///< crypt update operations cannot be performed after - ///< stream finalization -}; - -enum class HmacProviderError { - UNSUPPORTED_HASH_METHOD = 1, ///< hash method id provided is not supported - FAILED_CREATE_CONTEXT, ///< failed to create context - FAILED_INITIALIZE_CONTEXT, ///< failed to initialize context - FAILED_UPDATE_DIGEST, ///< failed to update digest - FAILED_FINALIZE_DIGEST, ///< failed to finalize digest - WRONG_DIGEST_SIZE, ///< wrong digest size -}; - -enum class RandomProviderError { - TOKEN_NOT_EXISTS = 1, ///< /dev/urandom path not present in system - FAILED_OPEN_FILE, ///< failed to open random provider file - FAILED_FETCH_BYTES, ///< failed to fetch bytes from source - INVALID_PROVIDER_TYPE, ///< invalid or unsupported random provider type -}; - -enum class KeyGeneratorError { - CANNOT_GENERATE_UNSPECIFIED = 1, ///< you need to specify valid key type - UNKNOWN_KEY_TYPE, ///< unknown key type - GENERATOR_NOT_INITIALIZED, ///< generator not initialized - KEY_GENERATION_FAILED, ///< key generation failed - KEY_DERIVATION_FAILED, ///< failed to derive key - FILE_NOT_FOUND, ///< file not found - FAILED_TO_READ_FILE, ///< failed to read file - INCORRECT_BITS_COUNT, ///< incorrect bits option - UNSUPPORTED_KEY_TYPE, ///< key type is not supported - WRONG_KEY_TYPE, ///< incorrect key type - CANNOT_LOAD_UNSPECIFIED, ///< cannot load unspecified key - GET_KEY_BYTES_FAILED, ///< failed to get key bytes from PKEY - INTERNAL_ERROR, ///< internal error happened - UNSUPPORTED_CURVE_TYPE, ///< generator for curve type is not implemented -}; - -enum class KeyValidatorError { - WRONG_PUBLIC_KEY_SIZE = 1, ///< public key has wrong size - WRONG_PRIVATE_KEY_SIZE, ///< private key has wrong size - INVALID_PUBLIC_KEY, ///< invalid public key - INVALID_PRIVATE_KEY, ///< private key cannot be decoded - KEYS_DONT_MATCH, ///< public key is not derived from private - DIFFERENT_KEY_TYPES, ///< key types in pair don't match - UNSUPPORTED_CRYPTO_ALGORYTHM, ///< crypto algorythm is not implemented - UNKNOWN_CRYPTO_ALGORYTHM, ///< unknown crypto algorythm -}; - -using Error = std::variant; -} // namespace libp2p::crypto - -// OUTCOME_HPP_DECLARE_ERROR(libp2p::crypto, CryptoProviderError) -// OUTCOME_HPP_DECLARE_ERROR(libp2p::crypto, OpenSslError) -// OUTCOME_HPP_DECLARE_ERROR(libp2p::crypto, HmacProviderError) -// OUTCOME_HPP_DECLARE_ERROR(libp2p::crypto, RandomProviderError) -// OUTCOME_HPP_DECLARE_ERROR(libp2p::crypto, KeyGeneratorError) -// OUTCOME_HPP_DECLARE_ERROR(libp2p::crypto, KeyValidatorError) - -#endif // LIBP2P_CRYPTO_ERROR_HPP diff --git a/library/include/libp2p/crypto/hasher.hpp b/library/include/libp2p/crypto/hasher.hpp deleted file mode 100644 index a194296b..00000000 --- a/library/include/libp2p/crypto/hasher.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_SRC_CRYPTO_HASHER_HPP -#define LIBP2P_SRC_CRYPTO_HASHER_HPP - -#include -#include -#include - -#include "vocab/byte_view.h" -#include "vocab/expected.h" - -namespace libp2p::crypto { - - using libp2p::crypto::common::HashType; - - class Hasher { - public: - virtual ~Hasher() = default; - - using Result = ipfs::expected; - - /// appends a new chunk of data - virtual Result write(ipfs::ByteView data) = 0; - - /** - * Calculates the current digest. - * Does not affect the internal state. - * New data still could be fed via write method. - */ - virtual Result digestOut(ipfs::span out) const = 0; - - /// resets the internal state - virtual Result reset() = 0; - - /// hash size in bytes - virtual size_t digestSize() const = 0; - - /// block size in bytes for the most optimal hash update via write method - virtual size_t blockSize() const = 0; - - /// runtime identifiable hasher type - virtual HashType hashType() const = 0; - - ipfs::expected, Error> digest() const; - }; - - std::unique_ptr CreateHasher(multi::HashType); - -} // namespace libp2p::crypto - -#endif // LIBP2P_SRC_CRYPTO_HASHER_HPP diff --git a/library/include/libp2p/crypto/sha/sha256.hpp b/library/include/libp2p/crypto/sha/sha256.hpp deleted file mode 100644 index edff50ee..00000000 --- a/library/include/libp2p/crypto/sha/sha256.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_SHA256_HPP -#define LIBP2P_SHA256_HPP - -#include -#include -#include "libp2p/common/types.hpp" - -namespace libp2p::crypto { - -class Sha256 : public Hasher { - public: - Sha256(); - - ~Sha256() override; - - Result write(ipfs::ByteView data) override; - - Result digestOut(ipfs::span out) const override; - - Result reset() override; - - size_t digestSize() const override; - - size_t blockSize() const override; - - HashType hashType() const override; - - private: - void sinkCtx(); - - SHA256_CTX ctx_; - bool initialized_; -}; - -/** - * Take a SHA-256 hash from bytes - * @param input to be hashed - * @return hashed bytes - */ -ipfs::expected sha256(ipfs::ByteView input); -} // namespace libp2p::crypto - -#endif // LIBP2P_SHA256_HPP diff --git a/library/include/libp2p/multi/hash_type.hpp b/library/include/libp2p/multi/hash_type.hpp deleted file mode 100644 index fdb863c2..00000000 --- a/library/include/libp2p/multi/hash_type.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_HASH_TYPE_HPP -#define LIBP2P_HASH_TYPE_HPP - -#include - -namespace libp2p::multi { - /// TODO(Harrm) FIL-14: Hash types are a part of multicodec table, it would be - /// good to move them there to avoid duplication and allow for extraction of - /// human-friendly name of a type from its code - /// @see MulticodecType - /// https://github.com/multiformats/js-multihash/blob/master/src/constants.js - enum class HashType : std::uint64_t { - identity = 0x0, - sha1 = 0x11, - sha256 = 0x12, - sha512 = 0x13, - blake2b_256 = 0xb220, - blake2s128 = 0xb250, - blake2s256 = 0xb260, - sha2_256_trunc254_padded = 0x1012, - poseidon_bls12_381_a1_fc1 = 0xb401, - }; -} // namespace libp2p::multi - -#endif // LIBP2P_HASH_TYPE_HPP diff --git a/library/include/libp2p/multi/multibase_codec/multibase_codec_impl.hpp b/library/include/libp2p/multi/multibase_codec/multibase_codec_impl.hpp deleted file mode 100644 index 5fe1cac5..00000000 --- a/library/include/libp2p/multi/multibase_codec/multibase_codec_impl.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_MULTIBASE_IMPL_HPP -#define LIBP2P_MULTIBASE_IMPL_HPP - -#include - -#include - -namespace libp2p::multi { -/** - * Implementation of the MultibaseCodec with fair codecs - */ -class MultibaseCodecImpl : public MultibaseCodec { - public: - ~MultibaseCodecImpl() override = default; - - std::string encode(const ByteBuffer& bytes, Encoding encoding) const override; - - FactoryResult decode(std::string_view string) const override; -}; -} // namespace libp2p::multi - -// OUTCOME_HPP_DECLARE_ERROR(libp2p::multi, MultibaseCodecImpl::Error) - -#endif // LIBP2P_MULTIBASE_IMPL_HPP diff --git a/library/include/libp2p/multi/multihash.hpp b/library/include/libp2p/multi/multihash.hpp deleted file mode 100644 index 43acb685..00000000 --- a/library/include/libp2p/multi/multihash.hpp +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_MULTIHASH_HPP -#define LIBP2P_MULTIHASH_HPP - -#include "vocab/byte_view.h" -#include "vocab/expected.h" - -#include -#include -#include - -#include -#include - -namespace libp2p::multi { - -/** - * Special format of hash used in Libp2p. Allows to differentiate between - * outputs of different hash functions. More - * https://github.com/multiformats/multihash - */ -class Multihash { - public: - Multihash(const Multihash& other); - - Multihash& operator=(const Multihash& other) = default; - - Multihash(Multihash&& other) noexcept; - - Multihash& operator=(Multihash&& other) noexcept = default; - - ~Multihash() noexcept; - - static constexpr uint8_t kMaxHashLength = 127; - - enum class Error { - ZERO_INPUT_LENGTH = 1, - INPUT_TOO_LONG, - INPUT_TOO_SHORT, - INCONSISTENT_LENGTH, - INVALID_HEXADECIMAL_INPUT - }; - - /** - * @brief Creates a multihash from hash type and the hash itself. Note that - * the max hash length is 127 - * @param type - numerical code of the hash type. - * @param hash - binary buffer with the hash - * @return result with the multihash in case of success - */ - static ipfs::expected create(HashType type, - ipfs::ByteView hash); - - /** - * @brief Creates a multihash from a string, which represents a binary - * buffer in hexadecimal form. The first byte denotes the hash type, the - * second one contains the hash length, and the following are the hash - * itself - * @param hex - the string with hexadecimal representation of the multihash - * @return result with the multihash in case of success - */ - static ipfs::expected createFromHex(std::string_view hex); - - /** - * @brief Creates a multihash from a binary - * buffer. The first byte denotes the hash type, the - * second one contains the hash length, and the following are the hash - * itself - * @param b - the buffer with the multihash - * @return result with the multihash in case of success - */ - static ipfs::expected createFromBytes(ipfs::ByteView b); - - /** - * @return the info about hash type - */ - const HashType& getType() const; - - /** - * @return the hash stored in this multihash - */ - ipfs::ByteView getHash() const; - - /** - * @return a string with hexadecimal representation of the multihash - */ - std::string toHex() const; - - /** - * @return a buffer with the multihash, including its type, length and hash - */ - std::vector const& toBuffer() const; - - /** - * @return Pre-calculated hash for std containers - */ - size_t stdHash() const; - - bool operator==(const Multihash& other) const; - - bool operator!=(const Multihash& other) const; - - bool operator<(const Multihash& other) const; - - private: - /** - * Header consists of hash type and hash size, both 1 byte or 2 hex digits - * long, thus 4 hex digits long in total - */ - static constexpr uint8_t kHeaderSize = 4; - - /** - * Constructs a multihash from a type and a hash. Inits length_ with the - * size of the hash. Does no checks on the validity of provided data, in - * contrary to public fabric methods - * @param type - the info about the hash type - * @param hash - a binary buffer with the hash - */ - Multihash(HashType type, ipfs::ByteView hash); - - /** - * Contains a one byte hash type, a one byte hash length, and the stored - * hash itself - */ - struct Data { - // TODO(artem): move to small_vector - // as soon as toBuffer() -> span is acceptable - std::vector bytes; - uint8_t hash_offset{}; ///< size of non-hash data from the beginning - HashType type; - size_t std_hash; ///< Hash for unordered containers - - Data(HashType t, ipfs::ByteView h); - - ~Data() noexcept; - }; - - const Data& data() const; - - std::shared_ptr data_; -}; - -std::string to_string(Multihash::Error); - -} // namespace libp2p::multi - -namespace std { -template <> -struct hash { - size_t operator()(const libp2p::multi::Multihash& x) const { - return x.stdHash(); - } -}; -} // namespace std - -#endif // LIBP2P_MULTIHASH_HPP diff --git a/library/include/libp2p/peer/peer_id.hpp b/library/include/libp2p/peer/peer_id.hpp deleted file mode 100644 index eadc40c8..00000000 --- a/library/include/libp2p/peer/peer_id.hpp +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef LIBP2P_PEER_ID_HPP -#define LIBP2P_PEER_ID_HPP - -#include -#include -#include -#include -#include -#include "libp2p/crypto/key.h" - -#include -#include - -namespace libp2p::peer { - -/** - * Unique identifier of the peer - SHA256 Multihash, in most cases, of its - * public key - */ -class PeerId { - enum class FactoryError { SUCCESS = 0, SHA256_EXPECTED = 1 }; - using Error = std::variant; - using FactoryResult = ipfs::expected; - - public: - PeerId(const PeerId& other) = default; - PeerId& operator=(const PeerId& other) = default; - PeerId(PeerId&& other) noexcept = default; - PeerId& operator=(PeerId&& other) noexcept = default; - ~PeerId() = default; - - /** - * Create a PeerId from the public key - * @param key, from which PeerId is to be created - * @return instance of PeerId - */ - static FactoryResult fromPublicKey(const crypto::ProtobufKey& key); - - /** - * Create a PeerId from the byte array (serialized multihash). - * @param v buffer - * @return instance of PeerId - */ - static FactoryResult fromBytes(ipfs::ByteView v); - - /** - * Create a PeerId from base58-encoded string (not Multibase58!) with its - * SHA256-hashed ID - * @param id, with which PeerId is to be created - * @return instance of PeerId in case of success, error otherwise - */ - static FactoryResult fromBase58(std::string_view id); - - static FactoryResult FromMultibase(std::string_view id); - - /** - * Create a PeerId from SHA256 hash of its ID - * @param hash, with which PeerId is to be created; MUST be SHA256 - * @return instance of PeerId in case of success, error otherwise - */ - static FactoryResult fromHash(const multi::Multihash& hash); - - /** - * Get a base58 (not Multibase58!) representation of this PeerId - * @return base58-encoded SHA256 multihash of the peer's ID - */ - std::string toBase58() const; - - /** - * @brief Get a hex representation of this PeerId. - */ - std::string toHex() const; - - /** - * Creates a vector representation of PeerId. - */ - const std::vector& toVector() const; - - /** - * Get a SHA256 multihash of the peer's ID - * @return multihash - */ - const multi::Multihash& toMultihash() const; - - bool operator<(const PeerId& other) const; - bool operator==(const PeerId& other) const; - bool operator!=(const PeerId& other) const; - - private: - /// if key, from which a PeerId is created, does not exceed this size, it's - /// put as a PeerId as-is, without SHA-256 hashing - static constexpr size_t kMaxInlineKeyLength = 42; - - /** - * Create an instance of PeerId - * @param hash, with which PeerId is to be created - */ - explicit PeerId(multi::Multihash hash); - - multi::Multihash hash_; -}; - -} // namespace libp2p::peer - -namespace std { -template <> -struct hash { - size_t operator()(const libp2p::peer::PeerId& peer_id) const; -}; -} // namespace std - -// OUTCOME_HPP_DECLARE_ERROR(libp2p::peer, PeerId::FactoryError) - -#endif // LIBP2P_PEER_ID_HPP diff --git a/library/include/vocab/byte.h b/library/include/vocab/byte.h index 39212424..17477c11 100644 --- a/library/include/vocab/byte.h +++ b/library/include/vocab/byte.h @@ -34,4 +34,10 @@ namespace { } } // namespace +namespace ipfs { +inline bool operator==(Byte a, Byte b) { + return to_integer(a) == to_integer(b); +} +} // namespace ipfs + #endif // IPFS_BYTE_H_ diff --git a/library/include/vocab/raw_ptr.h b/library/include/vocab/raw_ptr.h index 5bfd3f70..25405d3e 100644 --- a/library/include/vocab/raw_ptr.h +++ b/library/include/vocab/raw_ptr.h @@ -34,7 +34,7 @@ class raw_ptr { public: // Chromium's raw_ptr has a default ctor whose semantics depend on build // config. For components/ipfs purposes, there is no reason to ever default - // construct. Set it to nullptr. We have time needed to assign a word. + // construct. Set it to nullptr. We have time needed to read_start a word. raw_ptr() = delete; raw_ptr(T* p) : ptr_{p} {} diff --git a/library/include/vocab/slash_delimited.h b/library/include/vocab/slash_delimited.h index 554656c5..53fd1424 100644 --- a/library/include/vocab/slash_delimited.h +++ b/library/include/vocab/slash_delimited.h @@ -1,22 +1,35 @@ #ifndef IPFS_SLASH_DELIMITED_H_ #define IPFS_SLASH_DELIMITED_H_ +#include #include #include +namespace google::protobuf::internal { +class LogMessage; +} + namespace ipfs { struct SlashDelimited { std::string_view remainder_; public: - SlashDelimited(std::string_view unowned); + SlashDelimited() : remainder_{""} {} + explicit SlashDelimited(std::string_view unowned); explicit operator bool() const; std::string_view pop(); std::string_view pop_all(); std::string_view pop_n(std::size_t); std::string_view peek_back() const; + std::string pop_back(); std::string to_string() const { return std::string{remainder_}; } + std::string_view to_view() const { return remainder_; } }; } // namespace ipfs +std::ostream& operator<<(std::ostream&, ipfs::SlashDelimited const&); +google::protobuf::internal::LogMessage& operator<<( + google::protobuf::internal::LogMessage&, + ipfs::SlashDelimited const&); + #endif // IPFS_SLASH_DELIMITED_H_ diff --git a/library/src/ipfs_client/all_inclusive.cc b/library/src/ipfs_client/all_inclusive.cc deleted file mode 100644 index 3ea6dfe0..00000000 --- a/library/src/ipfs_client/all_inclusive.cc +++ /dev/null @@ -1,114 +0,0 @@ -#include - -#if HAS_ALL_INCLUSIVE - -#if __has_include() -#include -#endif - -#include - -#include "log_macros.h" - -using Self = ipfs::AllInclusiveContext; - -namespace { -struct CallbackCallback { - Self* me; - std::shared_ptr alsome; - std::string host; -}; -} // namespace -extern "C" { -static void c_ares_c_callback(void* vp, - int status, - int /*timeouts*/, - unsigned char* abuf, - int alen) { - auto cbcb = reinterpret_cast(vp); - struct ares_txt_reply* txt_out = nullptr; - LOG(INFO) << "Buffer contains " << alen << " bytes."; - if (abuf && alen && !ares_parse_txt_reply(abuf, alen, &txt_out) && txt_out) { - cbcb->me->DnsResults(cbcb->host, *txt_out); - ares_free_data(txt_out); - } else { - LOG(ERROR) << "c_ares status=" << status; - } - delete cbcb; -} -} - -Self::AllInclusiveContext(boost::asio::io_context& io) : io_{io} { - if (ares_library_init(ARES_LIB_INIT_ALL)) { - throw std::runtime_error("Failed to initialize c-ares library."); - } - if (ares_init(&ares_channel_)) { - throw std::runtime_error("Failed to initialize c-ares channel."); - } -} -Self::~AllInclusiveContext() { - pending_dns_.clear(); - ares_destroy(ares_channel_); - ares_library_cleanup(); -} -void Self::SendDnsTextRequest(std::string host, - DnsTextResultsCallback rcb, - DnsTextCompleteCallback ccb) { - auto p = pending_dns_.emplace(host, std::vector{}); - auto it = p.first; - auto is_first = p.second; - it->second.emplace_back(DnsCbs{rcb, ccb}); - LOG(INFO) << __PRETTY_FUNCTION__ << ' ' << host << ' ' << is_first; - if (is_first) { - auto cbcb = new CallbackCallback; - cbcb->me = this; - cbcb->alsome = shared_from_this(); - cbcb->host = host; - ares_query(ares_channel_, it->first.c_str(), ns_c_in, ns_t_txt, - &c_ares_c_callback, cbcb); - io_.post([this]() { CAresProcess(); }); - } -} -void Self::DnsResults(std::string& host, ares_txt_reply& result) { - LOG(INFO) << __PRETTY_FUNCTION__ << ' ' << host; - auto i = pending_dns_.find(host); - if (pending_dns_.end() == i) { - return; - } - std::vector v{std::string{}}; - for (auto r = &result; r; r = r->next) { - auto p = reinterpret_cast(r->txt); - v[0].assign(p, r->length); - for (auto& cbs : i->second) { - cbs.r(v); - } - } - for (auto& cbs : i->second) { - cbs.c(); - } - pending_dns_.erase(i); -} -void Self::CAresProcess() { - LOG(INFO) << __PRETTY_FUNCTION__ << ' ' << pending_dns_.size(); - fd_set readers, writers; - struct timeval tv, *tvp; - FD_ZERO(&readers); - FD_ZERO(&writers); - auto nfds = ares_fds(ares_channel_, &readers, &writers); - if (nfds) { - tvp = ares_timeout(ares_channel_, NULL, &tv); - auto count = select(nfds, &readers, &writers, NULL, tvp); - ares_process(ares_channel_, &readers, &writers); - nfds += count; - } - if (nfds || pending_dns_.size()) { - io_.post([this]() { CAresProcess(); }); - } -} -void Self::SendHttpRequest(HttpRequestDescription desc, - HttpCompleteCallback cb) const { - auto sess = std::make_shared(io_, ssl_ctx_, desc, cb); - sess->run(); -} - -#endif diff --git a/library/src/ipfs_client/car.cc b/library/src/ipfs_client/car.cc new file mode 100644 index 00000000..e3644234 --- /dev/null +++ b/library/src/ipfs_client/car.cc @@ -0,0 +1,132 @@ +#include "car.h" + +#include + +#include + +#include "log_macros.h" + +#include + +using Self = ipfs::Car; +using Byte = ipfs::Byte; +using ByteView = ipfs::ByteView; +using VarInt = libp2p::multi::UVarint; + +namespace { +short ReadHeader(ByteView&, ipfs::ContextApi const&); +std::pair GetV1PayloadPos(ByteView); +} // namespace + +Self::Car(ByteView bytes, ContextApi const& api) { + auto after_header = bytes; + auto version = ReadHeader(after_header, api); + switch (version) { + case 0: + LOG(ERROR) << "Problem parsing CAR header."; + break; + case 1: + LOG(INFO) << "Reading CARv1"; + data_ = after_header; + break; + case 2: { + auto [off, siz] = GetV1PayloadPos(after_header); + LOG(INFO) << "CARv2 carries a payload of " << siz << "B @ " << off; + // TODO validate off and siz are sane, e.g. not pointing back into pragma + // or whatever + data_ = bytes.subspan(off, siz); + ReadHeader(data_, api); + break; + } + default: + LOG(ERROR) << "Unsupported CAR format version " << version; + } +} +auto Self::NextBlock() -> std::optional { + auto len = VarInt::create(data_); + if (!len) { + return std::nullopt; + } + data_ = data_.subspan(len->size()); + if (len->toUInt64() > data_.size()) { + LOG(ERROR) << "Length prefix claims cid+block is " << len->toUInt64() + << " bytes, but I only have " << data_.size() + << " bytes left in the CAR payload."; + data_ = {}; + return std::nullopt; + } + Block rv; + rv.bytes = data_.subspan(0U, len->toUInt64()); + data_ = data_.subspan(len->toUInt64()); + if (rv.cid.ReadStart(rv.bytes)) { + // TODO : check hash + return rv; + } + return std::nullopt; +} + +namespace { +// https://ipld.io/specs/transport/car/carv2/ +short ReadHeader(ByteView& bytes, ipfs::ContextApi const& api) { + auto header_len = VarInt::create(bytes); + if (!header_len || + header_len->toUInt64() + header_len->size() > bytes.size()) { + return 0; + } + bytes = bytes.subspan(header_len->size()); + auto header_bytes = bytes.subspan(0UL, header_len->toUInt64()); + auto header = api.ParseCbor(header_bytes); + if (!header) { + return 0; + } + auto version_node = header->at("version"); + if (!version_node) { + return 0; + } + auto version = version_node->as_unsigned(); + if (version) { + bytes = bytes.subspan(header_len->toUInt64()); + return version.value(); + } + return 0; +} +std::uint64_t read_le_u64(ByteView bytes, unsigned& off) { + auto b = bytes.subspan(off, off + 8); + off += 8U; + auto shift_in = [](std::uint64_t i, Byte y) { + return (i << 8) | static_cast(y); + }; + return std::accumulate(b.rbegin(), b.rend(), 0UL, shift_in); +} +std::pair GetV1PayloadPos(ByteView bytes) { + // Following the 11 byte pragma, the CARv2 [header] is a fixed-length sequence + // of 40 bytes, broken into the following sections: + if (bytes.size() < 40) { + return {}; + } + + // Characteristics: A 128-bit (16-byte) bitfield used to describe certain + // features of the enclosed data. + auto reading_off = 16U; + + // Data offset: A 64-bit (8-byte) unsigned + // little-endian integer indicating the byte-offset from the beginning of the + // CARv2 [pragma] to the first byte of the CARv1 data payload. + auto data_offset = read_le_u64(bytes, reading_off); + + // Data size: A 64-bit + // (8-byte) unsigned little-endian integer indicating the byte-length of the + // CARv1 data payload. + auto data_size = read_le_u64(bytes, reading_off); + + // Index offset: A 64-bit (8-byte) unsigned little-endian + // integer indicating the byte-offset from the beginning of the CARv2 to the + // first byte of the index payload. This value may be 0 to indicate the + // absence of index data. + reading_off += 8; // Ignoring index and therefore index offset + + assert(reading_off == 40UL); + + return {data_offset, data_size}; +} +} // namespace \ No newline at end of file diff --git a/library/src/ipfs_client/car.h b/library/src/ipfs_client/car.h new file mode 100644 index 00000000..619ac48e --- /dev/null +++ b/library/src/ipfs_client/car.h @@ -0,0 +1,26 @@ +#ifndef IPFS_CAR_H_ +#define IPFS_CAR_H_ + +#include +#include + +#include +#include + +namespace ipfs { +class ContextApi; +class Car { + public: + Car(ByteView, ContextApi const&); + struct Block { + Cid cid; + ByteView bytes; + }; + std::optional NextBlock(); + + private: + ByteView data_; +}; +} // namespace ipfs + +#endif // IPFS_CAR_H_ diff --git a/library/src/ipfs_client/car_unittest.cc b/library/src/ipfs_client/car_unittest.cc new file mode 100644 index 00000000..bebadf29 --- /dev/null +++ b/library/src/ipfs_client/car_unittest.cc @@ -0,0 +1,70 @@ +#include "car.h" + +#include + +#include +#include +#include + +using T = ipfs::Car; +namespace fs = std::filesystem; + +namespace { +struct CarTest : public testing::Test { + std::shared_ptr api = std::make_shared(); + fs::path dir() const { + auto cars_unittest_cc = fs::path{__FILE__}; + auto ipfs_client = cars_unittest_cc.parent_path(); + auto src = ipfs_client.parent_path(); + auto library = src.parent_path(); + auto project_root = library.parent_path(); + return project_root / "test_data" / "cars"; + } + std::vector list(std::string file_name) { + std::vector bytes; + auto fp = dir() / file_name; + std::ifstream f{fp}; + bytes.resize(file_size(fp)); + EXPECT_TRUE(f.read(bytes.data(), bytes.size())); + T car(ipfs::as_bytes(bytes), *api); + std::vector rv; + while (auto block = car.NextBlock()) { + rv.push_back(block->cid); + } + EXPECT_GT(rv.size(), 1UL); + return rv; + } +}; +} // namespace + +#if HAS_JSON_CBOR_ADAPTER + +TEST_F(CarTest, SmallishDirectoryAndAllItsContents) { + auto result = + list("bafybeifyeyhzmhj5fg2f5v7k4gsvazw7iwsjehpq77o54vd4kwdd3fud3y"); + EXPECT_EQ(result.size(), 4UL); + EXPECT_EQ(result.at(0).to_string(), + "bafybeifyeyhzmhj5fg2f5v7k4gsvazw7iwsjehpq77o54vd4kwdd3fud3y"); + EXPECT_EQ(result.at(1).to_string(), + "bafkreigks6arfsq3xxfpvqrrwonchxcnu6do76auprhhfomao6c273sixm"); + EXPECT_EQ(result.at(2).to_string(), + "bafkreih3ryqpylsmh4siyygdtplff46bgrzjro4xpofu2widxbifkyqgam"); + EXPECT_EQ(result.at(3).to_string(), + "bafkreif2pall7dybz7vecqka3zo24irdwabwdi4wc55jznaq75q7eaavvu"); +} + +TEST_F(CarTest, V2FromOfficialTestFixture) { + auto result = list("carv2-basic.car"); + EXPECT_EQ(result.size(), 5UL); + EXPECT_EQ(result.at(0).to_string(), + "bafybeih3c32qqnas54jxdubr5vfkeomqhwco7ww7dor42z4omr23dirs7a"); + EXPECT_EQ(result.at(1).to_string(), + "bafybeigzydkto3jg6gjr66wvfv5myah4ccinf3nqqcf7mhxlbiksqjxwey"); + EXPECT_EQ(result.at(2).to_string(), + "bafybeigxiw3xk723iwj65k3yeaygy66gj22jnj2bbigqpx32gt76ys4x6e"); + EXPECT_EQ(result.at(3).to_string(), + "bafkreifuosuzujyf4i6psbneqtwg2fhplc2wxptc5euspa2gn3bwhnihfu"); + EXPECT_EQ(result.at(4).to_string(), + "bafkreifc4hca3inognou377hfhvu2xfchn2ltzi7yu27jkaeujqqqdbjju"); +} +#endif diff --git a/library/src/ipfs_client/cid.cc b/library/src/ipfs_client/cid.cc index f94539e6..b2068608 100644 --- a/library/src/ipfs_client/cid.cc +++ b/library/src/ipfs_client/cid.cc @@ -12,46 +12,49 @@ Self::Cid(ipfs::MultiCodec cdc, ipfs::MultiHash hsh) : codec_{cdc}, hash_{hsh} {} Self::Cid(ipfs::ByteView bytes) { - assign(bytes); + ReadStart(bytes); } Self::Cid(std::string_view s) { if (s.size() == 46 && s[0] == 'Q' && s[1] == 'm') { auto bytes = mb::Codec::Get(mb::Code::BASE58_BTC)->decode(s); - assign(bytes); + auto view = ByteView{bytes}; + ReadStart(view); } else if (auto bytes = mb::decode(s)) { if (bytes->size() > 4) { - assign(bytes.value()); + auto view = ByteView{bytes.value()}; + ReadStart(view); } } else { LOG(WARNING) << "Failed to decode the multibase for a CID: " << s; } } -void Self::assign(ipfs::ByteView bytes) { - if (bytes.size() == 34 && bytes[0] == ipfs::Byte{0x12} && +bool Self::ReadStart(ByteView& bytes) { + if (bytes.size() >= 34 && bytes[0] == ipfs::Byte{0x12} && bytes[1] == ipfs::Byte{0x20}) { hash_ = MultiHash{bytes}; codec_ = hash_.valid() ? MultiCodec::DAG_PB : MultiCodec::INVALID; - return; + bytes = bytes.subspan(34); + return true; } auto version = VarInt::create(bytes); if (!version) { - return; + return false; } if (version->toUInt64() != 1U) { LOG(ERROR) << "CID version " << version->toUInt64() << " not supported."; - return; + return false; } bytes = bytes.subspan(version->size()); auto codec = VarInt::create(bytes); if (!codec) { - return; + return false; } auto cdc = static_cast(codec->toUInt64()); codec_ = Validate(cdc); bytes = bytes.subspan(codec->size()); - hash_ = MultiHash{bytes}; + return hash_.ReadPrefix(bytes); } bool Self::valid() const { diff --git a/library/src/ipfs_client/gw/block_request_splitter.cc b/library/src/ipfs_client/gw/block_request_splitter.cc index 7665ab23..3ded788f 100644 --- a/library/src/ipfs_client/gw/block_request_splitter.cc +++ b/library/src/ipfs_client/gw/block_request_splitter.cc @@ -11,23 +11,20 @@ auto Self::handle(ipfs::gw::RequestPtr r) -> HandleOutcome { if (r->type != Type::Car) { return HandleOutcome::NOT_HANDLED; } - // if (r->path.empty()) { - r->type = Type::Block; - return HandleOutcome::NOT_HANDLED; - /* } - { - auto br = std::make_shared(*r); - br->type = Type::Block; - br->path.clear(); - forward(br); - } - { - auto pr = std::make_shared(*r); - pr->type = Type::Providers; - pr->path.clear(); - pr->affinity.clear(); - forward(pr); - } - return HandleOutcome::NOT_HANDLED; - */ + { + auto br = std::make_shared(*r); + br->type = Type::Block; + br->path.clear(); + forward(br); + } + /* + { + auto pr = std::make_shared(*r); + pr->type = Type::Providers; + pr->path.clear(); + pr->affinity.clear(); + forward(pr); + } + */ + return HandleOutcome::NOT_HANDLED; } \ No newline at end of file diff --git a/library/src/ipfs_client/gw/block_request_splitter_unittest.cc b/library/src/ipfs_client/gw/block_request_splitter_unittest.cc index f435492d..5f742282 100644 --- a/library/src/ipfs_client/gw/block_request_splitter_unittest.cc +++ b/library/src/ipfs_client/gw/block_request_splitter_unittest.cc @@ -33,8 +33,7 @@ TEST(BlockRequestSplitterTest, not_yet_implemented) { req->path = "path"; req->parallel = 123; tested.request(req); - // EXPECT_EQ(rec->requests_received.size(), 3U); - EXPECT_EQ(rec->requests_received.size(), 1U); + EXPECT_EQ(rec->requests_received.size(), 2U); EXPECT_TRUE(rec->requests_received.at(0)->type == g::Type::Block) << static_cast(rec->requests_received.at(0)->type); // EXPECT_TRUE(rec->requests_received.at(1)->type == g::Type::Providers) << @@ -45,9 +44,8 @@ static_cast(rec->requests_received.at(0)->type); // EXPECT_EQ(rec->requests_received.at(1)->main_param, "cid"); // EXPECT_EQ(rec->requests_received.at(2)->main_param, "cid"); // EXPECT_EQ(rec->requests_received.at(0)->path, ""); - EXPECT_EQ(rec->requests_received.at(0)->path, "path"); - // EXPECT_EQ(rec->requests_received.at(1)->path, ""); - // EXPECT_EQ(rec->requests_received.at(2)->path, "path"); + EXPECT_EQ(rec->requests_received.at(0)->path, ""); + EXPECT_EQ(rec->requests_received.at(1)->path, "path"); EXPECT_EQ(rec->requests_received.at(0)->parallel, 123); // EXPECT_EQ(rec->requests_received.at(1)->parallel, 123); // EXPECT_EQ(rec->requests_received.at(2)->parallel, 123); diff --git a/library/src/ipfs_client/gw/dnslink_requestor_unittest.cc b/library/src/ipfs_client/gw/dnslink_requestor_unittest.cc index 3a3e469d..1eaf6287 100644 --- a/library/src/ipfs_client/gw/dnslink_requestor_unittest.cc +++ b/library/src/ipfs_client/gw/dnslink_requestor_unittest.cc @@ -13,7 +13,7 @@ struct DnslinkRequestorTest : public testing::Test { std::shared_ptr api = std::make_shared(); std::shared_ptr t_ = std::make_shared(api); std::shared_ptr r_ = - ig::GatewayRequest::fromIpfsPath("/ipns/not_a_cid"sv); + ig::GatewayRequest::fromIpfsPath(i::SlashDelimited{"/ipns/not_a_cid"}); ig::Requestor& t() { return *t_; } std::shared_ptr orc_ = std::make_shared( std::make_shared()); diff --git a/library/src/ipfs_client/gw/gateway_http_requestor.cc b/library/src/ipfs_client/gw/gateway_http_requestor.cc index 4f384b9e..ecac0bf0 100644 --- a/library/src/ipfs_client/gw/gateway_http_requestor.cc +++ b/library/src/ipfs_client/gw/gateway_http_requestor.cc @@ -4,9 +4,9 @@ #include #include -#include #include #include +#include #include "log_macros.h" @@ -65,7 +65,8 @@ auto Self::handle(ipfs::gw::RequestPtr r) -> HandleOutcome { if (ct.empty()) { LOG(ERROR) << "No content-type header?"; } - if (ct.size() && desc->accept.size() && ct != desc->accept) { + if (ct.size() && desc->accept.size() && + ct.find(desc->accept) == std::string::npos) { LOG(WARNING) << "Requested with Accept: " << desc->accept << " but received response with content-type: " << ct; LOG(INFO) << "Demote(" << prefix_ << ')'; @@ -126,7 +127,7 @@ ipfs::ipld::NodePtr Self::node_from_type(std::optional const& cid, switch (t) { case ReqTyp::Block: { if (cid.has_value()) { - ipfs::Block blk{cid.value(), std::string{body}}; + ipfs::PbDag blk{cid.value(), as_bytes(body)}; if (blk.cid_matches_data(*api_)) { return ipfs::ipld::DagNode::fromBlock(blk); } diff --git a/library/src/ipfs_client/gw/gateway_http_requestor_unittest.cc b/library/src/ipfs_client/gw/gateway_http_requestor_unittest.cc index 8e1d47ce..03641944 100644 --- a/library/src/ipfs_client/gw/gateway_http_requestor_unittest.cc +++ b/library/src/ipfs_client/gw/gateway_http_requestor_unittest.cc @@ -32,8 +32,8 @@ struct GatewayHttpRequestorTest : public ::testing::Test { t->or_else(chain); auto noop = [](auto) {}; auto noop2 = [](auto, auto) {}; - auto req = R::fromIpfsPath( - "/ipfs/bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku"sv); + auto req = R::fromIpfsPath(i::SlashDelimited{ + "/ipfs/bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku"}); req->orchestrator(orc = std::make_shared(t, api)); req->dependent = std::make_shared( "/ipfs/bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku", diff --git a/library/src/ipfs_client/gw/gateway_request.cc b/library/src/ipfs_client/gw/gateway_request.cc index ef842a30..1b251b1f 100644 --- a/library/src/ipfs_client/gw/gateway_request.cc +++ b/library/src/ipfs_client/gw/gateway_request.cc @@ -4,10 +4,11 @@ #include #include -#include +#include #include #include #include +#include #include #include "log_macros.h" @@ -153,10 +154,13 @@ std::optional Self::max_response_size() const { case Type::Block: return BLOCK_RESPONSE_BUFFER_SIZE; case Type::Car: { - auto n = std::count(path.begin(), path.end(), '/'); - // now n >= number of path components, but there is also a block for root - n++; - return n * BLOCK_RESPONSE_BUFFER_SIZE; + // There could be an unlimited number of blocks in the CAR + // The _floor_ is the number of path components. + // But one path component could be a HAMT sharded directory that we may + // need to pass through several layers on. + // And the final path component could be a UnixFS file with an unlimited + // number of blocks in it. + return std::nullopt; } case Type::Zombie: return 0; @@ -215,9 +219,10 @@ bool Self::RespondSuccessfully(std::string_view bytes, case Type::Block: { DCHECK(cid.has_value()); if (!cid.has_value()) { - LOG(ERROR) << "Your CID doesn't even hae a value!"; + LOG(ERROR) << "Your CID doesn't even have a value!"; return false; } + DCHECK(api); auto node = DagNode::fromBytes(api, cid.value(), bytes); success = orchestrator_->add_node(main_param, node); } break; @@ -249,15 +254,31 @@ bool Self::RespondSuccessfully(std::string_view bytes, LOG(FATAL) << "I have no orchestrator!!"; } break; - case Type::Zombie: - LOG(ERROR) << "Responding to a zombie is ill-advised."; - break; - case Type::Car: - LOG(WARNING) << "TODO - handle responses to CAR requests."; + case Type::Car: { + DCHECK(api); + Car car(as_bytes(bytes), *api); + auto added = 0; + while (auto block = car.NextBlock()) { + auto cid_s = block->cid.to_string(); + auto n = DagNode::fromBytes(api, block->cid, block->bytes); + if (!n) { + LOG(ERROR) << "Unable to handle block from CAR: " << cid_s; + } else if (orchestrator_->add_node(cid_s, n)) { + ++added; + } else { + LOG(INFO) << "Did not add node from CAR: " << cid_s; + } + } + LOG(INFO) << "Added " << added << " nodes from a CAR."; + success = added > 0; break; + } case Type::Providers: LOG(WARNING) << "TODO - handle responses to providers requests."; break; + case Type::Zombie: + LOG(WARNING) << "Responding to a zombie is ill-advised."; + break; default: LOG(ERROR) << "TODO " << static_cast(type); } @@ -276,3 +297,9 @@ void Self::Hook(std::function f) { void Self::orchestrator(std::shared_ptr const& orc) { orchestrator_ = orc; } +bool Self::PartiallyRedundant() const { + if (!orchestrator_) { + return false; + } + return orchestrator_->has_key(main_param); +} diff --git a/library/src/ipfs_client/gw/gateway_request_unittest.cc b/library/src/ipfs_client/gw/gateway_request_unittest.cc new file mode 100644 index 00000000..a10fa1dd --- /dev/null +++ b/library/src/ipfs_client/gw/gateway_request_unittest.cc @@ -0,0 +1,107 @@ +#include +#include + +#include +#include + +using T = ig::GatewayRequest; + +namespace { +constexpr std::array a_car{ + 0x0a, 0xa1, 0x67, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3a, 0xa2, 0x65, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x81, + 0xd8, 0x2a, 0x58, 0x25, 0x00, 0x01, 0x70, 0x12, 0x20, 0x36, 0x28, 0x15, + 0x89, 0x64, 0x53, 0x16, 0x7b, 0xc1, 0xd1, 0xa6, 0x80, 0x31, 0xf4, 0x80, + 0x9b, 0xe8, 0x0c, 0x94, 0x9d, 0xca, 0x5c, 0xeb, 0x59, 0x85, 0xce, 0x93, + 0xcc, 0xef, 0x34, 0x0f, 0xbe, 0x67, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x01, 0x28, 0x01, 0x55, 0x12, 0x20, 0x77, 0x0e, 0x60, 0x76, 0x24, + 0xd6, 0x89, 0x26, 0x5c, 0xa6, 0xc4, 0x48, 0x84, 0xd0, 0x80, 0x7d, 0x9b, + 0x05, 0x4d, 0x23, 0xc4, 0x73, 0xc1, 0x06, 0xc7, 0x2b, 0xe9, 0xde, 0x08, + 0xb7, 0x37, 0x6c, 0x67, 0x6f, 0x6f, 0x64, 0x32, 0x01, 0x55, 0x12, 0x20, + 0xd2, 0x69, 0x9a, 0x29, 0x4b, 0xbd, 0x90, 0x4d, 0x1d, 0xff, 0x27, 0x48, + 0x9b, 0xef, 0x29, 0x26, 0x77, 0x94, 0xf4, 0xab, 0xe2, 0x63, 0x91, 0x0d, + 0xbe, 0x8f, 0x76, 0xba, 0xb0, 0xe7, 0x2b, 0x19, 0x48, 0x65, 0x6c, 0x6c, + 0x6f, 0x20, 0x57, 0x68, 0x69, 0x72, 0x6c, 0x65, 0x64, 0x21, 0x89, 0x01, + 0x01, 0x70, 0x12, 0x20, 0x36, 0x28, 0x15, 0x89, 0x64, 0x53, 0x16, 0x7b, + 0xc1, 0xd1, 0xa6, 0x80, 0x31, 0xf4, 0x80, 0x9b, 0xe8, 0x0c, 0x94, 0x9d, + 0xca, 0x5c, 0xeb, 0x59, 0x85, 0xce, 0x93, 0xcc, 0xef, 0x34, 0x0f, 0xbe, + 0x12, 0x2e, 0x0a, 0x24, 0x01, 0x55, 0x12, 0x20, 0x77, 0x0e, 0x60, 0x76, + 0x24, 0xd6, 0x89, 0x26, 0x5c, 0xa6, 0xc4, 0x48, 0x84, 0xd0, 0x80, 0x7d, + 0x9b, 0x05, 0x4d, 0x23, 0xc4, 0x73, 0xc1, 0x06, 0xc7, 0x2b, 0xe9, 0xde, + 0x08, 0xb7, 0x37, 0x6c, 0x12, 0x04, 0x67, 0x6f, 0x6f, 0x64, 0x18, 0x04, + 0x12, 0x2f, 0x0a, 0x24, 0x01, 0x55, 0x12, 0x20, 0xd2, 0x69, 0x9a, 0x29, + 0x4b, 0xbd, 0x90, 0x4d, 0x1d, 0xff, 0x27, 0x48, 0x9b, 0xef, 0x29, 0x26, + 0x77, 0x94, 0xf4, 0xab, 0xe2, 0x63, 0x91, 0x0d, 0xbe, 0x8f, 0x76, 0xba, + 0xb0, 0xe7, 0x2b, 0x19, 0x12, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x18, + 0x0e, 0x0a, 0x02, 0x08, 0x01, 0x81, 0x08, 0x01, 0x00, 0x00, 0x00, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, + 0x28, 0x15, 0x89, 0x64, 0x53, 0x16, 0x7b, 0xc1, 0xd1, 0xa6, 0x80, 0x31, + 0xf4, 0x80, 0x9b, 0xe8, 0x0c, 0x94, 0x9d, 0xca, 0x5c, 0xeb, 0x59, 0x85, + 0xce, 0x93, 0xcc, 0xef, 0x34, 0x0f, 0xbe, 0x97, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x77, 0x0e, 0x60, 0x76, 0x24, 0xd6, 0x89, 0x26, 0x5c, + 0xa6, 0xc4, 0x48, 0x84, 0xd0, 0x80, 0x7d, 0x9b, 0x05, 0x4d, 0x23, 0xc4, + 0x73, 0xc1, 0x06, 0xc7, 0x2b, 0xe9, 0xde, 0x08, 0xb7, 0x37, 0x6c, 0x3b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x69, 0x9a, 0x29, 0x4b, + 0xbd, 0x90, 0x4d, 0x1d, 0xff, 0x27, 0x48, 0x9b, 0xef, 0x29, 0x26, 0x77, + 0x94, 0xf4, 0xab, 0xe2, 0x63, 0x91, 0x0d, 0xbe, 0x8f, 0x76, 0xba, 0xb0, + 0xe7, 0x2b, 0x19, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +struct GatewayRequestTest : public testing::Test { + T t_; + std::shared_ptr api = std::make_shared(); + std::shared_ptr rtor = std::make_shared(); + std::shared_ptr orc = + std::make_shared(rtor, api); + GatewayRequestTest() { + t_.orchestrator(orc); + t_.main_param = "main"; + } +}; +} // namespace + +TEST_F(GatewayRequestTest, RespondsToCar) { + t_.cid = + i::Cid{"bafybeibwfakyszctcz54dungqay7jae35agjjhokltvvtboospgo6napxy"}; + t_.type = ig::Type::Car; + auto p = reinterpret_cast(a_car.data()); + EXPECT_FALSE(orc->has_key( + "bafkreidxbzqhmjgwretfzjwejccnbad5tmcu2i6eopaqnrzl5hparnzxnq")); + EXPECT_FALSE(orc->has_key( + "bafkreigsngncss55sbgr37zhjcn66kjgo6kpjk7cmoiq3pupo25lbzzlde")); + EXPECT_FALSE(orc->has_key( + "bafybeibwfakyszctcz54dungqay7jae35agjjhokltvvtboospgo6napxy")); + t_.RespondSuccessfully({p, a_car.size()}, api); + EXPECT_TRUE(orc->has_key( + "bafkreidxbzqhmjgwretfzjwejccnbad5tmcu2i6eopaqnrzl5hparnzxnq")); + EXPECT_TRUE(orc->has_key( + "bafkreigsngncss55sbgr37zhjcn66kjgo6kpjk7cmoiq3pupo25lbzzlde")); + EXPECT_TRUE(orc->has_key( + "bafybeibwfakyszctcz54dungqay7jae35agjjhokltvvtboospgo6napxy")); +} +TEST_F(GatewayRequestTest, suffices) { + t_.type = ig::Type::Car; + EXPECT_EQ(t_.url_suffix(), "/ipfs/main/?dag-scope=entity"); + t_.type = ig::Type::Ipns; + EXPECT_EQ(t_.url_suffix(), "/ipns/main"); + t_.type = ig::Type::Providers; + EXPECT_EQ(t_.url_suffix(), "/routing/v1/providers/main"); + t_.type = ig::Type::Identity; + EXPECT_EQ(t_.url_suffix(), ""); + t_.type = ig::Type::Zombie; + EXPECT_EQ(t_.url_suffix(), ""); +} +TEST_F(GatewayRequestTest, accept_param) { + t_.type = ig::Type::Car; + EXPECT_EQ(t_.accept(), "application/vnd.ipld.car"); + t_.type = ig::Type::Ipns; + EXPECT_EQ(t_.accept(), "application/vnd.ipfs.ipns-record"); + t_.type = ig::Type::Providers; + EXPECT_EQ(t_.accept(), "application/json"); + t_.type = ig::Type::Identity; + EXPECT_EQ(t_.accept(), ""); + t_.type = ig::Type::Zombie; + EXPECT_EQ(t_.accept(), ""); +} diff --git a/library/src/ipfs_client/gw/requestor.cc b/library/src/ipfs_client/gw/requestor.cc index 576ddb97..72e6746c 100644 --- a/library/src/ipfs_client/gw/requestor.cc +++ b/library/src/ipfs_client/gw/requestor.cc @@ -3,9 +3,9 @@ #include #include -#include #include #include +#include #include #include "log_macros.h" @@ -54,55 +54,12 @@ void Self::request(ReqPtr req) { break; } } -void Self::failure(ipfs::gw::RequestPtr r) const { - if (next_) { - LOG(WARNING) << name() << " failed on " << r->debug_string() - << " ... passing along to " << next_->name(); - next_->request(r); - } else { - definitive_failure(r); - } -} void Self::definitive_failure(ipfs::gw::RequestPtr r) const { DCHECK(r); DCHECK(r->dependent); r->dependent->finish(Response::PLAIN_NOT_FOUND); } -void Self::success(ipfs::gw::RequestPtr req, std::string_view body) const { - Response res; - res.status_ = 200; - res.body_.assign(body); - receive_response(req, res); -} -void Self::iterate_nodes( - GatewayRequest const& req, - Response const& res, - std::function cb) const { - if (res.body_.empty()) { - return; - } - Cid cid(req.main_param); - if (!cid.valid()) { - return; - } - Block b{std::move(cid), res.body_}; - if (!b.valid()) { - return; - } - auto n = ipld::DagNode::fromBlock(b); - if (n) { - cb(req.main_param, n); - } -} -void Self::receive_response(ipfs::gw::RequestPtr req, - ipfs::Response const& res) const { - if (res.status_ / 100 == 2) { - req->RespondSuccessfully(res.body_, api_); - } else if (req->parallel == 0) { - LOG(ERROR) << "Finally failing on " << req->debug_string(); - definitive_failure(req); - } -} + void Self::forward(ipfs::gw::RequestPtr req) const { if (next_) { next_->request(req); diff --git a/library/src/ipfs_client/gw/requestor_pool.cc b/library/src/ipfs_client/gw/requestor_pool.cc index b9cdaa65..b337dda1 100644 --- a/library/src/ipfs_client/gw/requestor_pool.cc +++ b/library/src/ipfs_client/gw/requestor_pool.cc @@ -33,6 +33,9 @@ auto Self::check(Waiting w) -> HandleOutcome { using O = HandleOutcome; auto next_retry = pool_.size(); auto req = w.req; + if (req->PartiallyRedundant()) { + return O::DONE; + } for (auto i = w.at_idx; i < pool_.size(); ++i) { if (req->type == Type::Zombie) { return O::DONE; diff --git a/library/src/ipfs_client/gw/requestor_pool_unittest.cc b/library/src/ipfs_client/gw/requestor_pool_unittest.cc index 4c253896..185e67dd 100644 --- a/library/src/ipfs_client/gw/requestor_pool_unittest.cc +++ b/library/src/ipfs_client/gw/requestor_pool_unittest.cc @@ -12,7 +12,7 @@ struct RequestorPoolTest : public ::testing::Test { std::shared_ptr tested = std::make_shared(); std::shared_ptr req = - ig::GatewayRequest::fromIpfsPath("/ipns/ipfs.io"sv); + ig::GatewayRequest::fromIpfsPath(i::SlashDelimited{"/ipns/ipfs.io"}); void add() { auto p = std::make_shared(); members.push_back(p); diff --git a/library/src/ipfs_client/gw/requestor_unittest.cc b/library/src/ipfs_client/gw/requestor_unittest.cc index 5e534bd1..70775d4c 100644 --- a/library/src/ipfs_client/gw/requestor_unittest.cc +++ b/library/src/ipfs_client/gw/requestor_unittest.cc @@ -52,3 +52,5 @@ TEST_F(RequestorTest, done_stops_request) { EXPECT_EQ(b->requests_sent_to_handle.size(), 0); EXPECT_TRUE(a->requests_sent_to_handle.at(0) == req_); } + +TEST_F(RequestorTest, success_callsback) {} diff --git a/library/src/ipfs_client/ipld/chunk.cc b/library/src/ipfs_client/ipld/chunk.cc index caaa866d..e5540b08 100644 --- a/library/src/ipfs_client/ipld/chunk.cc +++ b/library/src/ipfs_client/ipld/chunk.cc @@ -7,14 +7,13 @@ using Chunk = ipfs::ipld::Chunk; Chunk::Chunk(std::string data) : data_{data} {} Chunk::~Chunk() {} -auto Chunk::resolve(ipfs::SlashDelimited path, - ipfs::ipld::DagNode::BlockLookup, - std::string&) -> ResolveResult { - if (path) { - LOG(ERROR) << "Can't resolve a path (" << path.to_string() +auto Chunk::resolve(ResolutionState& params) -> ResolveResult { + if (params.IsFinalComponent()) { + return Response{"", 200, data_, params.MyPath().to_string()}; + } else { + LOG(ERROR) << "Can't resolve a path (" << params.MyPath() << ") inside of a file chunk!"; return ProvenAbsent{}; } - return Response{"", 200, data_, {}}; } diff --git a/library/src/ipfs_client/ipld/chunk.h b/library/src/ipfs_client/ipld/chunk.h index 03f41bca..b846cc53 100644 --- a/library/src/ipfs_client/ipld/chunk.h +++ b/library/src/ipfs_client/ipld/chunk.h @@ -7,7 +7,7 @@ namespace ipfs::ipld { class Chunk : public DagNode { std::string const data_; - ResolveResult resolve(SlashDelimited, BlockLookup, std::string&) override; + ResolveResult resolve(ResolutionState&) override; public: explicit Chunk(std::string); diff --git a/library/src/ipfs_client/ipld/dag_cbor_node.cc b/library/src/ipfs_client/ipld/dag_cbor_node.cc index c7e0809d..064a8937 100644 --- a/library/src/ipfs_client/ipld/dag_cbor_node.cc +++ b/library/src/ipfs_client/ipld/dag_cbor_node.cc @@ -4,50 +4,21 @@ using Self = ipfs::ipld::DagCborNode; -auto Self::resolve(SlashDelimited path, BlockLookup blu, std::string& to_here) -> ResolveResult { +auto Self::resolve(ResolutionState& params) -> ResolveResult { if (auto cid = doc_->as_link()) { auto cid_str = cid.value().to_string(); - LOG(INFO) << to_here << " I am a DAG-CBOR link to " << cid_str; - if (links_.empty()) { - Link l{cid_str, blu(cid_str)}; - links_.push_back({std::string{}, l}); - } - auto& child = links_.back().second; - if (!child.node) { - child.node = blu(child.cid); - } - if (child.node) { - LOG(INFO) << to_here << " Indirection through link... "; - return child.node->resolve(path, blu, to_here); - } - return MoreDataNeeded{{"/ipfs/"+child.cid}}; + return CallChild(params, "", cid_str); } - if (!path) { - LOG(INFO) << to_here << " I am not a link, nor do I have a path... preview"; - return Response{"text/html", 200, doc_->html(), to_here}; + if (params.IsFinalComponent()) { + return Response{"text/html", 200, doc_->html(), + params.PathToResolve().to_string()}; } - auto nxt = path.pop(); - to_here.append("/").append(nxt); - auto it = std::find_if(links_.begin(), links_.end(), [nxt](auto&l){return l.first==nxt;}); - if (links_.end() != it) { - auto& link = it->second; - if (!link.node) { - link.node = blu(link.cid); + return CallChild(params, [this](std::string_view element_name) -> NodePtr { + if (auto child = doc_->at(element_name)) { + return std::make_shared(std::move(child)); } - if (link.node) { - LOG(INFO) << to_here << " CBOR node: descending into '" << nxt - << "' = " << link.cid; - return link.node->resolve(path, blu, to_here); - } - } else if (auto child = doc_->at(nxt)) { - auto child_node = std::make_shared(std::move(child)); - Link link2child{"",child_node}; - links_.emplace_back(nxt, link2child); - LOG(INFO) << "Descending into newly-created child node for map entry '" - << nxt << "', path is now '" << path.to_string() << "'."; - return links_.back().second.node->resolve(path, blu, to_here); - } - return ProvenAbsent{}; + return {}; + }); } Self::DagCborNode(std::unique_ptr p) : doc_{std::move(p)} {} diff --git a/library/src/ipfs_client/ipld/dag_cbor_node.h b/library/src/ipfs_client/ipld/dag_cbor_node.h index 0eb9bd8d..c9ba5333 100644 --- a/library/src/ipfs_client/ipld/dag_cbor_node.h +++ b/library/src/ipfs_client/ipld/dag_cbor_node.h @@ -7,8 +7,7 @@ namespace ipfs::ipld { class DagCborNode final : public DagNode { - ResolveResult resolve(SlashDelimited,BlockLookup, - std::string&) override; + ResolveResult resolve(ResolutionState&) override; public: using Data = DagCborValue; diff --git a/library/src/ipfs_client/ipld/dag_cbor_node_unittest.cc b/library/src/ipfs_client/ipld/dag_cbor_node_unittest.cc index 19dc8bb4..4195cad4 100644 --- a/library/src/ipfs_client/ipld/dag_cbor_node_unittest.cc +++ b/library/src/ipfs_client/ipld/dag_cbor_node_unittest.cc @@ -51,7 +51,7 @@ TEST_F(DagCborTest,ObjectWithLink) { return ipfs::ipld::NodePtr{}; }; std::string to_here{"/ipfs/bafyreifrkkhbwkf3fibwhbzcmpqnmh3b4t5t4ig7qdtymkdoatcycwe6n4"}; - auto result = tested().resolve(""sv, blu, to_here); + auto result = tested().resolve(i::SlashDelimited{""}, blu); auto& response = std::get(result); EXPECT_EQ(response.mime_,"text/html"); EXPECT_EQ(response.body_, R"HTML(DAG-CBOR Preview @@ -74,7 +74,7 @@ TEST_F(DagCborTest,ObjectWithLink) { )HTML" ); - result = tested().resolve("metadata.json"sv, blu, to_here); + result = tested().resolve(i::SlashDelimited{"metadata.json"}, blu); auto resp = std::get(result); EXPECT_EQ(resp.status_,200); EXPECT_EQ(resp.body_,metadata_json); diff --git a/library/src/ipfs_client/ipld/dag_json_node.cc b/library/src/ipfs_client/ipld/dag_json_node.cc index b0e6af20..dfb3f38b 100644 --- a/library/src/ipfs_client/ipld/dag_json_node.cc +++ b/library/src/ipfs_client/ipld/dag_json_node.cc @@ -18,41 +18,23 @@ Self::DagJsonNode(std::unique_ptr j) : data_(std::move(j)) { } Self::~DagJsonNode() noexcept {} -auto Self::resolve(SlashDelimited path, - BlockLookup blu, - std::string& up_to_here) -> ResolveResult { - if (auto link = is_link()) { - return child_resolve(path, blu, up_to_here, *link); +auto Self::resolve(ResolutionState& params) -> ResolveResult { + auto respond_as_link = CallChild(params, ""); + if (!std::get_if(&respond_as_link)) { + return respond_as_link; } - if (!path) { - return Response{"text/html", 200, html(), up_to_here}; + if (params.IsFinalComponent()) { + return Response{"text/html", 200, html(), params.MyPath().to_string()}; } - auto nxt = path.pop(); - for (auto& [k, l] : links_) { - if (k == nxt) { - return child_resolve(path, blu, up_to_here, l); + return CallChild(params, [this](std::string_view name) -> NodePtr { + auto child_data = (*data_)[name]; + if (child_data) { + return std::make_shared(std::move(child_data)); } - } - auto child_data = (*data_)[nxt]; - if (child_data) { - links_.emplace_back( - nxt, Link("", std::make_shared(std::move(child_data)))); - return child_resolve(path, blu, up_to_here, links_.back().second); - } - return ProvenAbsent{}; -} -auto Self::child_resolve(SlashDelimited path, - BlockLookup blu, - std::string& up_to_here, - Link& l) -> ResolveResult { - if (!l.node) { - l.node = blu(l.cid); - } - if (!l.node) { - return MoreDataNeeded{{"/ipfs/" + l.cid}}; - } - return l.node->resolve(path, blu, up_to_here); + return {}; + }); } + auto Self::is_link() -> Link* { if (links_.size() == 1UL && links_.front().first.empty()) { return &links_.front().second; diff --git a/library/src/ipfs_client/ipld/dag_json_node.h b/library/src/ipfs_client/ipld/dag_json_node.h index 7c3803a2..1d8012a0 100644 --- a/library/src/ipfs_client/ipld/dag_json_node.h +++ b/library/src/ipfs_client/ipld/dag_json_node.h @@ -8,14 +8,8 @@ namespace ipfs::ipld { class DagJsonNode final : public DagNode { std::unique_ptr data_; std::string html_; - ResolveResult resolve(SlashDelimited path, - BlockLookup, - std::string& up_to_here) override; + ResolveResult resolve(ResolutionState& params) override; Link* is_link(); - ResolveResult child_resolve(SlashDelimited path, - BlockLookup, - std::string& up_to_here, - Link& l); std::string const& html(); public: diff --git a/library/src/ipfs_client/ipld/dag_json_node_unittest.cc b/library/src/ipfs_client/ipld/dag_json_node_unittest.cc index d15cb8e5..186155e4 100644 --- a/library/src/ipfs_client/ipld/dag_json_node_unittest.cc +++ b/library/src/ipfs_client/ipld/dag_json_node_unittest.cc @@ -17,7 +17,7 @@ namespace n = nlohmann; namespace { struct DagJsonNodeTest : public ::testing::Test { - Super::BlockLookup noop_blu() const { + auto noop_blu() const { return [](auto&) { return ii::NodePtr{}; }; } std::unique_ptr tested_; @@ -68,7 +68,7 @@ struct DagJsonNodeTest : public ::testing::Test { TEST_F(DagJsonNodeTest, preview) { std::string p; - auto result = super().resolve(""sv, noop_blu(), p); + auto result = super().resolve(i::SlashDelimited{""}, noop_blu()); auto& resp = std::get(result); EXPECT_EQ(resp.status_, 200); EXPECT_EQ(resp.mime_, "text/html"); diff --git a/library/src/ipfs_client/ipld/dag_node.cc b/library/src/ipfs_client/ipld/dag_node.cc index aa60e704..4d11f6f2 100644 --- a/library/src/ipfs_client/ipld/dag_node.cc +++ b/library/src/ipfs_client/ipld/dag_node.cc @@ -11,11 +11,12 @@ #include "unixfs_file.h" #include -#include #include +#include #include "log_macros.h" +#include #include using Node = ipfs::ipld::DagNode; @@ -23,8 +24,35 @@ using Node = ipfs::ipld::DagNode; std::shared_ptr Node::fromBytes(std::shared_ptr const& api, Cid const& cid, std::string_view bytes) { + return fromBytes(api, cid, as_bytes(bytes)); +} +auto Node::fromBytes(std::shared_ptr const& api, + ipfs::Cid const& cid, + ipfs::ByteView bytes) -> NodePtr { std::shared_ptr result = nullptr; - + auto hash = api->Hash(cid.hash_type(), bytes); + if (!hash.has_value()) { + LOG(ERROR) << "Could not hash response for " << cid.to_string(); + return {}; + } + if (hash.value().size() != cid.hash().size()) { + return {}; + } + for (auto i = 0U; i < hash.value().size(); ++i) { + auto e = cid.hash()[i]; + auto a = hash.value().at(i); + if (e != a) { + return {}; + } + } + auto required = cid.hash(); + auto calculated = hash.value(); + if (!std::equal(required.begin(), required.end(), calculated.begin(), + calculated.end())) { + LOG(ERROR) << "Hash of response did not match the one in the CID " + << cid.to_string(); + return {}; + } switch (cid.codec()) { case MultiCodec::DAG_CBOR: { auto p = reinterpret_cast(bytes.data()); @@ -37,7 +65,8 @@ std::shared_ptr Node::fromBytes(std::shared_ptr const& api, } } break; case MultiCodec::DAG_JSON: { - auto json = api->ParseJson(bytes); + auto p = reinterpret_cast(bytes.data()); + auto json = api->ParseJson({p, bytes.size()}); if (json) { result = std::make_shared(std::move(json)); } else { @@ -47,7 +76,7 @@ std::shared_ptr Node::fromBytes(std::shared_ptr const& api, } break; case MultiCodec::RAW: case MultiCodec::DAG_PB: { - ipfs::Block b{cid, bytes}; + ipfs::PbDag b{cid, bytes}; if (b.valid()) { result = fromBlock(b); } else { @@ -74,33 +103,33 @@ std::shared_ptr Node::fromBytes(std::shared_ptr const& api, } return result; } -std::shared_ptr Node::fromBlock(ipfs::Block const& block) { +std::shared_ptr Node::fromBlock(ipfs::PbDag const& block) { std::shared_ptr result; switch (block.type()) { - case Block::Type::FileChunk: + case PbDag::Type::FileChunk: return std::make_shared(block.chunk_data()); - case Block::Type::NonFs: + case PbDag::Type::NonFs: return std::make_shared(block.unparsed()); - case Block::Type::Symlink: + case PbDag::Type::Symlink: return std::make_shared(block.chunk_data()); - case Block::Type::Directory: + case PbDag::Type::Directory: result = std::make_shared(); break; - case Block::Type::File: - case Block::Type::Raw: + case PbDag::Type::File: + case PbDag::Type::Raw: result = std::make_shared(); break; - case Block::Type::HAMTShard: + case PbDag::Type::HAMTShard: if (block.fsdata().has_fanout()) { result = std::make_shared(block.fsdata().fanout()); } else { result = std::make_shared(); } break; - case Block::Type::Metadata: + case PbDag::Type::Metadata: LOG(ERROR) << "Metadata blocks unhandled."; return result; - case Block::Type::Invalid: + case PbDag::Type::Invalid: LOG(ERROR) << "Invalid block."; return result; default: @@ -130,6 +159,89 @@ auto Node::as_hamt() -> DirShard* { void Node::set_api(std::shared_ptr api) { api_ = api; } +auto Node::resolve(SlashDelimited initial_path, BlockLookup blu) + -> ResolveResult { + ResolutionState state; + state.resolved_path_components = ""; + state.unresolved_path = initial_path; + state.get_available_block = blu; + return resolve(state); +} +auto Node::CallChild(ipfs::ipld::ResolutionState& state) -> ResolveResult { + return CallChild(state, state.NextComponent(api_.get())); +} +auto Node::CallChild(ipfs::ipld::ResolutionState& state, + std::string_view link_key, + std::string_view block_key) -> ResolveResult { + auto child = FindChild(link_key); + if (!child) { + links_.emplace_back(link_key, Link{std::string{block_key}, {}}); + } + return CallChild(state, link_key); +} +auto Node::CallChild(ResolutionState& state, std::string_view link_key) + -> ResolveResult { + auto* child = FindChild(link_key); + if (!child) { + return ProvenAbsent{}; + } + auto& node = child->node; + if (!node) { + node = state.GetBlock(child->cid); + } + if (node) { + Descend(state); + return node->resolve(state); + } else { + std::string needed{"/ipfs/"}; + needed.append(child->cid); + auto more = state.unresolved_path.to_view(); + if (more.size()) { + if (more.front() != '/') { + needed.push_back('/'); + } + needed.append(more); + } + return MoreDataNeeded{needed}; + } +} +auto Node::CallChild(ResolutionState& state, + std::function gen_child) + -> ResolveResult { + auto link_key = state.NextComponent(api_.get()); + auto child = FindChild(link_key); + if (!child) { + links_.emplace_back(link_key, Link{{}, {}}); + child = &links_.back().second; + } + auto& node = child->node; + if (!node) { + node = gen_child(link_key); + if (!node) { + return ProvenAbsent{}; + } + } + Descend(state); + return node->resolve(state); +} +auto Node::FindChild(std::string_view link_key) -> Link* { + for (auto& [name, link] : links_) { + if (name == link_key) { + return &link; + } + } + return nullptr; +} +void Node::Descend(ResolutionState& state) { + auto next = state.unresolved_path.pop(); + if (next.empty()) { + return; + } + if (!state.resolved_path_components.ends_with('/')) { + state.resolved_path_components.push_back('/'); + } + state.resolved_path_components.append(next); +} std::ostream& operator<<(std::ostream& s, ipfs::ipld::PathChange const& c) { return s << "PathChange{" << c.new_path << '}'; diff --git a/library/src/ipfs_client/ipld/directory_shard.cc b/library/src/ipfs_client/ipld/directory_shard.cc index 526c091c..7839e62b 100644 --- a/library/src/ipfs_client/ipld/directory_shard.cc +++ b/library/src/ipfs_client/ipld/directory_shard.cc @@ -15,46 +15,44 @@ using namespace std::literals; using Self = ipfs::ipld::DirShard; -auto Self::resolve(ipfs::SlashDelimited relpath, - ipfs::ipld::DagNode::BlockLookup blu, - std::string& to_here) -> ResolveResult { - if (!relpath) { - // TODO check if index.html is present and if not implement indexing - auto result = resolve("index.html"sv, blu, to_here); +auto Self::resolve(ResolutionState& parms) -> ResolveResult { + if (parms.IsFinalComponent()) { + auto index_parm = parms.WithPath("index.html"sv); + auto result = resolve(index_parm); + // TODO generate index.html if not present auto resp = std::get_if(&result); if (resp) { resp->mime_ = "text/html"; } return result; } - auto name = api_->UnescapeUrlComponent(relpath.pop()); + std::string name{parms.NextComponent(api_.get())}; auto hash = hexhash(name); - return resolve_internal(hash.begin(), hash.end(), name, relpath, blu, - to_here); + return resolve_internal(hash.begin(), hash.end(), name, parms); } auto Self::resolve_internal(ipfs::ipld::DirShard::HashIter hash_b, ipfs::ipld::DirShard::HashIter hash_e, - std::string_view element_name, - ipfs::SlashDelimited path_after_dir, - ipfs::ipld::DagNode::BlockLookup blu, - std::string& path_to_dir) -> ResolveResult { + std::string_view human_name, + ResolutionState& parms) -> ResolveResult { auto hash_chunk = hash_b == hash_e ? std::string{} : *hash_b; for (auto& [name, link] : links_) { if (!starts_with(name, hash_chunk)) { continue; } - if (!link.node) { - link.node = blu(link.cid); - } - if (!link.node) { - return MoreDataNeeded{std::vector{"/ipfs/" + link.cid}}; - } - if (ends_with(name, element_name)) { - VLOG(2) << "Found " << element_name << ", leaving HAMT sharded directory " + if (ends_with(name, human_name)) { + VLOG(2) << "Found " << human_name << ", leaving HAMT sharded directory " << name << "->" << link.cid; - return link.node->resolve(path_after_dir, blu, path_to_dir); + return CallChild(parms, name); + } + auto node = parms.GetBlock(link.cid); + if (!node) { + // Unfortunately we can't really append more path and do a full Car + // request + // The gateway would hash whatever we gave it and compare it to a + // partially-consumed hash + return MoreDataNeeded{{"/ipfs/" + link.cid}}; } - auto downcast = link.node->as_hamt(); + auto downcast = node->as_hamt(); if (downcast) { if (hash_b == hash_e) { LOG(ERROR) << "Ran out of hash bits."; @@ -63,8 +61,8 @@ auto Self::resolve_internal(ipfs::ipld::DirShard::HashIter hash_b, VLOG(2) << "Found hash chunk, continuing to next level of HAMT sharded " "directory " << name << "->" << link.cid; - return downcast->resolve_internal(std::next(hash_b), hash_e, element_name, - path_after_dir, blu, path_to_dir); + return downcast->resolve_internal(std::next(hash_b), hash_e, human_name, + parms); } else { return ProvenAbsent{}; } diff --git a/library/src/ipfs_client/ipld/directory_shard.h b/library/src/ipfs_client/ipld/directory_shard.h index 0a4a6cca..c1cb8113 100644 --- a/library/src/ipfs_client/ipld/directory_shard.h +++ b/library/src/ipfs_client/ipld/directory_shard.h @@ -7,7 +7,7 @@ namespace ipfs::ipld { class DirShard : public DagNode { std::uint64_t const fanout_; - ResolveResult resolve(SlashDelimited, BlockLookup, std::string&) override; + ResolveResult resolve(ResolutionState&) override; DirShard* as_hamt() override; std::vector hexhash(std::string_view path_element) const; @@ -15,9 +15,7 @@ class DirShard : public DagNode { ResolveResult resolve_internal(HashIter, HashIter, std::string_view, - SlashDelimited, - BlockLookup, - std::string&); + ResolutionState&); public: explicit DirShard(std::uint64_t fanout = 256UL); diff --git a/library/src/ipfs_client/ipld/ipns_name.cc b/library/src/ipfs_client/ipld/ipns_name.cc index fb645d49..f3820092 100644 --- a/library/src/ipfs_client/ipld/ipns_name.cc +++ b/library/src/ipfs_client/ipld/ipns_name.cc @@ -7,17 +7,19 @@ using Self = ipfs::ipld::IpnsName; Self::IpnsName(std::string_view target_abs_path) : target_path_{target_abs_path} {} -auto Self::resolve(ipfs::SlashDelimited path, - ipfs::ipld::DagNode::BlockLookup blu, - std::string& up_to_here) -> ResolveResult { - if (!target_) { - SlashDelimited t{target_path_}; - t.pop(); // Discard namespace, though realistically it's going to be ipfs - // basically all the time - target_ = blu(std::string{t.pop()}); +auto Self::resolve(ResolutionState& params) -> ResolveResult { + // Can't use PathChange, as the target is truly absolute (rootless) + SlashDelimited t{target_path_}; + t.pop(); // Discard namespace, though realistically it's going to be ipfs + // basically all the time + auto name = t.pop(); + if (t) { + LOG(WARNING) << "Odd case: name points at /ns/root/MORE/PATH (" + << target_path_ << "): " << params.MyPath(); + auto path = t.to_string() + "/" + params.PathToResolve().to_string(); + auto altered = params.WithPath(path); + return CallChild(altered, "", name); + } else { + return CallChild(params, "", name); } - if (target_) { - return target_->resolve(path, blu, up_to_here); - } - return MoreDataNeeded{std::vector{target_path_}}; -} \ No newline at end of file +} diff --git a/library/src/ipfs_client/ipld/ipns_name.h b/library/src/ipfs_client/ipld/ipns_name.h index de53f45f..8b50d6e8 100644 --- a/library/src/ipfs_client/ipld/ipns_name.h +++ b/library/src/ipfs_client/ipld/ipns_name.h @@ -6,11 +6,8 @@ namespace ipfs::ipld { class IpnsName : public DagNode { std::string const target_path_; - NodePtr target_; - ResolveResult resolve(SlashDelimited path, - BlockLookup, - std::string& up_to_here) override; + ResolveResult resolve(ResolutionState& params) override; public: IpnsName(std::string_view target_abs_path); diff --git a/library/src/ipfs_client/ipld/resolution_state.cc b/library/src/ipfs_client/ipld/resolution_state.cc new file mode 100644 index 00000000..7b51513d --- /dev/null +++ b/library/src/ipfs_client/ipld/resolution_state.cc @@ -0,0 +1,36 @@ +#include + +#include + +using Self = ipfs::ipld::ResolutionState; + +bool Self::IsFinalComponent() const { + return !unresolved_path; +} +auto Self::PathToResolve() const -> SlashDelimited { + return unresolved_path; +} +auto Self::MyPath() const -> SlashDelimited { + return SlashDelimited{resolved_path_components}; +} +std::string Self::NextComponent(ContextApi const* api) const { + auto copy = unresolved_path; + if (api) { + return api->UnescapeUrlComponent(copy.pop()); + } else { + return std::string{copy.pop()}; + } +} +auto Self::GetBlock(std::string const& block_key) const -> NodePtr { + return get_available_block(block_key); +} +Self Self::WithPath(std::string_view p) const { + auto rv = *this; + rv.unresolved_path = SlashDelimited{p}; + return rv; +} +auto Self::RestartResolvedPath() const -> ResolutionState { + auto rv = *this; + rv.resolved_path_components.clear(); + return rv; +} \ No newline at end of file diff --git a/library/src/ipfs_client/ipld/root.cc b/library/src/ipfs_client/ipld/root.cc index bc69fde5..fd5af1b2 100644 --- a/library/src/ipfs_client/ipld/root.cc +++ b/library/src/ipfs_client/ipld/root.cc @@ -19,16 +19,20 @@ Ptr Self::rooted() { return shared_from_this(); } -auto Self::resolve(SlashDelimited path, BlockLookup blu, std::string& to_here) - -> ResolveResult { - auto result = deroot()->resolve(path, blu, to_here); - if (std::get_if(&result)) { - auto missing_path = path.to_string(); - if (path.pop() == "_redirects") { +auto Self::resolve(ResolutionState& params) -> ResolveResult { + auto location = params.PathToResolve().to_string(); + auto result = deroot()->resolve(params); + if (auto pc = std::get_if(&result)) { + auto lower = params.WithPath(pc->new_path); + result = resolve(lower); + location.assign(lower.MyPath().to_view()); + } else if (std::get_if(&result)) { + if (params.NextComponent(api_.get()) == "_redirects") { return result; } if (!redirects_.has_value()) { - result = deroot()->resolve("_redirects"sv, blu, to_here); + auto redirects_path = params.WithPath("_redirects"); + result = resolve(redirects_path); auto redirect_resp = std::get_if(&result); if (redirect_resp && redirect_resp->status_ == 200) { redirects_ = redirects::File(redirect_resp->body_); @@ -41,42 +45,46 @@ auto Self::resolve(SlashDelimited path, BlockLookup blu, std::string& to_here) } if (redirects_.has_value() && redirects_.value().valid()) { Response* resp = nullptr; - auto status = redirects_.value().rewrite(missing_path); - if (missing_path.find("://") < missing_path.size()) { + auto status = redirects_.value().rewrite(location); + if (location.find("://") < location.size()) { LOG(INFO) << "_redirects file sent us to a whole URL, scheme-and-all: " - << missing_path << " status=" << status; - return Response{"", status, "", missing_path}; + << location << " status=" << status; + return Response{"", status, "", location}; } + auto lower_parm = params.WithPath(location).RestartResolvedPath(); switch (status / 100) { case 0: // no rewrites available - return result; + break; case 2: - return resolve(std::string_view{missing_path}, blu, to_here); + result = deroot()->resolve(lower_parm); + location.assign(lower_parm.MyPath().to_view()); + break; case 3: // Let the redirect happen - return Response{"", status, "", missing_path}; - case 4: - result = - deroot()->resolve(std::string_view{missing_path}, blu, to_here); + return Response{"", status, "", location}; + case 4: { + result = deroot()->resolve(lower_parm); + location.assign(lower_parm.MyPath().to_view()); if (std::get_if(&result)) { - return Response{"", 500, "", missing_path}; + return Response{"", 500, "", location}; } resp = std::get_if(&result); if (resp) { resp->status_ = status; return *resp; } - return result; // MoreDataNeeded to fetch e.g. custom 404 page + break; // MoreDataNeeded to fetch e.g. custom 404 page + } default: LOG(ERROR) << "Unsupported status came back from _redirects file: " << status; + return ProvenAbsent{}; } } - return ProvenAbsent{}; } auto resp = std::get_if(&result); if (resp && resp->location_.empty()) { - resp->location_ = path.to_string(); + resp->location_ = location; } return result; } diff --git a/library/src/ipfs_client/ipld/root.h b/library/src/ipfs_client/ipld/root.h index 458ab4d3..b57951b4 100644 --- a/library/src/ipfs_client/ipld/root.h +++ b/library/src/ipfs_client/ipld/root.h @@ -10,9 +10,7 @@ namespace ipfs::ipld { class Root : public DagNode { std::optional redirects_; - ResolveResult resolve(SlashDelimited path, - BlockLookup, - std::string&) override; + ResolveResult resolve(ResolutionState& params) override; std::shared_ptr rooted() override; std::shared_ptr deroot() override; diff --git a/library/src/ipfs_client/ipld/small_directory.cc b/library/src/ipfs_client/ipld/small_directory.cc index e721f518..b8613663 100644 --- a/library/src/ipfs_client/ipld/small_directory.cc +++ b/library/src/ipfs_client/ipld/small_directory.cc @@ -12,73 +12,24 @@ using namespace std::literals; using Self = ipfs::ipld::SmallDirectory; -namespace { -ipfs::ipld::NodePtr& node(ipfs::ipld::Link& l, - ipfs::ipld::DagNode::BlockLookup f) { - if (!l.node) { - l.node = f(l.cid); - } - return l.node; -} -} // namespace - -auto Self::resolve(SlashDelimited path, BlockLookup blu, std::string& to_here) - -> ResolveResult { - if (!path) { - LOG(INFO) << "Directory listing requested."; - SlashDelimited dir_path{to_here}; - dir_path.pop_n(2); - GeneratedDirectoryListing index_html{dir_path.to_string()}; +auto Self::resolve(ResolutionState& params) -> ResolveResult { + if (params.IsFinalComponent()) { + LOG(INFO) << "Directory listing requested for " << params.MyPath(); + auto result = CallChild(params, "index.html"); + if (auto resp = std::get_if(&result)) { + resp->mime_ = "text/html"; + } + if (!std::get_if(&result)) { + return result; + } + auto dir_path = params.MyPath().to_view(); + GeneratedDirectoryListing index_html{dir_path}; for (auto& [name, link] : links_) { - VLOG(2) << "Listing " << dir_path.to_string() << " encountered " << name - << '=' << link.cid; - if (name == "index.html") { - auto& n = node(link, blu); - if (n) { - auto result = n->resolve(""sv, blu, to_here.append("/index.html")); - auto resp = std::get_if(&result); - if (resp) { - resp->mime_ = "text/html"; - } - return result; - } else { - return MoreDataNeeded{std::vector{"/ipfs/" + link.cid}}; - } - } else { - index_html.AddEntry(name); - } + index_html.AddEntry(name); } return Response{"text/html", 200, index_html.Finish(), ""}; } - auto name = api_->UnescapeUrlComponent(path.pop()); - VLOG(2) << "Looking for '" << name << "' in directory " << to_here; - // TODO binary search - auto match = [&name](auto& l) { return l.first == name; }; - auto it = std::find_if(links_.begin(), links_.end(), match); - if (links_.end() == it) { - VLOG(1) << name << " does not exist in directory " << to_here - << ", these do: " - << std::accumulate(links_.begin(), links_.end(), std::string{}, - [](auto a, auto& b) { - auto& n = b.first; - return a.empty() ? n : a + ";" + n; - }); - return ProvenAbsent{}; - } - auto& link = it->second; - auto& nod = node(link, blu); - if (nod) { - VLOG(2) << to_here << " descending into " << link.cid << " for " << name; - if (to_here.back() != '/') { - to_here.push_back('/'); - } - to_here.append(name); - return nod->resolve(path, blu, to_here); - } else { - VLOG(1) << "Should descending into " << link.cid << " for " << name - << " but can't because it's missing. Will request."; - return MoreDataNeeded{std::vector{"/ipfs/" + link.cid}}; - } + return CallChild(params); } Self::~SmallDirectory() {} diff --git a/library/src/ipfs_client/ipld/small_directory.h b/library/src/ipfs_client/ipld/small_directory.h index b78729f8..a076122c 100644 --- a/library/src/ipfs_client/ipld/small_directory.h +++ b/library/src/ipfs_client/ipld/small_directory.h @@ -7,7 +7,7 @@ namespace ipfs::ipld { class SmallDirectory : public DagNode { - ResolveResult resolve(SlashDelimited, BlockLookup, std::string&) override; + ResolveResult resolve(ResolutionState&) override; public: virtual ~SmallDirectory() noexcept; diff --git a/library/src/ipfs_client/ipld/symlink.cc b/library/src/ipfs_client/ipld/symlink.cc index 8740ed70..b35725ad 100644 --- a/library/src/ipfs_client/ipld/symlink.cc +++ b/library/src/ipfs_client/ipld/symlink.cc @@ -8,33 +8,27 @@ Self::Symlink(std::string target) : target_{target} {} Self::~Symlink() {} -auto Self::resolve(SlashDelimited path, BlockLookup, std::string& to_here) - -> ResolveResult { +auto Self::resolve(ResolutionState& params) -> ResolveResult { std::string result; - if (is_absolute()) { - result.assign(SlashDelimited{to_here}.pop_n(2)).append("/").append(target_); - LOG(INFO) << "Absolute (relative-to-dag-root) symlink '" << target_ - << "' leads to '" << result << "' ... "; - } else { - auto c = to_here.find_last_not_of('/'); - c = to_here.find_last_of('/', c); - DCHECK(c != to_here.size()) << to_here; - result.assign(to_here, 0, c + 1).append(target_); - LOG(INFO) << "Relative symlink '" << target_ << "' leads to '" << result - << "' ... "; + if (!is_absolute()) { + auto left_path = params.MyPath(); + left_path.pop_n(2); // Returning a path relative to content root. + left_path.pop_back(); // Because the final component refers to this + // symlink, which is getting replaced with target + result.assign(left_path.to_view()); } - if (path) { - result.append("/").append(path.pop_all()); + result.append("/").append(target_); + if (!params.IsFinalComponent()) { + result.append("/").append(params.PathToResolve().to_string()); } std::size_t i; while ((i = result.find("//")) != std::string::npos) { result.erase(i, 1); } - DCHECK_GT(result.size(), 0U); - if (result.back() == '/') { + if (result.ends_with('/')) { result.resize(result.size() - 1); } - LOG(INFO) << "symlink: '" << to_here << "' -> '" << result << "'."; + LOG(INFO) << "symlink: '" << params.MyPath() << "' -> '" << result << "'."; return PathChange{result}; } diff --git a/library/src/ipfs_client/ipld/symlink.h b/library/src/ipfs_client/ipld/symlink.h index 0ef7b23d..937f0d24 100644 --- a/library/src/ipfs_client/ipld/symlink.h +++ b/library/src/ipfs_client/ipld/symlink.h @@ -7,9 +7,7 @@ namespace ipfs::ipld { class Symlink : public DagNode { std::string const target_; - ResolveResult resolve(SlashDelimited path, - BlockLookup, - std::string& up_to_here) override; + ResolveResult resolve(ResolutionState& params) override; bool is_absolute() const; diff --git a/library/src/ipfs_client/ipld/symlink_unittest.cc b/library/src/ipfs_client/ipld/symlink_unittest.cc index 5413ebf6..f1451682 100644 --- a/library/src/ipfs_client/ipld/symlink_unittest.cc +++ b/library/src/ipfs_client/ipld/symlink_unittest.cc @@ -1,9 +1,11 @@ #include "symlink.h" -#include +#include "small_directory.h" + +#include -#include #include +#include using namespace std::literals; namespace i = ipfs; @@ -13,34 +15,34 @@ TEST(SymlinkTest, fromBlock) { i::Cid cid("bafybeia4wauf6z6lnnnszia6upqr5jsq7nack5nnrubf333lfg2vlabtd4"); EXPECT_TRUE(cid.valid()); // The target is the last byte, \x61 aka 'a' - i::Block b{cid, "\x0a\x05\x08\x04\x12\x01\x61"}; - EXPECT_TRUE(b.type() == i::Block::Type::Symlink); + i::PbDag b{cid, "\x0a\x05\x08\x04\x12\x01\x61"}; + EXPECT_TRUE(b.type() == i::PbDag::Type::Symlink); auto node = ii::DagNode::fromBlock(b); EXPECT_TRUE(node); - std::string t = - "/ipfs/bafybeia4wauf6z6lnnnszia6upqr5jsq7nack5nnrubf333lfg2vlabtd4/c"; auto blu = [](std::string const&) { return ii::NodePtr{}; }; - auto result = node->resolve("d/e"sv, blu, t); + auto result = node->resolve(i::SlashDelimited{"d/e"}, blu); auto actual = std::get(result); - auto expect = - "/ipfs/bafybeia4wauf6z6lnnnszia6upqr5jsq7nack5nnrubf333lfg2vlabtd4/" - "a/d/e"; + auto expect = "/a/d/e"; EXPECT_EQ(actual.new_path, expect); } TEST(SymlinkTest, rooted) { - ii::Symlink sub{"/another/path.txt"}; - ii::DagNode& t = sub; - auto blu = [](std::string const&) -> ii::NodePtr { - throw std::runtime_error{"Block lookup not expected."}; + auto target = "/b"; + auto sub = std::make_shared(target); + // This dir actually contains an inlined symlink which points to /b/c, but + // it's the Symlink ctor arg that counts + std::string dirbytes = + "\x12\x15\x0a\x0e\x01\x70\x00\x0a\x0a\x08\x08\x04\x12\x04\x2f\x62\x2f\x63" + "\x12\x01\x61\x18\x0a\x0a\x02\x08\x01"; + auto api = std::make_shared(); + auto dir = ii::DagNode::fromBytes( + api, i::Cid("bafyaagiscmfayalqaaeaubqiaqjael3cciawcgaibibaqai"), + dirbytes); + ii::DagNode& t = *sub; + auto blu = [sub](std::string const& block_key) -> ii::NodePtr { + EXPECT_EQ("bafyaacakayeaieqcf5ra", block_key); + return sub; }; - std::string observed_path_to_link{"/ipns/"}; - observed_path_to_link - .append("k51qzi5uqu5dkq4jxcqvujfm2woh4p9y6inrojofxflzdnfht168zf8ynfzuu1") - .append("/symlinks/rooted.txt"); - auto res = t.resolve(""sv, blu, observed_path_to_link); + auto res = t.resolve(i::SlashDelimited{}, blu); EXPECT_TRUE(std::holds_alternative(res)); - EXPECT_EQ( - std::get(res).new_path, - "/ipns/k51qzi5uqu5dkq4jxcqvujfm2woh4p9y6inrojofxflzdnfht168zf8ynfzuu1/" - "another/path.txt"); + EXPECT_EQ(std::get(res).new_path, target); } diff --git a/library/src/ipfs_client/ipld/unixfs_file.cc b/library/src/ipfs_client/ipld/unixfs_file.cc index c8dc8d76..784a1df3 100644 --- a/library/src/ipfs_client/ipld/unixfs_file.cc +++ b/library/src/ipfs_client/ipld/unixfs_file.cc @@ -6,12 +6,10 @@ using namespace std::literals; using Self = ipfs::ipld::UnixfsFile; -auto Self::resolve(ipfs::SlashDelimited path, - ipfs::ipld::DagNode::BlockLookup blu, - std::string& to_here) -> ResolveResult { - if (path) { - LOG(ERROR) << "Can't path through a file, (at " << to_here - << ") but given the path " << path.to_string(); +auto Self::resolve(ResolutionState& params) -> ResolveResult { + if (!params.IsFinalComponent()) { + LOG(ERROR) << "Can't path through a file, (at " << params.MyPath() + << ") but given the path " << params.PathToResolve(); return ProvenAbsent{}; } std::vector missing; @@ -19,10 +17,10 @@ auto Self::resolve(ipfs::SlashDelimited path, for (auto& child : links_) { auto& link = child.second; if (!link.node) { - link.node = blu(link.cid); + link.node = params.GetBlock(link.cid); } if (link.node) { - auto recurse = link.node->resolve(""sv, blu, to_here); + auto recurse = link.node->resolve(params); auto mdn = std::get_if(&recurse); if (mdn) { missing.insert(missing.end(), mdn->ipfs_abs_paths_.begin(), @@ -33,8 +31,6 @@ auto Self::resolve(ipfs::SlashDelimited path, body.append(std::get(recurse).body_); } } else { - VLOG(2) << "In order to resolve the file at path " << to_here - << " I need CID " << link.cid; missing.push_back("/ipfs/" + link.cid); } } @@ -43,10 +39,12 @@ auto Self::resolve(ipfs::SlashDelimited path, "", 200, body, - ""s, + params.MyPath().to_string(), }; } - return MoreDataNeeded{missing}; + auto result = MoreDataNeeded{missing}; + result.insist_on_car = true; + return result; } Self::~UnixfsFile() {} diff --git a/library/src/ipfs_client/ipld/unixfs_file.h b/library/src/ipfs_client/ipld/unixfs_file.h index bedd5c1d..3447e949 100644 --- a/library/src/ipfs_client/ipld/unixfs_file.h +++ b/library/src/ipfs_client/ipld/unixfs_file.h @@ -5,7 +5,7 @@ namespace ipfs::ipld { class UnixfsFile : public DagNode { - ResolveResult resolve(SlashDelimited, BlockLookup, std::string&) override; + ResolveResult resolve(ResolutionState&) override; public: virtual ~UnixfsFile() noexcept; diff --git a/library/src/ipfs_client/ipns_record.cc b/library/src/ipfs_client/ipns_record.cc index cf2eecdd..86be780f 100644 --- a/library/src/ipfs_client/ipns_record.cc +++ b/library/src/ipfs_client/ipns_record.cc @@ -4,12 +4,10 @@ #include #include -#include -#include - #include "log_macros.h" -#include +#include +#include #if __has_include() #include @@ -25,15 +23,6 @@ bool matches(ipfs::MultiHash const& hash, if (!result.has_value()) { return false; } - /* std::vector result(hasher->digestSize(), ipfs::Byte{}); - if (hasher->write(pubkey_bytes).value()) { - if (!hasher->digestOut({result.data(), result.size()}).has_value()) { - LOG(ERROR) << "Error getting digest."; - } - } else { - LOG(ERROR) << "Attempt to hash bytes returned false"; - } - */ return std::equal(result->begin(), result->end(), hash.digest().begin(), hash.digest().end()); } @@ -171,8 +160,8 @@ auto ipfs::ValidateIpnsRecord(ipfs::ByteView top_level_bytes, bytes_str.size()}; ByteView key_bytes{reinterpret_cast(pk.data().data()), pk.data().size()}; - if (!api.verify_key_signature(static_cast(pk.type()), - signature, bytes, key_bytes)) { + if (!api.VerifyKeySignature(static_cast(pk.type()), signature, + bytes, key_bytes)) { LOG(ERROR) << "Verification failed!!"; return {}; } diff --git a/library/src/ipfs_client/ipns_record_unittest.cc b/library/src/ipfs_client/ipns_record_unittest.cc index e626c704..73bcf919 100644 --- a/library/src/ipfs_client/ipns_record_unittest.cc +++ b/library/src/ipfs_client/ipns_record_unittest.cc @@ -27,8 +27,8 @@ struct Api final : public i::ContextApi { std::string const& url) const { throw 1; } - bool verify_key_signature(SigningKeyType, - ByteView signature, + bool VerifyKeySignature(SigningKeyType, + ByteView signature, ByteView data, ByteView key_bytes) const { return true; diff --git a/library/src/ipfs_client/multi_hash.cc b/library/src/ipfs_client/multi_hash.cc index 4f9813b9..20cf5b19 100644 --- a/library/src/ipfs_client/multi_hash.cc +++ b/library/src/ipfs_client/multi_hash.cc @@ -9,27 +9,28 @@ Self::MultiHash(ipfs::HashType t, ipfs::ByteView digest) : type_{t}, hash_(digest.begin(), digest.end()) {} Self::MultiHash(ipfs::ByteView bytes) { + ReadPrefix(bytes); +} +bool Self::ReadPrefix(ipfs::ByteView& bytes) { auto i = VarInt::create(bytes); if (!i) { - return; + return false; } bytes = bytes.subspan(i->size()); auto type = Validate(static_cast(i->toUInt64())); - i = VarInt::create(bytes); if (!i) { - return; + return false; } auto length = i->toUInt64(); - if (!length) { - return; - } - auto hash = bytes.subspan(i->size()); - - if (hash.size() == length) { - hash_.assign(hash.begin(), hash.end()); - type_ = type; + if (length > bytes.size()) { + return false; } + bytes = bytes.subspan(i->size()); + hash_.assign(bytes.begin(), std::next(bytes.begin(), length)); + bytes = bytes.subspan(length); + type_ = type; + return true; } bool Self::valid() const { return type_ != HashType::INVALID && hash_.size() > 0UL; diff --git a/library/src/ipfs_client/orchestrator.cc b/library/src/ipfs_client/orchestrator.cc index a28c8e50..018fc810 100644 --- a/library/src/ipfs_client/orchestrator.cc +++ b/library/src/ipfs_client/orchestrator.cc @@ -34,7 +34,11 @@ void Self::build_response(std::shared_ptr req) { } else { VLOG(2) << "Requesting root " << affinity << " resolve path " << req_path.to_string(); - from_tree(req, it->second, req_path, affinity); + auto root = it->second->rooted(); + if (root != it->second) { + it->second = root; + } + from_tree(req, root, req_path, affinity); } } void Self::from_tree(std::shared_ptr req, @@ -47,7 +51,7 @@ void Self::from_tree(std::shared_ptr req, return i == dags_.end() ? ipld::NodePtr{} : i->second; }; auto start = std::string{req->path().pop_n(2)}; - auto result = root->resolve(relative_path, block_look_up, start); + auto result = root->resolve(relative_path, block_look_up); auto response = std::get_if(&result); if (response) { VLOG(1) << "Tree gave us a response: status=" << response->status_ @@ -56,13 +60,22 @@ void Self::from_tree(std::shared_ptr req, << response->body_.size() << " bytes."; if (response->mime_.empty() && !response->body_.empty()) { if (response->location_.empty()) { + LOG(INFO) << "Request for " << req->path() + << " returned no location, so sniffing from request path and " + "body of " + << response->body_.size() << "B."; response->mime_ = sniff(req->path(), response->body_); } else { std::string hit_path{req->path().pop_n(2)}; - if (hit_path.back() != '/' && response->location_.front() != '/') { + if (!hit_path.ends_with('/') && + !(response->location_.starts_with('/'))) { hit_path.push_back('/'); } hit_path.append(response->location_); + LOG(INFO) << "Request for " << req->path() << " returned a location of " + << response->location_ << " and a body of " + << response->body_.size() << " bytes, sniffing mime from " + << hit_path; response->mime_ = sniff(SlashDelimited{hit_path}, response->body_); } } @@ -123,8 +136,8 @@ std::string Self::sniff(ipfs::SlashDelimited p, std::string const& body) const { ext.assign(file_name, dot + 1); } auto result = api_->MimeType(ext, body, fake_url); - VLOG(2) << "Deduced mime from (ext=" << ext << " body of " << body.size() - << " bytes, 'url'=" << fake_url << ")=" << result; + LOG(INFO) << "Deduced mime from (ext=" << ext << " body of " << body.size() + << " bytes, 'url'=" << fake_url << ")=" << result; return result; } diff --git a/library/src/ipfs_client/orchestrator_unittest.cc b/library/src/ipfs_client/orchestrator_unittest.cc index 1d0e984a..b8abb2b4 100644 --- a/library/src/ipfs_client/orchestrator_unittest.cc +++ b/library/src/ipfs_client/orchestrator_unittest.cc @@ -2,12 +2,12 @@ #include -#include #include #include #include #include #include +#include #include "ipld/ipns_name.h" @@ -23,10 +23,10 @@ using Success = i::Response; namespace { struct MockApi final : public ipfs::ContextApi { MockApi() { i::log::SetLevel(i::log::Level::OFF); } - bool verify_key_signature(ipfs::SigningKeyType, - ipfs::ByteView signature, - ipfs::ByteView data, - ipfs::ByteView key_bytes) const { + bool VerifyKeySignature(SigningKeyType, + ByteView signature, + ByteView data, + ByteView key_bytes) const { return true; } std::string MimeType(std::string e, @@ -74,6 +74,7 @@ struct MockApi final : public ipfs::ContextApi { } }; struct TestRequestor final : public ig::Requestor { + TestRequestor() { api_ = std::make_shared(); } std::string_view name() const { return "return test requestor"; } HandleOutcome handle(ig::RequestPtr r) { auto cid = r->main_param; @@ -185,7 +186,7 @@ struct OrchestratingRealData : public ::testing::Test { } // namespace TEST_F(OrchestratingRealData, one_html_present) { - ipfs::log::SetLevel(ipfs::log::Level::TRACE); + ipfs::log::SetLevel(ipfs::log::Level::OFF); dorequest(abs_path("/one.html")); EXPECT_EQ(resp_.status_, 200); EXPECT_EQ(resp_.body_, "my one\n"); @@ -220,7 +221,6 @@ TEST_F(OrchestratingRealData, multinodefile_hit) { "/ipfs/bafybeif5shuqnuh2psa3syipw62scqokgbta43vv6xtfdjl6qirahmcxeq/bdir/" "cdir/multinodefile.txt"); EXPECT_EQ(resp_.status_, 200); - EXPECT_EQ(resp_.status_, 200); auto i = 0ul; for (auto a = 'A'; a <= 'Z'; ++a) { for (auto b = 'a'; a <= 'z'; ++a) { @@ -253,10 +253,11 @@ TEST_F(OrchestratingRealData, multinodefile_pbdagleaves) { } } TEST_F(OrchestratingRealData, examples_has_index_html) { + i::log::SetLevel(i::log::Level::INFO); dorequest("/ipfs/QmQyqMY5vUBSbSxyitJqthgwZunCQjDVtNd8ggVCxzuPQ4/examples"); EXPECT_EQ(resp_.status_, 200); - EXPECT_EQ(resp_.mime_, "text/html"); EXPECT_EQ(resp_.body_, "my index\n"); + EXPECT_EQ(resp_.mime_, "text/html"); } TEST_F(OrchestratingRealData, examples_articles_generates_list) { dorequest( diff --git a/library/src/ipfs_client/dag_block.cc b/library/src/ipfs_client/pb_dag.cc similarity index 75% rename from library/src/ipfs_client/dag_block.cc rename to library/src/ipfs_client/pb_dag.cc index 59ba0430..6f72bcf2 100644 --- a/library/src/ipfs_client/dag_block.cc +++ b/library/src/ipfs_client/pb_dag.cc @@ -1,4 +1,4 @@ -#include "ipfs_client/dag_block.h" +#include "ipfs_client/pb_dag.h" #include @@ -57,17 +57,19 @@ std::pair InitBlock(ipfs::MultiCodec c, } } // namespace -ipfs::Block::Block(Cid const& c, std::istream& s) : cid_(c) { +ipfs::PbDag::PbDag(Cid const& c, std::istream& s) : cid_(c) { std::tie(valid_, fs_node_) = InitBlock(c.codec(), s, node_, fsdata_); } -ipfs::Block::Block(Cid const& c, std::string_view s) - : cid_(c), original_bytes_(s) { +ipfs::PbDag::PbDag(Cid const& c, ByteView s) + : cid_(c), + original_bytes_(reinterpret_cast(s.data()), s.size()) { std::tie(valid_, fs_node_) = InitBlock(c.codec(), original_bytes_, node_, fsdata_); } +ipfs::PbDag::PbDag(Cid const& c, std::string_view s) : PbDag(c, as_bytes(s)) {} -ipfs::Block::Block(Block const& rhs) +ipfs::PbDag::PbDag(PbDag const& rhs) : node_(rhs.node_), fsdata_(rhs.fsdata_), valid_(rhs.valid_), @@ -76,15 +78,15 @@ ipfs::Block::Block(Block const& rhs) cid_(rhs.cid_), original_bytes_(rhs.original_bytes_) {} -ipfs::Block::Block() = default; +ipfs::PbDag::PbDag() = default; -ipfs::Block::~Block() noexcept {} +ipfs::PbDag::~PbDag() noexcept {} -bool ipfs::Block::valid() const { +bool ipfs::PbDag::valid() const { return valid_; } -auto ipfs::Block::type() const -> Type { +auto ipfs::PbDag::type() const -> Type { if (!valid()) { return Type::Invalid; } @@ -104,24 +106,24 @@ auto ipfs::Block::type() const -> Type { return Type::Invalid; } -bool ipfs::Block::is_file() const { +bool ipfs::PbDag::is_file() const { return valid() && fs_node_ && fsdata_.type() == unix_fs::Data_DataType_File; } -std::string const& ipfs::Block::chunk_data() const { +std::string const& ipfs::PbDag::chunk_data() const { return fsdata_.data(); } -std::string const& ipfs::Block::unparsed() const { +std::string const& ipfs::PbDag::unparsed() const { return node_.data(); } -auto ipfs::Block::cid() const -> Cid const& { +auto ipfs::PbDag::cid() const -> Cid const& { DCHECK(cid_.has_value()); return cid_.value(); } -std::string ipfs::Block::LinkCid(ipfs::ByteView binary_link_hash) const { +std::string ipfs::PbDag::LinkCid(ipfs::ByteView binary_link_hash) const { Cid result(binary_link_hash); if (!result.valid()) { LOG(FATAL) << "Failed to decode link CID as binary ( link from " @@ -135,7 +137,7 @@ std::string ipfs::Block::LinkCid(ipfs::ByteView binary_link_hash) const { return str_res; } -bool ipfs::Block::cid_matches_data(ContextApi& api) const { +bool ipfs::PbDag::cid_matches_data(ContextApi& api) const { if (!cid_) { // TODO - probably remove those constructors and make cid_ not optional return true; @@ -154,7 +156,7 @@ bool ipfs::Block::cid_matches_data(ContextApi& api) const { hashed.end()); } -std::vector ipfs::Block::binary_hash(ContextApi& api, +std::vector ipfs::PbDag::binary_hash(ContextApi& api, HashType algo) const { if (algo == HashType::INVALID) { algo = cid().hash_type(); @@ -167,25 +169,25 @@ std::vector ipfs::Block::binary_hash(ContextApi& api, } } -std::ostream& operator<<(std::ostream& s, ipfs::Block::Type t) { +std::ostream& operator<<(std::ostream& s, ipfs::PbDag::Type t) { switch (t) { - case ipfs::Block::Type::Raw: + case ipfs::PbDag::Type::Raw: return s << "Raw"; - case ipfs::Block::Type::Directory: + case ipfs::PbDag::Type::Directory: return s << "Directory"; - case ipfs::Block::Type::File: + case ipfs::PbDag::Type::File: return s << "File"; - case ipfs::Block::Type::Metadata: + case ipfs::PbDag::Type::Metadata: return s << "Metadata"; - case ipfs::Block::Type::Symlink: + case ipfs::PbDag::Type::Symlink: return s << "Symlink"; - case ipfs::Block::Type::HAMTShard: + case ipfs::PbDag::Type::HAMTShard: return s << "HAMTShard"; - case ipfs::Block::Type::FileChunk: + case ipfs::PbDag::Type::FileChunk: return s << "FileChunk"; - case ipfs::Block::Type::NonFs: + case ipfs::PbDag::Type::NonFs: return s << "NonFs"; - case ipfs::Block::Type::Invalid: + case ipfs::PbDag::Type::Invalid: return s << "Invalid"; default: return s << "Invalid value for Block::Type enum (" << static_cast(t) diff --git a/library/src/ipfs_client/dag_block_unittest.cc b/library/src/ipfs_client/pb_dag_unittest.cc similarity index 92% rename from library/src/ipfs_client/dag_block_unittest.cc rename to library/src/ipfs_client/pb_dag_unittest.cc index 177b2e50..37e7090b 100644 --- a/library/src/ipfs_client/dag_block_unittest.cc +++ b/library/src/ipfs_client/pb_dag_unittest.cc @@ -1,4 +1,4 @@ -#include +#include #include @@ -22,7 +22,7 @@ TEST(BlockTest, RealBlockValidates) { EXPECT_EQ(block_bytes.at(6), 'a'); auto cid = Cid{"bafybeigj4sef5qdwdxisatzjdoetjcfdyfqvzuhmstrj5o2ibkbix6vs5i"}; EXPECT_TRUE(cid.valid()); - ipfs::Block block{cid, block_bytes}; + ipfs::PbDag block{cid, ipfs::as_bytes(block_bytes)}; EXPECT_TRUE(block.valid()); EXPECT_TRUE(block.is_file()); MockApi api; @@ -37,7 +37,7 @@ TEST(BlockTest, IdentityBlockValidates) { EXPECT_EQ(block_bytes.size(), 10UL); EXPECT_EQ(block_bytes.at(6), 'a'); auto cid = Cid{"bafkqac2jobzxk3janrxxezln"}; - ipfs::Block block{cid, block_bytes}; + ipfs::PbDag block{cid, block_bytes}; EXPECT_TRUE(block.valid()); EXPECT_TRUE(block.is_file()); MockApi api; @@ -49,7 +49,7 @@ TEST(BlockTest, DirectoryCopiedIsStillDirectory) { EXPECT_EQ(block_bytes.size(), 4U); auto cid = Cid{"bafyaabakaieac"}; EXPECT_TRUE(cid.valid()); - ipfs::Block block{cid, block_bytes}; + ipfs::PbDag block{cid, block_bytes}; EXPECT_TRUE(block.valid()); EXPECT_FALSE(block.is_file()); MockApi api; @@ -72,7 +72,7 @@ TEST(BlockTest, AdHoc) { std::ifstream f{e.path()}; std::stringstream buffer; buffer << f.rdbuf(); - ipfs::Block block{cid, buffer.str()}; + ipfs::PbDag block{cid, buffer.str()}; MockApi api; EXPECT_TRUE(block.cid_matches_data(api)) << e.path(); L_VAR(static_cast(block.type())); @@ -89,7 +89,7 @@ TEST(BlockTest, AdHoc) { TEST(BlockTest, TypeNames) { using namespace ipfs; - using T = Block::Type; + using T = PbDag::Type; EXPECT_EQ(Stringify(T::Raw), "Raw"); EXPECT_EQ(Stringify(T::Directory), "Directory"); EXPECT_EQ(Stringify(T::File), "File"); diff --git a/library/include/ipfs_client/all_inclusive.h b/library/src/ipfs_client/test_context.cc similarity index 60% rename from library/include/ipfs_client/all_inclusive.h rename to library/src/ipfs_client/test_context.cc index 91f6a424..5b416235 100644 --- a/library/include/ipfs_client/all_inclusive.h +++ b/library/src/ipfs_client/test_context.cc @@ -1,138 +1,111 @@ -#ifndef IPFS_ALL_INCLUSIVE_CONTEXT_H_ -#define IPFS_ALL_INCLUSIVE_CONTEXT_H_ +#include -#ifdef _MSC_VER -// #warning "AllInclusiveContext has not been ported to Windows." -#else +#if HAS_ALL_INCLUSIVE -#include "gw/default_requestor.h" +#if __has_include() +#include +#endif -#include "context_api.h" -#include "dag_cbor_value.h" -#include "gateways.h" -#include "json_cbor_adapter.h" -#include "orchestrator.h" +#include -#include +#include "log_macros.h" -#include +using Self = ipfs::AllInclusiveContext; -#include - -#if ! __has_include() -#warning "One needs access to Boost to use this header" -#elif !__has_include() -#warning "One needs c-ares available to use this header." -#elif !HAS_JSON_CBOR_ADAPTER -#warning "One needs access to nlohmann/json to use this header" -#else - -#define HAS_ALL_INCLUSIVE 1 - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace google::protobuf { -constexpr LogLevel LOGLEVEL_DEBUG = static_cast(-1); -constexpr LogLevel LOGLEVEL_TRACE = static_cast(-2); -} // namespace google::protobuf - -namespace ipfs { - -class HttpSession; - -// LCOV_EXCL_START +namespace { +struct CallbackCallback { + Self* me; + std::shared_ptr alsome; + std::string host; +}; +} // namespace +extern "C" { +static void c_ares_c_callback(void* vp, + int status, + int /*timeouts*/, + unsigned char* abuf, + int alen) { + auto cbcb = reinterpret_cast(vp); + struct ares_txt_reply* txt_out = nullptr; + LOG(INFO) << "Buffer contains " << alen << " bytes."; + if (abuf && alen && !ares_parse_txt_reply(abuf, alen, &txt_out) && txt_out) { + cbcb->me->DnsResults(cbcb->host, *txt_out); + ares_free_data(txt_out); + } else { + LOG(ERROR) << "c_ares status=" << status; + } + delete cbcb; +} +} -class AllInclusiveContext final : public ContextApi { - void SendHttpRequest(HttpRequestDescription, - HttpCompleteCallback) const override; - struct DnsCbs { - DnsTextResultsCallback r; - DnsTextCompleteCallback c; - }; - std::map> pending_dns_; - void SendDnsTextRequest(std::string, - DnsTextResultsCallback, - DnsTextCompleteCallback) override; - std::string MimeType(std::string extension, - std::string_view, - std::string const&) const override { - // TODO implement real mime type detection - return "text/" + extension; +Self::AllInclusiveContext(boost::asio::io_context& io) : io_{io} { + if (ares_library_init(ARES_LIB_INIT_ALL)) { + throw std::runtime_error("Failed to initialize c-ares library."); } - std::string UnescapeUrlComponent(std::string_view url_comp) const override { - std::string rv{url_comp}; - auto xval = [](char c) { - if (c <= '9') { - return c - '0'; - } - if (c <= 'Z') { - return c - 'A'; - } - return c - 'a'; - }; - for (auto i = 0UL; i + 1UL < rv.size(); ++i) { - if (rv[i] != '%') { - continue; - } - auto a = rv[i + 1UL]; - if (rv[i + 1UL] == '%') { - rv.erase(i, 1UL); - continue; - } - if (i + 2UL >= rv.size()) { - break; - } - if (!std::isxdigit(a)) { - continue; - } - auto b = rv[i + 2UL]; - if (std::isxdigit(b)) { - rv[i] = xval(a) * 16 + xval(b); - rv.erase(i + 1UL, 2); - } + if (ares_init(&ares_channel_)) { + throw std::runtime_error("Failed to initialize c-ares channel."); + } +} +Self::~AllInclusiveContext() { + pending_dns_.clear(); + ares_destroy(ares_channel_); + ares_library_cleanup(); +} +void Self::SendDnsTextRequest(std::string host, + DnsTextResultsCallback rcb, + DnsTextCompleteCallback ccb) { + auto p = pending_dns_.emplace(host, std::vector{}); + auto it = p.first; + auto is_first = p.second; + it->second.emplace_back(DnsCbs{rcb, ccb}); + LOG(INFO) << __PRETTY_FUNCTION__ << ' ' << host << ' ' << is_first; + if (is_first) { + auto cbcb = new CallbackCallback; + cbcb->me = this; + cbcb->alsome = shared_from_this(); + cbcb->host = host; + ares_query(ares_channel_, it->first.c_str(), ns_c_in, ns_t_txt, + &c_ares_c_callback, cbcb); + io_.post([this]() { CAresProcess(); }); + } +} +void Self::DnsResults(std::string& host, ares_txt_reply& result) { + LOG(INFO) << __PRETTY_FUNCTION__ << ' ' << host; + auto i = pending_dns_.find(host); + if (pending_dns_.end() == i) { + return; + } + std::vector v{std::string{}}; + for (auto r = &result; r; r = r->next) { + auto p = reinterpret_cast(r->txt); + v[0].assign(p, r->length); + for (auto& cbs : i->second) { + cbs.r(v); } - return rv; } - std::unique_ptr ParseCbor(ByteView bytes) const override { - auto data = nlohmann::json::from_cbor( - bytes, false, true, nlohmann::detail::cbor_tag_handler_t::store); - return std::make_unique(data); + for (auto& cbs : i->second) { + cbs.c(); } - std::unique_ptr ParseJson( - std::string_view j_str) const override { - auto data = nlohmann::json::parse(j_str); - std::ostringstream oss; - oss << std::setw(2) << data; - GOOGLE_LOG(DEBUG) << "Parsed " << j_str.size() - << " bytes of JSON string and got " << oss.str(); - return std::make_unique(data); + pending_dns_.erase(i); +} +void Self::CAresProcess() { + LOG(INFO) << __PRETTY_FUNCTION__ << ' ' << pending_dns_.size(); + fd_set readers, writers; + struct timeval tv, *tvp; + FD_ZERO(&readers); + FD_ZERO(&writers); + auto nfds = ares_fds(ares_channel_, &readers, &writers); + if (nfds) { + tvp = ares_timeout(ares_channel_, NULL, &tv); + auto count = select(nfds, &readers, &writers, NULL, tvp); + ares_process(ares_channel_, &readers, &writers); + nfds += count; } - bool verify_key_signature(SigningKeyType, - ByteView, - ByteView, - ByteView) const override { - GOOGLE_LOG(ERROR) << "TODO\n"; - return true; + if (nfds || pending_dns_.size()) { + io_.post([this]() { CAresProcess(); }); } - boost::asio::io_context& io_; - boost::asio::ssl::context mutable ssl_ctx_ = - boost::asio::ssl::context{boost::asio::ssl::context::tls_client}; - // boost::asio::ssl::context{boost::asio::ssl::context::tlsv13_client}; - ares_channel_t* ares_channel_ = nullptr; - void CAresProcess(); +} - public: - AllInclusiveContext(boost::asio::io_context& io); - ~AllInclusiveContext() noexcept override; - void DnsResults(std::string&, ares_txt_reply&); -}; class HttpSession : public std::enable_shared_from_this { using tcp = boost::asio::ip::tcp; tcp::resolver resolver_; @@ -140,13 +113,16 @@ class HttpSession : public std::enable_shared_from_this { boost::beast::ssl_stream stream_; boost::beast::flat_buffer buffer_; // (Must persist between reads) boost::beast::http::request req_; - boost::beast::http::response res_; ipfs::ContextApi::HttpCompleteCallback cb_; int expiry_seconds_ = 91; std::string host_, port_, target_; ipfs::HttpRequestDescription desc_; tcp::resolver::results_type resolution_; std::string parsed_host_; + boost::beast::http::response_parser + response_parser_; + std::optional> + res_; void fail(boost::beast::error_code ec, char const* what) { GOOGLE_LOG(ERROR) << what << ": " << ec.value() << ' ' << ec.message() @@ -186,7 +162,13 @@ class HttpSession : public std::enable_shared_from_this { ssl_ctx_(ssc), stream_(boost::asio::make_strand(ioc), ssc), cb_{cb}, - desc_{desc} {} + desc_{desc} { + if (auto sz = desc_.max_response_size) { + response_parser_.body_limit(*sz * 2); + } else { + response_parser_.body_limit(boost::none); + } + } // Start the asynchronous operation void run() { @@ -279,12 +261,12 @@ class HttpSession : public std::enable_shared_from_this { extend_time(); if (use_ssl()) { boost::beast::http::async_read( - stream_, buffer_, res_, + stream_, buffer_, response_parser_, boost::beast::bind_front_handler(&HttpSession::on_read, shared_from_this())); } else { boost::beast::http::async_read( - boost::beast::get_lowest_layer(stream_), buffer_, res_, + boost::beast::get_lowest_layer(stream_), buffer_, response_parser_, boost::beast::bind_front_handler(&HttpSession::on_read, shared_from_this())); } @@ -293,27 +275,29 @@ class HttpSession : public std::enable_shared_from_this { void on_read(boost::beast::error_code ec, std::size_t bytes_transferred) { if (ec) return fail(ec, "read"); + res_ = response_parser_.release(); ipfs::ContextApi::HeaderAccess get_hdr = [this](std::string_view k) -> std::string { - std::string rv{res_[k]}; + std::string rv{(*res_)[k]}; return rv; }; - GOOGLE_LOG(INFO) << "HTTP read (" << desc_.url << ";host=" << host_ << '(' << host_.size() - << ");port=" << port_ << ";target=" << target_ - << ": status=" << res_.result_int() << ", body is " + GOOGLE_LOG(INFO) << "HTTP read (" << desc_.url << ";host=" << host_ << '(' + << host_.size() << ");port=" << port_ + << ";target=" << target_ + << ": status=" << res_->result_int() << ", body is " << bytes_transferred << "B, headers... "; - if (res_.result_int() == 400) { - GOOGLE_LOG(WARNING) << "Got that annoying 400 status: " << res_.body(); + if (res_->result_int() == 400) { + GOOGLE_LOG(WARNING) << "Got that annoying 400 status: " << res_->body(); } - for (auto& h : res_) { + for (auto& h : *res_) { auto& n = h.name_string(); if (n.substr(0, 6) != "Access") { GOOGLE_LOG(DEBUG) << "\t Header=" << h.name_string() << ": " << h.value(); } } - if (res_.result_int() / 100 == 3) { - auto loc = res_[boost::beast::http::field::location]; + if (res_->result_int() / 100 == 3) { + auto loc = (*res_)[boost::beast::http::field::location]; if (loc.size()) { desc_.url = loc; GOOGLE_LOG(WARNING) << "Redirecting to " << loc << " aka " << desc_.url; @@ -324,10 +308,10 @@ class HttpSession : public std::enable_shared_from_this { return; } } - auto content_type = res_[boost::beast::http::field::content_type]; + auto content_type = (*res_)[boost::beast::http::field::content_type]; if (content_type.empty() || boost::algorithm::icontains(content_type, desc_.accept)) { - cb_(res_.result_int(), res_.body(), get_hdr); + cb_(res_->result_int(), res_->body(), get_hdr); } else { GOOGLE_LOG(INFO) << desc_.url << " response incorrect content type: " << content_type @@ -355,18 +339,10 @@ class HttpSession : public std::enable_shared_from_this { } }; -inline std::shared_ptr start_default( - boost::asio::io_context& io) { - auto api = std::make_shared(io); - auto gl = Gateways::DefaultGateways(); - auto rtor = gw::default_requestor(gl, {}, api); - auto orc = std::make_shared(rtor, api); - return orc; +void Self::SendHttpRequest(HttpRequestDescription desc, + HttpCompleteCallback cb) const { + auto sess = std::make_shared(io_, ssl_ctx_, desc, cb); + sess->run(); } -} // namespace ipfs - -#endif // boost - -#endif //_MSC_VER -#endif // IPFS_ALL_INCLUSIVE_CONTEXT_H_ +#endif diff --git a/library/src/libp2p/crypto/provider.h b/library/src/libp2p/crypto/provider.h deleted file mode 100644 index 0ffb79f6..00000000 --- a/library/src/libp2p/crypto/provider.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef IPFS_PROVIDER_H_ -#define IPFS_PROVIDER_H_ - -#include "libp2p/crypto/key.h" - -#include - -#include -#include - -namespace libp2p::crypto { -class Provider { - public: - template - using Result = ipfs::expected; - - virtual Result derive(const PrivateKey& private_key) const = 0; - - virtual Result sign(ipfs::ByteView message, - const PrivateKey& private_key) const = 0; - - virtual Result verify(ipfs::ByteView message, - const Signature& signature, - const PublicKey& key) const = 0; -}; -} // namespace libp2p::crypto - -#endif // IPFS_PROVIDER_H_ diff --git a/library/src/libp2p/multi/multibase_codec/codecs/base58.cc b/library/src/libp2p/multi/multibase_codec/codecs/base58.cc deleted file mode 100644 index c3af0a2a..00000000 --- a/library/src/libp2p/multi/multibase_codec/codecs/base58.cc +++ /dev/null @@ -1,187 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "libp2p/multi/multibase_codec/codecs/base58.hpp" - -#include -#include - -// #include -#include "libp2p/multi/multibase_codec/codecs/base_error.hpp" - -namespace { -// All alphanumeric characters except for "0", "I", "O", and "l" -constexpr std::string_view pszBase58 = - "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - -// clang-format off - constexpr std::array mapBase58 = { - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, - -1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1, - 22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1, - -1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46, - 47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, - }; -// clang-format on - -/** - * Tests if the given character is a whitespace character. The whitespace - * characters are: space, form-feed ('\f'), newline ('\n'), carriage return - * ('\r'), horizontal tab ('\t'), and vertical tab ('\v') - * @param c - char to be tested - * @return true, if char is space, false otherwise - */ -constexpr bool isSpace(char c) noexcept { - return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || - c == '\v'; -} -} // namespace - -namespace libp2p::multi::detail { - -/** - * Actual implementation of the encoding - * @param pbegin - pointer to the beginning of bytes collection - * @param pend - pointer to the end of bytes collection - * @return encoded string - */ -std::string encodeImpl(const unsigned char* pbegin, const unsigned char* pend) { - // Skip & count leading zeroes. - int zeroes = 0; - int length = 0; - while (pbegin != pend && *pbegin == 0) { - std::advance(pbegin, 1); - zeroes++; - } - // Allocate enough space in big-endian base58 representation. - // log(256) / log(58), rounded up. - // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions) - int size = (pend - pbegin) * 138 / 100 + 1; - std::vector b58(size); - // Process the bytes. - while (pbegin != pend) { - int carry = *pbegin; - int i = 0; - // Apply "b58 = b58 * 256 + ch". - for (auto it = b58.rbegin(); - (carry != 0 || i < length) && (it != b58.rend()); it++, i++) { - carry += 256 * (*it); - *it = carry % 58; - carry /= 58; - } - - length = i; - std::advance(pbegin, 1); - } - // Skip leading zeroes in base58 result. - auto it = b58.begin() + (size - length); - while (it != b58.end() && *it == 0) { - it++; - } - // Translate the result into a string. - std::string str; - str.reserve(zeroes + (b58.end() - it)); - str.assign(zeroes, '1'); - while (it != b58.end()) { - str += pszBase58[*it]; - std::advance(it, 1); - } - return str; -} - -/** - * Actual implementation of the decoding - * @param psz - pointer to the string to be decoded - * @return decoded bytes, if the process went successfully, none otherwise - */ -std::optional> decodeImpl(const char* psz) { - // Skip leading spaces. - while ((*psz != '0') && isSpace(*psz)) { - std::advance(psz, 1); - } - // Skip and count leading '1's. - int zeroes = 0; - int length = 0; - while (*psz == '1') { - zeroes++; - std::advance(psz, 1); - } - // Allocate enough space in big-endian base256 representation. - // log(58) / log(256), rounded up. - // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions) - int size = strlen(psz) * 733 / 1000 + 1; - std::vector b256(size); - // Process the characters. - while (*psz && !isSpace(*psz)) { // NOLINT - // Decode base58 character - int carry = mapBase58.at(static_cast(*psz)); - if (carry == -1) { // Invalid b58 character - return {}; - } - int i = 0; - for (auto it = b256.rbegin(); - (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) { - carry += 58 * (*it); - *it = carry % 256; - carry /= 256; - } - if (carry != 0) { - return {}; - } - length = i; - std::advance(psz, 1); - } - // Skip trailing spaces. - while (isSpace(*psz)) { - std::advance(psz, 1); - } - if (*psz != 0) { - return {}; - } - // Skip leading zeroes in b256. - auto it = b256.begin() + (size - length); - while (it != b256.end() && *it == 0) { - it++; - } - // Copy result into output vector. - std::vector vch(zeroes + (b256.end() - it)); - vch.assign(zeroes, 0x00); - while (it != b256.end()) { - vch.push_back(*(it++)); - } - return vch; -} - -std::string encodeBase58(ipfs::ByteView bytes) { - unsigned char const* ptr = - reinterpret_cast(bytes.data()); - return encodeImpl(ptr, ptr + bytes.size()); -} - -ipfs::expected decodeBase58( - std::string_view string) { - auto decoded_bytes = decodeImpl(string.data()); - if (decoded_bytes) { - ipfs::Byte const* b = - reinterpret_cast(decoded_bytes->data()); - ipfs::Byte const* e = std::next(b, decoded_bytes->size()); - return common::ByteArray(b, e); - } - // return absl::InvalidArgumentError("INVALID_BASE58_INPUT"); - return ipfs::unexpected(BaseError::INVALID_BASE58_INPUT); -} - -} // namespace libp2p::multi::detail diff --git a/library/src/libp2p/multi/multibase_codec/multibase_codec_impl.cc b/library/src/libp2p/multi/multibase_codec/multibase_codec_impl.cc deleted file mode 100644 index c550146c..00000000 --- a/library/src/libp2p/multi/multibase_codec/multibase_codec_impl.cc +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright Soramitsu Co., Ltd. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include "log_macros.h" - -#include - -#include -#include -#include -#include - -namespace { -using namespace libp2p::multi; // NOLINT -using namespace libp2p::multi::detail; // NOLINT - -/** - * Get the encoding by a character - * @param ch of encoding - * @return related encoding, if character stands for one of them, none - * otherwise - */ -std::optional encodingByChar(char ch) { - switch (ch) { - case 'f': - return MultibaseCodec::Encoding::BASE16_LOWER; - case 'F': - return MultibaseCodec::Encoding::BASE16_UPPER; - case 'b': - return MultibaseCodec::Encoding::BASE32_LOWER; - case 'B': - return MultibaseCodec::Encoding::BASE32_UPPER; - case 'k': - return MultibaseCodec::Encoding::BASE36; - case 'z': - return MultibaseCodec::Encoding::BASE58; - case 'm': - return MultibaseCodec::Encoding::BASE64; - default: - return std::nullopt; - } -} - -struct CodecFunctions { - using EncodeFuncType = decltype(encodeBase58); - using DecodeFuncType = decltype(decodeBase58); - - EncodeFuncType* encode; - DecodeFuncType* decode; -}; - - -/// all available codec functions -const std::unordered_map codecs{ - {MultibaseCodec::Encoding::BASE16_UPPER, - CodecFunctions{&ipfs::base16::encodeUpper, &ipfs::base16::decode}}, - {MultibaseCodec::Encoding::BASE16_LOWER, - CodecFunctions{&ipfs::base16::encodeLower, &ipfs::base16::decode}}, - {MultibaseCodec::Encoding::BASE32_UPPER, - CodecFunctions{&encodeBase32Upper, &decodeBase32Upper}}, - {MultibaseCodec::Encoding::BASE32_LOWER, - CodecFunctions{&encodeBase32Lower, &decodeBase32Lower}}, - {MultibaseCodec::Encoding::BASE36, - CodecFunctions{&encodeBase36Lower, &decodeBase36}}, - {MultibaseCodec::Encoding::BASE58, - CodecFunctions{&encodeBase58, &decodeBase58}} - //, {MultibaseCodec::Encoding::BASE64,CodecFunctions{&todo_encode, - // &todo_decode}} -}; -} // namespace - -namespace libp2p::multi { -using common::ByteArray; - -std::string MultibaseCodecImpl::encode(const ByteArray& bytes, - Encoding encoding) const { - if (bytes.empty()) { - return ""; - } - - return static_cast(encoding) + codecs.at(encoding).encode(bytes); -} - -auto MultibaseCodecImpl::decode(std::string_view string) const - -> FactoryResult { - if (string.length() < 2) { - return ipfs::unexpected{Error::INPUT_TOO_SHORT}; - } - - auto encoding_base = encodingByChar(string.front()); - if (!encoding_base) { - return ipfs::unexpected{Error::UNSUPPORTED_BASE}; - } - auto codec = codecs.find(*encoding_base); - if (codecs.end() == codec) { - return ipfs::unexpected{Error::UNSUPPORTED_BASE}; - } - auto result = codec->second.decode(string.substr(1)); - if (result.has_value()) { - return result.value(); - } else { - return ipfs::unexpected{Error::BASE_CODEC_ERROR}; - } -} -} // namespace libp2p::multi - -bool libp2p::multi::case_critical(MultibaseCodec::Encoding e) { - using E = MultibaseCodec::Encoding; - switch (e) { - case E::BASE16_LOWER: - case E::BASE16_UPPER: - case E::BASE32_LOWER: - case E::BASE32_UPPER: - case E::BASE36: - return false; - case E::BASE58: - case E::BASE64: - return true; - } - LOG(FATAL) << "TODO implement encode for this multibase encoding " - << static_cast(e); - return false; -} diff --git a/library/src/libp2p/multi/multibase_codec/multibase_codec_impl_unittest.cc b/library/src/libp2p/multi/multibase_codec/multibase_codec_impl_unittest.cc deleted file mode 100644 index c414e2fd..00000000 --- a/library/src/libp2p/multi/multibase_codec/multibase_codec_impl_unittest.cc +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -namespace m = libp2p::multi; -using Codec = m::MultibaseCodec; -using Impl = m::MultibaseCodecImpl; - -TEST(MultibaseCodecImplTest, DecodeUnknownUnsupportedMultibase) { - Impl i; - auto result = - i.decode("?Question mark is not even in the table of multibase prefixes"); - EXPECT_TRUE(result.has_error()); - EXPECT_EQ(Codec::Error::UNSUPPORTED_BASE, result.error()); -} - -TEST(MultibaseCodecImplTest, DecodeKnownUnsupportedMultibase) { - Impl i; - auto result = i.decode( - "mBase64 *IS* found in encodingByChar, but not mapped in codecs array."); - EXPECT_TRUE(result.has_error()); - EXPECT_EQ(Codec::Error::UNSUPPORTED_BASE, result.error()); -} diff --git a/library/src/libp2p/multi/uvarint.cc b/library/src/libp2p/multi/uvarint.cc index 96997b6d..2e6ed6eb 100644 --- a/library/src/libp2p/multi/uvarint.cc +++ b/library/src/libp2p/multi/uvarint.cc @@ -5,10 +5,7 @@ #include -#include - namespace libp2p::multi { -using common::hex_upper; UVarint::UVarint(UVarint const& rhs) : bytes_(rhs.bytes_) {} UVarint::UVarint(uint64_t number) { @@ -22,9 +19,12 @@ UVarint::UVarint(uint64_t number) { } while (number != 0); } -UVarint::UVarint(ipfs::ByteView varint_bytes) - : bytes_(varint_bytes.begin(), - varint_bytes.begin() + calculateSize(varint_bytes)) {} +UVarint::UVarint(ipfs::ByteView varint_bytes) { + auto size = calculateSize(varint_bytes); + if (size <= varint_bytes.size()) { + bytes_.assign(varint_bytes.begin(), varint_bytes.begin() + size); + } +} UVarint::UVarint(ipfs::ByteView varint_bytes, size_t varint_size) : bytes_(varint_bytes.begin(), varint_bytes.begin() + varint_size) {} diff --git a/library/src/vocab/byte_view.cc b/library/src/vocab/byte_view.cc index 66d35686..f71dcaa0 100644 --- a/library/src/vocab/byte_view.cc +++ b/library/src/vocab/byte_view.cc @@ -1 +1,2 @@ #include "vocab/byte_view.h" + diff --git a/library/src/vocab/slash_delimited.cc b/library/src/vocab/slash_delimited.cc index 0ef33662..c81ae582 100644 --- a/library/src/vocab/slash_delimited.cc +++ b/library/src/vocab/slash_delimited.cc @@ -1,5 +1,14 @@ #include +#include "log_macros.h" + +#include + +#if __has_include() +#include +#define HAS_STRINGPIECE 1 +#endif + using Self = ipfs::SlashDelimited; Self::SlashDelimited(std::string_view unowned) : remainder_{unowned} {} @@ -62,3 +71,47 @@ std::string_view Self::peek_back() const { return s; } } +std::string Self::pop_back() { + auto non_slash = remainder_.find_last_not_of('/'); + if (non_slash == std::string_view::npos) { + return ""; + } + auto slash = remainder_.find_last_of('/', non_slash); + std::string rv; + if (slash == std::string_view::npos) { + rv = remainder_; + remainder_ = ""; + } else { + rv = remainder_.substr(slash + 1, non_slash - slash); + remainder_ = remainder_.substr(0UL, slash); + } + return rv; +} + +std::ostream& operator<<(std::ostream& str, ipfs::SlashDelimited const& sd) { + return str << sd.to_view(); +} + +#if __has_include() +#include + +using namespace google::protobuf::internal; +using namespace google::protobuf; + +#if PROTOBUF_VERSION >= 3020000 +#include +LogMessage& operator<<(LogMessage& str, ipfs::SlashDelimited const& sd) { + return str << sd.to_view(); +} +#elif __has_include() +#include +LogMessage& operator<<(LogMessage& str, ipfs::SlashDelimited const& sd) { + return str << StringPiece{sd.to_view()}; +} +#else +LogMessage& operator<<(LogMessage& str, ipfs::SlashDelimited const& sd) { + return str << std::string{sd.to_view()}; +} +#endif + +#endif diff --git a/test_data/blocks/QmNUHvbMqn8G2yWHgaBC4AfiwL9kj96jwCcNbkuKiEsFzu b/test_data/blocks/QmNUHvbMqn8G2yWHgaBC4AfiwL9kj96jwCcNbkuKiEsFzu deleted file mode 100644 index 69e7ebe7..00000000 --- a/test_data/blocks/QmNUHvbMqn8G2yWHgaBC4AfiwL9kj96jwCcNbkuKiEsFzu +++ /dev/null @@ -1,2 +0,0 @@ - -˜Yg0 Yg1 Yg2 Yg3 Yg4 Yg5 Yg6 Yg7 Yg8 Yg9 Yh0 Yh1 Yh2 Yh3 Yh4 Yh5 Yh6 Yh7 Yh8 Yh9 Yi0 Yi1 Yi2 Yi3 Yi4 Yi5 Yi6 Yi7 Yi8 Yi9 Yj0 Yj1 Yj2 Yj3 Yj4 Yj5  \ No newline at end of file diff --git a/test_data/blocks/QmNVBnw8L44WWYq3EQXSwFFoRJnEEoDB4Ht9kLhuiVGxmF b/test_data/blocks/QmNVBnw8L44WWYq3EQXSwFFoRJnEEoDB4Ht9kLhuiVGxmF deleted file mode 100644 index 9c8212d7..00000000 --- a/test_data/blocks/QmNVBnw8L44WWYq3EQXSwFFoRJnEEoDB4Ht9kLhuiVGxmF +++ /dev/null @@ -1,2 +0,0 @@ - -˜Ao4 Ao5 Ao6 Ao7 Ao8 Ao9 Ap0 Ap1 Ap2 Ap3 Ap4 Ap5 Ap6 Ap7 Ap8 Ap9 Aq0 Aq1 Aq2 Aq3 Aq4 Aq5 Aq6 Aq7 Aq8 Aq9 Ar0 Ar1 Ar2 Ar3 Ar4 Ar5 Ar6 Ar7 Ar8 Ar9  \ No newline at end of file diff --git a/test_data/blocks/QmNsxKnTV7SLbFBPGAsWsH731WuTC829FCoFoqu4hPJydm b/test_data/blocks/QmNsxKnTV7SLbFBPGAsWsH731WuTC829FCoFoqu4hPJydm deleted file mode 100644 index 71c2d8a4..00000000 --- a/test_data/blocks/QmNsxKnTV7SLbFBPGAsWsH731WuTC829FCoFoqu4hPJydm +++ /dev/null @@ -1,2 +0,0 @@ - -˜Mi4 Mi5 Mi6 Mi7 Mi8 Mi9 Mj0 Mj1 Mj2 Mj3 Mj4 Mj5 Mj6 Mj7 Mj8 Mj9 Mk0 Mk1 Mk2 Mk3 Mk4 Mk5 Mk6 Mk7 Mk8 Mk9 Ml0 Ml1 Ml2 Ml3 Ml4 Ml5 Ml6 Ml7 Ml8 Ml9  \ No newline at end of file diff --git a/test_data/blocks/QmNwEgMrExwSsE8DCjZjahYfHUfkSWRhtqSkQUh4Fk3udD b/test_data/blocks/QmNwEgMrExwSsE8DCjZjahYfHUfkSWRhtqSkQUh4Fk3udD deleted file mode 100644 index 1aa5add7..00000000 --- a/test_data/blocks/QmNwEgMrExwSsE8DCjZjahYfHUfkSWRhtqSkQUh4Fk3udD +++ /dev/null @@ -1,3 +0,0 @@ - - my one - \ No newline at end of file diff --git a/test_data/blocks/QmNwYYo6CEL8S6PqN8LjJYMso8uDVfnoVHXU8eFT87z3od b/test_data/blocks/QmNwYYo6CEL8S6PqN8LjJYMso8uDVfnoVHXU8eFT87z3od deleted file mode 100644 index c6950b93..00000000 --- a/test_data/blocks/QmNwYYo6CEL8S6PqN8LjJYMso8uDVfnoVHXU8eFT87z3od +++ /dev/null @@ -1,2 +0,0 @@ - -˜Vb2 Vb3 Vb4 Vb5 Vb6 Vb7 Vb8 Vb9 Vc0 Vc1 Vc2 Vc3 Vc4 Vc5 Vc6 Vc7 Vc8 Vc9 Vd0 Vd1 Vd2 Vd3 Vd4 Vd5 Vd6 Vd7 Vd8 Vd9 Ve0 Ve1 Ve2 Ve3 Ve4 Ve5 Ve6 Ve7  \ No newline at end of file diff --git a/test_data/blocks/QmP1ENUYYwCycXw1Unj6rfTeRpe5S54T46qxiEYKRgmfJe b/test_data/blocks/QmP1ENUYYwCycXw1Unj6rfTeRpe5S54T46qxiEYKRgmfJe deleted file mode 100644 index 6c26878c..00000000 --- a/test_data/blocks/QmP1ENUYYwCycXw1Unj6rfTeRpe5S54T46qxiEYKRgmfJe +++ /dev/null @@ -1,2 +0,0 @@ - -˜Ww0 Ww1 Ww2 Ww3 Ww4 Ww5 Ww6 Ww7 Ww8 Ww9 Wx0 Wx1 Wx2 Wx3 Wx4 Wx5 Wx6 Wx7 Wx8 Wx9 Wy0 Wy1 Wy2 Wy3 Wy4 Wy5 Wy6 Wy7 Wy8 Wy9 Wz0 Wz1 Wz2 Wz3 Wz4 Wz5  \ No newline at end of file diff --git a/test_data/blocks/QmQQD24KQvDcgyJ8McU2qz57jvN5itbkbNv6EpcZqeQeHb b/test_data/blocks/QmQQD24KQvDcgyJ8McU2qz57jvN5itbkbNv6EpcZqeQeHb deleted file mode 100644 index 4817e9e8..00000000 --- a/test_data/blocks/QmQQD24KQvDcgyJ8McU2qz57jvN5itbkbNv6EpcZqeQeHb +++ /dev/null @@ -1,14 +0,0 @@ - -Š€€€var s4=Object.defineProperty;var l4=(e,t,r)=>t in e?s4(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var _n=(e,t,r)=>(l4(e,typeof t!="symbol"?t+"":t,r),r);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const a of document.querySelectorAll('link[rel="modulepreload"]'))n(a);new MutationObserver(a=>{for(const i of a)if(i.type==="childList")for(const o of i.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&n(o)}).observe(document,{childList:!0,subtree:!0});function r(a){const i={};return a.integrity&&(i.integrity=a.integrity),a.referrerpolicy&&(i.referrerPolicy=a.referrerpolicy),a.crossorigin==="use-credentials"?i.credentials="include":a.crossorigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function n(a){if(a.ep)return;a.ep=!0;const i=r(a);fetch(a.href,i)}})();var ir=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function u4(e){if(e.__esModule)return e;var t=e.default;if(typeof t=="function"){var r=function n(){if(this instanceof n){var a=[null];a.push.apply(a,arguments);var i=Function.bind.apply(t,a);return new i}return t.apply(this,arguments)};r.prototype=t.prototype}else r={};return Object.defineProperty(r,"__esModule",{value:!0}),Object.keys(e).forEach(function(n){var a=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(r,n,a.get?a:{enumerable:!0,get:function(){return e[n]}})}),r}var hx={},c4={get exports(){return hx},set exports(e){hx=e}},_f=function(e){return e&&e.Math==Math&&e},Se=_f(typeof globalThis=="object"&&globalThis)||_f(typeof window=="object"&&window)||_f(typeof self=="object"&&self)||_f(typeof ir=="object"&&ir)||function(){return this}()||Function("return this")(),er={},le=function(e){try{return!!e()}catch{return!0}},f4=le,Ve=!f4(function(){return Object.defineProperty({},1,{get:function(){return 7}})[1]!=7}),d4=le,Tc=!d4(function(){var e=function(){}.bind();return typeof e!="function"||e.hasOwnProperty("prototype")}),v4=Tc,$f=Function.prototype.call,Ye=v4?$f.bind($f):function(){return $f.apply($f,arguments)},Ec={},OI={}.propertyIsEnumerable,CI=Object.getOwnPropertyDescriptor,p4=CI&&!OI.call({1:2},1);Ec.f=p4?function(t){var r=CI(this,t);return!!r&&r.enumerable}:OI;var cn=function(e,t){return{enumerable:!(e&1),configurable:!(e&2),writable:!(e&4),value:t}},II=Tc,kI=Function.prototype,h4=kI.bind,sy=kI.call,m4=II&&h4.bind(sy,sy),ue=II?function(e){return e&&m4(e)}:function(e){return e&&function(){return sy.apply(e,arguments)}},PI=ue,g4=PI({}.toString),y4=PI("".slice),Br=function(e){return y4(g4(e),8,-1)},b4=ue,_4=le,$4=Br,Mh=Object,x4=b4("".split),Ac=_4(function(){return!Mh("z").propertyIsEnumerable(0)})?function(e){return $4(e)=="String"?x4(e,""):Mh(e)}:Mh,S4=TypeError,zt=function(e){if(e==null)throw S4("Can't call method on "+e);return e},w4=Ac,T4=zt,Or=function(e){return w4(T4(e))},Qe=function(e){return typeof e=="function"},E4=Qe,qe=function(e){return typeof e=="object"?e!==null:E4(e)},Lh=Se,A4=Qe,O4=function(e){return A4(e)?e:void 0},Et=function(e,t){return arguments.length<2?O4(Lh[e]):Lh[e]&&Lh[e][t]},C4=ue,fn=C4({}.isPrototypeOf),I4=Et,Wa=I4("navigator","userAgent")||"",RI=Se,Dh=Wa,mx=RI.process,gx=RI.Deno,yx=mx&&mx.versions||gx&&gx.version,bx=yx&&yx.v8,Tn,Hd;bx&&(Tn=bx.split("."),Hd=Tn[0]>0&&Tn[0]<4?1:+(Tn[0]+Tn[1]));!Hd&&Dh&&(Tn=Dh.match(/Edge\/(\d+)/),(!Tn||Tn[1]>=74)&&(Tn=Dh.match(/Chrome\/(\d+)/),Tn&&(Hd=+Tn[1])));var Gi=Hd,_x=Gi,k4=le,$l=!!Object.getOwnPropertySymbols&&!k4(function(){var e=Symbol();return!String(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&_x&&_x<41}),P4=$l,MI=P4&&!Symbol.sham&&typeof Symbol.iterator=="symbol",R4=Et,M4=Qe,L4=fn,D4=MI,N4=Object,Go=D4?function(e){return typeof e=="symbol"}:function(e){var t=R4("Symbol");return M4(t)&&L4(t.prototype,N4(e))},F4=String,Wo=function(e){try{return F4(e)}catch{return"Object"}},V4=Qe,j4=Wo,B4=TypeError,qt=function(e){if(V4(e))return e;throw B4(j4(e)+" is not a function")},H4=qt,Ya=function(e,t){var r=e[t];return r==null?void 0:H4(r)},Nh=Ye,Fh=Qe,Vh=qe,U4=TypeError,LI=function(e,t){var r,n;if(t==="string"&&Fh(r=e.toString)&&!Vh(n=Nh(r,e))||Fh(r=e.valueOf)&&!Vh(n=Nh(r,e))||t!=="string"&&Fh(r=e.toString)&&!Vh(n=Nh(r,e)))return n;throw U4("Can't convert object to primitive value")},ji={},G4={get exports(){return ji},set exports(e){ji=e}},DI=!1,$x=Se,W4=Object.defineProperty,Mb=function(e,t){try{W4($x,e,{value:t,configurable:!0,writable:!0})}catch{$x[e]=t}return t},Y4=Se,z4=Mb,xx="__core-js_shared__",q4=Y4[xx]||z4(xx,{}),Lb=q4,Sx=Lb;(G4.exports=function(e,t){return Sx[e]||(Sx[e]=t!==void 0?t:{})})("versions",[]).push({version:"3.22.8",mode:"global",copyright:"© 2014-2022 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.22.8/LICENSE",source:"https://github.com/zloirock/core-js"});var K4=zt,Z4=Object,$t=function(e){return Z4(K4(e))},X4=ue,J4=$t,Q4=X4({}.hasOwnProperty),at=Object.hasOwn||function(t,r){return Q4(J4(t),r)},e6=ue,t6=0,r6=Math.random(),n6=e6(1 .toString),xl=function(e){return"Symbol("+(e===void 0?"":e)+")_"+n6(++t6+r6,36)},a6=Se,i6=ji,wx=at,o6=xl,Tx=$l,NI=MI,us=i6("wks"),Io=a6.Symbol,Ex=Io&&Io.for,s6=NI?Io:Io&&Io.withoutSetter||o6,Ke=function(e){if(!wx(us,e)||!(Tx||typeof us[e]=="string")){var t="Symbol."+e;Tx&&wx(Io,e)?us[e]=Io[e]:NI&&Ex?us[e]=Ex(t):us[e]=s6(t)}return us[e]},l6=Ye,Ax=qe,Ox=Go,u6=Ya,c6=LI,f6=Ke,d6=TypeError,v6=f6("toPrimitive"),Xv=function(e,t){if(!Ax(e)||Ox(e))return e;var r=u6(e,v6),n;if(r){if(t===void 0&&(t="default"),n=l6(r,e,t),!Ax(n)||Ox(n))return n;throw d6("Can't convert object to primitive value")}return t===void 0&&(t="number"),c6(e,t)},p6=Xv,h6=Go,Wi=function(e){var t=p6(e,"string");return h6(t)?t:t+""},m6=Se,Cx=qe,ly=m6.document,g6=Cx(ly)&&Cx(ly.createElement),Jv=function(e){return g6?ly.createElement(e):{}},y6=Ve,b6=le,_6=Jv,FI=!y6&&!b6(function(){return Object.defineProperty(_6("div"),"a",{get:function(){return 7}}).a!=7}),$6=Ve,x6=Ye,S6=Ec,w6=cn,T6=Or,E6=Wi,A6=at,O6=FI,Ix=Object.getOwnPropertyDescriptor;er.f=$6?Ix:function(t,r){if(t=T6(t),r=E6(r),O6)try{return Ix(t,r)}catch{}if(A6(t,r))return w6(!x6(S6.f,t,r),t[r])};var ht={},C6=Ve,I6=le,VI=C6&&I6(function(){return Object.defineProperty(function(){},"prototype",{value:42,writable:!1}).prototype!=42}),k6=qe,P6=String,R6=TypeError,Ge=function(e){if(k6(e))return e;throw R6(P6(e)+" is not an object")},M6=Ve,L6=FI,D6=VI,xf=Ge,kx=Wi,N6=TypeError,jh=Object.defineProperty,F6=Object.getOwnPropertyDescriptor,Bh="enumerable",Hh="configurable",Uh="writable";ht.f=M6?D6?function(t,r,n){if(xf(t),r=kx(r),xf(n),typeof t=="function"&&r==="prototype"&&"value"in n&&Uh in n&&!n[Uh]){var a=F6(t,r);a&&a[Uh]&&(t[r]=n.value,n={configurable:Hh in n?n[Hh]:a[Hh],enumerable:Bh in n?n[Bh]:a[Bh],writable:!1})}return jh(t,r,n)}:jh:function(t,r,n){if(xf(t),r=kx(r),xf(n),L6)try{return jh(t,r,n)}catch{}if("get"in n||"set"in n)throw N6("Accessors not supported");return"value"in n&&(t[r]=n.value),t};var V6=Ve,j6=ht,B6=cn,br=V6?function(e,t,r){return j6.f(e,t,B6(1,r))}:function(e,t,r){return e[t]=r,e},Gu={},H6={get exports(){return Gu},set exports(e){Gu=e}},uy=Ve,U6=at,jI=Function.prototype,G6=uy&&Object.getOwnPropertyDescriptor,Db=U6(jI,"name"),W6=Db&&function(){}.name==="something",Y6=Db&&(!uy||uy&&G6(jI,"name").configurable),Sl={EXISTS:Db,PROPER:W6,CONFIGURABLE:Y6},z6=ue,q6=Qe,cy=Lb,K6=z6(Function.toString);q6(cy.inspectSource)||(cy.inspectSource=function(e){return K6(e)});var Qv=cy.inspectSource,Z6=Se,X6=Qe,J6=Qv,Px=Z6.WeakMap,BI=X6(Px)&&/native code/.test(J6(Px)),Q6=ji,eV=xl,Rx=Q6("keys"),ep=function(e){return Rx[e]||(Rx[e]=eV(e))},Oc={},tV=BI,HI=Se,Gh=ue,rV=qe,nV=br,Wh=at,Yh=Lb,aV=ep,iV=Oc,Mx="Object already initialized",fy=HI.TypeError,oV=HI.WeakMap,Ud,Wu,Gd,sV=function(e){return Gd(e)?Wu(e):Ud(e,{})},lV=function(e){return function(t){var r;if(!rV(t)||(r=Wu(t)).type!==e)throw fy("Incompatible receiver, "+e+" required");return r}};if(tV||Yh.state){var ro=Yh.state||(Yh.state=new oV),uV=Gh(ro.get),Lx=Gh(ro.has),cV=Gh(ro.set);Ud=function(e,t){if(Lx(ro,e))throw new fy(Mx);return t.facade=e,cV(ro,e,t),t},Wu=function(e){return uV(ro,e)||{}},Gd=function(e){return Lx(ro,e)}}else{var cs=aV("state");iV[cs]=!0,Ud=function(e,t){if(Wh(e,cs))throw new fy(Mx);return t.facade=e,nV(e,cs,t),t},Wu=function(e){return Wh(e,cs)?e[cs]:{}},Gd=function(e){return Wh(e,cs)}}var Kt={set:Ud,get:Wu,has:Gd,enforce:sV,getterFor:lV},fV=le,dV=Qe,Sf=at,UI=Ve,vV=Sl.CONFIGURABLE,pV=Qv,GI=Kt,hV=GI.enforce,mV=GI.get,bd=Object.defineProperty,gV=UI&&!fV(function(){return bd(function(){},"length",{value:8}).length!==8}),yV=String(String).split("String"),bV=H6.exports=function(e,t,r){String(t).slice(0,7)==="Symbol("&&(t="["+String(t).replace(/^Symbol\(([^)]*)\)/,"$1")+"]"),r&&r.getter&&(t="get "+t),r&&r.setter&&(t="set "+t),(!Sf(e,"name")||vV&&e.name!==t)&&bd(e,"name",{value:t,configurable:!0}),gV&&r&&Sf(r,"arity")&&e.length!==r.arity&&bd(e,"length",{value:r.arity});try{r&&Sf(r,"constructor")&&r.constructor?UI&&bd(e,"prototype",{writable:!1}):e.prototype&&(e.prototype=void 0)}catch{}var n=hV(e);return Sf(n,"source")||(n.source=yV.join(typeof t=="string"?t:"")),e};Function.prototype.toString=bV(function(){return dV(this)&&mV(this).source||pV(this)},"toString");var _V=Qe,$V=br,xV=Gu,SV=Mb,Ot=function(e,t,r,n){n||(n={});var a=n.enumerable,i=n.name!==void 0?n.name:t;return _V(r)&&xV(r,i,n),n.global?a?e[t]=r:SV(t,r):(n.unsafe?e[t]&&(a=!0):delete e[t],a?e[t]=r:$V(e,t,r)),e},za={},wV=Math.ceil,TV=Math.floor,WI=Math.trunc||function(t){var r=+t;return(r>0?TV:wV)(r)},EV=WI,Zt=function(e){var t=+e;return t!==t||t===0?0:EV(t)},AV=Zt,OV=Math.max,CV=Math.min,qa=function(e,t){var r=AV(e);return r<0?OV(r+t,0):CV(r,t)},IV=Zt,kV=Math.min,Hr=function(e){return e>0?kV(IV(e),9007199254740991):0},PV=Hr,Ct=function(e){return PV(e.length)},RV=Or,MV=qa,LV=Ct,Dx=function(e){return function(t,r,n){var a=RV(t),i=LV(a),o=MV(n,i),l;if(e&&r!=r){for(;i>o;)if(l=a[o++],l!=l)return!0}else for(;i>o;o++)if((e||o in a)&&a[o]===r)return e||o||0;return!e&&-1}},Cc={includes:Dx(!0),indexOf:Dx(!1)},DV=ue,zh=at,NV=Or,FV=Cc.indexOf,VV=Oc,Nx=DV([].push),YI=function(e,t){var r=NV(e),n=0,a=[],i;for(i in r)!zh(VV,i)&&zh(r,i)&&Nx(a,i);for(;t.length>n;)zh(r,i=t[n++])&&(~FV(a,i)||Nx(a,i));return a},Nb=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],jV=YI,BV=Nb,HV=BV.concat("length","prototype");za.f=Object.getOwnPropertyNames||function(t){return jV(t,HV)};var Ic={};Ic.f=Object.getOwnPropertySymbols;var UV=Et,GV=ue,WV=za,YV=Ic,zV=Ge,qV=GV([].concat),Fb=UV("Reflect","ownKeys")||function(t){var r=WV.f(zV(t)),n=YV.f;return n?qV(r,n(t)):r},Fx=at,KV=Fb,ZV=er,XV=ht,tp=function(e,t,r){for(var n=KV(t),a=XV.f,i=ZV.f,o=0;oo;)E8.f(t,l=a[o++],n[l]);return t};var I8=Et,qI=I8("document","documentElement"),k8=Ge,P8=rp,Vx=Nb,R8=Oc,M8=qI,L8=Jv,D8=ep,jx=">",Bx="<",dy="prototype",vy="script",KI=D8("IE_PROTO"),Kh=function(){},ZI=function(e){return Bx+vy+jx+e+Bx+"/"+vy+jx},Hx=function(e){e.write(ZI("")),e.close();var t=e.parentWindow.Object;return e=null,t},N8=function(){var e=L8("iframe"),t="java"+vy+":",r;return e.style.display="none",M8.appendChild(e),e.src=String(t),r=e.contentWindow.document,r.open(),r.write(ZI("document.F=Object")),r.close(),r.F},wf,$d=function(){try{wf=new ActiveXObject("htmlfile")}catch{}$d=typeof document<"u"?document.domain&&wf?Hx(wf):N8():Hx(wf);for(var e=Vx.length;e--;)delete $d[dy][Vx[e]];return $d()};R8[KI]=!0;var dn=Object.create||function(t,r){var n;return t!==null?(Kh[dy]=k8(t),n=new Kh,Kh[dy]=null,n[KI]=t):n=$d(),r===void 0?n:P8.f(n,r)},np={},F8=Wi,V8=ht,j8=cn,Za=function(e,t,r){var n=F8(t);n in e?V8.f(e,n,j8(0,r)):e[n]=r},Ux=qa,B8=Ct,H8=Za,U8=Array,G8=Math.max,Mc=function(e,t,r){for(var n=B8(e),a=Ux(t,n),i=Ux(r===void 0?n:r,n),o=U8(G8(i-a,0)),l=0;am;m++)if((l||m in v)&&(_=v[m],A=p(_,m,c),e))if(t)b[m]=A;else if(A)switch(e){case 3:return!0;case 5:return _;case 6:return m;case 2:Kx(b,_)}else switch(e){case 4:return!1;case 7:Kx(b,_)}return i?-1:n||a?a:b}},tr={forEach:ci(0),map:ci(1),filter:ci(2),some:ci(3),every:ci(4),find:ci(5),findIndex:ci(6),filterReject:ci(7)},ap=C,Hb=Se,Ub=Ye,kj=ue,il=Ve,ol=$l,Pj=le,Bt=at,Rj=fn,py=Ge,ip=Or,Gb=Wi,Mj=et,hy=cn,Yu=dn,ik=Rc,Lj=za,ok=np,Dj=Ic,sk=er,lk=ht,Nj=rp,uk=Ec,Zh=Ot,Wb=ji,Fj=ep,ck=Oc,Zx=xl,Vj=Ke,jj=jb,Bj=Cr,Hj=ek,Uj=Ur,fk=Kt,op=tr.forEach,wr=Fj("hidden"),sp="Symbol",zu="prototype",Gj=fk.set,Xx=fk.getterFor(sp),an=Object[zu],ko=Hb.Symbol,mu=ko&&ko[zu],Wj=Hb.TypeError,Xh=Hb.QObject,dk=sk.f,Ai=lk.f,vk=ok.f,Yj=uk.f,pk=kj([].push),Ra=Wb("symbols"),Dc=Wb("op-symbols"),zj=Wb("wks"),my=!Xh||!Xh[zu]||!Xh[zu].findChild,gy=il&&Pj(function(){return Yu(Ai({},"a",{get:function(){return Ai(this,"a",{value:7}).a}})).a!=7})?function(e,t,r){var n=dk(an,t);n&&delete an[t],Ai(e,t,r),n&&e!==an&&Ai(an,t,n)}:Ai,Jh=function(e,t){var r=Ra[e]=Yu(mu);return Gj(r,{type:sp,tag:e,description:t}),il||(r.description=t),r},lp=function(t,r,n){t===an&&lp(Dc,r,n),py(t);var a=Gb(r);return py(n),Bt(Ra,a)?(n.enumerable?(Bt(t,wr)&&t[wr][a]&&(t[wr][a]=!1),n=Yu(n,{enumerable:hy(0,!1)})):(Bt(t,wr)||Ai(t,wr,hy(1,{})),t[wr][a]=!0),gy(t,a,n)):Ai(t,a,n)},Yb=function(t,r){py(t);var n=ip(r),a=ik(n).concat(gk(n));return op(a,function(i){(!il||Ub(yy,n,i))&&lp(t,i,n[i])}),t},qj=function(t,r){return r===void 0?Yu(t):Yb(Yu(t),r)},yy=function(t){var r=Gb(t),n=Ub(Yj,this,r);return this===an&&Bt(Ra,r)&&!Bt(Dc,r)?!1:n||!Bt(this,r)||!Bt(Ra,r)||Bt(this,wr)&&this[wr][r]?n:!0},hk=function(t,r){var n=ip(t),a=Gb(r);if(!(n===an&&Bt(Ra,a)&&!Bt(Dc,a))){var i=dk(n,a);return i&&Bt(Ra,a)&&!(Bt(n,wr)&&n[wr][a])&&(i.enumerable=!0),i}},mk=function(t){var r=vk(ip(t)),n=[];return op(r,function(a){!Bt(Ra,a)&&!Bt(ck,a)&&pk(n,a)}),n},gk=function(e){var t=e===an,r=vk(t?Dc:ip(e)),n=[];return op(r,function(a){Bt(Ra,a)&&(!t||Bt(an,a))&&pk(n,Ra[a])}),n};ol||(ko=function(){if(Rj(mu,this))throw Wj("Symbol is not a constructor");var t=!arguments.length||arguments[0]===void 0?void 0:Mj(arguments[0]),r=Zx(t),n=function(a){this===an&&Ub(n,Dc,a),Bt(this,wr)&&Bt(this[wr],r)&&(this[wr][r]=!1),gy(this,r,hy(1,a))};return il&&my&&gy(an,r,{configurable:!0,set:n}),Jh(r,t)},mu=ko[zu],Zh(mu,"toString",function(){return Xx(this).tag}),Zh(ko,"withoutSetter",function(e){return Jh(Zx(e),e)}),uk.f=yy,lk.f=lp,Nj.f=Yb,sk.f=hk,Lj.f=ok.f=mk,Dj.f=gk,jj.f=function(e){return Jh(Vj(e),e)},il&&(Ai(mu,"description",{configurable:!0,get:function(){return Xx(this).description}}),Zh(an,"propertyIsEnumerable",yy,{unsafe:!0})));ap({global:!0,constructor:!0,wrap:!0,forced:!ol,sham:!ol},{Symbol:ko});op(ik(zj),function(e){Bj(e)});ap({target:sp,stat:!0,forced:!ol},{useSetter:function(){my=!0},useSimple:function(){my=!1}});ap({target:"Object",stat:!0,forced:!ol,sham:!il},{create:qj,defineProperty:lp,defineProperties:Yb,getOwnPropertyDescriptor:hk});ap({target:"Object",stat:!0,forced:!ol},{getOwnPropertyNames:mk});Hj();Uj(ko,sp);ck[wr]=!0;var Kj=$l,yk=Kj&&!!Symbol.for&&!!Symbol.keyFor,Zj=C,Xj=Et,Jj=at,Qj=et,bk=ji,eB=yk,Qh=bk("string-to-symbol-registry"),tB=bk("symbol-to-string-registry");Zj({target:"Symbol",stat:!0,forced:!eB},{for:function(e){var t=Qj(e);if(Jj(Qh,t))return Qh[t];var r=Xj("Symbol")(t);return Qh[t]=r,tB[r]=t,r}});var rB=C,nB=at,aB=Go,iB=Wo,oB=ji,sB=yk,Jx=oB("symbol-to-string-registry");rB({target:"Symbol",stat:!0,forced:!sB},{keyFor:function(t){if(!aB(t))throw TypeError(iB(t)+" is not a symbol");if(nB(Jx,t))return Jx[t]}});var lB=Tc,_k=Function.prototype,Qx=_k.apply,eS=_k.call,vn=typeof Reflect=="object"&&Reflect.apply||(lB?eS.bind(Qx):function(){return eS.apply(Qx,arguments)}),uB=ue,zo=uB([].slice),cB=C,$k=Et,xk=vn,fB=Ye,Nc=ue,Sk=le,dB=Yo,vB=Qe,pB=qe,tS=Go,wk=zo,hB=$l,Mi=$k("JSON","stringify"),Tf=Nc(/./.exec),rS=Nc("".charAt),mB=Nc("".charCodeAt),gB=Nc("".replace),yB=Nc(1 .toString),bB=/[\uD800-\uDFFF]/g,nS=/^[\uD800-\uDBFF]$/,aS=/^[\uDC00-\uDFFF]$/,iS=!hB||Sk(function(){var e=$k("Symbol")();return Mi([e])!="[null]"||Mi({a:e})!="{}"||Mi(Object(e))!="{}"}),oS=Sk(function(){return Mi("\uDF06\uD834")!=='"\\udf06\\ud834"'||Mi("\uDEAD")!=='"\\udead"'}),_B=function(e,t){var r=wk(arguments),n=t;if(!(!pB(t)&&e===void 0||tS(e)))return dB(t)||(t=function(a,i){if(vB(n)&&(i=fB(n,this,a,i)),!tS(i))return i}),r[1]=t,xk(Mi,null,r)},$B=function(e,t,r){var n=rS(r,t-1),a=rS(r,t+1);return Tf(nS,e)&&!Tf(aS,a)||Tf(aS,e)&&!Tf(nS,n)?"\\u"+yB(mB(e,0),16):e};Mi&&cB({target:"JSON",stat:!0,arity:3,forced:iS||oS},{stringify:function(t,r,n){var a=wk(arguments),i=xk(iS?_B:Mi,null,a);return oS&&typeof i=="string"?gB(i,bB,$B):i}});var xB=C,SB=$l,wB=le,Tk=Ic,TB=$t,EB=!SB||wB(function(){Tk.f(1)});xB({target:"Object",stat:!0,forced:EB},{getOwnPropertySymbols:function(t){var r=Tk.f;return r?r(TB(t)):[]}});var AB=C,OB=Ve,CB=Se,Ef=ue,IB=at,kB=Qe,PB=fn,RB=et,MB=ht.f,LB=tp,wa=CB.Symbol,no=wa&&wa.prototype;if(OB&&kB(wa)&&(!("description"in no)||wa().description!==void 0)){var sS={},Af=function(){var t=arguments.length<1||arguments[0]===void 0?void 0:RB(arguments[0]),r=PB(no,this)?new wa(t):t===void 0?wa():wa(t);return t===""&&(sS[r]=!0),r};LB(Af,wa),Af.prototype=no,no.constructor=Af;var DB=String(wa("test"))=="Symbol(test)",NB=Ef(no.toString),FB=Ef(no.valueOf),VB=/^Symbol\((.*)\)[^)]+$/,jB=Ef("".replace),BB=Ef("".slice);MB(no,"description",{configurable:!0,get:function(){var t=FB(this),r=NB(t);if(IB(sS,t))return"";var n=DB?BB(r,7,-1):jB(r,VB,"$1");return n===""?void 0:n}}),AB({global:!0,constructor:!0,forced:!0},{Symbol:Af})}var HB=Cr;HB("asyncIterator");var UB=Cr;UB("hasInstance");var GB=Cr;GB("isConcatSpreadable");var WB=Cr;WB("iterator");var YB=Cr;YB("match");var zB=Cr;zB("matchAll");var qB=Cr;qB("replace");var KB=Cr;KB("search");var ZB=Cr;ZB("species");var XB=Cr;XB("split");var JB=Cr,QB=ek;JB("toPrimitive");QB();var e7=Et,t7=Cr,r7=Ur;t7("toStringTag");r7(e7("Symbol"),"Symbol");var n7=Cr;n7("unscopables");var a7=Qe,i7=String,o7=TypeError,Ek=function(e){if(typeof e=="object"||a7(e))return e;throw o7("Can't set "+i7(e)+" as a prototype")},s7=ue,l7=Ge,u7=Ek,ca=Object.setPrototypeOf||("__proto__"in{}?function(){var e=!1,t={},r;try{r=s7(Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set),r(t,[]),e=t instanceof Array}catch{}return function(a,i){return l7(a),u7(i),e?r(a,i):a.__proto__=i,a}}():void 0),c7=ht.f,Ak=function(e,t,r){r in e||c7(e,r,{configurable:!0,get:function(){return t[r]},set:function(n){t[r]=n}})},f7=Qe,d7=qe,lS=ca,Tl=function(e,t,r){var n,a;return lS&&f7(n=t.constructor)&&n!==r&&d7(a=n.prototype)&&a!==r.prototype&&lS(e,a),e},v7=et,Fc=function(e,t){return e===void 0?arguments.length<2?"":t:v7(e)},p7=qe,h7=br,Ok=function(e,t){p7(t)&&"cause"in t&&h7(e,"cause",t.cause)},m7=ue,Ck=Error,g7=m7("".replace),y7=function(e){return String(Ck(e).stack)}("zxcasd"),Ik=/\n\s*at [^:]*:[^\n]*/,b7=Ik.test(y7),up=function(e,t){if(b7&&typeof e=="string"&&!Ck.prepareStackTrace)for(;t--;)e=g7(e,Ik,"");return e},_7=le,$7=cn,zb=!_7(function(){var e=Error("a");return"stack"in e?(Object.defineProperty(e,"stack",$7(1,7)),e.stack!==7):!0}),uS=Et,x7=at,em=br,S7=fn,cS=ca,fS=tp,dS=Ak,w7=Tl,T7=Fc,E7=Ok,A7=up,O7=zb,C7=Ve,kk=function(e,t,r,n){var a="stackTraceLimit",i=n?2:1,o=e.split("."),l=o[o.length-1],u=uS.apply(null,o);if(u){var f=u.prototype;if(x7(f,"cause")&&delete f.cause,!r)return u;var d=uS("Error"),s=t(function(c,v){var p=T7(n?v:c,void 0),h=n?new u(c):new u;return p!==void 0&&em(h,"message",p),O7&&em(h,"stack",A7(h.stack,2)),this&&S7(f,this)&&w7(h,this,s),arguments.length>i&&E7(h,arguments[i]),h});s.prototype=f,l!=="Error"?cS?cS(s,d):fS(s,d,{name:!0}):C7&&a in u&&(dS(s,u,a),dS(s,u,"prepareStackTrace")),fS(s,u);try{f.name!==l&&em(f,"name",l),f.constructor=s}catch{}return s}},Pk=C,I7=Se,fa=vn,Rk=kk,by="WebAssembly",vS=I7[by],Wd=Error("e",{cause:7}).cause!==7,qo=function(e,t){var r={};r[e]=Rk(e,t,Wd),Pk({global:!0,constructor:!0,arity:1,forced:Wd},r)},qb=function(e,t){if(vS&&vS[e]){var r={};r[e]=Rk(by+"."+e,t,Wd),Pk({target:by,stat:!0,constructor:!0,arity:1,forced:Wd},r)}};qo("Error",function(e){return function(r){return fa(e,this,arguments)}});qo("EvalError",function(e){return function(r){return fa(e,this,arguments)}});qo("RangeError",function(e){return function(r){return fa(e,this,arguments)}});qo("ReferenceError",function(e){return function(r){return fa(e,this,arguments)}});qo("SyntaxError",function(e){return function(r){return fa(e,this,arguments)}});qo("TypeError",function(e){return function(r){return fa(e,this,arguments)}});qo("URIError",function(e){return function(r){return fa(e,this,arguments)}});qb("CompileError",function(e){return function(r){return fa(e,this,arguments)}});qb("LinkError",function(e){return function(r){return fa(e,this,arguments)}});qb("RuntimeError",function(e){return function(r){return fa(e,this,arguments)}});var k7=Ve,P7=le,R7=Ge,M7=dn,pS=Fc,xd=Error.prototype.toString,L7=P7(function(){if(k7){var e=M7(Object.defineProperty({},"name",{get:function(){return this===e}}));if(xd.call(e)!=="true")return!0}return xd.call({message:1,name:2})!=="2: 1"||xd.call({})!=="Error"}),Mk=L7?function(){var t=R7(this),r=pS(t.name,"Error"),n=pS(t.message);return r?n?r+": "+n:r:n}:xd,D7=Ot,hS=Mk,mS=Error.prototype;mS.toString!==hS&&D7(mS,"toString",hS);var N7=le,Kb=!N7(function(){function e(){}return e.prototype.constructor=null,Object.getPrototypeOf(new e)!==e.prototype}),F7=at,V7=Qe,j7=$t,B7=ep,H7=Kb,gS=B7("IE_PROTO"),_y=Object,U7=_y.prototype,pn=H7?_y.getPrototypeOf:function(e){var t=j7(e);if(F7(t,gS))return t[gS];var r=t.constructor;return V7(r)&&t instanceof r?r.prototype:t instanceof _y?U7:null},Vc={},G7=Ke,W7=Vc,Y7=G7("iterator"),z7=Array.prototype,Zb=function(e){return e!==void 0&&(W7.Array===e||z7[Y7]===e)},q7=Ka,yS=Ya,K7=Vc,Z7=Ke,X7=Z7("iterator"),jc=function(e){if(e!=null)return yS(e,X7)||yS(e,"@@iterator")||K7[q7(e)]},J7=Ye,Q7=qt,eH=Ge,tH=Wo,rH=jc,nH=TypeError,cp=function(e,t){var r=arguments.length<2?rH(e):t;if(Q7(r))return eH(J7(r,e));throw nH(tH(e)+" is not iterable")},aH=Ye,bS=Ge,iH=Ya,Lk=function(e,t,r){var n,a;bS(e);try{if(n=iH(e,"return"),!n){if(t==="throw")throw r;return r}n=aH(n,e)}catch(i){a=!0,n=i}if(t==="throw")throw r;if(a)throw n;return bS(n),r},oH=ua,sH=Ye,lH=Ge,uH=Wo,cH=Zb,fH=Ct,_S=fn,dH=cp,vH=jc,$S=Lk,pH=TypeError,Sd=function(e,t){this.stopped=e,this.result=t},xS=Sd.prototype,da=function(e,t,r){var n=r&&r.that,a=!!(r&&r.AS_ENTRIES),i=!!(r&&r.IS_ITERATOR),o=!!(r&&r.INTERRUPTED),l=oH(t,n),u,f,d,s,c,v,p,h=function(g){return u&&$S(u,"normal",g),new Sd(!0,g)},m=function(g){return a?(lH(g),o?l(g[0],g[1],h):l(g[0],g[1])):o?l(g,h):l(g)};if(i)u=e;else{if(f=vH(e),!f)throw pH(uH(e)+" is not iterable");if(cH(f)){for(d=0,s=fH(e);s>d;d++)if(c=m(e[d]),c&&_S(xS,c))return c;return new Sd(!1)}u=dH(e,f)}for(v=u.next;!(p=sH(v,u)).done;){try{c=m(p.value)}catch(g){$S(u,"throw",g)}if(typeof c=="object"&&c&&_S(xS,c))return c}return new Sd(!1)},hH=C,mH=fn,gH=pn,Yd=ca,yH=tp,Dk=dn,Of=br,tm=cn,bH=up,_H=Ok,$H=da,xH=Fc,SH=Ke,wH=zb,TH=SH("toStringTag"),zd=Error,EH=[].push,qu=function(t,r){var n=arguments.length>2?arguments[2]:void 0,a=mH(rm,this),i;Yd?i=Yd(new zd,a?gH(this):rm):(i=a?this:Dk(rm),Of(i,TH,"Error")),r!==void 0&&Of(i,"message",xH(r)),wH&&Of(i,"stack",bH(i.stack,1)),_H(i,n);var o=[];return $H(t,EH,{that:o}),Of(i,"errors",o),i};Yd?Yd(qu,zd):yH(qu,zd,{name:!0});var rm=qu.prototype=Dk(zd.prototype,{constructor:tm(1,qu),message:tm(1,""),name:tm(1,"AggregateError")});hH({global:!0,constructor:!0,arity:2},{AggregateError:qu});var AH=C,OH=Et,CH=vn,SS=le,IH=kk,Xb="AggregateError",wS=OH(Xb),TS=!SS(function(){return wS([1]).errors[0]!==1})&&SS(function(){return wS([1],Xb,{cause:7}).cause!==7});AH({global:!0,constructor:!0,arity:2,forced:TS},{AggregateError:IH(Xb,function(e){return function(r,n){return CH(e,this,arguments)}},TS,!0)});var kH=Ke,PH=dn,RH=ht.f,$y=kH("unscopables"),xy=Array.prototype;xy[$y]==null&&RH(xy,$y,{configurable:!0,value:PH(null)});var Xa=function(e){xy[$y][e]=!0},MH=C,LH=$t,DH=Ct,NH=Zt,FH=Xa;MH({target:"Array",proto:!0},{at:function(t){var r=LH(this),n=DH(r),a=NH(t),i=a>=0?a:n+a;return i<0||i>=n?void 0:r[i]}});FH("at");var VH=TypeError,jH=9007199254740991,Jb=function(e){if(e>jH)throw VH("Maximum allowed index exceeded");return e},BH=le,HH=Ke,UH=Gi,GH=HH("species"),Bc=function(e){return UH>=51||!BH(function(){var t=[],r=t.constructor={};return r[GH]=function(){return{foo:1}},t[e](Boolean).foo!==1})},WH=C,YH=le,zH=Yo,qH=qe,KH=$t,ZH=Ct,ES=Jb,AS=Za,XH=Lc,JH=Bc,QH=Ke,eU=Gi,Nk=QH("isConcatSpreadable"),tU=eU>=51||!YH(function(){var e=[];return e[Nk]=!1,e.concat()[0]!==e}),rU=JH("concat"),nU=function(e){if(!qH(e))return!1;var t=e[Nk];return t!==void 0?!!t:zH(e)},aU=!tU||!rU;WH({target:"Array",proto:!0,arity:1,forced:aU},{concat:function(t){var r=KH(this),n=XH(r,0),a=0,i,o,l,u,f;for(i=-1,l=arguments.length;i2?arguments[2]:void 0,u=uU((l===void 0?a:nm(l,a))-o,a-i),f=1;for(o0;)o in n?n[i]=n[o]:lU(n,i),i+=f,o+=f;return n},cU=C,fU=Fk,dU=Xa;cU({target:"Array",proto:!0},{copyWithin:fU});dU("copyWithin");var vU=le,Ja=function(e,t){var r=[][e];return!!r&&vU(function(){r.call(null,t||function(){return 1},1)})},pU=C,hU=tr.every,mU=Ja,gU=mU("every");pU({target:"Array",proto:!0,forced:!gU},{every:function(t){return hU(this,t,arguments.length>1?arguments[1]:void 0)}});var yU=$t,CS=qa,bU=Ct,e0=function(t){for(var r=yU(this),n=bU(r),a=arguments.length,i=CS(a>1?arguments[1]:void 0,n),o=a>2?arguments[2]:void 0,l=o===void 0?n:CS(o,n);l>i;)r[i++]=t;return r},_U=C,$U=e0,xU=Xa;_U({target:"Array",proto:!0},{fill:$U});xU("fill");var SU=C,wU=tr.filter,TU=Bc,EU=TU("filter");SU({target:"Array",proto:!0,forced:!EU},{filter:function(t){return wU(this,t,arguments.length>1?arguments[1]:void 0)}});var AU=C,OU=tr.find,CU=Xa,Sy="find",Vk=!0;Sy in[]&&Array(1)[Sy](function(){Vk=!1});AU({target:"Array",proto:!0,forced:Vk},{find:function(t){return OU(this,t,arguments.length>1?arguments[1]:void 0)}});CU(Sy);var IU=C,kU=tr.findIndex,PU=Xa,wy="findIndex",jk=!0;wy in[]&&Array(1)[wy](function(){jk=!1});IU({target:"Array",proto:!0,forced:jk},{findIndex:function(t){return kU(this,t,arguments.length>1?arguments[1]:void 0)}});PU(wy);var RU=Yo,MU=Ct,LU=Jb,DU=ua,Bk=function(e,t,r,n,a,i,o,l){for(var u=a,f=0,d=o?DU(o,l):!1,s,c;f0&&RU(s)?(c=MU(s),u=Bk(e,t,s,c,u,i-1)-1):(LU(u+1),e[u]=s),u++),f++;return u},Hk=Bk,NU=C,FU=Hk,VU=$t,jU=Ct,BU=Zt,HU=Lc;NU({target:"Array",proto:!0},{flat:function(){var t=arguments.length?arguments[0]:void 0,r=VU(this),n=jU(r),a=HU(r,0);return a.length=FU(a,r,r,n,0,t===void 0?1:BU(t)),a}});var UU=C,GU=Hk,WU=qt,YU=$t,zU=Ct,qU=Lc;UU({target:"Array",proto:!0},{flatMap:function(t){var r=YU(this),n=zU(r),a;return WU(t),a=qU(r,0),a.length=GU(a,r,r,n,0,1,t,arguments.length>1?arguments[1]:void 0),a}});var KU=tr.forEach,ZU=Ja,XU=ZU("forEach"),Uk=XU?[].forEach:function(t){return KU(this,t,arguments.length>1?arguments[1]:void 0)},JU=C,IS=Uk;JU({target:"Array",proto:!0,forced:[].forEach!=IS},{forEach:IS});var QU=Ge,e9=Lk,t9=function(e,t,r,n){try{return n?t(QU(r)[0],r[1]):t(r)}catch(a){e9(e,"throw",a)}},r9=ua,n9=Ye,a9=$t,i9=t9,o9=Zb,s9=wl,l9=Ct,kS=Za,u9=cp,c9=jc,PS=Array,Gk=function(t){var r=a9(t),n=s9(this),a=arguments.length,i=a>1?arguments[1]:void 0,o=i!==void 0;o&&(i=r9(i,a>2?arguments[2]:void 0));var l=c9(r),u=0,f,d,s,c,v,p;if(l&&!(this===PS&&o9(l)))for(c=u9(r,l),v=c.next,d=n?new this:[];!(s=n9(v,c)).done;u++)p=o?i9(c,i,[s.value,u],!0):s.value,kS(d,u,p);else for(f=l9(r),d=n?new this(f):PS(f);f>u;u++)p=o?i(r[u],u):r[u],kS(d,u,p);return d.length=u,d},f9=Ke,Wk=f9("iterator"),Yk=!1;try{var d9=0,RS={next:function(){return{done:!!d9++}},return:function(){Yk=!0}};RS[Wk]=function(){return this},Array.from(RS,function(){throw 2})}catch{}var fp=function(e,t){if(!t&&!Yk)return!1;var r=!1;try{var n={};n[Wk]=function(){return{next:function(){return{done:r=!0}}}},e(n)}catch{}return r},v9=C,p9=Gk,h9=fp,m9=!h9(function(e){Array.from(e)});v9({target:"Array",stat:!0,forced:m9},{from:p9});var g9=C,y9=Cc.includes,b9=le,_9=Xa,$9=b9(function(){return!Array(1).includes()});g9({target:"Array",proto:!0,forced:$9},{includes:function(t){return y9(this,t,arguments.length>1?arguments[1]:void 0)}});_9("includes");var x9=C,S9=ue,w9=Cc.indexOf,T9=Ja,Ty=S9([].indexOf),MS=!!Ty&&1/Ty([1],1,-0)<0,E9=T9("indexOf");x9({target:"Array",proto:!0,forced:MS||!E9},{indexOf:function(t){var r=arguments.length>1?arguments[1]:void 0;return MS?Ty(this,t,r)||0:w9(this,t,r)}});var A9=C,O9=Yo;A9({target:"Array",stat:!0},{isArray:O9});var C9=le,I9=Qe,LS=pn,k9=Ot,P9=Ke,Ey=P9("iterator"),zk=!1,Fo,am,im;[].keys&&(im=[].keys(),"next"in im?(am=LS(LS(im)),am!==Object.prototype&&(Fo=am)):zk=!0);var R9=Fo==null||C9(function(){var e={};return Fo[Ey].call(e)!==e});R9&&(Fo={});I9(Fo[Ey])||k9(Fo,Ey,function(){return this});var qk={IteratorPrototype:Fo,BUGGY_SAFARI_ITERATORS:zk},M9=qk.IteratorPrototype,L9=dn,D9=cn,N9=Ur,F9=Vc,V9=function(){return this},t0=function(e,t,r,n){var a=t+" Iterator";return e.prototype=L9(M9,{next:D9(+!n,r)}),N9(e,a,!1),F9[a]=V9,e},j9=C,B9=Ye,Kk=Sl,H9=Qe,U9=t0,DS=pn,NS=ca,G9=Ur,W9=br,om=Ot,Y9=Ke,z9=Vc,Zk=qk,q9=Kk.PROPER,K9=Kk.CONFIGURABLE,FS=Zk.IteratorPrototype,Cf=Zk.BUGGY_SAFARI_ITERATORS,jl=Y9("iterator"),VS="keys",Bl="values",jS="entries",Z9=function(){return this},r0=function(e,t,r,n,a,i,o){U9(r,t,n);var l=function(g){if(g===a&&c)return c;if(!Cf&&g in d)return d[g];switch(g){case VS:return function(){return new r(this,g)};case Bl:return function(){return new r(this,g)};case jS:return function(){return new r(this,g)}}return function(){return new r(this)}},u=t+" Iterator",f=!1,d=e.prototype,s=d[jl]||d["@@iterator"]||a&&d[a],c=!Cf&&s||l(a),v=t=="Array"&&d.entries||s,p,h,m;if(v&&(p=DS(v.call(new e)),p!==Object.prototype&&p.next&&(DS(p)!==FS&&(NS?NS(p,FS):H9(p[jl])||om(p,jl,Z9)),G9(p,u,!0))),q9&&a==Bl&&s&&s.name!==Bl&&(K9?W9(d,"name",Bl):(f=!0,c=function(){return B9(s,this)})),a)if(h={values:l(Bl),keys:i?c:l(VS),entries:l(jS)},o)for(m in h)(Cf||f||!(m in d))&&om(d,m,h[m]);else j9({target:t,proto:!0,forced:Cf||f},h);return d[jl]!==c&&om(d,jl,c,{name:a}),z9[t]=c,h},X9=Or,n0=Xa,BS=Vc,Xk=Kt,J9=ht.f,Q9=r0,eG=Ve,Jk="Array Iterator",tG=Xk.set,rG=Xk.getterFor(Jk),Qk=Q9(Array,"Array",function(e,t){tG(this,{type:Jk,target:X9(e),index:0,kind:t})},function(){var e=rG(this),t=e.target,r=e.kind,n=e.index++;return!t||n>=t.length?(e.target=void 0,{value:void 0,done:!0}):r=="keys"?{value:n,done:!1}:r=="values"?{value:t[n],done:!1}:{value:[n,t[n]],done:!1}},"values"),HS=BS.Arguments=BS.Array;n0("keys");n0("values");n0("entries");if(eG&&HS.name!=="values")try{J9(HS,"name",{value:"values"})}catch{}var nG=C,aG=ue,iG=Ac,oG=Or,sG=Ja,lG=aG([].join),uG=iG!=Object,cG=sG("join",",");nG({target:"Array",proto:!0,forced:uG||!cG},{join:function(t){return lG(oG(this),t===void 0?",":t)}});var fG=vn,dG=Or,vG=Zt,pG=Ct,hG=Ja,mG=Math.min,Ay=[].lastIndexOf,eP=!!Ay&&1/[1].lastIndexOf(1,-0)<0,gG=hG("lastIndexOf"),yG=eP||!gG,tP=yG?function(t){if(eP)return fG(Ay,this,arguments)||0;var r=dG(this),n=pG(r),a=n-1;for(arguments.length>1&&(a=mG(a,vG(arguments[1]))),a<0&&(a=n+a);a>=0;a--)if(a in r&&r[a]===t)return a||0;return-1}:Ay,bG=C,US=tP;bG({target:"Array",proto:!0,forced:US!==[].lastIndexOf},{lastIndexOf:US});var _G=C,$G=tr.map,xG=Bc,SG=xG("map");_G({target:"Array",proto:!0,forced:!SG},{map:function(t){return $G(this,t,arguments.length>1?arguments[1]:void 0)}});var wG=C,TG=le,EG=wl,AG=Za,rP=Array,OG=TG(function(){function e(){}return!(rP.of.call(e)instanceof e)});wG({target:"Array",stat:!0,forced:OG},{of:function(){for(var t=0,r=arguments.length,n=new(EG(this)?this:rP)(r);r>t;)AG(n,t,arguments[t++]);return n.length=r,n}});var CG=qt,IG=$t,kG=Ac,PG=Ct,RG=TypeError,GS=function(e){return function(t,r,n,a){CG(r);var i=IG(t),o=kG(i),l=PG(i),u=e?l-1:0,f=e?-1:1;if(n<2)for(;;){if(u in o){a=o[u],u+=f;break}if(u+=f,e?u<0:l<=u)throw RG("Reduce of empty array with no initial value")}for(;e?u>=0:l>u;u+=f)u in o&&(a=r(a,o[u],u,i));return a}},dp={left:GS(!1),right:GS(!0)},MG=Br,LG=Se,Ko=MG(LG.process)=="process",DG=C,NG=dp.left,FG=Ja,WS=Gi,VG=Ko,jG=FG("reduce"),BG=!VG&&WS>79&&WS<83;DG({target:"Array",proto:!0,forced:!jG||BG},{reduce:function(t){var r=arguments.length;return NG(this,t,r,r>1?arguments[1]:void 0)}});var HG=C,UG=dp.right,GG=Ja,YS=Gi,WG=Ko,YG=GG("reduceRight"),zG=!WG&&YS>79&&YS<83;HG({target:"Array",proto:!0,forced:!YG||zG},{reduceRight:function(t){return UG(this,t,arguments.length,arguments.length>1?arguments[1]:void 0)}});var qG=C,KG=ue,ZG=Yo,XG=KG([].reverse),zS=[1,2];qG({target:"Array",proto:!0,forced:String(zS)===String(zS.reverse())},{reverse:function(){return ZG(this)&&(this.length=this.length),XG(this)}});var JG=C,qS=Yo,QG=wl,eW=qe,KS=qa,tW=Ct,rW=Or,nW=Za,aW=Ke,iW=Bc,oW=zo,sW=iW("slice"),lW=aW("species"),sm=Array,uW=Math.max;JG({target:"Array",proto:!0,forced:!sW},{slice:function(t,r){var n=rW(this),a=tW(n),i=KS(t,a),o=KS(r===void 0?a:r,a),l,u,f;if(qS(n)&&(l=n.constructor,QG(l)&&(l===sm||qS(l.prototype))?l=void 0:eW(l)&&(l=l[lW],l===null&&(l=void 0)),l===sm||l===void 0))return oW(n,i,o);for(u=new(l===void 0?sm:l)(uW(o-i,0)),f=0;i1?arguments[1]:void 0)}});var ZS=Mc,pW=Math.floor,Oy=function(e,t){var r=e.length,n=pW(r/2);return r<8?hW(e,t):mW(e,Oy(ZS(e,0,n),t),Oy(ZS(e,n),t),t)},hW=function(e,t){for(var r=e.length,n=1,a,i;n0;)e[i]=e[--i];i!==n++&&(e[i]=a)}return e},mW=function(e,t,r,n){for(var a=t.length,i=r.length,o=0,l=0;o3)){if(AW)return!0;if(rw)return rw<603;var e="",t,r,n,a;for(t=65;t<76;t++){switch(r=String.fromCharCode(t),t){case 66:case 69:case 70:case 72:n=3;break;case 68:case 71:n=4;break;default:n=2}for(a=0;a<47;a++)Ci.push({k:r+a,v:n})}for(Ci.sort(function(i,o){return o.v-i.v}),a=0;aQS(r)?1:-1}};_W({target:"Array",proto:!0,forced:PW},{sort:function(t){t!==void 0&&$W(t);var r=xW(this);if(oP)return t===void 0?nw(r):nw(r,t);var n=[],a=SW(r),i,o;for(o=0;oa-u+l;d--)lm(n,d-1)}else if(l>u)for(d=a-u;d>i;d--)s=d+u-1,c=d+l-1,s in n?n[c]=n[s]:lm(n,c);for(d=0;d>1,l=t===23?Ta(2,-24)-Ta(2,-77):0,u=e<0||e===0&&1/e<0?1:0,f=0,d,s,c;for(e=oY(e),e!=e||e===1/0?(s=e!=e?1:0,d=i):(d=sY(lY(e)/uY),c=Ta(2,-d),e*c<1&&(d--,c*=2),d+o>=1?e+=l/c:e+=l*Ta(2,1-o),e*c>=2&&(d++,c/=2),d+o>=i?(s=0,d=i):d+o>=1?(s=(e*c-1)*Ta(2,t),d=d+o):(s=e*Ta(2,o-1)*Ta(2,t),d=0));t>=8;)n[f++]=s&255,s/=256,t-=8;for(d=d<0;)n[f++]=d&255,d/=256,a-=8;return n[--f]|=u*128,n},fY=function(e,t){var r=e.length,n=r*8-t-1,a=(1<>1,o=n-7,l=r-1,u=e[l--],f=u&127,d;for(u>>=7;o>0;)f=f*256+e[l--],o-=8;for(d=f&(1<<-o)-1,f>>=-o,o+=t;o>0;)d=d*256+e[l--],o-=8;if(f===0)f=1-i;else{if(f===a)return d?NaN:u?-1/0:1/0;d=d+Ta(2,t),f=f-i}return(u?-1:1)*d*Ta(2,f-t)},dY={pack:cY,unpack:fY},vp=Se,l0=ue,um=Ve,vY=s0,lP=Sl,iw=br,ow=Hc,cm=le,If=va,pY=Zt,hY=Hr,qd=sP,uP=dY,mY=pn,sw=ca,gY=za.f,yY=ht.f,bY=e0,_Y=Mc,cP=Ur,fP=Kt,$Y=lP.PROPER,lw=lP.CONFIGURABLE,sl=fP.get,uw=fP.set,Kd="ArrayBuffer",dP="DataView",Gs="prototype",xY="Wrong length",vP="Wrong index",xn=vp[Kd],Pr=xn,fs=Pr&&Pr[Gs],Kn=vp[dP],ao=Kn&&Kn[Gs],cw=Object.prototype,SY=vp.Array,Zd=vp.RangeError,wY=l0(bY),TY=l0([].reverse),pP=uP.pack,fw=uP.unpack,dw=function(e){return[e&255]},vw=function(e){return[e&255,e>>8&255]},pw=function(e){return[e&255,e>>8&255,e>>16&255,e>>24&255]},hw=function(e){return e[3]<<24|e[2]<<16|e[1]<<8|e[0]},EY=function(e){return pP(e,23,4)},AY=function(e){return pP(e,52,8)},kf=function(e,t){yY(e[Gs],t,{get:function(){return sl(this)[t]}})},fi=function(e,t,r,n){var a=qd(r),i=sl(e);if(a+t>i.byteLength)throw Zd(vP);var o=sl(i.buffer).bytes,l=a+i.byteOffset,u=_Y(o,l,l+t);return n?u:TY(u)},di=function(e,t,r,n,a,i){var o=qd(r),l=sl(e);if(o+t>l.byteLength)throw Zd(vP);for(var u=sl(l.buffer).bytes,f=o+l.byteOffset,d=n(+a),s=0;sa)throw Zd("Wrong offset");if(n=n===void 0?a-i:hY(n),i+n>a)throw Zd(xY);uw(this,{buffer:t,byteLength:n,byteOffset:i}),um||(this.buffer=t,this.byteLength=n,this.byteOffset=i)},ao=Kn[Gs],um&&(kf(Pr,"byteLength"),kf(Kn,"buffer"),kf(Kn,"byteLength"),kf(Kn,"byteOffset")),ow(ao,{getInt8:function(t){return fi(this,1,t)[0]<<24>>24},getUint8:function(t){return fi(this,1,t)[0]},getInt16:function(t){var r=fi(this,2,t,arguments.length>1?arguments[1]:void 0);return(r[1]<<8|r[0])<<16>>16},getUint16:function(t){var r=fi(this,2,t,arguments.length>1?arguments[1]:void 0);return r[1]<<8|r[0]},getInt32:function(t){return hw(fi(this,4,t,arguments.length>1?arguments[1]:void 0))},getUint32:function(t){return hw(fi(this,4,t,arguments.length>1?arguments[1]:void 0))>>>0},getFloat32:function(t){return fw(fi(this,4,t,arguments.length>1?arguments[1]:void 0),23)},getFloat64:function(t){return fw(fi(this,8,t,arguments.length>1?arguments[1]:void 0),52)},setInt8:function(t,r){di(this,1,t,dw,r)},setUint8:function(t,r){di(this,1,t,dw,r)},setInt16:function(t,r){di(this,2,t,vw,r,arguments.length>2?arguments[2]:void 0)},setUint16:function(t,r){di(this,2,t,vw,r,arguments.length>2?arguments[2]:void 0)},setInt32:function(t,r){di(this,4,t,pw,r,arguments.length>2?arguments[2]:void 0)},setUint32:function(t,r){di(this,4,t,pw,r,arguments.length>2?arguments[2]:void 0)},setFloat32:function(t,r){di(this,4,t,EY,r,arguments.length>2?arguments[2]:void 0)},setFloat64:function(t,r){di(this,8,t,AY,r,arguments.length>2?arguments[2]:void 0)}});else{var mw=$Y&&xn.name!==Kd;if(!cm(function(){xn(1)})||!cm(function(){new xn(-1)})||cm(function(){return new xn,new xn(1.5),new xn(NaN),mw&&!lw})){Pr=function(t){return If(this,fs),new xn(qd(t))},Pr[Gs]=fs;for(var gw=gY(xn),yw=0,fm;gw.length>yw;)(fm=gw[yw++])in Pr||iw(Pr,fm,xn[fm]);fs.constructor=Pr}else mw&&lw&&iw(xn,"name",Kd);sw&&mY(ao)!==cw&&sw(ao,cw);var Pf=new Kn(new Pr(2)),bw=l0(ao.setInt8);Pf.setInt8(0,2147483648),Pf.setInt8(1,2147483649),(Pf.getInt8(0)||!Pf.getInt8(1))&&ow(ao,{setInt8:function(t,r){bw(this,t,r<<24>>24)},setUint8:function(t,r){bw(this,t,r<<24>>24)}},{unsafe:!0})}cP(Pr,Kd);cP(Kn,dP);var pp={ArrayBuffer:Pr,DataView:Kn},OY=C,CY=Se,IY=pp,kY=El,u0="ArrayBuffer",_w=IY[u0],PY=CY[u0];OY({global:!0,constructor:!0,forced:PY!==_w},{ArrayBuffer:_w});kY(u0);var RY=s0,c0=Ve,gr=Se,hP=Qe,f0=qe,Vo=at,d0=Ka,MY=Wo,v0=br,Cy=Ot,LY=ht.f,DY=fn,p0=pn,Al=ca,NY=Ke,mP=xl,Xd=gr.Int8Array,Iy=Xd&&Xd.prototype,$w=gr.Uint8ClampedArray,xw=$w&&$w.prototype,ta=Xd&&p0(Xd),Cn=Iy&&p0(Iy),FY=Object.prototype,h0=gr.TypeError,Sw=NY("toStringTag"),ky=mP("TYPED_ARRAY_TAG"),m0=mP("TYPED_ARRAY_CONSTRUCTOR"),Ma=RY&&!!Al&&d0(gr.opera)!=="Opera",gP=!1,Tr,Ii,Ws,La={Int8Array:1,Uint8Array:1,Uint8ClampedArray:1,Int16Array:2,Uint16Array:2,Int32Array:4,Uint32Array:4,Float32Array:4,Float64Array:8},g0={BigInt64Array:8,BigUint64Array:8},VY=function(t){if(!f0(t))return!1;var r=d0(t);return r==="DataView"||Vo(La,r)||Vo(g0,r)},yP=function(e){if(!f0(e))return!1;var t=d0(e);return Vo(La,t)||Vo(g0,t)},jY=function(e){if(yP(e))return e;throw h0("Target is not a typed array")},BY=function(e){if(hP(e)&&(!Al||DY(ta,e)))return e;throw h0(MY(e)+" is not a typed array constructor")},HY=function(e,t,r,n){if(c0){if(r)for(var a in La){var i=gr[a];if(i&&Vo(i.prototype,e))try{delete i.prototype[e]}catch{try{i.prototype[e]=t}catch{}}}(!Cn[e]||r)&&Cy(Cn,e,r?t:Ma&&Iy[e]||t,n)}},UY=function(e,t,r){var n,a;if(c0){if(Al){if(r){for(n in La)if(a=gr[n],a&&Vo(a,e))try{delete a[e]}catch{}}if(!ta[e]||r)try{return Cy(ta,e,r?t:Ma&&ta[e]||t)}catch{}else return}for(n in La)a=gr[n],a&&(!a[e]||r)&&Cy(a,e,t)}};for(Tr in La)Ii=gr[Tr],Ws=Ii&&Ii.prototype,Ws?v0(Ws,m0,Ii):Ma=!1;for(Tr in g0)Ii=gr[Tr],Ws=Ii&&Ii.prototype,Ws&&v0(Ws,m0,Ii);if((!Ma||!hP(ta)||ta===Function.prototype)&&(ta=function(){throw h0("Incorrect invocation")},Ma))for(Tr in La)gr[Tr]&&Al(gr[Tr],ta);if((!Ma||!Cn||Cn===FY)&&(Cn=ta.prototype,Ma))for(Tr in La)gr[Tr]&&Al(gr[Tr].prototype,Cn);Ma&&p0(xw)!==Cn&&Al(xw,Cn);if(c0&&!Vo(Cn,Sw)){gP=!0,LY(Cn,Sw,{get:function(){return f0(this)?this[ky]:void 0}});for(Tr in La)gr[Tr]&&v0(gr[Tr],ky,Tr)}var dt={NATIVE_ARRAY_BUFFER_VIEWS:Ma,TYPED_ARRAY_CONSTRUCTOR:m0,TYPED_ARRAY_TAG:gP&&ky,aTypedArray:jY,aTypedArrayConstructor:BY,exportTypedArrayMethod:HY,exportTypedArrayStaticMethod:UY,isView:VY,isTypedArray:yP,TypedArray:ta,TypedArrayPrototype:Cn},GY=C,bP=dt,WY=bP.NATIVE_ARRAY_BUFFER_VIEWS;GY({target:"ArrayBuffer",stat:!0,forced:!WY},{isView:bP.isView});var YY=wl,zY=Wo,qY=TypeError,y0=function(e){if(YY(e))return e;throw qY(zY(e)+" is not a constructor")},ww=Ge,KY=y0,ZY=Ke,XY=ZY("species"),Ol=function(e,t){var r=ww(e).constructor,n;return r===void 0||(n=ww(r)[XY])==null?t:KY(n)},JY=C,b0=ue,QY=le,_P=pp,Tw=Ge,Ew=qa,ez=Hr,tz=Ol,_0=_P.ArrayBuffer,Py=_P.DataView,$P=Py.prototype,Aw=b0(_0.prototype.slice),rz=b0($P.getUint8),nz=b0($P.setUint8),az=QY(function(){return!new _0(2).slice(1,void 0).byteLength});JY({target:"ArrayBuffer",proto:!0,unsafe:!0,forced:az},{slice:function(t,r){if(Aw&&r===void 0)return Aw(Tw(this),t);for(var n=Tw(this).byteLength,a=Ew(t,n),i=Ew(r===void 0?n:r,n),o=new(tz(this,_0))(ez(i-a)),l=new Py(this),u=new Py(o),f=0;a0;(a>>>=1)&&(r+=r))a&1&&(n+=r);return n},TP=ue,Tz=Hr,Ow=et,Ez=hp,Az=zt,Oz=TP(Ez),Cz=TP("".slice),Iz=Math.ceil,Cw=function(e){return function(t,r,n){var a=Ow(Az(t)),i=Tz(r),o=a.length,l=n===void 0?" ":Ow(n),u,f;return i<=o||l==""?a:(u=i-o,f=Oz(l,Iz(u/l.length)),f.length>u&&(f=Cz(f,0,u)),e?a+f:f+a)}},$0={start:Cw(!1),end:Cw(!0)},Yi=ue,Iw=le,io=$0.start,kz=RangeError,Pz=Math.abs,Qa=Date.prototype,dm=Qa.toISOString,Rz=Yi(Qa.getTime),Mz=Yi(Qa.getUTCDate),Lz=Yi(Qa.getUTCFullYear),Dz=Yi(Qa.getUTCHours),Nz=Yi(Qa.getUTCMilliseconds),Fz=Yi(Qa.getUTCMinutes),Vz=Yi(Qa.getUTCMonth),jz=Yi(Qa.getUTCSeconds),Bz=Iw(function(){return dm.call(new Date(-5e13-1))!="0385-07-25T07:06:39.999Z"})||!Iw(function(){dm.call(new Date(NaN))})?function(){if(!isFinite(Rz(this)))throw kz("Invalid time value");var t=this,r=Lz(t),n=Nz(t),a=r<0?"-":r>9999?"+":"";return a+io(Pz(r),a?6:4,0)+"-"+io(Vz(t)+1,2,0)+"-"+io(Mz(t),2,0)+"T"+io(Dz(t),2,0)+":"+io(Fz(t),2,0)+":"+io(jz(t),2,0)+"."+io(n,3,0)+"Z"}:dm,Hz=C,kw=Bz;Hz({target:"Date",proto:!0,forced:Date.prototype.toISOString!==kw},{toISOString:kw});var Uz=C,Gz=le,Wz=$t,Yz=Xv,zz=Gz(function(){return new Date(NaN).toJSON()!==null||Date.prototype.toJSON.call({toISOString:function(){return 1}})!==1});Uz({target:"Date",proto:!0,arity:1,forced:zz},{toJSON:function(t){var r=Wz(this),n=Yz(r,"number");return typeof n=="number"&&!isFinite(n)?null:r.toISOString()}});var qz=Ge,Kz=LI,Zz=TypeError,Xz=function(e){if(qz(this),e==="string"||e==="default")e="string";else if(e!=="number")throw Zz("Incorrect hint");return Kz(this,e)},Jz=at,Qz=Ot,eq=Xz,tq=Ke,Pw=tq("toPrimitive"),Rw=Date.prototype;Jz(Rw,Pw)||Qz(Rw,Pw,eq);var EP=ue,rq=Ot,x0=Date.prototype,Mw="Invalid Date",AP="toString",nq=EP(x0[AP]),aq=EP(x0.getTime);String(new Date(NaN))!=Mw&&rq(x0,AP,function(){var t=aq(this);return t===t?nq(this):Mw});var iq=C,Uc=ue,oq=et,sq=Uc("".charAt),lq=Uc("".charCodeAt),uq=Uc(/./.exec),cq=Uc(1 .toString),fq=Uc("".toUpperCase),dq=/[\w*+\-./@]/,Lw=function(e,t){for(var r=cq(e,16);r.length1?arguments[1]:void 0),v;v=v?v.next:s.first;)for(c(v.value,v.key,this);v&&v.removed;)v=v.previous},has:function(d){return!!u(this,d)}}),Uw(i,r?{get:function(d){var s=u(this,d);return s&&s.value},set:function(d,s){return l(this,d===0?0:d,s)}}:{add:function(d){return l(this,d=d===0?0:d,d)}}),Hl&&pK(i,"size",{get:function(){return o(this).size}}),a},setStrong:function(e,t,r){var n=t+" Iterator",a=gm(t),i=gm(n);bK(e,t,function(o,l){Ww(this,{type:n,target:o,state:a(o),kind:l,last:void 0})},function(){for(var o=i(this),l=o.kind,u=o.last;u&&u.removed;)u=u.previous;return!o.target||!(o.last=u=u?u.next:o.state.first)?(o.target=void 0,{value:void 0,done:!0}):l=="keys"?{value:u.key,done:!1}:l=="values"?{value:u.value,done:!1}:{value:[u.key,u.value],done:!1}},r?"entries":"values",!r,!0),_K(t)}},$K=gp,xK=DP;$K("Map",function(e){return function(){return e(this,arguments.length?arguments[0]:void 0)}},xK);var SK=Math.log,NP=Math.log1p||function(t){var r=+t;return r>-1e-8&&r<1e-8?r-r*r/2:SK(1+r)},wK=C,TK=NP,ym=Math.acosh,EK=Math.log,Yw=Math.sqrt,AK=Math.LN2,OK=!ym||Math.floor(ym(Number.MAX_VALUE))!=710||ym(1/0)!=1/0;wK({target:"Math",stat:!0,forced:OK},{acosh:function(t){var r=+t;return r<1?NaN:r>9490626562425156e-8?EK(r)+AK:TK(r-1+Yw(r-1)*Yw(r+1))}});var CK=C,zw=Math.asinh,IK=Math.log,kK=Math.sqrt;function FP(e){var t=+e;return!isFinite(t)||t==0?t:t<0?-FP(-t):IK(t+kK(t*t+1))}CK({target:"Math",stat:!0,forced:!(zw&&1/zw(0)>0)},{asinh:FP});var PK=C,qw=Math.atanh,RK=Math.log;PK({target:"Math",stat:!0,forced:!(qw&&1/qw(-0)<0)},{atanh:function(t){var r=+t;return r==0?r:RK((1+r)/(1-r))/2}});var A0=Math.sign||function(t){var r=+t;return r==0||r!=r?r:r<0?-1:1},MK=C,LK=A0,DK=Math.abs,NK=Math.pow;MK({target:"Math",stat:!0},{cbrt:function(t){var r=+t;return LK(r)*NK(DK(r),1/3)}});var FK=C,VK=Math.floor,jK=Math.log,BK=Math.LOG2E;FK({target:"Math",stat:!0},{clz32:function(t){var r=t>>>0;return r?31-VK(jK(r+.5)*BK):32}});var Ul=Math.expm1,HK=Math.exp,yp=!Ul||Ul(10)>22025.465794806718||Ul(10)<22025.465794806718||Ul(-2e-17)!=-2e-17?function(t){var r=+t;return r==0?r:r>-1e-6&&r<1e-6?r+r*r/2:HK(r)-1}:Ul,UK=C,GK=yp,Kw=Math.cosh,WK=Math.abs,bm=Math.E;UK({target:"Math",stat:!0,forced:!Kw||Kw(710)===1/0},{cosh:function(t){var r=GK(WK(t)-1)+1;return(r+1/(r*bm*bm))*(bm/2)}});var YK=C,Zw=yp;YK({target:"Math",stat:!0,forced:Zw!=Math.expm1},{expm1:Zw});var zK=A0,qK=Math.abs,bp=Math.pow,Ry=bp(2,-52),Td=bp(2,-23),KK=bp(2,127)*(2-Td),_m=bp(2,-126),ZK=function(e){return e+1/Ry-1/Ry},XK=Math.fround||function(t){var r=+t,n=qK(r),a=zK(r),i,o;return n<_m?a*ZK(n/_m/Td)*_m*Td:(i=(1+Td/Ry)*n,o=i-(i-n),o>KK||o!=o?a*(1/0):a*o)},JK=C,QK=XK;JK({target:"Math",stat:!0},{fround:QK});var eZ=C,Xw=Math.hypot,tZ=Math.abs,rZ=Math.sqrt,nZ=!!Xw&&Xw(1/0,NaN)!==1/0;eZ({target:"Math",stat:!0,arity:2,forced:nZ},{hypot:function(t,r){for(var n=0,a=0,i=arguments.length,o=0,l,u;a0?(u=l/o,n+=u*u):n+=l;return o===1/0?1/0:o*rZ(n)}});var aZ=C,iZ=le,Jw=Math.imul,oZ=iZ(function(){return Jw(4294967295,5)!=-5||Jw.length!=2});aZ({target:"Math",stat:!0,forced:oZ},{imul:function(t,r){var n=65535,a=+t,i=+r,o=n&a,l=n&i;return 0|o*l+((n&a>>>16)*l+o*(n&i>>>16)<<16>>>0)}});var sZ=Math.log,lZ=Math.LOG10E,VP=Math.log10||function(t){return sZ(t)*lZ},uZ=C,cZ=VP;uZ({target:"Math",stat:!0},{log10:cZ});var fZ=C,dZ=NP;fZ({target:"Math",stat:!0},{log1p:dZ});var vZ=C,pZ=Math.log,hZ=Math.LN2;vZ({target:"Math",stat:!0},{log2:function(t){return pZ(t)/hZ}});var mZ=C,gZ=A0;mZ({target:"Math",stat:!0},{sign:gZ});var yZ=C,bZ=le,Qw=yp,_Z=Math.abs,e2=Math.exp,$Z=Math.E,xZ=bZ(function(){return Math.sinh(-2e-17)!=-2e-17});yZ({target:"Math",stat:!0,forced:xZ},{sinh:function(t){var r=+t;return _Z(r)<1?(Qw(r)-Qw(-r))/2:(e2(r-1)-e2(-r-1))*($Z/2)}});var SZ=C,t2=yp,r2=Math.exp;SZ({target:"Math",stat:!0},{tanh:function(t){var r=+t,n=t2(r),a=t2(-r);return n==1/0?1:a==1/0?-1:(n-a)/(r2(r)+r2(-r))}});var wZ=Ur;wZ(Math,"Math",!0);var TZ=C,EZ=WI;TZ({target:"Math",stat:!0},{trunc:EZ});var AZ=ue,_p=AZ(1 .valueOf),$p=` -\v\f\r    â€â€‚         âŸã€€\u2028\u2029\uFEFF`,OZ=ue,CZ=zt,IZ=et,kZ=$p,n2=OZ("".replace),Jd="["+kZ+"]",PZ=RegExp("^"+Jd+Jd+"*"),RZ=RegExp(Jd+Jd+"*$"),$m=function(e){return function(t){var r=IZ(CZ(t));return e&1&&(r=n2(r,PZ,"")),e&2&&(r=n2(r,RZ,"")),r}},Cl={start:$m(1),end:$m(2),trim:$m(3)},MZ=Ve,O0=Se,jP=ue,LZ=Pc,DZ=Ot,a2=at,NZ=Tl,FZ=fn,VZ=Go,BP=Xv,jZ=le,BZ=za.f,HZ=er.f,UZ=ht.f,GZ=_p,WZ=Cl.trim,My="Number",xi=O0[My],xm=xi.prototype,YZ=O0.TypeError,zZ=jP("".slice),Rf=jP("".charCodeAt),qZ=function(e){var t=BP(e,"number");return typeof t=="bigint"?t:KZ(t)},KZ=function(e){var t=BP(e,"number"),r,n,a,i,o,l,u,f;if(VZ(t))throw YZ("Cannot convert a Symbol value to a number");if(typeof t=="string"&&t.length>2){if(t=WZ(t),r=Rf(t,0),r===43||r===45){if(n=Rf(t,2),n===88||n===120)return NaN}else if(r===48){switch(Rf(t,1)){case 66:case 98:a=2,i=49;break;case 79:case 111:a=8,i=55;break;default:return+t}for(o=zZ(t,2),l=o.length,u=0;ui)return NaN;return parseInt(o,a)}}return+t};if(LZ(My,!xi(" 0o1")||!xi("0b1")||xi("+0x1"))){for(var ds=function(t){var r=arguments.length<1?0:xi(qZ(t)),n=this;return FZ(xm,n)&&jZ(function(){GZ(n)})?NZ(Object(r),n,ds):r},i2=MZ?BZ(xi):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,isFinite,isInteger,isNaN,isSafeInteger,parseFloat,parseInt,fromString,range".split(","),Sm=0,Mf;i2.length>Sm;Sm++)a2(xi,Mf=i2[Sm])&&!a2(ds,Mf)&&UZ(ds,Mf,HZ(xi,Mf));ds.prototype=xm,xm.constructor=ds,DZ(O0,My,ds,{constructor:!0})}var ZZ=C;ZZ({target:"Number",stat:!0},{EPSILON:Math.pow(2,-52)});var XZ=Se,JZ=XZ.isFinite,QZ=Number.isFinite||function(t){return typeof t=="number"&&JZ(t)},eX=C,tX=QZ;eX({target:"Number",stat:!0},{isFinite:tX});var rX=qe,nX=Math.floor,C0=Number.isInteger||function(t){return!rX(t)&&isFinite(t)&&nX(t)===t},aX=C,iX=C0;aX({target:"Number",stat:!0},{isInteger:iX});var oX=C;oX({target:"Number",stat:!0},{isNaN:function(t){return t!=t}});var sX=C,lX=C0,uX=Math.abs;sX({target:"Number",stat:!0},{isSafeInteger:function(t){return lX(t)&&uX(t)<=9007199254740991}});var cX=C;cX({target:"Number",stat:!0},{MAX_SAFE_INTEGER:9007199254740991});var fX=C;fX({target:"Number",stat:!0},{MIN_SAFE_INTEGER:-9007199254740991});var HP=Se,dX=le,vX=ue,pX=et,hX=Cl.trim,mX=$p,gX=vX("".charAt),Qd=HP.parseFloat,o2=HP.Symbol,s2=o2&&o2.iterator,yX=1/Qd(mX+"-0")!==-1/0||s2&&!dX(function(){Qd(Object(s2))}),UP=yX?function(t){var r=hX(pX(t)),n=Qd(r);return n===0&&gX(r,0)=="-"?-0:n}:Qd,bX=C,l2=UP;bX({target:"Number",stat:!0,forced:Number.parseFloat!=l2},{parseFloat:l2});var GP=Se,_X=le,$X=ue,xX=et,SX=Cl.trim,u2=$p,wu=GP.parseInt,c2=GP.Symbol,f2=c2&&c2.iterator,WP=/^[+-]?0x/i,wX=$X(WP.exec),TX=wu(u2+"08")!==8||wu(u2+"0x16")!==22||f2&&!_X(function(){wu(Object(f2))}),YP=TX?function(t,r){var n=SX(xX(t));return wu(n,r>>>0||(wX(WP,n)?16:10))}:wu,EX=C,d2=YP;EX({target:"Number",stat:!0,forced:Number.parseInt!=d2},{parseInt:d2});var AX=C,I0=ue,OX=Zt,CX=_p,IX=hp,kX=VP,ev=le,PX=RangeError,v2=String,RX=isFinite,MX=Math.abs,LX=Math.floor,p2=Math.pow,DX=Math.round,ra=I0(1 .toExponential),NX=I0(IX),h2=I0("".slice),zP=ra(-69e-12,4)==="-6.9000e-11"&&ra(1.255,2)==="1.25e+0"&&ra(12345,3)==="1.235e+4"&&ra(25,0)==="3e+1",FX=ev(function(){ra(1,1/0)})&&ev(function(){ra(1,-1/0)}),VX=!ev(function(){ra(1/0,1/0)})&&!ev(function(){ra(NaN,1/0)}),jX=!zP||!FX||!VX;AX({target:"Number",proto:!0,forced:jX},{toExponential:function(t){var r=CX(this);if(t===void 0)return ra(r);var n=OX(t);if(!RX(r))return String(r);if(n<0||n>20)throw PX("Incorrect fraction digits");if(zP)return ra(r,n);var a="",i="",o=0,l="",u="";if(r<0&&(a="-",r=-r),r===0)o=0,i=NX("0",n+1);else{var f=kX(r);o=LX(f);var d=0,s=p2(10,o-n);d=DX(r/s),2*r>=(2*d+1)*s&&(d+=1),d>=p2(10,n+1)&&(d/=10,o+=1),i=v2(d)}return n!==0&&(i=h2(i,0,1)+"."+h2(i,1)),o===0?(l="+",u="0"):(l=o>0?"+":"-",u=v2(MX(o))),i+="e"+l+u,a+i}});var BX=C,k0=ue,HX=Zt,UX=_p,GX=hp,m2=le,WX=RangeError,qP=String,KP=Math.floor,Ly=k0(GX),g2=k0("".slice),Gl=k0(1 .toFixed),Fs=function(e,t,r){return t===0?r:t%2===1?Fs(e,t-1,r*e):Fs(e*e,t/2,r)},YX=function(e){for(var t=0,r=e;r>=4096;)t+=12,r/=4096;for(;r>=2;)t+=1,r/=2;return t},vs=function(e,t,r){for(var n=-1,a=r;++n<6;)a+=t*e[n],e[n]=a%1e7,a=KP(a/1e7)},wm=function(e,t){for(var r=6,n=0;--r>=0;)n+=e[r],e[r]=KP(n/t),n=n%t*1e7},y2=function(e){for(var t=6,r="";--t>=0;)if(r!==""||t===0||e[t]!==0){var n=qP(e[t]);r=r===""?n:r+Ly("0",7-n.length)+n}return r},zX=m2(function(){return Gl(8e-5,3)!=="0.000"||Gl(.9,0)!=="1"||Gl(1.255,2)!=="1.25"||Gl(0xde0b6b3a7640080,0)!=="1000000000000000128"})||!m2(function(){Gl({})});BX({target:"Number",proto:!0,forced:zX},{toFixed:function(t){var r=UX(this),n=HX(t),a=[0,0,0,0,0,0],i="",o="0",l,u,f,d;if(n<0||n>20)throw WX("Incorrect fraction digits");if(r!=r)return"NaN";if(r<=-1e21||r>=1e21)return qP(r);if(r<0&&(i="-",r=-r),r>1e-21)if(l=YX(r*Fs(2,69,1))-69,u=l<0?r*Fs(2,-l,1):r/Fs(2,l,1),u*=4503599627370496,l=52-l,l>0){for(vs(a,0,u),f=n;f>=7;)vs(a,1e7,0),f-=7;for(vs(a,Fs(10,f,1),0),f=l-1;f>=23;)wm(a,1<<23),f-=23;wm(a,1<0?(d=o.length,o=i+(d<=n?"0."+Ly("0",n-d)+o:g2(o,0,d-n)+"."+g2(o,d-n))):o=i+o,o}});var qX=C,KX=ue,b2=le,_2=_p,tv=KX(1 .toPrecision),ZX=b2(function(){return tv(1,void 0)!=="1"})||!b2(function(){tv({})});qX({target:"Number",proto:!0,forced:ZX},{toPrecision:function(t){return t===void 0?tv(_2(this)):tv(_2(this),t)}});var $2=Ve,XX=ue,JX=Ye,QX=le,Tm=Rc,eJ=Ic,tJ=Ec,rJ=$t,nJ=Ac,ps=Object.assign,x2=Object.defineProperty,aJ=XX([].concat),ZP=!ps||QX(function(){if($2&&ps({b:1},ps(x2({},"a",{enumerable:!0,get:function(){x2(this,"b",{value:3,enumerable:!1})}}),{b:2})).b!==1)return!0;var e={},t={},r=Symbol(),n="abcdefghijklmnopqrst";return e[r]=7,n.split("").forEach(function(a){t[a]=a}),ps({},e)[r]!=7||Tm(ps({},t)).join("")!=n})?function(t,r){for(var n=rJ(t),a=arguments.length,i=1,o=eJ.f,l=tJ.f;a>i;)for(var u=nJ(arguments[i++]),f=o?aJ(Tm(u),o(u)):Tm(u),d=f.length,s=0,c;d>s;)c=f[s++],(!$2||JX(l,u,c))&&(n[c]=u[c]);return n}:ps,iJ=C,S2=ZP;iJ({target:"Object",stat:!0,arity:2,forced:Object.assign!==S2},{assign:S2});var oJ=C,sJ=Ve,lJ=dn;oJ({target:"Object",stat:!0,sham:!sJ},{create:lJ});var uJ=Se,cJ=le,w2=i0,xp=!cJ(function(){if(!(w2&&w2<535)){var e=Math.random();__defineSetter__.call(null,e,function(){}),delete uJ[e]}}),fJ=C,dJ=Ve,vJ=xp,pJ=qt,hJ=$t,mJ=ht;dJ&&fJ({target:"Object",proto:!0,forced:vJ},{__defineGetter__:function(t,r){mJ.f(hJ(this),t,{get:pJ(r),enumerable:!0,configurable:!0})}});var gJ=C,yJ=Ve,T2=rp.f;gJ({target:"Object",stat:!0,forced:Object.defineProperties!==T2,sham:!yJ},{defineProperties:T2});var bJ=C,_J=Ve,E2=ht.f;bJ({target:"Object",stat:!0,forced:Object.defineProperty!==E2,sham:!_J},{defineProperty:E2});var $J=C,xJ=Ve,SJ=xp,wJ=qt,TJ=$t,EJ=ht;xJ&&$J({target:"Object",proto:!0,forced:SJ},{__defineSetter__:function(t,r){EJ.f(TJ(this),t,{set:wJ(r),enumerable:!0,configurable:!0})}});var AJ=Ve,XP=ue,OJ=Rc,CJ=Or,IJ=Ec.f,kJ=XP(IJ),PJ=XP([].push),A2=function(e){return function(t){for(var r=CJ(t),n=OJ(r),a=n.length,i=0,o=[],l;a>i;)l=n[i++],(!AJ||kJ(r,l))&&PJ(o,e?[l,r[l]]:r[l]);return o}},JP={entries:A2(!0),values:A2(!1)},RJ=C,MJ=JP.entries;RJ({target:"Object",stat:!0},{entries:function(t){return MJ(t)}});var LJ=C,DJ=Gc,NJ=le,FJ=qe,VJ=Da.onFreeze,Dy=Object.freeze,jJ=NJ(function(){Dy(1)});LJ({target:"Object",stat:!0,forced:jJ,sham:!DJ},{freeze:function(t){return Dy&&FJ(t)?Dy(VJ(t)):t}});var BJ=C,HJ=da,UJ=Za;BJ({target:"Object",stat:!0},{fromEntries:function(t){var r={};return HJ(t,function(n,a){UJ(r,n,a)},{AS_ENTRIES:!0}),r}});var GJ=C,WJ=le,YJ=Or,QP=er.f,eR=Ve,zJ=WJ(function(){QP(1)}),qJ=!eR||zJ;GJ({target:"Object",stat:!0,forced:qJ,sham:!eR},{getOwnPropertyDescriptor:function(t,r){return QP(YJ(t),r)}});var KJ=C,ZJ=Ve,XJ=Fb,JJ=Or,QJ=er,eQ=Za;KJ({target:"Object",stat:!0,sham:!ZJ},{getOwnPropertyDescriptors:function(t){for(var r=JJ(t),n=QJ.f,a=XJ(r),i={},o=0,l,u;a.length>o;)u=n(r,l=a[o++]),u!==void 0&&eQ(i,l,u);return i}});var tQ=C,rQ=le,nQ=np.f,aQ=rQ(function(){return!Object.getOwnPropertyNames(1)});tQ({target:"Object",stat:!0,forced:aQ},{getOwnPropertyNames:nQ});var iQ=C,oQ=le,sQ=$t,tR=pn,lQ=Kb,uQ=oQ(function(){tR(1)});iQ({target:"Object",stat:!0,forced:uQ,sham:!lQ},{getPrototypeOf:function(t){return tR(sQ(t))}});var cQ=C,fQ=at;cQ({target:"Object",stat:!0},{hasOwn:fQ});var rR=Object.is||function(t,r){return t===r?t!==0||1/t===1/r:t!=t&&r!=r},dQ=C,vQ=rR;dQ({target:"Object",stat:!0},{is:vQ});var pQ=C,O2=mp;pQ({target:"Object",stat:!0,forced:Object.isExtensible!==O2},{isExtensible:O2});var hQ=C,mQ=le,gQ=qe,yQ=Br,C2=S0,Ny=Object.isFrozen,bQ=mQ(function(){Ny(1)});hQ({target:"Object",stat:!0,forced:bQ||C2},{isFrozen:function(t){return!gQ(t)||C2&&yQ(t)=="ArrayBuffer"?!0:Ny?Ny(t):!1}});var _Q=C,$Q=le,xQ=qe,SQ=Br,I2=S0,Fy=Object.isSealed,wQ=$Q(function(){Fy(1)});_Q({target:"Object",stat:!0,forced:wQ||I2},{isSealed:function(t){return!xQ(t)||I2&&SQ(t)=="ArrayBuffer"?!0:Fy?Fy(t):!1}});var TQ=C,EQ=$t,nR=Rc,AQ=le,OQ=AQ(function(){nR(1)});TQ({target:"Object",stat:!0,forced:OQ},{keys:function(t){return nR(EQ(t))}});var CQ=C,IQ=Ve,kQ=xp,PQ=$t,RQ=Wi,MQ=pn,LQ=er.f;IQ&&CQ({target:"Object",proto:!0,forced:kQ},{__lookupGetter__:function(t){var r=PQ(this),n=RQ(t),a;do if(a=LQ(r,n))return a.get;while(r=MQ(r))}});var DQ=C,NQ=Ve,FQ=xp,VQ=$t,jQ=Wi,BQ=pn,HQ=er.f;NQ&&DQ({target:"Object",proto:!0,forced:FQ},{__lookupSetter__:function(t){var r=VQ(this),n=jQ(t),a;do if(a=HQ(r,n))return a.set;while(r=BQ(r))}});var UQ=C,GQ=qe,WQ=Da.onFreeze,YQ=Gc,zQ=le,Vy=Object.preventExtensions,qQ=zQ(function(){Vy(1)});UQ({target:"Object",stat:!0,forced:qQ,sham:!YQ},{preventExtensions:function(t){return Vy&&GQ(t)?Vy(WQ(t)):t}});var KQ=C,ZQ=qe,XQ=Da.onFreeze,JQ=Gc,QQ=le,jy=Object.seal,eee=QQ(function(){jy(1)});KQ({target:"Object",stat:!0,forced:eee,sham:!JQ},{seal:function(t){return jy&&ZQ(t)?jy(XQ(t)):t}});var tee=C,ree=ca;tee({target:"Object",stat:!0},{setPrototypeOf:ree});var nee=Vb,aee=Ka,iee=nee?{}.toString:function(){return"[object "+aee(this)+"]"},oee=Vb,see=Ot,lee=iee;oee||see(Object.prototype,"toString",lee,{unsafe:!0});var uee=C,cee=JP.values;uee({target:"Object",stat:!0},{values:function(t){return cee(t)}});var fee=C,k2=UP;fee({global:!0,forced:parseFloat!=k2},{parseFloat:k2});var dee=C,P2=YP;dee({global:!0,forced:parseInt!=P2},{parseInt:P2});var vee=TypeError,zi=function(e,t){if(e=51&&/native code/.test(e))return!1;var r=new Au(function(i){i(1)}),n=function(i){i(function(){},function(){})},a=r.constructor={};return a[Yee]=n,Uy=r.then(function(){})instanceof n,Uy?!t&&Wee&&!lR:!0}),zc={CONSTRUCTOR:zee,REJECTION_EVENT:lR,SUBCLASSING:Uy},qi={},z2=qt,qee=function(e){var t,r;this.promise=new e(function(n,a){if(t!==void 0||r!==void 0)throw TypeError("Bad Promise constructor");t=n,r=a}),this.resolve=z2(t),this.reject=z2(r)};qi.f=function(e){return new qee(e)};var Kee=C,rv=Ko,Bi=Se,ll=Ye,q2=Ot,K2=ca,Zee=Ur,Xee=El,Jee=qt,Ed=Qe,Qee=qe,ete=va,tte=Ol,uR=Sp.set,R0=oR,rte=Dee,nte=Wc,ate=Nee,cR=Kt,nv=Yc,M0=zc,fR=qi,wp="Promise",dR=M0.CONSTRUCTOR,ite=M0.REJECTION_EVENT,ote=M0.SUBCLASSING,Lm=cR.getterFor(wp),ste=cR.set,Is=nv&&nv.prototype,xo=nv,Nf=Is,vR=Bi.TypeError,Gy=Bi.document,L0=Bi.process,Wy=fR.f,lte=Wy,ute=!!(Gy&&Gy.createEvent&&Bi.dispatchEvent),pR="unhandledrejection",cte="rejectionhandled",Z2=0,hR=1,fte=2,D0=1,mR=2,Ff,X2,dte,J2,gR=function(e){var t;return Qee(e)&&Ed(t=e.then)?t:!1},yR=function(e,t){var r=t.value,n=t.state==hR,a=n?e.ok:e.fail,i=e.resolve,o=e.reject,l=e.domain,u,f,d;try{a?(n||(t.rejection===mR&&pte(t),t.rejection=D0),a===!0?u=r:(l&&l.enter(),u=a(r),l&&(l.exit(),d=!0)),u===e.promise?o(vR("Promise-chain cycle")):(f=gR(u))?ll(f,u,i,o):i(u)):o(r)}catch(s){l&&!d&&l.exit(),o(s)}},bR=function(e,t){e.notified||(e.notified=!0,R0(function(){for(var r=e.reactions,n;n=r.get();)yR(n,e);e.notified=!1,t&&!e.rejection&&vte(e)}))},_R=function(e,t,r){var n,a;ute?(n=Gy.createEvent("Event"),n.promise=t,n.reason=r,n.initEvent(e,!1,!0),Bi.dispatchEvent(n)):n={promise:t,reason:r},!ite&&(a=Bi["on"+e])?a(n):e===pR&&rte("Unhandled promise rejection",r)},vte=function(e){ll(uR,Bi,function(){var t=e.facade,r=e.value,n=Q2(e),a;if(n&&(a=nte(function(){rv?L0.emit("unhandledRejection",r,t):_R(pR,t,r)}),e.rejection=rv||Q2(e)?mR:D0,a.error))throw a.value})},Q2=function(e){return e.rejection!==D0&&!e.parent},pte=function(e){ll(uR,Bi,function(){var t=e.facade;rv?L0.emit("rejectionHandled",t):_R(cte,t,e.value)})},Vs=function(e,t,r){return function(n){e(t,n,r)}},Ys=function(e,t,r){e.done||(e.done=!0,r&&(e=r),e.value=t,e.state=fte,bR(e,!0))},Yy=function(e,t,r){if(!e.done){e.done=!0,r&&(e=r);try{if(e.facade===t)throw vR("Promise can't be resolved itself");var n=gR(t);n?R0(function(){var a={done:!1};try{ll(n,t,Vs(Yy,a,e),Vs(Ys,a,e))}catch(i){Ys(a,i,e)}}):(e.value=t,e.state=hR,bR(e,!1))}catch(a){Ys({done:!1},a,e)}}};if(dR&&(xo=function(t){ete(this,Nf),Jee(t),ll(Ff,this);var r=Lm(this);try{t(Vs(Yy,r),Vs(Ys,r))}catch(n){Ys(r,n)}},Nf=xo.prototype,Ff=function(t){ste(this,{type:wp,done:!1,notified:!1,parent:!1,reactions:new ate,rejection:!1,state:Z2,value:void 0})},Ff.prototype=q2(Nf,"then",function(t,r){var n=Lm(this),a=Wy(tte(this,xo));return n.parent=!0,a.ok=Ed(t)?t:!0,a.fail=Ed(r)&&r,a.domain=rv?L0.domain:void 0,n.state==Z2?n.reactions.add(a):R0(function(){yR(a,n)}),a.promise}),X2=function(){var e=new Ff,t=Lm(e);this.promise=e,this.resolve=Vs(Yy,t),this.reject=Vs(Ys,t)},fR.f=Wy=function(e){return e===xo||e===dte?new X2(e):lte(e)},Ed(nv)&&Is!==Object.prototype)){J2=Is.then,ote||q2(Is,"then",function(t,r){var n=this;return new xo(function(a,i){ll(J2,n,a,i)}).then(t,r)},{unsafe:!0});try{delete Is.constructor}catch{}K2&&K2(Is,Nf)}Kee({global:!0,constructor:!0,wrap:!0,forced:dR},{Promise:xo});Zee(xo,wp,!1);Xee(wp);var hte=Yc,mte=fp,gte=zc.CONSTRUCTOR,$R=gte||!mte(function(e){hte.all(e).then(void 0,function(){})}),yte=C,bte=Ye,_te=qt,$te=qi,xte=Wc,Ste=da,wte=$R;yte({target:"Promise",stat:!0,forced:wte},{all:function(t){var r=this,n=$te.f(r),a=n.resolve,i=n.reject,o=xte(function(){var l=_te(r.resolve),u=[],f=0,d=1;Ste(t,function(s){var c=f++,v=!1;d++,bte(l,r,s).then(function(p){v||(v=!0,u[c]=p,--d||a(u))},i)}),--d||a(u)});return o.error&&i(o.value),n.promise}});var Tte=C,Ete=zc.CONSTRUCTOR,zy=Yc,Ate=Et,Ote=Qe,Cte=Ot,eT=zy&&zy.prototype;Tte({target:"Promise",proto:!0,forced:Ete,real:!0},{catch:function(e){return this.then(void 0,e)}});if(Ote(zy)){var tT=Ate("Promise").prototype.catch;eT.catch!==tT&&Cte(eT,"catch",tT,{unsafe:!0})}var Ite=C,kte=Ye,Pte=qt,Rte=qi,Mte=Wc,Lte=da,Dte=$R;Ite({target:"Promise",stat:!0,forced:Dte},{race:function(t){var r=this,n=Rte.f(r),a=n.reject,i=Mte(function(){var o=Pte(r.resolve);Lte(t,function(l){kte(o,r,l).then(n.resolve,a)})});return i.error&&a(i.value),n.promise}});var Nte=C,Fte=Ye,Vte=qi,jte=zc.CONSTRUCTOR;Nte({target:"Promise",stat:!0,forced:jte},{reject:function(t){var r=Vte.f(this);return Fte(r.reject,void 0,t),r.promise}});var Bte=Ge,Hte=qe,Ute=qi,xR=function(e,t){if(Bte(e),Hte(t)&&t.constructor===e)return t;var r=Ute.f(e),n=r.resolve;return n(t),r.promise},Gte=C,Wte=Et,Yte=zc.CONSTRUCTOR,zte=xR;Wte("Promise");Gte({target:"Promise",stat:!0,forced:Yte},{resolve:function(t){return zte(this,t)}});var qte=C,Kte=Ye,Zte=qt,Xte=qi,Jte=Wc,Qte=da;qte({target:"Promise",stat:!0},{allSettled:function(t){var r=this,n=Xte.f(r),a=n.resolve,i=n.reject,o=Jte(function(){var l=Zte(r.resolve),u=[],f=0,d=1;Qte(t,function(s){var c=f++,v=!1;d++,Kte(l,r,s).then(function(p){v||(v=!0,u[c]={status:"fulfilled",value:p},--d||a(u))},function(p){v||(v=!0,u[c]={status:"rejected",reason:p},--d||a(u))})}),--d||a(u)});return o.error&&i(o.value),n.promise}});var ere=C,tre=Ye,rre=qt,nre=Et,are=qi,ire=Wc,ore=da,rT="No one promise resolved";ere({target:"Promise",stat:!0},{any:function(t){var r=this,n=nre("AggregateError"),a=are.f(r),i=a.resolve,o=a.reject,l=ire(function(){var u=rre(r.resolve),f=[],d=0,s=1,c=!1;ore(t,function(v){var p=d++,h=!1;s++,tre(u,r,v).then(function(m){h||c||(c=!0,i(m))},function(m){h||c||(h=!0,f[p]=m,--s||o(new n(f,rT)))})}),--s||o(new n(f,rT))});return l.error&&o(l.value),a.promise}});var sre=C,av=Yc,lre=le,SR=Et,wR=Qe,ure=Ol,nT=xR,cre=Ot,qy=av&&av.prototype,fre=!!av&&lre(function(){qy.finally.call({then:function(){}},function(){})});sre({target:"Promise",proto:!0,real:!0,forced:fre},{finally:function(e){var t=ure(this,SR("Promise")),r=wR(e);return this.then(r?function(n){return nT(t,e()).then(function(){return n})}:e,r?function(n){return nT(t,e()).then(function(){throw n})}:e)}});if(wR(av)){var aT=SR("Promise").prototype.finally;qy.finally!==aT&&cre(qy,"finally",aT,{unsafe:!0})}var dre=C,vre=vn,pre=qt,hre=Ge,mre=le,gre=!mre(function(){Reflect.apply(function(){})});dre({target:"Reflect",stat:!0,forced:gre},{apply:function(t,r,n){return vre(pre(t),r,hre(n))}});var yre=C,bre=Et,Dm=vn,_re=IP,iT=y0,$re=Ge,oT=qe,xre=dn,TR=le,N0=bre("Reflect","construct"),Sre=Object.prototype,wre=[].push,ER=TR(function(){function e(){}return!(N0(function(){},[],e)instanceof e)}),AR=!TR(function(){N0(function(){})}),sT=ER||AR;yre({target:"Reflect",stat:!0,forced:sT,sham:sT},{construct:function(t,r){iT(t),$re(r);var n=arguments.length<3?t:iT(arguments[2]);if(AR&&!ER)return N0(t,r,n);if(t==n){switch(r.length){case 0:return new t;case 1:return new t(r[0]);case 2:return new t(r[0],r[1]);case 3:return new t(r[0],r[1],r[2]);case 4:return new t(r[0],r[1],r[2],r[3])}var a=[null];return Dm(wre,a,r),new(Dm(_re,t,a))}var i=n.prototype,o=xre(oT(i)?i:Sre),l=Dm(t,o,r);return oT(l)?l:o}});var Tre=C,Ere=Ve,lT=Ge,Are=Wi,OR=ht,Ore=le,Cre=Ore(function(){Reflect.defineProperty(OR.f({},1,{value:1}),1,{value:2})});Tre({target:"Reflect",stat:!0,forced:Cre,sham:!Ere},{defineProperty:function(t,r,n){lT(t);var a=Are(r);lT(n);try{return OR.f(t,a,n),!0}catch{return!1}}});var Ire=C,kre=Ge,Pre=er.f;Ire({target:"Reflect",stat:!0},{deleteProperty:function(t,r){var n=Pre(kre(t),r);return n&&!n.configurable?!1:delete t[r]}});var uT=at,CR=function(e){return e!==void 0&&(uT(e,"value")||uT(e,"writable"))},Rre=C,Mre=Ye,Lre=qe,Dre=Ge,Nre=CR,Fre=er,Vre=pn;function IR(e,t){var r=arguments.length<3?e:arguments[2],n,a;if(Dre(e)===r)return e[t];if(n=Fre.f(e,t),n)return Nre(n)?n.value:n.get===void 0?void 0:Mre(n.get,r);if(Lre(a=Vre(e)))return IR(a,t,r)}Rre({target:"Reflect",stat:!0},{get:IR});var jre=C,Bre=Ve,Hre=Ge,Ure=er;jre({target:"Reflect",stat:!0,sham:!Bre},{getOwnPropertyDescriptor:function(t,r){return Ure.f(Hre(t),r)}});var Gre=C,Wre=Ge,Yre=pn,zre=Kb;Gre({target:"Reflect",stat:!0,sham:!zre},{getPrototypeOf:function(t){return Yre(Wre(t))}});var qre=C;qre({target:"Reflect",stat:!0},{has:function(t,r){return r in t}});var Kre=C,Zre=Ge,Xre=mp;Kre({target:"Reflect",stat:!0},{isExtensible:function(t){return Zre(t),Xre(t)}});var Jre=C,Qre=Fb;Jre({target:"Reflect",stat:!0},{ownKeys:Qre});var ene=C,tne=Et,rne=Ge,nne=Gc;ene({target:"Reflect",stat:!0,sham:!nne},{preventExtensions:function(t){rne(t);try{var r=tne("Object","preventExtensions");return r&&r(t),!0}catch{return!1}}});var ane=C,ine=Ye,one=Ge,cT=qe,sne=CR,lne=le,Ky=ht,fT=er,une=pn,dT=cn;function kR(e,t,r){var n=arguments.length<4?e:arguments[3],a=fT.f(one(e),t),i,o,l;if(!a){if(cT(o=une(e)))return kR(o,t,r,n);a=dT(0)}if(sne(a)){if(a.writable===!1||!cT(n))return!1;if(i=fT.f(n,t)){if(i.get||i.set||i.writable===!1)return!1;i.value=r,Ky.f(n,t,i)}else Ky.f(n,t,dT(0,r))}else{if(l=a.set,l===void 0)return!1;ine(l,n,r)}return!0}var cne=lne(function(){var e=function(){},t=Ky.f(new e,"a",{configurable:!0});return Reflect.set(e.prototype,"a",1,t)!==!1});ane({target:"Reflect",stat:!0,forced:cne},{set:kR});var fne=C,dne=Ge,vne=Ek,vT=ca;vT&&fne({target:"Reflect",stat:!0},{setPrototypeOf:function(t,r){dne(t),vne(r);try{return vT(t,r),!0}catch{return!1}}});var pne=C,hne=Se,mne=Ur;pne({global:!0},{Reflect:{}});mne(hne.Reflect,"Reflect",!0);var gne=qe,yne=Br,bne=Ke,_ne=bne("match"),qc=function(e){var t;return gne(e)&&((t=e[_ne])!==void 0?!!t:yne(e)=="RegExp")},$ne=Ge,F0=function(){var e=$ne(this),t="";return e.hasIndices&&(t+="d"),e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),e.dotAll&&(t+="s"),e.unicode&&(t+="u"),e.sticky&&(t+="y"),t},xne=Ye,Sne=at,wne=fn,Tne=F0,pT=RegExp.prototype,Kc=function(e){var t=e.flags;return t===void 0&&!("flags"in pT)&&!Sne(e,"flags")&&wne(pT,e)?xne(Tne,e):t},V0=le,Ene=Se,j0=Ene.RegExp,B0=V0(function(){var e=j0("a","y");return e.lastIndex=2,e.exec("abcd")!=null}),Ane=B0||V0(function(){return!j0("a","y").sticky}),One=B0||V0(function(){var e=j0("^r","gy");return e.lastIndex=2,e.exec("str")!=null}),Tp={BROKEN_CARET:One,MISSED_STICKY:Ane,UNSUPPORTED_Y:B0},Cne=le,Ine=Se,kne=Ine.RegExp,H0=Cne(function(){var e=kne(".","s");return!(e.dotAll&&e.exec(` -`)&&e.flags==="s")}),Pne=le,Rne=Se,Mne=Rne.RegExp,PR=Pne(function(){var e=Mne("(?b)","g");return e.exec("b").groups.a!=="b"||"b".replace(e,"$c")!=="bc"}),Lne=Ve,U0=Se,Zc=ue,Dne=Pc,Nne=Tl,Fne=br,Vne=za.f,hT=fn,jne=qc,mT=et,Bne=Kc,RR=Tp,Hne=Ak,Une=Ot,Gne=le,Wne=at,Yne=Kt.enforce,zne=El,qne=Ke,MR=H0,LR=PR,Kne=qne("match"),Li=U0.RegExp,ks=Li.prototype,Zne=U0.SyntaxError,Xne=Zc(ks.exec),iv=Zc("".charAt),gT=Zc("".replace),yT=Zc("".indexOf),Jne=Zc("".slice),Qne=/^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,Po=/a/g,Nm=/a/g,eae=new Li(Po)!==Po,DR=RR.MISSED_STICKY,tae=RR.UNSUPPORTED_Y,rae=Lne&&(!eae||DR||MR||LR||Gne(function(){return Nm[Kne]=!1,Li(Po)!=Po||Li(Nm)==Nm||Li(Po,"i")!="/a/i"})),nae=function(e){for(var t=e.length,r=0,n="",a=!1,i;r<=t;r++){if(i=iv(e,r),i==="\\"){n+=i+iv(e,++r);continue}!a&&i==="."?n+="[\\s\\S]":(i==="["?a=!0:i==="]"&&(a=!1),n+=i)}return n},aae=function(e){for(var t=e.length,r=0,n="",a=[],i={},o=!1,l=!1,u=0,f="",d;r<=t;r++){if(d=iv(e,r),d==="\\")d=d+iv(e,++r);else if(d==="]")o=!1;else if(!o)switch(!0){case d==="[":o=!0;break;case d==="(":Xne(Qne,Jne(e,r+1))&&(r+=2,l=!0),n+=d,u++;continue;case(d===">"&&l):if(f===""||Wne(i,f))throw new Zne("Invalid capture group name");i[f]=!0,a[a.length]=[f,u],l=!1,f="";continue}l?f+=d:n+=d}return[n,a]};if(Dne("RegExp",rae)){for(var so=function(t,r){var n=hT(ks,this),a=jne(t),i=r===void 0,o=[],l=t,u,f,d,s,c,v;if(!n&&a&&i&&t.constructor===so)return t;if((a||hT(ks,t))&&(t=t.source,i&&(r=Bne(l))),t=t===void 0?"":mT(t),r=r===void 0?"":mT(r),l=t,MR&&"dotAll"in Po&&(f=!!r&&yT(r,"s")>-1,f&&(r=gT(r,/s/g,""))),u=r,DR&&"sticky"in Po&&(d=!!r&&yT(r,"y")>-1,d&&tae&&(r=gT(r,/y/g,""))),LR&&(s=aae(t),t=s[0],o=s[1]),c=Nne(Li(t,r),n?this:ks,so),(f||d||o.length)&&(v=Yne(c),f&&(v.dotAll=!0,v.raw=so(nae(t),u)),d&&(v.sticky=!0),o.length&&(v.groups=o)),t!==l)try{Fne(c,"source",l===""?"(?:)":l)}catch{}return c},bT=Vne(Li),_T=0;bT.length>_T;)Hne(so,Li,bT[_T++]);ks.constructor=so,so.prototype=ks,Une(U0,"RegExp",so,{constructor:!0})}zne("RegExp");var $T=Gu,iae=ht,Xc=function(e,t,r){return r.get&&$T(r.get,t,{getter:!0}),r.set&&$T(r.set,t,{setter:!0}),iae.f(e,t,r)},oae=Ve,sae=H0,lae=Br,uae=Xc,cae=Kt.get,xT=RegExp.prototype,fae=TypeError;oae&&sae&&uae(xT,"dotAll",{configurable:!0,get:function(){if(this!==xT){if(lae(this)==="RegExp")return!!cae(this).dotAll;throw fae("Incompatible receiver, RegExp required")}}});var js=Ye,Ep=ue,dae=et,vae=F0,pae=Tp,hae=ji,mae=dn,gae=Kt.get,yae=H0,bae=PR,_ae=hae("native-string-replace",String.prototype.replace),ov=RegExp.prototype.exec,Zy=ov,$ae=Ep("".charAt),xae=Ep("".indexOf),Sae=Ep("".replace),Fm=Ep("".slice),Xy=function(){var e=/a/,t=/b*/g;return js(ov,e,"a"),js(ov,t,"a"),e.lastIndex!==0||t.lastIndex!==0}(),NR=pae.BROKEN_CARET,Jy=/()??/.exec("")[1]!==void 0,wae=Xy||Jy||NR||yae||bae;wae&&(Zy=function(t){var r=this,n=gae(r),a=dae(t),i=n.raw,o,l,u,f,d,s,c;if(i)return i.lastIndex=r.lastIndex,o=js(Zy,i,a),r.lastIndex=i.lastIndex,o;var v=n.groups,p=NR&&r.sticky,h=js(vae,r),m=r.source,g=0,b=a;if(p&&(h=Sae(h,"y",""),xae(h,"g")===-1&&(h+="g"),b=Fm(a,r.lastIndex),r.lastIndex>0&&(!r.multiline||r.multiline&&$ae(a,r.lastIndex-1)!==` -`)&&(m="(?: "+m+")",b=" "+b,g++),l=new RegExp("^(?:"+m+")",h)),Jy&&(l=new RegExp("^"+m+"$(?!\\s)",h)),Xy&&(u=r.lastIndex),f=js(ov,p?l:r,b),p?f?(f.input=Fm(f.input,g),f[0]=Fm(f[0],g),f.index=r.lastIndex,r.lastIndex+=f[0].length):r.lastIndex=0:Xy&&f&&(r.lastIndex=r.global?f.index+f[0].length:u),Jy&&f&&f.length>1&&js(_ae,f[0],l,function(){for(d=1;d=0?a:n+a;return i<0||i>=n?void 0:sie(r,i)}});var W0=ue,uie=Zt,cie=et,fie=zt,die=W0("".charAt),ET=W0("".charCodeAt),vie=W0("".slice),AT=function(e){return function(t,r){var n=cie(fie(t)),a=uie(r),i=n.length,o,l;return a<0||a>=i?e?"":void 0:(o=ET(n,a),o<55296||o>56319||a+1===i||(l=ET(n,a+1))<56320||l>57343?e?die(n,a):o:e?vie(n,a,a+2):(o-55296<<10)+(l-56320)+65536)}},Op={codeAt:AT(!1),charAt:AT(!0)},pie=C,hie=Op.codeAt;pie({target:"String",proto:!0},{codePointAt:function(t){return hie(this,t)}});var mie=qc,gie=TypeError,Y0=function(e){if(mie(e))throw gie("The method doesn't accept regular expressions");return e},yie=Ke,bie=yie("match"),z0=function(e){var t=/./;try{"/./"[e](t)}catch{try{return t[bie]=!1,"/./"[e](t)}catch{}}return!1},_ie=C,jR=ue,$ie=er.f,xie=Hr,OT=et,Sie=Y0,wie=zt,Tie=z0,CT=jR("".endsWith),Eie=jR("".slice),Aie=Math.min,BR=Tie("endsWith"),Oie=!BR&&!!function(){var e=$ie(String.prototype,"endsWith");return e&&!e.writable}();_ie({target:"String",proto:!0,forced:!Oie&&!BR},{endsWith:function(t){var r=OT(wie(this));Sie(t);var n=arguments.length>1?arguments[1]:void 0,a=r.length,i=n===void 0?a:Aie(xie(n),a),o=OT(t);return CT?CT(r,o,i):Eie(r,i-o.length,i)===o}});var Cie=C,Iie=ue,kie=qa,Pie=RangeError,IT=String.fromCharCode,kT=String.fromCodePoint,Rie=Iie([].join),Mie=!!kT&&kT.length!=1;Cie({target:"String",stat:!0,arity:1,forced:Mie},{fromCodePoint:function(t){for(var r=[],n=arguments.length,a=0,i;n>a;){if(i=+arguments[a++],kie(i,1114111)!==i)throw Pie(i+" is not a valid code point");r[a]=i<65536?IT(i):IT(((i-=65536)>>10)+55296,i%1024+56320)}return Rie(r,"")}});var Lie=C,Die=ue,Nie=Y0,Fie=zt,PT=et,Vie=z0,jie=Die("".indexOf);Lie({target:"String",proto:!0,forced:!Vie("includes")},{includes:function(t){return!!~jie(PT(Fie(this)),PT(Nie(t)),arguments.length>1?arguments[1]:void 0)}});var Bie=Op.charAt,Hie=et,HR=Kt,Uie=r0,UR="String Iterator",Gie=HR.set,Wie=HR.getterFor(UR);Uie(String,"String",function(e){Gie(this,{type:UR,string:Hie(e),index:0})},function(){var t=Wie(this),r=t.string,n=t.index,a;return n>=r.length?{value:void 0,done:!0}:(a=Bie(r,n),t.index+=a.length,{value:a,done:!1})});var RT=ue,MT=Ot,Yie=Ap,LT=le,GR=Ke,zie=br,qie=GR("species"),Vm=RegExp.prototype,Cp=function(e,t,r,n){var a=GR(e),i=!LT(function(){var f={};return f[a]=function(){return 7},""[e](f)!=7}),o=i&&!LT(function(){var f=!1,d=/a/;return e==="split"&&(d={},d.constructor={},d.constructor[qie]=function(){return d},d.flags="",d[a]=/./[a]),d.exec=function(){return f=!0,null},d[a](""),!f});if(!i||!o||r){var l=RT(/./[a]),u=t(a,""[e],function(f,d,s,c,v){var p=RT(f),h=d.exec;return h===Yie||h===Vm.exec?i&&!v?{done:!0,value:l(d,s,c)}:{done:!0,value:p(s,d,c)}:{done:!1}});MT(String.prototype,e,u[0]),MT(Vm,a,u[1])}n&&zie(Vm[a],"sham",!0)},Kie=Op.charAt,Ip=function(e,t,r){return t+(r?Kie(e,t).length:1)},DT=Ye,Zie=Ge,Xie=Qe,Jie=Br,Qie=Ap,eoe=TypeError,Jc=function(e,t){var r=e.exec;if(Xie(r)){var n=DT(r,e,t);return n!==null&&Zie(n),n}if(Jie(e)==="RegExp")return DT(Qie,e,t);throw eoe("RegExp#exec called on incompatible receiver")},toe=Ye,roe=Cp,noe=Ge,aoe=Hr,jm=et,ioe=zt,ooe=Ya,soe=Ip,NT=Jc;roe("match",function(e,t,r){return[function(a){var i=ioe(this),o=a==null?void 0:ooe(a,e);return o?toe(o,a,i):new RegExp(a)[e](jm(i))},function(n){var a=noe(this),i=jm(n),o=r(t,a,i);if(o.done)return o.value;if(!a.global)return NT(a,i);var l=a.unicode;a.lastIndex=0;for(var u=[],f=0,d;(d=NT(a,i))!==null;){var s=jm(d[0]);u[f]=s,s===""&&(a.lastIndex=soe(i,aoe(a.lastIndex),l)),f++}return f===0?null:u}]});var loe=C,uoe=Ye,WR=ue,coe=t0,FT=zt,YR=Hr,Zu=et,foe=Ge,doe=Br,voe=qc,zR=Kc,poe=Ya,hoe=Ot,moe=le,goe=Ke,yoe=Ol,boe=Ip,_oe=Jc,qR=Kt,$oe=DI,sv=goe("matchAll"),KR="RegExp String",ZR=KR+" Iterator",xoe=qR.set,Soe=qR.getterFor(ZR),VT=RegExp.prototype,woe=TypeError,Qy=WR("".indexOf),lv=WR("".matchAll),Bm=!!lv&&!moe(function(){lv("a",/./)}),Toe=coe(function(t,r,n,a){xoe(this,{type:ZR,regexp:t,string:r,global:n,unicode:a,done:!1})},KR,function(){var t=Soe(this);if(t.done)return{value:void 0,done:!0};var r=t.regexp,n=t.string,a=_oe(r,n);return a===null?{value:void 0,done:t.done=!0}:t.global?(Zu(a[0])===""&&(r.lastIndex=boe(n,YR(r.lastIndex),t.unicode)),{value:a,done:!1}):(t.done=!0,{value:a,done:!1})}),XR=function(e){var t=foe(this),r=Zu(e),n=yoe(t,RegExp),a=Zu(zR(t)),i,o,l;return i=new n(n===RegExp?t.source:t,a),o=!!~Qy(a,"g"),l=!!~Qy(a,"u"),i.lastIndex=YR(t.lastIndex),new Toe(i,r,o,l)};loe({target:"String",proto:!0,forced:Bm},{matchAll:function(t){var r=FT(this),n,a,i,o;if(t!=null){if(voe(t)&&(n=Zu(FT(zR(t))),!~Qy(n,"g")))throw woe("`.matchAll` does not allow non-global regexes");if(Bm)return lv(r,t);if(i=poe(t,sv),i===void 0&&$oe&&doe(t)=="RegExp"&&(i=XR),i)return uoe(i,t,r)}else if(Bm)return lv(r,t);return a=Zu(r),o=new RegExp(t,"g"),o[sv](a)}});sv in VT||hoe(VT,sv,XR);var Eoe=Wa,JR=/Version\/10(?:\.\d+){1,2}(?: [\w./]+)?(?: Mobile\/\w+)? Safari\//.test(Eoe),Aoe=C,Ooe=$0.end,Coe=JR;Aoe({target:"String",proto:!0,forced:Coe},{padEnd:function(t){return Ooe(this,t,arguments.length>1?arguments[1]:void 0)}});var Ioe=C,koe=$0.start,Poe=JR;Ioe({target:"String",proto:!0,forced:Poe},{padStart:function(t){return koe(this,t,arguments.length>1?arguments[1]:void 0)}});var Roe=C,QR=ue,Moe=Or,Loe=$t,jT=et,Doe=Ct,BT=QR([].push),Noe=QR([].join);Roe({target:"String",stat:!0},{raw:function(t){for(var r=Moe(Loe(t).raw),n=Doe(r),a=arguments.length,i=[],o=0;n>o;){if(BT(i,jT(r[o++])),o===n)return Noe(i,"");o]*>)/g,Goe=/\$([$&'`]|\d{1,2})/g,eM=function(e,t,r,n,a,i){var o=r+e.length,l=n.length,u=Goe;return a!==void 0&&(a=joe(a),u=Uoe),Hoe(i,u,function(f,d){var s;switch(Hm(d,0)){case"$":return"$";case"&":return e;case"`":return Um(t,0,r);case"'":return Um(t,o);case"<":s=a[Um(d,1,-1)];break;default:var c=+d;if(c===0)return f;if(c>l){var v=Boe(c/10);return v===0?f:v<=l?n[v-1]===void 0?Hm(d,1):n[v-1]+Hm(d,1):f}s=n[c-1]}return s===void 0?"":s})},Woe=vn,HT=Ye,kp=ue,Yoe=Cp,zoe=le,qoe=Ge,Koe=Qe,Zoe=Zt,Xoe=Hr,hs=et,Joe=zt,Qoe=Ip,ese=Ya,tse=eM,rse=Jc,nse=Ke,e1=nse("replace"),ase=Math.max,ise=Math.min,ose=kp([].concat),Gm=kp([].push),UT=kp("".indexOf),GT=kp("".slice),sse=function(e){return e===void 0?e:String(e)},lse=function(){return"a".replace(/./,"$0")==="$0"}(),WT=function(){return/./[e1]?/./[e1]("a","$0")==="":!1}(),use=!zoe(function(){var e=/./;return e.exec=function(){var t=[];return t.groups={a:"7"},t},"".replace(e,"$")!=="7"});Yoe("replace",function(e,t,r){var n=WT?"$":"$0";return[function(i,o){var l=Joe(this),u=i==null?void 0:ese(i,e1);return u?HT(u,i,l,o):HT(t,hs(l),i,o)},function(a,i){var o=qoe(this),l=hs(a);if(typeof i=="string"&&UT(i,n)===-1&&UT(i,"$<")===-1){var u=r(t,o,l,i);if(u.done)return u.value}var f=Koe(i);f||(i=hs(i));var d=o.global;if(d){var s=o.unicode;o.lastIndex=0}for(var c=[];;){var v=rse(o,l);if(v===null||(Gm(c,v),!d))break;var p=hs(v[0]);p===""&&(o.lastIndex=Qoe(l,Xoe(o.lastIndex),s))}for(var h="",m=0,g=0;g=m&&(h+=GT(l,m,_)+x,m=_+b.length)}return h+GT(l,m)}]},!use||!lse||WT);var cse=C,fse=Ye,K0=ue,YT=zt,dse=Qe,vse=qc,Yl=et,pse=Ya,hse=Kc,mse=eM,gse=Ke,yse=gse("replace"),bse=TypeError,tM=K0("".indexOf);K0("".replace);var zT=K0("".slice),_se=Math.max,qT=function(e,t,r){return r>e.length?-1:t===""?r:tM(e,t,r)};cse({target:"String",proto:!0},{replaceAll:function(t,r){var n=YT(this),a,i,o,l,u,f,d,s,c,v=0,p=0,h="";if(t!=null){if(a=vse(t),a&&(i=Yl(YT(hse(t))),!~tM(i,"g")))throw bse("`.replaceAll` does not allow non-global regexes");if(o=pse(t,yse),o)return fse(o,t,n,r)}for(l=Yl(n),u=Yl(t),f=dse(r),f||(r=Yl(r)),d=u.length,s=_se(1,d),v=qT(l,u,0);v!==-1;)c=f?Yl(r(u,v,l)):mse(u,l,v,[],void 0,r),h+=zT(l,p,v)+c,p=v+d,v=qT(l,u,v+s);return p1||"".split(/.?/).length?n=function(a,i){var o=Wm(XT(this)),l=i===void 0?eE:i>>>0;if(l===0)return[];if(a===void 0)return[o];if(!Cse(a))return zl(t,o,a,l);for(var u=[],f=(a.ignoreCase?"i":"")+(a.multiline?"m":"")+(a.unicode?"u":"")+(a.sticky?"y":""),d=0,s=new RegExp(a.source,f+"g"),c,v,p;(c=zl(Lse,s,o))&&(v=s.lastIndex,!(v>d&&(gs(u,ql(o,d,c.index)),c.length>1&&c.index=l)));)s.lastIndex===c.index&&s.lastIndex++;return d===o.length?(p||!Vse(s,""))&&gs(u,""):gs(u,ql(o,d)),u.length>l?JT(u,0,l):u}:"0".split(void 0,0).length?n=function(a,i){return a===void 0&&i===0?[]:zl(t,this,a,i)}:n=t,[function(i,o){var l=XT(this),u=i==null?void 0:Mse(i,e);return u?zl(u,i,l,o):zl(n,Wm(l),i,o)},function(a,i){var o=Ise(this),l=Wm(a),u=r(n,o,l,i,n!==t);if(u.done)return u.value;var f=kse(o,RegExp),d=o.unicode,s=(o.ignoreCase?"i":"")+(o.multiline?"m":"")+(o.unicode?"u":"")+(ms?"g":"y"),c=new f(ms?"^(?:"+o.source+")":o,s),v=i===void 0?eE:i>>>0;if(v===0)return[];if(l.length===0)return QT(c,l)===null?[l]:[];for(var p=0,h=0,m=[];h1?arguments[1]:void 0,r.length)),a=tE(t);return rE?rE(r,a,n):zse(r,n,n+a.length)===a}});var Zse=C,Xse=ue,Jse=zt,nE=Zt,Qse=et,ele=Xse("".slice),tle=Math.max,rle=Math.min,nle=!"".substr||"ab".substr(-1)!=="b";Zse({target:"String",proto:!0,forced:nle},{substr:function(t,r){var n=Qse(Jse(this)),a=n.length,i=nE(t),o,l;return i===1/0&&(i=0),i<0&&(i=tle(a+i,0)),o=r===void 0?a:nE(r),o<=0||o===1/0?"":(l=rle(i+o,a),i>=l?"":ele(n,i,l))}});var ale=Sl.PROPER,ile=le,aE=$p,iE="​…᠎",X0=function(e){return ile(function(){return!!aE[e]()||iE[e]()!==iE||ale&&aE[e].name!==e})},ole=C,sle=Cl.trim,lle=X0;ole({target:"String",proto:!0,forced:lle("trim")},{trim:function(){return sle(this)}});var ule=Cl.end,cle=X0,iM=cle("trimEnd")?function(){return ule(this)}:"".trimEnd,fle=C,oE=iM;fle({target:"String",proto:!0,name:"trimEnd",forced:"".trimRight!==oE},{trimRight:oE});var dle=C,sE=iM;dle({target:"String",proto:!0,name:"trimEnd",forced:"".trimEnd!==sE},{trimEnd:sE});var vle=Cl.start,ple=X0,oM=ple("trimStart")?function(){return vle(this)}:"".trimStart,hle=C,lE=oM;hle({target:"String",proto:!0,name:"trimStart",forced:"".trimLeft!==lE},{trimLeft:lE});var mle=C,uE=oM;mle({target:"String",proto:!0,name:"trimStart",forced:"".trimStart!==uE},{trimStart:uE});var gle=ue,yle=zt,cE=et,ble=/"/g,_le=gle("".replace),Gr=function(e,t,r,n){var a=cE(yle(e)),i="<"+t;return r!==""&&(i+=" "+r+'="'+_le(cE(n),ble,""")+'"'),i+">"+a+""},$le=le,Wr=function(e){return $le(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3})},xle=C,Sle=Gr,wle=Wr;xle({target:"String",proto:!0,forced:wle("anchor")},{anchor:function(t){return Sle(this,"a","name",t)}});var Tle=C,Ele=Gr,Ale=Wr;Tle({target:"String",proto:!0,forced:Ale("big")},{big:function(){return Ele(this,"big","","")}});var Ole=C,Cle=Gr,Ile=Wr;Ole({target:"String",proto:!0,forced:Ile("blink")},{blink:function(){return Cle(this,"blink","","")}});var kle=C,Ple=Gr,Rle=Wr;kle({target:"String",proto:!0,forced:Rle("bold")},{bold:function(){return Ple(this,"b","","")}});var Mle=C,Lle=Gr,Dle=Wr;Mle({target:"String",proto:!0,forced:Dle("fixed")},{fixed:function(){return Lle(this,"tt","","")}});var Nle=C,Fle=Gr,Vle=Wr;Nle({target:"String",proto:!0,forced:Vle("fontcolor")},{fontcolor:function(t){return Fle(this,"font","color",t)}});var jle=C,Ble=Gr,Hle=Wr;jle({target:"String",proto:!0,forced:Hle("fontsize")},{fontsize:function(t){return Ble(this,"font","size",t)}});var Ule=C,Gle=Gr,Wle=Wr;Ule({target:"String",proto:!0,forced:Wle("italics")},{italics:function(){return Gle(this,"i","","")}});var Yle=C,zle=Gr,qle=Wr;Yle({target:"String",proto:!0,forced:qle("link")},{link:function(t){return zle(this,"a","href",t)}});var Kle=C,Zle=Gr,Xle=Wr;Kle({target:"String",proto:!0,forced:Xle("small")},{small:function(){return Zle(this,"small","","")}});var Jle=C,Qle=Gr,eue=Wr;Jle({target:"String",proto:!0,forced:eue("strike")},{strike:function(){return Qle(this,"strike","","")}});var tue=C,rue=Gr,nue=Wr;tue({target:"String",proto:!0,forced:nue("sub")},{sub:function(){return rue(this,"sub","","")}});var aue=C,iue=Gr,oue=Wr;aue({target:"String",proto:!0,forced:oue("sup")},{sup:function(){return iue(this,"sup","","")}});var Mn={},fE={get exports(){return Mn},set exports(e){Mn=e}},sM=Se,Ym=le,sue=fp,lue=dt.NATIVE_ARRAY_BUFFER_VIEWS,uue=sM.ArrayBuffer,lo=sM.Int8Array,J0=!lue||!Ym(function(){lo(1)})||!Ym(function(){new lo(-1)})||!sue(function(e){new lo,new lo(null),new lo(1.5),new lo(e)},!0)||Ym(function(){return new lo(new uue(2),1,void 0).length!==1}),cue=Zt,fue=RangeError,due=function(e){var t=cue(e);if(t<0)throw fue("The argument can't be less than 0");return t},vue=due,pue=RangeError,lM=function(e,t){var r=vue(e);if(r%t)throw pue("Wrong offset");return r},hue=ua,mue=Ye,gue=y0,yue=$t,bue=Ct,_ue=cp,$ue=jc,xue=Zb,Sue=dt.aTypedArrayConstructor,uM=function(t){var r=gue(this),n=yue(t),a=arguments.length,i=a>1?arguments[1]:void 0,o=i!==void 0,l=$ue(n),u,f,d,s,c,v;if(l&&!xue(l))for(c=_ue(n,l),v=c.next,n=[];!(s=mue(v,c)).done;)n.push(s.value);for(o&&a>2&&(i=hue(i,arguments[2])),f=bue(n),d=new(Sue(r))(f),u=0;f>u;u++)d[u]=o?i(n[u],u):n[u];return d},dE=C,cM=Se,vE=Ye,wue=Ve,Tue=J0,Zo=dt,fM=pp,pE=va,Eue=cn,ys=br,Aue=C0,Oue=Hr,hE=sP,zm=lM,dM=Wi,Kl=at,Cue=Ka,t1=qe,Iue=Go,kue=dn,Pue=fn,Vf=ca,Rue=za.f,mE=uM,Mue=tr.forEach,Lue=El,vM=ht,pM=er,hM=Kt,Due=Tl,r1=hM.get,Nue=hM.set,Q0=vM.f,Fue=pM.f,Vue=Math.round,qm=cM.RangeError,mM=fM.ArrayBuffer,jue=mM.prototype,Bue=fM.DataView,jf=Zo.NATIVE_ARRAY_BUFFER_VIEWS,Hue=Zo.TYPED_ARRAY_CONSTRUCTOR,gE=Zo.TYPED_ARRAY_TAG,yE=Zo.TypedArray,Zl=Zo.TypedArrayPrototype,Uue=Zo.aTypedArrayConstructor,n1=Zo.isTypedArray,Bf="BYTES_PER_ELEMENT",Km="Wrong length",bE=function(e,t){Uue(e);for(var r=0,n=t.length,a=new e(n);n>r;)a[r]=t[r++];return a},Hf=function(e,t){Q0(e,t,{get:function(){return r1(this)[t]}})},_E=function(e){var t;return Pue(jue,e)||(t=Cue(e))=="ArrayBuffer"||t=="SharedArrayBuffer"},gM=function(e,t){return n1(e)&&!Iue(t)&&t in e&&Aue(+t)&&t>=0},$E=function(t,r){return r=dM(r),gM(t,r)?Eue(2,t[r]):Fue(t,r)},xE=function(t,r,n){return r=dM(r),gM(t,r)&&t1(n)&&Kl(n,"value")&&!Kl(n,"get")&&!Kl(n,"set")&&!n.configurable&&(!Kl(n,"writable")||n.writable)&&(!Kl(n,"enumerable")||n.enumerable)?(t[r]=n.value,t):Q0(t,r,n)};wue?(jf||(pM.f=$E,vM.f=xE,Hf(Zl,"buffer"),Hf(Zl,"byteOffset"),Hf(Zl,"byteLength"),Hf(Zl,"length")),dE({target:"Object",stat:!0,forced:!jf},{getOwnPropertyDescriptor:$E,defineProperty:xE}),fE.exports=function(e,t,r){var n=e.match(/\d+$/)[0]/8,a=e+(r?"Clamped":"")+"Array",i="get"+e,o="set"+e,l=cM[a],u=l,f=u&&u.prototype,d={},s=function(h,m){var g=r1(h);return g.view[i](m*n+g.byteOffset,!0)},c=function(h,m,g){var b=r1(h);r&&(g=(g=Vue(g))<0?0:g>255?255:g&255),b.view[o](m*n+b.byteOffset,g,!0)},v=function(h,m){Q0(h,m,{get:function(){return s(this,m)},set:function(g){return c(this,m,g)},enumerable:!0})};jf?Tue&&(u=t(function(h,m,g,b){return pE(h,f),Due(function(){return t1(m)?_E(m)?b!==void 0?new l(m,zm(g,n),b):g!==void 0?new l(m,zm(g,n)):new l(m):n1(m)?bE(u,m):vE(mE,u,m):new l(hE(m))}(),h,u)}),Vf&&Vf(u,yE),Mue(Rue(l),function(h){h in u||ys(u,h,l[h])}),u.prototype=f):(u=t(function(h,m,g,b){pE(h,f);var _=0,A=0,D,V,R;if(!t1(m))R=hE(m),V=R*n,D=new mM(V);else if(_E(m)){D=m,A=zm(g,n);var x=m.byteLength;if(b===void 0){if(x%n||(V=x-A,V<0))throw qm(Km)}else if(V=Oue(b)*n,V+A>x)throw qm(Km);R=V/n}else return n1(m)?bE(u,m):vE(mE,u,m);for(Nue(h,{buffer:D,byteOffset:A,byteLength:V,length:R,view:new Bue(D)});_=0?a:n+a;return i<0||i>=n?void 0:r[i]});var nce=ue,bM=dt,ace=Fk,ice=nce(ace),oce=bM.aTypedArray,sce=bM.exportTypedArrayMethod;sce("copyWithin",function(t,r){return ice(oce(this),t,r,arguments.length>2?arguments[2]:void 0)});var _M=dt,lce=tr.every,uce=_M.aTypedArray,cce=_M.exportTypedArrayMethod;cce("every",function(t){return lce(uce(this),t,arguments.length>1?arguments[1]:void 0)});var fce=Xv,dce=TypeError,vce=function(e){var t=fce(e,"number");if(typeof t=="number")throw dce("Can't convert number to bigint");return BigInt(t)},$M=dt,pce=e0,hce=vce,mce=Ka,gce=Ye,yce=ue,bce=le,_ce=$M.aTypedArray,$ce=$M.exportTypedArrayMethod,xce=yce("".slice),Sce=bce(function(){var e=0;return new Int8Array(2).fill({valueOf:function(){return e++}}),e!==1});$ce("fill",function(t){var r=arguments.length;_ce(this);var n=xce(mce(this),0,3)==="Big"?hce(t):+t;return gce(pce,this,n,r>1?arguments[1]:void 0,r>2?arguments[2]:void 0)},Sce);var wce=Ct,Tce=function(e,t){for(var r=0,n=wce(t),a=new e(n);n>r;)a[r]=t[r++];return a},xM=dt,Ece=Ol,Ace=xM.TYPED_ARRAY_CONSTRUCTOR,Oce=xM.aTypedArrayConstructor,Pp=function(e){return Oce(Ece(e,e[Ace]))},Cce=Tce,Ice=Pp,kce=function(e,t){return Cce(Ice(e),t)},SM=dt,Pce=tr.filter,Rce=kce,Mce=SM.aTypedArray,Lce=SM.exportTypedArrayMethod;Lce("filter",function(t){var r=Pce(Mce(this),t,arguments.length>1?arguments[1]:void 0);return Rce(this,r)});var wM=dt,Dce=tr.find,Nce=wM.aTypedArray,Fce=wM.exportTypedArrayMethod;Fce("find",function(t){return Dce(Nce(this),t,arguments.length>1?arguments[1]:void 0)});var TM=dt,Vce=tr.findIndex,jce=TM.aTypedArray,Bce=TM.exportTypedArrayMethod;Bce("findIndex",function(t){return Vce(jce(this),t,arguments.length>1?arguments[1]:void 0)});var EM=dt,Hce=tr.forEach,Uce=EM.aTypedArray,Gce=EM.exportTypedArrayMethod;Gce("forEach",function(t){Hce(Uce(this),t,arguments.length>1?arguments[1]:void 0)});var Wce=J0,Yce=dt.exportTypedArrayStaticMethod,zce=uM;Yce("from",zce,Wce);var AM=dt,qce=Cc.includes,Kce=AM.aTypedArray,Zce=AM.exportTypedArrayMethod;Zce("includes",function(t){return qce(Kce(this),t,arguments.length>1?arguments[1]:void 0)});var OM=dt,Xce=Cc.indexOf,Jce=OM.aTypedArray,Qce=OM.exportTypedArrayMethod;Qce("indexOf",function(t){return Xce(Jce(this),t,arguments.length>1?arguments[1]:void 0)});var efe=Se,tfe=le,e_=ue,CM=dt,t_=Qk,rfe=Ke,r_=rfe("iterator"),SE=efe.Uint8Array,nfe=e_(t_.values),afe=e_(t_.keys),ife=e_(t_.entries),n_=CM.aTypedArray,Rp=CM.exportTypedArrayMethod,Ps=SE&&SE.prototype,Mp=!tfe(function(){Ps[r_].call([1])}),IM=!!Ps&&Ps.values&&Ps[r_]===Ps.values&&Ps.values.name==="values",kM=function(){return nfe(n_(this))};Rp("entries",function(){return ife(n_(this))},Mp);Rp("keys",function(){return afe(n_(this))},Mp);Rp("values",kM,Mp||!IM,{name:"values"});Rp(r_,kM,Mp||!IM,{name:"values"});var PM=dt,ofe=ue,sfe=PM.aTypedArray,lfe=PM.exportTypedArrayMethod,ufe=ofe([].join);lfe("join",function(t){return ufe(sfe(this),t)});var RM=dt,cfe=vn,ffe=tP,dfe=RM.aTypedArray,vfe=RM.exportTypedArrayMethod;vfe("lastIndexOf",function(t){var r=arguments.length;return cfe(ffe,dfe(this),r>1?[t,arguments[1]]:[t])});var MM=dt,pfe=tr.map,hfe=Pp,mfe=MM.aTypedArray,gfe=MM.exportTypedArrayMethod;gfe("map",function(t){return pfe(mfe(this),t,arguments.length>1?arguments[1]:void 0,function(r,n){return new(hfe(r))(n)})});var LM=dt,yfe=J0,bfe=LM.aTypedArrayConstructor,_fe=LM.exportTypedArrayStaticMethod;_fe("of",function(){for(var t=0,r=arguments.length,n=new(bfe(this))(r);r>t;)n[t]=arguments[t++];return n},yfe);var DM=dt,$fe=dp.left,xfe=DM.aTypedArray,Sfe=DM.exportTypedArrayMethod;Sfe("reduce",function(t){var r=arguments.length;return $fe(xfe(this),t,r,r>1?arguments[1]:void 0)});var NM=dt,wfe=dp.right,Tfe=NM.aTypedArray,Efe=NM.exportTypedArrayMethod;Efe("reduceRight",function(t){var r=arguments.length;return wfe(Tfe(this),t,r,r>1?arguments[1]:void 0)});var FM=dt,Afe=FM.aTypedArray,Ofe=FM.exportTypedArrayMethod,Cfe=Math.floor;Ofe("reverse",function(){for(var t=this,r=Afe(t).length,n=Cfe(r/2),a=0,i;a1?arguments[1]:void 0,1),n=Pfe(t);if(i1)return jM(HM,this,n,r);var a=this.length,i=Ife(n),o=0;if(i+r>a)throw Rfe("Wrong length");for(;oi;)l[i]=n[i++];return l},Hfe);var GM=dt,Ufe=tr.some,Gfe=GM.aTypedArray,Wfe=GM.exportTypedArrayMethod;Wfe("some",function(t){return Ufe(Gfe(this),t,arguments.length>1?arguments[1]:void 0)});var Yfe=Se,zfe=ue,o1=le,qfe=qt,Kfe=a0,WM=dt,TE=nP,Zfe=aP,EE=Gi,AE=i0,Xfe=WM.aTypedArray,Jfe=WM.exportTypedArrayMethod,Xu=Yfe.Uint16Array,zs=Xu&&zfe(Xu.prototype.sort),Qfe=!!zs&&!(o1(function(){zs(new Xu(2),null)})&&o1(function(){zs(new Xu(2),{})})),OE=!!zs&&!o1(function(){if(EE)return EE<74;if(TE)return TE<67;if(Zfe)return!0;if(AE)return AE<602;var e=new Xu(516),t=Array(516),r,n;for(r=0;r<516;r++)n=r%4,e[r]=515-r,t[r]=r-2*n+3;for(zs(e,function(a,i){return(a/4|0)-(i/4|0)}),r=0;r<516;r++)if(e[r]!==t[r])return!0}),ede=function(e){return function(t,r){return e!==void 0?+e(t,r)||0:r!==r?-1:t!==t?1:t===0&&r===0?1/t>0&&1/r<0?1:-1:t>r}};Jfe("sort",function(t){return t!==void 0&&qfe(t),OE?zs(this,t):Kfe(Xfe(this),ede(t))},!OE||Qfe);var YM=dt,tde=Hr,CE=qa,rde=Pp,nde=YM.aTypedArray,ade=YM.exportTypedArrayMethod;ade("subarray",function(t,r){var n=nde(this),a=n.length,i=CE(t,a),o=rde(n);return new o(n.buffer,n.byteOffset+i*n.BYTES_PER_ELEMENT,tde((r===void 0?a:CE(r,a))-i))});var ide=Se,ode=vn,zM=dt,s1=le,IE=zo,uv=ide.Int8Array,kE=zM.aTypedArray,sde=zM.exportTypedArrayMethod,qM=[].toLocaleString,lde=!!uv&&s1(function(){qM.call(new uv(1))}),ude=s1(function(){return[1,2].toLocaleString()!=new uv([1,2]).toLocaleString()})||!s1(function(){uv.prototype.toLocaleString.call([1,2])});sde("toLocaleString",function(){return ode(qM,lde?IE(kE(this)):kE(this),IE(arguments))},ude);var cde=dt.exportTypedArrayMethod,fde=le,dde=Se,vde=ue,PE=dde.Uint8Array,pde=PE&&PE.prototype||{},cv=[].toString,hde=vde([].join);fde(function(){cv.call({})})&&(cv=function(){return hde(this)});var mde=pde.toString!=cv;cde("toString",cv,mde);var gde=C,i_=ue,yde=et,RE=String.fromCharCode,ME=i_("".charAt),LE=i_(/./.exec),DE=i_("".slice),bde=/^[\da-f]{2}$/i,_de=/^[\da-f]{4}$/i;gde({global:!0},{unescape:function(t){for(var r=yde(t),n="",a=r.length,i=0,o,l;i>(-2*i&6))));return n}});var qde=C,oL=Et,sL=ue,lL=le,YE=et,Kde=zi,Zde=nL.itoc,Bo=oL("btoa"),zE=sL("".charAt),Xde=sL("".charCodeAt),qE=!!Bo&&!lL(function(){Bo()}),KE=!!Bo&&lL(function(){return Bo(null)!=="bnVsbA=="}),ZE=!!Bo&&Bo.length!==1;qde({global:!0,enumerable:!0,forced:qE||KE||ZE},{btoa:function(t){if(Kde(arguments.length,1),qE||KE||ZE)return Bo(YE(t));for(var r=YE(t),n="",a=0,i=Zde,o,l;zE(r,a)||(i="=",a%1);){if(l=Xde(r,a+=3/4),l>255)throw new(oL("DOMException"))("The string contains characters outside of the Latin1 range","InvalidCharacterError");o=o<<8|l,n+=zE(i,63&o>>8-a%1*8)}return n}});var uL={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0},Jde=Jv,Qm=Jde("span").classList,XE=Qm&&Qm.constructor&&Qm.constructor.prototype,cL=XE===Object.prototype?void 0:XE,JE=Se,QE=uL,Qde=cL,eg=Uk,eve=br,fL=function(e){if(e&&e.forEach!==eg)try{eve(e,"forEach",eg)}catch{e.forEach=eg}};for(var tg in QE)QE[tg]&&fL(JE[tg]&&JE[tg].prototype);fL(Qde);var eA=Se,dL=uL,tve=cL,gu=Qk,rg=br,vL=Ke,ng=vL("iterator"),tA=vL("toStringTag"),ag=gu.values,pL=function(e,t){if(e){if(e[ng]!==ag)try{rg(e,ng,ag)}catch{e[ng]=ag}if(e[tA]||rg(e,tA,t),dL[t]){for(var r in gu)if(e[r]!==gu[r])try{rg(e,r,gu[r])}catch{e[r]=gu[r]}}}};for(var ig in dL)pL(eA[ig]&&eA[ig].prototype,ig);pL(tve,"DOMTokenList");var rve=Ko,nve=function(e){try{if(rve)return Function('return require("'+e+'")')()}catch{}},hL={IndexSizeError:{s:"INDEX_SIZE_ERR",c:1,m:1},DOMStringSizeError:{s:"DOMSTRING_SIZE_ERR",c:2,m:0},HierarchyRequestError:{s:"HIERARCHY_REQUEST_ERR",c:3,m:1},WrongDocumentError:{s:"WRONG_DOCUMENT_ERR",c:4,m:1},InvalidCharacterError:{s:"INVALID_CHARACTER_ERR",c:5,m:1},NoDataAllowedError:{s:"NO_DATA_ALLOWED_ERR",c:6,m:0},NoModificationAllowedError:{s:"NO_MODIFICATION_ALLOWED_ERR",c:7,m:1},NotFoundError:{s:"NOT_FOUND_ERR",c:8,m:1},NotSupportedError:{s:"NOT_SUPPORTED_ERR",c:9,m:1},InUseAttributeError:{s:"INUSE_ATTRIBUTE_ERR",c:10,m:1},InvalidStateError:{s:"INVALID_STATE_ERR",c:11,m:1},SyntaxError:{s:"SYNTAX_ERR",c:12,m:1},InvalidModificationError:{s:"INVALID_MODIFICATION_ERR",c:13,m:1},NamespaceError:{s:"NAMESPACE_ERR",c:14,m:1},InvalidAccessError:{s:"INVALID_ACCESS_ERR",c:15,m:1},ValidationError:{s:"VALIDATION_ERR",c:16,m:0},TypeMismatchError:{s:"TYPE_MISMATCH_ERR",c:17,m:1},SecurityError:{s:"SECURITY_ERR",c:18,m:1},NetworkError:{s:"NETWORK_ERR",c:19,m:1},AbortError:{s:"ABORT_ERR",c:20,m:1},URLMismatchError:{s:"URL_MISMATCH_ERR",c:21,m:1},QuotaExceededError:{s:"QUOTA_EXCEEDED_ERR",c:22,m:1},TimeoutError:{s:"TIMEOUT_ERR",c:23,m:1},InvalidNodeTypeError:{s:"INVALID_NODE_TYPE_ERR",c:24,m:1},DataCloneError:{s:"DATA_CLONE_ERR",c:25,m:1}},ave=C,ive=nve,fv=Et,c_=le,ove=dn,f_=cn,dv=ht.f,sve=Ot,Ad=Xc,Od=at,lve=va,uve=Ge,mL=Mk,rA=Fc,qs=hL,cve=up,gL=Kt,d_=Ve,ul="DOMException",l1="DATA_CLONE_ERR",Lp=fv("Error"),Fa=fv(ul)||function(){try{var e=fv("MessageChannel")||ive("worker_threads").MessageChannel;new e().port1.postMessage(new WeakMap)}catch(t){if(t.name==l1&&t.code==25)return t.constructor}}(),fve=Fa&&Fa.prototype,yL=Lp.prototype,dve=gL.set,vve=gL.getterFor(ul),pve="stack"in Lp(ul),bL=function(e){return Od(qs,e)&&qs[e].m?qs[e].c:0},v_=function(){lve(this,Ou);var t=arguments.length,r=rA(t<1?void 0:arguments[0]),n=rA(t<2?void 0:arguments[1],"Error"),a=bL(n);if(dve(this,{type:ul,name:n,message:r,code:a}),d_||(this.name=n,this.message=r,this.code=a),pve){var i=Lp(r);i.name=ul,dv(this,"stack",f_(1,cve(i.stack,1)))}},Ou=v_.prototype=ove(yL),_L=function(e){return{enumerable:!0,configurable:!0,get:e}},og=function(e){return _L(function(){return vve(this)[e]})};d_&&(Ad(Ou,"code",og("code")),Ad(Ou,"message",og("message")),Ad(Ou,"name",og("name")));dv(Ou,"constructor",f_(1,v_));var Dp=c_(function(){return!(new Fa instanceof Lp)}),hve=Dp||c_(function(){return yL.toString!==mL||String(new Fa(1,2))!=="2: 1"}),mve=Dp||c_(function(){return new Fa(1,"DataCloneError").code!==25});Dp||Fa[l1]!==25||fve[l1];var nA=Dp;ave({global:!0,constructor:!0,forced:nA},{DOMException:nA?v_:Fa});var Ju=fv(ul),vv=Ju.prototype;hve&&Fa===Ju&&sve(vv,"toString",mL);mve&&d_&&Fa===Ju&&Ad(vv,"code",_L(function(){return bL(uve(this).name)}));for(var aA in qs)if(Od(qs,aA)){var iA=qs[aA],Xf=iA.s,oA=f_(6,iA.c);Od(Ju,Xf)||dv(Ju,Xf,oA),Od(vv,Xf)||dv(vv,Xf,oA)}var gve=C,p_=Et,u1=cn,c1=ht.f,sA=at,yve=va,bve=Tl,lA=Fc,sg=hL,_ve=up,Np="DOMException",$L=p_("Error"),Fp=p_(Np),h_=function(){yve(this,$ve);var t=arguments.length,r=lA(t<1?void 0:arguments[0]),n=lA(t<2?void 0:arguments[1],"Error"),a=new Fp(r,n),i=$L(r);return i.name=Np,c1(a,"stack",u1(1,_ve(i.stack,1))),bve(a,this,h_),a},$ve=h_.prototype=Fp.prototype,xve="stack"in $L(Np),Sve="stack"in new Fp(1,2),uA=xve&&!Sve;gve({global:!0,constructor:!0,forced:uA},{DOMException:uA?h_:Fp});var yu=p_(Np),cA=yu.prototype;if(cA.constructor!==yu){c1(cA,"constructor",u1(1,yu));for(var fA in sg)if(sA(sg,fA)){var dA=sg[fA],vA=dA.s;sA(yu,vA)||c1(yu,vA,u1(6,dA.c))}}var wve=Et,Tve=Ur,pA="DOMException";Tve(wve(pA),pA);var Eve=C,Ave=Se,hA=Sp.clear;Eve({global:!0,bind:!0,enumerable:!0,forced:Ave.clearImmediate!==hA},{clearImmediate:hA});var Ove=C,Cve=Se,mA=Sp.set;Ove({global:!0,bind:!0,enumerable:!0,forced:Cve.setImmediate!==mA},{setImmediate:mA});var Ive=C,kve=Se,Pve=oR,Rve=qt,Mve=zi,Lve=Ko,Dve=kve.process;Ive({global:!0,enumerable:!0,dontCallGetSet:!0},{queueMicrotask:function(t){Mve(arguments.length,1),Rve(t);var r=Lve&&Dve.domain;Pve(r?r.bind(t):t)}});var Nve=C,Mt=Se,ef=Et,ei=ue,Vp=le,Fve=xl,f1=Qe,xL=wl,d1=qe,Vve=Go,jve=da,SL=Ge,wL=Ka,Bve=at,Hve=Za,lg=br,v1=Ct,Uve=zi,Gve=Kc,Wve=zb,bu=Mt.Object,TL=Mt.Date,cl=Mt.Error,Yve=Mt.EvalError,zve=Mt.RangeError,qve=Mt.ReferenceError,Kve=Mt.SyntaxError,EL=Mt.TypeError,Zve=Mt.URIError,Xve=Mt.PerformanceMark,fl=Mt.WebAssembly,Jve=fl&&fl.CompileError||cl,Qve=fl&&fl.LinkError||cl,epe=fl&&fl.RuntimeError||cl,dl=ef("DOMException"),AL=ef("Set"),pv=ef("Map"),m_=pv.prototype,OL=ei(m_.has),tpe=ei(m_.get),hv=ei(m_.set),rpe=ei(AL.prototype.add),npe=ef("Object","keys"),ape=ei([].push),ipe=ei((!0).valueOf),ope=ei(1 .valueOf),spe=ei("".valueOf),lpe=ei(TL.prototype.getTime),p1=Fve("structuredClone"),Qu="DataCloneError",ug="Transferring",CL=function(e){return!Vp(function(){var t=new Mt.Set([7]),r=e(t),n=e(bu(7));return r==t||!r.has(7)||typeof n!="object"||n!=7})&&e},upe=function(e){return!Vp(function(){var t=new cl,r=e({a:t,b:t});return!(r&&r.a===r.b&&r.a instanceof cl)})},cpe=function(e){return!Vp(function(){var t=e(new Mt.AggregateError([1],p1,{cause:3}));return t.name!="AggregateError"||t.errors[0]!=1||t.message!=p1||t.cause!=3})},Ho=Mt.structuredClone,fpe=!upe(Ho)||!cpe(Ho),dpe=!Ho&&CL(function(e){return new Xve(p1,{detail:e}).detail}),vi=CL(Ho)||dpe,cg=function(e){throw new dl("Uncloneable type: "+e,Qu)},pr=function(e,t){throw new dl((t||"Cloning")+" of "+e+" cannot be properly polyfilled in this engine",Qu)},ar=function(e,t){if(Vve(e)&&cg("Symbol"),!d1(e))return e;if(t){if(OL(t,e))return tpe(t,e)}else t=new pv;var r=wL(e),n=!1,a,i,o,l,u,f,d,s,c,v;switch(r){case"Array":o=[],n=!0;break;case"Object":o={},n=!0;break;case"Map":o=new pv,n=!0;break;case"Set":o=new AL,n=!0;break;case"RegExp":o=new RegExp(e.source,Gve(e));break;case"Error":switch(i=e.name,i){case"AggregateError":o=ef("AggregateError")([]);break;case"EvalError":o=Yve();break;case"RangeError":o=zve();break;case"ReferenceError":o=qve();break;case"SyntaxError":o=Kve();break;case"TypeError":o=EL();break;case"URIError":o=Zve();break;case"CompileError":o=Jve();break;case"LinkError":o=Qve();break;case"RuntimeError":o=epe();break;default:o=cl()}n=!0;break;case"DOMException":o=new dl(e.message,e.name),n=!0;break;case"DataView":case"Int8Array":case"Uint8Array":case"Uint8ClampedArray":case"Int16Array":case"Uint16Array":case"Int32Array":case"Uint32Array":case"Float32Array":case"Float64Array":case"BigInt64Array":case"BigUint64Array":a=Mt[r],d1(a)||pr(r),o=new a(ar(e.buffer,t),e.byteOffset,r==="DataView"?e.byteLength:e.length);break;case"DOMQuad":try{o=new DOMQuad(ar(e.p1,t),ar(e.p2,t),ar(e.p3,t),ar(e.p4,t))}catch{vi?o=vi(e):pr(r)}break;case"FileList":if(a=Mt.DataTransfer,xL(a)){for(l=new a,u=0,f=v1(e);u1&&arguments[1]!=null?SL(arguments[1]):void 0,n=r?r.transfer:void 0,a;return n!==void 0&&(a=new pv,vpe(n,a)),ar(t,a)}});var h1=Se,ppe=vn,hpe=Qe,mpe=Wa,gpe=zo,ype=zi,bpe=/MSIE .\./.test(mpe),_pe=h1.Function,gA=function(e){return bpe?function(t,r){var n=ype(arguments.length,1)>2,a=hpe(t)?t:_pe(t),i=n?gpe(arguments,2):void 0;return e(n?function(){ppe(a,this,i)}:a,r)}:e},kL={setTimeout:gA(h1.setTimeout),setInterval:gA(h1.setInterval)},$pe=C,xpe=Se,yA=kL.setInterval;$pe({global:!0,bind:!0,forced:xpe.setInterval!==yA},{setInterval:yA});var Spe=C,wpe=Se,bA=kL.setTimeout;Spe({global:!0,bind:!0,forced:wpe.setTimeout!==bA},{setTimeout:bA});var Tpe=le,Epe=Ke,Ape=DI,Ope=Epe("iterator"),PL=!Tpe(function(){var e=new URL("b?a=1&b=2&c=3","http://a"),t=e.searchParams,r="";return e.pathname="c%20d",t.forEach(function(n,a){t.delete("b"),r+=a+n}),Ape&&!e.toJSON||!t.sort||e.href!=="http://a/c%20d?a=1&c=3"||t.get("c")!=="3"||String(new URLSearchParams("?a=1"))!=="a=1"||!t[Ope]||new URL("https://a@b").username!=="a"||new URLSearchParams(new URLSearchParams("a=b")).get("a")!=="b"||new URL("http://теÑÑ‚").host!=="xn--e1aybc"||new URL("http://a#б").hash!=="#%D0%B1"||r!=="a1c3"||new URL("http://x",void 0).host!=="x"}),Xo=ue,fg=2147483647,Cu=36,RL=1,m1=26,Cpe=38,Ipe=700,kpe=72,Ppe=128,Rpe="-",Mpe=/[^\0-\u007E]/,ML=/[.\u3002\uFF0E\uFF61]/g,_A="Overflow: input needs wider integers to process",dg=Cu-RL,$A=RangeError,Lpe=Xo(ML.exec),Bs=Math.floor,vg=String.fromCharCode,xA=Xo("".charCodeAt),LL=Xo([].join),ki=Xo([].push),Dpe=Xo("".replace),Npe=Xo("".split),Fpe=Xo("".toLowerCase),Vpe=function(e){for(var t=[],r=0,n=e.length;r=55296&&a<=56319&&r>1,e+=Bs(e/t);e>dg*m1>>1;)e=Bs(e/dg),n+=Cu;return Bs(n+(dg+1)*e/(e+Cpe))},Bpe=function(e){var t=[];e=Vpe(e);var r=e.length,n=Ppe,a=0,i=kpe,o,l;for(o=0;o=n&&lBs((fg-a)/s))throw $A(_A);for(a+=(d-n)*s,n=d,o=0;ofg)throw $A(_A);if(l==n){for(var c=a,v=Cu;;){var p=v<=i?RL:v>=i+m1?m1:v-i;if(c0?arguments[0]:void 0;BL(this,new UL(t))},ec=jp.prototype;Gpe(ec,{append:function(t,r){bs(arguments.length,2);var n=wn(this);Eo(n.entries,{key:Rr(t),value:Rr(r)}),n.updateURL()},delete:function(e){bs(arguments.length,1);for(var t=wn(this),r=t.entries,n=Rr(e),a=0;an.key?1:-1}),t.updateURL()},forEach:function(t){for(var r=wn(this).entries,n=qpe(t,arguments.length>1?arguments[1]:void 0),a=0,i;a1?RA(arguments[1]):{})}}),pg(mv)){var gg=function(t){return FL(this,hg),new mv(t,arguments.length>1?RA(arguments[1]):{})};hg.constructor=gg,gg.prototype=hg,g1({global:!0,constructor:!0,dontCallGetSet:!0,forced:!0},{Request:gg})}}var yhe={URLSearchParams:jp,getState:wn},bhe=C,b_=Ve,_he=PL,__=Se,MA=ua,hn=ue,gv=Ot,Zr=Xc,$he=va,_1=at,$_=ZP,_s=Gk,$n=Mc,xhe=Op.codeAt,She=Hpe,xa=et,whe=Ur,The=zi,GL=yhe,WL=Kt,Ehe=WL.set,yv=WL.getterFor("URL"),Ahe=GL.URLSearchParams,Ohe=GL.getState,Ql=__.URL,$1=__.TypeError,bv=__.parseInt,Che=Math.floor,LA=Math.pow,rn=hn("".charAt),An=hn(/./.exec),_u=hn([].join),Ihe=hn(1 .toString),khe=hn([].pop),Rs=hn([].push),DA=hn("".replace),Phe=hn([].shift),Rhe=hn("".split),ku=hn("".slice),_v=hn("".toLowerCase),Mhe=hn([].unshift),Lhe="Invalid authority",yg="Invalid scheme",uo="Invalid host",NA="Invalid port",YL=/[a-z]/i,Dhe=/[\d+-.a-z]/i,x1=/\d/,Nhe=/^0x/i,Fhe=/^[0-7]+$/,Vhe=/^\d+$/,zL=/^[\da-f]+$/i,jhe=/[\0\t\n\r #%/:<>?@[\\\]^|]/,Bhe=/[\0\t\n\r #/:<>?@[\\\]^|]/,Hhe=/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g,Uhe=/[\t\n\r]/g,Xr,Ghe=function(e){var t=Rhe(e,"."),r,n,a,i,o,l,u;if(t.length&&t[t.length-1]==""&&t.length--,r=t.length,r>4)return e;for(n=[],a=0;a1&&rn(i,0)=="0"&&(o=An(Nhe,i)?16:8,i=ku(i,o==8?1:2)),i==="")l=0;else{if(!An(o==10?Vhe:o==8?Fhe:zL,i))return e;l=bv(i,o)}Rs(n,l)}for(a=0;a=LA(256,5-r))return null}else if(l>255)return null;for(u=khe(n),a=0;a6))return;for(l=0;c();){if(u=null,l>0)if(c()=="."&&l<4)a++;else return;if(!An(x1,c()))return;for(;An(x1,c());){if(f=bv(c(),10),u===null)u=f;else{if(u==0)return;u=u*10+f}if(u>255)return;a++}t[r]=t[r]*256+u,l++,(l==2||l==4)&&r++}if(l!=4)return;break}else if(c()==":"){if(a++,!c())return}else if(c())return;t[r++]=i}if(n!==null)for(d=r-n,r=7;r!=0&&d>0;)s=t[r],t[r--]=t[n+d-1],t[n+--d]=s;else if(r!=8)return;return t},Yhe=function(e){for(var t=null,r=1,n=null,a=0,i=0;i<8;i++)e[i]!==0?(a>r&&(t=n,r=a),n=null,a=0):(n===null&&(n=i),++a);return a>r&&(t=n,r=a),t},eu=function(e){var t,r,n,a;if(typeof e=="number"){for(t=[],r=0;r<4;r++)Mhe(t,e%256),e=Che(e/256);return _u(t,".")}else if(typeof e=="object"){for(t="",n=Yhe(e),r=0;r<8;r++)a&&e[r]===0||(a&&(a=!1),n===r?(t+=r?":":"::",a=!0):(t+=Ihe(e[r],16),r<7&&(t+=":")));return"["+t+"]"}return e},Cd={},qL=$_({},Cd,{" ":1,'"':1,"<":1,">":1,"`":1}),KL=$_({},qL,{"#":1,"?":1,"{":1,"}":1}),bg=$_({},KL,{"/":1,":":1,";":1,"=":1,"@":1,"[":1,"\\":1,"]":1,"^":1,"|":1}),pi=function(e,t){var r=xhe(e,0);return r>32&&r<127&&!_1(t,e)?e:encodeURIComponent(e)},Qf={ftp:21,file:null,http:80,https:443,ws:80,wss:443},$u=function(e,t){var r;return e.length==2&&An(YL,rn(e,0))&&((r=rn(e,1))==":"||!t&&r=="|")},FA=function(e){var t;return e.length>1&&$u(ku(e,0,2))&&(e.length==2||(t=rn(e,2))==="/"||t==="\\"||t==="?"||t==="#")},zhe=function(e){return e==="."||_v(e)==="%2e"},qhe=function(e){return e=_v(e),e===".."||e==="%2e."||e===".%2e"||e==="%2e%2e"},_g={},VA={},$g={},jA={},BA={},xg={},HA={},UA={},ed={},td={},Sg={},wg={},Tg={},Eg={},GA={},Ag={},$s={},zn={},WA={},co={},_a={},x_=function(e,t,r){var n=xa(e),a,i,o;if(t){if(i=this.parse(n),i)throw $1(i);this.searchParams=null}else{if(r!==void 0&&(a=new x_(r,!0)),i=this.parse(n,null,a),i)throw $1(i);o=Ohe(new Ahe),o.bindURL(this),this.searchParams=o}};x_.prototype={type:"URL",parse:function(e,t,r){var n=this,a=t||_g,i=0,o="",l=!1,u=!1,f=!1,d,s,c,v;for(e=xa(e),t||(n.scheme="",n.username="",n.password="",n.host=null,n.port=null,n.path=[],n.query=null,n.fragment=null,n.cannotBeABaseURL=!1,e=DA(e,Hhe,"")),e=DA(e,Uhe,""),d=_s(e);i<=d.length;){switch(s=d[i],a){case _g:if(s&&An(YL,s))o+=_v(s),a=VA;else{if(t)return yg;a=$g;continue}break;case VA:if(s&&(An(Dhe,s)||s=="+"||s=="-"||s=="."))o+=_v(s);else if(s==":"){if(t&&(n.isSpecial()!=_1(Qf,o)||o=="file"&&(n.includesCredentials()||n.port!==null)||n.scheme=="file"&&!n.host))return;if(n.scheme=o,t){n.isSpecial()&&Qf[n.scheme]==n.port&&(n.port=null);return}o="",n.scheme=="file"?a=Eg:n.isSpecial()&&r&&r.scheme==n.scheme?a=jA:n.isSpecial()?a=UA:d[i+1]=="/"?(a=BA,i++):(n.cannotBeABaseURL=!0,Rs(n.path,""),a=WA)}else{if(t)return yg;o="",a=$g,i=0;continue}break;case $g:if(!r||r.cannotBeABaseURL&&s!="#")return yg;if(r.cannotBeABaseURL&&s=="#"){n.scheme=r.scheme,n.path=$n(r.path),n.query=r.query,n.fragment="",n.cannotBeABaseURL=!0,a=_a;break}a=r.scheme=="file"?Eg:xg;continue;case jA:if(s=="/"&&d[i+1]=="/")a=ed,i++;else{a=xg;continue}break;case BA:if(s=="/"){a=td;break}else{a=zn;continue}case xg:if(n.scheme=r.scheme,s==Xr)n.username=r.username,n.password=r.password,n.host=r.host,n.port=r.port,n.path=$n(r.path),n.query=r.query;else if(s=="/"||s=="\\"&&n.isSpecial())a=HA;else if(s=="?")n.username=r.username,n.password=r.password,n.host=r.host,n.port=r.port,n.path=$n(r.path),n.query="",a=co;else if(s=="#")n.username=r.username,n.password=r.password,n.host=r.host,n.port=r.port,n.path=$n(r.path),n.query=r.query,n.fragment="",a=_a;else{n.username=r.username,n.password=r.password,n.host=r.host,n.port=r.port,n.path=$n(r.path),n.path.length--,a=zn;continue}break;case HA:if(n.isSpecial()&&(s=="/"||s=="\\"))a=ed;else if(s=="/")a=td;else{n.username=r.username,n.password=r.password,n.host=r.host,n.port=r.port,a=zn;continue}break;case UA:if(a=ed,s!="/"||rn(o,i+1)!="/")continue;i++;break;case ed:if(s!="/"&&s!="\\"){a=td;continue}break;case td:if(s=="@"){l&&(o="%40"+o),l=!0,c=_s(o);for(var p=0;p65535)return NA;n.port=n.isSpecial()&&g===Qf[n.scheme]?null:g,o=""}if(t)return;a=$s;continue}else return NA;break;case Eg:if(n.scheme="file",s=="/"||s=="\\")a=GA;else if(r&&r.scheme=="file")if(s==Xr)n.host=r.host,n.path=$n(r.path),n.query=r.query;else if(s=="?")n.host=r.host,n.path=$n(r.path),n.query="",a=co;else if(s=="#")n.host=r.host,n.path=$n(r.path),n.query=r.query,n.fragment="",a=_a;else{FA(_u($n(d,i),""))||(n.host=r.host,n.path=$n(r.path),n.shortenPath()),a=zn;continue}else{a=zn;continue}break;case GA:if(s=="/"||s=="\\"){a=Ag;break}r&&r.scheme=="file"&&!FA(_u($n(d,i),""))&&($u(r.path[0],!0)?Rs(n.path,r.path[0]):n.host=r.host),a=zn;continue;case Ag:if(s==Xr||s=="/"||s=="\\"||s=="?"||s=="#"){if(!t&&$u(o))a=zn;else if(o==""){if(n.host="",t)return;a=$s}else{if(v=n.parseHost(o),v)return v;if(n.host=="localhost"&&(n.host=""),t)return;o="",a=$s}continue}else o+=s;break;case $s:if(n.isSpecial()){if(a=zn,s!="/"&&s!="\\")continue}else if(!t&&s=="?")n.query="",a=co;else if(!t&&s=="#")n.fragment="",a=_a;else if(s!=Xr&&(a=zn,s!="/"))continue;break;case zn:if(s==Xr||s=="/"||s=="\\"&&n.isSpecial()||!t&&(s=="?"||s=="#")){if(qhe(o)?(n.shortenPath(),s!="/"&&!(s=="\\"&&n.isSpecial())&&Rs(n.path,"")):zhe(o)?s!="/"&&!(s=="\\"&&n.isSpecial())&&Rs(n.path,""):(n.scheme=="file"&&!n.path.length&&$u(o)&&(n.host&&(n.host=""),o=rn(o,0)+":"),Rs(n.path,o)),o="",n.scheme=="file"&&(s==Xr||s=="?"||s=="#"))for(;n.path.length>1&&n.path[0]==="";)Phe(n.path);s=="?"?(n.query="",a=co):s=="#"&&(n.fragment="",a=_a)}else o+=pi(s,KL);break;case WA:s=="?"?(n.query="",a=co):s=="#"?(n.fragment="",a=_a):s!=Xr&&(n.path[0]+=pi(s,Cd));break;case co:!t&&s=="#"?(n.fragment="",a=_a):s!=Xr&&(s=="'"&&n.isSpecial()?n.query+="%27":s=="#"?n.query+="%23":n.query+=pi(s,Cd));break;case _a:s!=Xr&&(n.fragment+=pi(s,qL));break}i++}},parseHost:function(e){var t,r,n;if(rn(e,0)=="["){if(rn(e,e.length-1)!="]"||(t=Whe(ku(e,1,-1)),!t))return uo;this.host=t}else if(this.isSpecial()){if(e=She(e),An(jhe,e)||(t=Ghe(e),t===null))return uo;this.host=t}else{if(An(Bhe,e))return uo;for(t="",r=_s(e),n=0;n1?arguments[1]:void 0,a=Ehe(r,new x_(t,!1,n));b_||(r.href=a.serialize(),r.origin=a.getOrigin(),r.protocol=a.getProtocol(),r.username=a.getUsername(),r.password=a.getPassword(),r.host=a.getHost(),r.hostname=a.getHostname(),r.port=a.getPort(),r.pathname=a.getPathname(),r.search=a.getSearch(),r.searchParams=a.getSearchParams(),r.hash=a.getHash())},hr=pl.prototype,Jr=function(e,t){return{get:function(){return yv(this)[e]()},set:t&&function(r){return yv(this)[t](r)},configurable:!0,enumerable:!0}};b_&&(Zr(hr,"href",Jr("serialize","setHref")),Zr(hr,"origin",Jr("getOrigin")),Zr(hr,"protocol",Jr("getProtocol","setProtocol")),Zr(hr,"username",Jr("getUsername","setUsername")),Zr(hr,"password",Jr("getPassword","setPassword")),Zr(hr,"host",Jr("getHost","setHost")),Zr(hr,"hostname",Jr("getHostname","setHostname")),Zr(hr,"port",Jr("getPort","setPort")),Zr(hr,"pathname",Jr("getPathname","setPathname")),Zr(hr,"search",Jr("getSearch","setSearch")),Zr(hr,"searchParams",Jr("getSearchParams")),Zr(hr,"hash",Jr("getHash","setHash")));gv(hr,"toJSON",function(){return yv(this).serialize()},{enumerable:!0});gv(hr,"toString",function(){return yv(this).serialize()},{enumerable:!0});if(Ql){var YA=Ql.createObjectURL,zA=Ql.revokeObjectURL;YA&&gv(pl,"createObjectURL",MA(YA,Ql)),zA&&gv(pl,"revokeObjectURL",MA(zA,Ql))}whe(pl,"URL");bhe({global:!0,constructor:!0,forced:!_he,sham:!b_},{URL:pl});var Khe=C,Zhe=Ye;Khe({target:"URL",proto:!0,enumerable:!0},{toJSON:function(){return Zhe(URL.prototype.toString,this)}});(function(e){e.exports=QI})(c4);var qA={},Xhe={get exports(){return qA},set exports(e){qA=e}};(function(e){var t=function(r){var n=Object.prototype,a=n.hasOwnProperty,i,o=typeof Symbol=="function"?Symbol:{},l=o.iterator||"@@iterator",u=o.asyncIterator||"@@asyncIterator",f=o.toStringTag||"@@toStringTag";function d(I,O,L){return Object.defineProperty(I,O,{value:L,enumerable:!0,configurable:!0,writable:!0}),I[O]}try{d({},"")}catch{d=function(O,L,H){return O[L]=H}}function s(I,O,L,H){var Y=O&&O.prototype instanceof b?O:b,oe=Object.create(Y.prototype),Oe=new j(H||[]);return oe._invoke=U(I,L,Oe),oe}r.wrap=s;function c(I,O,L){try{return{type:"normal",arg:I.call(O,L)}}catch(H){return{type:"throw",arg:H}}}var v="suspendedStart",p="suspendedYield",h="executing",m="completed",g={};function b(){}function _(){}function A(){}var D={};d(D,l,function(){return this});var V=Object.getPrototypeOf,R=V&&V(V(J([])));R&&R!==n&&a.call(R,l)&&(D=R);var x=A.prototype=b.prototype=Object.create(D);_.prototype=A,d(x,"constructor",A),d(A,"constructor",_),_.displayName=d(A,f,"GeneratorFunction");function P(I){["next","throw","return"].forEach(function(O){d(I,O,function(L){return this._invoke(O,L)})})}r.isGeneratorFunction=function(I){var O=typeof I=="function"&&I.constructor;return O?O===_||(O.displayName||O.name)==="GeneratorFunction":!1},r.mark=function(I){return Object.setPrototypeOf?Object.setPrototypeOf(I,A):(I.__proto__=A,d(I,f,"GeneratorFunction")),I.prototype=Object.create(x),I},r.awrap=function(I){return{__await:I}};function B(I,O){function L(oe,Oe,M,K){var W=c(I[oe],I,Oe);if(W.type==="throw")K(W.arg);else{var ce=W.arg,Ee=ce.value;return Ee&&typeof Ee=="object"&&a.call(Ee,"__await")?O.resolve(Ee.__await).then(function(Ce){L("next",Ce,M,K)},function(Ce){L("throw",Ce,M,K)}):O.resolve(Ee).then(function(Ce){ce.value=Ce,M(ce)},function(Ce){return L("throw",Ce,M,K)})}}var H;function Y(oe,Oe){function M(){return new O(function(K,W){L(oe,Oe,K,W)})}return H=H?H.then(M,M):M()}this._invoke=Y}P(B.prototype),d(B.prototype,u,function(){return this}),r.AsyncIterator=B,r.async=function(I,O,L,H,Y){Y===void 0&&(Y=Promise);var oe=new B(s(I,O,L,H),Y);return r.isGeneratorFunction(O)?oe:oe.next().then(function(Oe){return Oe.done?Oe.value:oe.next()})};function U(I,O,L){var H=v;return function(oe,Oe){if(H===h)throw new Error("Generator is already running");if(H===m){if(oe==="throw")throw Oe;return Q()}for(L.method=oe,L.arg=Oe;;){var M=L.delegate;if(M){var K=N(M,L);if(K){if(K===g)continue;return K}}if(L.method==="next")L.sent=L._sent=L.arg;else if(L.method==="throw"){if(H===v)throw H=m,L.arg;L.dispatchException(L.arg)}else L.method==="return"&&L.abrupt("return",L.arg);H=h;var W=c(I,O,L);if(W.type==="normal"){if(H=L.done?m:p,W.arg===g)continue;return{value:W.arg,done:L.done}}else W.type==="throw"&&(H=m,L.method="throw",L.arg=W.arg)}}}function N(I,O){var L=I.iterator[O.method];if(L===i){if(O.delegate=null,O.method==="throw"){if(I.iterator.return&&(O.method="return",O.arg=i,N(I,O),O.method==="throw"))return g;O.method="throw",O.arg=new TypeError("The iterator does not provide a 'throw' method")}return g}var H=c(L,I.iterator,O.arg);if(H.type==="throw")return O.method="throw",O.arg=H.arg,O.delegate=null,g;var Y=H.arg;if(!Y)return O.method="throw",O.arg=new TypeError("iterator result is not an object"),O.delegate=null,g;if(Y.done)O[I.resultName]=Y.value,O.next=I.nextLoc,O.method!=="return"&&(O.method="next",O.arg=i);else return Y;return O.delegate=null,g}P(x),d(x,f,"Generator"),d(x,l,function(){return this}),d(x,"toString",function(){return"[object Generator]"});function G(I){var O={tryLoc:I[0]};1 in I&&(O.catchLoc=I[1]),2 in I&&(O.finallyLoc=I[2],O.afterLoc=I[3]),this.tryEntries.push(O)}function S(I){var O=I.completion||{};O.type="normal",delete O.arg,I.completion=O}function j(I){this.tryEntries=[{tryLoc:"root"}],I.forEach(G,this),this.reset(!0)}r.keys=function(I){var O=[];for(var L in I)O.push(L);return O.reverse(),function H(){for(;O.length;){var Y=O.pop();if(Y in I)return H.value=Y,H.done=!1,H}return H.done=!0,H}};function J(I){if(I){var O=I[l];if(O)return O.call(I);if(typeof I.next=="function")return I;if(!isNaN(I.length)){var L=-1,H=function Y(){for(;++L=0;--H){var Y=this.tryEntries[H],oe=Y.completion;if(Y.tryLoc==="root")return L("end");if(Y.tryLoc<=this.prev){var Oe=a.call(Y,"catchLoc"),M=a.call(Y,"finallyLoc");if(Oe&&M){if(this.prev=0;--L){var H=this.tryEntries[L];if(H.tryLoc<=this.prev&&a.call(H,"finallyLoc")&&this.prev=0;--O){var L=this.tryEntries[O];if(L.finallyLoc===I)return this.complete(L.completion,L.afterLoc),S(L),g}},catch:function(I){for(var O=this.tryEntries.length-1;O>=0;--O){var L=this.tryEntries[O];if(L.tryLoc===I){var H=L.completion;if(H.type==="throw"){var Y=H.arg;S(L)}return Y}}throw new Error("illegal catch attempt")},delegateYield:function(I,O,L){return this.delegate={iterator:J(I),resultName:O,nextLoc:L},this.method==="next"&&(this.arg=i),g}},r}(e.exports);try{regeneratorRuntime=t}catch{typeof globalThis=="object"?globalThis.regeneratorRuntime=t:Function("r","regeneratorRuntime = r")(t)}})(Xhe);/*! @license DOMPurify 2.3.10 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.3.10/LICENSE */function Oi(e){return Oi=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Oi(e)}function S1(e,t){return S1=Object.setPrototypeOf||function(n,a){return n.__proto__=a,n},S1(e,t)}function Jhe(){if(typeof Reflect>"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function Id(e,t,r){return Jhe()?Id=Reflect.construct:Id=function(a,i,o){var l=[null];l.push.apply(l,i);var u=Function.bind.apply(a,l),f=new u;return o&&S1(f,o.prototype),f},Id.apply(null,arguments)}function Sn(e){return Qhe(e)||eme(e)||tme(e)||rme()}function Qhe(e){if(Array.isArray(e))return w1(e)}function eme(e){if(typeof Symbol<"u"&&e[Symbol.iterator]!=null||e["@@iterator"]!=null)return Array.from(e)}function tme(e,t){if(e){if(typeof e=="string")return w1(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);if(r==="Object"&&e.constructor&&(r=e.constructor.name),r==="Map"||r==="Set")return Array.from(e);if(r==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return w1(e,t)}}function w1(e,t){(t==null||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r1?r-1:0),a=1;a/gm),gme=aa(/^data-[\-\w.\u00B7-\uFFFF]/),yme=aa(/^aria-[\-\w]+$/),bme=aa(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),_me=aa(/^(?:\w+script|data):/i),$me=aa(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),xme=aa(/^html$/i),Sme=function(){return typeof window>"u"?null:window},wme=function(t,r){if(Oi(t)!=="object"||typeof t.createPolicy!="function")return null;var n=null,a="data-tt-policy-suffix";r.currentScript&&r.currentScript.hasAttribute(a)&&(n=r.currentScript.getAttribute(a));var i="dompurify"+(n?"#"+n:"");try{return t.createPolicy(i,{createHTML:function(l){return l},createScriptURL:function(l){return l}})}catch{return console.warn("TrustedTypes policy "+i+" could not be created."),null}};function XL(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:Sme(),t=function(k){return XL(k)};if(t.version="2.3.10",t.removed=[],!e||!e.document||e.document.nodeType!==9)return t.isSupported=!1,t;var r=e.document,n=e.document,a=e.DocumentFragment,i=e.HTMLTemplateElement,o=e.Node,l=e.Element,u=e.NodeFilter,f=e.NamedNodeMap,d=f===void 0?e.NamedNodeMap||e.MozNamedAttrMap:f,s=e.HTMLFormElement,c=e.DOMParser,v=e.trustedTypes,p=l.prototype,h=rd(p,"cloneNode"),m=rd(p,"nextSibling"),g=rd(p,"childNodes"),b=rd(p,"parentNode");if(typeof i=="function"){var _=n.createElement("template");_.content&&_.content.ownerDocument&&(n=_.content.ownerDocument)}var A=wme(v,r),D=A?A.createHTML(""):"",V=n,R=V.implementation,x=V.createNodeIterator,P=V.createDocumentFragment,B=V.getElementsByTagName,U=r.importNode,N={};try{N=fo(n).documentMode?n.documentMode:{}}catch{}var G={};t.isSupported=typeof b=="function"&&R&&typeof R.createHTMLDocument<"u"&&N!==9;var S=hme,j=mme,J=gme,Q=yme,I=_me,O=$me,L=bme,H=null,Y=je({},[].concat(Sn(XA),Sn(Cg),Sn(Ig),Sn(kg),Sn(JA))),oe=null,Oe=je({},[].concat(Sn(QA),Sn(Pg),Sn(eO),Sn(nd))),M=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),K=null,W=null,ce=!0,Ee=!0,Ce=!1,ge=!1,ye=!1,$=!1,T=!1,F=!1,q=!1,Z=!1,ae=!0,fe=!0,ne=!1,ie={},ee=null,_e=je({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),me=null,$e=je({},["audio","video","img","source","image","track"]),Ae=null,We=je({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),ut="http://www.w3.org/1998/Math/MathML",ct="http://www.w3.org/2000/svg",Ze="http://www.w3.org/1999/xhtml",rr=Ze,Yn=!1,ga,to=["application/xhtml+xml","text/html"],mf="text/html",it,Jt=null,gf=n.createElement("form"),ax=function(k){return k instanceof RegExp||k instanceof Function},kh=function(k){Jt&&Jt===k||((!k||Oi(k)!=="object")&&(k={}),k=fo(k),ga=to.indexOf(k.PARSER_MEDIA_TYPE)===-1?ga=mf:ga=k.PARSER_MEDIA_TYPE,it=ga==="application/xhtml+xml"?function(re){return re}:kd,H="ALLOWED_TAGS"in k?je({},k.ALLOWED_TAGS,it):Y,oe="ALLOWED_ATTR"in k?je({},k.ALLOWED_ATTR,it):Oe,Ae="ADD_URI_SAFE_ATTR"in k?je(fo(We),k.ADD_URI_SAFE_ATTR,it):We,me="ADD_DATA_URI_TAGS"in k?je(fo($e),k.ADD_DATA_URI_TAGS,it):$e,ee="FORBID_CONTENTS"in k?je({},k.FORBID_CONTENTS,it):_e,K="FORBID_TAGS"in k?je({},k.FORBID_TAGS,it):{},W="FORBID_ATTR"in k?je({},k.FORBID_ATTR,it):{},ie="USE_PROFILES"in k?k.USE_PROFILES:!1,ce=k.ALLOW_ARIA_ATTR!==!1,Ee=k.ALLOW_DATA_ATTR!==!1,Ce=k.ALLOW_UNKNOWN_PROTOCOLS||!1,ge=k.SAFE_FOR_TEMPLATES||!1,ye=k.WHOLE_DOCUMENT||!1,F=k.RETURN_DOM||!1,q=k.RETURN_DOM_FRAGMENT||!1,Z=k.RETURN_TRUSTED_TYPE||!1,T=k.FORCE_BODY||!1,ae=k.SANITIZE_DOM!==!1,fe=k.KEEP_CONTENT!==!1,ne=k.IN_PLACE||!1,L=k.ALLOWED_URI_REGEXP||L,rr=k.NAMESPACE||Ze,k.CUSTOM_ELEMENT_HANDLING&&ax(k.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(M.tagNameCheck=k.CUSTOM_ELEMENT_HANDLING.tagNameCheck),k.CUSTOM_ELEMENT_HANDLING&&ax(k.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(M.attributeNameCheck=k.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),k.CUSTOM_ELEMENT_HANDLING&&typeof k.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements=="boolean"&&(M.allowCustomizedBuiltInElements=k.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),ge&&(Ee=!1),q&&(F=!0),ie&&(H=je({},Sn(JA)),oe=[],ie.html===!0&&(je(H,XA),je(oe,QA)),ie.svg===!0&&(je(H,Cg),je(oe,Pg),je(oe,nd)),ie.svgFilters===!0&&(je(H,Ig),je(oe,Pg),je(oe,nd)),ie.mathMl===!0&&(je(H,kg),je(oe,eO),je(oe,nd))),k.ADD_TAGS&&(H===Y&&(H=fo(H)),je(H,k.ADD_TAGS,it)),k.ADD_ATTR&&(oe===Oe&&(oe=fo(oe)),je(oe,k.ADD_ATTR,it)),k.ADD_URI_SAFE_ATTR&&je(Ae,k.ADD_URI_SAFE_ATTR,it),k.FORBID_CONTENTS&&(ee===_e&&(ee=fo(ee)),je(ee,k.FORBID_CONTENTS,it)),fe&&(H["#text"]=!0),ye&&je(H,["html","head","body"]),H.table&&(je(H,["tbody"]),delete K.tbody),yr&&yr(k),Jt=k)},ix=je({},["mi","mo","mn","ms","mtext"]),ox=je({},["foreignobject","desc","title","annotation-xml"]),n4=je({},["title","style","font","a","script"]),yf=je({},Cg);je(yf,Ig),je(yf,vme);var Ph=je({},kg);je(Ph,pme);var a4=function(k){var re=b(k);(!re||!re.tagName)&&(re={namespaceURI:Ze,tagName:"template"});var pe=kd(k.tagName),vt=kd(re.tagName);return k.namespaceURI===ct?re.namespaceURI===Ze?pe==="svg":re.namespaceURI===ut?pe==="svg"&&(vt==="annotation-xml"||ix[vt]):Boolean(yf[pe]):k.namespaceURI===ut?re.namespaceURI===Ze?pe==="math":re.namespaceURI===ct?pe==="math"&&ox[vt]:Boolean(Ph[pe]):k.namespaceURI===Ze?re.namespaceURI===ct&&!ox[vt]||re.namespaceURI===ut&&!ix[vt]?!1:!Ph[pe]&&(n4[pe]||!yf[pe]):!1},ya=function(k){tu(t.removed,{element:k});try{k.parentNode.removeChild(k)}catch{try{k.outerHTML=D}catch{k.remove()}}},sx=function(k,re){try{tu(t.removed,{attribute:re.getAttributeNode(k),from:re})}catch{tu(t.removed,{attribute:null,from:re})}if(re.removeAttribute(k),k==="is"&&!oe[k])if(F||q)try{ya(re)}catch{}else try{re.setAttribute(k,"")}catch{}},lx=function(k){var re,pe;if(T)k=""+k;else{var vt=ume(k,/^[\r\n\t ]+/);pe=vt&&vt[0]}ga==="application/xhtml+xml"&&(k=''+k+"");var $r=A?A.createHTML(k):k;if(rr===Ze)try{re=new c().parseFromString($r,ga)}catch{}if(!re||!re.documentElement){re=R.createDocument(rr,"template",null);try{re.documentElement.innerHTML=Yn?"":$r}catch{}}var nr=re.body||re.documentElement;return k&&pe&&nr.insertBefore(n.createTextNode(pe),nr.childNodes[0]||null),rr===Ze?B.call(re,ye?"html":"body")[0]:ye?re.documentElement:nr},ux=function(k){return x.call(k.ownerDocument||k,k,u.SHOW_ELEMENT|u.SHOW_COMMENT|u.SHOW_TEXT,null,!1)},i4=function(k){return k instanceof s&&(typeof k.nodeName!="string"||typeof k.textContent!="string"||typeof k.removeChild!="function"||!(k.attributes instanceof d)||typeof k.removeAttribute!="function"||typeof k.setAttribute!="function"||typeof k.namespaceURI!="string"||typeof k.insertBefore!="function")},Fl=function(k){return Oi(o)==="object"?k instanceof o:k&&Oi(k)==="object"&&typeof k.nodeType=="number"&&typeof k.nodeName=="string"},ba=function(k,re,pe){G[k]&&lme(G[k],function(vt){vt.call(t,re,pe,Jt)})},cx=function(k){var re;if(ba("beforeSanitizeElements",k,null),i4(k)||dr(/[\u0080-\uFFFF]/,k.nodeName))return ya(k),!0;var pe=it(k.nodeName);if(ba("uponSanitizeElement",k,{tagName:pe,allowedTags:H}),k.hasChildNodes()&&!Fl(k.firstElementChild)&&(!Fl(k.content)||!Fl(k.content.firstElementChild))&&dr(/<[/\w]/g,k.innerHTML)&&dr(/<[/\w]/g,k.textContent)||pe==="select"&&dr(/