From 699cef3e10b3fd0138b8a424bb262e0dfaa27850 Mon Sep 17 00:00:00 2001 From: Toni Nguyen Date: Thu, 30 Jan 2025 20:32:51 +0100 Subject: [PATCH] chore: Bump MOTIS version to 2.0.14 (#37) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use `maxTravelTime` to filter results (#668) * Use 'maxTravelTime' to filter results * Change unit to minutes * Fix formatting * Fix type for MSVC build * Update nigiri dependency * Set limit for maximum travel time * GBFS: Performance/Memory Improvements + Vehicle Types (#670) * gbfs: partition providers, faster updates, less memory usage * fix vehicle_docks_available * slightly faster geofencing zone mapping * rename provider_cache -> provider_file_infos * ts formatting * formatting * clang fixes * clang fix * clang fixes * trying to fix apple clang * static_cast all the things * review changes * fix include * 65k gbfs providers should be enough * remove obsolete comment * sort vehicle status before diff * fill cache during gbfs update * cleanup * partition vehicle types by form factor + propulsion type * rental api changes (RENTAL mode + form factor + propulsion type) * ui fix * rename provider segment -> products * vehicle type id -> idx * rename more segment -> products * one more r-tree to speed up geofencing zone mapping * clang fix * fix api descriptions * api: add rental provider filter * ui: fix direct connection display for rental connections * return constraint support, allow roundtrip for direct connections * ui formatting * fix missing gbfs data after update * http proxy support * share decompressed bitvecs between routing requests * fix missing initializer --------- Co-authored-by: Felix Gündling * replace wheelchair with pedestrianProfile and useRoutedTransfers params (#683) * replace wheelchair with pedestrianProfile and useRoutedTransfers parameters * fix test * ui: debounce search requests * increase trains limit to support big cities like Paris/London/.. * add timeout option * cli changes (#685) * cli changes * wip * update nigiri * Update README.md: not beta anymore * update nigiri: speedup ~8% by not finding 24h+ transfers * basic benchmark and QA tooling (#686) * bench * wip * wip * wip * wip * fix command line flag handling * full dataset test (#687) * full dataset test * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * body size limit 128M * cmake: Add option to pass flags not used for host tools (#689) * update nigiri: rt update fixes time travel * more rebostness against invalid delay update data https://github.com/motis-project/nigiri/pull/162 * update nigiri: trim stop time before empty check for interpolation * motis config: fix crash with no parameters * update nigiri: better trip names (#695) * polish translation * Detailed transfers flag + output exactly what nigiri routed (#698) * wip * output exactly what nigiri routed * remove logging output * remove unused variable * fix eval * wip * wip * Initial style guide docs/STYLE.md * Fix missing closing tag (#700) * Fix missing closing tag * Add sections for important tools This adds a section for `strong`, as well as `vector_map` and `vecvec`. * Fix index out of range for stop_times last arrival of multi-section run (#704) * fix index out of range for stop_times last arrival of multi-section run * follow style guide Co-authored-by: Felix Gündling --------- Co-authored-by: Felix Gündling * (Mobile) UI improvements (#705) * ui: move components to lib * ui: make components more responsive * ui: more compact layout * ui: i18n fixes * ui: make toggle button state more visible * ui: error handling, avoid repeated effect triggering * ui: more small screen adjustments * ui: url state handling * ui: show backend error msgs, compact transfer display * UI fixes (#710) * ui: fall back to black routeTextColor (gtfs spec) * update ui deps * ui: workaround to avoid clickthrough * ui: linting * update nigiri: monotonicity enforcement on utc times (fixes interpolation for frequency expanded trips) * ui changes * Improve formatDuration (#713) * Update formatDuration.ts * fix formatting * fix formatting * Fix formatting * osr_footpaths: add missing footpaths (#707) * osr_footpaths: add missing footpaths * update osr (ramp support) * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * formatting --------- Co-authored-by: Michael Kutzner <174690291+MichaelKutzner@users.noreply.github.com> Co-authored-by: Pablo Hoch Co-authored-by: Felix Gündling Co-authored-by: Felix Gündling Co-authored-by: Jonah Brüchert Co-authored-by: Traines Co-authored-by: Altonss <66519591+Altonss@users.noreply.github.com> --- .github/workflows/ci.yml | 17 +- .pkg | 14 +- .pkg.lock | 4 +- CMakeLists.txt | 9 +- README.md | 16 +- docs/STYLE.md | 345 ++++ exe/flags.h | 38 + exe/generate.cc | 341 ++++ exe/main.cc | 173 +- include/motis/box_rtree.h | 110 ++ include/motis/compute_footpaths.h | 4 +- include/motis/config.h | 4 + include/motis/data.h | 2 +- include/motis/endpoints/routing.h | 14 +- include/motis/fwd.h | 4 + include/motis/gbfs/compression.h | 64 + include/motis/gbfs/data.h | 242 ++- include/motis/gbfs/geofencing.h | 7 + include/motis/gbfs/lru_cache.h | 189 ++ include/motis/gbfs/mode.h | 26 + include/motis/gbfs/osr_mapping.h | 7 +- include/motis/gbfs/partition.h | 117 ++ include/motis/gbfs/routing_data.h | 47 + include/motis/hashes.h | 2 +- include/motis/http_client.h | 12 + include/motis/journey_to_response.h | 5 +- include/motis/point_rtree.h | 30 +- include/motis/street_routing.h | 11 +- include/motis/tag_lookup.h | 4 +- include/motis/types.h | 4 +- openapi.yaml | 248 ++- src/compute_footpaths.cc | 136 +- src/data.cc | 6 +- src/endpoints/footpaths.cc | 13 +- src/endpoints/routing.cc | 189 +- src/endpoints/stop_times.cc | 2 +- src/endpoints/trip.cc | 6 +- src/gbfs/data.cc | 40 + src/gbfs/geofencing.cc | 25 +- src/gbfs/mode.cc | 118 ++ src/gbfs/osr_mapping.cc | 444 +++-- src/gbfs/parser.cc | 122 +- src/gbfs/routing_data.cc | 81 + src/gbfs/update.cc | 811 +++++--- src/http_client.cc | 24 +- src/http_req.cc | 11 +- src/import.cc | 17 +- src/journey_to_response.cc | 30 +- src/match_platforms.cc | 10 +- src/mode_to_profile.cc | 4 +- src/railviz.cc | 4 +- src/street_routing.cc | 103 +- src/tag_lookup.cc | 5 +- test/config_test.cc | 2 + test/gbfs_partition_test.cc | 99 + test/routing_test.cc | 21 +- ui/package-lock.json | 1630 +++++++++++------ ui/package.json | 2 +- ui/src/app.css | 8 + ui/src/app.d.ts | 10 +- ui/src/app.html | 18 + ui/src/lib/AddressTypeahead.svelte | 66 +- .../{routes => lib}/ConnectionDetail.svelte | 66 +- ui/src/lib/DateInput.svelte | 2 +- ui/src/{routes => lib}/Debug.svelte | 15 + ui/src/lib/DirectConnection.svelte | 33 + ui/src/lib/ErrorMessage.svelte | 9 + .../{routes => lib}/ItineraryGeoJSON.svelte | 0 ui/src/{routes => lib}/ItineraryList.svelte | 83 +- ui/src/{routes => lib}/LevelSelect.svelte | 0 ui/src/{routes => lib}/RailViz.svelte | 22 +- ui/src/lib/Route.svelte | 2 +- ui/src/{routes => lib}/SearchMask.svelte | 22 +- ui/src/{routes => lib}/StopTimes.svelte | 72 +- ui/src/lib/Time.svelte | 2 +- ui/src/lib/components/ui/button/button.svelte | 5 +- ui/src/lib/components/ui/card/card.svelte | 2 +- .../ui/radio-group/radio-group.svelte | 2 +- ui/src/lib/components/ui/toggle/toggle.svelte | 4 +- ui/src/lib/formatDuration.ts | 5 +- ui/src/lib/getModeName.ts | 27 +- ui/src/lib/i18n/de.ts | 9 +- ui/src/lib/i18n/en.ts | 16 +- ui/src/lib/i18n/fr.ts | 16 +- ui/src/lib/i18n/pl.ts | 41 + ui/src/lib/i18n/translation.ts | 8 + ui/src/lib/map/Control.svelte | 2 +- ui/src/lib/map/Map.svelte | 3 +- ui/src/lib/modeStyle.ts | 35 +- ui/src/lib/openapi/schemas.gen.ts | 42 +- ui/src/lib/openapi/types.gen.ts | 176 +- ui/src/routes/+page.svelte | 194 +- 92 files changed, 5519 insertions(+), 1563 deletions(-) create mode 100644 docs/STYLE.md create mode 100644 exe/flags.h create mode 100644 exe/generate.cc create mode 100644 include/motis/box_rtree.h create mode 100644 include/motis/gbfs/compression.h create mode 100644 include/motis/gbfs/lru_cache.h create mode 100644 include/motis/gbfs/mode.h create mode 100644 include/motis/gbfs/partition.h create mode 100644 include/motis/gbfs/routing_data.h create mode 100644 src/gbfs/data.cc create mode 100644 src/gbfs/mode.cc create mode 100644 src/gbfs/routing_data.cc create mode 100644 test/gbfs_partition_test.cc rename ui/src/{routes => lib}/ConnectionDetail.svelte (71%) rename ui/src/{routes => lib}/Debug.svelte (95%) create mode 100644 ui/src/lib/DirectConnection.svelte create mode 100644 ui/src/lib/ErrorMessage.svelte rename ui/src/{routes => lib}/ItineraryGeoJSON.svelte (100%) rename ui/src/{routes => lib}/ItineraryList.svelte (69%) rename ui/src/{routes => lib}/LevelSelect.svelte (100%) rename ui/src/{routes => lib}/RailViz.svelte (93%) rename ui/src/{routes => lib}/SearchMask.svelte (83%) rename ui/src/{routes => lib}/StopTimes.svelte (57%) create mode 100644 ui/src/lib/i18n/pl.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa0785f16b..8b54b246be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,6 +269,8 @@ jobs: BUILDCACHE_DIRECT_MODE: true BUILDCACHE_MAX_CACHE_SIZE: 26843545600 BUILDCACHE_LUA_PATH: ${{ github.workspace }}/tools + UBSAN_OPTIONS: halt_on_error=1:abort_on_error=1 + ASAN_OPTIONS: alloc_dealloc_mismatch=0 steps: - uses: actions/checkout@v4 @@ -291,6 +293,19 @@ jobs: - name: Run Integration Tests run: ${{ matrix.config.emulator }} build/motis-test + # ==== FULL DATASET TEST ==== + - name: Test Full Dataset + if: matrix.config.preset != 'linux-debug' + run: | + ln -s deps/tiles/profile tiles-profiles + wget https://github.com/motis-project/test-data/raw/aachen/aachen.osm.pbf + wget https://github.com/motis-project/test-data/raw/aachen/AVV_GTFS_Masten_mit_SPNV.zip + ${{ matrix.config.emulator }} ./build/motis config aachen.osm.pbf AVV_GTFS_Masten_mit_SPNV.zip + ${{ matrix.config.emulator }} ./build/motis import + ${{ matrix.config.emulator }} ./build/motis generate -n 10 + ${{ matrix.config.emulator }} ./build/motis batch + ${{ matrix.config.emulator }} ./build/motis compare -q queries.txt -r responses.txt responses.txt + # ==== DISTRIBUTION ==== - name: Create Distribution if: matrix.config.artifact @@ -318,7 +333,7 @@ jobs: upload_url: ${{ github.event.release.upload_url }} asset_path: ./motis-${{ matrix.config.artifact }}.tar.bz2 asset_name: motis-${{ matrix.config.artifact }}.tar.bz2 - asset_content_type: application/x-tar + asset_content_type: application/x- docker: runs-on: ubuntu-20.04 diff --git a/.pkg b/.pkg index 3971201ff9..5274c20140 100644 --- a/.pkg +++ b/.pkg @@ -5,19 +5,19 @@ [cista] url=git@github.com:felixguendling/cista.git branch=master - commit=950f96f4ded53a6b5753824b280550b722933e55 + commit=6362f3ad8c3133a0abf64e5d8c9ea3e21f531ee8 [osr] url=git@github.com:motis-project/osr.git branch=master - commit=478bed28978461f0728c311899cc6bb22f0dd591 + commit=650e05c5dc59598f84a5e9bae2db75d5cc3433b8 [utl] url=git@github.com:motis-project/utl.git branch=master - commit=368fdcb8326ced5bb151b60c09a07c2e5f09bf55 + commit=07fb33df7b79b73e84e0d2c69c6ee445221f6e32 [adr] url=git@github.com:triptix-tech/adr.git branch=master - commit=9bf19dd88d7805d6bea1cebf5b09a394605fa3f6 + commit=d5036b92fed3867abb474440987343a8ae4cb3bf [googletest] url=git@github.com:motis-project/googletest.git branch=master @@ -29,7 +29,7 @@ [openapi-cpp] url=git@github.com:triptix-tech/openapi-cpp.git branch=master - commit=dac46d043f07a119d8b7d9ccb47e51049b259bfe + commit=688d45bd96addb26eaccc5d264761030e5ef43f9 [unordered_dense] url=git@github.com:motis-project/unordered_dense.git branch=master @@ -54,3 +54,7 @@ url=git@github.com:motis-project/mimalloc.git branch=dev commit=e2f4fe647e8aff4603a7d5119b8639fd1a47c8a6 +[lz4] + url=git@github.com:motis-project/lz4.git + branch=dev + commit=c4765545ebb14b0a56c663e21923166923f8280e diff --git a/.pkg.lock b/.pkg.lock index 5625329ff0..6ab09b51ef 100644 --- a/.pkg.lock +++ b/.pkg.lock @@ -42,9 +42,9 @@ sol2 40c7cbc7c5cfed1e8c7f1bbe6fcbe23d7a67fc75 variant 5aa73631dc969087c77433a5cdef246303051f69 tiles ab6c4b13544570f893c2d64434c613d8fd7d2ceb rtree.c 6ed73a7dc4f1184f2b5b2acd8ac1c2b28a273057 -osr 478bed28978461f0728c311899cc6bb22f0dd591 +osr 650e05c5dc59598f84a5e9bae2db75d5cc3433b8 reflect-cpp c54fe66de4650b60c23aadd4a06d9db4ffeda22f FTXUI dd6a5d371fd7a3e2937bb579955003c54b727233 tg 20c0f298b8ce58de29a790290f44dca7c4ecc364 utf8proc 779b780da3b99d123133eb99707b65c7e4324cc8 -adr 9bf19dd88d7805d6bea1cebf5b09a394605fa3f6 +adr d5036b92fed3867abb474440987343a8ae4cb3bf diff --git a/CMakeLists.txt b/CMakeLists.txt index d69ec847b2..3046f1813a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,8 @@ target_link_libraries(motislib pbf_sdf_fonts_res-res ssl crypto + tg + lz4_static ) @@ -144,7 +146,6 @@ target_link_libraries(motis rtree geo cista - tg ianatzdb-res pbf_sdf_fonts_res-res tiles_server_res-res @@ -197,3 +198,9 @@ add_custom_target(motis-web-ui WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ui" VERBATIM ) + +foreach(t mimalloc adr osr nigiri gtfsrt + geo tiles tiles-import-library + motis motis-api motislib) + target_compile_options(${t} PUBLIC ${MOTIS_TARGET_FLAGS}) +endforeach() diff --git a/README.md b/README.md index 3adfc35b9e..26c1267710 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,5 @@

-> [!NOTE] -> This is the MOTIS 2 beta version. -> You can find the `0.x.y` legacy branch [here](https://github.com/motis-project/motis/tree/legacy). - > [!TIP] > :sparkles: Join the international MOTIS community at [**motis:matrix.org**](https://matrix.to/#/#motis:matrix.org) @@ -60,7 +56,9 @@ Features can be turned on and off as needed. - Download one or more GTFS datasets and place them in the folder ```bash -./motis my.osm.pbf my.gtfs.zip +./motis config my.osm.pbf gtfs.zip # generates a minimal config.yml +./motis import # preprocesses data +./motis server # starts a HTTP server on port 8080 ``` This will preprocess the input files and create a `data` folder. @@ -81,7 +79,9 @@ wget https://github.com/motis-project/motis/releases/latest/download/motis-${TAR tar xf motis-${TARGET}.tar.bz2 wget https://github.com/motis-project/test-data/raw/aachen/aachen.osm.pbf wget https://opendata.avv.de/current_GTFS/AVV_GTFS_Masten_mit_SPNV.zip -./motis aachen.osm.pbf AVV_GTFS_Masten_mit_SPNV.zip +./motis config aachen.osm.pbf AVV_GTFS_Masten_mit_SPNV.zip +./motis import +./motis server ``` **Windows** @@ -90,7 +90,9 @@ wget https://opendata.avv.de/current_GTFS/AVV_GTFS_Masten_mit_SPNV.zip Invoke-WebRequest https://github.com/motis-project/motis/releases/latest/download/motis-windows.zip -OutFile motis-windows.zip Expand-Archive motis-windows.zip Invoke-WebRequest https://github.com/motis-project/test-data/archive/refs/heads/aachen.zip -OutFile aachen.zip -./motis aachen.osm.pbf AVV_GTFS_Masten_mit_SPNV.zip +./motis config aachen.osm.pbf AVV_GTFS_Masten_mit_SPNV.zip +./motis import +./motis server ``` # Documentation diff --git a/docs/STYLE.md b/docs/STYLE.md new file mode 100644 index 0000000000..282379dcef --- /dev/null +++ b/docs/STYLE.md @@ -0,0 +1,345 @@ +# MOTIS C++ Style + +# Preamble + +Beaware that these rules only apply to MOTIS C++ and are very opinionated. +C++ has a big diversity of programming styles from "C with classes" to "Modern C++". +A lot of codebases have specific rules that make sense in this specific context +(e.g. embedded programming, gaming, Google search, etc.) and therefore different +guidelines. Over the years we learned that the rules described here are a good fit +for this specific project. + +So in general our goals are: + +- We want high-level, maintainable C++ code by default, not "high level assembly" +- but: don’t use features just because you can (like template meta programming, etc.) + +# Style + +- Header names: ***`*.h`**, Implementation names: **`*.cc`** +- Don’t use include guards (`#ifndef #define #endif`), use **`#pragma once`** +- Consistently use **`struct`** instead of `class` + - default visibility: public (which is what we need → no getter / setter) + - you don’t need to write a constructor for 1-line initialization +- Always use ++i instead of i++ if it makes no difference for the program logic: + `for (auto i = 0U; i < 10; ++i) { … }` +- Don't `using namespace std;` +- Don’t use `NULL` or `0`, use **nullptr** instead +- Don’t write `const auto&`, write **`auto const&`** +- Don’t write `const char*`, write **`char const`** + + +# Case + +- Everything **`snake_case`** (as in the C++ Standard Library) +- Template parameters **`PascalCase`** (as in the C++ Standard Library) +- Constants **`kPascalCase`** (as in the Google C++ Styleguide), not `UPPER_CASE` to prevent collisions with macro names +- Postfix **`member_variables_`** with an underscore to improve code readability when reading code without an IDE + +```cpp +constexpr auto kMyConstant = 3.141; + +template +struct my_class : public my_parent { + void member_fn(std::string const& fn_param) const override { + auto const local_cvar = abc(); + auto local_var = def(); + } + int my_field_; +}; +``` + +# Includes + +- Include only what you use (but everything you use!) +- Group includes: + - for `.cc` files: first its own `.h` file + - Standard headers with `<...>` syntax + - C headers (use `` instead of ``, etc.) + - C++ standard library headers (e.g. ``) + - Non-standard headers with `"..."` syntax + - generic to specific = boost libraries, then more and more specific + - last: project includes + - if available: local inclues `"./test_util.h"` from the local folder (only done for tests) +- Do not repeat include files from your own header file +- Repeat everything else - even it's transitiveley included already through other headers. + The include might be removed from the header you include which leads broken compilation. + Try to make the compilation as robust as possible. + + +Example include files for `message.cc`: +```cpp +#include "motis/module/message.h" + +#include +#include + +#include "boost/asio.hpp" + +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +#include "motis/core/common/logging.h" +``` + +# Simplify Code: Predicate Usage + +```cpp +// bad +if (is_valid()) { + set_param(false); +} else { + set_param(true); +} + +// bad +set_param(is_valid() ? false : true); + +// good +set_param(!is_valid()); +``` + +# Always use Braces + +```cpp +// bad +for (auto i = 0u; i < 10; ++i) + if (is_valid()) + return get_a(); + else + count_b(); + +// good +for (auto i = 0u; i < 10; ++i) { + if (is_valid()) { + return get_a(); + } else { + count_b(); + } +} +``` + +# Use Short Variable Names + +Only use shortened version of the variable name if it's still obvious what the variable holds. + +- Index = `idx` +- Input = `in` +- Output = `out` +- Request = `req` +- Response = `res` +- Initialization = `init` +- ... etc. + +If the context in which the variable is used is short, you can make variable names even shorter. For example `for (auto const& e : events) { /* ... */ }` or `auto const& b = get_buffer()`. + +Don't use `lhs` and `rhs` - for comparison with `friend bool operator==`. Use `a` and `b`. + +# Signatures in Headers + +Omit information that's not needed for a forward declaration. + +```cpp +void* get_memory(my_memory_manager& memory_manager); // bad + +void* get_memory(my_memory_manager&); // good + +// const for value parameters is not needed in headers +void calc_mask(bool const, bool const, bool const, bool const); // bad + +void calc_mask(bool local_traffic, // slightly less bad + bool long_distance_traffic, + bool local_stations, + bool long_distance_stations); + +void calc_mask(mask_options); // good +``` + +# Low Indentation + +Try to keep indentation at a minimum by handling cases one by one and bailing out early. + +Example: + +Bad: + +```cpp +int main(int argc, char** argv) { + if (argc > 1) { + for (int i = 0; i < argc; ++i) { + if (std::strcmp("hello", argv[i]) == 0) { + /* ... 100 lines of code ... */ + } + } + } +} +``` + +Good: + +```cpp +int main(int argc, char** argv) { + if (argc <= 1) { + return 0; + } + for (int i = 0; i < argc; ++i) { + if (std::strcmp("hello", argv[i]) != 0) { + continue; + } + /* ... 100 lines of code ... */ + } +} +``` + +# Function Length / File Length + +Functions should have one task only. If they grow over ~50 lines of code, please check if they could be split into several functions to improve readability. But: don't split just randomly to not go over some arbitrary lines of code limit. + +- Better: split earlier if it makes sense! Files are free! (more than one responsibility) +- Split later i.e. if you want to keep one block of logic without interruption (easier to understand) + +# Pointers + +Read C++ data types from right to left: + +**`int const* const`** +- `const` (read only) pointer (address can't be modified) +- to `const int` (int value at address can't be modified) + +**int const&** +- reference +- on a const `int` value (read only) + +**auto const&** +- reference +- on a value (type deduced by the compiler) + +# Use RAII + +Whenever possible use RAII to manage resource like memory (`std::unique_ptr`, `std::shared_ptr`, etc.), files (`std::fstream`), network sockets (Boost Asio), etc. + +This means we do not want `new` or `delete` - except for placement new or placement delete in some very specific cases. + +# Use `utl` Library + +If there is no tool available in the C++ Standard Library please check first if we already have something in our [utl](https://github.com/motis-project/utl) library. + +# Use `strong` types + +Use `cista::strong` to define types, that cannot be converted implicitly. Using a `strong` type will ensure, that parameters cannot be mismatched, unlike `int` or `std::size_t`. This also makes function parameters clearer. + +# `const` + +Make everything (variables, loop variables, member functions, etc.) as `const` as possible. This indicates thread-safety (as long as only `const` methods are used) and helps to catch bugs when our mental model doesn't match the reality (the compiler will tell us). + +# Initializaiton + +Use [Aggregate Initialization](https://en.cppreference.com/w/cpp/language/aggregate_initialization) if possible. This also applies to member variables. A big advantage is that it doesn't allow implicit type conversions. + +# Namespaces + +Rename long namespace names instead of importing them completely. + +```cpp +using boost::program_options; // bad +namespace po = boost::program_option; // good +``` + +This way we still know where functions come from when reading code. +It becomes hard to know where a function came from when several large namespaces are completely imported. + +Don't alias or import namespaces in header files. + +# AAA-Style + +Use [Almost Alway Auto (AAA)](https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/) style if possible. + +- Program against interfaces +- Abstraction +- Less typing + +Example: `for (auto const& el : c())` + +No client code change if +- c returns another collection type (i.e. set instead of vector) +- the element type changes but still has a compatible interface + +# No Raw Loops + +It takes time to understand a raw for loop: +```cpp +for (int i = -1; i <= 9; i += 2) { + if (i % 2 == 0) { continue; } + if (i > 5 && i % 2 == 1) { break; } + printf(“%s\n”, i/3); +} +``` + +- Raw for loops can + - do crazy things + - be boring (can often be expressed with a standard library algorithm!!) + +- Find an element loop → `std::find`, `std::lower_bound`, ... +- Check each element loop → `std::all_of`, `std::none_of`, `std::any_of` +- Conversion loop → `std::transform`, `utl::to_vec` +- Counting: `std::count_if`, `std::accumulate` +- Sorting: `std::sort`, `std::nth_element`, `std::is_sorted` +- Logic: `std::all_of`, `std::any_of` +- Iterating multiple elements at once: `utl::zip`, `utl::pairwise`, `utl::nwise` +- Erasing elements: `utl::erase_if`, `utl::erase_duplicates` +- etc. + +Hint: `utl` provides a cleaner interface wrapping `std::` functions for collections so you don't have to call `begin` and `end` all the time! + +Benefits: +- Function name tells the reader of your code already what it does! +- Standard library implementation does not contain errors and is performant! + +Alternative (if no function in the standard or `utl` helps): +- Use range based for loop if there's no named function: `for (auto const& el : collection) { .. }` + +# Comparators + +Either use +- Preferred: mark the operate you need `= default;` +- If that doesn't do the job you can check `CISTA_FRIEND_COMPARABLE` +- If you want to be selective and only compare a subset of member variables: `std::tie(a_, b_) == std::(a_, b_)` + +# Set/Map vs Vector + +Our go-to data structure is `std::vector`. (Hash-)maps and (hash-)sets are very expensive. + +Never use `std::unordered_map`. We have better alternatives in all projects (e.g. unordered_dense). + +## `vecvec` and `vector_map` + +- Use `vector_map` for mappings with a `strong` key type and a continuous domain. +- Prefer using `vecvec` instead of `vector>`, as data is stored and accessed more efficient. To store data, that may appear in any order, you may consider `paged_vecvec` instead. + +# Tooling + +- Always develop with Address Sanitizer (ASan) and Undefined Behaviour Sanitizer (UBSan) enabled if performance allows it (it's usually worth it to use small data sets to be able to develop with sanitizers enabled!): `CXXFLAGS=-fno-omit-frame-pointer -fsanitizer=address,undefined`. + - **Notice**: Some checks can cause false positive and should be disabled if necessary (compare `ci.yml`). + Example: `ASAN_OPTIONS=alloc_dealloc_mismatch=0` +- Check your code with `valgrind`. + +# Spirit + +- No deep inheritance hierarchies (no "enterprise" code) +- Don't write getters / setters for member variables: just make them public + (which is the default for `struct` - remember: always use structs) +- Don't introduce a new variable for every value if it gets used only one time and the variable doesn't tell the reader any important information (-> inline variables). +- No GoF "design patterns" (Factory, Visitor, ...) if there is a simpler solution (there's always a simpler solution) +- Function / struct length: + - it should be possible to understand every function by shortly looking at it + - hints where to split: + - single responsibility + - short enough to be reusable in another context +- Don’t write “extensible” code that cares for functionality you might need at some point in the future. Just solve the problem at hand. +- Build the **smallest and simplest** solution possible that solves your problem +- Use abstractions to avoid thinking about details: helps to keep functions short +- Comment only the tricky / hacky pieces of your code + (there should not be too many comments, otherwise your code is bad) +- Instead of comments use good (but short!) names for variables and functions +- Less code = less maintenance, less places for bugs, easier to understand +- Write robust code: `utl::verify()` assumptions about input data diff --git a/exe/flags.h b/exe/flags.h new file mode 100644 index 0000000000..890ecd4d91 --- /dev/null +++ b/exe/flags.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include "boost/program_options.hpp" + +namespace motis { + +inline void add_data_path_opt(boost::program_options::options_description& desc, + std::filesystem::path& p) { + desc.add_options()( + "data,d", boost::program_options::value(&p)->default_value(p), + "The data path contains all preprocessed data as well as a `config.yml`. " + "It will be created by the `motis import` command. After the import has " + "finished, `motis server` only needs the `data` folder and can run " + "without the input files (such as OpenStreetMap file, GTFS datasets, " + "tiles-profiles, etc.)"); +} + +inline void add_config_path_opt( + boost::program_options::options_description& desc, + std::filesystem::path& p) { + desc.add_options()( + "config,c", boost::program_options::value(&p)->default_value(p), + "Configuration YAML file. Legacy INI files are still supported but this " + "support will be dropped in the future."); +} + +inline boost::program_options::variables_map parse_opt( + int ac, char** av, boost::program_options::options_description& desc) { + namespace po = boost::program_options; + auto vm = po::variables_map{}; + po::store(po::command_line_parser(ac, av).options(desc).run(), vm); + po::notify(vm); + return vm; +} + +} // namespace motis \ No newline at end of file diff --git a/exe/generate.cc b/exe/generate.cc new file mode 100644 index 0000000000..183febb113 --- /dev/null +++ b/exe/generate.cc @@ -0,0 +1,341 @@ +#include "conf/configuration.h" + +#include +#include +#include +#include +#include + +#include "boost/json/parse.hpp" +#include "boost/json/serialize.hpp" +#include "boost/json/value_from.hpp" +#include "boost/json/value_to.hpp" +#include "boost/url/url.hpp" + +#include "fmt/std.h" + +#include "utl/enumerate.h" +#include "utl/get_or_create.h" +#include "utl/helpers/algorithm.h" +#include "utl/init_from.h" +#include "utl/parallel_for.h" +#include "utl/parser/cstr.h" +#include "utl/sorted_diff.h" +#include "utl/timing.h" + +#include "nigiri/routing/query.h" +#include "nigiri/timetable.h" + +#include "motis-api/motis-api.h" +#include "motis/config.h" +#include "motis/data.h" +#include "motis/endpoints/routing.h" +#include "motis/place.h" +#include "motis/point_rtree.h" +#include "motis/tag_lookup.h" + +#include "./flags.h" + +namespace n = nigiri; +namespace fs = std::filesystem; +namespace po = boost::program_options; +namespace json = boost::json; + +namespace motis { + +static std::atomic_uint32_t seed{0U}; + +std::uint32_t rand_in(std::uint32_t const from, std::uint32_t const to) { + auto a = ++seed; + a = (a ^ 61U) ^ (a >> 16U); + a = a + (a << 3U); + a = a ^ (a >> 4U); + a = a * 0x27d4eb2d; + a = a ^ (a >> 15U); + return from + (a % (to - from)); +} + +template +It rand_in(It const begin, It const end) { + return std::next( + begin, + rand_in(0U, static_cast(std::distance(begin, end)))); +} + +template +Collection::value_type rand_in(Collection const& c) { + using std::begin; + using std::end; + utl::verify(!c.empty(), "empty collection"); + return *rand_in(begin(c), end(c)); +} + +n::location_idx_t random_stop(n::timetable const& tt, + std::vector const& stops) { + auto s = n::location_idx_t::invalid(); + do { + s = rand_in(stops); + } while (tt.location_routes_[s].empty()); + return s; +} + +int generate(int ac, char** av) { + auto data_path = fs::path{"data"}; + auto n = 100U; + + auto desc = po::options_description{"Options"}; + desc.add_options() // + ("help", "Prints this help message") // + ("n,n", po::value(&n)->default_value(n), "number of queries"); + add_data_path_opt(desc, data_path); + auto vm = parse_opt(ac, av, desc); + + if (vm.count("help")) { + std::cout << desc << "\n"; + return 0; + } + + auto const c = config::read(data_path / "config.yml"); + utl::verify(c.timetable_.has_value(), "timetable required"); + + auto d = data{data_path, c}; + utl::verify(d.tt_, "timetable required"); + + auto stops = std::vector{}; + stops.resize(d.tt_->n_locations()); + for (auto i = 0U; i != stops.size(); ++i) { + stops[i] = n::location_idx_t{i}; + } + + { + auto out = std::ofstream{"queries.txt"}; + for (auto i = 0U; i != n; ++i) { + auto p = api::plan_params{}; + p.fromPlace_ = d.tags_->id(*d.tt_, random_stop(*d.tt_, stops)); + p.toPlace_ = d.tags_->id(*d.tt_, random_stop(*d.tt_, stops)); + out << p.to_url("/api/v1/plan") << "\n"; + } + } + + return 0; +} + +int batch(int ac, char** av) { + auto data_path = fs::path{"data"}; + auto queries_path = fs::path{"queries.txt"}; + auto responses_path = fs::path{"responses.txt"}; + + auto desc = po::options_description{"Options"}; + desc.add_options() // + ("help", "Prints this help message") // + ("queries,q", po::value(&queries_path)->default_value(queries_path), + "queries file") // + ("responses,r", po::value(&responses_path)->default_value(responses_path), + "response file"); + add_data_path_opt(desc, data_path); + + auto vm = parse_opt(ac, av, desc); + if (vm.count("help")) { + std::cout << desc << "\n"; + return 0; + } + + auto queries = std::vector{}; + { + auto f = cista::mmap{queries_path.generic_string().c_str(), + cista::mmap::protection::READ}; + utl::for_each_token(utl::cstr{f.view()}, '\n', [&](utl::cstr s) { + queries.push_back(api::plan_params{boost::urls::url{s.view()}.params()}); + }); + } + + auto const c = config::read(data_path / "config.yml"); + utl::verify(c.timetable_.has_value(), "timetable required"); + + auto d = data{data_path, c}; + utl::verify(d.tt_, "timetable required"); + + auto mtx = std::mutex{}; + auto out = std::ofstream{responses_path}; + auto total = std::atomic_uint64_t{}; + auto const routing = utl::init_from(d).value(); + utl::parallel_for_run(queries.size(), [&](std::size_t const id) { + UTL_START_TIMING(total); + auto response = routing(queries.at(id).to_url("/api/v1/plan")); + UTL_STOP_TIMING(total); + + auto const timing = static_cast(UTL_TIMING_MS(total)); + response.debugOutput_.emplace("id", id); + response.debugOutput_.emplace("timing", timing); + { + auto const lock = std::scoped_lock{mtx}; + out << json::serialize(json::value_from(response)) << "\n"; + } + total += timing; + }); + + std::cout << "AVG: " + << (static_cast(total) / + static_cast(queries.size())) + << "\n"; + + return 0U; +} + +int compare(int ac, char** av) { + auto queries_path = fs::path{"queries.txt"}; + auto responses_paths = std::vector{}; + auto desc = po::options_description{"Options"}; + desc.add_options() // + ("help", "Prints this help message") // + ("queries,q", po::value(&queries_path)->default_value(queries_path), + "queries file") // + ("responses,r", + po::value(&responses_paths) + ->multitoken() + ->default_value(responses_paths), + "response files"); + + auto vm = parse_opt(ac, av, desc); + if (vm.count("help")) { + std::cout << desc << "\n"; + return 0; + } + + auto const open_file = [](fs::path const& p) { + auto f = std::ifstream{}; + f.exceptions(std::ios_base::failbit | std::ios_base::badbit); + try { + f.open(p); + } catch (std::exception const& e) { + throw utl::fail("could not open file \"{}\": {}", p, e.what()); + } + return f; + }; + + auto const read_line = [](std::ifstream& f) -> std::optional { + if (f.peek() == EOF || f.eof()) { + return std::nullopt; + } + std::string line; + std::getline(f, line); + return line; + }; + + struct info { + unsigned id_; + std::optional params_{}; + std::vector> responses_{}; + }; + auto response_buf = hash_map{}; + auto const get = [&](unsigned const id) -> info& { + return utl::get_or_create(response_buf, id, [&]() { + auto x = info{.id_ = id}; + x.responses_.resize(responses_paths.size()); + return x; + }); + }; + auto const is_finished = [](info const& x) { + return x.params_.has_value() && + utl::all_of(x.responses_, [](auto&& r) { return r.has_value(); }); + }; + auto const params = [](api::Itinerary const& x) { + return std::tie(x.startTime_, x.endTime_, x.transfers_); + }; + auto const print_params = [](api::Itinerary const& x) { + std::cout << x.startTime_ << ", " << x.endTime_ + << ", transfers=" << x.transfers_; + }; + auto const print_none = []() { std::cout << "\t\t\t\t\t\t"; }; + auto n_equal = 0U; + auto const print_differences = [&](info const& x) { + auto const& ref = x.responses_[0].value().itineraries_; + for (auto i = 1U; i < x.responses_.size(); ++i) { + auto const uut = x.responses_[i].value().itineraries_; + if (std::ranges::equal(ref | std::views::transform(params), + uut | std::views::transform(params))) { + ++n_equal; + continue; + } + + std::cout << "QUERY=" << x.id_ << "\n"; + utl::sorted_diff( + ref, uut, + [&](api::Itinerary const& a, api::Itinerary const& b) { + return params(a) < params(b); + }, + [&](api::Itinerary const&, api::Itinerary const&) { + return false; // always call for equal + }, + utl::overloaded{ + [&](utl::op op, api::Itinerary const& j) { + if (op == utl::op::kAdd) { + print_none(); + std::cout << "\t\t\t"; + print_params(j); + std::cout << "\n"; + } else { + print_params(j); + std::cout << "\t\t\t"; + print_none(); + std::cout << "\n"; + } + }, + [&](api::Itinerary const& a, api::Itinerary const& b) { + print_params(a); + std::cout << "\t\t\t"; + print_params(b); + std::cout << "\n"; + }}); + std::cout << "\n\n"; + } + }; + auto n_consumed = 0U; + auto const consume_if_finished = [&](info const& x) { + if (!is_finished(x)) { + return; + } + print_differences(x); + response_buf.erase(x.id_); + ++n_consumed; + }; + + auto query_file = open_file(queries_path); + auto responses_files = + utl::to_vec(responses_paths, [&](auto&& p) { return open_file(p); }); + + auto query_id = 0U; + auto done = false; + while (!done) { + done = true; + + if (auto const q = read_line(query_file); q.has_value()) { + auto& info = get(query_id++); + info.params_ = api::plan_params{boost::urls::url{*q}.params()}; + consume_if_finished(info); + done = false; + } + + for (auto const [i, res_file] : utl::enumerate(responses_files)) { + if (auto const r = read_line(res_file); r.has_value()) { + auto res = + boost::json::value_to(boost::json::parse(*r)); + utl::sort(res.itineraries_, + [&](auto&& a, auto&& b) { return params(a) < params(b); }); + auto const id = res.debugOutput_.at("id"); + auto& info = get(static_cast(id)); + info.responses_[i] = std::move(res); + consume_if_finished(info); + done = false; + } + } + } + + std::cout << "consumed: " << n_consumed << "\n"; + std::cout << "buffered: " << response_buf.size() << "\n"; + std::cout << " equal: " << n_equal << "\n"; + + return 0; +} + +} // namespace motis \ No newline at end of file diff --git a/exe/main.cc b/exe/main.cc index c3683a66d5..b66571d53b 100644 --- a/exe/main.cc +++ b/exe/main.cc @@ -12,6 +12,8 @@ #include "motis/import.h" #include "motis/server.h" +#include "./flags.h" + #if !defined(MOTIS_VERSION) #define MOTIS_VERSION "unknown" #endif @@ -20,89 +22,82 @@ namespace po = boost::program_options; using namespace std::string_view_literals; namespace fs = std::filesystem; +namespace motis { +int generate(int, char**); +int batch(int, char**); +int compare(int, char**); +} // namespace motis + using namespace motis; int main(int ac, char** av) { - auto data_path = fs::path{"data"}; - auto config_path = fs::path{"config.yml"}; - - auto desc = po::options_description{"Global options"}; - desc.add_options() // - ("version", "Prints the MOTIS version") // - ("help", "Prints this help message") // - ("data,d", po::value(&data_path)->default_value(data_path), - "The data path contains all preprocessed data as well as a `config.yml` " - "and is required by `motis server`. It will be created by the `motis " - "import` command. After the import has finished, `motis server` only " - "needs the `data` folder and can run without the input files (such as " - "OpenStreetMap file, GTFS datasets, tiles-profiles, etc.)") // - ("config,c", po::value(&config_path)->default_value(config_path), - "Configuration YAML file. Legacy INI files are still supported but this " - "support will be dropped in the future.") // - ("command", po::value(), - "Command to execute:\n" - " - \"import\": preprocesses the input data\n" - " and creates the `data` folder.\n" - " - \"server\": serves static files\n" - " and all API endpoints such as\n" - " routing, geocoding, tiles, etc.") // - ("paths", po::value>(), - "List of paths to import for the simple mode. File type will be " - "determined based on extension:\n" - " - \".osm.pbf\" will be used as\n" - " OpenStreetMap file.\n" - " This enables street routing,\n" - " geocoding and map tiles\n" - " - the rest will be interpreted as\n" - " static timetables.\n" - " This enables transit routing"); - - auto const help = [&]() { - std::cout << "MOTIS " << MOTIS_VERSION << "\n\n" - << "Usage:\n" - " - simple: motis [PATHS...]\n" - " - import: motis import [-c config.yml] [-d data_dir]\n" - " - server: motis server [-d data_dir]\n\n" - << desc << "\n"; - }; - - enum mode { kImport, kServer, kSimple } mode = kSimple; - if (ac > 1) { - auto const cmd = std::string_view{av[1]}; - switch (cista::hash(cmd)) { - case cista::hash("import"): - mode = kImport; - --ac; - ++av; - break; - case cista::hash("server"): - mode = kServer; - --ac; - ++av; - break; - } - } else { - help(); - return 1; - } - - auto pos = po::positional_options_description{}.add("paths", -1); - auto vm = po::variables_map{}; - po::store(po::command_line_parser(ac, av).options(desc).positional(pos).run(), - vm); - po::notify(vm); - - if (vm.count("version")) { - std::cout << MOTIS_VERSION << "\n"; + if (ac > 1 && av[1] == "--help"sv) { + fmt::println( + "MOTIS {}\n\n" + "Usage:\n" + " --help print this help message\n" + " --version print program version\n\n" + "Commands:\n" + " generate generate random queries and write them to a file\n" + " batch run queries from a file\n" + " compare compare results from different batch runs\n" + " config generate a config file from a list of input files\n" + " import prepare input data, creates the data directory\n" + " server starts a web server serving the API\n", + MOTIS_VERSION); return 0; - } else if (vm.count("help")) { - help(); + } else if (ac <= 1 || (ac >= 2 && av[1] == "--version"sv)) { + fmt::println("{}", MOTIS_VERSION); return 0; } - switch (mode) { - case kServer: + // Skip program argument, quit if no command. + --ac; + ++av; + + // Execute command. + auto const cmd = std::string_view{av[0]}; + switch (cista::hash(cmd)) { + case cista::hash("generate"): return generate(ac, av); + case cista::hash("batch"): return batch(ac, av); + case cista::hash("compare"): return compare(ac, av); + + case cista::hash("config"): { + auto paths = std::vector{}; + for (auto i = 1; i != ac; ++i) { + paths.push_back(std::string{av[i]}); + } + if (paths.empty() || paths.front() == "--help") { + fmt::println( + "usage: motis config [PATHS...]\n\n" + "Generates a config.yml file in the current working " + "directory.\n\n" + "File type will be determined based on extension:\n" + " - \".osm.pbf\" will be used as OpenStreetMap file.\n" + " This enables street routing, geocoding and map tiles\n" + " - the rest will be interpreted as static timetables.\n" + " This enables transit routing." + "\n\n" + "Example: motis config germany-latest.osm.pbf " + "germany.gtfs.zip\n"); + return paths.empty() ? 1 : 0; + } + std::ofstream{"config.yml"} << config::read_simple(paths) << "\n"; + return 0; + } + + case cista::hash("server"): try { + auto data_path = fs::path{"data"}; + + auto desc = po::options_description{"Server Options"}; + add_data_path_opt(desc, data_path); + auto vm = parse_opt(ac, av, desc); + if (vm.count("help")) { + std::cout << desc << "\n"; + return 0; + } + auto const c = config::read(data_path / "config.yml"); return server(data{data_path, c}, c); } catch (std::exception const& e) { @@ -110,9 +105,21 @@ int main(int ac, char** av) { return 1; } - case kImport: { + case cista::hash("import"): { auto c = config{}; try { + auto data_path = fs::path{"data"}; + auto config_path = fs::path{"config.yml"}; + + auto desc = po::options_description{"Import Options"}; + add_data_path_opt(desc, data_path); + add_config_path_opt(desc, config_path); + auto vm = parse_opt(ac, av, desc); + if (vm.count("help")) { + std::cout << desc << "\n"; + return 0; + } + c = config_path.extension() == ".ini" ? config::read_legacy(config_path) : config::read(config_path); auto const bars = utl::global_progress_bars{false}; @@ -124,20 +131,6 @@ int main(int ac, char** av) { return 1; } } - - case kSimple: - try { - auto const bars = utl::global_progress_bars{false}; - auto args = vm.count("paths") - ? vm.at("paths").as>() - : std::vector{}; - - auto const c = config::read_simple(args); - server(import(c, data_path), c); - } catch (std::exception const& e) { - std::cerr << "error: " << e.what() << "\n"; - } - return 0; } google::protobuf::ShutdownProtobufLibrary(); diff --git a/include/motis/box_rtree.h b/include/motis/box_rtree.h new file mode 100644 index 0000000000..adbe533162 --- /dev/null +++ b/include/motis/box_rtree.h @@ -0,0 +1,110 @@ +#pragma once + +#include + +#include "cista/strong.h" + +#include "rtree.h" + +#include "geo/box.h" +#include "geo/latlng.h" + +namespace motis { + +template +concept BoxRtreePosHandler = requires(geo::box const& b, T const x, Fn&& f) { + { std::forward(f)(b, x) }; +}; + +template +struct box_rtree { + box_rtree() : rtree_{rtree_new()} {} + + ~box_rtree() { + if (rtree_ != nullptr) { + rtree_free(rtree_); + } + } + + box_rtree(box_rtree const& o) { + if (this != &o) { + if (rtree_ != nullptr) { + rtree_free(rtree_); + } + rtree_ = rtree_clone(o.rtree_); + } + } + + box_rtree(box_rtree&& o) { + if (this != &o) { + rtree_ = o.rtree_; + o.rtree_ = nullptr; + } + } + + box_rtree& operator=(box_rtree const& o) { + if (this != &o) { + if (rtree_ != nullptr) { + rtree_free(rtree_); + } + rtree_ = rtree_clone(o.rtree_); + } + return *this; + } + + box_rtree& operator=(box_rtree&& o) { + if (this != &o) { + rtree_ = o.rtree_; + o.rtree_ = nullptr; + } + return *this; + } + + void add(geo::box const& b, T const t) { + auto const min_corner = b.min_.lnglat(); + auto const max_corner = b.max_.lnglat(); + rtree_insert( + rtree_, min_corner.data(), max_corner.data(), + reinterpret_cast(static_cast(cista::to_idx(t)))); + } + + void remove(geo::box const& b, T const t) { + auto const min_corner = b.min_.lnglat(); + auto const max_corner = b.max_.lnglat(); + rtree_delete( + rtree_, min_corner.data(), max_corner.data(), + reinterpret_cast(static_cast(cista::to_idx(t)))); + } + + template + void find(geo::box const& b, Fn&& fn) const { + auto const min = b.min_.lnglat(); + auto const max = b.max_.lnglat(); + rtree_search( + rtree_, min.data(), max.data(), + [](double const* min_corner, double const* max_corner, void const* item, + void* udata) { + if constexpr (BoxRtreePosHandler) { + (*reinterpret_cast(udata))( + geo::box{geo::latlng{min_corner[1], min_corner[0]}, + geo::latlng{max_corner[1], max_corner[0]}}, + T{static_cast>( + reinterpret_cast(item))}); + } else { + (*reinterpret_cast(udata))(T{static_cast>( + reinterpret_cast(item))}); + } + return true; + }, + &fn); + } + + template + void find(geo::latlng const& pos, Fn&& fn) const { + return find(geo::box{pos, pos}, std::forward(fn)); + } + + rtree* rtree_{nullptr}; +}; + +} // namespace motis diff --git a/include/motis/compute_footpaths.h b/include/motis/compute_footpaths.h index e84945335b..66d244ffa1 100644 --- a/include/motis/compute_footpaths.h +++ b/include/motis/compute_footpaths.h @@ -17,6 +17,8 @@ elevator_footpath_map_t compute_footpaths(osr::ways const&, osr::lookup const&, osr::platforms const&, nigiri::timetable&, - bool update_coordinates); + bool update_coordinates, + bool extend_missing, + std::chrono::seconds max_duration); } // namespace motis \ No newline at end of file diff --git a/include/motis/config.h b/include/motis/config.h index 3cd70600d4..a5a6ef11bb 100644 --- a/include/motis/config.h +++ b/include/motis/config.h @@ -87,6 +87,8 @@ struct config { unsigned update_interval_{60}; unsigned http_timeout_{10}; bool incremental_rt_update_{false}; + bool use_osm_stop_coordinates_{false}; + bool extend_missing_footpaths_{false}; std::uint16_t max_footpath_length_{15}; std::optional default_timezone_{}; std::map datasets_{}; @@ -114,6 +116,8 @@ struct config { std::map default_restrictions_{}; unsigned update_interval_{60}; unsigned http_timeout_{10}; + unsigned cache_size_{50}; + std::optional proxy_{}; }; std::optional gbfs_{}; diff --git a/include/motis/data.h b/include/motis/data.h index 28d5da4879..4ef25d081c 100644 --- a/include/motis/data.h +++ b/include/motis/data.h @@ -50,7 +50,7 @@ struct data { friend std::ostream& operator<<(std::ostream&, data const&); void load_osr(); - void load_tt(); + void load_tt(std::filesystem::path const&); void load_shapes(); void load_railviz(); void load_geocoder(); diff --git a/include/motis/endpoints/routing.h b/include/motis/endpoints/routing.h index ded693a623..7f5175e5c2 100644 --- a/include/motis/endpoints/routing.h +++ b/include/motis/endpoints/routing.h @@ -1,5 +1,9 @@ #pragma once +#include +#include +#include + #include "osr/location.h" #include "osr/types.h" @@ -19,10 +23,13 @@ struct routing { osr::location const&, osr::direction, std::vector const&, + std::optional> const&, + std::optional> const&, + std::optional> const& rental_providers, bool wheelchair, std::chrono::seconds max, unsigned max_matching_distance, - gbfs::gbfs_data const*) const; + gbfs::gbfs_routing_data&) const; nigiri::hash_map> @@ -35,10 +42,13 @@ struct routing { std::pair, nigiri::duration_t> route_direct( elevators const*, - gbfs::gbfs_data const*, + gbfs::gbfs_routing_data&, api::Place const& from, api::Place const& to, std::vector const&, + std::optional> const&, + std::optional> const&, + std::optional> const& rental_providers, nigiri::unixtime_t start_time, bool wheelchair, std::chrono::seconds max) const; diff --git a/include/motis/fwd.h b/include/motis/fwd.h index 3c8130c10a..dc354185b1 100644 --- a/include/motis/fwd.h +++ b/include/motis/fwd.h @@ -46,6 +46,10 @@ struct elevators; namespace gbfs { struct gbfs_data; struct gbfs_provider; +struct gbfs_products_ref; +struct gbfs_routing_data; +struct provider_routing_data; +struct products_routing_data; } // namespace gbfs } // namespace motis diff --git a/include/motis/gbfs/compression.h b/include/motis/gbfs/compression.h new file mode 100644 index 0000000000..08fd49eee3 --- /dev/null +++ b/include/motis/gbfs/compression.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include + +#include "cista/containers/bitvec.h" + +#include "utl/verify.h" + +#include "lz4.h" + +#include "motis/gbfs/data.h" + +namespace motis::gbfs { + +template +inline compressed_bitvec compress_bitvec( + cista::basic_bitvec const& bv) { + auto const* original_data = reinterpret_cast(bv.blocks_.data()); + auto const original_bytes = + static_cast(bv.blocks_.size() * + sizeof(typename cista::basic_bitvec::block_t)); + auto const max_compressed_size = LZ4_compressBound(original_bytes); + + auto cbv = compressed_bitvec{ + .data_ = + std::unique_ptr{ + static_cast( + std::malloc(static_cast(max_compressed_size)))}, + .original_bytes_ = original_bytes, + .bitvec_size_ = bv.size_}; + utl::verify(cbv.data_ != nullptr, + "could not allocate memory for compressed bitvec"); + + cbv.compressed_bytes_ = LZ4_compress_default( + original_data, cbv.data_.get(), original_bytes, max_compressed_size); + utl::verify(cbv.compressed_bytes_ > 0, "could not compress bitvec"); + + if (auto* compressed = std::realloc( + cbv.data_.get(), static_cast(cbv.compressed_bytes_)); + compressed != nullptr) { + cbv.data_.release(); + cbv.data_.reset(static_cast(compressed)); + } + return cbv; +} + +template +inline void decompress_bitvec(compressed_bitvec const& cbv, + cista::basic_bitvec& bv) { + bv.resize(static_cast::size_type>( + cbv.bitvec_size_)); + auto const decompressed_bytes = LZ4_decompress_safe( + cbv.data_.get(), reinterpret_cast(bv.blocks_.data()), + cbv.compressed_bytes_, + static_cast( + bv.blocks_.size() * + sizeof(typename cista::basic_bitvec::block_t))); + utl::verify(decompressed_bytes == cbv.original_bytes_, + "could not decompress bitvec"); +} + +} // namespace motis::gbfs diff --git a/include/motis/gbfs/data.h b/include/motis/gbfs/data.h index 7d14921bdf..9c1f060e2c 100644 --- a/include/motis/gbfs/data.h +++ b/include/motis/gbfs/data.h @@ -1,7 +1,13 @@ #pragma once +#include +#include #include +#include +#include +#include #include +#include #include #include #include @@ -9,17 +15,23 @@ #include "tg.h" +#include "cista/hash.h" #include "cista/strong.h" +#include "geo/box.h" #include "geo/latlng.h" #include "osr/routing/additional_edge.h" #include "osr/routing/sharing_data.h" #include "osr/types.h" +#include "motis/config.h" +#include "motis/fwd.h" #include "motis/point_rtree.h" #include "motis/types.h" +#include "motis/gbfs/lru_cache.h" + namespace motis::gbfs { enum class gbfs_version : std::uint8_t { @@ -28,6 +40,9 @@ enum class gbfs_version : std::uint8_t { k3 = 2, }; +using vehicle_type_idx_t = + cista::strong; + enum class vehicle_form_factor : std::uint8_t { kBicycle = 0, kCargoBicycle = 1, @@ -38,6 +53,17 @@ enum class vehicle_form_factor : std::uint8_t { kOther = 6 }; +enum class propulsion_type : std::uint8_t { + kHuman = 0, + kElectricAssist = 1, + kElectric = 2, + kCombustion = 3, + kCombustionDiesel = 4, + kHybrid = 5, + kPlugInHybrid = 6, + kHydrogenFuelCell = 7 +}; + enum class return_constraint : std::uint8_t { kNone = 0, // includes free_floating + hybrid kAnyStation = 1, @@ -46,7 +72,9 @@ enum class return_constraint : std::uint8_t { struct vehicle_type { std::string id_; + vehicle_type_idx_t idx_{vehicle_type_idx_t::invalid()}; vehicle_form_factor form_factor_{}; + propulsion_type propulsion_type_{}; return_constraint return_constraint_{}; }; @@ -84,12 +112,13 @@ struct station_information { std::string cross_street_{}; rental_uris rental_uris_{}; - std::unique_ptr station_area_{}; + std::shared_ptr station_area_{}; }; struct station_status { unsigned num_vehicles_available_{}; - hash_map vehicle_types_available_{}; + hash_map vehicle_types_available_{}; + hash_map vehicle_docks_available_{}; bool is_renting_{true}; bool is_returning_{true}; }; @@ -100,18 +129,21 @@ struct station { }; struct vehicle_status { + bool operator==(vehicle_status const& o) const { return id_ == o.id_; } + auto operator<=>(vehicle_status const& o) const { return id_ <=> o.id_; } + std::string id_; geo::latlng pos_; bool is_reserved_{}; bool is_disabled_{}; - std::string vehicle_type_id_; + vehicle_type_idx_t vehicle_type_idx_; std::string station_id_; std::string home_station_id_; rental_uris rental_uris_{}; }; struct rule { - std::vector vehicle_type_ids_{}; + std::vector vehicle_type_idxs_{}; bool ride_start_allowed_{}; bool ride_end_allowed_{}; bool ride_through_allowed_{}; @@ -128,14 +160,20 @@ struct geofencing_restrictions { struct zone { zone() = default; zone(tg_geom* geom, std::vector&& rules, std::string&& name) - : geom_{geom}, + : geom_{geom, tg_geom_deleter{}}, rules_{std::move(rules)}, clockwise_{geom_ && tg_geom_num_polys(geom_.get()) > 0 ? tg_poly_clockwise(tg_geom_poly_at(geom_.get(), 0)) : true}, name_{std::move(name)} {} - std::unique_ptr geom_; + geo::box bounding_box() const { + auto const rect = tg_geom_rect(geom_.get()); + return geo::box{geo::latlng{rect.min.y, rect.min.x}, + geo::latlng{rect.max.y, rect.max.x}}; + } + + std::shared_ptr geom_; std::vector rules_; bool clockwise_{true}; std::string name_; @@ -148,7 +186,9 @@ struct geofencing_zones { void clear(); geofencing_restrictions get_restrictions( - geo::latlng const&, geofencing_restrictions const& default_restrictions); + geo::latlng const& pos, + vehicle_type_idx_t, + geofencing_restrictions const& default_restrictions) const; }; struct additional_node { @@ -163,41 +203,205 @@ struct additional_node { std::variant data_; }; -struct gbfs_provider { +struct file_info { + bool has_value() const { return expiry_.has_value(); } + + bool needs_update(std::chrono::system_clock::time_point const now) const { + return !expiry_.has_value() || *expiry_ < now; + } + + std::optional expiry_{}; + cista::hash_t hash_{}; +}; + +struct provider_file_infos { + bool needs_update() const { + auto const now = std::chrono::system_clock::now(); + return urls_fi_.needs_update(now) || + system_information_fi_.needs_update(now) || + vehicle_types_fi_.needs_update(now) || + station_information_fi_.needs_update(now) || + station_status_fi_.needs_update(now) || + vehicle_status_fi_.needs_update(now) || + geofencing_zones_fi_.needs_update(now); + } + + hash_map urls_{}; + + file_info urls_fi_{}; + file_info system_information_fi_{}; + file_info vehicle_types_fi_{}; + file_info station_information_fi_{}; + file_info station_status_fi_{}; + file_info vehicle_status_fi_{}; + file_info geofencing_zones_fi_{}; +}; + +struct compressed_bitvec { + struct free_deleter { + void operator()(char* p) const { std::free(p); } + }; + + std::unique_ptr data_{}; + int original_bytes_{}; + int compressed_bytes_{}; + std::size_t bitvec_size_{}; +}; + +struct routing_data { + std::vector additional_nodes_{}; + osr::hash_map> + additional_edges_{}; + + osr::bitvec start_allowed_{}; + osr::bitvec end_allowed_{}; + osr::bitvec through_allowed_{}; + bool station_parking_{}; +}; + +struct compressed_routing_data { + std::vector additional_nodes_{}; + osr::hash_map> + additional_edges_{}; + + compressed_bitvec start_allowed_{}; + compressed_bitvec end_allowed_{}; + compressed_bitvec through_allowed_{}; +}; + +struct provider_routing_data; + +struct products_routing_data { + products_routing_data(std::shared_ptr&& prd, + compressed_routing_data const& compressed); + osr::sharing_data get_sharing_data( osr::node_idx_t::value_t const additional_node_offset) const { return {.start_allowed_ = start_allowed_, .end_allowed_ = end_allowed_, .through_allowed_ = through_allowed_, .additional_node_offset_ = additional_node_offset, - .additional_edges_ = additional_edges_}; + .additional_edges_ = compressed_.additional_edges_}; + } + + std::shared_ptr provider_routing_data_; + compressed_routing_data const& compressed_; + + osr::bitvec start_allowed_; + osr::bitvec end_allowed_; + osr::bitvec through_allowed_; +}; + +using gbfs_products_idx_t = + cista::strong; + +struct provider_routing_data + : std::enable_shared_from_this { + std::shared_ptr get_products_routing_data( + gbfs_products_idx_t const prod_idx) const { + return std::make_shared( + shared_from_this(), products_.at(to_idx(prod_idx))); + } + + std::vector products_; +}; + +struct provider_products { + bool includes_vehicle_type(vehicle_type_idx_t const idx) const { + return (idx == vehicle_type_idx_t::invalid() && vehicle_types_.empty()) || + std::find(begin(vehicle_types_), end(vehicle_types_), idx) != + end(vehicle_types_); + } + + gbfs_products_idx_t idx_{gbfs_products_idx_t::invalid()}; + std::vector vehicle_types_; + vehicle_form_factor form_factor_{vehicle_form_factor::kBicycle}; + propulsion_type propulsion_type_{propulsion_type::kHuman}; + return_constraint return_constraint_{return_constraint::kNone}; + + bool has_vehicles_to_rent_{}; +}; + +struct gbfs_products_ref { + friend bool operator==(gbfs_products_ref const&, + gbfs_products_ref const&) = default; + + explicit operator bool() const noexcept { + return provider_ != gbfs_provider_idx_t::invalid(); } + gbfs_provider_idx_t provider_{gbfs_provider_idx_t::invalid()}; + gbfs_products_idx_t products_{gbfs_products_idx_t::invalid()}; +}; + +struct gbfs_provider { std::string id_; // from config - gbfs_provider_idx_t idx_{}; + gbfs_provider_idx_t idx_{gbfs_provider_idx_t::invalid()}; + + std::shared_ptr file_infos_{}; system_information sys_info_{}; - hash_map stations_{}; - hash_map vehicle_types_{}; + std::map stations_{}; + vector_map vehicle_types_{}; + hash_map vehicle_types_map_{}; std::vector vehicle_status_; geofencing_zones geofencing_zones_{}; geofencing_restrictions default_restrictions_{}; - std::vector additional_nodes_; - osr::hash_map> - additional_edges_; + vector_map products_; + bool has_vehicles_to_rent_{}; +}; - osr::bitvec start_allowed_; - osr::bitvec end_allowed_; - osr::bitvec through_allowed_; +struct provider_feed { + bool operator==(provider_feed const& o) const { return id_ == o.id_; } + bool operator==(std::string const& id) const { return id_ == id; } + bool operator<(provider_feed const& o) const { return id_ < o.id_; } - bool has_vehicles_to_rent_{}; + std::string id_; + std::string url_; + headers_t headers_{}; + std::optional dir_{}; + geofencing_restrictions default_restrictions_{}; +}; + +struct aggregated_feed { + bool operator==(aggregated_feed const& o) const { return id_ == o.id_; } + bool operator==(std::string const& id) const { return id_ == id; } + bool operator<(aggregated_feed const& o) const { return id_ < o.id_; } + + bool needs_update() const { + return !expiry_.has_value() || + expiry_.value() < std::chrono::system_clock::now(); + } + + std::string id_; + std::string url_; + headers_t headers_{}; + std::optional expiry_{}; + std::vector feeds_{}; }; struct gbfs_data { + explicit gbfs_data(std::size_t const cache_size) : cache_{cache_size} {} + + std::shared_ptr get_products_routing_data( + osr::ways const& w, osr::lookup const& l, gbfs_products_ref); + + std::shared_ptr>> + standalone_feeds_{}; + std::shared_ptr>> + aggregated_feeds_{}; + vector_map> providers_{}; hash_map provider_by_id_{}; point_rtree provider_rtree_{}; + + lru_cache cache_; + + // used to share decompressed routing data between routing requests + std::mutex products_routing_data_mutex_; + hash_map> + products_routing_data_{}; }; } // namespace motis::gbfs diff --git a/include/motis/gbfs/geofencing.h b/include/motis/gbfs/geofencing.h index 2fff10debb..6a49ea8aa9 100644 --- a/include/motis/gbfs/geofencing.h +++ b/include/motis/gbfs/geofencing.h @@ -1,11 +1,18 @@ #pragma once +#include +#include + #include "tg.h" #include "geo/latlng.h" +#include "motis/gbfs/data.h" + namespace motis::gbfs { +bool applies(std::vector const& rule_vehicle_type_idxs, + std::vector const& segment_vehicle_type_idxs); bool multipoly_contains_point(tg_geom const* geom, geo::latlng const& pos); } // namespace motis::gbfs diff --git a/include/motis/gbfs/lru_cache.h b/include/motis/gbfs/lru_cache.h new file mode 100644 index 0000000000..b132d779d0 --- /dev/null +++ b/include/motis/gbfs/lru_cache.h @@ -0,0 +1,189 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "motis/types.h" + +#include "utl/helpers/algorithm.h" + +namespace motis::gbfs { + +template +class lru_cache { +public: + explicit lru_cache(std::size_t const max_size) : max_size_{max_size} {} + + lru_cache(lru_cache const& o) : max_size_{o.max_size_} { + auto read_lock = std::shared_lock{o.mutex_}; + cache_map_ = o.cache_map_; + lru_order_ = o.lru_order_; + pending_computations_.clear(); + } + + lru_cache& operator=(lru_cache const& o) { + if (this != &o) { + auto read_lock = std::shared_lock{o.mutex_}; + auto write_lock = std::unique_lock{mutex_}; + max_size_ = o.max_size_; + cache_map_ = o.cache_map_; + lru_order_ = o.lru_order_; + pending_computations_.clear(); + } + return *this; + } + + template + std::shared_ptr get_or_compute(Key const key, F compute_fn) { + // check with shared lock if entry already exists + { + auto read_lock = std::shared_lock{mutex_}; + if (auto it = cache_map_.find(key); it != cache_map_.end()) { + move_to_front(key); + return it->second->value_; + } + } + + // not found -> acquire exclusive lock to modify the cache + auto write_lock = std::unique_lock{mutex_}; + + // check again in case another thread inserted it + if (auto it = cache_map_.find(key); it != cache_map_.end()) { + move_to_front(key); + return it->second->value_; + } + + // if another thread is already computing it, wait for it + if (auto it = pending_computations_.find(key); + it != pending_computations_.end()) { + auto future = it->second; + write_lock.unlock(); + return future.get(); + } + + // create pending computation + auto promise = std::promise>{}; + auto shared_future = promise.get_future().share(); + pending_computations_[key] = shared_future; + write_lock.unlock(); + + // compute the value + auto value = compute_fn(); + + // store the result + write_lock.lock(); + + if (lru_order_.size() >= max_size_) { + // evict least recently used cache entry + auto const last_key = lru_order_.back(); + cache_map_.erase(last_key); + lru_order_.pop_back(); + } + + cache_map_.try_emplace( + key, std::make_shared(cache_entry{key, value})); + lru_order_.insert(lru_order_.begin(), key); + pending_computations_.erase(key); + promise.set_value(value); + + return value; + } + + std::shared_ptr get(Key const key) { + auto read_lock = std::shared_lock{mutex_}; + if (auto it = cache_map_.find(key); it != cache_map_.end()) { + return it->second->value_; + } + return nullptr; + } + + bool contains(Key const key) { + auto read_lock = std::shared_lock{mutex_}; + return cache_map_.find(key) != cache_map_.end(); + } + + template + void update_if_exists(Key const key, F update_fn) { + auto write_lock = std::unique_lock{mutex_}; + if (auto it = cache_map_.find(key); it != cache_map_.end()) { + it->second->value_ = update_fn(it->second->value_); + move_to_front(key); + } + } + + /// adds an entry to the cache if there is still space or updates + /// an existing entry if it already exists + template + bool try_add_or_update(Key const key, F compute_fn) { + auto write_lock = std::unique_lock{mutex_}; + + if (auto it = cache_map_.find(key); it != cache_map_.end()) { + it->second->value_ = compute_fn(); + move_to_front(key); + return true; + } + + if (lru_order_.size() >= max_size_) { + return false; + } + + cache_map_.try_emplace( + key, std::make_shared(cache_entry{key, compute_fn()})); + lru_order_.insert(lru_order_.begin(), key); + return true; + } + + void remove(Key const key) { + auto write_lock = std::unique_lock{mutex_}; + if (auto it = cache_map_.find(key); it != cache_map_.end()) { + if (auto const lru_it = utl::find(lru_order_, key); + lru_it != lru_order_.end()) { + lru_order_.erase(lru_it); + } + cache_map_.erase(it); + } + } + + std::vector>> get_all_entries() const { + auto read_lock = std::shared_lock{mutex_}; + auto entries = std::vector>>{}; + entries.reserve(lru_order_.size()); + for (auto const it = lru_order_.rbegin(); it != lru_order_.rend(); ++it) { + if (auto const map_it = cache_map_.find(*it); + map_it != cache_map_.end()) { + entries.emplace_back(map_it->first, map_it->second->value_); + } + } + return entries; + } + + std::size_t size() const { return lru_order_.size(); } + + bool empty() const { return lru_order_.empty(); } + +private: + struct cache_entry { + Key key_{}; + std::shared_ptr value_{}; + }; + + void move_to_front(Key const key) { + auto const it = utl::find(lru_order_, key); + if (it != lru_order_.end()) { + lru_order_.erase(it); + lru_order_.insert(lru_order_.begin(), key); + } + } + + std::size_t max_size_; + hash_map> cache_map_; + std::vector lru_order_; + hash_map>> + pending_computations_{}; + mutable std::shared_mutex mutex_; +}; + +} // namespace motis::gbfs diff --git a/include/motis/gbfs/mode.h b/include/motis/gbfs/mode.h new file mode 100644 index 0000000000..98a769ec6e --- /dev/null +++ b/include/motis/gbfs/mode.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "motis/gbfs/data.h" + +#include "motis-api/motis-api.h" + +namespace motis::gbfs { + +api::RentalFormFactorEnum to_api_form_factor(vehicle_form_factor); +vehicle_form_factor from_api_form_factor(api::RentalFormFactorEnum); + +api::RentalPropulsionTypeEnum to_api_propulsion_type(propulsion_type); +propulsion_type from_api_propulsion_type(api::RentalPropulsionTypeEnum); + +api::RentalReturnConstraintEnum to_api_return_constraint(return_constraint); + +bool products_match( + provider_products const& prod, + std::optional> const& form_factors, + std::optional> const& + propulsion_types); + +} // namespace motis::gbfs diff --git a/include/motis/gbfs/osr_mapping.h b/include/motis/gbfs/osr_mapping.h index b2a5872a56..4656526dec 100644 --- a/include/motis/gbfs/osr_mapping.h +++ b/include/motis/gbfs/osr_mapping.h @@ -4,8 +4,9 @@ namespace motis::gbfs { -void map_geofencing_zones(osr::ways const&, osr::lookup const&, gbfs_provider&); -void map_stations(osr::ways const&, osr::lookup const&, gbfs_provider&); -void map_vehicles(osr::ways const&, osr::lookup const&, gbfs_provider&); +void map_data(osr::ways const&, + osr::lookup const&, + gbfs_provider const&, + provider_routing_data&); } // namespace motis::gbfs diff --git a/include/motis/gbfs/partition.h b/include/motis/gbfs/partition.h new file mode 100644 index 0000000000..f50fdc13a5 --- /dev/null +++ b/include/motis/gbfs/partition.h @@ -0,0 +1,117 @@ +#pragma once + +#include +#include +#include +#include + +#include "cista/strong.h" + +namespace motis::gbfs { + +template +struct partition { + explicit partition(T const n) : n_{n} { + partition_.resize(static_cast(cista::to_idx(n))); + for (auto i = T{0}; i < n; ++i) { + partition_[static_cast(cista::to_idx(i))] = i; + } + if (n != 0) { + // initially there's only one set ending at n-1 + set_ends_.push_back(n - 1); + } + } + + void refine(std::span const s) { + if (s.empty()) { + return; + } + + // mark elements in s + auto in_s = + std::vector(static_cast(cista::to_idx(n_)), false); + for (auto const elem : s) { + assert(elem < n_); + in_s[static_cast(cista::to_idx(elem))] = true; + } + + // process each existing set + auto current_start = T{0}; + auto new_set_ends = std::vector{}; + new_set_ends.reserve(2 * set_ends_.size()); + + for (auto const set_end : set_ends_) { + // count elements in current set that are in s + auto count = T{0}; + for (auto i = current_start; i <= set_end; ++i) { + if (in_s[static_cast(cista::to_idx( + partition_[static_cast(cista::to_idx(i))]))]) { + ++count; + } + } + + auto const set_size = set_end - current_start + 1; + // if split is needed (some but not all elements are in s) + if (count != 0 && count != set_size) { + // partition the set into two parts + auto split_pos = current_start; + for (auto i = current_start; i <= set_end; ++i) { + if (in_s[static_cast(cista::to_idx( + partition_[static_cast(cista::to_idx(i))]))]) { + // move element to front of split + if (i != split_pos) { + std::swap(partition_[static_cast(cista::to_idx(i))], + partition_[static_cast( + cista::to_idx(split_pos))]); + } + ++split_pos; + } + } + + // add end positions for both new sets + new_set_ends.push_back(split_pos - 1); + new_set_ends.push_back(set_end); + } else { + // no split needed, keep original set + new_set_ends.push_back(set_end); + } + + current_start = set_end + 1; + } + + set_ends_ = std::move(new_set_ends); + } + + std::vector> get_sets() const { + auto result = std::vector>{}; + result.reserve(set_ends_.size()); + + auto current_start = T{0}; + for (auto const set_end : set_ends_) { + auto set = std::vector{}; + set.reserve( + static_cast(cista::to_idx(set_end - current_start + 1))); + for (auto i = current_start; i <= set_end; ++i) { + set.push_back(partition_[static_cast(cista::to_idx(i))]); + } + result.push_back(std::move(set)); + current_start = set_end + 1; + } + + return result; + } + + // the number of elements in the partition - the original set + // contains the elements 0, 1, ..., n - 1 + T n_; + + // stores the elements grouped by sets - the elements of each set are + // stored contiguously, e.g. "0345789" could be {{0, 3, 4}, {5}, {7, 8, 9}} + // or {{0}, {3, 4}, {5}, {7, 8, 9}}, depending on set_ends_. + std::vector partition_; + + // stores the end index of each set in partition_ + std::vector set_ends_; +}; + +} // namespace motis::gbfs diff --git a/include/motis/gbfs/routing_data.h b/include/motis/gbfs/routing_data.h new file mode 100644 index 0000000000..cf70180342 --- /dev/null +++ b/include/motis/gbfs/routing_data.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +#include "motis/fwd.h" +#include "motis/gbfs/data.h" +#include "motis/types.h" + +namespace motis::gbfs { + +struct gbfs_routing_data { + gbfs_routing_data() = default; + gbfs_routing_data(osr::ways const* w, + osr::lookup const* l, + std::shared_ptr data) + : w_{w}, l_{l}, data_{std::move(data)} {} + + bool has_data() const { return data_ != nullptr; } + + std::shared_ptr get_provider_routing_data( + gbfs_provider const&); + + products_routing_data* get_products_routing_data( + gbfs_provider const& provider, gbfs_products_idx_t prod_idx); + products_routing_data* get_products_routing_data(gbfs_products_ref); + + nigiri::transport_mode_id_t get_transport_mode(gbfs_products_ref); + gbfs_products_ref get_products_ref(nigiri::transport_mode_id_t) const; + + osr::ways const* w_{}; + osr::lookup const* l_{}; + std::shared_ptr data_{}; + + hash_map> products_; + std::vector products_refs_; + hash_map + products_ref_to_transport_mode_; +}; + +std::shared_ptr compute_provider_routing_data( + osr::ways const&, osr::lookup const&, gbfs_provider const&); + +std::shared_ptr get_provider_routing_data( + osr::ways const&, osr::lookup const&, gbfs_data&, gbfs_provider const&); + +} // namespace motis::gbfs diff --git a/include/motis/hashes.h b/include/motis/hashes.h index 610e92a058..058d90f2fc 100644 --- a/include/motis/hashes.h +++ b/include/motis/hashes.h @@ -11,7 +11,7 @@ using meta_entry_t = std::pair; using meta_t = std::map; constexpr auto const osr_version = []() { - return meta_entry_t{"osr_bin_ver", 8U}; + return meta_entry_t{"osr_bin_ver", 9U}; }; constexpr auto const adr_version = []() { return meta_entry_t{"adr_bin_ver", 4U}; diff --git a/include/motis/http_client.h b/include/motis/http_client.h index 78f59e9ce6..1a413b89eb 100644 --- a/include/motis/http_client.h +++ b/include/motis/http_client.h @@ -38,6 +38,14 @@ struct http_client { bool ssl_{}; }; + struct proxy_settings { + operator bool() const { return !host_.empty(); } + + std::string host_; + std::string port_; + bool ssl_{}; + }; + struct connection; struct request; @@ -46,8 +54,12 @@ struct http_client { boost::asio::awaitable get( boost::urls::url url, std::map headers); + void set_proxy(boost::urls::url const&); + hash_map> connections_; std::chrono::seconds timeout_{std::chrono::seconds{10}}; + + proxy_settings proxy_{}; }; } // namespace motis diff --git a/include/motis/journey_to_response.h b/include/motis/journey_to_response.h index bf31183532..c2022ea335 100644 --- a/include/motis/journey_to_response.h +++ b/include/motis/journey_to_response.h @@ -35,12 +35,13 @@ api::Itinerary journey_to_response(osr::ways const*, nigiri::rt_timetable const*, platform_matches_t const* matches, nigiri::shapes_storage const*, - gbfs::gbfs_data const*, + gbfs::gbfs_routing_data&, bool const wheelchair, nigiri::routing::journey const&, place_t const& start, place_t const& dest, street_routing_cache_t&, - osr::bitvec& blocked_mem); + osr::bitvec& blocked_mem, + bool detailed_transfers); } // namespace motis diff --git a/include/motis/point_rtree.h b/include/motis/point_rtree.h index 0cbaf6d607..ff50185df8 100644 --- a/include/motis/point_rtree.h +++ b/include/motis/point_rtree.h @@ -26,7 +26,15 @@ struct point_rtree { } } - point_rtree(point_rtree const&) = delete; + point_rtree(point_rtree const& o) { + if (this != &o) { + if (rtree_ != nullptr) { + rtree_free(rtree_); + } + rtree_ = rtree_clone(o.rtree_); + } + } + point_rtree(point_rtree&& o) { if (this != &o) { rtree_ = o.rtree_; @@ -34,7 +42,16 @@ struct point_rtree { } } - point_rtree& operator=(point_rtree const&) = delete; + point_rtree& operator=(point_rtree const& o) { + if (this != &o) { + if (rtree_ != nullptr) { + rtree_free(rtree_); + } + rtree_ = rtree_clone(o.rtree_); + } + return *this; + } + point_rtree& operator=(point_rtree&& o) { if (this != &o) { rtree_ = o.rtree_; @@ -50,6 +67,13 @@ struct point_rtree { reinterpret_cast(static_cast(cista::to_idx(t)))); } + void remove(geo::latlng const& pos, T const t) { + auto const min_corner = std::array{pos.lng(), pos.lat()}; + rtree_delete( + rtree_, min_corner.data(), nullptr, + reinterpret_cast(static_cast(cista::to_idx(t)))); + } + std::vector in_radius(geo::latlng const& x, double distance) const { auto ret = std::vector{}; in_radius(x, distance, [&](auto&& item) { ret.emplace_back(item); }); @@ -90,4 +114,4 @@ struct point_rtree { rtree* rtree_{nullptr}; }; -} // namespace motis \ No newline at end of file +} // namespace motis diff --git a/include/motis/street_routing.h b/include/motis/street_routing.h index b59e5ec279..2f457bdcd8 100644 --- a/include/motis/street_routing.h +++ b/include/motis/street_routing.h @@ -27,17 +27,18 @@ api::Itinerary dummy_itinerary(api::Place const& from, api::Itinerary route(osr::ways const&, osr::lookup const&, - gbfs::gbfs_data const*, + gbfs::gbfs_routing_data&, elevators const*, api::Place const& from, api::Place const& to, api::ModeEnum, - bool const wheelchair, + bool wheelchair, nigiri::unixtime_t start_time, std::optional end_time, - gbfs_provider_idx_t, + gbfs::gbfs_products_ref, street_routing_cache_t&, osr::bitvec& blocked_mem, - std::chrono::seconds max = std::chrono::seconds{3600}); + std::chrono::seconds max = std::chrono::seconds{3600}, + bool dummy = false); -} // namespace motis \ No newline at end of file +} // namespace motis diff --git a/include/motis/tag_lookup.h b/include/motis/tag_lookup.h index 0be60a44d9..eb0bb0dabc 100644 --- a/include/motis/tag_lookup.h +++ b/include/motis/tag_lookup.h @@ -18,7 +18,9 @@ struct tag_lookup { nigiri::source_idx_t get_src(std::string_view tag) const; std::string_view get_tag(nigiri::source_idx_t) const; std::string id(nigiri::timetable const&, nigiri::location_idx_t) const; - std::string id(nigiri::timetable const&, nigiri::rt::run_stop) const; + std::string id(nigiri::timetable const&, + nigiri::rt::run_stop, + nigiri::event_type) const; nigiri::location_idx_t get_location(nigiri::timetable const&, std::string_view) const; std::pair get_trip( diff --git a/include/motis/types.h b/include/motis/types.h index e4d4ae8678..03ee1b3c47 100644 --- a/include/motis/types.h +++ b/include/motis/types.h @@ -32,7 +32,7 @@ using hash_map = nigiri::hash_map; using elevator_idx_t = cista::strong; using gbfs_provider_idx_t = - cista::strong; + cista::strong; struct elevator { friend bool operator==(elevator const&, elevator const&) = default; @@ -53,4 +53,4 @@ struct elevator { using rtt_ptr_t = std::shared_ptr; -} // namespace motis \ No newline at end of file +} // namespace motis diff --git a/openapi.yaml b/openapi.yaml index cdd9506025..31e0187565 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -359,11 +359,11 @@ paths: schema: type: integer - - name: maxHours + - name: maxTravelTime in: query required: false description: | - The maximum travel time in hours. + The maximum travel time in minutes. If not provided, the routing to uses the value hardcoded in the server which is usually quite high. @@ -371,10 +371,8 @@ paths: optimal (e.g. the least transfers) journeys not being found. If this value is too low to reach the destination at all, it can lead to slow routing performance. - - TODO: pass parameter to nigiri schema: - type: number + type: integer - name: minTransferTime in: query @@ -412,7 +410,7 @@ paths: - name: maxMatchingDistance in: query - required: true + required: false description: | Optional. Default is 25 meters. @@ -421,14 +419,39 @@ paths: type: number default: 25 - - name: wheelchair + - name: pedestrianProfile in: query - description: Whether the trip must be wheelchair accessible. required: false + description: | + Optional. Default is `FOOT`. + + Accessibility profile to use for pedestrian routing in transfers + between transit connections, on the first mile, and last mile. + schema: + $ref: '#/components/schemas/PedestrianProfile' + default: FOOT + + - name: useRoutedTransfers + in: query + required: false + description: | + Optional. Default is `false`. + + Whether to use transfers routed on OpenStreetMap data. schema: type: boolean default: false + - name: detailedTransfers + in: query + required: true + description: | + - true: Compute transfer polylines and step instructions. + - false: Only return basic information (start time, end time, duration) for transfers. + schema: + type: boolean + default: true + - name: transitModes in: query required: false @@ -498,6 +521,153 @@ paths: $ref: '#/components/schemas/Mode' explode: false + - name: directRentalFormFactors + in: query + required: false + description: | + Experimental. Expect unannounced breaking changes (without version bumps). + + Optional. Only applies to direct connections. + + A list of vehicle type form factors that are allowed to be used for direct connections. + If empty (the default), all form factors are allowed. + Example: `BICYCLE,SCOOTER_STANDING`. + schema: + type: array + items: + $ref: '#/components/schemas/RentalFormFactor' + explode: false + + - name: preTransitRentalFormFactors + in: query + required: false + description: | + Experimental. Expect unannounced breaking changes (without version bumps). + + Optional. Only applies if the `from` place is a coordinate (not a transit stop). Does not apply to direct connections (see `directRentalFormFactors`). + + A list of vehicle type form factors that are allowed to be used from the `from` coordinate to the first transit stop. + If empty (the default), all form factors are allowed. + Example: `BICYCLE,SCOOTER_STANDING`. + schema: + type: array + items: + $ref: '#/components/schemas/RentalFormFactor' + explode: false + + - name: postTransitRentalFormFactors + in: query + required: false + description: | + Experimental. Expect unannounced breaking changes (without version bumps). + + Optional. Only applies if the `to` place is a coordinate (not a transit stop). Does not apply to direct connections (see `directRentalFormFactors`). + + A list of vehicle type form factors that are allowed to be used from the last transit stop to the `to` coordinate. + If empty (the default), all form factors are allowed. + Example: `BICYCLE,SCOOTER_STANDING`. + schema: + type: array + items: + $ref: '#/components/schemas/RentalFormFactor' + explode: false + + - name: directRentalPropulsionTypes + in: query + required: false + description: | + Experimental. Expect unannounced breaking changes (without version bumps). + + Optional. Only applies to direct connections. + + A list of vehicle type form factors that are allowed to be used for direct connections. + If empty (the default), all propulsion types are allowed. + Example: `HUMAN,ELECTRIC,ELECTRIC_ASSIST`. + schema: + type: array + items: + $ref: '#/components/schemas/RentalPropulsionType' + explode: false + + - name: preTransitRentalPropulsionTypes + in: query + required: false + description: | + Experimental. Expect unannounced breaking changes (without version bumps). + + Optional. Only applies if the `from` place is a coordinate (not a transit stop). Does not apply to direct connections (see `directRentalPropulsionTypes`). + + A list of vehicle propulsion types that are allowed to be used from the `from` coordinate to the first transit stop. + If empty (the default), all propulsion types are allowed. + Example: `HUMAN,ELECTRIC,ELECTRIC_ASSIST`. + schema: + type: array + items: + $ref: '#/components/schemas/RentalPropulsionType' + explode: false + + - name: postTransitRentalPropulsionTypes + in: query + required: false + description: | + Experimental. Expect unannounced breaking changes (without version bumps). + + Optional. Only applies if the `to` place is a coordinate (not a transit stop). Does not apply to direct connections (see `directRentalPropulsionTypes`). + + A list of vehicle propulsion types that are allowed to be used from the last transit stop to the `to` coordinate. + If empty (the default), all propulsion types are allowed. + Example: `HUMAN,ELECTRIC,ELECTRIC_ASSIST`. + schema: + type: array + items: + $ref: '#/components/schemas/RentalPropulsionType' + explode: false + + - name: directRentalProviders + in: query + required: false + description: | + Experimental. Expect unannounced breaking changes (without version bumps). + + Optional. Only applies to direct connections. + + A list of rental providers that are allowed to be used for direct connections. + If empty (the default), all providers are allowed. + schema: + type: array + items: + type: string + + - name: preTransitRentalProviders + in: query + required: false + description: | + Experimental. Expect unannounced breaking changes (without version bumps). + + Optional. Only applies if the `from` place is a coordinate (not a transit stop). Does not apply to direct connections (see `directRentalProviders`). + + A list of rental providers that are allowed to be used from the `from` coordinate to the first transit stop. + If empty (the default), all providers are allowed. + schema: + type: array + items: + type: string + + - name: postTransitRentalProviders + in: query + required: false + description: | + Experimental. Expect unannounced breaking changes (without version bumps). + + Optional. Only applies if the `to` place is a coordinate (not a transit stop). Does not apply to direct connections (see `directRentalProviders`). + + A list of rental providers that are allowed to be used from the last transit stop to the `to` coordinate. + If empty (the default), all providers are allowed. + schema: + type: array + items: + type: string + - name: numItineraries in: query required: false @@ -614,6 +784,14 @@ paths: type: integer default: 1800 minimum: 0 + + - name: timeout + in: query + required: false + description: Optional. Query timeout in seconds. + schema: + type: integer + minimum: 0 responses: '200': description: routing result @@ -943,13 +1121,20 @@ components: description: score according to the internal scoring system (the scoring algorithm might change in the future) type: number + PedestrianProfile: + description: Different accessibility profiles for pedestrians. + type: string + enum: + - FOOT + - WHEELCHAIR + Mode: description: | # Street modes - `WALK` - `BIKE` - - `BIKE_RENTAL` + - `RENTAL` Experimental. Expect unannounced breaking changes (without version bumps). - `CAR` - `CAR_PARKING` @@ -974,8 +1159,8 @@ components: # === Street === - WALK - BIKE + - RENTAL - CAR - - BIKE_RENTAL - CAR_PARKING # === Transit === - TRANSIT @@ -1251,6 +1436,36 @@ components: and thus the directions should say something like "cross" type: boolean + RentalFormFactor: + type: string + enum: + - BICYCLE + - CARGO_BICYCLE + - CAR + - MOPED + - SCOOTER_STANDING + - SCOOTER_SEATED + - OTHER + + RentalPropulsionType: + type: string + enum: + - HUMAN + - ELECTRIC_ASSIST + - ELECTRIC + - COMBUSTION + - COMBUSTION_DIESEL + - HYBRID + - PLUG_IN_HYBRID + - HYDROGEN_FUEL_CELL + + RentalReturnConstraint: + type: string + enum: + - NONE + - ANY_STATION + - ROUNDTRIP_STATION + Rental: description: Vehicle rental type: object @@ -1278,6 +1493,12 @@ components: rentalUriWeb: type: string description: Rental URI for web (deep link to the specific station or vehicle) + formFactor: + $ref: '#/components/schemas/RentalFormFactor' + propulsionType: + $ref: '#/components/schemas/RentalPropulsionType' + returnConstraint: + $ref: '#/components/schemas/RentalReturnConstraint' Leg: type: object @@ -1428,7 +1649,12 @@ components: foot: type: number description: | - optional; missing if no path was found with the foot profile + optional; missing if no path was found (timetable / osr) + footpath duration in minutes for the foot profile + footRouted: + type: number + description: | + optional; missing if no path was found with foot routing footpath duration in minutes for the foot profile wheelchair: type: number diff --git a/src/compute_footpaths.cc b/src/compute_footpaths.cc index 44bf906cbe..65964c86a0 100644 --- a/src/compute_footpaths.cc +++ b/src/compute_footpaths.cc @@ -3,7 +3,10 @@ #include "cista/mmap.h" #include "cista/serialization.h" +#include "utl/concat.h" +#include "utl/erase_if.h" #include "utl/parallel_for.h" +#include "utl/sorted_diff.h" #include "osr/routing/profiles/foot.h" #include "osr/routing/route.h" @@ -47,12 +50,15 @@ vector_map lookup_locations( return ret; } -elevator_footpath_map_t compute_footpaths(osr::ways const& w, - osr::lookup const& lookup, - osr::platforms const& pl, - nigiri::timetable& tt, - bool const update_coordinates) { - fmt::println(std::clog, " -> creating matches"); +elevator_footpath_map_t compute_footpaths( + osr::ways const& w, + osr::lookup const& lookup, + osr::platforms const& pl, + nigiri::timetable& tt, + bool const update_coordinates, + bool const extend_missing, + std::chrono::seconds const max_duration) { + fmt::println(std::clog, "creating matches"); auto const matches = get_matches(tt, pl, w); fmt::println(std::clog, " -> creating r-tree"); @@ -67,10 +73,7 @@ elevator_footpath_map_t compute_footpaths(osr::ways const& w, tt.locations_.coordinates_[i] = *center; } } - - if (!tt.location_routes_[i].empty()) { - t.add(tt.locations_.coordinates_[i], i); - } + t.add(tt.locations_.coordinates_[i], i); } return t; }(); @@ -102,52 +105,91 @@ elevator_footpath_map_t compute_footpaths(osr::ways const& w, auto const wheelchair_candidates = lookup_locations( w, lookup, pl, tt, matches, osr::search_profile::kWheelchair); - auto m = std::mutex{}; + struct state { + std::vector sorted_tt_fps_; + std::vector missing_; + std::vector neighbors_; + std::vector neighbors_loc_; + std::vector neighbor_candidates_; + }; + for (auto const mode : {osr::search_profile::kFoot, osr::search_profile::kWheelchair}) { auto const& candidates = mode == osr::search_profile::kFoot ? foot_candidates : wheelchair_candidates; - utl::parallel_for_run(tt.n_locations(), [&](auto const i) { - auto const l = n::location_idx_t{i}; - auto& footpaths = - (mode == osr::search_profile::kFoot ? footpaths_out_foot[l] - : footpaths_out_wheelchair[l]); - auto neighbors = std::vector{}; - loc_rtree.in_radius(tt.locations_.coordinates_[l], kMaxDistance, - [&](n::location_idx_t const x) { - if (x != l) { - neighbors.emplace_back(x); - } - }); - auto const results = osr::route( - w, mode, get_loc(tt, w, pl, matches, l), - utl::to_vec(neighbors, - [&](auto&& x) { return get_loc(tt, w, pl, matches, x); }), - candidates[l], - utl::to_vec(neighbors, [&](auto&& x) { return candidates[x]; }), - kMaxDuration, osr::direction::kForward, nullptr, nullptr, - [](osr::path const& p) { return p.uses_elevator_; }); - for (auto const [n, r] : utl::zip(neighbors, results)) { - if (r.has_value()) { - auto lock = std::scoped_lock{m}; - auto const duration = n::duration_t{r->cost_ / 60U}; - if (duration < n::footpath::kMaxDuration) { - footpaths.emplace_back(n::footpath{n, duration}); + utl::parallel_for_run_threadlocal( + tt.n_locations(), [&](state& s, auto const i) { + cista::for_each_field(s, [](auto& f) { f.clear(); }); + + auto const l = n::location_idx_t{i}; + auto& footpaths = (mode == osr::search_profile::kFoot + ? footpaths_out_foot[l] + : footpaths_out_wheelchair[l]); + loc_rtree.in_radius(tt.locations_.coordinates_[l], kMaxDistance, + [&](n::location_idx_t const x) { + if (x != l) { + s.neighbors_.emplace_back(x); + } + }); + auto const results = osr::route( + w, mode, get_loc(tt, w, pl, matches, l), + utl::transform_to( + s.neighbors_, s.neighbors_loc_, + [&](auto&& x) { return get_loc(tt, w, pl, matches, x); }), + candidates[l], + utl::transform_to(s.neighbors_, s.neighbor_candidates_, + [&](auto&& x) { return candidates[x]; }), + kMaxDuration, osr::direction::kForward, nullptr, nullptr, + [](osr::path const& p) { return p.uses_elevator_; }); + for (auto const [n, r] : utl::zip(s.neighbors_, results)) { + if (r.has_value()) { + auto const duration = n::duration_t{r->cost_ / 60U}; + footpaths.emplace_back(n::footpath{n, duration}); + for (auto const& seg : r->segments_) { + add_if_elevator(seg.from_, l, n); + add_if_elevator(seg.from_, n, l); + } + } } - for (auto const& s : r->segments_) { - add_if_elevator(s.from_, l, n); - add_if_elevator(s.from_, n, l); + + if (extend_missing && mode == osr::search_profile::kFoot) { + auto const& tt_fps = tt.locations_.footpaths_out_[0].at(l); + s.sorted_tt_fps_.resize(tt_fps.size()); + std::copy(begin(tt_fps), end(tt_fps), begin(s.sorted_tt_fps_)); + utl::sort(s.sorted_tt_fps_); + utl::sort(footpaths); + + utl::sorted_diff( + s.sorted_tt_fps_, footpaths, + [](auto&& a, auto&& b) { return a.target() < b.target(); }, + [](auto&& a, auto&& b) { return a.target() == b.target(); }, + utl::overloaded{ + [](n::footpath, n::footpath) { assert(false); }, + [&](utl::op const op, n::footpath const x) { + if (op == utl::op::kDel) { + auto const duration = + n::duration_t{static_cast(std::ceil( + (geo::distance( + tt.locations_.coordinates_[l], + tt.locations_.coordinates_[x.target()]) / + 0.7) / + 60.0))}; + s.missing_.emplace_back(x.target(), duration); + } + }}); + + utl::concat(footpaths, s.missing_); } - } - } - utl::sort(footpaths_out_foot[l]); - utl::sort(footpaths_out_wheelchair[l]); + utl::erase_if(footpaths, [&](n::footpath fp) { + return fp.duration() > max_duration; + }); + utl::sort(footpaths); - pt->update_monotonic( - (mode == osr::search_profile::kFoot ? 0U : tt.n_locations()) + i); - }); + pt->update_monotonic( + (mode == osr::search_profile::kFoot ? 0U : tt.n_locations()) + i); + }); } fmt::println(std::clog, " -> create ingoing footpaths"); diff --git a/src/data.cc b/src/data.cc index e58c09ba10..7f71b5852e 100644 --- a/src/data.cc +++ b/src/data.cc @@ -98,7 +98,7 @@ data::data(std::filesystem::path p, config const& c) auto tt = std::async(std::launch::async, [&]() { if (c.timetable_) { - load_tt(); + load_tt(config_.osr_footpath_ ? "tt_ext.bin" : "tt.bin"); if (c.timetable_->with_shapes_) { load_shapes(); } @@ -189,9 +189,9 @@ void data::load_osr() { pl_->build_rtree(*w_); } -void data::load_tt() { +void data::load_tt(fs::path const& p) { tags_ = tag_lookup::read(path_ / "tags.bin"); - tt_ = n::timetable::read(path_ / "tt.bin"); + tt_ = n::timetable::read(path_ / p); tt_->locations_.resolve_timezones(); location_rtee_ = std::make_unique>( create_location_rtree(*tt_)); diff --git a/src/endpoints/footpaths.cc b/src/endpoints/footpaths.cc index d25d0147d6..f8eae85c38 100644 --- a/src/endpoints/footpaths.cc +++ b/src/endpoints/footpaths.cc @@ -31,13 +31,16 @@ api::footpaths_response footpaths::operator()( auto footpaths = hash_map{}; - for (auto const fp : tt_.locations_.footpaths_out_[0][l]) { - if (tt_.location_routes_[fp.target()].empty()) { - continue; - } + for (auto const fp : tt_.locations_.footpaths_out_[0].at(l)) { footpaths[fp.target()].default_ = fp.duration().count(); } + if (!tt_.locations_.footpaths_out_[1].empty()) { + for (auto const fp : tt_.locations_.footpaths_out_[1].at(l)) { + footpaths[fp.target()].foot_ = fp.duration().count(); + } + } + auto const loc = get_loc(tt_, w_, pl_, matches_, l); for (auto const mode : {osr::search_profile::kFoot, osr::search_profile::kWheelchair}) { @@ -57,7 +60,7 @@ api::footpaths_response footpaths::operator()( std::ceil(r->cost_ * kTransferTimeMultiplier / 60U); if (duration < n::footpath::kMaxDuration.count()) { switch (mode) { - case osr::search_profile::kFoot: fp.foot_ = duration; break; + case osr::search_profile::kFoot: fp.footRouted_ = duration; break; case osr::search_profile::kWheelchair: fp.wheelchair_ = duration; fp.wheelchairUsesElevator_ = r->uses_elevator_; diff --git a/src/endpoints/routing.cc b/src/endpoints/routing.cc index ccfa03abe7..58a5907518 100644 --- a/src/endpoints/routing.cc +++ b/src/endpoints/routing.cc @@ -1,5 +1,7 @@ #include "motis/endpoints/routing.h" +#include + #include "boost/thread/tss.hpp" #include "utl/erase_duplicates.h" @@ -20,6 +22,8 @@ #include "motis/constants.h" #include "motis/endpoints/routing.h" #include "motis/gbfs/data.h" +#include "motis/gbfs/mode.h" +#include "motis/gbfs/routing_data.h" #include "motis/journey_to_response.h" #include "motis/max_distance.h" #include "motis/mode_to_profile.h" @@ -118,10 +122,14 @@ std::vector routing::get_offsets( osr::location const& pos, osr::direction const dir, std::vector const& modes, + std::optional> const& form_factors, + std::optional> const& + propulsion_types, + std::optional> const& rental_providers, bool const wheelchair, std::chrono::seconds const max, unsigned const max_matching_distance, - gbfs::gbfs_data const* gbfs) const { + gbfs::gbfs_routing_data& gbfs_rd) const { if (!loc_tree_ || !pl_ || !tt_ || !loc_tree_ || !matches_) { return {}; } @@ -146,27 +154,45 @@ std::vector routing::get_offsets( }); if (profile == osr::search_profile::kBikeSharing) { - if (gbfs == nullptr) { + if (!gbfs_rd.has_data()) { return; } auto providers = hash_set{}; - gbfs->provider_rtree_.in_radius( + gbfs_rd.data_->provider_rtree_.in_radius( pos.pos_, max_dist, [&](auto const pi) { providers.insert(pi); }); for (auto const& pi : providers) { - auto const& provider = gbfs->providers_.at(pi); - auto const sharing = provider->get_sharing_data(w_->n_nodes()); - auto const paths = - osr::route(*w_, *l_, profile, pos, near_stop_locations, - static_cast(max.count()), dir, - kMaxMatchingDistance, nullptr, &sharing); - ignore_walk = true; - for (auto const [p, l] : utl::zip(paths, near_stops)) { - if (p.has_value()) { - offsets.emplace_back(l, n::duration_t{p->cost_ / 60}, - static_cast( - kGbfsTransportModeIdOffset + to_idx(pi))); + auto const& provider = gbfs_rd.data_->providers_.at(pi); + if (provider == nullptr || + (rental_providers && utl::find(*rental_providers, provider->id_) == + end(*rental_providers))) { + continue; + } + auto provider_rd = std::shared_ptr{}; + for (auto const& prod : provider->products_) { + if (prod.return_constraint_ == + gbfs::return_constraint::kRoundtripStation || + !gbfs::products_match(prod, form_factors, propulsion_types)) { + continue; + } + if (!provider_rd) { + provider_rd = gbfs_rd.get_provider_routing_data(*provider); + } + auto const prod_ref = gbfs::gbfs_products_ref{pi, prod.idx_}; + auto* prod_rd = + gbfs_rd.get_products_routing_data(*provider, prod.idx_); + auto const sharing = prod_rd->get_sharing_data(w_->n_nodes()); + auto const paths = + osr::route(*w_, *l_, profile, pos, near_stop_locations, + static_cast(max.count()), dir, + kMaxMatchingDistance, nullptr, &sharing); + ignore_walk = true; + for (auto const [p, l] : utl::zip(paths, near_stops)) { + if (p.has_value()) { + offsets.emplace_back(l, n::duration_t{p->cost_ / 60}, + gbfs_rd.get_transport_mode(prod_ref)); + } } } } @@ -184,12 +210,12 @@ std::vector routing::get_offsets( } }; - if (utl::find(modes, api::ModeEnum::BIKE_RENTAL) != end(modes)) { - handle_mode(api::ModeEnum::BIKE_RENTAL); + if (utl::find(modes, api::ModeEnum::RENTAL) != end(modes)) { + handle_mode(api::ModeEnum::RENTAL); } for (auto const m : modes) { - if (m == api::ModeEnum::BIKE_RENTAL) { + if (m == api::ModeEnum::RENTAL) { continue; // handled above } if (m == api::ModeEnum::WALK && ignore_walk) { @@ -223,19 +249,22 @@ std::pair> get_start_time( std::pair, n::duration_t> routing::route_direct( elevators const* e, - gbfs::gbfs_data const* gbfs, + gbfs::gbfs_routing_data& gbfs_rd, api::Place const& from, api::Place const& to, std::vector const& modes, + std::optional> const& form_factors, + std::optional> const& + propulsion_types, + std::optional> const& rental_providers, n::unixtime_t const start_time, bool wheelchair, std::chrono::seconds max) const { if (!w_ || !l_) { return {}; } - auto const omit_walk = - gbfs != nullptr && - utl::find(modes, api::ModeEnum::BIKE_RENTAL) != end(modes); + auto const omit_walk = gbfs_rd.has_data() && + utl::find(modes, api::ModeEnum::RENTAL) != end(modes); auto fastest_direct = kInfinityDuration; auto cache = street_routing_cache_t{}; auto itineraries = std::vector{}; @@ -243,9 +272,9 @@ std::pair, n::duration_t> routing::route_direct( if (m == api::ModeEnum::CAR || m == api::ModeEnum::BIKE || m == api::ModeEnum::CAR_PARKING || (!omit_walk && m == api::ModeEnum::WALK)) { - auto itinerary = route( - *w_, *l_, gbfs, e, from, to, m, wheelchair, start_time, std::nullopt, - gbfs_provider_idx_t::invalid(), cache, *blocked, max); + auto itinerary = + route(*w_, *l_, gbfs_rd, e, from, to, m, wheelchair, start_time, + std::nullopt, {}, cache, *blocked, max); if (itinerary.legs_.empty()) { continue; } @@ -255,26 +284,38 @@ std::pair, n::duration_t> routing::route_direct( fastest_direct = duration; } itineraries.emplace_back(std::move(itinerary)); - } else if (m == api::ModeEnum::BIKE_RENTAL && gbfs != nullptr) { + } else if (m == api::ModeEnum::RENTAL && gbfs_rd.has_data()) { auto const max_dist = get_max_distance(osr::search_profile::kBikeSharing, max); auto providers = hash_set{}; - gbfs->provider_rtree_.in_radius( + gbfs_rd.data_->provider_rtree_.in_radius( {from.lat_, from.lon_}, max_dist, [&](auto const pi) { providers.insert(pi); }); for (auto const& pi : providers) { - auto itinerary = - route(*w_, *l_, gbfs, e, from, to, m, wheelchair, start_time, - std::nullopt, pi, cache, *blocked, max); - if (itinerary.legs_.empty()) { + auto const& provider = gbfs_rd.data_->providers_.at(pi); + if (provider == nullptr || + (rental_providers && utl::find(*rental_providers, provider->id_) == + end(*rental_providers))) { continue; } - auto const duration = std::chrono::duration_cast( - std::chrono::seconds{itinerary.duration_}); - if (duration < fastest_direct) { - fastest_direct = duration; + for (auto const& prod : provider->products_) { + if (!gbfs::products_match(prod, form_factors, propulsion_types)) { + continue; + } + auto itinerary = route( + *w_, *l_, gbfs_rd, e, from, to, m, wheelchair, start_time, + std::nullopt, gbfs::gbfs_products_ref{provider->idx_, prod.idx_}, + cache, *blocked, max); + if (itinerary.legs_.empty()) { + continue; + } + auto const duration = std::chrono::duration_cast( + std::chrono::seconds{itinerary.duration_}); + if (duration < fastest_direct) { + fastest_direct = duration; + } + itineraries.emplace_back(std::move(itinerary)); } - itineraries.emplace_back(std::move(itinerary)); } } } @@ -353,7 +394,7 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { auto const rt = rt_; auto const rtt = rt->rtt_.get(); auto const e = rt_->e_.get(); - auto const gbfs = gbfs_; + auto gbfs_rd = gbfs::gbfs_routing_data{w_, l_, gbfs_}; if (blocked.get() == nullptr && w_ != nullptr) { blocked.reset(new osr::bitvec{w_->n_nodes()}); } @@ -377,14 +418,36 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { query.arriveBy_ ? post_transit_modes : pre_transit_modes; auto const& dest_modes = query.arriveBy_ ? pre_transit_modes : post_transit_modes; + auto const& start_form_factors = query.arriveBy_ + ? query.postTransitRentalFormFactors_ + : query.preTransitRentalFormFactors_; + auto const& dest_form_factors = query.arriveBy_ + ? query.preTransitRentalFormFactors_ + : query.postTransitRentalFormFactors_; + auto const& start_propulsion_types = + query.arriveBy_ ? query.postTransitRentalPropulsionTypes_ + : query.preTransitRentalPropulsionTypes_; + auto const& dest_propulsion_types = + query.arriveBy_ ? query.postTransitRentalPropulsionTypes_ + : query.preTransitRentalPropulsionTypes_; + auto const& start_rental_providers = query.arriveBy_ + ? query.postTransitRentalProviders_ + : query.preTransitRentalProviders_; + auto const& dest_rental_providers = query.arriveBy_ + ? query.preTransitRentalProviders_ + : query.postTransitRentalProviders_; auto const [start_time, t] = get_start_time(query); UTL_START_TIMING(direct); auto const [direct, fastest_direct] = t.has_value() && !direct_modes.empty() && w_ && l_ - ? route_direct(e, gbfs.get(), from_p, to_p, direct_modes, *t, - query.wheelchair_, + ? route_direct(e, gbfs_rd, from_p, to_p, direct_modes, + query.directRentalFormFactors_, + query.directRentalPropulsionTypes_, + query.directRentalProviders_, *t, + query.pedestrianProfile_ == + api::PedestrianProfileEnum::WHEELCHAIR, std::chrono::seconds{query.maxDirectTime_}) : std::pair{std::vector{}, kInfinityDuration}; UTL_STOP_TIMING(direct); @@ -406,9 +469,12 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { auto const dir = query.arriveBy_ ? osr::direction::kBackward : osr::direction::kForward; return get_offsets( - pos, dir, start_modes, query.wheelchair_, + pos, dir, start_modes, start_form_factors, + start_propulsion_types, start_rental_providers, + query.pedestrianProfile_ == + api::PedestrianProfileEnum::WHEELCHAIR, std::chrono::seconds{query.maxPreTransitTime_}, - query.maxMatchingDistance_, gbfs.get()); + query.maxMatchingDistance_, gbfs_rd); }}, start), .destination_ = std::visit( @@ -418,9 +484,12 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { auto const dir = query.arriveBy_ ? osr::direction::kForward : osr::direction::kBackward; return get_offsets( - pos, dir, dest_modes, query.wheelchair_, + pos, dir, dest_modes, dest_form_factors, + dest_propulsion_types, dest_rental_providers, + query.pedestrianProfile_ == + api::PedestrianProfileEnum::WHEELCHAIR, std::chrono::seconds{query.maxPostTransitTime_}, - query.maxMatchingDistance_, gbfs.get()); + query.maxMatchingDistance_, gbfs_rd); }}, dest), .td_start_ = @@ -433,7 +502,9 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { ? osr::direction::kBackward : osr::direction::kForward; return get_td_offsets( - *e, pos, dir, start_modes, query.wheelchair_, + *e, pos, dir, start_modes, + query.pedestrianProfile_ == + api::PedestrianProfileEnum::WHEELCHAIR, std::chrono::seconds{query.maxPreTransitTime_}); }}, start) @@ -448,7 +519,9 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { ? osr::direction::kForward : osr::direction::kBackward; return get_td_offsets( - *e, pos, dir, dest_modes, query.wheelchair_, + *e, pos, dir, dest_modes, + query.pedestrianProfile_ == + api::PedestrianProfileEnum::WHEELCHAIR, std::chrono::seconds{ query.maxPostTransitTime_}); }}, @@ -457,10 +530,21 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { .max_transfers_ = static_cast( query.maxTransfers_.has_value() ? *query.maxTransfers_ : n::routing::kMaxTransfers), + .max_travel_time_ = query.maxTravelTime_ + .and_then([](std::int64_t const dur) { + return std::optional{n::duration_t{dur}}; + }) + .value_or(kInfinityDuration), .min_connection_count_ = static_cast(query.numItineraries_), .extend_interval_earlier_ = start_time.extend_interval_earlier_, .extend_interval_later_ = start_time.extend_interval_later_, - .prf_idx_ = static_cast(query.wheelchair_ ? 2U : 1U), + .prf_idx_ = static_cast( + query.useRoutedTransfers_ + ? (query.pedestrianProfile_ == + api::PedestrianProfileEnum::WHEELCHAIR + ? 2U + : 1U) + : 0U), .allowed_claszes_ = to_clasz_mask(query.transitModes_), .require_bike_transport_ = query.requireBikeTransport_, .transfer_time_settings_ = @@ -502,7 +586,9 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { auto const r = n::routing::raptor_search( *tt_, rtt, *search_state, *raptor_state, std::move(q), query.arriveBy_ ? n::direction::kBackward : n::direction::kForward, - std::nullopt); + query.timeout_.has_value() + ? std::optional{*query.timeout_} + : std::nullopt); return { .debugOutput_ = join(std::move(query_stats), r.search_stats_.to_map(), @@ -513,10 +599,11 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { .itineraries_ = utl::to_vec( *r.journeys_, [&, cache = street_routing_cache_t{}](auto&& j) mutable { - return journey_to_response(w_, l_, pl_, *tt_, *tags_, e, rtt, - matches_, shapes_, gbfs.get(), - query.wheelchair_, j, start, dest, - cache, *blocked); + return journey_to_response( + w_, l_, pl_, *tt_, *tags_, e, rtt, matches_, shapes_, gbfs_rd, + query.pedestrianProfile_ == + api::PedestrianProfileEnum::WHEELCHAIR, + j, start, dest, cache, *blocked, query.detailedTransfers_); }), .previousPageCursor_ = fmt::format("EARLIER|{}", to_seconds(r.interval_.from_)), diff --git a/src/endpoints/stop_times.cc b/src/endpoints/stop_times.cc index 366f6d46fd..138a08c30c 100644 --- a/src/endpoints/stop_times.cc +++ b/src/endpoints/stop_times.cc @@ -356,7 +356,7 @@ api::stoptimes_response stop_times::operator()( .routeColor_ = to_str(s.get_route_color(ev_type).color_), .routeTextColor_ = to_str(s.get_route_color(ev_type).text_color_), - .tripId_ = tags_.id(tt_, s), + .tripId_ = tags_.id(tt_, s, ev_type), .routeShortName_ = std::string{s.trip_display_name(ev_type)}, .source_ = fmt::format("{}", fmt::streamed(fr.dbg()))}; }), diff --git a/src/endpoints/trip.cc b/src/endpoints/trip.cc index a45d0d3883..77eeb974fa 100644 --- a/src/endpoints/trip.cc +++ b/src/endpoints/trip.cc @@ -8,6 +8,7 @@ #include "nigiri/timetable.h" #include "motis/data.h" +#include "motis/gbfs/routing_data.h" #include "motis/journey_to_response.h" #include "motis/parse_location.h" #include "motis/tag_lookup.h" @@ -34,9 +35,10 @@ api::Itinerary trip::operator()(boost::urls::url_view const& url) const { auto const dest_time = to_l.time(n::event_type::kArr); auto cache = street_routing_cache_t{}; auto blocked = osr::bitvec{}; + auto gbfs_rd = gbfs::gbfs_routing_data{}; return journey_to_response( - w_, l_, pl_, tt_, tags_, nullptr, rtt, matches_, shapes_, nullptr, false, + w_, l_, pl_, tt_, tags_, nullptr, rtt, matches_, shapes_, gbfs_rd, false, {.legs_ = {n::routing::journey::leg{ n::direction::kForward, from_l.get_location_idx(), to_l.get_location_idx(), start_time, dest_time, @@ -49,7 +51,7 @@ api::Itinerary trip::operator()(boost::urls::url_view const& url) const { .transfers_ = 0U}, tt_location{from_l.get_location_idx(), from_l.get_scheduled_location_idx()}, - tt_location{to_l.get_location_idx()}, cache, blocked); + tt_location{to_l.get_location_idx()}, cache, blocked, false); } } // namespace motis::ep diff --git a/src/gbfs/data.cc b/src/gbfs/data.cc new file mode 100644 index 0000000000..808dc984f7 --- /dev/null +++ b/src/gbfs/data.cc @@ -0,0 +1,40 @@ +#include "motis/gbfs/data.h" + +#include "osr/lookup.h" +#include "osr/ways.h" + +#include "motis/gbfs/compression.h" +#include "motis/gbfs/routing_data.h" + +namespace motis::gbfs { + +products_routing_data::products_routing_data( + std::shared_ptr&& prd, + compressed_routing_data const& compressed) + : provider_routing_data_{std::move(prd)}, compressed_{compressed} { + decompress_bitvec(compressed_.start_allowed_, start_allowed_); + decompress_bitvec(compressed_.end_allowed_, end_allowed_); + decompress_bitvec(compressed_.through_allowed_, through_allowed_); +} + +std::shared_ptr gbfs_data::get_products_routing_data( + osr::ways const& w, + osr::lookup const& l, + gbfs_products_ref const prod_ref) { + auto lock = std::unique_lock{products_routing_data_mutex_}; + + if (auto it = products_routing_data_.find(prod_ref); + it != end(products_routing_data_)) { + if (auto prod_rd = it->second.lock(); prod_rd) { + return prod_rd; + } + } + + auto provider_rd = get_provider_routing_data( + w, l, *this, *providers_.at(prod_ref.provider_)); + auto prod_rd = provider_rd->get_products_routing_data(prod_ref.products_); + products_routing_data_[prod_ref] = prod_rd; + return prod_rd; +} + +} // namespace motis::gbfs diff --git a/src/gbfs/geofencing.cc b/src/gbfs/geofencing.cc index e53f7fee89..880e1ac2c9 100644 --- a/src/gbfs/geofencing.cc +++ b/src/gbfs/geofencing.cc @@ -1,9 +1,20 @@ #include "motis/gbfs/data.h" +#include "utl/helpers/algorithm.h" + #include "tg.h" namespace motis::gbfs { +bool applies(std::vector const& rule_vehicle_type_idxs, + std::vector const& segment_vehicle_type_idxs) { + return rule_vehicle_type_idxs.empty() || + utl::all_of(segment_vehicle_type_idxs, [&](auto const& idx) { + return utl::find(rule_vehicle_type_idxs, idx) != + end(rule_vehicle_type_idxs); + }); +} + bool multipoly_contains_point(tg_geom const* geom, geo::latlng const& pos) { auto const n_polys = tg_geom_num_polys(geom); for (auto i = 0; i < n_polys; ++i) { @@ -18,12 +29,18 @@ bool multipoly_contains_point(tg_geom const* geom, geo::latlng const& pos) { geofencing_restrictions geofencing_zones::get_restrictions( geo::latlng const& pos, - geofencing_restrictions const& default_restrictions) { + vehicle_type_idx_t const vehicle_type_idx, + geofencing_restrictions const& default_restrictions) const { + auto const check_vehicle_type = + vehicle_type_idx != vehicle_type_idx_t::invalid(); for (auto const& z : zones_) { if (multipoly_contains_point(z.geom_.get(), pos)) { - // vehicle_type_ids currently ignored, using first rule - if (!z.rules_.empty()) { - auto const& r = z.rules_.front(); + for (auto const& r : z.rules_) { + if (check_vehicle_type && !r.vehicle_type_idxs_.empty() && + utl::find(r.vehicle_type_idxs_, vehicle_type_idx) == + end(r.vehicle_type_idxs_)) { + continue; + } return geofencing_restrictions{ .ride_start_allowed_ = r.ride_start_allowed_, .ride_end_allowed_ = r.ride_end_allowed_, diff --git a/src/gbfs/mode.cc b/src/gbfs/mode.cc new file mode 100644 index 0000000000..e4533f91be --- /dev/null +++ b/src/gbfs/mode.cc @@ -0,0 +1,118 @@ +#include "motis/gbfs/mode.h" + +#include + +#include "utl/helpers/algorithm.h" +#include "utl/verify.h" + +#include "motis/constants.h" + +namespace motis::gbfs { + +api::RentalFormFactorEnum to_api_form_factor(vehicle_form_factor const ff) { + switch (ff) { + case vehicle_form_factor::kBicycle: + return api::RentalFormFactorEnum::BICYCLE; + case vehicle_form_factor::kCargoBicycle: + return api::RentalFormFactorEnum::CARGO_BICYCLE; + case vehicle_form_factor::kCar: return api::RentalFormFactorEnum::CAR; + case vehicle_form_factor::kMoped: return api::RentalFormFactorEnum::MOPED; + case vehicle_form_factor::kScooterStanding: + return api::RentalFormFactorEnum::SCOOTER_STANDING; + case vehicle_form_factor::kScooterSeated: + return api::RentalFormFactorEnum::SCOOTER_STANDING; + case vehicle_form_factor::kOther: return api::RentalFormFactorEnum::OTHER; + } + std::unreachable(); +} + +vehicle_form_factor from_api_form_factor(api::RentalFormFactorEnum const ff) { + switch (ff) { + case api::RentalFormFactorEnum::BICYCLE: + return vehicle_form_factor::kBicycle; + case api::RentalFormFactorEnum::CARGO_BICYCLE: + return vehicle_form_factor::kCargoBicycle; + case api::RentalFormFactorEnum::CAR: return vehicle_form_factor::kCar; + case api::RentalFormFactorEnum::MOPED: return vehicle_form_factor::kMoped; + case api::RentalFormFactorEnum::SCOOTER_STANDING: + return vehicle_form_factor::kScooterStanding; + case api::RentalFormFactorEnum::SCOOTER_SEATED: + return vehicle_form_factor::kScooterSeated; + case api::RentalFormFactorEnum::OTHER: return vehicle_form_factor::kOther; + } + throw utl::fail("invalid rental form factor"); +} + +api::RentalPropulsionTypeEnum to_api_propulsion_type(propulsion_type const pt) { + switch (pt) { + case propulsion_type::kHuman: return api::RentalPropulsionTypeEnum::HUMAN; + case propulsion_type::kElectricAssist: + return api::RentalPropulsionTypeEnum::ELECTRIC_ASSIST; + case propulsion_type::kElectric: + return api::RentalPropulsionTypeEnum::ELECTRIC; + case propulsion_type::kCombustion: + return api::RentalPropulsionTypeEnum::COMBUSTION; + case propulsion_type::kCombustionDiesel: + return api::RentalPropulsionTypeEnum::COMBUSTION_DIESEL; + case propulsion_type::kHybrid: return api::RentalPropulsionTypeEnum::HYBRID; + case propulsion_type::kPlugInHybrid: + return api::RentalPropulsionTypeEnum::PLUG_IN_HYBRID; + case propulsion_type::kHydrogenFuelCell: + return api::RentalPropulsionTypeEnum::HYDROGEN_FUEL_CELL; + } + std::unreachable(); +} + +propulsion_type from_api_propulsion_type( + api::RentalPropulsionTypeEnum const pt) { + switch (pt) { + case api::RentalPropulsionTypeEnum::HUMAN: return propulsion_type::kHuman; + case api::RentalPropulsionTypeEnum::ELECTRIC_ASSIST: + return propulsion_type::kElectricAssist; + case api::RentalPropulsionTypeEnum::ELECTRIC: + return propulsion_type::kElectric; + case api::RentalPropulsionTypeEnum::COMBUSTION: + return propulsion_type::kCombustion; + case api::RentalPropulsionTypeEnum::COMBUSTION_DIESEL: + return propulsion_type::kCombustionDiesel; + case api::RentalPropulsionTypeEnum::HYBRID: return propulsion_type::kHybrid; + case api::RentalPropulsionTypeEnum::PLUG_IN_HYBRID: + return propulsion_type::kPlugInHybrid; + case api::RentalPropulsionTypeEnum::HYDROGEN_FUEL_CELL: + return propulsion_type::kHydrogenFuelCell; + } + throw utl::fail("invalid rental propulsion type"); +} + +api::RentalReturnConstraintEnum to_api_return_constraint( + return_constraint const rc) { + switch (rc) { + case return_constraint::kNone: return api::RentalReturnConstraintEnum::NONE; + case return_constraint::kAnyStation: + return api::RentalReturnConstraintEnum::ANY_STATION; + case return_constraint::kRoundtripStation: + return api::RentalReturnConstraintEnum::ROUNDTRIP_STATION; + } + std::unreachable(); +} + +bool products_match( + provider_products const& prod, + std::optional> const& form_factors, + std::optional> const& + propulsion_types) { + if (form_factors.has_value() && + utl::find(*form_factors, to_api_form_factor(prod.form_factor_)) == + end(*form_factors)) { + return false; + } + if (propulsion_types.has_value() && + utl::find(*propulsion_types, + to_api_propulsion_type(prod.propulsion_type_)) == + end(*propulsion_types)) { + return false; + } + return true; +} + +} // namespace motis::gbfs diff --git a/src/gbfs/osr_mapping.cc b/src/gbfs/osr_mapping.cc index 922d3e93ba..7b90f10da4 100644 --- a/src/gbfs/osr_mapping.cc +++ b/src/gbfs/osr_mapping.cc @@ -15,228 +15,316 @@ #include "utl/enumerate.h" #include "utl/helpers/algorithm.h" +#include "utl/to_vec.h" +#include "utl/zip.h" #include "motis/constants.h" #include "motis/types.h" +#include "motis/box_rtree.h" +#include "motis/gbfs/compression.h" #include "motis/gbfs/data.h" #include "motis/gbfs/geofencing.h" namespace motis::gbfs { -void map_geofencing_zones(osr::ways const& w, - osr::lookup const& l, - gbfs_provider& provider) { - auto const make_loc_bitvec = [&]() { - auto bv = osr::bitvec{}; - bv.resize(static_cast::size_type>( - w.n_nodes() + provider.stations_.size() + - provider.vehicle_status_.size())); - return bv; - }; - - auto done = make_loc_bitvec(); - provider.start_allowed_ = make_loc_bitvec(); - provider.end_allowed_ = make_loc_bitvec(); - provider.through_allowed_ = make_loc_bitvec(); - - // global rules - if (!provider.geofencing_zones_.global_rules_.empty()) { - // vehicle_type_ids currently ignored, using first rule - auto const& r = provider.geofencing_zones_.global_rules_.front(); - provider.default_restrictions_.ride_start_allowed_ = r.ride_start_allowed_; - provider.default_restrictions_.ride_end_allowed_ = r.ride_end_allowed_; - provider.default_restrictions_.ride_through_allowed_ = - r.ride_through_allowed_; - provider.default_restrictions_.station_parking_ = r.station_parking_; +struct osr_mapping { + osr_mapping(osr::ways const& w, + osr::lookup const& l, + gbfs_provider const& provider) + : w_{w}, l_{l}, provider_{provider} { + products_data_.resize(provider.products_.size()); } - if (provider.default_restrictions_.ride_end_allowed_ && - !provider.default_restrictions_.station_parking_) { - provider.end_allowed_.one_out(); - } - if (provider.default_restrictions_.ride_through_allowed_) { - provider.through_allowed_.one_out(); - } - auto const global_station_parking = - provider.default_restrictions_.station_parking_.value_or(false); - - auto const handle_point = [&](osr::node_idx_t const n, - geo::latlng const& pos) { - auto start_allowed = std::optional{}; - auto end_allowed = std::optional{}; - auto through_allowed = std::optional{}; - auto station_parking = global_station_parking; - for (auto const& z : provider.geofencing_zones_.zones_) { - // check if pos is inside the zone multipolygon - if (multipoly_contains_point(z.geom_.get(), pos)) { - // vehicle_type_ids currently ignored, using first rule - if (!z.rules_.empty()) { - auto const& r = z.rules_.front(); - start_allowed = r.ride_start_allowed_; - end_allowed = r.ride_end_allowed_; - through_allowed = r.ride_through_allowed_; - if (r.station_parking_.has_value()) { - station_parking = r.station_parking_.value(); + void map_geofencing_zones() { + auto const make_loc_bitvec = [&]() { + auto bv = osr::bitvec{}; + bv.resize(static_cast::size_type>( + w_.n_nodes() + provider_.stations_.size() + + provider_.vehicle_status_.size())); + return bv; + }; + + auto zone_rtree = box_rtree{}; + for (auto const [i, z] : + utl::enumerate(provider_.geofencing_zones_.zones_)) { + zone_rtree.add(z.bounding_box(), i); + } + + for (auto [prod, rd] : utl::zip(provider_.products_, products_data_)) { + auto default_restrictions = provider_.default_restrictions_; + rd.start_allowed_ = make_loc_bitvec(); + rd.end_allowed_ = make_loc_bitvec(); + rd.through_allowed_ = make_loc_bitvec(); + + // global rules + for (auto const& r : provider_.geofencing_zones_.global_rules_) { + if (!applies(r.vehicle_type_idxs_, prod.vehicle_types_)) { + continue; + } + default_restrictions.ride_start_allowed_ = r.ride_start_allowed_; + default_restrictions.ride_end_allowed_ = r.ride_end_allowed_; + default_restrictions.ride_through_allowed_ = r.ride_through_allowed_; + default_restrictions.station_parking_ = r.station_parking_; + break; + } + + if (prod.return_constraint_ == return_constraint::kAnyStation) { + default_restrictions.station_parking_ = true; + } + + if (default_restrictions.ride_end_allowed_ && + !default_restrictions.station_parking_) { + rd.end_allowed_.one_out(); + } + if (default_restrictions.ride_through_allowed_) { + rd.through_allowed_.one_out(); + } + + rd.station_parking_ = + default_restrictions.station_parking_.value_or(false); + } + + auto done = make_loc_bitvec(); + + auto zone_indices = std::vector{}; + zone_indices.reserve(provider_.geofencing_zones_.zones_.size()); + auto const handle_point = [&](osr::node_idx_t const n, + geo::latlng const& pos) { + for (auto [prod, rd] : utl::zip(provider_.products_, products_data_)) { + auto start_allowed = std::optional{}; + auto end_allowed = std::optional{}; + auto through_allowed = std::optional{}; + auto station_parking = rd.station_parking_; + + // zones have to be checked in the order they are defined + zone_indices.clear(); + zone_rtree.find(pos, [&](std::size_t const zone_idx) { + zone_indices.push_back(zone_idx); + }); + utl::sort(zone_indices); + + for (auto const zone_idx : zone_indices) { + auto const& z = provider_.geofencing_zones_.zones_[zone_idx]; + // check if pos is inside the zone multipolygon + if (multipoly_contains_point(z.geom_.get(), pos)) { + for (auto const& r : z.rules_) { + if (!applies(r.vehicle_type_idxs_, prod.vehicle_types_)) { + continue; + } + start_allowed = r.ride_start_allowed_; + end_allowed = r.ride_end_allowed_; + through_allowed = r.ride_through_allowed_; + if (r.station_parking_.has_value()) { + station_parking = r.station_parking_.value(); + } + break; + } + if (start_allowed.has_value()) { + break; // for now + } } } - if (start_allowed.has_value()) { - break; // for now + if (end_allowed.has_value() && !station_parking) { + rd.end_allowed_.set(n, *end_allowed); + } + if (through_allowed.has_value()) { + rd.through_allowed_.set(n, *through_allowed); } } + }; + + auto const* osr_r = w_.r_.get(); + for (auto const& z : provider_.geofencing_zones_.zones_) { + l_.find(z.bounding_box(), [&](osr::way_idx_t const way) { + for (auto const n : osr_r->way_nodes_[way]) { + if (done.test(n)) { + continue; + } + done.set(n, true); + handle_point(n, w_.get_node_pos(n).as_latlng()); + } + }); } - if (end_allowed.has_value() && !station_parking) { - provider.end_allowed_.set(n, *end_allowed); - } - if (through_allowed.has_value()) { - provider.through_allowed_.set(n, *through_allowed); - } - }; + } + + void map_stations() { + for (auto [prod_b, rd_b] : utl::zip(provider_.products_, products_data_)) { + auto& prod = prod_b; // fix for apple clang + auto& rd = rd_b; + auto next_node_id = static_cast( + w_.n_nodes() + rd.additional_nodes_.size()); + for (auto const& [id, st] : provider_.stations_) { + auto is_renting = + st.status_.is_renting_ && st.status_.num_vehicles_available_ > 0; + auto is_returning = st.status_.is_returning_; - auto const* osr_r = w.r_.get(); - for (auto const& z : provider.geofencing_zones_.zones_) { - auto const rect = tg_geom_rect(z.geom_.get()); - auto const bb = geo::box{geo::latlng{rect.min.y, rect.min.x}, - geo::latlng{rect.max.y, rect.max.x}}; + // if the station lists vehicles available by type, at least one of + // the vehicle types included in the product segment must be available + if (is_renting && !st.status_.vehicle_types_available_.empty()) { + is_renting = utl::any_of( + st.status_.vehicle_types_available_, [&](auto const& vt) { + return vt.second != 0 && prod.includes_vehicle_type(vt.first); + }); + } + + // same for returning vehicles + if (is_returning && !st.status_.vehicle_docks_available_.empty()) { + is_returning = utl::any_of( + st.status_.vehicle_docks_available_, [&](auto const& vt) { + return vt.second != 0 && prod.includes_vehicle_type(vt.first); + }); + } - l.find(bb, [&](osr::way_idx_t const way) { - for (auto const n : osr_r->way_nodes_[way]) { - if (done.test(n)) { + if (!is_renting && !is_returning) { continue; } - done.set(n, true); - handle_point(n, w.get_node_pos(n).as_latlng()); - } - }); - } -} -void map_stations(osr::ways const& w, - osr::lookup const& l, - gbfs_provider& provider) { - auto next_node_id = static_cast( - w.n_nodes() + provider.additional_nodes_.size()); - for (auto const& [id, st] : provider.stations_) { - auto const is_renting = - st.status_.is_renting_ && st.status_.num_vehicles_available_ > 0; - auto const is_returning = st.status_.is_returning_; - - if (!is_renting && !is_returning) { - continue; - } + auto const matches = l_.match>( + osr::location{st.info_.pos_, osr::level_t{}}, false, + osr::direction::kForward, kMaxMatchingDistance, nullptr); + if (matches.empty()) { + continue; + } - auto const matches = l.match>( - osr::location{st.info_.pos_, osr::level_t{}}, false, - osr::direction::kForward, kMaxMatchingDistance, nullptr); - if (matches.empty()) { - continue; - } + auto const additional_node_id = next_node_id++; + rd.additional_nodes_.emplace_back( + additional_node{additional_node::station{id}}); + if (is_renting) { + rd.start_allowed_.set(additional_node_id, true); + } + if (is_returning) { + rd.end_allowed_.set(additional_node_id, true); + if (st.info_.station_area_) { + auto const* geom = st.info_.station_area_.get(); + auto const rect = tg_geom_rect(geom); + auto const bb = geo::box{geo::latlng{rect.min.y, rect.min.x}, + geo::latlng{rect.max.y, rect.max.x}}; + auto const* osr_r = w_.r_.get(); + l_.find(bb, [&](osr::way_idx_t const way) { + for (auto const n : osr_r->way_nodes_[way]) { + if (multipoly_contains_point(geom, + w_.get_node_pos(n).as_latlng())) { + rd.end_allowed_.set(n, true); + } + } + }); + } + } - auto const additional_node_id = next_node_id++; - provider.additional_nodes_.emplace_back( - additional_node{additional_node::station{id}}); - if (is_renting) { - provider.start_allowed_.set(additional_node_id, true); - } - if (is_returning) { - provider.end_allowed_.set(additional_node_id, true); - if (st.info_.station_area_) { - auto const* geom = st.info_.station_area_.get(); - auto const rect = tg_geom_rect(geom); - auto const bb = geo::box{geo::latlng{rect.min.y, rect.min.x}, - geo::latlng{rect.max.y, rect.max.x}}; - auto const* osr_r = w.r_.get(); - l.find(bb, [&](osr::way_idx_t const way) { - for (auto const n : osr_r->way_nodes_[way]) { - if (multipoly_contains_point(geom, w.get_node_pos(n).as_latlng())) { - provider.end_allowed_.set(n, true); + for (auto const& m : matches) { + auto const handle_node = [&](osr::node_candidate const node) { + if (node.valid() && node.dist_to_node_ <= kMaxMatchingDistance) { + auto const edge_to_an = osr::additional_edge{ + additional_node_id, + static_cast(node.dist_to_node_)}; + auto& node_edges = rd.additional_edges_[node.node_]; + if (utl::find(node_edges, edge_to_an) == end(node_edges)) { + node_edges.emplace_back(edge_to_an); + } + + auto const edge_from_an = osr::additional_edge{ + node.node_, static_cast(node.dist_to_node_)}; + auto& an_edges = rd.additional_edges_[additional_node_id]; + if (utl::find(an_edges, edge_from_an) == end(an_edges)) { + an_edges.emplace_back(edge_from_an); + } } - } - }); + }; + + handle_node(m.left_); + handle_node(m.right_); + } } } + } + + void map_vehicles() { + for (auto [prod, rd] : utl::zip(provider_.products_, products_data_)) { + auto next_node_id = static_cast( + w_.n_nodes() + rd.additional_nodes_.size()); + for (auto const [vehicle_idx, vs] : + utl::enumerate(provider_.vehicle_status_)) { + if (vs.is_disabled_ || vs.is_reserved_ || !vs.station_id_.empty() || + (!vs.home_station_id_.empty() && + prod.return_constraint_ != return_constraint::kRoundtripStation) || + !prod.includes_vehicle_type(vs.vehicle_type_idx_)) { + continue; + } + + auto const restrictions = provider_.geofencing_zones_.get_restrictions( + vs.pos_, vs.vehicle_type_idx_, geofencing_restrictions{}); + if (!restrictions.ride_start_allowed_) { + continue; + } + + auto const matches = l_.match>( + osr::location{vs.pos_, osr::level_t{}}, false, + osr::direction::kForward, kMaxMatchingDistance, nullptr); + if (matches.empty()) { + continue; + } + + auto const additional_node_id = next_node_id++; + rd.additional_nodes_.emplace_back( + additional_node{additional_node::vehicle{vehicle_idx}}); + rd.start_allowed_.set(additional_node_id, true); - for (auto const& m : matches) { - auto const handle_node = [&](osr::node_candidate const node) { - if (node.valid() && node.dist_to_node_ <= kMaxMatchingDistance) { + auto const& add_additional_edges = [&](osr::node_candidate const& nc) { auto const edge_to_an = osr::additional_edge{ additional_node_id, - static_cast(node.dist_to_node_)}; - auto& node_edges = provider.additional_edges_[node.node_]; + static_cast(nc.dist_to_node_)}; + auto& node_edges = rd.additional_edges_[nc.node_]; if (utl::find(node_edges, edge_to_an) == end(node_edges)) { node_edges.emplace_back(edge_to_an); } auto const edge_from_an = osr::additional_edge{ - node.node_, static_cast(node.dist_to_node_)}; - auto& an_edges = provider.additional_edges_[additional_node_id]; + nc.node_, static_cast(nc.dist_to_node_)}; + auto& an_edges = rd.additional_edges_[additional_node_id]; if (utl::find(an_edges, edge_from_an) == end(an_edges)) { an_edges.emplace_back(edge_from_an); } - } - }; + }; - handle_node(m.left_); - handle_node(m.right_); + for (auto const& m : matches) { + if (m.left_.valid() && + m.left_.dist_to_node_ <= kMaxMatchingDistance) { + add_additional_edges(m.left_); + } + if (m.right_.valid() && + m.right_.dist_to_node_ <= kMaxMatchingDistance) { + add_additional_edges(m.right_); + } + } + } } } -} - -void map_vehicles(osr::ways const& w, - osr::lookup const& l, - gbfs_provider& provider) { - auto next_node_id = static_cast( - w.n_nodes() + provider.additional_nodes_.size()); - for (auto const [vehicle_idx, vs] : - utl::enumerate(provider.vehicle_status_)) { - if (vs.is_disabled_ || vs.is_reserved_ || !vs.station_id_.empty() || - !vs.home_station_id_.empty()) { - continue; - } - auto const restrictions = provider.geofencing_zones_.get_restrictions( - vs.pos_, geofencing_restrictions{}); - if (!restrictions.ride_start_allowed_) { - continue; - } + osr::ways const& w_; + osr::lookup const& l_; + gbfs_provider const& provider_; - auto const matches = l.match>( - osr::location{vs.pos_, osr::level_t{}}, false, osr::direction::kForward, - kMaxMatchingDistance, nullptr); - if (matches.empty()) { - continue; - } + std::vector products_data_; +}; - auto const additional_node_id = next_node_id++; - provider.additional_nodes_.emplace_back( - additional_node{additional_node::vehicle{vehicle_idx}}); - provider.start_allowed_.set(additional_node_id, true); - - auto const& add_additional_edges = [&](osr::node_candidate const& nc) { - auto const edge_to_an = osr::additional_edge{ - additional_node_id, static_cast(nc.dist_to_node_)}; - auto& node_edges = provider.additional_edges_[nc.node_]; - if (utl::find(node_edges, edge_to_an) == end(node_edges)) { - node_edges.emplace_back(edge_to_an); - } - - auto const edge_from_an = osr::additional_edge{ - nc.node_, static_cast(nc.dist_to_node_)}; - auto& an_edges = provider.additional_edges_[additional_node_id]; - if (utl::find(an_edges, edge_from_an) == end(an_edges)) { - an_edges.emplace_back(edge_from_an); - } - }; +void map_data(osr::ways const& w, + osr::lookup const& l, + gbfs_provider const& provider, + provider_routing_data& prd) { + auto mapping = osr_mapping{w, l, provider}; + mapping.map_geofencing_zones(); + mapping.map_stations(); + mapping.map_vehicles(); - for (auto const& m : matches) { - if (m.left_.valid() && m.left_.dist_to_node_ <= kMaxMatchingDistance) { - add_additional_edges(m.left_); - } - if (m.right_.valid() && m.right_.dist_to_node_ <= kMaxMatchingDistance) { - add_additional_edges(m.right_); - } - } - } + prd.products_ = utl::to_vec(mapping.products_data_, [&](auto& rd) { + return compressed_routing_data{ + .additional_nodes_ = std::move(rd.additional_nodes_), + .additional_edges_ = std::move(rd.additional_edges_), + .start_allowed_ = compress_bitvec(rd.start_allowed_), + .end_allowed_ = compress_bitvec(rd.end_allowed_), + .through_allowed_ = compress_bitvec(rd.through_allowed_)}; + }); } } // namespace motis::gbfs diff --git a/src/gbfs/parser.cc b/src/gbfs/parser.cc index 504b52c255..012ce4b370 100644 --- a/src/gbfs/parser.cc +++ b/src/gbfs/parser.cc @@ -5,6 +5,7 @@ #include "cista/hash.h" +#include "utl/helpers/algorithm.h" #include "utl/raii.h" #include "utl/to_vec.h" @@ -193,8 +194,8 @@ void load_station_information(gbfs_provider& provider, .name_ = name, .pos_ = geo::latlng{lat, lon}, .rental_uris_ = parse_rental_uris(station_obj), - .station_area_ = - std::unique_ptr(area)}}; + .station_area_ = std::shared_ptr( + area, tg_geom_deleter{})}}; } } @@ -211,8 +212,6 @@ void load_station_status(gbfs_provider& provider, json::value const& root) { auto const station_it = provider.stations_.find(station_id); if (station_it == end(provider.stations_)) { - std::cerr << "[GBFS] (" << provider.id_ << "): station_id=\"" - << station_id << "\" referenced in station_status not found\n"; continue; } @@ -222,26 +221,53 @@ void load_station_status(gbfs_provider& provider, json::value const& root) { station_obj.at(num_vehicles_available_key).to_number(), .is_renting_ = get_bool(version, station_obj, "is_renting"), .is_returning_ = get_bool(version, station_obj, "is_returning")}; + if (station_obj.contains("vehicle_types_available")) { auto const& vta = station_obj.at("vehicle_types_available").as_array(); auto unrestricted_available = 0U; auto any_station_available = 0U; + auto roundtrip_available = 0U; for (auto const& vt : vta) { auto const vehicle_type_id = static_cast(vt.at("vehicle_type_id").as_string()); auto const count = vt.at("count").to_number(); - station.status_.vehicle_types_available_[vehicle_type_id] = count; - if (auto const it = provider.vehicle_types_.find(vehicle_type_id); - it != end(provider.vehicle_types_)) { - switch (it->second.return_constraint_) { + if (auto const vt_it = + provider.vehicle_types_map_.find(vehicle_type_id); + vt_it != end(provider.vehicle_types_map_)) { + auto const vehicle_type_idx = vt_it->second; + station.status_.vehicle_types_available_[vehicle_type_idx] = count; + switch ( + provider.vehicle_types_[vehicle_type_idx].return_constraint_) { case return_constraint::kNone: ++unrestricted_available; break; case return_constraint::kAnyStation: ++any_station_available; break; - case return_constraint::kRoundtripStation: break; + case return_constraint::kRoundtripStation: + ++roundtrip_available; + break; } } } station.status_.num_vehicles_available_ = - unrestricted_available + any_station_available; + unrestricted_available + any_station_available + roundtrip_available; + } + + if (station_obj.contains("vehicle_docks_available")) { + for (auto const& vt : + station_obj.at("vehicle_docks_available").as_array()) { + auto& vto = vt.as_object(); + if (vto.contains("vehicle_type_ids") && vto.contains("count")) { + for (auto const& vti : vto.at("vehicle_type_ids").as_array()) { + auto const vehicle_type_id = + static_cast(vti.as_string()); + if (auto const vt_it = + provider.vehicle_types_map_.find(vehicle_type_id); + vt_it != end(provider.vehicle_types_map_)) { + auto const vehicle_type_idx = vt_it->second; + station.status_.vehicle_docks_available_[vehicle_type_idx] = + vto.at("count").to_number(); + } + } + } + } } } } @@ -253,6 +279,7 @@ vehicle_form_factor parse_form_factor(std::string_view const s) { return vehicle_form_factor::kCargoBicycle; case cista::hash("car"): return vehicle_form_factor::kCar; case cista::hash("moped"): return vehicle_form_factor::kMoped; + case cista::hash("scooter"): // < 3.0 case cista::hash("scooter_standing"): return vehicle_form_factor::kScooterStanding; case cista::hash("scooter_seated"): @@ -262,6 +289,23 @@ vehicle_form_factor parse_form_factor(std::string_view const s) { } } +propulsion_type parse_propulsion_type(std::string_view const s) { + switch (cista::hash(s)) { + case cista::hash("human"): return propulsion_type::kHuman; + case cista::hash("electric_assist"): + return propulsion_type::kElectricAssist; + case cista::hash("electric"): return propulsion_type::kElectric; + case cista::hash("combustion"): return propulsion_type::kCombustion; + case cista::hash("combustion_diesel"): + return propulsion_type::kCombustionDiesel; + case cista::hash("hybrid"): return propulsion_type::kHybrid; + case cista::hash("plug_in_hybrid"): return propulsion_type::kPlugInHybrid; + case cista::hash("hydrogen_fuel_cell"): + return propulsion_type::kHydrogenFuelCell; + default: return propulsion_type::kHuman; + } +} + return_constraint parse_return_constraint(json::object const& vt) { if (vt.contains("return_constraint")) { switch (cista::hash(static_cast( @@ -279,14 +323,20 @@ return_constraint parse_return_constraint(json::object const& vt) { void load_vehicle_types(gbfs_provider& provider, json::value const& root) { provider.vehicle_types_.clear(); + provider.vehicle_types_map_.clear(); for (auto const& v : root.at("data").at("vehicle_types").as_array()) { auto const id = static_cast(v.at("vehicle_type_id").as_string()); - provider.vehicle_types_[id] = vehicle_type{ + auto const idx = vehicle_type_idx_t{provider.vehicle_types_.size()}; + provider.vehicle_types_.emplace_back(vehicle_type{ .id_ = id, + .idx_ = idx, .form_factor_ = parse_form_factor( static_cast(v.at("form_factor").as_string())), - .return_constraint_ = parse_return_constraint(v.as_object())}; + .propulsion_type_ = parse_propulsion_type( + static_cast(v.at("propulsion_type").as_string())), + .return_constraint_ = parse_return_constraint(v.as_object())}); + provider.vehicle_types_map_[id] = idx; } } @@ -312,12 +362,11 @@ void load_vehicle_status(gbfs_provider& provider, json::value const& root) { .as_string()); auto const type_id = optional_str(vehicle_obj, "vehicle_type_id"); + auto type_idx = vehicle_type_idx_t::invalid(); - if (auto const it = provider.vehicle_types_.find(type_id); - it != end(provider.vehicle_types_) && - it->second.return_constraint_ == return_constraint::kRoundtripStation) { - // roundtrip vehicles currently not supported - continue; + if (auto const it = provider.vehicle_types_map_.find(type_id); + it != end(provider.vehicle_types_map_)) { + type_idx = it->second; } provider.vehicle_status_.emplace_back(vehicle_status{ @@ -326,25 +375,35 @@ void load_vehicle_status(gbfs_provider& provider, json::value const& root) { vehicle_obj.at("lon").as_double()}, .is_reserved_ = get_bool(version, vehicle_obj, "is_reserved"), .is_disabled_ = get_bool(version, vehicle_obj, "is_disabled"), - .vehicle_type_id_ = type_id, + .vehicle_type_idx_ = type_idx, .station_id_ = optional_str(vehicle_obj, "station_id"), .home_station_id_ = optional_str(vehicle_obj, "home_station_id"), .rental_uris_ = parse_rental_uris(vehicle_obj)}); } + + utl::sort(provider.vehicle_status_); } -rule parse_rule(gbfs_version const version, json::value const& r) { +rule parse_rule(gbfs_provider& provider, + gbfs_version const version, + json::value const& r) { auto const vti_key = version == gbfs_version::k2 ? "vehicle_type_id" : "vehicle_type_ids"; auto const& rule_obj = r.as_object(); + + auto vehicle_type_idxs = std::vector{}; + if (rule_obj.contains(vti_key)) { + for (auto const& vt : rule_obj.at(vti_key).as_array()) { + if (auto const it = provider.vehicle_types_map_.find( + static_cast(vt.as_string())); + it != end(provider.vehicle_types_map_)) { + vehicle_type_idxs.emplace_back(it->second); + } + } + } + return rule{ - .vehicle_type_ids_ = - rule_obj.contains(vti_key) - ? utl::to_vec(rule_obj.at(vti_key).as_array(), - [](auto const& vt) { - return static_cast(vt.as_string()); - }) - : std::vector{}, + .vehicle_type_idxs_ = std::move(vehicle_type_idxs), .ride_start_allowed_ = version == gbfs_version::k2 ? rule_obj.at("ride_allowed").as_bool() : rule_obj.at("ride_start_allowed").as_bool(), @@ -368,9 +427,9 @@ void load_geofencing_zones(gbfs_provider& provider, json::value const& root) { auto zones = utl::to_vec(zones_obj.at("features").as_array(), [&](auto const& z) { auto const& props = z.at("properties").as_object(); - auto rules = - utl::to_vec(props.at("rules").as_array(), - [&](auto const& r) { return parse_rule(version, r); }); + auto rules = utl::to_vec( + props.at("rules").as_array(), + [&](auto const& r) { return parse_rule(provider, version, r); }); auto* geom = parse_multipolygon(z.at("geometry").as_object()); @@ -384,8 +443,9 @@ void load_geofencing_zones(gbfs_provider& provider, json::value const& root) { // required in 3.0, but some feeds don't have it auto global_rules = root.at("data").as_object().contains("global_rules") - ? utl::to_vec(root.at("data").at("global_rules").as_array(), - [&](auto const& r) { return parse_rule(version, r); }) + ? utl::to_vec( + root.at("data").at("global_rules").as_array(), + [&](auto const& r) { return parse_rule(provider, version, r); }) : std::vector{}; provider.geofencing_zones_.version_ = version; diff --git a/src/gbfs/routing_data.cc b/src/gbfs/routing_data.cc new file mode 100644 index 0000000000..6dedfcf78f --- /dev/null +++ b/src/gbfs/routing_data.cc @@ -0,0 +1,81 @@ +#include "motis/gbfs/routing_data.h" + +#include "osr/lookup.h" +#include "osr/types.h" +#include "osr/ways.h" + +#include "fmt/format.h" + +#include "utl/timer.h" + +#include "motis/constants.h" +#include "motis/gbfs/data.h" +#include "motis/gbfs/osr_mapping.h" + +namespace motis::gbfs { + +std::shared_ptr compute_provider_routing_data( + osr::ways const& w, osr::lookup const& l, gbfs_provider const& provider) { + auto timer = utl::scoped_timer{ + fmt::format("compute routing data for gbfs provider {}", provider.id_)}; + auto prd = std::make_shared(); + + map_data(w, l, provider, *prd); + + return prd; +} + +std::shared_ptr get_provider_routing_data( + osr::ways const& w, + osr::lookup const& l, + gbfs_data& data, + gbfs_provider const& provider) { + return data.cache_.get_or_compute(provider.idx_, [&]() { + return compute_provider_routing_data(w, l, provider); + }); +} + +std::shared_ptr +gbfs_routing_data::get_provider_routing_data(gbfs_provider const& provider) { + return gbfs::get_provider_routing_data(*w_, *l_, *data_, provider); +} + +products_routing_data* gbfs_routing_data::get_products_routing_data( + gbfs_provider const& provider, gbfs_products_idx_t const prod_idx) { + auto const prod_ref = gbfs::gbfs_products_ref{provider.idx_, prod_idx}; + if (auto const it = products_.find(prod_ref); it != end(products_)) { + return it->second.get(); + } else { + return products_ + .emplace(prod_ref, data_->get_products_routing_data(*w_, *l_, prod_ref)) + .first->second.get(); + } +} + +products_routing_data* gbfs_routing_data::get_products_routing_data( + gbfs_products_ref const prod_ref) { + return get_products_routing_data(*data_->providers_.at(prod_ref.provider_), + prod_ref.products_); +} + +nigiri::transport_mode_id_t gbfs_routing_data::get_transport_mode( + gbfs_products_ref const prod_ref) { + if (auto const it = products_ref_to_transport_mode_.find(prod_ref); + it != end(products_ref_to_transport_mode_)) { + return it->second; + } else { + auto const id = static_cast( + kGbfsTransportModeIdOffset + products_refs_.size()); + products_refs_.emplace_back(prod_ref); + products_ref_to_transport_mode_[prod_ref] = id; + return id; + } +} + +gbfs_products_ref gbfs_routing_data::get_products_ref( + nigiri::transport_mode_id_t const id) const { + return products_refs_.at( + static_cast(id - kGbfsTransportModeIdOffset)); +} + +} // namespace motis::gbfs diff --git a/src/gbfs/update.cc b/src/gbfs/update.cc index 89f0d08749..d62441f316 100644 --- a/src/gbfs/update.cc +++ b/src/gbfs/update.cc @@ -1,25 +1,32 @@ #include "motis/gbfs/update.h" +#include +#include +#include #include #include #include #include +#include #include #include "boost/asio/co_spawn.hpp" #include "boost/asio/detached.hpp" +#include "boost/asio/experimental/awaitable_operators.hpp" #include "boost/asio/experimental/parallel_group.hpp" #include "boost/asio/redirect_error.hpp" #include "boost/asio/steady_timer.hpp" #include "boost/json.hpp" -#include "openssl/sha.h" +#include "cista/hash.h" #include "fmt/format.h" #include "utl/helpers/algorithm.h" +#include "utl/overloaded.h" +#include "utl/sorted_diff.h" #include "utl/timer.h" #include "utl/to_vec.h" @@ -29,11 +36,15 @@ #include "motis/http_client.h" #include "motis/http_req.h" +#include "motis/gbfs/compression.h" #include "motis/gbfs/osr_mapping.h" #include "motis/gbfs/parser.h" +#include "motis/gbfs/partition.h" +#include "motis/gbfs/routing_data.h" namespace asio = boost::asio; using asio::awaitable; +using namespace asio::experimental::awaitable_operators; namespace json = boost::json; @@ -41,7 +52,8 @@ namespace motis::gbfs { struct gbfs_file { json::value json_; - std::string hash_; + cista::hash_t hash_{}; + std::chrono::system_clock::time_point next_refresh_; }; std::string read_file(std::filesystem::path const& path) { @@ -51,220 +63,632 @@ std::string read_file(std::filesystem::path const& path) { return buf.str(); } -std::string hash(std::string_view const s) { - unsigned char hash[SHA256_DIGEST_LENGTH]; - SHA256(reinterpret_cast(s.data()), s.size(), hash); - return std::string{reinterpret_cast(hash), SHA256_DIGEST_LENGTH}; +bool needs_refresh(file_info const& fi) { + return fi.needs_update(std::chrono::system_clock::now()); } -awaitable fetch_file(std::string_view const name, - std::string_view const url, - headers_t const& headers, - std::optional const& dir, - http_client& client) { - auto content = std::string{}; - if (dir.has_value()) { - content = read_file(*dir / fmt::format("{}.json", name)); - } else { - auto const res = co_await client.get(boost::urls::url{url}, headers); - content = get_http_body(res); +// try to hash only the value of the "data" key to ignore fields like +// "last_updated" +cista::hash_t hash_gbfs_data(std::string_view const json) { + auto const pos = json.find("\"data\""); + if (pos == std::string_view::npos) { + return cista::hash(json); } - co_return gbfs_file{.json_ = json::parse(content), .hash_ = hash(content)}; -} -void add_provider_to_rtree(gbfs_data& data, gbfs_provider const& provider) { - for (auto const& station : provider.stations_) { - data.provider_rtree_.add(station.second.info_.pos_, provider.idx_); - } - for (auto const& vehicle : provider.vehicle_status_) { - if (vehicle.station_id_.empty()) { - data.provider_rtree_.add(vehicle.pos_, provider.idx_); + auto i = pos + 6; + auto const skip_whitespace = [&]() { + while (i < json.size() && (json[i] == ' ' || json[i] == '\n' || + json[i] == '\r' || json[i] == '\t')) { + ++i; } + }; + skip_whitespace(); + + if (i >= json.size() || json[i++] != ':') { + return cista::hash(json); } -} -awaitable load_feed(config::gbfs const& c, - osr::ways const& w, - osr::lookup const& l, - gbfs_data* d, - std::string const& prefix, - std::string const& id, - std::string const& url, - headers_t const& headers, - std::optional const& dir, - http_client& client); - -struct manifest_feed { - std::string combined_id_{}; - std::string url_{}; -}; + skip_whitespace(); + + if (i >= json.size() || json[i] != '{') { + return cista::hash(json); + } + + auto const start = i; + auto depth = 1; + auto in_string = false; -awaitable load_manifest(config::gbfs const& c, - osr::ways const& w, - osr::lookup const& l, - gbfs_data* d, - std::string const& prefix, - headers_t const& headers, - http_client& client, - boost::json::object const& root) { - auto feeds = std::vector{}; - if (root.contains("data") && - root.at("data").as_object().contains("datasets")) { - // GBFS 3.x manifest.json - for (auto const& dataset : root.at("data").at("datasets").as_array()) { - auto const system_id = - static_cast(dataset.at("system_id").as_string()); - auto const combined_id = fmt::format("{}:{}", prefix, system_id); - - auto const& versions = dataset.at("versions").as_array(); - if (versions.empty()) { - continue; + while (++i < json.size()) { + if (in_string) { + if (json[i] == '"' && json[i - 1] != '\\') { + in_string = false; } - // versions array must be sorted by increasing version number - auto const& latest_version = versions.back().as_object(); - feeds.emplace_back(manifest_feed{ - combined_id, - static_cast(latest_version.at("url").as_string())}); + continue; + } + + switch (json[i]) { + case '"': in_string = true; break; + case '{': ++depth; break; + case '}': + if (--depth == 0) { + return cista::hash(json.substr(start, i - start + 1)); + } + } + } + + return cista::hash(json); +} + +std::chrono::system_clock::time_point get_expiry( + boost::json::object const& root, + std::chrono::seconds const def = std::chrono::seconds{0}) { + auto const now = std::chrono::system_clock::now(); + if (root.contains("data")) { + auto const& data = root.at("data").as_object(); + if (data.contains("ttl")) { + return now + std::chrono::seconds{data.at("ttl").to_number()}; } - } else if (root.contains("systems")) { - // Lamassu 2.3 format - for (auto const& system : root.at("systems").as_array()) { - auto const system_id = - static_cast(system.at("id").as_string()); - auto const combined_id = fmt::format("{}:{}", prefix, system_id); - feeds.emplace_back(manifest_feed{ - combined_id, static_cast(system.at("url").as_string())}); + } + return now + def; +} + +struct gbfs_update { + gbfs_update(config::gbfs const& c, + osr::ways const& w, + osr::lookup const& l, + gbfs_data* d, + gbfs_data const* prev_d) + : c_{c}, w_{w}, l_{l}, d_{d}, prev_d_{prev_d} { + client_.timeout_ = std::chrono::seconds{c.http_timeout_}; + if (c.proxy_ && !c.proxy_->empty()) { + client_.set_proxy(boost::urls::url{*c.proxy_}); } } - auto executor = co_await asio::this_coro::executor; - auto awaitables = utl::to_vec(feeds, [&](auto const& feed) { - return boost::asio::co_spawn( - executor, - [&, feed]() -> awaitable { - co_await load_feed(c, w, l, d, prefix, feed.combined_id_, feed.url_, - headers, {}, client); - }, - asio::deferred); - }); - - auto x = + awaitable run() { + auto executor = co_await asio::this_coro::executor; + if (prev_d_ == nullptr) { + // this is first time gbfs_update is run: initialize feeds from config + d_->aggregated_feeds_ = + std::make_shared>>(); + d_->standalone_feeds_ = + std::make_shared>>(); + + auto const no_hdr = headers_t{}; + auto awaitables = utl::to_vec(c_.feeds_, [&](auto const& f) { + auto const& id = f.first; + auto const& feed = f.second; + auto const dir = + feed.url_.starts_with("http:") || feed.url_.starts_with("https:") + ? std::nullopt + : std::optional{feed.url_}; + + return boost::asio::co_spawn( + executor, + [this, id, feed, dir, &no_hdr]() -> awaitable { + co_await init_feed(id, feed.url_, feed.headers_.value_or(no_hdr), + dir); + }, + asio::deferred); + }); + co_await asio::experimental::make_parallel_group(awaitables) .async_wait(asio::experimental::wait_for_all(), asio::use_awaitable); -} + } else { + // update run: copy over data from previous state and update feeds + // where necessary + d_->aggregated_feeds_ = prev_d_->aggregated_feeds_; + d_->standalone_feeds_ = prev_d_->standalone_feeds_; + // the set of providers can change if aggregated feeds are used + change. + // gbfs_provider_idx_t for existing providers is stable, if a provider is + // removed its entry is set to a nullptr. new providers may be added. + d_->providers_.resize(prev_d_->providers_.size()); + d_->provider_by_id_ = prev_d_->provider_by_id_; + d_->provider_rtree_ = prev_d_->provider_rtree_; + d_->cache_ = prev_d_->cache_; + + if (!d_->aggregated_feeds_->empty()) { + co_await asio::experimental::make_parallel_group( + utl::to_vec(*d_->aggregated_feeds_, + [&](auto const& af) { + return boost::asio::co_spawn( + executor, + [this, af = af.get()]() -> awaitable { + co_await update_aggregated_feed(*af); + }, + asio::deferred); + })) + .async_wait(asio::experimental::wait_for_all(), + asio::use_awaitable); + } -awaitable load_feed(config::gbfs const& c, - osr::ways const& w, - osr::lookup const& l, - gbfs_data* d, - std::string const& prefix, - std::string const& id, - std::string const& url, - headers_t const& headers, - std::optional const& dir, - http_client& client) { - std::cout << "[GBFS] loading feed " << id << ": " << url << std::endl; - try { - auto const discovery = - co_await fetch_file("gbfs", url, headers, dir, client); - - auto const& root = discovery.json_.as_object(); - if ((root.contains("data") && - root.at("data").as_object().contains("datasets")) || - root.contains("systems")) { - // File is not an individual feed, but a manifest.json / Lamassu file - co_return co_await load_manifest(c, w, l, d, id, headers, client, root); + if (!d_->standalone_feeds_->empty()) { + co_await asio::experimental::make_parallel_group( + utl::to_vec(*d_->standalone_feeds_, + [&](auto const& pf) { + return boost::asio::co_spawn( + executor, + [this, pf = pf.get()]() -> awaitable { + co_await update_provider_feed(*pf); + }, + asio::deferred); + })) + .async_wait(asio::experimental::wait_for_all(), + asio::use_awaitable); + } } + } - auto const urls = parse_discovery(discovery.json_); + awaitable init_feed(std::string const& id, + std::string const& url, + headers_t const& headers, + std::optional const& dir) { + // initialization of a (standalone or aggregated) feed from the config + try { + auto discovery = co_await fetch_file("gbfs", url, headers, dir); + auto const& root = discovery.json_.as_object(); + if ((root.contains("data") && + root.at("data").as_object().contains("datasets")) || + root.contains("systems")) { + // file is not an individual feed, but a manifest.json / Lamassu file + co_return co_await init_aggregated_feed(id, url, headers, root); + } + + auto saf = + d_->standalone_feeds_ + ->emplace_back(std::make_unique( + provider_feed{.id_ = id, + .url_ = url, + .headers_ = headers, + .dir_ = dir, + .default_restrictions_ = + lookup_default_restrictions("", id)})) + .get(); + + co_return co_await update_provider_feed(*saf, std::move(discovery)); + } catch (std::exception const& ex) { + std::cerr << "[GBFS] error initializing feed " << id << " (" << url + << "): " << ex.what() << "\n"; + } + } + + awaitable update_provider_feed( + provider_feed const& pf, + std::optional discovery = std::nullopt) { + auto& provider = add_provider(pf); + + // check if exists in old data - if so, reuse existing file infos + gbfs_provider const* prev_provider = nullptr; + if (prev_d_ != nullptr) { + if (auto const it = prev_d_->provider_by_id_.find(pf.id_); + it != end(prev_d_->provider_by_id_)) { + prev_provider = prev_d_->providers_[it->second].get(); + provider.file_infos_ = prev_provider->file_infos_; + } + } + if (!provider.file_infos_) { + provider.file_infos_ = std::make_shared(); + } + + co_return co_await process_provider_feed(pf, provider, prev_provider, + std::move(discovery)); + } - auto const fetch = [&](std::string_view const name) { - return fetch_file(name, urls.at(name), headers, dir, client); + gbfs_provider& add_provider(provider_feed const& pf) { + auto const init_provider = [&](gbfs_provider& provider, + gbfs_provider_idx_t const idx) { + provider.id_ = pf.id_; + provider.idx_ = idx; + provider.default_restrictions_ = pf.default_restrictions_; }; - auto const provider_idx = gbfs_provider_idx_t{d->providers_.size()}; - d->provider_by_id_[id] = provider_idx; - auto provider = - d->providers_.emplace_back(std::make_unique()).get(); - provider->id_ = id; - provider->idx_ = provider_idx; - - auto const set_default_restrictions = - [&](config::gbfs::restrictions const& r) { - provider->default_restrictions_ = geofencing_restrictions{ - .ride_start_allowed_ = r.ride_start_allowed_, - .ride_end_allowed_ = r.ride_end_allowed_, - .ride_through_allowed_ = r.ride_through_allowed_}; - }; - - if (auto const it = c.default_restrictions_.find(id); - it != end(c.default_restrictions_)) { - set_default_restrictions(it->second); - } else if (auto const prefix_it = c.default_restrictions_.find(prefix); - prefix_it != end(c.default_restrictions_)) { - set_default_restrictions(prefix_it->second); + if (auto it = d_->provider_by_id_.find(pf.id_); + it != end(d_->provider_by_id_)) { + // existing provider, keep idx + auto const idx = it->second; + assert(d_->providers_.at(idx) == nullptr); + d_->providers_[idx] = std::make_unique(); + auto& provider = *d_->providers_[idx].get(); + init_provider(provider, idx); + return provider; + } else { + // new provider + auto const idx = gbfs_provider_idx_t{d_->providers_.size()}; + auto& provider = + *d_->providers_.emplace_back(std::make_unique()).get(); + d_->provider_by_id_[pf.id_] = idx; + init_provider(provider, idx); + return provider; } + } + + awaitable process_provider_feed( + provider_feed const& pf, + gbfs_provider& provider, + gbfs_provider const* prev_provider, + std::optional discovery = std::nullopt) { + auto& file_infos = provider.file_infos_; - if (urls.contains("system_information")) { - load_system_information(*provider, - (co_await fetch("system_information")).json_); + if (!discovery && needs_refresh(provider.file_infos_->urls_fi_)) { + discovery = co_await fetch_file("gbfs", pf.url_, pf.headers_, pf.dir_); } + if (discovery) { + file_infos->urls_ = parse_discovery(discovery->json_); + file_infos->urls_fi_.expiry_ = discovery->next_refresh_; + file_infos->urls_fi_.hash_ = discovery->hash_; + } + + auto const update = [&](std::string_view const name, file_info& fi, + auto const& fn, + bool const force = false) -> awaitable { + if (force || (file_infos->urls_.contains(name) && needs_refresh(fi))) { + auto file = co_await fetch_file(name, file_infos->urls_.at(name), + pf.headers_, pf.dir_); + auto const hash_changed = file.hash_ != fi.hash_; + auto j_root = file.json_.as_object(); + fi.expiry_ = file.next_refresh_; + fi.hash_ = file.hash_; + fn(provider, file.json_); + co_return hash_changed; + } + co_return false; + }; - if (urls.contains("vehicle_types")) { - load_vehicle_types(*provider, (co_await fetch("vehicle_types")).json_); + auto const sys_info_updated = co_await update( + "system_information", file_infos->system_information_fi_, + load_system_information); + if (!sys_info_updated && prev_provider != nullptr) { + provider.sys_info_ = prev_provider->sys_info_; } - if (urls.contains("station_information") && - urls.contains("station_status")) { - load_station_information(*provider, - (co_await fetch("station_information")).json_); - load_station_status(*provider, (co_await fetch("station_status")).json_); + auto const vehicle_types_updated = co_await update( + "vehicle_types", file_infos->vehicle_types_fi_, load_vehicle_types); + if (!vehicle_types_updated && prev_provider != nullptr) { + provider.vehicle_types_ = prev_provider->vehicle_types_; + provider.vehicle_types_map_ = prev_provider->vehicle_types_map_; } - if (urls.contains("vehicle_status")) { // 3.x - load_vehicle_status(*provider, (co_await fetch("vehicle_status")).json_); - } else if (urls.contains("free_bike_status")) { // 2.x - load_vehicle_status(*provider, - (co_await fetch("free_bike_status")).json_); + auto const stations_updated = co_await update( + "station_information", file_infos->station_information_fi_, + load_station_information); + if (!stations_updated && prev_provider != nullptr) { + provider.stations_ = prev_provider->stations_; } - if (urls.contains("geofencing_zones")) { - load_geofencing_zones(*provider, - (co_await fetch("geofencing_zones")).json_); + auto const station_status_updated = + co_await update("station_status", file_infos->station_status_fi_, + load_station_status, stations_updated); + + auto const vehicle_status_updated = + co_await update("vehicle_status", file_infos->vehicle_status_fi_, + load_vehicle_status) // 3.x + || co_await update("free_bike_status", file_infos->vehicle_status_fi_, + load_vehicle_status); // 1.x / 2.x + if (!vehicle_status_updated && prev_provider != nullptr) { + provider.vehicle_status_ = prev_provider->vehicle_status_; } - map_geofencing_zones(w, l, *provider); - map_stations(w, l, *provider); - map_vehicles(w, l, *provider); + auto const geofencing_updated = + co_await update("geofencing_zones", file_infos->geofencing_zones_fi_, + load_geofencing_zones); + if (!geofencing_updated && prev_provider != nullptr) { + provider.geofencing_zones_ = prev_provider->geofencing_zones_; + } - provider->has_vehicles_to_rent_ = provider->start_allowed_.count() != 0; + if (prev_provider != nullptr) { + provider.has_vehicles_to_rent_ = prev_provider->has_vehicles_to_rent_; + } - if (provider->has_vehicles_to_rent_) { - add_provider_to_rtree(*d, *provider); + auto const data_changed = vehicle_types_updated || stations_updated || + station_status_updated || + vehicle_status_updated || geofencing_updated; + + if (data_changed) { + partition_provider(provider); + provider.has_vehicles_to_rent_ = utl::any_of( + provider.products_, + [](auto const& prod) { return prod.has_vehicles_to_rent_; }); + + update_rtree(provider, prev_provider); + + d_->cache_.try_add_or_update(provider.idx_, [&]() { + return compute_provider_routing_data(w_, l_, provider); + }); + } else if (prev_provider != nullptr) { + // data not changed, copy previously computed products + provider.products_ = prev_provider->products_; + provider.has_vehicles_to_rent_ = prev_provider->has_vehicles_to_rent_; } + } - std::cout << "[GBFS] provider " << id - << " initialized: " << provider->stations_.size() << " stations (" - << utl::count_if( - provider->stations_, - [](auto const& s) { - return s.second.status_.is_renting_ && - s.second.status_.num_vehicles_available_ > 0; - }) - << " renting, " - << utl::count_if(provider->stations_, - [](auto const& s) { - return s.second.status_.is_returning_; - }) - << " returning), " << provider->vehicle_status_.size() - << " vehicles, " << provider->vehicle_types_.size() - << " vehicle types, " << provider->geofencing_zones_.zones_.size() - << " geofencing zones\n"; - } catch (std::exception const& ex) { - std::cerr << "[GBFS] error loading feed " << id << " (" << url - << "): " << ex.what() << "\n"; + void partition_provider(gbfs_provider& provider) { + if (provider.vehicle_types_.empty()) { + // providers without vehicle types only need one product segment + auto& prod = provider.products_.emplace_back(); + prod.idx_ = gbfs_products_idx_t{0}; + prod.has_vehicles_to_rent_ = + utl::any_of(provider.stations_, + [](auto const& st) { + return st.second.status_.is_renting_ && + st.second.status_.num_vehicles_available_ > 0; + }) || + utl::any_of(provider.vehicle_status_, [](auto const& vs) { + return !vs.is_disabled_ && !vs.is_reserved_; + }); + } else { + auto part = partition{vehicle_type_idx_t{provider.vehicle_types_.size()}}; + + // refine by form factor + propulsion type + auto by_form_factor = + hash_map, + std::vector>{}; + for (auto const& vt : provider.vehicle_types_) { + by_form_factor[std::pair{vt.form_factor_, vt.propulsion_type_}] + .push_back(vt.idx_); + } + for (auto const& [_, vt_indices] : by_form_factor) { + part.refine(vt_indices); + } + + // refine by return constraints + auto by_return_constraint = + hash_map>{}; + for (auto const& vt : provider.vehicle_types_) { + by_return_constraint[vt.return_constraint_].push_back(vt.idx_); + } + for (auto const& [_, vt_indices] : by_return_constraint) { + part.refine(vt_indices); + } + + // refine by return stations + // TODO: only do this if the station is not in a zone where vehicles + // can be returned anywhere + auto vts = std::vector{}; + for (auto const& [id, st] : provider.stations_) { + if (!st.status_.vehicle_docks_available_.empty()) { + vts.clear(); + for (auto const& [vt, num] : st.status_.vehicle_docks_available_) { + vts.push_back(vt); + } + part.refine(vts); + } + } + + // refine by geofencing zones + for (auto const& z : provider.geofencing_zones_.zones_) { + for (auto const& r : z.rules_) { + part.refine(r.vehicle_type_idxs_); + } + } + + for (auto const& set : part.get_sets()) { + auto const prod_idx = gbfs_products_idx_t{provider.products_.size()}; + auto& prod = provider.products_.emplace_back(); + prod.idx_ = prod_idx; + prod.vehicle_types_ = set; + auto const first_vt = + provider.vehicle_types_.at(prod.vehicle_types_.front()); + prod.form_factor_ = first_vt.form_factor_; + prod.propulsion_type_ = first_vt.propulsion_type_; + prod.return_constraint_ = first_vt.return_constraint_; + prod.has_vehicles_to_rent_ = + utl::any_of(provider.stations_, + [&](auto const& st) { + return st.second.status_.is_renting_ && + st.second.status_.num_vehicles_available_ > 0; + }) || + utl::any_of(provider.vehicle_status_, [&](auto const& vs) { + return !vs.is_disabled_ && !vs.is_reserved_ && + prod.includes_vehicle_type(vs.vehicle_type_idx_); + }); + } + } + } + + void update_rtree(gbfs_provider const& provider, + gbfs_provider const* prev_provider) { + auto added_stations = 0U; + auto added_vehicles = 0U; + auto removed_stations = 0U; + auto removed_vehicles = 0U; + auto moved_stations = 0U; + auto moved_vehicles = 0U; + + if (prev_provider != nullptr) { + using ST = std::pair; + utl::sorted_diff( + prev_provider->stations_, provider.stations_, + [](ST const& a, ST const& b) { return a.first < b.first; }, + [](ST const& a, ST const& b) { + return a.second.info_.pos_ == b.second.info_.pos_; + }, + utl::overloaded{ + [&](utl::op const o, ST const& s) { + if (o == utl::op::kAdd) { + d_->provider_rtree_.add(s.second.info_.pos_, provider.idx_); + ++added_stations; + } else { // del + d_->provider_rtree_.remove(s.second.info_.pos_, + provider.idx_); + ++removed_stations; + } + }, + [&](ST const& a, ST const& b) { + d_->provider_rtree_.remove(a.second.info_.pos_, provider.idx_); + d_->provider_rtree_.add(b.second.info_.pos_, provider.idx_); + ++moved_stations; + }}); + utl::sorted_diff( + prev_provider->vehicle_status_, provider.vehicle_status_, + [](vehicle_status const& a, vehicle_status const& b) { + return a.id_ < b.id_; + }, + [](vehicle_status const& a, vehicle_status const& b) { + return a.pos_ == b.pos_; + }, + utl::overloaded{ + [&](utl::op const o, vehicle_status const& v) { + if (o == utl::op::kAdd) { + d_->provider_rtree_.add(v.pos_, provider.idx_); + ++added_vehicles; + } else { // del + d_->provider_rtree_.remove(v.pos_, provider.idx_); + ++removed_vehicles; + } + }, + [&](vehicle_status const& a, vehicle_status const& b) { + d_->provider_rtree_.remove(a.pos_, provider.idx_); + d_->provider_rtree_.add(b.pos_, provider.idx_); + ++moved_vehicles; + }}); + } else { + for (auto const& station : provider.stations_) { + d_->provider_rtree_.add(station.second.info_.pos_, provider.idx_); + ++added_stations; + } + for (auto const& vehicle : provider.vehicle_status_) { + if (vehicle.station_id_.empty()) { + d_->provider_rtree_.add(vehicle.pos_, provider.idx_); + ++added_vehicles; + } + } + } + } + + awaitable init_aggregated_feed(std::string const& prefix, + std::string const& url, + headers_t const& headers, + boost::json::object const& root) { + auto af = + d_->aggregated_feeds_ + ->emplace_back(std::make_unique(aggregated_feed{ + .id_ = prefix, + .url_ = url, + .headers_ = headers, + .expiry_ = get_expiry(root, std::chrono::hours{1})})) + .get(); + + co_return co_await process_aggregated_feed(*af, root); + } + + awaitable update_aggregated_feed(aggregated_feed& af) { + if (af.needs_update()) { + auto const file = co_await fetch_file("manifest", af.url_, af.headers_); + co_await process_aggregated_feed(af, file.json_.as_object()); + } else { + co_await update_aggregated_feed_provider_feeds(af); + } } -} + + awaitable process_aggregated_feed(aggregated_feed& af, + boost::json::object const& root) { + auto feeds = std::vector{}; + if (root.contains("data") && + root.at("data").as_object().contains("datasets")) { + // GBFS 3.x manifest.json + for (auto const& dataset : root.at("data").at("datasets").as_array()) { + auto const system_id = + static_cast(dataset.at("system_id").as_string()); + auto const combined_id = fmt::format("{}:{}", af.id_, system_id); + + auto const& versions = dataset.at("versions").as_array(); + if (versions.empty()) { + continue; + } + // versions array must be sorted by increasing version number + auto const& latest_version = versions.back().as_object(); + feeds.emplace_back(provider_feed{ + .id_ = combined_id, + .url_ = + static_cast(latest_version.at("url").as_string()), + .default_restrictions_ = + lookup_default_restrictions(af.id_, combined_id)}); + } + } else if (root.contains("systems")) { + // Lamassu 2.3 format + for (auto const& system : root.at("systems").as_array()) { + auto const system_id = + static_cast(system.at("id").as_string()); + auto const combined_id = fmt::format("{}:{}", af.id_, system_id); + feeds.emplace_back(provider_feed{ + .id_ = combined_id, + .url_ = static_cast(system.at("url").as_string()), + .default_restrictions_ = + lookup_default_restrictions(af.id_, combined_id)}); + } + } + + af.feeds_ = std::move(feeds); + co_await update_aggregated_feed_provider_feeds(af); + } + + awaitable update_aggregated_feed_provider_feeds(aggregated_feed& af) { + auto executor = co_await asio::this_coro::executor; + co_await asio::experimental::make_parallel_group( + utl::to_vec(af.feeds_, + [&](auto const& pf) { + return boost::asio::co_spawn( + executor, + [this, pf = &pf]() -> awaitable { + co_await update_provider_feed(*pf); + }, + asio::deferred); + })) + .async_wait(asio::experimental::wait_for_all(), asio::use_awaitable); + } + + awaitable fetch_file( + std::string_view const name, + std::string_view const url, + headers_t const& headers, + std::optional const& dir = std::nullopt) { + auto content = std::string{}; + if (dir.has_value()) { + content = read_file(*dir / fmt::format("{}.json", name)); + } else { + auto const res = co_await client_.get(boost::urls::url{url}, headers); + content = get_http_body(res); + } + auto j = json::parse(content); + auto j_root = j.as_object(); + auto const next_refresh = + std::chrono::system_clock::now() + + std::chrono::seconds{ + j_root.contains("ttl") ? j_root.at("ttl").to_number() : 0}; + co_return gbfs_file{.json_ = std::move(j), + .hash_ = hash_gbfs_data(content), + .next_refresh_ = next_refresh}; + } + + geofencing_restrictions lookup_default_restrictions(std::string const& prefix, + std::string const& id) { + auto const convert = [&](config::gbfs::restrictions const& r) { + return geofencing_restrictions{ + .ride_start_allowed_ = r.ride_start_allowed_, + .ride_end_allowed_ = r.ride_end_allowed_, + .ride_through_allowed_ = r.ride_through_allowed_}; + }; + + if (auto const it = c_.default_restrictions_.find(id); + it != end(c_.default_restrictions_)) { + return convert(it->second); + } else if (auto const prefix_it = c_.default_restrictions_.find(prefix); + prefix_it != end(c_.default_restrictions_)) { + return convert(prefix_it->second); + } else { + return {}; + } + } + + config::gbfs const& c_; + osr::ways const& w_; + osr::lookup const& l_; + + gbfs_data* d_; + gbfs_data const* prev_d_; + + http_client client_; +}; awaitable update(config const& c, osr::ways const& w, @@ -276,35 +700,12 @@ awaitable update(config const& c, co_return; } - auto d = std::make_shared(); - auto client = http_client{}; - auto const no_hdr = headers_t{}; - client.timeout_ = std::chrono::seconds{c.gbfs_->http_timeout_}; - - auto executor = co_await asio::this_coro::executor; - auto awaitables = utl::to_vec(c.gbfs_->feeds_, [&](auto const& f) { - auto const& id = f.first; - auto const& feed = f.second; - auto const dir = - feed.url_.starts_with("http:") || feed.url_.starts_with("https:") - ? std::nullopt - : std::optional{feed.url_}; - - return boost::asio::co_spawn( - executor, - [id, feed, dir, &c, &d, &w, &l, &no_hdr, &client]() -> awaitable { - co_await load_feed(c.gbfs_.value(), w, l, d.get(), "", id, feed.url_, - feed.headers_.value_or(no_hdr), dir, client); - }, - asio::deferred); - }); - - auto x = - co_await asio::experimental::make_parallel_group(awaitables) - .async_wait(asio::experimental::wait_for_all(), asio::use_awaitable); + auto const prev_d = data_ptr; + auto const d = std::make_shared(c.gbfs_->cache_size_); + auto update = gbfs_update{*c.gbfs_, w, l, d.get(), prev_d.get()}; + co_await update.run(); data_ptr = d; - co_return; } void run_gbfs_update(boost::asio::io_context& ioc, diff --git a/src/http_client.cc b/src/http_client.cc index 029a415b8f..2eb259c093 100644 --- a/src/http_client.cc +++ b/src/http_client.cc @@ -88,6 +88,7 @@ struct http_client::connection connection(Executor const& executor, connection_key key, std::chrono::seconds const timeout, + proxy_settings const& proxy, std::size_t const max_in_flight = 1) : key_{std::move(key)}, unlimited_pipelining_{max_in_flight == kUnlimitedHttpPipelining}, @@ -95,7 +96,8 @@ struct http_client::connection requests_in_flight_{std::make_unique< asio::experimental::channel>( executor, max_in_flight)}, - timeout_{timeout} { + timeout_{timeout}, + proxy_{proxy} { ssl_ctx_.set_default_verify_paths(); ssl_ctx_.set_verify_mode(ssl::verify_none); ssl_ctx_.set_options(ssl::context::default_workarounds | @@ -128,15 +130,17 @@ struct http_client::connection auto executor = co_await asio::this_coro::executor; auto resolver = asio::ip::tcp::resolver{executor}; - auto const results = - co_await resolver.async_resolve(key_.host_, key_.port_); + auto const host = proxy_ ? proxy_.host_ : key_.host_; + auto const port = proxy_ ? proxy_.port_ : key_.port_; + + auto const results = co_await resolver.async_resolve(host, port); ++n_connects_; if (ssl()) { ssl_stream_ = std::make_unique>(executor, ssl_ctx_); if (!SSL_set_tlsext_host_name(ssl_stream_->native_handle(), - const_cast(key_.host_.c_str()))) { + const_cast(host.c_str()))) { throw boost::system::system_error{{static_cast(::ERR_get_error()), asio::error::get_ssl_category()}}; } @@ -290,7 +294,7 @@ struct http_client::connection } while (!pending_requests_.empty()); } - bool ssl() const { return key_.ssl_; } + bool ssl() const { return proxy_ ? proxy_.ssl_ : key_.ssl_; } connection_key key_{}; bool unlimited_pipelining_{false}; @@ -313,6 +317,7 @@ struct http_client::connection ssl::context ssl_ctx_{ssl::context::tlsv12_client}; std::chrono::seconds timeout_; + http_client::proxy_settings proxy_; unsigned n_sent_{}; unsigned n_received_{}; @@ -335,7 +340,8 @@ asio::awaitable http_client::get( auto executor = co_await asio::this_coro::executor; if (auto const it = connections_.find(key); it == connections_.end()) { - auto conn = std::make_shared(executor, key, timeout_, 1); + auto conn = + std::make_shared(executor, key, timeout_, proxy_, 1); connections_[key] = conn; asio::co_spawn(executor, conn->run(), asio::detached); } @@ -348,4 +354,10 @@ asio::awaitable http_client::get( co_return response; } +void http_client::set_proxy(boost::urls::url const& url) { + proxy_.ssl_ = url.scheme_id() == boost::urls::scheme::https; + proxy_.host_ = url.host(); + proxy_.port_ = url.has_port() ? url.port() : (proxy_.ssl_ ? "443" : "80"); +} + } // namespace motis diff --git a/src/http_req.cc b/src/http_req.cc index d191aa285f..3ac1c5ff0e 100644 --- a/src/http_req.cc +++ b/src/http_req.cc @@ -24,6 +24,8 @@ namespace http = beast::http; namespace asio = boost::asio; namespace ssl = asio::ssl; +constexpr auto const kBodySizeLimit = 128U * 1024U * 1024U; // 128 M + template asio::awaitable req(Stream&&, boost::urls::url const&, @@ -94,14 +96,17 @@ asio::awaitable req( co_await http::async_write(stream, req); + auto p = http::response_parser{}; + p.eager(true); + p.body_limit(kBodySizeLimit); + auto buffer = beast::flat_buffer{}; - auto res = http::response{}; - co_await http::async_read(stream, buffer, res); + co_await http::async_read(stream, buffer, p); auto ec = beast::error_code{}; beast::get_lowest_layer(stream).socket().shutdown( asio::ip::tcp::socket::shutdown_both, ec); - co_return res; + co_return p.release(); } asio::awaitable> http_GET( diff --git a/src/import.cc b/src/import.cc index 04045f9b59..8e59c35ca6 100644 --- a/src/import.cc +++ b/src/import.cc @@ -297,7 +297,7 @@ data import(config const& c, fs::path const& data_path, bool const write) { } }, [&]() { - d.load_tt(); + d.load_tt("tt.bin"); if (c.timetable_->with_shapes_) { d.load_shapes(); } @@ -367,19 +367,22 @@ data import(config const& c, fs::path const& data_path, bool const write) { auto osr_footpath = task{ "osr_footpath", - [&]() { return c.osr_footpath_; }, - [&]() { return d.tt_ && d.w_ && d.l_ && d.pl_; }, + [&]() { return c.osr_footpath_ && c.timetable_; }, + [&]() { return d.tt_ && d.tags_ && d.w_ && d.l_ && d.pl_; }, [&]() { - auto const elevator_footpath_map = - compute_footpaths(*d.w_, *d.l_, *d.pl_, *d.tt_, true); + auto const elevator_footpath_map = compute_footpaths( + *d.w_, *d.l_, *d.pl_, *d.tt_, + c.timetable_->use_osm_stop_coordinates_, + c.timetable_->extend_missing_footpaths_, + std::chrono::seconds{c.timetable_->max_footpath_length_ * 60U}); if (write) { cista::write(data_path / "elevator_footpath_map.bin", elevator_footpath_map); - d.tt_->write(data_path / "tt.bin"); + d.tt_->write(data_path / "tt_ext.bin"); } }, - [&]() {}, + [&]() { d.load_tt("tt_ext.bin"); }, {tt_hash, osm_hash, osr_version(), osr_footpath_version(), n_version()}}; auto matches = diff --git a/src/journey_to_response.cc b/src/journey_to_response.cc index 56c8d4e8bc..821d81cc4e 100644 --- a/src/journey_to_response.cc +++ b/src/journey_to_response.cc @@ -17,6 +17,8 @@ #include "nigiri/types.h" #include "motis/constants.h" +#include "motis/gbfs/mode.h" +#include "motis/gbfs/routing_data.h" #include "motis/place.h" #include "motis/street_routing.h" #include "motis/tag_lookup.h" @@ -35,7 +37,7 @@ api::ModeEnum to_mode(osr::search_profile const m) { case osr::search_profile::kWheelchair: return api::ModeEnum::WALK; case osr::search_profile::kCar: return api::ModeEnum::CAR; case osr::search_profile::kBike: return api::ModeEnum::BIKE; - case osr::search_profile::kBikeSharing: return api::ModeEnum::BIKE_RENTAL; + case osr::search_profile::kBikeSharing: return api::ModeEnum::RENTAL; } std::unreachable(); } @@ -49,13 +51,14 @@ api::Itinerary journey_to_response(osr::ways const* w, n::rt_timetable const* rtt, platform_matches_t const* matches, n::shapes_storage const* shapes, - gbfs::gbfs_data const* gbfs, + gbfs::gbfs_routing_data& gbfs_rd, bool const wheelchair, n::routing::journey const& j, place_t const& start, place_t const& dest, street_routing_cache_t& cache, - osr::bitvec& blocked_mem) { + osr::bitvec& blocked_mem, + bool const detailed_transfers) { utl::verify(!j.legs_.empty(), "journey without legs"); auto itinerary = api::Itinerary{ @@ -120,7 +123,7 @@ api::Itinerary journey_to_response(osr::ways const* w, .agencyName_ = {std::string{agency.long_name_}}, .agencyUrl_ = {std::string{agency.url_}}, .agencyId_ = {std::string{agency.short_name_}}, - .tripId_ = tags.id(tt, enter_stop), + .tripId_ = tags.id(tt, enter_stop, n::event_type::kDep), .routeShortName_ = {std::string{ enter_stop.trip_display_name()}}, .source_ = fmt::to_string(fr.dbg())}); @@ -161,28 +164,27 @@ api::Itinerary journey_to_response(osr::ways const* w, [&](n::footpath) { append( w && l - ? route(*w, *l, gbfs, e, from, to, api::ModeEnum::WALK, - wheelchair, j_leg.dep_time_, j_leg.arr_time_, - gbfs_provider_idx_t::invalid(), cache, - blocked_mem, + ? route(*w, *l, gbfs_rd, e, from, to, api::ModeEnum::WALK, + wheelchair, j_leg.dep_time_, j_leg.arr_time_, {}, + cache, blocked_mem, std::chrono::duration_cast( j_leg.arr_time_ - j_leg.dep_time_) + - std::chrono::minutes{5}) + std::chrono::minutes{10}, + !detailed_transfers) : dummy_itinerary(from, to, api::ModeEnum::WALK, j_leg.dep_time_, j_leg.arr_time_)); }, [&](n::routing::offset const x) { append(route( - *w, *l, gbfs, e, from, to, + *w, *l, gbfs_rd, e, from, to, x.transport_mode_id_ >= kGbfsTransportModeIdOffset - ? api::ModeEnum::BIKE_RENTAL + ? api::ModeEnum::RENTAL : to_mode(osr::search_profile{ static_cast(x.transport_mode_id_)}), wheelchair, j_leg.dep_time_, j_leg.arr_time_, x.transport_mode_id_ >= kGbfsTransportModeIdOffset - ? gbfs_provider_idx_t{x.transport_mode_id_ - - kGbfsTransportModeIdOffset} - : gbfs_provider_idx_t::invalid(), + ? gbfs_rd.get_products_ref(x.transport_mode_id_) + : gbfs::gbfs_products_ref{}, cache, blocked_mem, std::chrono::duration_cast( j_leg.arr_time_ - j_leg.dep_time_) + diff --git a/src/match_platforms.cc b/src/match_platforms.cc index 17ca12a14d..de49d52eaa 100644 --- a/src/match_platforms.cc +++ b/src/match_platforms.cc @@ -101,20 +101,20 @@ double get_match_bonus(Collection&& names, auto bonus = 0U; auto const size = static_cast(name.size()); if (has_exact_match(names, ref)) { - bonus += 200.0 - size; + bonus += std::max(0.0, 200.0 - size); } if (has_number_match(names, name)) { - bonus += 140.0 - size; + bonus += std::max(0.0, 140.0 - size); } if (auto const track = get_track(ref); track.has_value() && has_number_match(names, *track)) { - bonus += 60.0 - size; + bonus += std::max(0.0, 60.0 - size); } if (has_exact_match(names, name)) { - bonus += 15.0 - size; + bonus += std::max(0.0, 15.0 - size); } if (has_contains_match(names, ref)) { - bonus += 5.0 - size; + bonus += std::max(0.0, 5.0 - size); } return bonus; } diff --git a/src/mode_to_profile.cc b/src/mode_to_profile.cc index 996655e7fb..3d2936e1b5 100644 --- a/src/mode_to_profile.cc +++ b/src/mode_to_profile.cc @@ -24,9 +24,9 @@ osr::search_profile to_profile(api::ModeEnum const m, bool const wheelchair) { case api::ModeEnum::CAR_PARKING: return wheelchair ? osr::search_profile::kCarParkingWheelchair : osr::search_profile::kCarParking; - case api::ModeEnum::BIKE_RENTAL: return osr::search_profile::kBikeSharing; + case api::ModeEnum::RENTAL: return osr::search_profile::kBikeSharing; default: throw utl::fail("unsupported mode"); } } -} // namespace motis \ No newline at end of file +} // namespace motis diff --git a/src/railviz.cc b/src/railviz.cc index 649307a891..ef4ff55b91 100644 --- a/src/railviz.cc +++ b/src/railviz.cc @@ -34,7 +34,7 @@ namespace n = nigiri; -constexpr auto const kLimit = 4096U; +constexpr auto const kLimit = 12'000U; using static_rtree = cista::raw::rtree; using rt_rtree = cista::raw::rtree; @@ -370,7 +370,7 @@ api::trips_response get_trains(tag_lookup const& tags, [&](auto&& p) { enc.push(p); }); return {.trips_ = {api::TripInfo{ - .tripId_ = tags.id(tt, from), + .tripId_ = tags.id(tt, from, n::event_type::kDep), .routeShortName_ = std::string{from.trip_display_name(n::event_type::kDep)}}}, .routeColor_ = diff --git a/src/street_routing.cc b/src/street_routing.cc index ed320911e3..0a65982c7f 100644 --- a/src/street_routing.cc +++ b/src/street_routing.cc @@ -8,6 +8,8 @@ #include "osr/routing/sharing_data.h" #include "motis/constants.h" +#include "motis/gbfs/mode.h" +#include "motis/gbfs/routing_data.h" #include "motis/mode_to_profile.h" #include "motis/place.h" #include "motis/polyline.h" @@ -117,15 +119,18 @@ std::vector get_step_instructions( struct sharing { sharing(osr::ways const& w, - gbfs::gbfs_data const& gbfs, - gbfs_provider_idx_t const provider_idx) + gbfs::gbfs_routing_data& gbfs_rd, + gbfs::gbfs_products_ref const prod_ref) : w_{w}, - gbfs_{gbfs}, - provider_{*gbfs_.providers_.at(provider_idx).get()} {} + gbfs_rd_{gbfs_rd}, + provider_{*gbfs_rd_.data_->providers_.at(prod_ref.provider_)}, + products_{provider_.products_.at(prod_ref.products_)}, + prod_rd_{gbfs_rd_.get_products_routing_data(prod_ref)} {} api::Rental get_rental(osr::node_idx_t const n) const { auto ret = rental_; - auto const& an = provider_.additional_nodes_.at(get_additional_node_idx(n)); + auto const& an = + prod_rd_->compressed_.additional_nodes_.at(get_additional_node_idx(n)); std::visit(utl::overloaded{ [&](gbfs::additional_node::station const& s) { auto const& st = provider_.stations_.at(s.id_); @@ -153,7 +158,8 @@ struct sharing { [&](gbfs::additional_node::vehicle const& vehicle) { return provider_.vehicle_status_.at(vehicle.idx_).pos_; }}, - provider_.additional_nodes_.at(get_additional_node_idx(n)).data_); + prod_rd_->compressed_.additional_nodes_.at(get_additional_node_idx(n)) + .data_); } std::size_t get_additional_node_idx(osr::node_idx_t const n) const { @@ -161,19 +167,25 @@ struct sharing { } osr::ways const& w_; - gbfs::gbfs_data const& gbfs_; + gbfs::gbfs_routing_data& gbfs_rd_; gbfs::gbfs_provider const& provider_; + gbfs::provider_products const& products_; + gbfs::products_routing_data const* prod_rd_; osr::sharing_data sharing_data_{ - .start_allowed_ = provider_.start_allowed_, - .end_allowed_ = provider_.end_allowed_, - .through_allowed_ = provider_.through_allowed_, + .start_allowed_ = prod_rd_->start_allowed_, + .end_allowed_ = prod_rd_->end_allowed_, + .through_allowed_ = prod_rd_->through_allowed_, .additional_node_offset_ = w_.n_nodes(), - .additional_edges_ = provider_.additional_edges_}; + .additional_edges_ = prod_rd_->compressed_.additional_edges_}; api::Rental rental_{ .systemId_ = provider_.sys_info_.id_, .systemName_ = provider_.sys_info_.name_, .url_ = provider_.sys_info_.url_, - }; + .formFactor_ = gbfs::to_api_form_factor(products_.form_factor_), + .propulsionType_ = + gbfs::to_api_propulsion_type(products_.propulsion_type_), + .returnConstraint_ = + gbfs::to_api_return_constraint(products_.return_constraint_)}; }; api::Itinerary dummy_itinerary(api::Place const& from, @@ -203,7 +215,7 @@ api::Itinerary dummy_itinerary(api::Place const& from, api::Itinerary route(osr::ways const& w, osr::lookup const& l, - gbfs::gbfs_data const* gbfs, + gbfs::gbfs_routing_data& gbfs_rd, elevators const* e, api::Place const& from, api::Place const& to, @@ -211,20 +223,26 @@ api::Itinerary route(osr::ways const& w, bool const wheelchair, n::unixtime_t const start_time, std::optional const end_time, - gbfs_provider_idx_t const provider_idx, + gbfs::gbfs_products_ref const prod_ref, street_routing_cache_t& cache, osr::bitvec& blocked_mem, - std::chrono::seconds const max) { + std::chrono::seconds const max, + bool const dummy) { + if (dummy) { + return dummy_itinerary(from, to, mode, start_time, *end_time); + } + auto const profile = to_profile(mode, wheelchair); - utl::verify(profile != osr::search_profile::kBikeSharing || gbfs != nullptr, - "sharing mobility not configured"); + utl::verify( + profile != osr::search_profile::kBikeSharing || gbfs_rd.has_data(), + "sharing mobility not configured"); auto const is_additional_node = [&](osr::node_idx_t const n) { return n >= w.n_nodes(); }; auto const sharing_data = profile == osr::search_profile::kBikeSharing - ? std::optional{sharing(w, *gbfs, provider_idx)} + ? std::optional{sharing(w, gbfs_rd, prod_ref)} : std::nullopt; auto const get_node_pos = [&](osr::node_idx_t const n) -> geo::latlng { @@ -238,13 +256,12 @@ api::Itinerary route(osr::ways const& w, }; auto const path = [&]() { - auto p = - get_path(w, l, e, sharing_data ? &sharing_data->sharing_data_ : nullptr, - get_location(from), get_location(to), - static_cast( - to_idx(provider_idx + kGbfsTransportModeIdOffset)), - to_profile(mode, wheelchair), start_time, - static_cast(max.count()), cache, blocked_mem); + auto p = get_path( + w, l, e, sharing_data ? &sharing_data->sharing_data_ : nullptr, + get_location(from), get_location(to), + static_cast(gbfs_rd.get_transport_mode(prod_ref)), + to_profile(mode, wheelchair), start_time, + static_cast(max.count()), cache, blocked_mem); if (p.has_value() && profile == osr::search_profile::kBikeSharing) { // Coordinates of additional nodes are not known to osr. @@ -265,7 +282,10 @@ api::Itinerary route(osr::ways const& w, return {}; } std::cout << "ROUTING\n FROM: " << from << " \n TO: " << to - << "\n -> CREATING DUMMY LEG\n"; + << "\n -> CREATING DUMMY LEG (mode=" << mode + << ", profile=" << osr::to_str(profile) + << ", provider=" << prod_ref.provider_ + << ", products=" << prod_ref.products_ << ")\n"; return dummy_itinerary(from, to, mode, start_time, *end_time); } @@ -275,7 +295,8 @@ api::Itinerary route(osr::ways const& w, .count() : path->cost_, .startTime_ = start_time, - .endTime_ = start_time + std::chrono::seconds{path->cost_}, + .endTime_ = + end_time ? *end_time : start_time + std::chrono::seconds{path->cost_}, .transfers_ = 0}; auto t = std::chrono::time_point_cast(start_time); @@ -287,9 +308,12 @@ api::Itinerary route(osr::ways const& w, auto const range = std::span{lb, ub}; auto const is_last_leg = ub == end(path->segments_); auto const is_bike_leg = lb->mode_ == osr::mode::kBike; + auto const from_additional_node = + is_additional_node(range.front().from_); + auto const to_additional_node = is_additional_node(range.back().to_); auto const is_rental = (profile == osr::search_profile::kBikeSharing && is_bike_leg && - is_additional_node(range.back().to_)); + (from_additional_node || to_additional_node)); auto const to_node = range.back().to_; auto const to_pos = get_node_pos(to_node); @@ -318,10 +342,7 @@ api::Itinerary route(osr::ways const& w, } auto& leg = itinerary.legs_.emplace_back(api::Leg{ - .mode_ = (lb->mode_ == osr::mode::kBike && - profile == osr::search_profile::kBikeSharing) - ? api::ModeEnum::BIKE_RENTAL - : to_mode(lb->mode_), + .mode_ = is_rental ? api::ModeEnum::RENTAL : to_mode(lb->mode_), .from_ = pred_place, .to_ = next_place, .duration_ = std::chrono::duration_cast( @@ -333,9 +354,11 @@ api::Itinerary route(osr::ways const& w, .legGeometry_ = to_polyline<7>(concat), .steps_ = get_step_instructions(w, get_location(from), get_location(to), range), - .rental_ = is_rental ? std::optional{sharing_data->get_rental( - range.back().to_)} - : std::nullopt}); + .rental_ = is_rental + ? std::optional{sharing_data->get_rental( + from_additional_node ? range.front().from_ + : range.back().to_)} + : std::nullopt}); leg.from_.departure_ = leg.from_.scheduledDeparture_ = leg.scheduledStartTime_ = leg.startTime_; @@ -346,6 +369,16 @@ api::Itinerary route(osr::ways const& w, pred_end_time = t; }); + if (end_time && !itinerary.legs_.empty()) { + itinerary.legs_.back().to_.arrival_ = + itinerary.legs_.back().to_.scheduledArrival_ = + itinerary.legs_.back().endTime_ = + itinerary.legs_.back().scheduledEndTime_ = *end_time; + for (auto& leg : itinerary.legs_) { + leg.duration_ = (leg.endTime_.time_ - leg.startTime_.time_).count(); + } + } + return itinerary; } diff --git a/src/tag_lookup.cc b/src/tag_lookup.cc index 01d62039e0..5743bb91cf 100644 --- a/src/tag_lookup.cc +++ b/src/tag_lookup.cc @@ -49,10 +49,11 @@ std::string tag_lookup::id(nigiri::timetable const& tt, } std::string tag_lookup::id(nigiri::timetable const& tt, - n::rt::run_stop s) const { + n::rt::run_stop s, + n::event_type const ev_type) const { if (s.fr_->is_scheduled()) { // trip id - auto const t = s.get_trip_idx(n::event_type::kDep); + auto const t = s.get_trip_idx(ev_type); auto const id_idx = tt.trip_ids_[t].front(); auto const id = tt.trip_id_strings_[id_idx].view(); auto const src = tt.trip_id_src_[id_idx]; diff --git a/test/config_test.cc b/test/config_test.cc index d7c0bb0f8e..c77ef2e44a 100644 --- a/test/config_test.cc +++ b/test/config_test.cc @@ -51,6 +51,8 @@ osm: europe-latest.osm.pbf update_interval: 60 http_timeout: 10 incremental_rt_update: false + use_osm_stop_coordinates: false + extend_missing_footpaths: false max_footpath_length: 15 datasets: de: diff --git a/test/gbfs_partition_test.cc b/test/gbfs_partition_test.cc new file mode 100644 index 0000000000..b768fbf456 --- /dev/null +++ b/test/gbfs_partition_test.cc @@ -0,0 +1,99 @@ +#include "gtest/gtest.h" + +#include +#include +#include +#include + +#include "motis/gbfs/partition.h" + +using namespace motis::gbfs; + +// helper function to compare sets regardless of order +template +bool compare_partitions(std::vector> const& actual, + std::vector> const& expected) { + if (actual.size() != expected.size()) { + return false; + } + + auto actual_sets = std::vector>{}; + auto expected_sets = std::vector>{}; + + for (auto const& vec : actual) { + actual_sets.emplace_back(begin(vec), end(vec)); + } + for (auto const& vec : expected) { + expected_sets.emplace_back(begin(vec), end(vec)); + } + + std::sort(actual_sets.begin(), actual_sets.end()); + std::sort(expected_sets.begin(), expected_sets.end()); + + return actual_sets == expected_sets; +} + +TEST(motis, gbfs_partition_test) { + using T = int; + + auto p = partition{10}; + + // Initial partition test + auto const single_set = + std::vector>{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; + EXPECT_TRUE(compare_partitions(p.get_sets(), single_set)); + + // First refinement + p.refine(std::array{1, 2, 3}); + auto const two_sets = + std::vector>{{1, 2, 3}, {0, 4, 5, 6, 7, 8, 9}}; + EXPECT_TRUE(compare_partitions(p.get_sets(), two_sets)); + + // Same refinement in different orders should yield same result + p.refine(std::array{1, 2, 3}); + EXPECT_TRUE(compare_partitions(p.get_sets(), two_sets)); + p.refine(std::array{3, 2, 1}); + EXPECT_TRUE(compare_partitions(p.get_sets(), two_sets)); + + // Further refinement + p.refine(std::array{7, 8}); + auto const three_sets = + std::vector>{{1, 2, 3}, {7, 8}, {0, 4, 5, 6, 9}}; + EXPECT_TRUE(compare_partitions(p.get_sets(), three_sets)); + + // Final refinement + p.refine(std::array{1, 3}); + auto const four_sets = + std::vector>{{1, 3}, {2}, {7, 8}, {0, 4, 5, 6, 9}}; + EXPECT_TRUE(compare_partitions(p.get_sets(), four_sets)); +} + +TEST(motis, gbfs_partition_empty_refinement) { + using T = int; + auto p = partition{5}; + + p.refine(std::array{}); + EXPECT_TRUE(compare_partitions(p.get_sets(), + std::vector>{{0, 1, 2, 3, 4}})); +} + +TEST(motis, gbfs_partition_single_element) { + using T = int; + auto p = partition{1}; + + p.refine(std::array{0}); + EXPECT_TRUE( + compare_partitions(p.get_sets(), std::vector>{{0}})); +} + +TEST(motis, gbfs_partition_disjoint_refinements) { + using T = int; + auto p = partition{6}; + + p.refine(std::array{0, 1}); + p.refine(std::array{2, 3}); + p.refine(std::array{4, 5}); + + auto const expected = std::vector>{{0, 1}, {2, 3}, {4, 5}}; + EXPECT_TRUE(compare_partitions(p.get_sets(), expected)); +} diff --git a/test/routing_test.cc b/test/routing_test.cc index 117186f634..04bf6fd35e 100644 --- a/test/routing_test.cc +++ b/test/routing_test.cc @@ -327,6 +327,8 @@ TEST(motis, routing) { config::timetable{ .first_day_ = "2019-05-01", .num_days_ = 2, + .use_osm_stop_coordinates_ = true, + .extend_missing_footpaths_ = false, .datasets_ = {{"test", {.path_ = std::string{kGTFS}}}}}, .gbfs_ = {{.feeds_ = {{"CAB", {.url_ = "./test/resources/gbfs"}}}}}, .street_routing_ = true, @@ -373,7 +375,7 @@ TEST(motis, routing) { "&toPlace=49.87253873915287,8.629724234688751" "&time=2019-05-01T01:25Z" "&timetableView=false" - "&directModes=WALK,BIKE_RENTAL"); + "&directModes=WALK,RENTAL"); auto ss = std::stringstream{}; for (auto const& j : plan_response.direct_) { @@ -383,7 +385,7 @@ TEST(motis, routing) { EXPECT_EQ( R"(date=2019-05-01, start=01:25, end=01:38, duration=00:13, transfers=0, legs=[ (from=- [track=-, scheduled_track=-, level=0], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 01:25, mode="WALK", trip="-", end=2019-05-01 01:28), - (from=- [track=-, scheduled_track=-, level=0], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 01:28, mode="BIKE_RENTAL", trip="-", end=2019-05-01 01:29), + (from=- [track=-, scheduled_track=-, level=0], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 01:28, mode="RENTAL", trip="-", end=2019-05-01 01:29), (from=- [track=-, scheduled_track=-, level=0], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 01:29, mode="WALK", trip="-", end=2019-05-01 01:38) ])", ss.str()); @@ -396,7 +398,8 @@ TEST(motis, routing) { "&toPlace=50.11347,8.67664" "&time=2019-05-01T01:25Z" "&timetableView=false" - "&preTransitModes=WALK,BIKE_RENTAL"); + "&useRoutedTransfers=true" + "&preTransitModes=WALK,RENTAL"); auto ss = std::stringstream{}; for (auto const& j : plan_response.itineraries_) { @@ -406,9 +409,9 @@ TEST(motis, routing) { EXPECT_EQ( R"(date=2019-05-01, start=01:25, end=03:14, duration=01:49, transfers=1, legs=[ (from=- [track=-, scheduled_track=-, level=0], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 01:25, mode="WALK", trip="-", end=2019-05-01 01:28), - (from=- [track=-, scheduled_track=-, level=0], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 01:28, mode="BIKE_RENTAL", trip="-", end=2019-05-01 01:29), + (from=- [track=-, scheduled_track=-, level=0], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 01:28, mode="RENTAL", trip="-", end=2019-05-01 01:29), (from=- [track=-, scheduled_track=-, level=0], to=test_DA_10 [track=10, scheduled_track=10, level=-1], start=2019-05-01 01:29, mode="WALK", trip="-", end=2019-05-01 01:37), - (from=test_DA_10 [track=10, scheduled_track=10, level=-1], to=test_FFM_10 [track=10, scheduled_track=10, level=0], start=2019-05-01 02:35, mode="HIGHSPEED_RAIL", trip="ICE ", end=2019-05-01 02:45), + (from=test_DA_10 [track=10, scheduled_track=10, level=-1], to=test_FFM_10 [track=10, scheduled_track=10, level=0], start=2019-05-01 02:35, mode="HIGHSPEED_RAIL", trip="ICE", end=2019-05-01 02:45), (from=test_FFM_10 [track=10, scheduled_track=10, level=0], to=test_de:6412:10:6:1 [track=U4, scheduled_track=U4, level=-2], start=2019-05-01 02:45, mode="WALK", trip="-", end=2019-05-01 02:49), (from=test_de:6412:10:6:1 [track=U4, scheduled_track=U4, level=-2], to=test_FFM_HAUPT_U [track=-, scheduled_track=-, level=-4], start=2019-05-01 03:05, mode="SUBWAY", trip="U4", end=2019-05-01 03:10), (from=test_FFM_HAUPT_U [track=-, scheduled_track=-, level=-4], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 03:10, mode="WALK", trip="-", end=2019-05-01 03:14) @@ -422,7 +425,8 @@ TEST(motis, routing) { "?fromPlace=49.87263,8.63127" "&toPlace=50.11347,8.67664" "&time=2019-05-01T01:25Z" - "&wheelchair=true" + "&pedestrianProfile=WHEELCHAIR" + "&useRoutedTransfers=true" "&timetableView=false"); auto ss = std::stringstream{}; @@ -433,7 +437,7 @@ TEST(motis, routing) { EXPECT_EQ( R"(date=2019-05-01, start=01:29, end=02:28, duration=01:03, transfers=1, legs=[ (from=- [track=-, scheduled_track=-, level=0], to=test_DA_10 [track=10, scheduled_track=10, level=-1], start=2019-05-01 01:29, mode="WALK", trip="-", end=2019-05-01 01:35), - (from=test_DA_10 [track=10, scheduled_track=10, level=-1], to=test_FFM_12 [track=12, scheduled_track=10, level=0], start=2019-05-01 01:35, mode="HIGHSPEED_RAIL", trip="ICE ", end=2019-05-01 01:55), + (from=test_DA_10 [track=10, scheduled_track=10, level=-1], to=test_FFM_12 [track=12, scheduled_track=10, level=0], start=2019-05-01 01:35, mode="HIGHSPEED_RAIL", trip="ICE", end=2019-05-01 01:55), (from=test_FFM_12 [track=12, scheduled_track=10, level=0], to=test_FFM_101 [track=101, scheduled_track=101, level=-3], start=2019-05-01 01:55, mode="WALK", trip="-", end=2019-05-01 02:01), (from=test_FFM_101 [track=101, scheduled_track=101, level=-3], to=test_FFM_HAUPT_S [track=-, scheduled_track=-, level=-3], start=2019-05-01 02:15, mode="METRO", trip="S3", end=2019-05-01 02:20), (from=test_FFM_HAUPT_S [track=-, scheduled_track=-, level=-3], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 02:20, mode="WALK", trip="-", end=2019-05-01 02:28) @@ -447,6 +451,7 @@ TEST(motis, routing) { "?fromPlace=49.87263,8.63127" "&toPlace=50.11347,8.67664" "&time=2019-05-01T01:25Z" + "&useRoutedTransfers=true" "&timetableView=false"); auto ss = std::stringstream{}; @@ -457,7 +462,7 @@ TEST(motis, routing) { EXPECT_EQ( R"(date=2019-05-01, start=01:25, end=02:14, duration=00:49, transfers=1, legs=[ (from=- [track=-, scheduled_track=-, level=0], to=test_DA_10 [track=10, scheduled_track=10, level=-1], start=2019-05-01 01:25, mode="WALK", trip="-", end=2019-05-01 01:28), - (from=test_DA_10 [track=10, scheduled_track=10, level=-1], to=test_FFM_12 [track=12, scheduled_track=10, level=0], start=2019-05-01 01:35, mode="HIGHSPEED_RAIL", trip="ICE ", end=2019-05-01 01:55), + (from=test_DA_10 [track=10, scheduled_track=10, level=-1], to=test_FFM_12 [track=12, scheduled_track=10, level=0], start=2019-05-01 01:35, mode="HIGHSPEED_RAIL", trip="ICE", end=2019-05-01 01:55), (from=test_FFM_12 [track=12, scheduled_track=10, level=0], to=test_de:6412:10:6:1 [track=U4, scheduled_track=U4, level=-2], start=2019-05-01 01:55, mode="WALK", trip="-", end=2019-05-01 01:59), (from=test_de:6412:10:6:1 [track=U4, scheduled_track=U4, level=-2], to=test_FFM_HAUPT_U [track=-, scheduled_track=-, level=-4], start=2019-05-01 02:05, mode="SUBWAY", trip="U4", end=2019-05-01 02:10), (from=test_FFM_HAUPT_U [track=-, scheduled_track=-, level=-4], to=- [track=-, scheduled_track=-, level=0], start=2019-05-01 02:10, mode="WALK", trip="-", end=2019-05-01 02:14) diff --git a/ui/package-lock.json b/ui/package-lock.json index 2e219b30e2..6db2c349dd 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -24,7 +24,7 @@ "@hey-api/openapi-ts": "^0.53.11", "@playwright/test": "^1.28.1", "@sveltejs/adapter-static": "^3.0.5", - "@sveltejs/kit": "^2.7.2", + "@sveltejs/kit": "^2.12.0", "@sveltejs/vite-plugin-svelte": "^4.0.0-next.6", "@types/eslint": "^8.56.0", "@types/polyline": "^0.1.32", @@ -57,6 +57,7 @@ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -68,6 +69,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -77,10 +79,11 @@ } }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.0.tgz", - "integrity": "sha512-pRrmXMCwnmrkS3MLgAIW5dXRzeTv6GLjkjb4HmxNnvAKXN1Nfzp4KmGADBQvlVUcqi+a5D+hfGDLLnd5NnYxog==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz", + "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==", "dev": true, + "license": "MIT", "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", @@ -94,9 +97,10 @@ } }, "node_modules/@deck.gl/core": { - "version": "9.0.33", - "resolved": "https://registry.npmjs.org/@deck.gl/core/-/core-9.0.33.tgz", - "integrity": "sha512-KTfanNfb0b/JKV6BFSzQ8uMC07Yy5zvzLnnfHLV4l4ostHdEaPHdBEr5IDhsSRMBgcYSfsML3NpTFncVom+IyA==", + "version": "9.0.40", + "resolved": "https://registry.npmjs.org/@deck.gl/core/-/core-9.0.40.tgz", + "integrity": "sha512-NfBXRTuiqhYE42dOz73XnKaO7YZH8qsR1/9U/6lSV/XKnfrFsbhhRUePz3Ik6S3GbVpOoqCDuTFf0i3Tj+pxyw==", + "license": "MIT", "dependencies": { "@loaders.gl/core": "^4.2.0", "@loaders.gl/images": "^4.2.0", @@ -117,9 +121,10 @@ } }, "node_modules/@deck.gl/layers": { - "version": "9.0.33", - "resolved": "https://registry.npmjs.org/@deck.gl/layers/-/layers-9.0.33.tgz", - "integrity": "sha512-PBtxOuSq5QmlQ1N27FUIC3sC5iLFqAsdyEXUkjzWMPdLGjeow5xx32j3E0iag//ShgW4jiffS1dqgYywbjwYhg==", + "version": "9.0.40", + "resolved": "https://registry.npmjs.org/@deck.gl/layers/-/layers-9.0.40.tgz", + "integrity": "sha512-7emTkPLVWeVuV5VPBTmHDJegkGH1i76GuvhHNXikper/Zwljf9QVUacPqk3or4lHBCzzlkeccCsRmTd3l+MBYQ==", + "license": "MIT", "dependencies": { "@loaders.gl/images": "^4.2.0", "@loaders.gl/schema": "^4.2.0", @@ -137,9 +142,10 @@ } }, "node_modules/@deck.gl/mapbox": { - "version": "9.0.33", - "resolved": "https://registry.npmjs.org/@deck.gl/mapbox/-/mapbox-9.0.33.tgz", - "integrity": "sha512-8C4xOghijVnH0nHEAmt/QK8JUOIE5fg6rN/dmYuVe/QyLFsgh27l3MxY6EgWv1nnSTRCCnyX1i3tjxsdCKRPmw==", + "version": "9.0.40", + "resolved": "https://registry.npmjs.org/@deck.gl/mapbox/-/mapbox-9.0.40.tgz", + "integrity": "sha512-idx2f8vhoCplT2ss3wwl4FLjo4R2iLYmkgaFQKhCQC/yW/abqZLSdl7BJJ8L+Yo8Ka67pIUXChHDLigpVKUB1w==", + "license": "MIT", "dependencies": { "@luma.gl/constants": "~9.0.27", "@math.gl/web-mercator": "^4.0.0" @@ -157,6 +163,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -173,6 +180,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -189,6 +197,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -205,6 +214,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -221,6 +231,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -237,6 +248,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -253,6 +265,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -269,6 +282,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -285,6 +299,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -301,6 +316,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -317,6 +333,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -333,6 +350,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -349,6 +367,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -365,6 +384,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -381,6 +401,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -397,6 +418,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -413,6 +435,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -429,6 +452,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -445,6 +469,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -461,6 +486,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -477,6 +503,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -493,6 +520,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -509,6 +537,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -518,25 +547,30 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -546,6 +580,7 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -569,6 +604,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -579,6 +615,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -591,54 +628,56 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@floating-ui/core": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", - "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.8" + "@floating-ui/utils": "^0.2.9" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.12", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", - "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", "dev": true, "license": "MIT", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.8" + "@floating-ui/utils": "^0.2.9" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", - "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", "dev": true, "license": "MIT" }, "node_modules/@hey-api/client-fetch": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@hey-api/client-fetch/-/client-fetch-0.4.2.tgz", - "integrity": "sha512-9BqcLTjsM3rWbads3afJkELS86vK7EqJvYgT429EVS9IO/kN75HEka3Ay/k142xCHSfXOuOShMdDam3nbG8wVA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@hey-api/client-fetch/-/client-fetch-0.4.4.tgz", + "integrity": "sha512-ebh1JjUdMAqes/Rg8OvbjDqGWGNhgHgmPtHlkIOUtj3y2mUXqX2g9sVoI/rSKW/FdADPng/90k5AL7bwT8W2lA==", "license": "MIT", "funding": { - "url": "https://github.com/sponsors/mrlubos" + "url": "https://github.com/sponsors/hey-api" } }, "node_modules/@hey-api/openapi-ts": { - "version": "0.53.11", - "resolved": "https://registry.npmjs.org/@hey-api/openapi-ts/-/openapi-ts-0.53.11.tgz", - "integrity": "sha512-PaO+o0jDhfHVS5SjtonP5CzP/NYoW8dVZUn8WthSgzpgPts8AiWYXplOyk5uEnM4ZxbkZbeTiREwaNLnJmXlTQ==", + "version": "0.53.12", + "resolved": "https://registry.npmjs.org/@hey-api/openapi-ts/-/openapi-ts-0.53.12.tgz", + "integrity": "sha512-cOm8AlUqJIWdLXq+Pk4mTXhEApRSc9xEWTVT8MZAyEqrN1Yhiisl2wyZGH9quzKpolq+oqvgcx61txtwHwi8vQ==", "dev": true, + "license": "FSL-1.1-MIT", "dependencies": { - "@apidevtools/json-schema-ref-parser": "11.7.0", + "@apidevtools/json-schema-ref-parser": "11.7.2", "c12": "2.0.1", "commander": "12.1.0", "handlebars": "4.7.8" @@ -662,6 +701,7 @@ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -676,6 +716,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -686,6 +727,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -698,6 +740,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -711,12 +754,13 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@internationalized/date": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.5.6.tgz", - "integrity": "sha512-jLxQjefH9VI5P9UQuqB6qNKnvFt1Ky1TPIzHGsIlCi7sZZoMR8SdYbBGRvM0y+Jtb+ez4ieBzmiAUcpmPYpyOw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.7.0.tgz", + "integrity": "sha512-VJ5WS3fcVx0bejE/YHfbDKR/yawZgKqn/if+oEeLqNwBtPzVB06olkfcnojTmEMX+gTpH+FlQ69SHNitJ8/erQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -728,6 +772,7 @@ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -745,6 +790,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -757,6 +803,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -772,6 +819,7 @@ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -780,9 +828,10 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -796,6 +845,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -804,6 +854,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -811,12 +862,14 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -826,37 +879,41 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@loaders.gl/core": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@loaders.gl/core/-/core-4.3.1.tgz", - "integrity": "sha512-kFJQKpNmpYFdZdwPG1enZz18yUaUV9Mrr87KPb4hjf69p1UJuLQ2+wPxL/Ws9Di/aekAPoG9eCeSjyva8EIH0g==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@loaders.gl/core/-/core-4.3.3.tgz", + "integrity": "sha512-RaQ3uNg4ZaVqDRgvJ2CjaOjeeHdKvbKuzFFgbGnflVB9is5bu+h3EKc3Jke7NGVvLBsZ6oIXzkwHijVsMfxv8g==", + "license": "MIT", "dependencies": { - "@loaders.gl/loader-utils": "4.3.1", - "@loaders.gl/schema": "4.3.1", - "@loaders.gl/worker-utils": "4.3.1", + "@loaders.gl/loader-utils": "4.3.3", + "@loaders.gl/schema": "4.3.3", + "@loaders.gl/worker-utils": "4.3.3", "@probe.gl/log": "^4.0.2" } }, "node_modules/@loaders.gl/images": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@loaders.gl/images/-/images-4.3.1.tgz", - "integrity": "sha512-Epd64AtEo3oWrhZlftzMYNSC9b3fOfNXpKqw0itIJcSP3eC63JnUsBoYGNZ//vYMVXOCuMGJAAjCdMlNtez20Q==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@loaders.gl/images/-/images-4.3.3.tgz", + "integrity": "sha512-s4InjIXqEu0T7anZLj4OBUuDBt2BNnAD0GLzSexSkBfQZfpXY0XJNl4mMf5nUKb5NDfXhIKIqv8y324US+I28A==", + "license": "MIT", "dependencies": { - "@loaders.gl/loader-utils": "4.3.1" + "@loaders.gl/loader-utils": "4.3.3" }, "peerDependencies": { "@loaders.gl/core": "^4.3.0" } }, "node_modules/@loaders.gl/loader-utils": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-4.3.1.tgz", - "integrity": "sha512-+IGK18EHJCfw2N+x8Fqln7hea4HJ5U8ZLxOUyRDS455ActvB5FPaQox1ko2B9/kPHhVFynglS+xoWczHHzwJlQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-4.3.3.tgz", + "integrity": "sha512-8erUIwWLiIsZX36fFa/seZsfTsWlLk72Sibh/YZJrPAefuVucV4mGGzMBZ96LE2BUfJhadn250eio/59TUFbNw==", + "license": "MIT", "dependencies": { - "@loaders.gl/schema": "4.3.1", - "@loaders.gl/worker-utils": "4.3.1", + "@loaders.gl/schema": "4.3.3", + "@loaders.gl/worker-utils": "4.3.3", "@probe.gl/log": "^4.0.2", "@probe.gl/stats": "^4.0.2" }, @@ -865,9 +922,10 @@ } }, "node_modules/@loaders.gl/schema": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@loaders.gl/schema/-/schema-4.3.1.tgz", - "integrity": "sha512-sKhP4rL4JMMVHrZWdYL8KxO7nbbjNIbzreL7ymwNV7zCAS8JW+QjCoV1hEicl5Ma8OP5Lte/cTxpOz8MiOmMXQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@loaders.gl/schema/-/schema-4.3.3.tgz", + "integrity": "sha512-zacc9/8je+VbuC6N/QRfiTjRd+BuxsYlddLX1u5/X/cg9s36WZZBlU1oNKUgTYe8eO6+qLyYx77yi+9JbbEehw==", + "license": "MIT", "dependencies": { "@types/geojson": "^7946.0.7" }, @@ -876,22 +934,25 @@ } }, "node_modules/@loaders.gl/worker-utils": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-4.3.1.tgz", - "integrity": "sha512-WpJ5N9jMI/ZDefVjqAMBWHux8tKUTW5jtj7espddKW1Q2DQIrdXywVQO0SouUiRJlcVot5s5BlHD0JZwKfAlZw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-4.3.3.tgz", + "integrity": "sha512-eg45Ux6xqsAfqPUqJkhmbFZh9qfmYuPfA+34VcLtfeXIwAngeP6o4SrTmm9LWLGUKiSh47anCEV1p7borDgvGQ==", + "license": "MIT", "peerDependencies": { "@loaders.gl/core": "^4.3.0" } }, "node_modules/@luma.gl/constants": { - "version": "9.0.27", - "resolved": "https://registry.npmjs.org/@luma.gl/constants/-/constants-9.0.27.tgz", - "integrity": "sha512-NBkMim3u0xt4UDe4e69L6E/pq5XNxfX60GrggJDzfilVRfIbx5XwKhBXTyNjjtNEk4oc6uYLHWd/05jGRHcfLg==" + "version": "9.0.28", + "resolved": "https://registry.npmjs.org/@luma.gl/constants/-/constants-9.0.28.tgz", + "integrity": "sha512-mw3YwYfCbpCa8y28nNZGaJemprSkqthsunz0V79qpnMrFD3pOMIh+rw/hjQuqVW9ffmSXx+xY2bI8FT1YC8f7A==", + "license": "MIT" }, "node_modules/@luma.gl/core": { - "version": "9.0.27", - "resolved": "https://registry.npmjs.org/@luma.gl/core/-/core-9.0.27.tgz", - "integrity": "sha512-7OXM8ZknTuqt10nL8XHg3YzaHESzU2pSh+6BknLJbLM+UjNWOkDHArF6pRYu96Om0QsnOMK/RXKqXBr+Ni0gvw==", + "version": "9.0.28", + "resolved": "https://registry.npmjs.org/@luma.gl/core/-/core-9.0.28.tgz", + "integrity": "sha512-5PHSEO70o+bze7uax/2e5YTNUAqwcPXrABOvvxm+ihw+guWpqIHGt8wStoY2HKwmQhF8eT4f7nc762E/oyl4NA==", + "license": "MIT", "dependencies": { "@math.gl/types": "^4.0.0", "@probe.gl/env": "^4.0.2", @@ -901,11 +962,12 @@ } }, "node_modules/@luma.gl/engine": { - "version": "9.0.27", - "resolved": "https://registry.npmjs.org/@luma.gl/engine/-/engine-9.0.27.tgz", - "integrity": "sha512-O4e7RbIjBJX5WLs8HJLjpccYEkcans4pz8+TI8Y7BO7gDq9ZbEASbVd5CT53jFLfTjnRuqAOpElfaXwQ/B7oWg==", + "version": "9.0.28", + "resolved": "https://registry.npmjs.org/@luma.gl/engine/-/engine-9.0.28.tgz", + "integrity": "sha512-EidAG/1Sgq0OeoyrebkcrC5TMvfK8ycIpSAjIRdi8hjwpHIoHFj5P3MWeApTZ1HV0DroxChzrxRCHYylI8svPQ==", + "license": "MIT", "dependencies": { - "@luma.gl/shadertools": "9.0.27", + "@luma.gl/shadertools": "9.0.28", "@math.gl/core": "^4.0.0", "@probe.gl/log": "^4.0.2", "@probe.gl/stats": "^4.0.2" @@ -915,9 +977,10 @@ } }, "node_modules/@luma.gl/shadertools": { - "version": "9.0.27", - "resolved": "https://registry.npmjs.org/@luma.gl/shadertools/-/shadertools-9.0.27.tgz", - "integrity": "sha512-JcOuYH2Fh4uljinXKbR04en1dqEthlJNdqV5efQ0fE9NetJul7Pkq+N1v/Oo8/vmJn9ZqEC49dgZHwtbzY8UnQ==", + "version": "9.0.28", + "resolved": "https://registry.npmjs.org/@luma.gl/shadertools/-/shadertools-9.0.28.tgz", + "integrity": "sha512-FFh9udQTcPOTGpMKjYbCqZ7M6SLiaER93afCpQoYT6i36bPjTX4WX51ijFxA1ABJyvsZAo4BLR54tF++jNxyEQ==", + "license": "MIT", "dependencies": { "@math.gl/core": "^4.0.0", "@math.gl/types": "^4.0.0", @@ -928,11 +991,12 @@ } }, "node_modules/@luma.gl/webgl": { - "version": "9.0.27", - "resolved": "https://registry.npmjs.org/@luma.gl/webgl/-/webgl-9.0.27.tgz", - "integrity": "sha512-GOzOiDfTFgT4If1XSeCqXswKrgXVwTyuf/1W21Vv7fs5inub5p3LISmZglrt/RcdaGyXQQ5zEqf/+x67dGTeYw==", + "version": "9.0.28", + "resolved": "https://registry.npmjs.org/@luma.gl/webgl/-/webgl-9.0.28.tgz", + "integrity": "sha512-CvEUlKkppNCdmr/Ilyb6ZzOSDaLDmhOIfR1wBDj9Gf8QJB7yZkrzapstHKkyvmKuf480ATamjlSABkYUD0CguQ==", + "license": "MIT", "dependencies": { - "@luma.gl/constants": "9.0.27", + "@luma.gl/constants": "9.0.28", "@probe.gl/env": "^4.0.2" }, "peerDependencies": { @@ -943,6 +1007,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "license": "ISC", "dependencies": { "get-stream": "^6.0.1", "minimist": "^1.2.6" @@ -962,22 +1027,26 @@ "node_modules/@mapbox/point-geometry": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", + "license": "ISC" }, "node_modules/@mapbox/tiny-sdf": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", - "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==" + "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==", + "license": "BSD-2-Clause" }, "node_modules/@mapbox/unitbezier": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", - "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" }, "node_modules/@mapbox/vector-tile": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "license": "BSD-3-Clause", "dependencies": { "@mapbox/point-geometry": "~0.1.0" } @@ -986,6 +1055,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "license": "ISC", "engines": { "node": ">=6.0.0" } @@ -994,6 +1064,7 @@ "version": "20.4.0", "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz", "integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==", + "license": "ISC", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.1", @@ -1012,12 +1083,14 @@ "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/quickselect": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", + "license": "ISC" }, "node_modules/@math.gl/core": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@math.gl/core/-/core-4.1.0.tgz", "integrity": "sha512-FrdHBCVG3QdrworwrUSzXIaK+/9OCRLscxI2OUy6sLOHyHgBMyfnEGs99/m3KNvs+95BsnQLWklVfpKfQzfwKA==", + "license": "MIT", "dependencies": { "@math.gl/types": "4.1.0" } @@ -1026,6 +1099,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/@math.gl/polygon/-/polygon-4.1.0.tgz", "integrity": "sha512-YA/9PzaCRHbIP5/0E9uTYrqe+jsYTQoqoDWhf6/b0Ixz8bPZBaGDEafLg3z7ffBomZLacUty9U3TlPjqMtzPjA==", + "license": "MIT", "dependencies": { "@math.gl/core": "4.1.0" } @@ -1033,17 +1107,20 @@ "node_modules/@math.gl/sun": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@math.gl/sun/-/sun-4.1.0.tgz", - "integrity": "sha512-i3q6OCBLSZ5wgZVhXg+X7gsjY/TUtuFW/2KBiq/U1ypLso3S4sEykoU/MGjxUv1xiiGtr+v8TeMbO1OBIh/HmA==" + "integrity": "sha512-i3q6OCBLSZ5wgZVhXg+X7gsjY/TUtuFW/2KBiq/U1ypLso3S4sEykoU/MGjxUv1xiiGtr+v8TeMbO1OBIh/HmA==", + "license": "MIT" }, "node_modules/@math.gl/types": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@math.gl/types/-/types-4.1.0.tgz", - "integrity": "sha512-clYZdHcmRvMzVK5fjeDkQlHUzXQSNdZ7s4xOqC3nJPgz4C/TZkUecTo9YS4PruZqtDda/ag4erndP0MIn40dGA==" + "integrity": "sha512-clYZdHcmRvMzVK5fjeDkQlHUzXQSNdZ7s4xOqC3nJPgz4C/TZkUecTo9YS4PruZqtDda/ag4erndP0MIn40dGA==", + "license": "MIT" }, "node_modules/@math.gl/web-mercator": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@math.gl/web-mercator/-/web-mercator-4.1.0.tgz", "integrity": "sha512-HZo3vO5GCMkXJThxRJ5/QYUYRr3XumfT8CzNNCwoJfinxy5NtKUd7dusNTXn7yJ40UoB8FMIwkVwNlqaiRZZAw==", + "license": "MIT", "dependencies": { "@math.gl/core": "4.1.0" } @@ -1053,6 +1130,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1066,6 +1144,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -1075,6 +1154,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1088,18 +1168,20 @@ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=14" } }, "node_modules/@playwright/test": { - "version": "1.48.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.1.tgz", - "integrity": "sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", + "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "playwright": "1.48.1" + "playwright": "1.49.1" }, "bin": { "playwright": "cli.js" @@ -1112,17 +1194,20 @@ "version": "1.0.0-next.28", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@probe.gl/env": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-4.0.9.tgz", - "integrity": "sha512-AOmVMD0/j78mX+k4+qX7ZhE0sY9H+EaJgIO6trik0BwV6VcrwxTGCGFAeuRsIGhETDnye06tkLXccYatYxAYwQ==" + "integrity": "sha512-AOmVMD0/j78mX+k4+qX7ZhE0sY9H+EaJgIO6trik0BwV6VcrwxTGCGFAeuRsIGhETDnye06tkLXccYatYxAYwQ==", + "license": "MIT" }, "node_modules/@probe.gl/log": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-4.0.9.tgz", "integrity": "sha512-ebuZaodSRE9aC+3bVC7cKRHT8garXeT1jTbj1R5tQRqQYc9iGeT3iemVOHx5bN9Q6gAs/0j54iPI+1DvWMAW4A==", + "license": "MIT", "dependencies": { "@probe.gl/env": "4.0.9" } @@ -1130,211 +1215,270 @@ "node_modules/@probe.gl/stats": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-4.0.9.tgz", - "integrity": "sha512-Q9Xt/sJUQaMsbjRKjOscv2t7wXIymTrOEJ4a3da4FTCn7bkKvcdxdyFAQySCrtPxE+YZ5I5lXpWPgv9BwmpE1g==" + "integrity": "sha512-Q9Xt/sJUQaMsbjRKjOscv2t7wXIymTrOEJ4a3da4FTCn7bkKvcdxdyFAQySCrtPxE+YZ5I5lXpWPgv9BwmpE1g==", + "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", - "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", + "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", - "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", + "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", - "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", + "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", - "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", + "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", + "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", + "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", - "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", + "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", - "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", + "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", - "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", + "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", - "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", + "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", + "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", - "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", + "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", - "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", + "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", - "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", + "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", - "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", + "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", - "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", + "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", - "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", + "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", - "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", + "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", - "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", + "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1344,12 +1488,13 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sveltejs/adapter-static": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.6.tgz", - "integrity": "sha512-MGJcesnJWj7FxDcB/GbrdYD3q24Uk0PIL4QIX149ku+hlJuj//nxUbb0HxUTpjkecWfHjVveSUnUaQWnPRXlpg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.8.tgz", + "integrity": "sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -1357,25 +1502,23 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.8.1.tgz", - "integrity": "sha512-uuOfFwZ4xvnfPsiTB6a4H1ljjTUksGhWnYq5X/Y9z4x5+3uM2Md8q/YVeHL+7w+mygAwoEFdgKZ8YkUuk+VKww==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.16.0.tgz", + "integrity": "sha512-S9i1ZWKqluzoaJ6riYnEdbe+xJluMTMkhABouBa66GaWcAyCjW/jAc0NdJQJ/DXyK1CnP5quBW25e99MNyvLxA==", "dev": true, - "hasInstallScript": true, "license": "MIT", "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", "devalue": "^5.1.0", - "esm-env": "^1.0.0", + "esm-env": "^1.2.2", "import-meta-resolve": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", - "sirv": "^3.0.0", - "tiny-glob": "^0.2.9" + "sirv": "^3.0.0" }, "bin": { "svelte-kit": "svelte-kit.js" @@ -1384,16 +1527,17 @@ "node": ">=18.13" }, "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.3" + "vite": "^5.0.3 || ^6.0.0" } }, "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.0.tgz", - "integrity": "sha512-kpVJwF+gNiMEsoHaw+FJL76IYiwBikkxYU83+BpqQLdVMff19KeRKLd2wisS8niNBMJ2omv5gG+iGDDwd8jzag==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.4.tgz", + "integrity": "sha512-0ba1RQ/PHen5FGpdSrW7Y3fAMQjrXantECALeOiOdBdzR5+5vPP6HVZRLmZaQL+W8m++o+haIAKq5qT+MiZ7VA==", "dev": true, + "license": "MIT", "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0||^3.0.0", "debug": "^4.3.7", @@ -1415,6 +1559,7 @@ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-3.0.1.tgz", "integrity": "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.3.7" }, @@ -1438,53 +1583,57 @@ } }, "node_modules/@turf/helpers": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.1.0.tgz", - "integrity": "sha512-dTeILEUVeNbaEeoZUOhxH5auv7WWlOShbx7QSd4s0T4Z0/iz90z9yaVCtZOLbU89umKotwKaJQltBNO9CzVgaQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.2.0.tgz", + "integrity": "sha512-cXo7bKNZoa7aC7ydLmUR02oB3IgDe7MxiPuRz3cCtYQHn+BJ6h1tihmamYDWWUlPHgSNF0i3ATc4WmDECZafKw==", + "license": "MIT", "dependencies": { "@types/geojson": "^7946.0.10", - "tslib": "^2.6.2" + "tslib": "^2.8.1" }, "funding": { "url": "https://opencollective.com/turf" } }, "node_modules/@turf/invariant": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.1.0.tgz", - "integrity": "sha512-OCLNqkItBYIP1nE9lJGuIUatWGtQ4rhBKAyTfFu0z8npVzGEYzvguEeof8/6LkKmTTEHW53tCjoEhSSzdRh08Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.2.0.tgz", + "integrity": "sha512-kV4u8e7Gkpq+kPbAKNC21CmyrXzlbBgFjO1PhrHPgEdNqXqDawoZ3i6ivE3ULJj2rSesCjduUaC/wyvH/sNr2Q==", + "license": "MIT", "dependencies": { - "@turf/helpers": "^7.1.0", + "@turf/helpers": "^7.2.0", "@types/geojson": "^7946.0.10", - "tslib": "^2.6.2" + "tslib": "^2.8.1" }, "funding": { "url": "https://opencollective.com/turf" } }, "node_modules/@turf/rhumb-bearing": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-7.1.0.tgz", - "integrity": "sha512-ESZt70eOljHVnQMFKIdiu8LIHuQlpZgzh2nqSfV40BrYjsjI/sBKeK+sp2cBWk88nsSDlriPuMTNh4f50Jqpkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-7.2.0.tgz", + "integrity": "sha512-jbdexlrR8X2ZauUciHx3tRwG+BXoMXke4B8p8/IgDlAfIrVdzAxSQN89FMzIKnjJ/kdLjo9bFGvb92bu31Etug==", + "license": "MIT", "dependencies": { - "@turf/helpers": "^7.1.0", - "@turf/invariant": "^7.1.0", + "@turf/helpers": "^7.2.0", + "@turf/invariant": "^7.2.0", "@types/geojson": "^7946.0.10", - "tslib": "^2.6.2" + "tslib": "^2.8.1" }, "funding": { "url": "https://opencollective.com/turf" } }, "node_modules/@turf/rhumb-distance": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-7.1.0.tgz", - "integrity": "sha512-fR1V+yC4E1tnbdThomosiLcv0PQOwbfLSPM8rSWuxbMcJtffsncWxyJ0+N1F5juuHbcdaYhlduX8ri5I0ZCejw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-7.2.0.tgz", + "integrity": "sha512-NsijTPON1yOc9tirRPEQQuJ5aQi7pREsqchQquaYKbHNWsexZjcDi4wnw2kM3Si4XjmgynT+2f7aXH7FHarHzw==", + "license": "MIT", "dependencies": { - "@turf/helpers": "^7.1.0", - "@turf/invariant": "^7.1.0", + "@turf/helpers": "^7.2.0", + "@turf/invariant": "^7.2.0", "@types/geojson": "^7946.0.10", - "tslib": "^2.6.2" + "tslib": "^2.8.1" }, "funding": { "url": "https://opencollective.com/turf" @@ -1494,13 +1643,15 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/eslint": { "version": "8.56.12", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -1509,17 +1660,20 @@ "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" }, "node_modules/@types/geojson": { - "version": "7946.0.14", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + "version": "7946.0.15", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz", + "integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==", + "license": "MIT" }, "node_modules/@types/geojson-vt": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "license": "MIT", "dependencies": { "@types/geojson": "*" } @@ -1527,23 +1681,27 @@ "node_modules/@types/hammerjs": { "version": "2.0.46", "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz", - "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==" + "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==", + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/mapbox__point-geometry": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", - "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==" + "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", + "license": "MIT" }, "node_modules/@types/mapbox__vector-tile": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", + "license": "MIT", "dependencies": { "@types/geojson": "*", "@types/mapbox__point-geometry": "*", @@ -1553,18 +1711,21 @@ "node_modules/@types/offscreencanvas": { "version": "2019.7.3", "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", - "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==" + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", + "license": "MIT" }, "node_modules/@types/pbf": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", - "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==" + "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", + "license": "MIT" }, "node_modules/@types/polyline": { "version": "0.1.32", "resolved": "https://registry.npmjs.org/@types/polyline/-/polyline-0.1.32.tgz", "integrity": "sha512-EC4sIW6rxpX7KD0cmAe/VVhQOR8T1HX8/LEDZ88Gk6ULwd/EiQkVdi8Mz7Yyq81EycU8IMbOyqFEqtna2zEtsA==", "dev": true, + "license": "MIT", "dependencies": { "@types/geojson": "*" } @@ -1573,12 +1734,14 @@ "version": "2.0.10", "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/supercluster": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "license": "MIT", "dependencies": { "@types/geojson": "*" } @@ -1588,6 +1751,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -1621,6 +1785,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", @@ -1649,6 +1814,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0" @@ -1666,6 +1832,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/utils": "7.18.0", @@ -1693,6 +1860,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -1706,6 +1874,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", @@ -1734,6 +1903,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -1756,6 +1926,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" @@ -1769,16 +1940,18 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", + "dev": true, + "license": "ISC" }, "node_modules/@vitest/expect": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, + "license": "MIT", "dependencies": { "@vitest/spy": "1.6.0", "@vitest/utils": "1.6.0", @@ -1793,6 +1966,7 @@ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, + "license": "MIT", "dependencies": { "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", @@ -1807,6 +1981,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^1.0.0" }, @@ -1822,6 +1997,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.20" }, @@ -1834,6 +2010,7 @@ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, + "license": "MIT", "dependencies": { "magic-string": "^0.30.5", "pathe": "^1.1.1", @@ -1848,6 +2025,7 @@ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, + "license": "MIT", "dependencies": { "tinyspy": "^2.2.0" }, @@ -1860,6 +2038,7 @@ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, + "license": "MIT", "dependencies": { "diff-sequences": "^29.6.3", "estree-walker": "^3.0.3", @@ -1871,9 +2050,10 @@ } }, "node_modules/acorn": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", - "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -1886,6 +2066,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -1894,6 +2075,7 @@ "version": "1.4.13", "resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz", "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==", + "license": "MIT", "peerDependencies": { "acorn": ">=8.9.0" } @@ -1903,6 +2085,7 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, + "license": "MIT", "dependencies": { "acorn": "^8.11.0" }, @@ -1915,6 +2098,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1931,6 +2115,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1940,6 +2125,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -1954,13 +2140,15 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1973,18 +2161,21 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", "engines": { "node": ">= 0.4" } @@ -1994,6 +2185,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2003,6 +2195,7 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -2026,6 +2219,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "browserslist": "^4.23.3", "caniuse-lite": "^1.0.30001646", @@ -2048,6 +2242,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", "engines": { "node": ">= 0.4" } @@ -2056,13 +2251,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -2071,9 +2268,9 @@ } }, "node_modules/bits-ui": { - "version": "1.0.0-next.63", - "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-1.0.0-next.63.tgz", - "integrity": "sha512-3z4+N+KudMK8AeBzhy/0568zVoEJCUgL4RkElB41BWGjofk68en2TaAfKFhhc/bn4z+uKrs9r1NtybDdsy0bpA==", + "version": "1.0.0-next.77", + "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-1.0.0-next.77.tgz", + "integrity": "sha512-IV0AyVEvsRkXv4s/fl4iea5E9W2b9EBf98s9mRMKMc1xHxM9MmtM2r6MZMqftHQ/c+gHTIt3A9EKuTlh7uay8w==", "dev": true, "license": "MIT", "dependencies": { @@ -2081,8 +2278,8 @@ "@floating-ui/dom": "^1.6.7", "@internationalized/date": "^3.5.6", "esm-env": "^1.1.2", - "runed": "^0.15.2", - "svelte-toolbelt": "^0.4.4" + "runed": "^0.22.0", + "svelte-toolbelt": "^0.7.0" }, "engines": { "node": ">=18", @@ -2092,7 +2289,7 @@ "url": "https://github.com/sponsors/huntabyte" }, "peerDependencies": { - "svelte": "^5.0.0-next.1" + "svelte": "^5.11.0" } }, "node_modules/brace-expansion": { @@ -2100,6 +2297,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -2109,6 +2307,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -2117,9 +2316,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "dev": true, "funding": [ { @@ -2135,10 +2334,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { @@ -2153,6 +2353,7 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -2162,6 +2363,7 @@ "resolved": "https://registry.npmjs.org/c12/-/c12-2.0.1.tgz", "integrity": "sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^4.0.1", "confbox": "^0.1.7", @@ -2190,6 +2392,7 @@ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2199,6 +2402,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2208,14 +2412,15 @@ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001669", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", - "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", + "version": "1.0.30001692", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz", + "integrity": "sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==", "dev": true, "funding": [ { @@ -2230,13 +2435,15 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chai": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", "dev": true, + "license": "MIT", "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", @@ -2255,6 +2462,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2271,6 +2479,7 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "license": "MIT", "dependencies": { "get-func-name": "^2.0.2" }, @@ -2279,10 +2488,11 @@ } }, "node_modules/chokidar": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", - "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, + "license": "MIT", "dependencies": { "readdirp": "^4.0.1" }, @@ -2298,6 +2508,7 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -2307,6 +2518,7 @@ "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", "dev": true, + "license": "MIT", "dependencies": { "consola": "^3.2.3" } @@ -2315,7 +2527,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2326,6 +2537,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2337,18 +2549,21 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT" }, "node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" } @@ -2357,19 +2572,22 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/confbox": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/consola": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", - "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", + "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", "dev": true, + "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" } @@ -2379,6 +2597,7 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2403,6 +2622,7 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -2411,10 +2631,11 @@ } }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -2432,6 +2653,7 @@ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, + "license": "MIT", "dependencies": { "type-detect": "^4.0.0" }, @@ -2443,13 +2665,15 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2458,19 +2682,22 @@ "version": "6.1.4", "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/destr": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.3.tgz", "integrity": "sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/detect-indent": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2479,19 +2706,22 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", - "dev": true - }, + "dev": true, + "license": "MIT" + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -2501,6 +2731,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -2512,13 +2743,15 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -2527,10 +2760,11 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -2541,31 +2775,36 @@ "node_modules/earcut": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", + "license": "ISC" }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.43", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.43.tgz", - "integrity": "sha512-NxnmFBHDl5Sachd2P46O7UJiMaMHMLSofoIWVJq3mj8NJgG0umiSeljAVP9lGzjI0UDLJJ5jjoGjcrB8RSbjLQ==", - "dev": true + "version": "1.5.83", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.83.tgz", + "integrity": "sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ==", + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/es6-promise": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/esbuild": { "version": "0.21.5", @@ -2573,6 +2812,7 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -2610,6 +2850,7 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2619,6 +2860,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2632,6 +2874,7 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -2687,6 +2930,7 @@ "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.4" }, @@ -2702,6 +2946,7 @@ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, + "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -2710,10 +2955,11 @@ } }, "node_modules/eslint-plugin-svelte": { - "version": "2.46.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.0.tgz", - "integrity": "sha512-1A7iEMkzmCZ9/Iz+EAfOGYL8IoIG6zeKEq1SmpxGeM5SXmoQq+ZNnCpXFVJpsxPWYx8jIVGMerQMzX20cqUl0g==", + "version": "2.46.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.1.tgz", + "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@jridgewell/sourcemap-codec": "^1.4.15", @@ -2748,6 +2994,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -2764,6 +3011,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2776,6 +3024,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2786,6 +3035,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2794,9 +3044,9 @@ } }, "node_modules/esm-env": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.1.4.tgz", - "integrity": "sha512-oO82nKPHKkzIj/hbtuDYy/JHqBHFlMIW36SDiPCVsj87ntDLcWN+sJ1erdVryd4NxODacFTsdrIE3b7IamqbOg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", "license": "MIT" }, "node_modules/espree": { @@ -2804,6 +3054,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -2821,6 +3072,7 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -2829,12 +3081,12 @@ } }, "node_modules/esrap": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.2.tgz", - "integrity": "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.3.tgz", + "integrity": "sha512-Xddc1RsoFJ4z9nR7W7BFaEPIp4UXoeQ0+077UdWLxbafMQFyU79sQJMk7kxNgRwQ9/aVgaKacCHC2pUACGwmYw==", + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15", - "@types/estree": "^1.0.1" + "@jridgewell/sourcemap-codec": "^1.4.15" } }, "node_modules/esrecurse": { @@ -2842,6 +3094,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -2854,6 +3107,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -2863,6 +3117,7 @@ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" } @@ -2872,6 +3127,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -2881,6 +3137,7 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", @@ -2904,6 +3161,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -2915,19 +3173,21 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -2938,6 +3198,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -2949,19 +3210,22 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", + "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -2971,6 +3235,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -2983,6 +3248,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2995,6 +3261,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -3011,6 +3278,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -3021,16 +3289,18 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -3047,6 +3317,7 @@ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, @@ -3060,6 +3331,7 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -3072,6 +3344,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -3083,7 +3356,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.2", @@ -3091,6 +3365,7 @@ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3104,6 +3379,7 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3112,6 +3388,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/geojson/-/geojson-0.5.0.tgz", "integrity": "sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==", + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -3119,13 +3396,15 @@ "node_modules/geojson-vt": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", - "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==" + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", + "license": "ISC" }, "node_modules/get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -3134,6 +3413,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -3146,6 +3426,7 @@ "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.3.tgz", "integrity": "sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==", "dev": true, + "license": "MIT", "dependencies": { "citty": "^0.1.6", "consola": "^3.2.3", @@ -3163,7 +3444,8 @@ "node_modules/gl-matrix": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", - "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" + "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==", + "license": "MIT" }, "node_modules/glob": { "version": "7.2.3", @@ -3171,6 +3453,7 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3191,6 +3474,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -3203,6 +3487,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3213,6 +3498,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3224,6 +3510,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", + "license": "MIT", "dependencies": { "ini": "^4.1.3", "kind-of": "^6.0.3", @@ -3237,6 +3524,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", "engines": { "node": ">=16" } @@ -3245,6 +3533,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -3260,6 +3549,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -3270,17 +3560,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true - }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -3296,28 +3581,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hammerjs": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==", + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -3327,6 +3609,7 @@ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", @@ -3348,6 +3631,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3357,6 +3641,7 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -3369,6 +3654,7 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=16.17.0" } @@ -3390,13 +3676,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -3406,6 +3694,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -3422,6 +3711,7 @@ "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3432,6 +3722,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -3442,6 +3733,7 @@ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -3451,12 +3743,14 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ini": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -3473,6 +3767,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -3481,10 +3776,11 @@ } }, "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -3500,6 +3796,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3509,6 +3806,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3518,6 +3816,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -3530,6 +3829,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3539,16 +3839,18 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-reference": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", - "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "license": "MIT", "dependencies": { - "@types/estree": "*" + "@types/estree": "^1.0.6" } }, "node_modules/is-stream": { @@ -3556,6 +3858,7 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -3567,13 +3870,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -3585,25 +3890,28 @@ } }, "node_modules/jiti": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.3.3.tgz", - "integrity": "sha512-EX4oNDwcXSivPrw2qKH2LB5PoFxEvgtv2JgwW0bU858HoLQ+kutSvjLMUqBd0PeJYEinLWhoI9Ol0eYMqj/wNQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", "dev": true, + "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } }, "node_modules/js-tokens": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", - "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", - "dev": true + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -3615,35 +3923,41 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-pretty-compact": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", - "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==" + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", + "license": "MIT" }, "node_modules/kdbush": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", - "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==" + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", + "license": "ISC" }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -3652,6 +3966,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3661,6 +3976,7 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3669,13 +3985,15 @@ "version": "0.35.0", "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -3689,6 +4007,7 @@ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -3697,16 +4016,18 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/local-pkg": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", - "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", "dev": true, + "license": "MIT", "dependencies": { - "mlly": "^1.4.2", - "pkg-types": "^1.0.3" + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" }, "engines": { "node": ">=14" @@ -3718,13 +4039,15 @@ "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -3739,13 +4062,15 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/loupe": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, + "license": "MIT", "dependencies": { "get-func-name": "^2.0.1" } @@ -3754,7 +4079,8 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/lucide-svelte": { "version": "0.460.1", @@ -3767,9 +4093,10 @@ } }, "node_modules/magic-string": { - "version": "0.30.12", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", - "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -3778,6 +4105,7 @@ "version": "4.7.1", "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz", "integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==", + "license": "BSD-3-Clause", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", @@ -3815,21 +4143,24 @@ } }, "node_modules/maplibre-gl/node_modules/earcut": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", - "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.1.tgz", + "integrity": "sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw==", + "license": "ISC" }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -3839,6 +4170,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -3852,6 +4184,7 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -3864,6 +4197,7 @@ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -3873,6 +4207,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -3887,6 +4222,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3896,6 +4232,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=8" } @@ -3905,6 +4242,7 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -3918,6 +4256,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -3929,6 +4268,7 @@ "version": "2.7.3", "resolved": "https://registry.npmjs.org/mjolnir.js/-/mjolnir.js-2.7.3.tgz", "integrity": "sha512-Z5z/+FzZqOSO3juSVKV3zcm4R2eAlWwlKMcqHmyFEJAaLILNcDKnIbnb4/kbcGyIuhtdWrzu8WOIR7uM6I34aw==", + "license": "MIT", "dependencies": { "@types/hammerjs": "^2.0.41", "hammerjs": "^2.0.8" @@ -3943,6 +4283,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -3951,22 +4292,31 @@ } }, "node_modules/mlly": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.2.tgz", - "integrity": "sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^8.12.1", - "pathe": "^1.1.2", - "pkg-types": "^1.2.0", + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", "ufo": "^1.5.4" } }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz", + "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==", + "dev": true, + "license": "MIT" + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -3976,6 +4326,7 @@ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -3984,53 +4335,80 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/murmurhash-js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", - "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==" + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", + "license": "MIT" }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "dev": true, + "license": "MIT", "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-fetch-native": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4040,6 +4418,7 @@ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4049,6 +4428,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^4.0.0" }, @@ -4064,6 +4444,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -4076,6 +4457,7 @@ "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.12.tgz", "integrity": "sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA==", "dev": true, + "license": "MIT", "dependencies": { "citty": "^0.1.6", "consola": "^3.2.3", @@ -4096,6 +4478,7 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4105,6 +4488,7 @@ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -4113,13 +4497,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.4.tgz", "integrity": "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -4129,6 +4515,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^4.0.0" }, @@ -4144,6 +4531,7 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -4161,6 +4549,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -4176,6 +4565,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -4190,13 +4580,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true + "dev": true, + "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -4209,6 +4601,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4218,6 +4611,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4227,6 +4621,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4235,13 +4630,15 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -4258,6 +4655,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4266,13 +4664,15 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -4281,6 +4681,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "license": "BSD-3-Clause", "dependencies": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" @@ -4293,19 +4694,22 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -4318,6 +4722,7 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4327,28 +4732,38 @@ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/pkg-types": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz", - "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", "dev": true, + "license": "MIT", "dependencies": { "confbox": "^0.1.8", - "mlly": "^1.7.2", - "pathe": "^1.1.2" + "mlly": "^1.7.4", + "pathe": "^2.0.1" } }, + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz", + "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==", + "dev": true, + "license": "MIT" + }, "node_modules/playwright": { - "version": "1.48.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.1.tgz", - "integrity": "sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", + "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.48.1" + "playwright-core": "1.49.1" }, "bin": { "playwright": "cli.js" @@ -4361,10 +4776,11 @@ } }, "node_modules/playwright-core": { - "version": "1.48.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.1.tgz", - "integrity": "sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==", + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", + "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", "dev": true, + "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, @@ -4382,9 +4798,9 @@ } }, "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", + "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", "dev": true, "funding": [ { @@ -4400,9 +4816,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.0", + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { @@ -4414,6 +4831,7 @@ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -4431,6 +4849,7 @@ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", "dev": true, + "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" }, @@ -4450,6 +4869,7 @@ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", "dev": true, + "license": "MIT", "dependencies": { "lilconfig": "^2.0.5", "yaml": "^1.10.2" @@ -4489,6 +4909,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "postcss-selector-parser": "^6.1.1" }, @@ -4504,6 +4925,7 @@ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.0" }, @@ -4534,6 +4956,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "engines": { "node": ">=12.0" }, @@ -4546,6 +4969,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -4558,45 +4982,31 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } + "license": "MIT" }, "node_modules/potpack": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", - "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" + "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==", + "license": "ISC" }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -4608,10 +5018,11 @@ } }, "node_modules/prettier-plugin-svelte": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.7.tgz", - "integrity": "sha512-/Dswx/ea0lV34If1eDcG3nulQ63YNr5KPDfMsjbdtpSWOxKKJ7nAc2qlVuYwEvCr4raIuredNoR7K4JCkmTGaQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz", + "integrity": "sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==", "dev": true, + "license": "MIT", "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" @@ -4622,6 +5033,7 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -4636,6 +5048,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -4646,13 +5059,15 @@ "node_modules/protocol-buffers-schema": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", - "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", + "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -4675,18 +5090,21 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/quickselect": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", - "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==" + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", + "license": "ISC" }, "node_modules/rc9": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", "dev": true, + "license": "MIT", "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" @@ -4696,24 +5114,27 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^2.3.0" } }, "node_modules/readdirp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", - "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz", + "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 14.16.0" + "node": ">= 14.18.0" }, "funding": { "type": "individual", @@ -4721,18 +5142,22 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4742,6 +5167,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -4750,6 +5176,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", "dependencies": { "protocol-buffers-schema": "^3.3.1" } @@ -4759,6 +5186,7 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -4770,6 +5198,7 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -4781,10 +5210,11 @@ } }, "node_modules/rollup": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", - "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", + "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "1.0.6" }, @@ -4796,22 +5226,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.24.0", - "@rollup/rollup-android-arm64": "4.24.0", - "@rollup/rollup-darwin-arm64": "4.24.0", - "@rollup/rollup-darwin-x64": "4.24.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", - "@rollup/rollup-linux-arm-musleabihf": "4.24.0", - "@rollup/rollup-linux-arm64-gnu": "4.24.0", - "@rollup/rollup-linux-arm64-musl": "4.24.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", - "@rollup/rollup-linux-riscv64-gnu": "4.24.0", - "@rollup/rollup-linux-s390x-gnu": "4.24.0", - "@rollup/rollup-linux-x64-gnu": "4.24.0", - "@rollup/rollup-linux-x64-musl": "4.24.0", - "@rollup/rollup-win32-arm64-msvc": "4.24.0", - "@rollup/rollup-win32-ia32-msvc": "4.24.0", - "@rollup/rollup-win32-x64-msvc": "4.24.0", + "@rollup/rollup-android-arm-eabi": "4.30.1", + "@rollup/rollup-android-arm64": "4.30.1", + "@rollup/rollup-darwin-arm64": "4.30.1", + "@rollup/rollup-darwin-x64": "4.30.1", + "@rollup/rollup-freebsd-arm64": "4.30.1", + "@rollup/rollup-freebsd-x64": "4.30.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", + "@rollup/rollup-linux-arm-musleabihf": "4.30.1", + "@rollup/rollup-linux-arm64-gnu": "4.30.1", + "@rollup/rollup-linux-arm64-musl": "4.30.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", + "@rollup/rollup-linux-riscv64-gnu": "4.30.1", + "@rollup/rollup-linux-s390x-gnu": "4.30.1", + "@rollup/rollup-linux-x64-gnu": "4.30.1", + "@rollup/rollup-linux-x64-musl": "4.30.1", + "@rollup/rollup-win32-arm64-msvc": "4.30.1", + "@rollup/rollup-win32-ia32-msvc": "4.30.1", + "@rollup/rollup-win32-x64-msvc": "4.30.1", "fsevents": "~2.3.2" } }, @@ -4834,14 +5267,15 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/runed": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/runed/-/runed-0.15.3.tgz", - "integrity": "sha512-HtayB+loDcGdqJDHW8JFdsZzGQMyVzim6+s3052MkjZnwmwDstmF+cusMeTssBe6TCdt5i9D/Tb+KYXN3L0kXA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.22.0.tgz", + "integrity": "sha512-ZWVXWhOr0P5xdNgtviz6D1ivLUDWKLCbeC5SUEJ3zBkqLReVqWHenFxMNFeFaiC5bfxhFxyxzyzB+98uYFtwdA==", "dev": true, "funding": [ "https://github.com/sponsors/huntabyte", @@ -4851,19 +5285,21 @@ "esm-env": "^1.0.0" }, "peerDependencies": { - "svelte": "^5.0.0-next.1" + "svelte": "^5.7.0" } }, "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dev": true, + "license": "MIT", "dependencies": { "mri": "^1.1.0" }, @@ -4876,6 +5312,7 @@ "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", "dev": true, + "license": "MIT", "dependencies": { "es6-promise": "^3.1.2", "graceful-fs": "^4.1.3", @@ -4889,6 +5326,7 @@ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -4901,6 +5339,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -4912,13 +5351,15 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -4931,6 +5372,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4939,13 +5381,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -4958,6 +5402,7 @@ "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz", "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==", "dev": true, + "license": "MIT", "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", @@ -4972,6 +5417,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4981,6 +5427,7 @@ "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.1.tgz", "integrity": "sha512-o7npfeJE6wi6J9l0/5LKshFzZ2rMatRiCDwYeDQaOzqdzRJwALhX7mk/A/ecg6wjMu7wdZbmXfD2S/vpOg0bdQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.14", "buffer-crc32": "^1.0.0", @@ -4996,6 +5443,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -5005,6 +5453,7 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -5013,19 +5462,22 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", - "dev": true + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", + "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "dev": true, + "license": "MIT" }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -5044,6 +5496,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5057,13 +5510,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -5076,6 +5531,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -5091,6 +5547,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5104,6 +5561,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5116,6 +5574,7 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -5128,6 +5587,7 @@ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, + "license": "MIT", "dependencies": { "min-indent": "^1.0.0" }, @@ -5140,6 +5600,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -5148,12 +5609,13 @@ } }, "node_modules/strip-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", - "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz", + "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", "dev": true, + "license": "MIT", "dependencies": { - "js-tokens": "^9.0.0" + "js-tokens": "^9.0.1" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -5174,6 +5636,7 @@ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -5196,6 +5659,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -5205,6 +5669,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -5225,6 +5690,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -5233,6 +5699,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "license": "ISC", "dependencies": { "kdbush": "^4.0.2" } @@ -5242,6 +5709,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -5254,6 +5722,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5262,9 +5731,10 @@ } }, "node_modules/svelte": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.1.0.tgz", - "integrity": "sha512-qD0pUvL3P26Vx+K1VodZROSu7MjDHFDunEVZ+2d3LUDWHyYI87AJFOIws0HufKWHDgXbPO4FCSugmysnX4LDwA==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.19.0.tgz", + "integrity": "sha512-qvd2GvvYnJxS/MteQKFSMyq8cQrAAut28QZ39ySv9k3ggmhw4Au4Rfcsqva74i0xMys//OhbhVCNfXPrDzL/Bg==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -5273,9 +5743,10 @@ "acorn-typescript": "^1.4.13", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", - "esm-env": "^1.0.0", - "esrap": "^1.2.2", - "is-reference": "^3.0.2", + "clsx": "^2.1.1", + "esm-env": "^1.2.1", + "esrap": "^1.4.3", + "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" @@ -5289,6 +5760,7 @@ "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.8.6.tgz", "integrity": "sha512-ij0u4Lw/sOTREP13BdWZjiXD/BlHE6/e2e34XzmVmsp5IN4kVa3PWP65NM32JAgwjZlwBg/+JtiNV1MM8khu0Q==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", "chokidar": "^3.4.1", @@ -5309,6 +5781,7 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -5333,6 +5806,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -5345,6 +5819,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -5357,6 +5832,7 @@ "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz", "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", "dev": true, + "license": "MIT", "dependencies": { "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", @@ -5385,6 +5861,7 @@ "integrity": "sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@types/pug": "^2.0.6", "detect-indent": "^6.1.0", @@ -5445,20 +5922,22 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/svelte-radix/-/svelte-radix-1.1.1.tgz", "integrity": "sha512-TCbV7fzlJ2aEUB0nu2EodVA+r1eYj526IYpmGUTV32Z0bIrCUvx3K8xX3tcxR5dDFA5ZBU1Hxr4RYC4TDFEQ4A==", + "license": "MIT", "peerDependencies": { "svelte": "^3.54.0 || ^4.0.0 || ^5.0.0 || ^5.0.0-next.1" } }, "node_modules/svelte-toolbelt": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.4.6.tgz", - "integrity": "sha512-k8OUvXBUifHZcAlWeY/HLg/4J0v5m2iOfOhn8fDmjt4AP8ZluaDh9eBFus9lFiLX6O5l6vKqI1dKL5wy7090NQ==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.7.0.tgz", + "integrity": "sha512-i/Tv4NwAWWqJnK5H0F8y/ubDnogDYlwwyzKhrspTUFzrFuGnYshqd2g4/R43ds841wmaFiSW/HsdsdWhPOlrAA==", "dev": true, "funding": [ "https://github.com/sponsors/huntabyte" ], "dependencies": { "clsx": "^2.1.1", + "runed": "^0.20.0", "style-to-object": "^1.0.8" }, "engines": { @@ -5466,13 +5945,29 @@ "pnpm": ">=8.7.0" }, "peerDependencies": { - "svelte": "^5.0.0-next.126" + "svelte": "^5.0.0" + } + }, + "node_modules/svelte-toolbelt/node_modules/runed": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.20.0.tgz", + "integrity": "sha512-YqPxaUdWL5nUXuSF+/v8a+NkVN8TGyEGbQwTA25fLY35MR/2bvZ1c6sCbudoo1kT4CAJPh4kUkcgGVxW127WKw==", + "dev": true, + "funding": [ + "https://github.com/sponsors/huntabyte", + "https://github.com/sponsors/tglide" + ], + "dependencies": { + "esm-env": "^1.0.0" + }, + "peerDependencies": { + "svelte": "^5.7.0" } }, "node_modules/tailwind-merge": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.4.tgz", - "integrity": "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", + "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", "dev": true, "license": "MIT", "funding": { @@ -5481,13 +5976,13 @@ } }, "node_modules/tailwind-variants": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-0.3.0.tgz", - "integrity": "sha512-ho2k5kn+LB1fT5XdNS3Clb96zieWxbStE9wNLK7D0AV64kdZMaYzAKo0fWl6fXLPY99ffF9oBJnIj5escEl/8A==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-0.3.1.tgz", + "integrity": "sha512-krn67M3FpPwElg4FsZrOQd0U26o7UDH/QOkK8RNaiCCrr052f6YJPBUfNKnPo/s/xRzNPtv1Mldlxsg8Tb46BQ==", "dev": true, "license": "MIT", "dependencies": { - "tailwind-merge": "^2.5.4" + "tailwind-merge": "2.5.4" }, "engines": { "node": ">=16.x", @@ -5497,34 +5992,46 @@ "tailwindcss": "*" } }, + "node_modules/tailwind-variants/node_modules/tailwind-merge": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.4.tgz", + "integrity": "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { - "version": "3.4.14", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", - "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dev": true, + "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.3.0", + "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.21.0", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", @@ -5549,6 +6056,7 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -5573,6 +6081,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -5581,14 +6090,28 @@ } }, "node_modules/tailwindcss/node_modules/jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, + "license": "MIT", "bin": { "jiti": "bin/jiti.js" } }, + "node_modules/tailwindcss/node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/tailwindcss/node_modules/postcss-load-config": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", @@ -5604,6 +6127,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" @@ -5624,23 +6148,12 @@ } } }, - "node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, "node_modules/tailwindcss/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -5649,10 +6162,11 @@ } }, "node_modules/tailwindcss/node_modules/yaml": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", - "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", "dev": true, + "license": "ISC", "bin": { "yaml": "bin.mjs" }, @@ -5665,6 +6179,7 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -5682,6 +6197,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -5693,13 +6209,15 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dev": true, + "license": "MIT", "dependencies": { "any-promise": "^1.0.0" } @@ -5709,6 +6227,7 @@ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "dev": true, + "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -5716,27 +6235,19 @@ "node": ">=0.8" } }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "dev": true, - "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tinypool": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -5744,13 +6255,15 @@ "node_modules/tinyqueue": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", - "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" }, "node_modules/tinyspy": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -5760,6 +6273,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -5772,15 +6286,17 @@ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -5792,18 +6308,21 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -5816,6 +6335,7 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -5825,6 +6345,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -5833,10 +6354,11 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5849,13 +6371,15 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -5865,9 +6389,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", "dev": true, "funding": [ { @@ -5883,9 +6407,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -5899,6 +6424,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -5907,13 +6433,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/vite": { - "version": "5.4.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz", - "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==", + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -5973,6 +6501,7 @@ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, + "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.3.4", @@ -5996,6 +6525,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -6005,16 +6535,17 @@ } }, "node_modules/vitefu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.3.tgz", - "integrity": "sha512-iKKfOMBHob2WxEJbqbJjHAkmYgvFDPhuqrO82om83S8RLk+17FtyMBfcyeH8GqD0ihShtkMW/zzJgiA51hCNCQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.5.tgz", + "integrity": "sha512-h4Vflt9gxODPFNGPwp4zAMZRpZR7eslzwH2c5hn5kNZ5rhnKyRJ50U+yGCdc2IRaBs8O4haIgLNGrV5CrpMsCA==", "dev": true, + "license": "MIT", "workspaces": [ "tests/deps/*", "tests/projects/*" ], "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0-beta.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "peerDependenciesMeta": { "vite": { @@ -6027,6 +6558,7 @@ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, + "license": "MIT", "dependencies": { "@vitest/expect": "1.6.0", "@vitest/runner": "1.6.0", @@ -6091,6 +6623,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", + "license": "MIT", "dependencies": { "@mapbox/point-geometry": "0.1.0", "@mapbox/vector-tile": "^1.3.1", @@ -6098,15 +6631,17 @@ } }, "node_modules/wgsl_reflect": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/wgsl_reflect/-/wgsl_reflect-1.0.14.tgz", - "integrity": "sha512-VYY1+5pNm3GE2I4ADNnlNBFTiLOsh3Cq/eeiwfMhjMzUwnlJOqJrzKUd/3owxL69txUfvgcQaB8M6ElVaBaAOA==" + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/wgsl_reflect/-/wgsl_reflect-1.0.16.tgz", + "integrity": "sha512-OE3urfXXbHMD5lhKZwxOxC9SFYynEGEkWXQmvi7B1gzzr5jb9+drh9A8MeBvVqKqznCoBuh8WOzVuSGSZs4CkQ==", + "license": "MIT" }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -6122,6 +6657,7 @@ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, + "license": "MIT", "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" @@ -6138,6 +6674,7 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6146,13 +6683,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -6171,6 +6710,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -6187,13 +6727,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -6208,6 +6750,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -6220,6 +6763,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -6232,6 +6776,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -6246,19 +6791,22 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 6" } @@ -6268,6 +6816,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -6278,7 +6827,8 @@ "node_modules/zimmerframe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", - "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==" + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", + "license": "MIT" } } } diff --git a/ui/package.json b/ui/package.json index efa3d970f0..c75621b5e2 100644 --- a/ui/package.json +++ b/ui/package.json @@ -18,7 +18,7 @@ "@hey-api/openapi-ts": "^0.53.11", "@playwright/test": "^1.28.1", "@sveltejs/adapter-static": "^3.0.5", - "@sveltejs/kit": "^2.7.2", + "@sveltejs/kit": "^2.12.0", "@sveltejs/vite-plugin-svelte": "^4.0.0-next.6", "@types/eslint": "^8.56.0", "@types/polyline": "^0.1.32", diff --git a/ui/src/app.css b/ui/src/app.css index 9580eb195a..bd8cce8fe9 100644 --- a/ui/src/app.css +++ b/ui/src/app.css @@ -97,3 +97,11 @@ .maplibregl-popup-content { background-color: hsl(var(--background)) !important; } + +.maplibregl-control-container .maplibregl-ctrl-top-left { + max-width: 100%; + bottom: 1rem; + display: flex; + flex-direction: column; + z-index: 3; +} diff --git a/ui/src/app.d.ts b/ui/src/app.d.ts index 743f07b2e5..e51b83ab11 100644 --- a/ui/src/app.d.ts +++ b/ui/src/app.d.ts @@ -1,11 +1,19 @@ // See https://kit.svelte.dev/docs/types#app + +import type { Itinerary } from '$lib/openapi'; + // for information about these interfaces declare global { namespace App { // interface Error {} // interface Locals {} // interface PageData {} - // interface PageState {} + interface PageState { + selectedItinerary?: Itinerary; + selectedStop?: { name: string; stopId: string; time: Date }; + stopArriveBy?: boolean; + tripId?: string; + } // interface Platform {} } } diff --git a/ui/src/app.html b/ui/src/app.html index 71b744f6c2..d09e778dba 100644 --- a/ui/src/app.html +++ b/ui/src/app.html @@ -65,6 +65,24 @@ d="M15.5 5.5c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zM5 12c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm0 8.5c-1.9 0-3.5-1.6-3.5-3.5s1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5-1.6 3.5-3.5 3.5zm5.8-10l2.4-2.4.8.8c1.3 1.3 3 2.1 5.1 2.1V9c-1.5 0-2.7-.6-3.6-1.5l-1.9-1.9c-.5-.4-1-.6-1.6-.6s-1.1.2-1.4.6L7.8 8.4c-.4.4-.6.9-.6 1.4 0 .6.2 1.1.6 1.4L11 14v5h2v-6.2l-2.2-2.3zM19 12c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm0 8.5c-1.9 0-3.5-1.6-3.5-3.5s1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5-1.6 3.5-3.5 3.5z" /> + + + + + + + + + { @@ -118,11 +119,20 @@ }, 150); } }); + + let comboOpen = false; + const preventClickthrough = (prevent: boolean) => { + const ctr = document.getElementById('searchmask-container')!; + if (prevent) { + ctr.style.pointerEvents = 'none'; + } else { + window.setTimeout(() => (ctr.style.pointerEvents = 'auto'), 1); + } + }; { @@ -131,6 +141,10 @@ inputValue = selected.label!; } }} + onOpenChange={(open) => { + comboOpen = open; + preventClickthrough(open); + }} > - {#snippet child({ props, open })} - {#if open} -
- {#each items as item (item.value)} - - {#if item.value.match?.type == 'STOP'} - - {:else if item.value.match?.type == 'ADDRESS'} - - {:else if item.value.match?.type == 'PLACE'} - - {/if} - - {item.value.match?.name} - - - {getDisplayArea(item.value.match)} - - - {/each} -
- {/if} - {/snippet} + {#each items as item (item.value)} + + {#if item.value.match?.type == 'STOP'} + + {:else if item.value.match?.type == 'ADDRESS'} + + {:else if item.value.match?.type == 'PLACE'} + + {/if} + + {item.value.match?.name} + + + {getDisplayArea(item.value.match)} + + + {/each} {/if} diff --git a/ui/src/routes/ConnectionDetail.svelte b/ui/src/lib/ConnectionDetail.svelte similarity index 71% rename from ui/src/routes/ConnectionDetail.svelte rename to ui/src/lib/ConnectionDetail.svelte index 6a38273481..2f6e487a13 100644 --- a/ui/src/routes/ConnectionDetail.svelte +++ b/ui/src/lib/ConnectionDetail.svelte @@ -1,7 +1,7 @@ + + diff --git a/ui/src/lib/ErrorMessage.svelte b/ui/src/lib/ErrorMessage.svelte new file mode 100644 index 0000000000..acd5b5426b --- /dev/null +++ b/ui/src/lib/ErrorMessage.svelte @@ -0,0 +1,9 @@ + + +
{e}
diff --git a/ui/src/routes/ItineraryGeoJSON.svelte b/ui/src/lib/ItineraryGeoJSON.svelte similarity index 100% rename from ui/src/routes/ItineraryGeoJSON.svelte rename to ui/src/lib/ItineraryGeoJSON.svelte diff --git a/ui/src/routes/ItineraryList.svelte b/ui/src/lib/ItineraryList.svelte similarity index 69% rename from ui/src/routes/ItineraryList.svelte rename to ui/src/lib/ItineraryList.svelte index 4e104fb501..fa9e40853a 100644 --- a/ui/src/routes/ItineraryList.svelte +++ b/ui/src/lib/ItineraryList.svelte @@ -1,25 +1,44 @@ {#snippet legSummary(l: Leg)} @@ -28,7 +47,7 @@ style={routeColor(l)} > - + {#if l.routeShortName} {l.routeShortName} @@ -47,20 +66,18 @@ {#if r.direct.length !== 0}
{#each r.direct as d} - + /> {/each}
{/if} {#if r.itineraries.length !== 0} -
+
{#each routingResponses as r, rI} {#await r}
@@ -75,12 +92,14 @@ routingResponses.splice( 0, 0, - plan({ - query: { ...baseQuery.query, pageCursor: r.previousPageCursor } - }).then((x) => x.data!) + throwOnError( + plan({ + query: { ...baseQuery.query, pageCursor: r.previousPageCursor } + }) + ) ); }} - class="px-2 py-1 bg-blue-600 hover:!bg-blue-700 text-white font-bold text-sm border rounded-lg" + class="px-2 py-1 bg-blue-600 hover:!bg-blue-700 text-white font-bold text-sm border rounded-lg text-nowrap" > {t.earlier} @@ -90,12 +109,12 @@ {#each r.itineraries as it} @@ -155,10 +176,14 @@
{/if} {:catch e} -
Error: {e}
+ {/await} {/each}
+ {:else if r.direct.length === 0} + {/if} + {:catch e} + {/await} {/if} diff --git a/ui/src/routes/LevelSelect.svelte b/ui/src/lib/LevelSelect.svelte similarity index 100% rename from ui/src/routes/LevelSelect.svelte rename to ui/src/lib/LevelSelect.svelte diff --git a/ui/src/routes/RailViz.svelte b/ui/src/lib/RailViz.svelte similarity index 93% rename from ui/src/routes/RailViz.svelte rename to ui/src/lib/RailViz.svelte index ea7dc8b63a..81b279a3ba 100644 --- a/ui/src/routes/RailViz.svelte +++ b/ui/src/lib/RailViz.svelte @@ -10,11 +10,12 @@ import { formatTime } from '$lib/toDateTime'; import { lngLatToStr } from '$lib/lngLatToStr'; import maplibregl from 'maplibre-gl'; - import { onDestroy } from 'svelte'; + import { onDestroy, untrack } from 'svelte'; import Control from '$lib/map/Control.svelte'; import { Button } from '$lib/components/ui/button'; import Palette from 'lucide-svelte/icons/palette'; import Rss from 'lucide-svelte/icons/rss'; + import { browser } from '$app/environment'; let { map, @@ -29,6 +30,7 @@ } = $props(); let colorMode = $state<'rt' | 'route'>('route'); + let railvizError = $state(); type RGBA = [number, number, number, number]; @@ -97,7 +99,7 @@ 'not found, timestamp=', new Date(timestamp), ' #keyframes=', - new Date(keyframes.length), + keyframes.length, ' first=', new Date(keyframes[0].time), ', last=', @@ -203,7 +205,6 @@ }); }; - let railvizError = $state(); let animation: number | null = null; const updateRailvizLayer = async () => { try { @@ -241,7 +242,10 @@ const updateRailviz = async () => { clearTimeout(timer); await updateRailvizLayer(); - timer = setTimeout(updateRailviz, 60000); + timer = setTimeout(() => { + console.log('updateRailviz: timer'); + updateRailviz(); + }, 60000); }; $effect(() => { @@ -268,13 +272,17 @@ }); map.addControl(overlay); - updateRailviz(); + console.log('updateRailviz: init'); + untrack(() => updateRailviz()); } }); $effect(() => { if (overlay && bounds && zoom && colorMode) { - updateRailviz(); + untrack(() => { + console.log(`updateRailviz: effect ${overlay} ${bounds} ${zoom} ${colorMode}`); + updateRailviz(); + }); } }); @@ -289,7 +297,7 @@ }); - + -
+
- + - - - - - - +
+ + + + + + +
diff --git a/ui/src/routes/StopTimes.svelte b/ui/src/lib/StopTimes.svelte similarity index 57% rename from ui/src/routes/StopTimes.svelte rename to ui/src/lib/StopTimes.svelte index af60fb831b..32770d4c1a 100644 --- a/ui/src/routes/StopTimes.svelte +++ b/ui/src/lib/StopTimes.svelte @@ -1,38 +1,58 @@ -
+
@@ -74,28 +92,12 @@ {@const scheduledTimestamp = arriveBy ? t.place.scheduledArrival! : t.place.scheduledDeparture!} - -
diff --git a/ui/src/lib/Time.svelte b/ui/src/lib/Time.svelte index f54954b524..5af2fb81d3 100644 --- a/ui/src/lib/Time.svelte +++ b/ui/src/lib/Time.svelte @@ -23,7 +23,7 @@ const lowDelay = $derived(isRealtime && delayMinutes <= 3); -
+
{#if variant == 'schedule'} {formatTime(scheduled)} {:else if variant === 'realtime-show-always' || (variant === 'realtime' && isRealtime)} diff --git a/ui/src/lib/components/ui/button/button.svelte b/ui/src/lib/components/ui/button/button.svelte index 868867fbf1..0cc74eb301 100644 --- a/ui/src/lib/components/ui/button/button.svelte +++ b/ui/src/lib/components/ui/button/button.svelte @@ -15,6 +15,7 @@ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-sm", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", + child: "", }, size: { default: "h-9 px-4 py-2", @@ -57,7 +58,7 @@ {#if href} @@ -66,7 +67,7 @@ {:else}
-
- { - stopArriveBy = false; - selectedStop = { name, stopId, time }; - }} - {onClickTrip} - /> +
+
- + {/if} - {#if selectedStop} - - + {#if page.state.selectedStop} + +

- {#if stopArriveBy} + {#if page.state.stopArriveBy} {t.arrivals} {:else} {t.departures} {/if} in - {selectedStop.name} + {stopNameFromResponse}

-
+
+ onClickStop( + page.state.selectedStop!.name, + page.state.selectedStop!.stopId, + page.state.selectedStop!.time, + arriveBy + )} {onClickTrip} />