From 5ced7f916d94e86e9a7ec164bee56f9a8e3a2a3a Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Mon, 26 May 2025 10:48:43 +0200 Subject: Replace Azure SWA with custom server --- .editorconfig | 50 + .github/workflows/deploy.yml | 33 - .github/workflows/update-stops-data.yml | 13 +- Backend/.gitignore | 264 - Backend/GetStopEstimates.cs | 43 - Backend/InfobusApp.csproj | 36 - Backend/Program.cs | 14 - Backend/Properties/launchSettings.json | 9 - Backend/host.json | 12 - Costasdev.Busurbano.slnx | 4 + README.md | 42 +- data/download-stops.py | 40 +- eslint.config.ts | 28 - index.html | 55 - package-lock.json | 7498 +++++---- package.json | 65 +- public/favicon.ico | Bin 16958 -> 0 bytes public/logo-256.jpg | Bin 7492 -> 0 bytes public/logo-256.png | Bin 37843 -> 0 bytes public/logo-512.jpg | Bin 16746 -> 0 bytes public/manifest.webmanifest | 84 - public/map-pin-icon.png | Bin 4033 -> 0 bytes public/screenshots/estimates-narrow.png | Bin 219332 -> 0 bytes public/screenshots/estimates-wide.jpeg | Bin 53529 -> 0 bytes public/screenshots/map-narrow.png | Bin 2295265 -> 0 bytes public/screenshots/map-wide.jpeg | Bin 336231 -> 0 bytes public/screenshots/stoplist-narrow.png | Bin 297920 -> 0 bytes public/screenshots/stoplist-wide.jpeg | Bin 102303 -> 0 bytes public/stops.json | 15037 ------------------- public/sw.js | 51 - src/AppContext.tsx | 234 - src/Costasdev.Busurbano.Backend/.gitignore | 264 + .../Costasdev.Busurbano.Backend.csproj | 13 + .../GetStopEstimates.cs | 43 + src/Costasdev.Busurbano.Backend/Program.cs | 10 + .../Properties/launchSettings.json | 14 + src/Costasdev.Busurbano.Backend/appsettings.json | 9 + src/ErrorBoundary.tsx | 46 - src/Layout.css | 60 - src/Layout.tsx | 55 - src/components/GroupedTable.tsx | 74 - src/components/LineIcon.css | 239 - src/components/LineIcon.tsx | 17 - src/components/RegularTable.tsx | 70 - src/components/StopItem.css | 54 - src/components/StopItem.tsx | 25 - src/controls/LocateControl.ts | 67 - src/data/StopDataProvider.ts | 160 - src/frontend/frontend.esproj | 22 + src/frontend/index.html | 55 + src/frontend/package-lock.json | 4083 +++++ src/frontend/package.json | 47 + src/frontend/public/favicon.ico | Bin 0 -> 16958 bytes src/frontend/public/logo-256.jpg | Bin 0 -> 7492 bytes src/frontend/public/logo-256.png | Bin 0 -> 37843 bytes src/frontend/public/logo-512.jpg | Bin 0 -> 16746 bytes src/frontend/public/manifest.webmanifest | 84 + src/frontend/public/map-pin-icon.png | Bin 0 -> 4033 bytes .../public/screenshots/estimates-narrow.png | Bin 0 -> 219332 bytes .../public/screenshots/estimates-wide.jpeg | Bin 0 -> 53529 bytes src/frontend/public/screenshots/map-narrow.png | Bin 0 -> 2295265 bytes src/frontend/public/screenshots/map-wide.jpeg | Bin 0 -> 336231 bytes .../public/screenshots/stoplist-narrow.png | Bin 0 -> 297920 bytes src/frontend/public/screenshots/stoplist-wide.jpeg | Bin 0 -> 102303 bytes src/frontend/public/stops.json | 15037 +++++++++++++++++++ src/frontend/public/sw.js | 51 + src/frontend/src/AppContext.tsx | 234 + src/frontend/src/ErrorBoundary.tsx | 46 + src/frontend/src/Layout.css | 60 + src/frontend/src/Layout.tsx | 55 + src/frontend/src/components/GroupedTable.tsx | 74 + src/frontend/src/components/LineIcon.css | 239 + src/frontend/src/components/LineIcon.tsx | 17 + src/frontend/src/components/RegularTable.tsx | 70 + src/frontend/src/components/StopItem.css | 54 + src/frontend/src/components/StopItem.tsx | 25 + src/frontend/src/controls/LocateControl.ts | 67 + src/frontend/src/data/StopDataProvider.ts | 160 + src/frontend/src/main.tsx | 43 + src/frontend/src/pages/Estimates.tsx | 99 + src/frontend/src/pages/Map.tsx | 75 + src/frontend/src/pages/Settings.tsx | 65 + src/frontend/src/pages/StopList.tsx | 135 + src/frontend/src/styles/Estimates.css | 105 + src/frontend/src/styles/Map.css | 86 + src/frontend/src/styles/Pages.css | 364 + src/frontend/src/styles/Settings.css | 94 + src/frontend/src/vite-env.d.ts | 1 + src/frontend/tsconfig.json | 27 + src/frontend/vite.config.ts | 26 + src/main.tsx | 43 - src/pages/Estimates.tsx | 99 - src/pages/Map.tsx | 75 - src/pages/Settings.tsx | 65 - src/pages/StopList.tsx | 135 - src/styles/Estimates.css | 105 - src/styles/Map.css | 86 - src/styles/Pages.css | 364 - src/styles/Settings.css | 94 - src/vite-env.d.ts | 1 - staticwebapp.config.json | 13 - swa-cli.config.json | 16 - tsconfig.app.json | 24 - tsconfig.json | 7 - tsconfig.node.json | 22 - vite.config.ts | 26 - 106 files changed, 25492 insertions(+), 22115 deletions(-) create mode 100644 .editorconfig delete mode 100644 .github/workflows/deploy.yml delete mode 100644 Backend/.gitignore delete mode 100644 Backend/GetStopEstimates.cs delete mode 100644 Backend/InfobusApp.csproj delete mode 100644 Backend/Program.cs delete mode 100644 Backend/Properties/launchSettings.json delete mode 100644 Backend/host.json create mode 100644 Costasdev.Busurbano.slnx delete mode 100644 eslint.config.ts delete mode 100644 index.html delete mode 100644 public/favicon.ico delete mode 100644 public/logo-256.jpg delete mode 100644 public/logo-256.png delete mode 100644 public/logo-512.jpg delete mode 100644 public/manifest.webmanifest delete mode 100644 public/map-pin-icon.png delete mode 100644 public/screenshots/estimates-narrow.png delete mode 100644 public/screenshots/estimates-wide.jpeg delete mode 100644 public/screenshots/map-narrow.png delete mode 100644 public/screenshots/map-wide.jpeg delete mode 100644 public/screenshots/stoplist-narrow.png delete mode 100644 public/screenshots/stoplist-wide.jpeg delete mode 100644 public/stops.json delete mode 100644 public/sw.js delete mode 100644 src/AppContext.tsx create mode 100644 src/Costasdev.Busurbano.Backend/.gitignore create mode 100644 src/Costasdev.Busurbano.Backend/Costasdev.Busurbano.Backend.csproj create mode 100644 src/Costasdev.Busurbano.Backend/GetStopEstimates.cs create mode 100644 src/Costasdev.Busurbano.Backend/Program.cs create mode 100644 src/Costasdev.Busurbano.Backend/Properties/launchSettings.json create mode 100644 src/Costasdev.Busurbano.Backend/appsettings.json delete mode 100644 src/ErrorBoundary.tsx delete mode 100644 src/Layout.css delete mode 100644 src/Layout.tsx delete mode 100644 src/components/GroupedTable.tsx delete mode 100644 src/components/LineIcon.css delete mode 100644 src/components/LineIcon.tsx delete mode 100644 src/components/RegularTable.tsx delete mode 100644 src/components/StopItem.css delete mode 100644 src/components/StopItem.tsx delete mode 100644 src/controls/LocateControl.ts delete mode 100644 src/data/StopDataProvider.ts create mode 100644 src/frontend/frontend.esproj create mode 100644 src/frontend/index.html create mode 100644 src/frontend/package-lock.json create mode 100644 src/frontend/package.json create mode 100644 src/frontend/public/favicon.ico create mode 100644 src/frontend/public/logo-256.jpg create mode 100644 src/frontend/public/logo-256.png create mode 100644 src/frontend/public/logo-512.jpg create mode 100644 src/frontend/public/manifest.webmanifest create mode 100644 src/frontend/public/map-pin-icon.png create mode 100644 src/frontend/public/screenshots/estimates-narrow.png create mode 100644 src/frontend/public/screenshots/estimates-wide.jpeg create mode 100644 src/frontend/public/screenshots/map-narrow.png create mode 100644 src/frontend/public/screenshots/map-wide.jpeg create mode 100644 src/frontend/public/screenshots/stoplist-narrow.png create mode 100644 src/frontend/public/screenshots/stoplist-wide.jpeg create mode 100644 src/frontend/public/stops.json create mode 100644 src/frontend/public/sw.js create mode 100644 src/frontend/src/AppContext.tsx create mode 100644 src/frontend/src/ErrorBoundary.tsx create mode 100644 src/frontend/src/Layout.css create mode 100644 src/frontend/src/Layout.tsx create mode 100644 src/frontend/src/components/GroupedTable.tsx create mode 100644 src/frontend/src/components/LineIcon.css create mode 100644 src/frontend/src/components/LineIcon.tsx create mode 100644 src/frontend/src/components/RegularTable.tsx create mode 100644 src/frontend/src/components/StopItem.css create mode 100644 src/frontend/src/components/StopItem.tsx create mode 100644 src/frontend/src/controls/LocateControl.ts create mode 100644 src/frontend/src/data/StopDataProvider.ts create mode 100644 src/frontend/src/main.tsx create mode 100644 src/frontend/src/pages/Estimates.tsx create mode 100644 src/frontend/src/pages/Map.tsx create mode 100644 src/frontend/src/pages/Settings.tsx create mode 100644 src/frontend/src/pages/StopList.tsx create mode 100644 src/frontend/src/styles/Estimates.css create mode 100644 src/frontend/src/styles/Map.css create mode 100644 src/frontend/src/styles/Pages.css create mode 100644 src/frontend/src/styles/Settings.css create mode 100644 src/frontend/src/vite-env.d.ts create mode 100644 src/frontend/tsconfig.json create mode 100644 src/frontend/vite.config.ts delete mode 100644 src/main.tsx delete mode 100644 src/pages/Estimates.tsx delete mode 100644 src/pages/Map.tsx delete mode 100644 src/pages/Settings.tsx delete mode 100644 src/pages/StopList.tsx delete mode 100644 src/styles/Estimates.css delete mode 100644 src/styles/Map.css delete mode 100644 src/styles/Pages.css delete mode 100644 src/styles/Settings.css delete mode 100644 src/vite-env.d.ts delete mode 100644 staticwebapp.config.json delete mode 100644 swa-cli.config.json delete mode 100644 tsconfig.app.json delete mode 100644 tsconfig.json delete mode 100644 tsconfig.node.json delete mode 100644 vite.config.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7f4b09b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,50 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yml,yaml,css}] +indent_style = space +indent_size = 2 + +[*.{md,markdown}] +trim_trailing_whitespace = false + +[*.json] +indent_style = space + +[*.cs] +indent_style = space +indent_size = 4 + +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion + +csharp_style_var_when_type_is_apparent = false:suggestion +csharp_style_var_elsewhere = true:suggestion + +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +dotnet_style_readonly_field = true:suggestion + +csharp_style_namespace_declarations = file_scoped:suggestion +csharp_prefer_static_local_function = true:suggestion + +csharp_prefer_braces = true:suggestion +csharp_space_between_method_call_parentheses = false:suggestion + +csharp_new_line_before_open_brace = all +csharp_indent_case_contents = true +csharp_indent_switch_labels = true + +resharper_unused_auto_property_accessor_global_highlighting = none +dotnet_code_quality_unused_parameters = all + +dotnet_diagnostic.IDE0005.severity = error # Remove unused 'using' statements +dotnet_diagnostic.IDE0290.severity = none # Disable suggesting to use primary constructors + diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 02b52ce..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Azure Static Web Apps CI/CD - -on: - push: - branches: - - main - -jobs: - build_and_deploy_job: - runs-on: ubuntu-latest - environment: Production - name: Build and Deploy Job - steps: - - uses: actions/checkout@v3 - with: - submodules: true - lfs: false - - uses: actions/setup-node@v4.2.0 - with: - node-version: '22' - cache: 'npm' - - name: Install dependencies - run: npm ci - - name: Build And Deploy - id: builddeploy - uses: Azure/static-web-apps-deploy@v1 - with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ORANGE_GLACIER_064358D03 }} - repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) - action: "upload" - app_location: "/" # App source code path - api_location: "./Backend" # Api source code path - optional - output_location: "dist" # Built app content directory - optional \ No newline at end of file diff --git a/.github/workflows/update-stops-data.yml b/.github/workflows/update-stops-data.yml index 8e0def9..5a1ace3 100644 --- a/.github/workflows/update-stops-data.yml +++ b/.github/workflows/update-stops-data.yml @@ -14,10 +14,10 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v5 - + - name: Run download script run: uv run data/download-stops.py - + - name: Commit changes if any id: commit run: | @@ -36,7 +36,7 @@ jobs: echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT echo "changes_made=true" >> $GITHUB_OUTPUT fi - + - name: Create Pull Request if: steps.commit.outputs.changes_made == 'true' env: @@ -45,19 +45,20 @@ jobs: run: | # Close any existing PRs created by this action existing_prs=$(gh pr list --json number,title,headRefName --search "Update stops data in:title head:update-stops-data- author:app/github-actions is:open") - + if [[ $(echo "$existing_prs" | jq length) -gt 0 ]]; then echo "Found existing PRs to close" echo "$existing_prs" | jq -c '.[]' | while read pr; do pr_number=$(echo "$pr" | jq -r '.number') echo "Closing PR #$pr_number" gh pr close $pr_number --comment "Superseded by a new PR with updated data" + gh branch delete $(echo "$pr" | jq -r '.headRefName') --force done fi - + # Create new PR gh pr create \ --title "Update stops data" \ --body "Automatically generated PR with updated stops data from scheduled fetch." \ --base main \ - --head "$BRANCH_NAME" \ No newline at end of file + --head "$BRANCH_NAME" diff --git a/Backend/.gitignore b/Backend/.gitignore deleted file mode 100644 index ff5b00c..0000000 --- a/Backend/.gitignore +++ /dev/null @@ -1,264 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# Azure Functions localsettings file -local.settings.json - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -project.fragment.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -#*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc \ No newline at end of file diff --git a/Backend/GetStopEstimates.cs b/Backend/GetStopEstimates.cs deleted file mode 100644 index a97625b..0000000 --- a/Backend/GetStopEstimates.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Microsoft.Azure.Functions.Worker; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Costasdev.VigoTransitApi; - -namespace Costasdev.UrbanoVigoWeb; - -public class GetStopEstimates -{ - private readonly VigoTransitApiClient _api; - - public GetStopEstimates(HttpClient http) - { - _api = new VigoTransitApiClient(http); - } - - [Function("GetStopEstimates")] - public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req) - { - var argumentAvailable = req.Query.TryGetValue("id", out var requestedStopIdString); - if (!argumentAvailable) - { - return new BadRequestObjectResult("Please provide a stop id"); - } - - var argumentNumber = int.TryParse(requestedStopIdString, out var requestedStopId); - if (!argumentNumber) - { - return new BadRequestObjectResult("Please provide a valid stop id"); - } - - try - { - var estimates = await _api.GetStopEstimates(requestedStopId); - return new OkObjectResult(estimates); - } - catch (InvalidOperationException) - { - return new BadRequestObjectResult("Stop not found"); - } - } -} - diff --git a/Backend/InfobusApp.csproj b/Backend/InfobusApp.csproj deleted file mode 100644 index 587bb81..0000000 --- a/Backend/InfobusApp.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - net8.0 - v4 - Exe - enable - enable - Costasdev.UrbanoVigoWeb - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - Never - - - - - - - \ No newline at end of file diff --git a/Backend/Program.cs b/Backend/Program.cs deleted file mode 100644 index 6bcb5fd..0000000 --- a/Backend/Program.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.Azure.Functions.Worker; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.DependencyInjection; - -var host = new HostBuilder() - .ConfigureFunctionsWebApplication() - .ConfigureServices(services => { - services.AddApplicationInsightsTelemetryWorkerService(); - services.ConfigureFunctionsApplicationInsights(); - services.AddHttpClient(); - }) - .Build(); - -host.Run(); diff --git a/Backend/Properties/launchSettings.json b/Backend/Properties/launchSettings.json deleted file mode 100644 index aead5a4..0000000 --- a/Backend/Properties/launchSettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "profiles": { - "urbanovigoWeb": { - "commandName": "Project", - "commandLineArgs": "--port 7240", - "launchBrowser": false - } - } -} \ No newline at end of file diff --git a/Backend/host.json b/Backend/host.json deleted file mode 100644 index ee5cf5f..0000000 --- a/Backend/host.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": "2.0", - "logging": { - "applicationInsights": { - "samplingSettings": { - "isEnabled": true, - "excludedTypes": "Request" - }, - "enableLiveMetricsFilters": true - } - } -} \ No newline at end of file diff --git a/Costasdev.Busurbano.slnx b/Costasdev.Busurbano.slnx new file mode 100644 index 0000000..65f771d --- /dev/null +++ b/Costasdev.Busurbano.slnx @@ -0,0 +1,4 @@ + + + + diff --git a/README.md b/README.md index 750af83..1285020 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,60 @@ -# UrbanoVigo Web +# Busurbano -UrbanoVigo Web is a web application designed to help users find bus stops and arrival times for urban buses in Vigo, Spain. +Busurbano is a web application designed to help users find bus stops and arrival times for urban buses in Vigo, Spain. ## Features +- **Bus Stop List**: View a list of all bus stops, search for specific stops, and mark your favourite stops. - **Real-time Bus Arrival Estimates**: Get real-time estimates for bus arrivals at various stops. -- **Bus Stop List**: View a list of all bus stops, search for specific stops, and mark your favorite stops. - **Interactive Map**: View bus stops on an interactive map. - **Settings**: Customize the theme (light/dark mode) and table style (regular/grouped). ## Technologies Used - **Frontend**: React 19, react-router, TypeScript, Vite -- **Backend** (.NET): - - Azure Functions - - [Costasdev.VigoTransitApi](https://github.com/arielcostas/urbanovigo) +- **Backend**: + - ASP.NET Core 9 Web API + - [Costasdev.VigoTransitApi](https://github.com/arielcostas/VigoTransitApi) - **Mapping**: - [Leaflet](https://leafletjs.com/) via [React-Leaflet](https://react-leaflet.js.org/) - [Leaflet Locate Control](https://github.com/domoritz/leaflet-locatecontrol) - [Leaflet Marker Cluster](https://github.com/Leaflet/Leaflet.markercluster) -- **Styling**: CSS, Fontsource Variable +- **Styling**: Good old CSS +- **Fonts**: [Outfit Variable](https://fonts.google.com/specimen/Outfit) from Google Fonts via [@fontsource](https://fontsource.org/fonts/outfit) ## Getting Started ### Prerequisites - Node 22 and npm -- .NET 8 SDK -- Azure Static Web Apps CLI (swa) `npm install -g @azure/static-web-apps-cli` +- .NET 9 SDK ### Installation 1. Clone the repository: ```sh - git clone https://github.com/arielcostas/urbanovigo-web.git - cd urbanovigo-web + git clone https://github.com/arielcostas/busurbano.git + cd busurbano ``` -2. Install frontend dependencies: +2. Install dependencies: ```sh - npm install - ``` - -3. Install backend dependencies: - ```sh - cd Backend + npm i dotnet restore - cd .. ``` ### Running the Application -1. Start the application with the Static Web Apps CLI: +1. Start the entire application: ```sh - swa start + npm run dev ``` -3. Open your browser and navigate to `http://localhost:5173`. +2. Open your browser and navigate to `http://localhost:5173`. ### Deployment -The application is configured to be deployed to Azure Static Web Apps via GitHub Actions. To deploy the application to Azure by yourself, remove it in your fork and create a new "Static Web App" resource in the Azure Portal with the repository and branch you want to deploy. +The application is (or will soon be) deployed to [busurbano.costas.dev](https://busurbano.costas.dev) via GitHub Actions, on a normal Ubuntu server with Nginx and a reverse proxy. ## Contributing @@ -70,4 +64,4 @@ Contributions are welcome! Please open an issue or submit a pull request. This project is licensed under the BSD 3-Clause licence, meaning you can do whatever you want with it as long as you include the original copyright and license notice. -Note that the data served by the application is obtained from [datos.vigo.org](https://datos.vigo.org) under the [Open Data Commons Attribution License](https://opendefinition.org/licenses/odc-by/), so you must comply with the terms of that license if you use the data in your own projects. \ No newline at end of file +Note that the data served by the application is obtained from [datos.vigo.org](https://datos.vigo.org) under the [Open Data Commons Attribution License](https://opendefinition.org/licenses/odc-by/), so you must comply with the terms of that license if you use the data in your own projects. diff --git a/data/download-stops.py b/data/download-stops.py index 0b7d77a..12a04dc 100644 --- a/data/download-stops.py +++ b/data/download-stops.py @@ -10,12 +10,15 @@ import sys import urllib.request import yaml # Add YAML support for overrides +OVERRIDES_DIR = "overrides" +OUTPUT_FILE = "../src/frontend/public/stops.json" + def load_stop_overrides(file_path): """Load stop overrides from a YAML file""" if not os.path.exists(file_path): print(f"Warning: Overrides file {file_path} not found") return {} - + try: with open(file_path, 'r', encoding='utf-8') as f: overrides = yaml.safe_load(f) @@ -31,44 +34,44 @@ def apply_overrides(stops, overrides): stop_id = stop.get("stopId") if stop_id in overrides: override = overrides[stop_id] - + # Apply or add alternate names if "alternateNames" in override: for key, value in override["alternateNames"].items(): stop["name"][key] = value - + # Apply location override if "location" in override: if "latitude" in override["location"]: stop["latitude"] = override["location"]["latitude"] if "longitude" in override["location"]: stop["longitude"] = override["location"]["longitude"] - + # Add amenities if "amenities" in override: stop["amenities"] = override["amenities"] - + # Mark stop as hidden if needed if "hide" in override: stop["hide"] = override["hide"] - + return stops def main(): print("Fetching stop list data...") - + # Download stop list data url = "https://datos.vigo.org/vci_api_app/api2.jsp?tipo=TRANSPORTE_PARADAS" req = urllib.request.Request(url) - + try: with urllib.request.urlopen(req) as response: # Read the response and decode from ISO-8859-1 to UTF-8 content = response.read().decode('iso-8859-1') data = json.loads(content) - + print(f"Downloaded {len(data)} stops") - + # Process the data processed_stops = [] for stop in data: @@ -82,10 +85,10 @@ def main(): "lines": [line.strip() for line in stop.get("lineas", "").split(",")] if stop.get("lineas") else [] } processed_stops.append(processed_stop) - + # Load and apply overrides script_dir = os.path.dirname(os.path.abspath(__file__)) - overrides_dir = os.path.join(script_dir, "overrides") + overrides_dir = os.path.join(script_dir, OVERRIDES_DIR) # For each YML/YAML file in the overrides directory, load and apply the overrides for filename in os.listdir(overrides_dir): if not filename.endswith(".yml") and not filename.endswith(".yaml"): @@ -95,7 +98,7 @@ def main(): overrides_file = os.path.join(overrides_dir, filename) overrides = load_stop_overrides(overrides_file) processed_stops = apply_overrides(processed_stops, overrides) - + # Filter out hidden stops visible_stops = [stop for stop in processed_stops if not stop.get("hide")] print(f"Removed {len(processed_stops) - len(visible_stops)} hidden stops") @@ -103,18 +106,17 @@ def main(): # Sort stops by ID ascending visible_stops.sort(key=lambda x: x["stopId"]) - # Save to public directory - output_file = os.path.join(script_dir, "..", "public", "stops.json") - + output_file = os.path.join(script_dir, OUTPUT_FILE) + with open(output_file, 'w', encoding='utf-8') as f: json.dump(visible_stops, f, ensure_ascii=False, indent=2) - + print(f"Saved processed stops data to {output_file}") return 0 - + except Exception as e: print(f"Error processing stops data: {e}", file=sys.stderr) return 1 if __name__ == "__main__": - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/eslint.config.ts b/eslint.config.ts deleted file mode 100644 index 092408a..0000000 --- a/eslint.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import tseslint from 'typescript-eslint' - -export default tseslint.config( - { ignores: ['dist'] }, - { - extends: [js.configs.recommended, ...tseslint.configs.recommended], - files: ['**/*.{ts,tsx}'], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - plugins: { - 'react-hooks': reactHooks, - 'react-refresh': reactRefresh, - }, - rules: { - ...reactHooks.configs.recommended.rules, - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], - }, - }, -) diff --git a/index.html b/index.html deleted file mode 100644 index 4812ce5..0000000 --- a/index.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - UrbanoVigo Web - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b18eeb4..22edc9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,4083 +1,3423 @@ { - "name": "frontend", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "frontend", - "version": "0.0.0", - "dependencies": { - "@fontsource-variable/outfit": "^5.2.5", - "fuse.js": "^7.1.0", - "leaflet": "^1.9.4", - "leaflet.locatecontrol": "^0.84.2", - "leaflet.markercluster": "^1.5.3", - "lucide-react": "^0.510.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-leaflet": "^5.0.0", - "react-leaflet-markercluster": "^5.0.0-rc.0", - "react-router": "^7.6.0" - }, - "devDependencies": { - "@eslint/js": "^9.26.0", - "@types/leaflet": "^1.9.17", - "@types/node": "^22.15.17", - "@types/react": "^19.1.3", - "@types/react-dom": "^19.1.4", - "@vitejs/plugin-react-swc": "^3.9.0", - "eslint": "^9.26.0", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.20", - "globals": "^16.1.0", - "jiti": "^2.4.2", - "typescript": "^5.8.3", - "typescript-eslint": "^8.32.0", - "vite": "^6.3.5" - }, - "engines": { - "node": ">=20.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-linux-x64-gnu": "*" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "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/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "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" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "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" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", - "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", - "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.26.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.26.0.tgz", - "integrity": "sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@fontsource-variable/outfit": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@fontsource-variable/outfit/-/outfit-5.2.5.tgz", - "integrity": "sha512-MejrIp6Cbmd3u5AZtsot8kmhZiyQM5CATsdcBB2hktYIrv5CVekRSUmFDXL4FpF7K70IvFp2ZMfImm5VhnVf7Q==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "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" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.2.tgz", - "integrity": "sha512-H9vwztj5OAqHg9GockCQC06k1natgcxWQSRpQcPJf6i5+MWBzfKkRtxGbjQf0X2ihii0ffLZCRGbYV2f2bjNCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.3", - "eventsource": "^3.0.2", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.24.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "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" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "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" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "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" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@react-leaflet/core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", - "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", - "license": "Hippocratic-2.1", - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", - "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", - "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", - "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", - "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", - "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", - "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", - "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", - "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", - "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", - "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", - "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", - "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", - "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", - "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", - "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", - "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", - "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", - "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", - "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", - "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@swc/core": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.24.tgz", - "integrity": "sha512-MaQEIpfcEMzx3VWWopbofKJvaraqmL6HbLlw2bFZ7qYqYw3rkhM0cQVEgyzbHtTWwCwPMFZSC2DUbhlZgrMfLg==", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.21" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.11.24", - "@swc/core-darwin-x64": "1.11.24", - "@swc/core-linux-arm-gnueabihf": "1.11.24", - "@swc/core-linux-arm64-gnu": "1.11.24", - "@swc/core-linux-arm64-musl": "1.11.24", - "@swc/core-linux-x64-gnu": "1.11.24", - "@swc/core-linux-x64-musl": "1.11.24", - "@swc/core-win32-arm64-msvc": "1.11.24", - "@swc/core-win32-ia32-msvc": "1.11.24", - "@swc/core-win32-x64-msvc": "1.11.24" - }, - "peerDependencies": { - "@swc/helpers": ">=0.5.17" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.11.24.tgz", - "integrity": "sha512-dhtVj0PC1APOF4fl5qT2neGjRLgHAAYfiVP8poJelhzhB/318bO+QCFWAiimcDoyMgpCXOhTp757gnoJJrheWA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.11.24.tgz", - "integrity": "sha512-H/3cPs8uxcj2Fe3SoLlofN5JG6Ny5bl8DuZ6Yc2wr7gQFBmyBkbZEz+sPVgsID7IXuz7vTP95kMm1VL74SO5AQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.24.tgz", - "integrity": "sha512-PHJgWEpCsLo/NGj+A2lXZ2mgGjsr96ULNW3+T3Bj2KTc8XtMUkE8tmY2Da20ItZOvPNC/69KroU7edyo1Flfbw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.24.tgz", - "integrity": "sha512-C2FJb08+n5SD4CYWCTZx1uR88BN41ZieoHvI8A55hfVf2woT8+6ZiBzt74qW2g+ntZ535Jts5VwXAKdu41HpBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.24.tgz", - "integrity": "sha512-ypXLIdszRo0re7PNNaXN0+2lD454G8l9LPK/rbfRXnhLWDBPURxzKlLlU/YGd2zP98wPcVooMmegRSNOKfvErw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.24.tgz", - "integrity": "sha512-IM7d+STVZD48zxcgo69L0yYptfhaaE9cMZ+9OoMxirNafhKKXwoZuufol1+alEFKc+Wbwp+aUPe/DeWC/Lh3dg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.24.tgz", - "integrity": "sha512-DZByJaMVzSfjQKKQn3cqSeqwy6lpMaQDQQ4HPlch9FWtDx/dLcpdIhxssqZXcR2rhaQVIaRQsCqwV6orSDGAGw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.24.tgz", - "integrity": "sha512-Q64Ytn23y9aVDKN5iryFi8mRgyHw3/kyjTjT4qFCa8AEb5sGUuSj//AUZ6c0J7hQKMHlg9do5Etvoe61V98/JQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.24.tgz", - "integrity": "sha512-9pKLIisE/Hh2vJhGIPvSoTK4uBSPxNVyXHmOrtdDot4E1FUUI74Vi8tFdlwNbaj8/vusVnb8xPXsxF1uB0VgiQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.11.24", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.24.tgz", - "integrity": "sha512-sybnXtOsdB+XvzVFlBVGgRHLqp3yRpHK7CrmpuDKszhj/QhmsaZzY/GHSeALlMtLup13M0gqbcQvsTNlAHTg3w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@swc/types": { - "version": "0.1.21", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.21.tgz", - "integrity": "sha512-2YEtj5HJVbKivud9N4bpPBAyZhj4S2Ipe5LkUG94alTpr7in/GU/EARgPAd3BwU+YOmFVJC2+kjqhGRi3r0ZpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/counter": "^0.1.3" - } - }, - "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "dev": true, - "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, - "license": "MIT" - }, - "node_modules/@types/leaflet": { - "version": "1.9.17", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.17.tgz", - "integrity": "sha512-IJ4K6t7I3Fh5qXbQ1uwL3CFVbCi6haW9+53oLWgdKlLP7EaS21byWFJxxqOx9y8I0AP0actXSJLVMbyvxhkUTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/node": { - "version": "22.15.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz", - "integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/react": { - "version": "19.1.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.3.tgz", - "integrity": "sha512-dLWQ+Z0CkIvK1J8+wrDPwGxEYFA4RAyHoZPxHVGspYmFVnwGSNT24cGIhFJrtfRnWVuW8X7NO52gCXmhkVUWGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.1.4", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.4.tgz", - "integrity": "sha512-WxYAszDYgsMV31OVyoG4jbAgJI1Gw0Xq9V19zwhy6+hUUJlJIdZ3r/cbdmTqFv++SktQkZ/X+46yGFxp5XJBEg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz", - "integrity": "sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.32.0", - "@typescript-eslint/type-utils": "8.32.0", - "@typescript-eslint/utils": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.0.tgz", - "integrity": "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.32.0", - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/typescript-estree": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.0.tgz", - "integrity": "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.0.tgz", - "integrity": "sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "8.32.0", - "@typescript-eslint/utils": "8.32.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.0.tgz", - "integrity": "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.0.tgz", - "integrity": "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "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" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "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" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.0.tgz", - "integrity": "sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.32.0", - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/typescript-estree": "8.32.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.0.tgz", - "integrity": "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.32.0", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vitejs/plugin-react-swc": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.9.0.tgz", - "integrity": "sha512-jYFUSXhwMCYsh/aQTgSGLIN3Foz5wMbH9ahb0Zva//UzwZYbMiZd7oT3AU9jHT9DLswYDswsRwPU9jVF3yA48Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@swc/core": "^1.11.21" - }, - "peerDependencies": { - "vite": "^4 || ^5 || ^6" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "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" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "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", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "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" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "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" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, - "license": "MIT" - }, - "node_modules/debug": { - "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" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "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, - "license": "MIT" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.26.0.tgz", - "integrity": "sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.26.0", - "@eslint/plugin-kit": "^0.2.8", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@modelcontextprotocol/sdk": "^1.8.0", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "zod": "^3.24.2" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.20", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", - "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": ">=8.40" - } - }, - "node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "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" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "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" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "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" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "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" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz", - "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", - "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": "^4.11 || 5 || ^5.0.0-beta.1" - } - }, - "node_modules/express/node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fast-deep-equal": { - "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, - "license": "MIT" - }, - "node_modules/fast-glob": { - "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.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "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" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "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, - "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, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "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" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/fuse.js": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", - "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=10" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "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" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.1.0.tgz", - "integrity": "sha512-aibexHNbb/jiUSObBgpHLj+sIuUmJnYcgXBlrfsiDZ9rt4aF2TFRbyLgZ2iFQuVZ1K5Mx3FVkbKRSgKrbK3K2g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "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" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "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" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "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" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jiti": { - "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-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" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "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, - "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, - "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, - "license": "MIT" - }, - "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" - } - }, - "node_modules/leaflet": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", - "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", - "license": "BSD-2-Clause" - }, - "node_modules/leaflet.locatecontrol": { - "version": "0.84.2", - "resolved": "https://registry.npmjs.org/leaflet.locatecontrol/-/leaflet.locatecontrol-0.84.2.tgz", - "integrity": "sha512-Tv0S2bAhpFgZYyyfPgeVhb3hPr9CnlcP15EpMQd9m5vA+aALhM6key1ucfnnD7n09AEeNEmIFe71T4V18Kpu7g==", - "license": "MIT" - }, - "node_modules/leaflet.markercluster": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz", - "integrity": "sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==", - "license": "MIT", - "peerDependencies": { - "leaflet": "^1.3.1" - } - }, - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "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, - "license": "MIT" - }, - "node_modules/lucide-react": { - "version": "0.510.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.510.0.tgz", - "integrity": "sha512-p8SQRAMVh7NhsAIETokSqDrc5CHnDLbV29mMnzaXx+Vc/hnqQzwI2r0FMWCcoTXnbw2KEjy48xwpGdEL+ck06Q==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/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" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "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" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "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" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "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, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "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" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "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", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/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" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "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" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "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/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", - "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", - "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.26.0" - }, - "peerDependencies": { - "react": "^19.1.0" - } - }, - "node_modules/react-leaflet": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz", - "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", - "license": "Hippocratic-2.1", - "dependencies": { - "@react-leaflet/core": "^3.0.0" - }, - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" - } - }, - "node_modules/react-leaflet-markercluster": { - "version": "5.0.0-rc.0", - "resolved": "https://registry.npmjs.org/react-leaflet-markercluster/-/react-leaflet-markercluster-5.0.0-rc.0.tgz", - "integrity": "sha512-jWa4bPD5LfLV3Lid1RWgl+yKUuQtnqeYtJzzLb/fiRjvX+rtwzY8pMoUFuygqyxNrWxMTQlWKBHxkpI7Sxvu4Q==", - "license": "MIT", - "dependencies": { - "@react-leaflet/core": "^3.0.0", - "leaflet": "^1.9.4", - "leaflet.markercluster": "^1.5.3", - "react-leaflet": "^5.0.0" - }, - "peerDependencies": { - "leaflet": "^1.9.4", - "leaflet.markercluster": "^1.5.3", - "react": "^19.0.0", - "react-leaflet": "^5.0.0" - } - }, - "node_modules/react-router": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz", - "integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==", - "license": "MIT", - "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "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" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", - "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.7" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.40.0", - "@rollup/rollup-android-arm64": "4.40.0", - "@rollup/rollup-darwin-arm64": "4.40.0", - "@rollup/rollup-darwin-x64": "4.40.0", - "@rollup/rollup-freebsd-arm64": "4.40.0", - "@rollup/rollup-freebsd-x64": "4.40.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", - "@rollup/rollup-linux-arm-musleabihf": "4.40.0", - "@rollup/rollup-linux-arm64-gnu": "4.40.0", - "@rollup/rollup-linux-arm64-musl": "4.40.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-musl": "4.40.0", - "@rollup/rollup-linux-s390x-gnu": "4.40.0", - "@rollup/rollup-linux-x64-gnu": "4.40.0", - "@rollup/rollup-linux-x64-musl": "4.40.0", - "@rollup/rollup-win32-arm64-msvc": "4.40.0", - "@rollup/rollup-win32-ia32-msvc": "4.40.0", - "@rollup/rollup-win32-x64-msvc": "4.40.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/set-cookie-parser": { - "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==", - "license": "MIT" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "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" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "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" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.32.0.tgz", - "integrity": "sha512-UMq2kxdXCzinFFPsXc9o2ozIpYCCOiEC46MG3yEh5Vipq6BO27otTtEBZA1fQ66DulEUgE97ucQ/3YY66CPg0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.32.0", - "@typescript-eslint/parser": "8.32.0", - "@typescript-eslint/utils": "8.32.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "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" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vite": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", - "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true + "name": "costasdev.busurbano", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "costasdev.busurbano", + "version": "1.0.0", + "license": "BSD-3-Clause", + "workspaces": [ + "src/frontend" + ], + "devDependencies": { + "concurrently": "^9.1.2", + "prettier": "^3.5.3" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", + "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", + "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", + "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", + "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", + "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", + "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", + "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", + "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", + "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", + "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", + "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", + "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", + "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", + "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", + "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", + "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", + "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", + "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", + "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", + "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", + "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", + "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", + "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", + "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", + "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "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/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "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" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "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" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", + "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz", + "integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.14.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@fontsource-variable/outfit": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@fontsource-variable/outfit/-/outfit-5.2.5.tgz", + "integrity": "sha512-MejrIp6Cbmd3u5AZtsot8kmhZiyQM5CATsdcBB2hktYIrv5CVekRSUmFDXL4FpF7K70IvFp2ZMfImm5VhnVf7Q==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "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" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "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" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "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" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@react-leaflet/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", + "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", + "license": "Hippocratic-2.1", + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.9", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.9.tgz", + "integrity": "sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", + "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz", + "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz", + "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz", + "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz", + "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz", + "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz", + "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz", + "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz", + "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz", + "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz", + "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz", + "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz", + "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz", + "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", + "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", + "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz", + "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", + "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", + "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", + "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/core": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.29.tgz", + "integrity": "sha512-g4mThMIpWbNhV8G2rWp5a5/Igv8/2UFRJx2yImrLGMgrDDYZIopqZ/z0jZxDgqNA1QDx93rpwNF7jGsxVWcMlA==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.21" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.11.29", + "@swc/core-darwin-x64": "1.11.29", + "@swc/core-linux-arm-gnueabihf": "1.11.29", + "@swc/core-linux-arm64-gnu": "1.11.29", + "@swc/core-linux-arm64-musl": "1.11.29", + "@swc/core-linux-x64-gnu": "1.11.29", + "@swc/core-linux-x64-musl": "1.11.29", + "@swc/core-win32-arm64-msvc": "1.11.29", + "@swc/core-win32-ia32-msvc": "1.11.29", + "@swc/core-win32-x64-msvc": "1.11.29" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.11.29.tgz", + "integrity": "sha512-whsCX7URzbuS5aET58c75Dloby3Gtj/ITk2vc4WW6pSDQKSPDuONsIcZ7B2ng8oz0K6ttbi4p3H/PNPQLJ4maQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.11.29.tgz", + "integrity": "sha512-S3eTo/KYFk+76cWJRgX30hylN5XkSmjYtCBnM4jPLYn7L6zWYEPajsFLmruQEiTEDUg0gBEWLMNyUeghtswouw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.29.tgz", + "integrity": "sha512-o9gdshbzkUMG6azldHdmKklcfrcMx+a23d/2qHQHPDLUPAN+Trd+sDQUYArK5Fcm7TlpG4sczz95ghN0DMkM7g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.29.tgz", + "integrity": "sha512-sLoaciOgUKQF1KX9T6hPGzvhOQaJn+3DHy4LOHeXhQqvBgr+7QcZ+hl4uixPKTzxk6hy6Hb0QOvQEdBAAR1gXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.29.tgz", + "integrity": "sha512-PwjB10BC0N+Ce7RU/L23eYch6lXFHz7r3NFavIcwDNa/AAqywfxyxh13OeRy+P0cg7NDpWEETWspXeI4Ek8otw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.29.tgz", + "integrity": "sha512-i62vBVoPaVe9A3mc6gJG07n0/e7FVeAvdD9uzZTtGLiuIfVfIBta8EMquzvf+POLycSk79Z6lRhGPZPJPYiQaA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.29.tgz", + "integrity": "sha512-YER0XU1xqFdK0hKkfSVX1YIyCvMDI7K07GIpefPvcfyNGs38AXKhb2byySDjbVxkdl4dycaxxhRyhQ2gKSlsFQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.29.tgz", + "integrity": "sha512-po+WHw+k9g6FAg5IJ+sMwtA/fIUL3zPQ4m/uJgONBATCVnDDkyW6dBA49uHNVtSEvjvhuD8DVWdFP847YTcITw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.29.tgz", + "integrity": "sha512-h+NjOrbqdRBYr5ItmStmQt6x3tnhqgwbj9YxdGPepbTDamFv7vFnhZR0YfB3jz3UKJ8H3uGJ65Zw1VsC+xpFkg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.11.29", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.29.tgz", + "integrity": "sha512-Q8cs2BDV9wqDvqobkXOYdC+pLUSEpX/KvI0Dgfun1F+LzuLotRFuDhrvkU9ETJA6OnD2+Fn/ieHgloiKA/Mn/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.21.tgz", + "integrity": "sha512-2YEtj5HJVbKivud9N4bpPBAyZhj4S2Ipe5LkUG94alTpr7in/GU/EARgPAd3BwU+YOmFVJC2+kjqhGRi3r0ZpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "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, + "license": "MIT" + }, + "node_modules/@types/leaflet": { + "version": "1.9.18", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.18.tgz", + "integrity": "sha512-ht2vsoPjezor5Pmzi5hdsA7F++v5UGq9OlUduWHmMZiuQGIpJ2WS5+Gg9HaAA79gNh1AIPtCqhzejcIZ3lPzXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/node": { + "version": "22.15.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz", + "integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.1.5", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.5.tgz", + "integrity": "sha512-piErsCVVbpMMT2r7wbawdZsq4xMvIAhQuac2gedQHysu1TZYEigE6pnFfgZT+/jQnrRuF5r+SHzuehFjfRjr4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.5.tgz", + "integrity": "sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz", + "integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/type-utils": "8.32.1", + "@typescript-eslint/utils": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz", + "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz", + "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz", + "integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz", + "integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/utils": "8.32.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz", + "integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz", + "integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "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" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "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" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz", + "integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz", + "integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.32.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.10.0.tgz", + "integrity": "sha512-ZmkdHw3wo/o/Rk05YsXZs/DJAfY2CdQ5DUAjoWji+PEr+hYADdGMCGgEAILbiKj+CjspBTuTACBcWDrmC8AUfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.9", + "@swc/core": "^1.11.22" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "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" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "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", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "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" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz", + "integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "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, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", + "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", + "integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.27.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "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" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "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" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "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" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "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" + } + }, + "node_modules/fast-deep-equal": { + "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, + "license": "MIT" + }, + "node_modules/fast-glob": { + "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.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "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" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "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, + "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, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/frontend": { + "resolved": "src/frontend", + "link": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/fuse.js": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", + "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "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" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.1.0.tgz", + "integrity": "sha512-aibexHNbb/jiUSObBgpHLj+sIuUmJnYcgXBlrfsiDZ9rt4aF2TFRbyLgZ2iFQuVZ1K5Mx3FVkbKRSgKrbK3K2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/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" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "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" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "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" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "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-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" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "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, + "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, + "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, + "license": "MIT" + }, + "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" + } + }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "license": "BSD-2-Clause" + }, + "node_modules/leaflet.locatecontrol": { + "version": "0.84.2", + "resolved": "https://registry.npmjs.org/leaflet.locatecontrol/-/leaflet.locatecontrol-0.84.2.tgz", + "integrity": "sha512-Tv0S2bAhpFgZYyyfPgeVhb3hPr9CnlcP15EpMQd9m5vA+aALhM6key1ucfnnD7n09AEeNEmIFe71T4V18Kpu7g==", + "license": "MIT" + }, + "node_modules/leaflet.markercluster": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz", + "integrity": "sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==", + "license": "MIT", + "peerDependencies": { + "leaflet": "^1.3.1" + } + }, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "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, + "license": "MIT" + }, + "node_modules/lucide-react": { + "version": "0.510.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.510.0.tgz", + "integrity": "sha512-p8SQRAMVh7NhsAIETokSqDrc5CHnDLbV29mMnzaXx+Vc/hnqQzwI2r0FMWCcoTXnbw2KEjy48xwpGdEL+ck06Q==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "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" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "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" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "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, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "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", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "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" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "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.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-leaflet": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz", + "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", + "license": "Hippocratic-2.1", + "dependencies": { + "@react-leaflet/core": "^3.0.0" + }, + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/react-leaflet-markercluster": { + "version": "5.0.0-rc.0", + "resolved": "https://registry.npmjs.org/react-leaflet-markercluster/-/react-leaflet-markercluster-5.0.0-rc.0.tgz", + "integrity": "sha512-jWa4bPD5LfLV3Lid1RWgl+yKUuQtnqeYtJzzLb/fiRjvX+rtwzY8pMoUFuygqyxNrWxMTQlWKBHxkpI7Sxvu4Q==", + "license": "MIT", + "dependencies": { + "@react-leaflet/core": "^3.0.0", + "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", + "react-leaflet": "^5.0.0" + }, + "peerDependencies": { + "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", + "react": "^19.0.0", + "react-leaflet": "^5.0.0" + } + }, + "node_modules/react-router": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz", + "integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "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" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz", + "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.7" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.41.1", + "@rollup/rollup-android-arm64": "4.41.1", + "@rollup/rollup-darwin-arm64": "4.41.1", + "@rollup/rollup-darwin-x64": "4.41.1", + "@rollup/rollup-freebsd-arm64": "4.41.1", + "@rollup/rollup-freebsd-x64": "4.41.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", + "@rollup/rollup-linux-arm-musleabihf": "4.41.1", + "@rollup/rollup-linux-arm64-gnu": "4.41.1", + "@rollup/rollup-linux-arm64-musl": "4.41.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-musl": "4.41.1", + "@rollup/rollup-linux-s390x-gnu": "4.41.1", + "@rollup/rollup-linux-x64-gnu": "4.41.1", + "@rollup/rollup-linux-x64-musl": "4.41.1", + "@rollup/rollup-win32-arm64-msvc": "4.41.1", + "@rollup/rollup-win32-ia32-msvc": "4.41.1", + "@rollup/rollup-win32-x64-msvc": "4.41.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "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==", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "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" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "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" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.32.1.tgz", + "integrity": "sha512-D7el+eaDHAmXvrZBy1zpzSNIRqnCOrkwTgZxTu3MUqRWk8k0q9m9Ho4+vPf7iHtgUfrK/o8IZaEApsxPlHTFCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.32.1", + "@typescript-eslint/parser": "8.32.1", + "@typescript-eslint/utils": "8.32.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "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" + } + }, + "node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "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" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "src/frontend": { + "version": "0.0.0", + "dependencies": { + "@fontsource-variable/outfit": "^5.2.5", + "fuse.js": "^7.1.0", + "leaflet": "^1.9.4", + "leaflet.locatecontrol": "^0.84.2", + "leaflet.markercluster": "^1.5.3", + "lucide-react": "^0.510.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-leaflet": "^5.0.0", + "react-leaflet-markercluster": "^5.0.0-rc.0", + "react-router": "^7.6.0" + }, + "devDependencies": { + "@eslint/js": "^9.26.0", + "@types/leaflet": "^1.9.17", + "@types/node": "^22.15.17", + "@types/react": "^19.1.3", + "@types/react-dom": "^19.1.4", + "@vitejs/plugin-react-swc": "^3.9.0", + "eslint": "^9.26.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.1.0", + "jiti": "^2.4.2", + "typescript": "^5.8.3", + "typescript-eslint": "^8.32.0", + "vite": "^6.3.5" + }, + "engines": { + "node": ">=20.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "*" + } } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "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" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.24.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.4.tgz", - "integrity": "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.24.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", - "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "zod": "^3.24.1" - } } - } } diff --git a/package.json b/package.json index 546b9cf..81ba10f 100644 --- a/package.json +++ b/package.json @@ -1,47 +1,22 @@ { - "name": "frontend", - "private": true, - "version": "0.0.0", - "engines": { - "node": ">=20.0.0" - }, - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "@fontsource-variable/outfit": "^5.2.5", - "fuse.js": "^7.1.0", - "leaflet": "^1.9.4", - "leaflet.locatecontrol": "^0.84.2", - "leaflet.markercluster": "^1.5.3", - "lucide-react": "^0.510.0", - "react": "^19.1.0", - "react-dom": "^19.1.0", - "react-leaflet": "^5.0.0", - "react-leaflet-markercluster": "^5.0.0-rc.0", - "react-router": "^7.6.0" - }, - "devDependencies": { - "@eslint/js": "^9.26.0", - "@types/leaflet": "^1.9.17", - "@types/node": "^22.15.17", - "@types/react": "^19.1.3", - "@types/react-dom": "^19.1.4", - "@vitejs/plugin-react-swc": "^3.9.0", - "eslint": "^9.26.0", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.20", - "globals": "^16.1.0", - "jiti": "^2.4.2", - "typescript": "^5.8.3", - "typescript-eslint": "^8.32.0", - "vite": "^6.3.5" - }, - "optionalDependencies": { - "@rollup/rollup-linux-x64-gnu": "*" - } + "name": "costasdev.busurbano", + "version": "1.0.0", + "scripts": { + "dev:backend": "dotnet watch --project src/Costasdev.Busurbano.Backend/Costasdev.Busurbano.Backend.csproj", + "dev:frontend": "npm run dev --prefix src/frontend", + "dev": "concurrently \"npm run dev:backend\" \"npm run dev:frontend\"", + "format:backend": "dotnet format --verbosity diagnostic", + "format:frontend": "prettier --write src/frontend/**/*.{ts,tsx,css}", + "format": "npm run format:backend && npm run format:frontend" + }, + "keywords": [], + "author": "", + "license": "BSD-3-Clause", + "devDependencies": { + "concurrently": "^9.1.2", + "prettier": "^3.5.3" + }, + "workspaces": [ + "src/frontend" + ] } diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index b81c323..0000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/logo-256.jpg b/public/logo-256.jpg deleted file mode 100644 index c823056..0000000 Binary files a/public/logo-256.jpg and /dev/null differ diff --git a/public/logo-256.png b/public/logo-256.png deleted file mode 100644 index a1d6c25..0000000 Binary files a/public/logo-256.png and /dev/null differ diff --git a/public/logo-512.jpg b/public/logo-512.jpg deleted file mode 100644 index cf45e80..0000000 Binary files a/public/logo-512.jpg and /dev/null differ diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest deleted file mode 100644 index 59fbab1..0000000 --- a/public/manifest.webmanifest +++ /dev/null @@ -1,84 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/SchemaStore/schemastore/refs/heads/master/src/schemas/json/web-manifest.json", - "id": "https://busurbano.costas.dev/", - "name": "UrbanoVigo Web", - "description": "Aplicación web para encontrar paradas y tiempos de llegada de los autobuses urbanos de Vigo, España.", - "short_name": "UrbanoVigo", - "start_url": "/", - "display": "standalone", - "orientation": "portrait-primary", - "lang": "es", - "background_color": "#ffffff", - "theme_color": "#007bff", - "icons": [ - { - "src": "/logo-512.jpg", - "sizes": "512x512", - "type": "image/jpg", - "purpose": "any maskable" - }, - { - "src": "/logo-256.jpg", - "sizes": "256x256", - "type": "image/jpg", - "purpose": "any maskable" - }, - { - "src": "/logo-256.png", - "sizes": "256x256", - "type": "image/png", - "purpose": "any maskable" - }, - { - "src": "/favicon.ico", - "sizes": "64x64", - "type": "image/x-icon", - "purpose": "any maskable" - } - ], - "screenshots": [ - { - "src": "/screenshots/stoplist-narrow.png", - "sizes": "1440x2960", - "type": "image/png", - "form_factor": "narrow", - "label": "Lista de paradas" - }, - { - "src": "/screenshots/map-narrow.png", - "sizes": "1440x2960", - "type": "image/png", - "form_factor": "narrow", - "label": "Mapa de paradas" - }, - { - "src": "/screenshots/estimates-narrow.png", - "sizes": "1440x2960", - "type": "image/png", - "form_factor": "narrow", - "label": "Estimaciones de llegada a parada" - }, - - { - "src": "/screenshots/stoplist-wide.jpeg", - "sizes": "1788x891", - "type": "image/jpeg", - "form_factor": "wide", - "label": "Lista de paradas" - }, - { - "src": "/screenshots/map-wide.jpeg", - "sizes": "1788x891", - "type": "image/jpeg", - "form_factor": "wide", - "label": "Mapa de paradas" - }, - { - "src": "/screenshots/estimates-wide.jpeg", - "sizes": "1788x891", - "type": "image/jpeg", - "form_factor": "wide", - "label": "Estimaciones de llegada a parada" - } - ] -} \ No newline at end of file diff --git a/public/map-pin-icon.png b/public/map-pin-icon.png deleted file mode 100644 index 0015b64..0000000 Binary files a/public/map-pin-icon.png and /dev/null differ diff --git a/public/screenshots/estimates-narrow.png b/public/screenshots/estimates-narrow.png deleted file mode 100644 index 0337442..0000000 Binary files a/public/screenshots/estimates-narrow.png and /dev/null differ diff --git a/public/screenshots/estimates-wide.jpeg b/public/screenshots/estimates-wide.jpeg deleted file mode 100644 index e81f094..0000000 Binary files a/public/screenshots/estimates-wide.jpeg and /dev/null differ diff --git a/public/screenshots/map-narrow.png b/public/screenshots/map-narrow.png deleted file mode 100644 index 14199c4..0000000 Binary files a/public/screenshots/map-narrow.png and /dev/null differ diff --git a/public/screenshots/map-wide.jpeg b/public/screenshots/map-wide.jpeg deleted file mode 100644 index 6d3ca64..0000000 Binary files a/public/screenshots/map-wide.jpeg and /dev/null differ diff --git a/public/screenshots/stoplist-narrow.png b/public/screenshots/stoplist-narrow.png deleted file mode 100644 index c1d9f25..0000000 Binary files a/public/screenshots/stoplist-narrow.png and /dev/null differ diff --git a/public/screenshots/stoplist-wide.jpeg b/public/screenshots/stoplist-wide.jpeg deleted file mode 100644 index 264e1a7..0000000 Binary files a/public/screenshots/stoplist-wide.jpeg and /dev/null differ diff --git a/public/stops.json b/public/stops.json deleted file mode 100644 index 762b6f4..0000000 --- a/public/stops.json +++ /dev/null @@ -1,15037 +0,0 @@ -[ - { - "stopId": 20, - "name": { - "original": "Rúa do Abade Juan de Bastos (fronte Asociación Veciños)" - }, - "latitude": 42.187593499, - "longitude": -8.741246641, - "lines": [ - "17" - ] - }, - { - "stopId": 40, - "name": { - "original": "Rúa do Abade Juan de Bastos (cruce Baixada da Moo)" - }, - "latitude": 42.192126677, - "longitude": -8.72901589, - "lines": [ - "17" - ] - }, - { - "stopId": 50, - "name": { - "original": "Rúa do Abade Juan de Bastos 24" - }, - "latitude": 42.19287042, - "longitude": -8.727513924, - "lines": [ - "17" - ] - }, - { - "stopId": 70, - "name": { - "original": "Rúa da Lagoa (cruce Camiño do Casmarcelo)" - }, - "latitude": 42.20020175, - "longitude": -8.700621608, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 80, - "name": { - "original": "Rúa da Lagoa 46" - }, - "latitude": 42.200132216, - "longitude": -8.700535777, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 90, - "name": { - "original": "Aeroporto de Peinador" - }, - "latitude": 42.225956918, - "longitude": -8.63286469, - "lines": [ - "A" - ] - }, - { - "stopId": 100, - "name": { - "original": "Avda. do Alcalde Lavadores 125" - }, - "latitude": 42.219008975, - "longitude": -8.69606935, - "lines": [ - "6" - ] - }, - { - "stopId": 110, - "name": { - "original": "Avda. do Alcalde Lavadores 171" - }, - "latitude": 42.215074591, - "longitude": -8.696738405, - "lines": [ - "6" - ] - }, - { - "stopId": 120, - "name": { - "original": "Avda. do Alcalde Lavadores 8" - }, - "latitude": 42.223288295, - "longitude": -8.700954873, - "lines": [ - "6" - ] - }, - { - "stopId": 130, - "name": { - "original": "Avda. do Alcalde Lavadores 102" - }, - "latitude": 42.219001694, - "longitude": -8.696198267, - "lines": [ - "6" - ] - }, - { - "stopId": 140, - "name": { - "original": "Avda. do Alcalde Lavadores 29" - }, - "latitude": 42.223444913, - "longitude": -8.700801996, - "lines": [ - "6" - ] - }, - { - "stopId": 150, - "name": { - "original": "Avda. do Alcalde Lavadores 48" - }, - "latitude": 42.222636676, - "longitude": -8.697201413, - "lines": [ - "6" - ] - }, - { - "stopId": 160, - "name": { - "original": "Avda. do Alcalde Lavadores 67" - }, - "latitude": 42.222830286, - "longitude": -8.697231476, - "lines": [ - "6" - ] - }, - { - "stopId": 170, - "name": { - "original": "Avda. do Alcalde Lavadores 152" - }, - "latitude": 42.215084316, - "longitude": -8.696854931, - "lines": [ - "6" - ] - }, - { - "stopId": 180, - "name": { - "original": "Estrada de Valadares 451" - }, - "latitude": 42.166144986, - "longitude": -8.720162371, - "lines": [ - "7" - ] - }, - { - "stopId": 190, - "name": { - "original": "Rúa de Ángel de Lema 58" - }, - "latitude": 42.250539537, - "longitude": -8.685179363, - "lines": [ - "C3i", - "10" - ] - }, - { - "stopId": 195, - "name": { - "original": "Rúa de Ángel de Lema 247" - }, - "latitude": 42.256624708, - "longitude": -8.677490797, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 200, - "name": { - "original": "Rúa de Ángel de Lema 100" - }, - "latitude": 42.252115803, - "longitude": -8.683374373, - "lines": [ - "C3i", - "10" - ] - }, - { - "stopId": 210, - "name": { - "original": "Rúa de Ángel de Lema 140" - }, - "latitude": 42.255798748, - "longitude": -8.678507526, - "lines": [ - "C3i", - "10" - ] - }, - { - "stopId": 220, - "name": { - "original": "Rúa de Ángel de Lema 163" - }, - "latitude": 42.252694363, - "longitude": -8.68302903, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 230, - "name": { - "original": "Rúa de Ángel de Lema 14" - }, - "latitude": 42.248041601, - "longitude": -8.691024475, - "lines": [ - "C3i", - "10" - ] - }, - { - "stopId": 240, - "name": { - "original": "Rúa de Ángel de Lema 19" - }, - "latitude": 42.247513476, - "longitude": -8.691874301, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 250, - "name": { - "original": "Rúa de Ángel de Lema 221" - }, - "latitude": 42.255252085, - "longitude": -8.679480662, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 260, - "name": { - "original": "Rúa de Ángel de Lema 91" - }, - "latitude": 42.250421216, - "longitude": -8.685464716, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 270, - "name": { - "original": "Rúa de Desiderio Pernas Arquitecto 1" - }, - "latitude": 42.18920151, - "longitude": -8.810340862, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 280, - "name": { - "original": "Rúa do Arquitecto Antonio Cominges 38" - }, - "latitude": 42.189490674, - "longitude": -8.808107114, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 290, - "name": { - "original": "Rúa do Arquitecto Gómez Román 37" - }, - "latitude": 42.190149471, - "longitude": -8.803788225, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 310, - "name": { - "original": "Rúa do Arquitecto Antonio Cominges 4" - }, - "latitude": 42.190850463, - "longitude": -8.80358845, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 320, - "name": { - "original": "Rúa do Arquitecto Antonio Cominges 70" - }, - "latitude": 42.189221331, - "longitude": -8.811730246, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 330, - "name": { - "original": "Rúa do Arquitecto Antonio Cominges 90" - }, - "latitude": 42.187213169, - "longitude": -8.813069201, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 340, - "name": { - "original": "Rúa de Aragón 116" - }, - "latitude": 42.238036494, - "longitude": -8.700921187, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 350, - "name": { - "original": "Rúa de Aragón 162" - }, - "latitude": 42.240488915, - "longitude": -8.700357923, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 360, - "name": { - "original": "Rúa de Aragón 193" - }, - "latitude": 42.24013184, - "longitude": -8.700947033, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 370, - "name": { - "original": "Rúa de Aragón 212" - }, - "latitude": 42.242101304, - "longitude": -8.698394546, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 380, - "name": { - "original": "Rúa de Aragón 221" - }, - "latitude": 42.242091376, - "longitude": -8.698668131, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 390, - "name": { - "original": "Rúa de Aragón 26" - }, - "latitude": 42.233174046, - "longitude": -8.702380309, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 400, - "name": { - "original": "Rúa de Aragón 91" - }, - "latitude": 42.235598195, - "longitude": -8.701426538, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 410, - "name": { - "original": "Rúa de Aragón 82" - }, - "latitude": 42.235524387, - "longitude": -8.701248417, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 420, - "name": { - "original": "Rúa de Aragón 147" - }, - "latitude": 42.238092485, - "longitude": -8.701156245, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 430, - "name": { - "original": "Rúa do Areal (Aduana)" - }, - "latitude": 42.239341996, - "longitude": -8.720234413, - "lines": [ - "A", - "6", - "9B", - "18A", - "24", - "28", - "H1" - ] - }, - { - "stopId": 530, - "name": { - "original": "Avda. de Ricardo Mella (Estación Coruxo)" - }, - "latitude": 42.193562859, - "longitude": -8.78173994, - "lines": [ - "12A" - ] - }, - { - "stopId": 540, - "name": { - "original": "Avda. de Ricardo Mella (fronte 223)" - }, - "latitude": 42.189424424, - "longitude": -8.790733064, - "lines": [ - "12A" - ] - }, - { - "stopId": 560, - "name": { - "original": "Avda. de Ricardo Mella 518" - }, - "latitude": 42.181015915, - "longitude": -8.807696921, - "lines": [ - "10" - ] - }, - { - "stopId": 570, - "name": { - "original": "Avda. de Ricardo Mella 250" - }, - "latitude": 42.195225102, - "longitude": -8.775226375, - "lines": [ - "12A" - ] - }, - { - "stopId": 572, - "name": { - "original": "Estrada de Madrid 210" - }, - "latitude": 42.214058797, - "longitude": -8.672946954, - "lines": [ - "12B", - "15B", - "15C", - "U2" - ] - }, - { - "stopId": 580, - "name": { - "original": "Avda. de Ricardo Mella 135" - }, - "latitude": 42.195766012, - "longitude": -8.773648966, - "lines": [ - "12A" - ] - }, - { - "stopId": 600, - "name": { - "original": "Avda. de Ricardo Mella 273" - }, - "latitude": 42.189927171, - "longitude": -8.800634184, - "lines": [ - "C3d", - "10", - "12A" - ] - }, - { - "stopId": 620, - "name": { - "original": "Avda. de Ricado Mella 165" - }, - "latitude": 42.1935678, - "longitude": -8.781529566, - "lines": [ - "12A" - ] - }, - { - "stopId": 630, - "name": { - "original": "Avda. de Ricardo Mella 223" - }, - "latitude": 42.189304527, - "longitude": -8.79068363, - "lines": [ - "12A" - ] - }, - { - "stopId": 650, - "name": { - "original": "Avda. de Ricardo Mella 289" - }, - "latitude": 42.181065441, - "longitude": -8.807509871, - "lines": [ - "C3d", - "10", - "12A" - ] - }, - { - "stopId": 660, - "name": { - "original": "Avda. do Alcalde Portanet 34" - }, - "latitude": 42.211494566, - "longitude": -8.736022397, - "lines": [ - "7", - "12B", - "17", - "H1" - ] - }, - { - "stopId": 680, - "name": { - "original": "Avda. do Aeroporto (Aeroclub)" - }, - "latitude": 42.229005723, - "longitude": -8.634356866, - "lines": [ - "A" - ] - }, - { - "stopId": 690, - "name": { - "original": "Avda. do Aeroporto 656" - }, - "latitude": 42.233064093, - "longitude": -8.642742935, - "lines": [ - "A", - "25" - ] - }, - { - "stopId": 700, - "name": { - "original": "Avda. do Aeroporto (Colexio)" - }, - "latitude": 42.228674047, - "longitude": -8.633340309, - "lines": [ - "A" - ] - }, - { - "stopId": 710, - "name": { - "original": "Rúa de Aragón (Instituto)" - }, - "latitude": 42.232478958, - "longitude": -8.701988706, - "lines": [ - "A", - "4A", - "9B", - "24", - "27", - "28" - ] - }, - { - "stopId": 720, - "name": { - "original": "Avda. do Aeroporto 215" - }, - "latitude": 42.235739016, - "longitude": -8.684254232, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 730, - "name": { - "original": "Avda. do Aeroporto 130" - }, - "latitude": 42.231109162, - "longitude": -8.690501398, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 740, - "name": { - "original": "Avda. do Aeroporto 181" - }, - "latitude": 42.233560754, - "longitude": -8.686937524, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 750, - "name": { - "original": "Avda. do Aeroporto 184" - }, - "latitude": 42.233103986, - "longitude": -8.68716283, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 760, - "name": { - "original": "Avda. do Aeroporto 240" - }, - "latitude": 42.236775611, - "longitude": -8.683736566, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 770, - "name": { - "original": "Avda. do Aeroporto 273" - }, - "latitude": 42.238939528, - "longitude": -8.681422497, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 780, - "name": { - "original": "Avda. do Aeroporto 298" - }, - "latitude": 42.238554288, - "longitude": -8.680663432, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 790, - "name": { - "original": "Avda. do Aeroporto 325" - }, - "latitude": 42.237426811, - "longitude": -8.675474476, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 800, - "name": { - "original": "Avda. do Aeroporto 328" - }, - "latitude": 42.237801674, - "longitude": -8.676524783, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 810, - "name": { - "original": "Avda. do Aeroporto 350" - }, - "latitude": 42.235521261, - "longitude": -8.67465521, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 820, - "name": { - "original": "Avda. do Aeroporto 377" - }, - "latitude": 42.234766626, - "longitude": -8.671305131, - "lines": [ - "A", - "9B" - ] - }, - { - "stopId": 830, - "name": { - "original": "Avda. do Aeroporto 378" - }, - "latitude": 42.234673289, - "longitude": -8.671348046, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 840, - "name": { - "original": "Avda. do Aeroporto 43" - }, - "latitude": 42.234904325, - "longitude": -8.699245802, - "lines": [ - "A", - "4A", - "9B", - "24", - "27", - "28" - ] - }, - { - "stopId": 850, - "name": { - "original": "Avda. do Aeroporto 423" - }, - "latitude": 42.23630176, - "longitude": -8.665791599, - "lines": [ - "A", - "9B" - ] - }, - { - "stopId": 860, - "name": { - "original": "Avda. do Aeroporto 446" - }, - "latitude": 42.235612667, - "longitude": -8.666529207, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 870, - "name": { - "original": "Avda. do Aeroporto 447" - }, - "latitude": 42.23543058, - "longitude": -8.66197943, - "lines": [ - "A", - "9B" - ] - }, - { - "stopId": 880, - "name": { - "original": "Avda. do Aeroporto 484" - }, - "latitude": 42.23544051, - "longitude": -8.662354939, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 890, - "name": { - "original": "Avda. do Aeroporto 491" - }, - "latitude": 42.232066419, - "longitude": -8.653842977, - "lines": [ - "A" - ] - }, - { - "stopId": 900, - "name": { - "original": "Avda. do Aeroporto 531" - }, - "latitude": 42.233527998, - "longitude": -8.648237616, - "lines": [ - "A" - ] - }, - { - "stopId": 910, - "name": { - "original": "Avda. do Aeroporto 54" - }, - "latitude": 42.234679919, - "longitude": -8.699623994, - "lines": [ - "A", - "4A", - "9B", - "24", - "27", - "28" - ] - }, - { - "stopId": 920, - "name": { - "original": "Avda. do Aeroporto (cruce Camiño das Cereixeiras)" - }, - "latitude": 42.233499069, - "longitude": -8.643325214, - "lines": [ - "A" - ] - }, - { - "stopId": 930, - "name": { - "original": "Avda. do Aeroporto 570" - }, - "latitude": 42.231979036, - "longitude": -8.65372496, - "lines": [ - "A" - ] - }, - { - "stopId": 940, - "name": { - "original": "Avda. do Aeroporto 605" - }, - "latitude": 42.230493878, - "longitude": -8.638023273, - "lines": [ - "A" - ] - }, - { - "stopId": 950, - "name": { - "original": "Avda. do Aeroporto 614" - }, - "latitude": 42.233626818, - "longitude": -8.647811163, - "lines": [ - "A", - "25" - ] - }, - { - "stopId": 960, - "name": { - "original": "Avda. do Aeroporto 686" - }, - "latitude": 42.230918888, - "longitude": -8.638532893, - "lines": [ - "A" - ] - }, - { - "stopId": 970, - "name": { - "original": "Avda. do Aeroporto 91" - }, - "latitude": 42.232787318, - "longitude": -8.693473285, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 980, - "name": { - "original": "Avda. da Atlántida 99" - }, - "latitude": 42.221170087, - "longitude": -8.763656977, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 990, - "name": { - "original": "Avda. da Atlántida (fronte 148)" - }, - "latitude": 42.222451366, - "longitude": -8.769134894, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 1000, - "name": { - "original": "Avda. da Atlántida 109" - }, - "latitude": 42.221220508, - "longitude": -8.767194468, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 1010, - "name": { - "original": "Avda. da Atlántida 136" - }, - "latitude": 42.221479642, - "longitude": -8.767482698, - "lines": [ - "10", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 1020, - "name": { - "original": "Avda. da Atlántida 150" - }, - "latitude": 42.222764778, - "longitude": -8.769405842, - "lines": [ - "10", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 1030, - "name": { - "original": "Avda. da Atlántida 25" - }, - "latitude": 42.223219677, - "longitude": -8.754753277, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 1040, - "name": { - "original": "Avda. da Atlántida 32" - }, - "latitude": 42.223237503, - "longitude": -8.755707801, - "lines": [ - "10", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 1050, - "name": { - "original": "Avda. da Atlántida 71" - }, - "latitude": 42.221875354, - "longitude": -8.760935381, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 1060, - "name": { - "original": "Avda. da Atlántida 84" - }, - "latitude": 42.221789505, - "longitude": -8.759905458, - "lines": [ - "10", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 1070, - "name": { - "original": "Avda. da Atlántida 114" - }, - "latitude": 42.221148357, - "longitude": -8.764660969, - "lines": [ - "10", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 1110, - "name": { - "original": "Praza Ribeira do Berbés" - }, - "latitude": 42.237821273, - "longitude": -8.729666379, - "lines": [ - "A", - "5B", - "6" - ] - }, - { - "stopId": 1120, - "name": { - "original": "Avda. de Beiramar (fronte Casa do Mar)" - }, - "latitude": 42.23416729, - "longitude": -8.733331094, - "lines": [ - "6", - "9B", - "15B", - "28" - ] - }, - { - "stopId": 1130, - "name": { - "original": "Avda. de Beiramar (Peiraos auxiliares)" - }, - "latitude": 42.231238831, - "longitude": -8.735255297, - "lines": [ - "6", - "9B", - "15B", - "28" - ] - }, - { - "stopId": 1140, - "name": { - "original": "Avda. de Beiramar (Freire)" - }, - "latitude": 42.225068475, - "longitude": -8.74774586, - "lines": [ - "6", - "9B", - "28" - ] - }, - { - "stopId": 1150, - "name": { - "original": "Rúa da Ribeira do Berbés" - }, - "latitude": 42.237384264, - "longitude": -8.729603006, - "lines": [ - "C1", - "C3d", - "A", - "5A", - "9B", - "10", - "15B", - "15C", - "28", - "N4" - ] - }, - { - "stopId": 1160, - "name": { - "original": "Avda. de Beiramar (Sto. Domingo)" - }, - "latitude": 42.225759663, - "longitude": -8.743239749, - "lines": [ - "6", - "9B", - "28" - ] - }, - { - "stopId": 1200, - "name": { - "original": "Avda. de Beiramar 51" - }, - "latitude": 42.234233798, - "longitude": -8.73312316, - "lines": [ - "10", - "15B" - ] - }, - { - "stopId": 1210, - "name": { - "original": "Avda. de Beiramar 61" - }, - "latitude": 42.230811976, - "longitude": -8.735364934, - "lines": [ - "10", - "15B" - ] - }, - { - "stopId": 1220, - "name": { - "original": "Avda. de Buenos Aires 46" - }, - "latitude": 42.247097055, - "longitude": -8.693109251, - "lines": [ - "5A", - "10", - "31", - "U2", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 1230, - "name": { - "original": "Avda. de Buenos Aires 49" - }, - "latitude": 42.247251925, - "longitude": -8.693122662, - "lines": [ - "5B", - "10", - "N1", - "H3" - ] - }, - { - "stopId": 1240, - "name": { - "original": "Avda. de Buenos Aires 8" - }, - "latitude": 42.249128205, - "longitude": -8.69514773, - "lines": [ - "5A", - "10", - "31", - "U2", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 1250, - "name": { - "original": "Avda. de Castelao 16" - }, - "latitude": 42.219730396, - "longitude": -8.737456513, - "lines": [ - "C3d", - "4A", - "4C", - "5B", - "10", - "12A", - "13", - "15A", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 1260, - "name": { - "original": "Avda. de Castelao 21" - }, - "latitude": 42.219775977, - "longitude": -8.736255523, - "lines": [ - "C3i", - "4A", - "4C", - "5B", - "10", - "11", - "12A", - "15A", - "N1", - "U1" - ] - }, - { - "stopId": 1270, - "name": { - "original": "Avda. de Castelao 50" - }, - "latitude": 42.218704937, - "longitude": -8.74254446, - "lines": [ - "C3d", - "4A", - "4C", - "5B", - "10", - "12A", - "13", - "15A", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 1280, - "name": { - "original": "Avda. de Castelao 41" - }, - "latitude": 42.218523315, - "longitude": -8.74223465, - "lines": [ - "C3i", - "4A", - "4C", - "10", - "11", - "12A", - "15A", - "N1", - "U1" - ] - }, - { - "stopId": 1290, - "name": { - "original": "Avda. de Castelao 54" - }, - "latitude": 42.218158263, - "longitude": -8.745797727, - "lines": [ - "C3d", - "4A", - "4C", - "5B", - "10", - "12A", - "13", - "15A", - "N4", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 1300, - "name": { - "original": "Avda. de Castelao 68" - }, - "latitude": 42.217466378, - "longitude": -8.751245499, - "lines": [ - "C3d", - "4A", - "4C", - "5B", - "10", - "12A", - "13", - "15A", - "N4", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 1310, - "name": { - "original": "Avda. de Castelao 73" - }, - "latitude": 42.217705528, - "longitude": -8.747753325, - "lines": [ - "C3i", - "4A", - "4C", - "10", - "11", - "12A", - "15A", - "N1", - "N4", - "U1" - ] - }, - { - "stopId": 1320, - "name": { - "original": "Avda. de Castelao 87" - }, - "latitude": 42.217302224, - "longitude": -8.751104752, - "lines": [ - "C3i", - "10", - "12A", - "N1", - "U1" - ] - }, - { - "stopId": 1330, - "name": { - "original": "Avda. de Castrelos (Pavillón)" - }, - "latitude": 42.219553947, - "longitude": -8.732509436, - "lines": [ - "A", - "16", - "23", - "27", - "H2" - ] - }, - { - "stopId": 1340, - "name": { - "original": "Avda. de Castrelos (Parque)" - }, - "latitude": 42.212870645, - "longitude": -8.732131792, - "lines": [ - "27", - "H2" - ] - }, - { - "stopId": 1350, - "name": { - "original": "Avda. de Castrelos 121" - }, - "latitude": 42.208026488, - "longitude": -8.7312098, - "lines": [ - "7", - "12B", - "17", - "27" - ] - }, - { - "stopId": 1360, - "name": { - "original": "Avda. de Castrelos 16" - }, - "latitude": 42.219613217, - "longitude": -8.732629194, - "lines": [ - "7", - "12B", - "17", - "27", - "H2", - "PTL" - ] - }, - { - "stopId": 1380, - "name": { - "original": "Avda. de Castrelos 179" - }, - "latitude": 42.20533568, - "longitude": -8.730078621, - "lines": [ - "7", - "12B", - "17", - "U1" - ] - }, - { - "stopId": 1390, - "name": { - "original": "Avda. de Castrelos 186" - }, - "latitude": 42.212735556, - "longitude": -8.732314182, - "lines": [ - "A", - "7", - "12B", - "17", - "27", - "U1", - "H2", - "H", - "PTL" - ] - }, - { - "stopId": 1400, - "name": { - "original": "Avda. de Castrelos 202" - }, - "latitude": 42.210706683, - "longitude": -8.732237372, - "lines": [ - "A", - "7", - "12B", - "17", - "27", - "U1", - "H1", - "H2", - "H", - "PTL" - ] - }, - { - "stopId": 1410, - "name": { - "original": "Avda. de Castrelos 13" - }, - "latitude": 42.218060161, - "longitude": -8.732450427, - "lines": [ - "A", - "16", - "23", - "27", - "H2" - ] - }, - { - "stopId": 1420, - "name": { - "original": "Avda. de Castrelos 297" - }, - "latitude": 42.201440099, - "longitude": -8.726409762, - "lines": [ - "7" - ] - }, - { - "stopId": 1430, - "name": { - "original": "Avda. de Castrelos 318" - }, - "latitude": 42.203408408, - "longitude": -8.728817983, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 1440, - "name": { - "original": "Avda. de Castrelos 339" - }, - "latitude": 42.198480135, - "longitude": -8.723827649, - "lines": [ - "7" - ] - }, - { - "stopId": 1450, - "name": { - "original": "Avda. de Castrelos 366" - }, - "latitude": 42.201044695, - "longitude": -8.726112037, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 1460, - "name": { - "original": "Avda. de Castrelos 396" - }, - "latitude": 42.198867605, - "longitude": -8.72460549, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 1470, - "name": { - "original": "Avda. de Castrelos 399" - }, - "latitude": 42.194996678, - "longitude": -8.72097155, - "lines": [ - "7" - ] - }, - { - "stopId": 1480, - "name": { - "original": "Avda. de Castrelos 526" - }, - "latitude": 42.19015727, - "longitude": -8.72109012, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 1490, - "name": { - "original": "Avda. de Castrelos 67" - }, - "latitude": 42.210613294, - "longitude": -8.732057664, - "lines": [ - "7", - "12B", - "17", - "27", - "H1", - "H2" - ] - }, - { - "stopId": 1500, - "name": { - "original": "Avda. de Castrelos 58" - }, - "latitude": 42.217084821, - "longitude": -8.732530893, - "lines": [ - "7", - "12B", - "17", - "27", - "H2", - "PTL" - ] - }, - { - "stopId": 1510, - "name": { - "original": "Avda. da Ponte 80" - }, - "latitude": 42.215203365, - "longitude": -8.670416197, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 1520, - "name": { - "original": "Avda. da Ponte 83" - }, - "latitude": 42.215400704, - "longitude": -8.671308533, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 1530, - "name": { - "original": "Avda. da Ponte (fronte Grupo S. Gorxal)" - }, - "latitude": 42.212814417, - "longitude": -8.670537674, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 1540, - "name": { - "original": "Avda. da Ponte 15" - }, - "latitude": 42.221677429, - "longitude": -8.66978207, - "lines": [ - "11", - "15A", - "15B", - "15C" - ] - }, - { - "stopId": 1550, - "name": { - "original": "Avda. da Ponte 18" - }, - "latitude": 42.221299207, - "longitude": -8.670013709, - "lines": [ - "11", - "15A", - "15B", - "15C" - ] - }, - { - "stopId": 1560, - "name": { - "original": "Avda. da Ponte 31" - }, - "latitude": 42.219388605, - "longitude": -8.669172606, - "lines": [ - "15A", - "15B" - ] - }, - { - "stopId": 1570, - "name": { - "original": "Avda. da Ponte 47" - }, - "latitude": 42.217957539, - "longitude": -8.669369577, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 1580, - "name": { - "original": "Avda. da Ponte 54" - }, - "latitude": 42.218393587, - "longitude": -8.669480106, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 1590, - "name": { - "original": "Avda. de Galicia (Parque Riouxa)" - }, - "latitude": 42.256667905, - "longitude": -8.682575386, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1600, - "name": { - "original": "Avda. de Galicia 103" - }, - "latitude": 42.251389209, - "longitude": -8.689369833, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1610, - "name": { - "original": "Avda. de Galicia 146" - }, - "latitude": 42.251376198, - "longitude": -8.68920404, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1620, - "name": { - "original": "Avda. de Galicia 139" - }, - "latitude": 42.253987165, - "longitude": -8.686196616, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1630, - "name": { - "original": "Avda. de Galicia 165" - }, - "latitude": 42.255177674, - "longitude": -8.684734482, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1640, - "name": { - "original": "Avda. de Galicia 200" - }, - "latitude": 42.254950083, - "longitude": -8.684862748, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1650, - "name": { - "original": "Avda. de Galicia 238" - }, - "latitude": 42.256910715, - "longitude": -8.68201353, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1660, - "name": { - "original": "Avda. de Galicia 280" - }, - "latitude": 42.259217959, - "longitude": -8.679666503, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1670, - "name": { - "original": "Avda. de Galicia 285" - }, - "latitude": 42.258365967, - "longitude": -8.680508997, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1680, - "name": { - "original": "Avda. de Galicia (Parque Cruce Balbarda)" - }, - "latitude": 42.251327471, - "longitude": -8.69260735, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1690, - "name": { - "original": "Avda. de Galicia 71" - }, - "latitude": 42.251420909, - "longitude": -8.692153216, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1710, - "name": { - "original": "Avda. de Vigo 6" - }, - "latitude": 42.274450823, - "longitude": -8.667138233, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1720, - "name": { - "original": "Avda. de Vigo 95" - }, - "latitude": 42.270480988, - "longitude": -8.667726374, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1730, - "name": { - "original": "Avda. de Vigo 129" - }, - "latitude": 42.267833798, - "longitude": -8.671345739, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1740, - "name": { - "original": "Avda. de Vigo 120" - }, - "latitude": 42.27068743, - "longitude": -8.668057842, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1750, - "name": { - "original": "Avda. de Vigo 161" - }, - "latitude": 42.266305919, - "longitude": -8.672818918, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1760, - "name": { - "original": "Avda. de Vigo 201" - }, - "latitude": 42.26408966, - "longitude": -8.674082239, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1770, - "name": { - "original": "Avda. de Vigo (Alameda de Rosalía de Castro)" - }, - "latitude": 42.26785896, - "longitude": -8.671440263, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1780, - "name": { - "original": "Avda. de Vigo 230" - }, - "latitude": 42.266245291, - "longitude": -8.672965754, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1790, - "name": { - "original": "Avda. de Vigo 261 (Cuatro Puentes)" - }, - "latitude": 42.261621089, - "longitude": -8.677207279, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1800, - "name": { - "original": "Avda. de Vigo 266" - }, - "latitude": 42.263995234, - "longitude": -8.674224503, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1810, - "name": { - "original": "Avda. de Vigo 320" - }, - "latitude": 42.262068498, - "longitude": -8.676736193, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1820, - "name": { - "original": "Avda. de Vigo 49" - }, - "latitude": 42.271878394, - "longitude": -8.666356304, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1830, - "name": { - "original": "Avda. de Vigo 11" - }, - "latitude": 42.274038501, - "longitude": -8.666949932, - "lines": [ - "C3d" - ] - }, - { - "stopId": 1840, - "name": { - "original": "Avda. de Vigo 72" - }, - "latitude": 42.27159436, - "longitude": -8.666389735, - "lines": [ - "C3i" - ] - }, - { - "stopId": 1850, - "name": { - "original": "Avda. de Europa (antes Camiño Freixeiro)" - }, - "latitude": 42.216135691, - "longitude": -8.759632243, - "lines": [ - "C3d", - "C3i", - "4A", - "12A", - "15A" - ] - }, - { - "stopId": 1860, - "name": { - "original": "Avda. de Europa (cruce Rúa da Pardaíña)" - }, - "latitude": 42.216741568, - "longitude": -8.757129742, - "lines": [ - "C3d", - "C3i", - "4A", - "12A", - "15A" - ] - }, - { - "stopId": 1870, - "name": { - "original": "Avda. de Europa 102" - }, - "latitude": 42.211235082, - "longitude": -8.773459294, - "lines": [ - "C3d", - "C3i", - "15A" - ] - }, - { - "stopId": 1880, - "name": { - "original": "Avda. de Europa (cruce Rúa das Teixugueiras)" - }, - "latitude": 42.216687933, - "longitude": -8.756794466, - "lines": [ - "C3d", - "C3i", - "4A", - "4C", - "12A", - "15A", - "N1" - ] - }, - { - "stopId": 1890, - "name": { - "original": "Avda. de Europa 23" - }, - "latitude": 42.215913672, - "longitude": -8.759904797, - "lines": [ - "C3d", - "C3i", - "4A", - "4C", - "12A", - "15A", - "N1" - ] - }, - { - "stopId": 1900, - "name": { - "original": "Avda. de Europa (cruce Rúa do Bravo)" - }, - "latitude": 42.211855119, - "longitude": -8.766755158, - "lines": [ - "C3d", - "C3i", - "4C", - "15A", - "N1" - ] - }, - { - "stopId": 1910, - "name": { - "original": "Avda. de Europa (fronte cruce Rúa do Bravo)" - }, - "latitude": 42.211905694, - "longitude": -8.766999036, - "lines": [ - "C3d", - "C3i", - "15A" - ] - }, - { - "stopId": 1920, - "name": { - "original": "Avda. de Europa 101" - }, - "latitude": 42.211066417, - "longitude": -8.772953743, - "lines": [ - "C3d", - "C3i", - "4C", - "15A", - "N1" - ] - }, - { - "stopId": 1930, - "name": { - "original": "Estrada de Madrid (fronte Seminario)" - }, - "latitude": 42.21474886, - "longitude": -8.69897918, - "lines": [ - "12A", - "12B", - "13", - "U2" - ] - }, - { - "stopId": 1940, - "name": { - "original": "Avda. de Madrid 136" - }, - "latitude": 42.218338954, - "longitude": -8.703817429, - "lines": [ - "12A", - "12B", - "13" - ] - }, - { - "stopId": 1950, - "name": { - "original": "Avda. de Madrid 124" - }, - "latitude": 42.220567154, - "longitude": -8.706419628, - "lines": [ - "12A", - "12B", - "13" - ] - }, - { - "stopId": 1960, - "name": { - "original": "Avda. de Madrid 62" - }, - "latitude": 42.224676782, - "longitude": -8.711832326, - "lines": [ - "12A", - "12B", - "13", - "U2", - "H2" - ] - }, - { - "stopId": 1970, - "name": { - "original": "Avda. de Madrid 57" - }, - "latitude": 42.223965709, - "longitude": -8.710062068, - "lines": [ - "12A", - "12B", - "13" - ] - }, - { - "stopId": 1980, - "name": { - "original": "Estrada de Madrid (Seminario)" - }, - "latitude": 42.214703324, - "longitude": -8.699378397, - "lines": [ - "12A", - "12B", - "13", - "U2" - ] - }, - { - "stopId": 1990, - "name": { - "original": "Avda. de Madrid (cruce Camiño do Raviso)" - }, - "latitude": 42.222130198, - "longitude": -8.708300774, - "lines": [ - "12A", - "12B", - "13", - "U2" - ] - }, - { - "stopId": 2000, - "name": { - "original": "Avda. de Madrid 133" - }, - "latitude": 42.220728012, - "longitude": -8.70612292, - "lines": [ - "12A", - "12B", - "13" - ] - }, - { - "stopId": 2010, - "name": { - "original": "Avda. de Madrid 195" - }, - "latitude": 42.218213283, - "longitude": -8.703163426, - "lines": [ - "12A", - "12B", - "13" - ] - }, - { - "stopId": 2020, - "name": { - "original": "Avda. de Madrid 2" - }, - "latitude": 42.228518615, - "longitude": -8.719214126, - "lines": [ - "12A", - "12B", - "13", - "U2" - ] - }, - { - "stopId": 2030, - "name": { - "original": "Avda. de Madrid 28" - }, - "latitude": 42.226744428, - "longitude": -8.716268699, - "lines": [ - "12A", - "12B", - "13", - "H2" - ] - }, - { - "stopId": 2040, - "name": { - "original": "Avda. de Madrid (trasera Colexio Hogar)" - }, - "latitude": 42.226835791, - "longitude": -8.715823453, - "lines": [ - "12A", - "12B", - "13" - ] - }, - { - "stopId": 2060, - "name": { - "original": "Avda. de Redondela 122" - }, - "latitude": 42.259945558, - "longitude": -8.672608434, - "lines": [ - "C3d" - ] - }, - { - "stopId": 2070, - "name": { - "original": "Avda. de Redondela 109" - }, - "latitude": 42.259481393, - "longitude": -8.67292487, - "lines": [ - "C3i" - ] - }, - { - "stopId": 2080, - "name": { - "original": "Avda. de Redondela 19" - }, - "latitude": 42.266569717, - "longitude": -8.667160768, - "lines": [ - "C3i" - ] - }, - { - "stopId": 2090, - "name": { - "original": "Avda. de Redondela 32" - }, - "latitude": 42.272074281, - "longitude": -8.664593691, - "lines": [ - "C3d" - ] - }, - { - "stopId": 2100, - "name": { - "original": "Avda. de Redondela 47" - }, - "latitude": 42.263186001, - "longitude": -8.668939094, - "lines": [ - "C3i" - ] - }, - { - "stopId": 2110, - "name": { - "original": "Avda. de Redondela 70" - }, - "latitude": 42.263286688, - "longitude": -8.668985036, - "lines": [ - "C3d" - ] - }, - { - "stopId": 2130, - "name": { - "original": "Avda. de Redondela (Instituto)" - }, - "latitude": 42.266758811, - "longitude": -8.667247828, - "lines": [ - "C3d" - ] - }, - { - "stopId": 2140, - "name": { - "original": "Avda. de Samil (Verbum)" - }, - "latitude": 42.213799707, - "longitude": -8.774374426, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 2150, - "name": { - "original": "Avda. de Samil (fronte Praia da Fonte)" - }, - "latitude": 42.221416498, - "longitude": -8.773724153, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 2160, - "name": { - "original": "Avda. de Samil 15" - }, - "latitude": 42.215907608, - "longitude": -8.774702031, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 2170, - "name": { - "original": "Avda. de Samil 35" - }, - "latitude": 42.210171416, - "longitude": -8.774585056, - "lines": [ - "C3d", - "4C", - "10" - ] - }, - { - "stopId": 2180, - "name": { - "original": "Avda. de Samil 67" - }, - "latitude": 42.206809895, - "longitude": -8.776206766, - "lines": [ - "C3d", - "4C", - "10" - ] - }, - { - "stopId": 2190, - "name": { - "original": "Avda. de Samil 81" - }, - "latitude": 42.205147646, - "longitude": -8.77674534, - "lines": [ - "C3d", - "4C", - "10" - ] - }, - { - "stopId": 2200, - "name": { - "original": "Avda. de Santa Mariña 110" - }, - "latitude": 42.22271748, - "longitude": -8.656176614, - "lines": [ - "11" - ] - }, - { - "stopId": 2210, - "name": { - "original": "Avda. de Santa Mariña 137" - }, - "latitude": 42.222538699, - "longitude": -8.656616496, - "lines": [ - "11" - ] - }, - { - "stopId": 2220, - "name": { - "original": "Avda. de Santa Mariña 17" - }, - "latitude": 42.220338634, - "longitude": -8.668666271, - "lines": [ - "11" - ] - }, - { - "stopId": 2230, - "name": { - "original": "Avda. de Santa Mariña 52" - }, - "latitude": 42.222347963, - "longitude": -8.662841482, - "lines": [ - "11" - ] - }, - { - "stopId": 2240, - "name": { - "original": "Avda. de Santa Mariña 77" - }, - "latitude": 42.222432209, - "longitude": -8.662773458, - "lines": [ - "11" - ] - }, - { - "stopId": 2250, - "name": { - "original": "Avda. de Santa Mariña (cruce Camiño do Narxo)" - }, - "latitude": 42.220826115, - "longitude": -8.659651094, - "lines": [ - "11" - ] - }, - { - "stopId": 2260, - "name": { - "original": "Avda. de Santa Mariña 18" - }, - "latitude": 42.220504663, - "longitude": -8.668053014, - "lines": [ - "11" - ] - }, - { - "stopId": 2270, - "name": { - "original": "Avda. de Santa Mariña 103" - }, - "latitude": 42.22113201, - "longitude": -8.658591621, - "lines": [ - "11" - ] - }, - { - "stopId": 2280, - "name": { - "original": "Baixada á Laxe 31" - }, - "latitude": 42.21650849, - "longitude": -8.719175368, - "lines": [ - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 2290, - "name": { - "original": "Baixada á Laxe 44" - }, - "latitude": 42.216415126, - "longitude": -8.719355076, - "lines": [ - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 2300, - "name": { - "original": "Baixada á Ponte Nova 13" - }, - "latitude": 42.22078735, - "longitude": -8.722722261, - "lines": [ - "18A" - ] - }, - { - "stopId": 2310, - "name": { - "original": "Baixada á Praia (fronte 187)" - }, - "latitude": 42.173398721, - "longitude": -8.811050666, - "lines": [ - "C3d", - "10", - "12A" - ] - }, - { - "stopId": 2320, - "name": { - "original": "Baixada á Praia 121" - }, - "latitude": 42.172541892, - "longitude": -8.809133287, - "lines": [ - "10" - ] - }, - { - "stopId": 2330, - "name": { - "original": "Avda. de Ricardo Mella 357" - }, - "latitude": 42.173316968, - "longitude": -8.81100291, - "lines": [ - "10" - ] - }, - { - "stopId": 2340, - "name": { - "original": "Baixada á Praia 44" - }, - "latitude": 42.167981444, - "longitude": -8.806504239, - "lines": [ - "C3d", - "10", - "12A" - ] - }, - { - "stopId": 2350, - "name": { - "original": "Baixada á Praia 74" - }, - "latitude": 42.169850316, - "longitude": -8.808861828, - "lines": [ - "C3d", - "10", - "12A" - ] - }, - { - "stopId": 2360, - "name": { - "original": "Baixada á Praia (Parque C.Cívico)" - }, - "latitude": 42.167825345, - "longitude": -8.806386831, - "lines": [ - "10" - ] - }, - { - "stopId": 2370, - "name": { - "original": "Baixada á Praia 94" - }, - "latitude": 42.172705652, - "longitude": -8.809114415, - "lines": [ - "C3d", - "10", - "12A" - ] - }, - { - "stopId": 2380, - "name": { - "original": "Baixada á Praia 101" - }, - "latitude": 42.169719111, - "longitude": -8.808832324, - "lines": [ - "10" - ] - }, - { - "stopId": 2390, - "name": { - "original": "Baixada á Salgueira 49" - }, - "latitude": 42.224020371, - "longitude": -8.716787891, - "lines": [ - "18A" - ] - }, - { - "stopId": 2410, - "name": { - "original": "Baixada ao Río 31" - }, - "latitude": 42.209020914, - "longitude": -8.702331689, - "lines": [ - "14" - ] - }, - { - "stopId": 2420, - "name": { - "original": "Rúa do Cacheno (Lavadero)" - }, - "latitude": 42.208468606, - "longitude": -8.702143934, - "lines": [ - "14" - ] - }, - { - "stopId": 2430, - "name": { - "original": "Rúa de Barcelona 64" - }, - "latitude": 42.223917068, - "longitude": -8.726168827, - "lines": [ - "C1" - ] - }, - { - "stopId": 2440, - "name": { - "original": "Rúa de Barcelona 2" - }, - "latitude": 42.228315534, - "longitude": -8.721741958, - "lines": [ - "C1" - ] - }, - { - "stopId": 2450, - "name": { - "original": "Rúa de Barcelona 32" - }, - "latitude": 42.226024692, - "longitude": -8.723390804, - "lines": [ - "C1" - ] - }, - { - "stopId": 2460, - "name": { - "original": "Rúa de Xeme 59" - }, - "latitude": 42.203300943, - "longitude": -8.696320858, - "lines": [ - "14" - ] - }, - { - "stopId": 2490, - "name": { - "original": "Rúa das Coutadas 57" - }, - "latitude": 42.194635725, - "longitude": -8.699504032, - "lines": [ - "6", - "27" - ] - }, - { - "stopId": 2500, - "name": { - "original": "Rúa de Ramiro Pascual (Igrexa)" - }, - "latitude": 42.191950062, - "longitude": -8.707193511, - "lines": [ - "27" - ] - }, - { - "stopId": 2510, - "name": { - "original": "Avda. de Castrelos 439" - }, - "latitude": 42.191323803, - "longitude": -8.721049887, - "lines": [ - "7" - ] - }, - { - "stopId": 2520, - "name": { - "original": "Estrada de Bembrive 238" - }, - "latitude": 42.204563665, - "longitude": -8.687025359, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 2540, - "name": { - "original": "Bouzas (Rotonda de Las Anclas)" - }, - "latitude": 42.22513153, - "longitude": -8.751597027, - "lines": [ - "6", - "9B", - "28" - ] - }, - { - "stopId": 2550, - "name": { - "original": "Camiño da Brea 10" - }, - "latitude": 42.204086577, - "longitude": -8.704832445, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 2560, - "name": { - "original": "Camiño da Brea 37" - }, - "latitude": 42.204297185, - "longitude": -8.704942415, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 2570, - "name": { - "original": "Camiño da Brea 54" - }, - "latitude": 42.207146083, - "longitude": -8.704526775, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 2580, - "name": { - "original": "Camiño da Brea 69" - }, - "latitude": 42.207235488, - "longitude": -8.704631381, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 2590, - "name": { - "original": "Rúa da Cabalaría 94" - }, - "latitude": 42.232442621, - "longitude": -8.689558541, - "lines": [ - "28" - ] - }, - { - "stopId": 2600, - "name": { - "original": "Rúa da Cabalaría 153" - }, - "latitude": 42.235437997, - "longitude": -8.689019794, - "lines": [ - "27", - "28" - ] - }, - { - "stopId": 2610, - "name": { - "original": "Rúa da Cabalaría 14" - }, - "latitude": 42.233426101, - "longitude": -8.693298639, - "lines": [ - "28" - ] - }, - { - "stopId": 2620, - "name": { - "original": "Rúa da Cabalaría 186" - }, - "latitude": 42.235420737, - "longitude": -8.68894034, - "lines": [ - "28" - ] - }, - { - "stopId": 2630, - "name": { - "original": "Rúa da Cabalaría (cruce Subida ao Rosal Florido)" - }, - "latitude": 42.233483693, - "longitude": -8.693266452, - "lines": [ - "27", - "28" - ] - }, - { - "stopId": 2640, - "name": { - "original": "Rúa da Cabalaría 67" - }, - "latitude": 42.232559793, - "longitude": -8.689848219, - "lines": [ - "27", - "28" - ] - }, - { - "stopId": 2735, - "name": { - "original": "Rúa da Cachamuíña (Concello)" - }, - "latitude": 42.235033314, - "longitude": -8.727202198, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 2740, - "name": { - "original": "Rúa do Cacheno 75" - }, - "latitude": 42.207451401, - "longitude": -8.701194432, - "lines": [ - "14" - ] - }, - { - "stopId": 2750, - "name": { - "original": "Rúa do Cacheno 28" - }, - "latitude": 42.20671834, - "longitude": -8.699160127, - "lines": [ - "14" - ] - }, - { - "stopId": 2760, - "name": { - "original": "Rúa do Cacheno 66" - }, - "latitude": 42.208194443, - "longitude": -8.701518979, - "lines": [ - "14" - ] - }, - { - "stopId": 2770, - "name": { - "original": "Rúa do Cacheno 49" - }, - "latitude": 42.20648703, - "longitude": -8.698760561, - "lines": [ - "14" - ] - }, - { - "stopId": 2780, - "name": { - "original": "Avda. das Camelias 135" - }, - "latitude": 42.222387178, - "longitude": -8.731207698, - "lines": [ - "4A", - "4C", - "5A", - "5B", - "11", - "12A", - "12B", - "16", - "17", - "27", - "N1", - "LZH" - ] - }, - { - "stopId": 2790, - "name": { - "original": "Avda. das Camelias 37" - }, - "latitude": 42.230566426, - "longitude": -8.730086804, - "lines": [ - "4A", - "4C", - "11", - "12B", - "17", - "27", - "N1" - ] - }, - { - "stopId": 2800, - "name": { - "original": "Avda. das Camelias 46" - }, - "latitude": 42.230291959, - "longitude": -8.730279255, - "lines": [ - "4A", - "4C", - "7", - "12B", - "17", - "27", - "PSA 4" - ] - }, - { - "stopId": 2810, - "name": { - "original": "Avda. das Camelias 80" - }, - "latitude": 42.227601839, - "longitude": -8.730236339, - "lines": [ - "4A", - "4C", - "7", - "12B", - "17", - "27", - "PSA 4" - ] - }, - { - "stopId": 2820, - "name": { - "original": "Avda. das Camelias (Praza 8 de Marzo)" - }, - "latitude": 42.227403959, - "longitude": -8.729948584, - "lines": [ - "4A", - "4C", - "11", - "12B", - "17", - "27", - "N1" - ] - }, - { - "stopId": 2830, - "name": { - "original": "Rúa de Camilo Veiga 33" - }, - "latitude": 42.22243855, - "longitude": -8.751978552, - "lines": [ - "C3d", - "13", - "15B", - "15C", - "U1", - "H" - ] - }, - { - "stopId": 2840, - "name": { - "original": "Rúa da Goleta 3" - }, - "latitude": 42.241698248, - "longitude": -8.665209215, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 2850, - "name": { - "original": "Rúa da Goleta 2" - }, - "latitude": 42.241676405, - "longitude": -8.665026825, - "lines": [ - "9B", - "28" - ] - }, - { - "stopId": 2870, - "name": { - "original": "Rúa de Cantabria (Compañía Suministradora de Auga)" - }, - "latitude": 42.237397409, - "longitude": -8.694169154, - "lines": [ - "4A", - "24" - ] - }, - { - "stopId": 2880, - "name": { - "original": "Rúa de Cantabria 148" - }, - "latitude": 42.239331582, - "longitude": -8.692983618, - "lines": [ - "4A", - "24" - ] - }, - { - "stopId": 2910, - "name": { - "original": "Rúa de Cantabria 212" - }, - "latitude": 42.241655974, - "longitude": -8.692827561, - "lines": [ - "4A", - "24" - ] - }, - { - "stopId": 2920, - "name": { - "original": "Rúa de Cantabria 45" - }, - "latitude": 42.235852081, - "longitude": -8.695592417, - "lines": [ - "4A", - "24" - ] - }, - { - "stopId": 2930, - "name": { - "original": "Rúa de Cantabria 58" - }, - "latitude": 42.235377808, - "longitude": -8.695695331, - "lines": [ - "4A", - "24" - ] - }, - { - "stopId": 2950, - "name": { - "original": "Rúa dos Canteiros 4" - }, - "latitude": 42.204307169, - "longitude": -8.729719236, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 2960, - "name": { - "original": "Rúa dos Canteiros 101" - }, - "latitude": 42.20073699, - "longitude": -8.738895516, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 2970, - "name": { - "original": "Rúa dos Canteiros 116" - }, - "latitude": 42.201317829, - "longitude": -8.735636365, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 2980, - "name": { - "original": "Rúa dos Canteiros 164" - }, - "latitude": 42.200758846, - "longitude": -8.739043037, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 2990, - "name": { - "original": "Rúa dos Canteiros 9" - }, - "latitude": 42.203792573, - "longitude": -8.729630723, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 3000, - "name": { - "original": "Rúa dos Canteiros 49" - }, - "latitude": 42.201188677, - "longitude": -8.733208966, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 3010, - "name": { - "original": "Rúa dos Canteiros 73" - }, - "latitude": 42.20121252, - "longitude": -8.735711467, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 3020, - "name": { - "original": "Rúa dos Canteiros 76" - }, - "latitude": 42.201218481, - "longitude": -8.733509374, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 3030, - "name": { - "original": "Avda. de Castrelos 458" - }, - "latitude": 42.194702579, - "longitude": -8.721025195, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 3050, - "name": { - "original": "Estrada de Casás (cruce Camiño da Pedra Branca)" - }, - "latitude": 42.192360267, - "longitude": -8.756680959, - "lines": [ - "29" - ] - }, - { - "stopId": 3052, - "name": { - "original": "Avda. Arquitecto Antonio Palacios (cruce Rúa Ricardo Torres)" - }, - "latitude": 42.216966631, - "longitude": -8.729813845, - "lines": [ - "A" - ] - }, - { - "stopId": 3060, - "name": { - "original": "Rúa da Ceboleira 30" - }, - "latitude": 42.224698049, - "longitude": -8.701749123, - "lines": [ - "6" - ] - }, - { - "stopId": 3070, - "name": { - "original": "Rúa da Ceboleira 49" - }, - "latitude": 42.224816342, - "longitude": -8.701565998, - "lines": [ - "6" - ] - }, - { - "stopId": 3080, - "name": { - "original": "Avda. de Cesáreo Vázquez 136" - }, - "latitude": 42.1873653089623, - "longitude": -8.800886236766305, - "lines": [ - "11" - ] - }, - { - "stopId": 3090, - "name": { - "original": "Avda. de Cesáreo Vázquez 182" - }, - "latitude": 42.191019711713736, - "longitude": -8.799628565094565, - "lines": [ - "C3d", - "10", - "11" - ] - }, - { - "stopId": 3100, - "name": { - "original": "Avda. de Cesáreo Vázquez 99" - }, - "latitude": 42.184766843, - "longitude": -8.802180879, - "lines": [ - "11", - "12A" - ] - }, - { - "stopId": 3110, - "name": { - "original": "Avda. de Cesáreo Vázquez 74" - }, - "latitude": 42.184416675, - "longitude": -8.802179713, - "lines": [ - "11" - ] - }, - { - "stopId": 3120, - "name": { - "original": "Avda. de Cesáreo Vázquez 141" - }, - "latitude": 42.187488521491225, - "longitude": -8.801226626055183, - "lines": [ - "11", - "12A" - ] - }, - { - "stopId": 3130, - "name": { - "original": "Avda. de Cesáreo Vázquez 169" - }, - "latitude": 42.191024803868736, - "longitude": -8.799397387002196, - "lines": [ - "11" - ] - }, - { - "stopId": 3140, - "name": { - "original": "Estrada De Zamáns 255" - }, - "latitude": 42.15800346, - "longitude": -8.686134691, - "lines": [ - "7" - ] - }, - { - "stopId": 3150, - "name": { - "original": "Estrada de Zamáns (cruce Igrexa)" - }, - "latitude": 42.157661469, - "longitude": -8.685973759, - "lines": [ - "7" - ] - }, - { - "stopId": 3160, - "name": { - "original": "Camiño da Falcoa 10" - }, - "latitude": 42.206593246, - "longitude": -8.721651793, - "lines": [ - "18B", - "18H" - ] - }, - { - "stopId": 3170, - "name": { - "original": "Rúa das Coutadas 76" - }, - "latitude": 42.220968446, - "longitude": -8.720400826, - "lines": [ - "18A" - ] - }, - { - "stopId": 3180, - "name": { - "original": "Camiño de Quirós 106" - }, - "latitude": 42.21955863, - "longitude": -8.711410119, - "lines": [ - "18B", - "18H" - ] - }, - { - "stopId": 3190, - "name": { - "original": "Camiño de Quirós (cruce Rúa de Dona Cristina)" - }, - "latitude": 42.219681782, - "longitude": -8.711385979, - "lines": [ - "18B", - "18H" - ] - }, - { - "stopId": 3230, - "name": { - "original": "Rúa de Colón 27" - }, - "latitude": 42.236471452, - "longitude": -8.720164905, - "lines": [ - "A", - "5A", - "9B", - "11", - "15B", - "15C", - "16", - "17" - ] - }, - { - "stopId": 3240, - "name": { - "original": "Rúa da Coruña 5" - }, - "latitude": 42.22214729, - "longitude": -8.734167916, - "lines": [ - "A", - "5A", - "5B", - "10", - "11", - "13", - "N4", - "U1", - "H1", - "H" - ] - }, - { - "stopId": 3250, - "name": { - "original": "Rúa da Coruña 26" - }, - "latitude": 42.222378625, - "longitude": -8.734134247, - "lines": [ - "C1", - "A", - "10", - "N4", - "H1" - ] - }, - { - "stopId": 3260, - "name": { - "original": "Rúa da Coruña 37" - }, - "latitude": 42.226287696, - "longitude": -8.737475832, - "lines": [ - "15B" - ] - }, - { - "stopId": 3270, - "name": { - "original": "Rúa da Coruña (fronte 39)" - }, - "latitude": 42.226490285, - "longitude": -8.73744901, - "lines": [ - "10", - "15B" - ] - }, - { - "stopId": 3280, - "name": { - "original": "Rúa de Manuel Lago Lago 1" - }, - "latitude": 42.188898503, - "longitude": -8.776299224, - "lines": [ - "29" - ] - }, - { - "stopId": 3290, - "name": { - "original": "Rúa da Costa 13" - }, - "latitude": 42.213397685, - "longitude": -8.72248211, - "lines": [ - "A", - "18B", - "18H" - ] - }, - { - "stopId": 3300, - "name": { - "original": "Rúa da Costa 22" - }, - "latitude": 42.211751348, - "longitude": -8.721691531, - "lines": [ - "A", - "18B", - "18H" - ] - }, - { - "stopId": 3310, - "name": { - "original": "Rúa da Costa 74" - }, - "latitude": 42.209233023, - "longitude": -8.720666368, - "lines": [ - "A", - "18B", - "18H" - ] - }, - { - "stopId": 3320, - "name": { - "original": "Rúa da Costa 63" - }, - "latitude": 42.210154848, - "longitude": -8.720902403, - "lines": [ - "A", - "18B", - "18H" - ] - }, - { - "stopId": 3350, - "name": { - "original": "Rúa do Couto 1" - }, - "latitude": 42.230911796, - "longitude": -8.722711253, - "lines": [ - "12A", - "27" - ] - }, - { - "stopId": 3360, - "name": { - "original": "Rúa do Doutor Canoa 8" - }, - "latitude": 42.237803518, - "longitude": -8.704409031, - "lines": [ - "31" - ] - }, - { - "stopId": 3370, - "name": { - "original": "Estrada de Bembrive (cruce Rúa Eifonso)" - }, - "latitude": 42.205676226, - "longitude": -8.693112047, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 3380, - "name": { - "original": "Cruce Eifonso" - }, - "latitude": 42.205623108, - "longitude": -8.693239335, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 3390, - "name": { - "original": "Estrada de Bembrive 160" - }, - "latitude": 42.205296644, - "longitude": -8.692558914, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 3400, - "name": { - "original": "Estrada da Gándara 22" - }, - "latitude": 42.163584451, - "longitude": -8.716088728, - "lines": [ - "7" - ] - }, - { - "stopId": 3420, - "name": { - "original": "Avda. de Castrelos (Cemiterio de Pereiró)" - }, - "latitude": 42.208071495, - "longitude": -8.731366082, - "lines": [ - "7", - "12B", - "17", - "27", - "U1" - ] - }, - { - "stopId": 3430, - "name": { - "original": "Avda. da Ponte 86 (Cemiterio)" - }, - "latitude": 42.215621206, - "longitude": -8.67221512, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 3450, - "name": { - "original": "Estrada de Camposancos 155" - }, - "latitude": 42.194732286, - "longitude": -8.769245322, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3460, - "name": { - "original": "Estrada de Camposancos 19" - }, - "latitude": 42.203197031, - "longitude": -8.753437723, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3470, - "name": { - "original": "Estrada de Camposancos 214" - }, - "latitude": 42.193581709, - "longitude": -8.772496159, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3480, - "name": { - "original": "Estrada de Camposancos 141" - }, - "latitude": 42.196095467, - "longitude": -8.766230519, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3490, - "name": { - "original": "Estrada de Camposancos 171" - }, - "latitude": 42.193613504, - "longitude": -8.772222574, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3500, - "name": { - "original": "Estrada de Camposancos 190" - }, - "latitude": 42.194553241, - "longitude": -8.770325583, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3510, - "name": { - "original": "Estrada de Camposancos 28" - }, - "latitude": 42.202849227, - "longitude": -8.753870291, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3520, - "name": { - "original": "Estrada de Camposancos 75" - }, - "latitude": 42.200000035, - "longitude": -8.759107913, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3530, - "name": { - "original": "Estrada de Camposancos 88" - }, - "latitude": 42.199773285, - "longitude": -8.759958845, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3540, - "name": { - "original": "Estrada de Camposancos 138" - }, - "latitude": 42.19617384, - "longitude": -8.766295392, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 3550, - "name": { - "original": "Estrada de Bembrive (cruce Camiño Cova)" - }, - "latitude": 42.19747765, - "longitude": -8.688158543, - "lines": [ - "6" - ] - }, - { - "stopId": 3560, - "name": { - "original": "Estrada de Bembrive 104" - }, - "latitude": 42.209126518, - "longitude": -8.695599845, - "lines": [ - "6" - ] - }, - { - "stopId": 3570, - "name": { - "original": "Estrada de Bembrive 109" - }, - "latitude": 42.209576972, - "longitude": -8.695580071, - "lines": [ - "6" - ] - }, - { - "stopId": 3572, - "name": { - "original": "Estrada de Bembrive 110" - }, - "latitude": 42.208457815, - "longitude": -8.695017358, - "lines": [ - "14" - ] - }, - { - "stopId": 3574, - "name": { - "original": "Estrada de Bembrive 129" - }, - "latitude": 42.208533311, - "longitude": -8.694987854, - "lines": [ - "14" - ] - }, - { - "stopId": 3580, - "name": { - "original": "Estrada de Bembrive 180" - }, - "latitude": 42.204440318, - "longitude": -8.690871804, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 3590, - "name": { - "original": "Estrada de Bembrive 195" - }, - "latitude": 42.204458432, - "longitude": -8.690765895, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 3600, - "name": { - "original": "Estrada de Bembrive 22" - }, - "latitude": 42.21246424, - "longitude": -8.697218847, - "lines": [ - "6" - ] - }, - { - "stopId": 3610, - "name": { - "original": "Estrada de Bembrive 237" - }, - "latitude": 42.204446407, - "longitude": -8.68809021, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 3620, - "name": { - "original": "Estrada de Bembrive 278" - }, - "latitude": 42.202562995, - "longitude": -8.685437577, - "lines": [ - "6" - ] - }, - { - "stopId": 3630, - "name": { - "original": "Estrada de Bembrive 269" - }, - "latitude": 42.20274418, - "longitude": -8.684443742, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 3640, - "name": { - "original": "Estrada de Bembrive 315" - }, - "latitude": 42.197359418, - "longitude": -8.688113004, - "lines": [ - "6" - ] - }, - { - "stopId": 3650, - "name": { - "original": "Estrada de Bembrive 346" - }, - "latitude": 42.199275919, - "longitude": -8.689032944, - "lines": [ - "6" - ] - }, - { - "stopId": 3660, - "name": { - "original": "Estrada de Bembrive 39" - }, - "latitude": 42.212227656, - "longitude": -8.697028614, - "lines": [ - "6" - ] - }, - { - "stopId": 3670, - "name": { - "original": "Estrada de Bembrive 398" - }, - "latitude": 42.194968863, - "longitude": -8.689201981, - "lines": [ - "6" - ] - }, - { - "stopId": 3680, - "name": { - "original": "Estrada de Bembrive 64" - }, - "latitude": 42.211144971, - "longitude": -8.69652789, - "lines": [ - "6" - ] - }, - { - "stopId": 3690, - "name": { - "original": "Estrada de Bembrive 73" - }, - "latitude": 42.210947345, - "longitude": -8.69627482, - "lines": [ - "6" - ] - }, - { - "stopId": 3700, - "name": { - "original": "Estrada de Bembrive (cruce Camiño Riomao)" - }, - "latitude": 42.194055385, - "longitude": -8.692079677, - "lines": [ - "6" - ] - }, - { - "stopId": 3710, - "name": { - "original": "Estrada de Bembrive 363" - }, - "latitude": 42.193846109, - "longitude": -8.69200489, - "lines": [ - "6" - ] - }, - { - "stopId": 3720, - "name": { - "original": "Estrada de Bembrive 341" - }, - "latitude": 42.1948986, - "longitude": -8.689213754, - "lines": [ - "6" - ] - }, - { - "stopId": 3730, - "name": { - "original": "Estrada de Bembrive 301" - }, - "latitude": 42.199203404, - "longitude": -8.688880116, - "lines": [ - "6" - ] - }, - { - "stopId": 3740, - "name": { - "original": "Rúa de Canido (Igrexa)" - }, - "latitude": 42.197431882, - "longitude": -8.790144971, - "lines": [ - "C3d", - "4C", - "10" - ] - }, - { - "stopId": 3750, - "name": { - "original": "Rúa de Canido (Praia de Canido)" - }, - "latitude": 42.193128934, - "longitude": -8.797957944, - "lines": [ - "10", - "11" - ] - }, - { - "stopId": 3760, - "name": { - "original": "Rúa de Canido (fronte 119)" - }, - "latitude": 42.1957321, - "longitude": -8.795211362, - "lines": [ - "10", - "11" - ] - }, - { - "stopId": 3770, - "name": { - "original": "Rúa de Canido 135" - }, - "latitude": 42.1950348, - "longitude": -8.795701844, - "lines": [ - "C3d", - "10", - "11" - ] - }, - { - "stopId": 3780, - "name": { - "original": "Rúa de Canido 217" - }, - "latitude": 42.193041793, - "longitude": -8.797590453, - "lines": [ - "C3d", - "10", - "11" - ] - }, - { - "stopId": 3790, - "name": { - "original": "Rúa de Canido 15" - }, - "latitude": 42.201898697, - "longitude": -8.781706742, - "lines": [ - "C3d", - "4C", - "10" - ] - }, - { - "stopId": 3800, - "name": { - "original": "Rúa de Canido 26" - }, - "latitude": 42.199639519, - "longitude": -8.785727373, - "lines": [ - "10" - ] - }, - { - "stopId": 3810, - "name": { - "original": "Rúa de Canido 55" - }, - "latitude": 42.200106486, - "longitude": -8.785121194, - "lines": [ - "C3d", - "4C", - "10" - ] - }, - { - "stopId": 3820, - "name": { - "original": "Rúa do Falcoído 16" - }, - "latitude": 42.182659954, - "longitude": -8.699663442, - "lines": [ - "A" - ] - }, - { - "stopId": 3830, - "name": { - "original": "Rúa do Falcoído (cruce Camiño Goaldino)" - }, - "latitude": 42.180635405, - "longitude": -8.696958243, - "lines": [ - "A" - ] - }, - { - "stopId": 3840, - "name": { - "original": "Rúa do Falcoído (cruce Camiño das Presas)" - }, - "latitude": 42.181019011, - "longitude": -8.696918009, - "lines": [ - "A" - ] - }, - { - "stopId": 3850, - "name": { - "original": "Estrada Clara Campoamor (cruce Estrada Marcosende)" - }, - "latitude": 42.167933917, - "longitude": -8.692758811, - "lines": [ - "A", - "U1" - ] - }, - { - "stopId": 3860, - "name": { - "original": "Estrada Clara Campoamor (cruce Rúa do Falcoído)" - }, - "latitude": 42.168248021, - "longitude": -8.692608608, - "lines": [ - "A", - "U1" - ] - }, - { - "stopId": 3870, - "name": { - "original": "Rúa do Falcoído 13" - }, - "latitude": 42.182749988, - "longitude": -8.699953254, - "lines": [ - "A" - ] - }, - { - "stopId": 3880, - "name": { - "original": "Estrada da Coutada 44" - }, - "latitude": 42.194829735, - "longitude": -8.699040324, - "lines": [ - "6" - ] - }, - { - "stopId": 3890, - "name": { - "original": "Estrada da Coutada 39" - }, - "latitude": 42.193625246, - "longitude": -8.7014263, - "lines": [ - "6", - "27" - ] - }, - { - "stopId": 3900, - "name": { - "original": "Estrada da Coutada 19" - }, - "latitude": 42.19232927, - "longitude": -8.704749414, - "lines": [ - "6", - "27" - ] - }, - { - "stopId": 3910, - "name": { - "original": "Estrada da Coutada 68" - }, - "latitude": 42.195404022, - "longitude": -8.695794851, - "lines": [ - "6" - ] - }, - { - "stopId": 3920, - "name": { - "original": "Estrada da Coutada 65" - }, - "latitude": 42.195725689, - "longitude": -8.697154293, - "lines": [ - "6", - "27" - ] - }, - { - "stopId": 3930, - "name": { - "original": "Estrada da Coutada 12" - }, - "latitude": 42.19287831, - "longitude": -8.703506202, - "lines": [ - "6", - "27" - ] - }, - { - "stopId": 3940, - "name": { - "original": "Estrada de Casás 83" - }, - "latitude": 42.196165214, - "longitude": -8.759890011, - "lines": [ - "29" - ] - }, - { - "stopId": 3950, - "name": { - "original": "Estrada de Casás (cruce Camiño do Rial)" - }, - "latitude": 42.196014193, - "longitude": -8.759919516, - "lines": [ - "29" - ] - }, - { - "stopId": 3960, - "name": { - "original": "Baixada do Castelo" - }, - "latitude": 42.213984907, - "longitude": -8.682160511, - "lines": [ - "12A", - "12B", - "13", - "15B", - "15C", - "31" - ] - }, - { - "stopId": 3970, - "name": { - "original": "Estrada Vella de Madrid 190" - }, - "latitude": 42.215872123, - "longitude": -8.679765298, - "lines": [ - "12B", - "15B", - "15C", - "U2" - ] - }, - { - "stopId": 3980, - "name": { - "original": "Estrada Vella de Madrid (cruce Hospital)" - }, - "latitude": 42.21620386, - "longitude": -8.681570425, - "lines": [ - "12A", - "12B", - "13", - "15B", - "15C", - "31", - "U2" - ] - }, - { - "stopId": 4000, - "name": { - "original": "Estrada de Fragoselo 143" - }, - "latitude": 42.182434997, - "longitude": -8.764713761, - "lines": [ - "29" - ] - }, - { - "stopId": 4010, - "name": { - "original": "Estrada de Fragoselo 170" - }, - "latitude": 42.184148566, - "longitude": -8.767237312, - "lines": [ - "29" - ] - }, - { - "stopId": 4020, - "name": { - "original": "Estrada de Fragoselo 79" - }, - "latitude": 42.187056187, - "longitude": -8.769605703, - "lines": [ - "29" - ] - }, - { - "stopId": 4030, - "name": { - "original": "Estrada de Fragoselo 111" - }, - "latitude": 42.184118753, - "longitude": -8.767049558, - "lines": [ - "29" - ] - }, - { - "stopId": 4040, - "name": { - "original": "Estrada de Fragoselo 108" - }, - "latitude": 42.18661248, - "longitude": -8.769574881, - "lines": [ - "29" - ] - }, - { - "stopId": 4050, - "name": { - "original": "Estrada de Fragoselo 196" - }, - "latitude": 42.182111026, - "longitude": -8.76479691, - "lines": [ - "29" - ] - }, - { - "stopId": 4060, - "name": { - "original": "Estrada da Gándara 7" - }, - "latitude": 42.164326088, - "longitude": -8.716892619, - "lines": [ - "7" - ] - }, - { - "stopId": 4070, - "name": { - "original": "Estrada da Gándara 55" - }, - "latitude": 42.162254659, - "longitude": -8.713740793, - "lines": [ - "7" - ] - }, - { - "stopId": 4080, - "name": { - "original": "Estrada da Gándara 48" - }, - "latitude": 42.162252671, - "longitude": -8.71400365, - "lines": [ - "7" - ] - }, - { - "stopId": 4090, - "name": { - "original": "Estrada da Garrida 124" - }, - "latitude": 42.170369621, - "longitude": -8.708506123, - "lines": [ - "7" - ] - }, - { - "stopId": 4100, - "name": { - "original": "Estrada da Garrida 199" - }, - "latitude": 42.16978602, - "longitude": -8.708967287, - "lines": [ - "7" - ] - }, - { - "stopId": 4110, - "name": { - "original": "Estrada da Garrida 40" - }, - "latitude": 42.165331611, - "longitude": -8.714862589, - "lines": [ - "7" - ] - }, - { - "stopId": 4120, - "name": { - "original": "Estrada da Garrida 84" - }, - "latitude": 42.166399713, - "longitude": -8.711237684, - "lines": [ - "7" - ] - }, - { - "stopId": 4130, - "name": { - "original": "Estrada da Garrida 83" - }, - "latitude": 42.16561193, - "longitude": -8.714589004, - "lines": [ - "7" - ] - }, - { - "stopId": 4140, - "name": { - "original": "Estrada da Garrida (frente 80)" - }, - "latitude": 42.166208944, - "longitude": -8.711992518, - "lines": [ - "7" - ] - }, - { - "stopId": 4150, - "name": { - "original": "Estrada de Miraflores 69" - }, - "latitude": 42.217620909, - "longitude": -8.712429612, - "lines": [ - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 4160, - "name": { - "original": "Estrada de Miraflores 36" - }, - "latitude": 42.217849364, - "longitude": -8.710994711, - "lines": [ - "18A" - ] - }, - { - "stopId": 4170, - "name": { - "original": "Estrada de Miraflores 64" - }, - "latitude": 42.217345186, - "longitude": -8.713011334, - "lines": [ - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 4200, - "name": { - "original": "Estrada de Moledo 6" - }, - "latitude": 42.215236994, - "longitude": -8.707384971, - "lines": [ - "14", - "18A" - ] - }, - { - "stopId": 4210, - "name": { - "original": "Estrada de Moledo 42" - }, - "latitude": 42.212141078, - "longitude": -8.704563545, - "lines": [ - "14", - "18A" - ] - }, - { - "stopId": 4220, - "name": { - "original": "Estrada de Moledo 22" - }, - "latitude": 42.213737557, - "longitude": -8.706283115, - "lines": [ - "14", - "18A" - ] - }, - { - "stopId": 4230, - "name": { - "original": "Estrada de Moledo 1" - }, - "latitude": 42.215373761, - "longitude": -8.707378349, - "lines": [ - "14", - "18A" - ] - }, - { - "stopId": 4240, - "name": { - "original": "Estrada de Moledo 73" - }, - "latitude": 42.212378349, - "longitude": -8.704729584, - "lines": [ - "14", - "18A" - ] - }, - { - "stopId": 4250, - "name": { - "original": "Estrada de Moledo 25" - }, - "latitude": 42.213377597, - "longitude": -8.70601168, - "lines": [ - "14", - "18A" - ] - }, - { - "stopId": 4280, - "name": { - "original": "Rúa de Emilia Pardo Bazán 80" - }, - "latitude": 42.224507337, - "longitude": -8.713465538, - "lines": [ - "14", - "18B", - "18H" - ] - }, - { - "stopId": 4290, - "name": { - "original": "Rúa de Emilia Pardo Bazán 3" - }, - "latitude": 42.227785739, - "longitude": -8.719460889, - "lines": [ - "14", - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 4300, - "name": { - "original": "Rúa de Emilia Pardo Bazán 104" - }, - "latitude": 42.22278924, - "longitude": -8.711754289, - "lines": [ - "14", - "18B", - "18H" - ] - }, - { - "stopId": 4310, - "name": { - "original": "Rúa de Emilia Pardo Bazán 111" - }, - "latitude": 42.222713762, - "longitude": -8.711555806, - "lines": [ - "14", - "18B", - "18H" - ] - }, - { - "stopId": 4320, - "name": { - "original": "Rúa de Emilia Pardo Bazán 2" - }, - "latitude": 42.227716225, - "longitude": -8.719750568, - "lines": [ - "14", - "18B", - "18H" - ] - }, - { - "stopId": 4330, - "name": { - "original": "Rúa de Emilia Pardo Bazán (cruce Baixada á Salgueira)" - }, - "latitude": 42.226463146, - "longitude": -8.71614062, - "lines": [ - "14", - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 4340, - "name": { - "original": "Rúa de Emilia Pardo Bazán 54" - }, - "latitude": 42.226112503, - "longitude": -8.715718376, - "lines": [ - "14", - "18B", - "18H" - ] - }, - { - "stopId": 4350, - "name": { - "original": "Rúa de Emilia Pardo Bazán 43" - }, - "latitude": 42.224562952, - "longitude": -8.713390437, - "lines": [ - "14", - "18B", - "18H" - ] - }, - { - "stopId": 4440, - "name": { - "original": "Estrada de San Xoán 169" - }, - "latitude": 42.183275038, - "longitude": -8.742437444, - "lines": [ - "17" - ] - }, - { - "stopId": 4450, - "name": { - "original": "Estrada de San Xoán 61" - }, - "latitude": 42.185081179, - "longitude": -8.748029634, - "lines": [ - "17" - ] - }, - { - "stopId": 4460, - "name": { - "original": "Estrada de San Xoán 141" - }, - "latitude": 42.18366712, - "longitude": -8.744402777, - "lines": [ - "17" - ] - }, - { - "stopId": 4490, - "name": { - "original": "Rúa de Manuel Lago Lago (fronte Colexio)" - }, - "latitude": 42.187522648, - "longitude": -8.772977937, - "lines": [ - "29" - ] - }, - { - "stopId": 4500, - "name": { - "original": "Rúa de Manuel Lago Lago 20" - }, - "latitude": 42.188761213, - "longitude": -8.775973652, - "lines": [ - "29" - ] - }, - { - "stopId": 4510, - "name": { - "original": "Rúa de Manuel Lago Lago (Colexio)" - }, - "latitude": 42.187542924, - "longitude": -8.772887753, - "lines": [ - "29" - ] - }, - { - "stopId": 4520, - "name": { - "original": "Estrada das Plantas (Cidade Deportiva)" - }, - "latitude": 42.175884385, - "longitude": -8.670789023, - "lines": [ - "15C" - ] - }, - { - "stopId": 4530, - "name": { - "original": "Estrada das Plantas (fronte cruce Camiño do Pouso)" - }, - "latitude": 42.199681015, - "longitude": -8.668860289, - "lines": [ - "15C" - ] - }, - { - "stopId": 4540, - "name": { - "original": "Estrada das Plantas (fronte Viveiros)" - }, - "latitude": 42.181370416, - "longitude": -8.667861084, - "lines": [ - "15C" - ] - }, - { - "stopId": 4550, - "name": { - "original": "Estrada das Plantas (cruce Camiño do Pouso)" - }, - "latitude": 42.199945182, - "longitude": -8.669085873, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 4560, - "name": { - "original": "Estrada de Valadares 233" - }, - "latitude": 42.177017792, - "longitude": -8.721519832, - "lines": [ - "7" - ] - }, - { - "stopId": 4570, - "name": { - "original": "Estrada de Valadares 100" - }, - "latitude": 42.183987864, - "longitude": -8.724154939, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 4580, - "name": { - "original": "Estrada de Valadares 146" - }, - "latitude": 42.180249473, - "longitude": -8.721850007, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 4590, - "name": { - "original": "Estrada de Valadares 173" - }, - "latitude": 42.180670846, - "longitude": -8.721533506, - "lines": [ - "7" - ] - }, - { - "stopId": 4600, - "name": { - "original": "Estrada de Valadares 212" - }, - "latitude": 42.176419487, - "longitude": -8.72197849, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 4610, - "name": { - "original": "Estrada de Valadares 262" - }, - "latitude": 42.172481228, - "longitude": -8.723905842, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 4620, - "name": { - "original": "Estrada de Valadares 329" - }, - "latitude": 42.172330151, - "longitude": -8.723766367, - "lines": [ - "7" - ] - }, - { - "stopId": 4630, - "name": { - "original": "Estrada de Valadares 406" - }, - "latitude": 42.165721529, - "longitude": -8.720146278, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 4640, - "name": { - "original": "Estrada de Valadares (cruce Camiño do Canizo)" - }, - "latitude": 42.18659932, - "longitude": -8.719619913, - "lines": [ - "7" - ] - }, - { - "stopId": 4650, - "name": { - "original": "Estrada de Valadares 48" - }, - "latitude": 42.186641056, - "longitude": -8.719853265, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 4660, - "name": { - "original": "Estrada de Valadares 99" - }, - "latitude": 42.183997801, - "longitude": -8.723857214, - "lines": [ - "7" - ] - }, - { - "stopId": 4670, - "name": { - "original": "Estrada do Vao 27" - }, - "latitude": 42.193836069, - "longitude": -8.776441689, - "lines": [ - "11" - ] - }, - { - "stopId": 4680, - "name": { - "original": "Estrada do Vao 116" - }, - "latitude": 42.19429691, - "longitude": -8.786574405, - "lines": [ - "11" - ] - }, - { - "stopId": 4690, - "name": { - "original": "Estrada do Vao 153" - }, - "latitude": 42.196307191, - "longitude": -8.790777973, - "lines": [ - "11" - ] - }, - { - "stopId": 4700, - "name": { - "original": "Estrada do Vao 46" - }, - "latitude": 42.194014721, - "longitude": -8.777055245, - "lines": [ - "11" - ] - }, - { - "stopId": 4710, - "name": { - "original": "Estrada do Vao 65" - }, - "latitude": 42.194064592, - "longitude": -8.781224067, - "lines": [ - "11" - ] - }, - { - "stopId": 4720, - "name": { - "original": "Estrada do Vao 90" - }, - "latitude": 42.193937416, - "longitude": -8.781634173, - "lines": [ - "11" - ] - }, - { - "stopId": 4730, - "name": { - "original": "Estrada do Vao 91" - }, - "latitude": 42.19405266, - "longitude": -8.78551292, - "lines": [ - "11" - ] - }, - { - "stopId": 4740, - "name": { - "original": "Estrada do Vao (Praia do Vao)" - }, - "latitude": 42.196595321, - "longitude": -8.791019372, - "lines": [ - "11" - ] - }, - { - "stopId": 4750, - "name": { - "original": "Estrada Vella de Madrid 6" - }, - "latitude": 42.213983883, - "longitude": -8.697464269, - "lines": [ - "12A", - "12B", - "13", - "U2", - "H3" - ] - }, - { - "stopId": 4760, - "name": { - "original": "Estrada Vella de Madrid 34" - }, - "latitude": 42.216359908, - "longitude": -8.693040769, - "lines": [ - "12A", - "12B", - "13", - "U2", - "H3" - ] - }, - { - "stopId": 4770, - "name": { - "original": "Estrada Vella de Madrid 104" - }, - "latitude": 42.219822923, - "longitude": -8.684198247, - "lines": [ - "12A", - "12B", - "13", - "31", - "U2" - ] - }, - { - "stopId": 4780, - "name": { - "original": "Estrada Vella de Madrid 136" - }, - "latitude": 42.220845201, - "longitude": -8.680581909, - "lines": [ - "12A", - "12B", - "13", - "31", - "U2" - ] - }, - { - "stopId": 4790, - "name": { - "original": "Estrada Vella de Madrid 123" - }, - "latitude": 42.220436017, - "longitude": -8.683690589, - "lines": [ - "12A", - "12B", - "13", - "31" - ] - }, - { - "stopId": 4800, - "name": { - "original": "Estrada Vella de Madrid 160" - }, - "latitude": 42.218049288, - "longitude": -8.679899408, - "lines": [ - "12A", - "12B", - "13", - "31", - "U2" - ] - }, - { - "stopId": 4810, - "name": { - "original": "Estrada Vella de Madrid 177" - }, - "latitude": 42.21827574, - "longitude": -8.679588272, - "lines": [ - "12A", - "12B", - "13", - "31" - ] - }, - { - "stopId": 4820, - "name": { - "original": "Estrada Vella de Madrid 31" - }, - "latitude": 42.216687676, - "longitude": -8.693917852, - "lines": [ - "12A", - "12B", - "13", - "H3" - ] - }, - { - "stopId": 4830, - "name": { - "original": "Estrada Vella de Madrid 81" - }, - "latitude": 42.218719793, - "longitude": -8.690012555, - "lines": [ - "12A", - "12B", - "13", - "H3" - ] - }, - { - "stopId": 4840, - "name": { - "original": "Estrada Vella de Madrid 76" - }, - "latitude": 42.218745617, - "longitude": -8.689009409, - "lines": [ - "12A", - "12B", - "13", - "U2", - "H3" - ] - }, - { - "stopId": 4850, - "name": { - "original": "Estrada Vella de Madrid (frente Centro Comercial)" - }, - "latitude": 42.216448197, - "longitude": -8.68163748, - "lines": [ - "12A", - "13", - "31" - ] - }, - { - "stopId": 4860, - "name": { - "original": "Estrada da Venda (cruce Camiño da Coutadiña)" - }, - "latitude": 42.182744465, - "longitude": -8.70286123, - "lines": [ - "A", - "6" - ] - }, - { - "stopId": 4870, - "name": { - "original": "Estrada da Venda 5" - }, - "latitude": 42.192029809, - "longitude": -8.712623715, - "lines": [ - "A", - "27", - "H3" - ] - }, - { - "stopId": 4880, - "name": { - "original": "Estrada da Venda 240" - }, - "latitude": 42.188021902, - "longitude": -8.711457595, - "lines": [ - "A", - "H3" - ] - }, - { - "stopId": 4890, - "name": { - "original": "Estrada da Venda 238" - }, - "latitude": 42.186610014, - "longitude": -8.710023944, - "lines": [ - "A", - "6" - ] - }, - { - "stopId": 4900, - "name": { - "original": "Estrada da Venda 35" - }, - "latitude": 42.188304845, - "longitude": -8.711474749, - "lines": [ - "A", - "27", - "H3" - ] - }, - { - "stopId": 4910, - "name": { - "original": "Estrada da Venda 4" - }, - "latitude": 42.19205763, - "longitude": -8.712722956, - "lines": [ - "A", - "H3" - ] - }, - { - "stopId": 4920, - "name": { - "original": "Estrada da Venda 49" - }, - "latitude": 42.186610342, - "longitude": -8.709937804, - "lines": [ - "A", - "6" - ] - }, - { - "stopId": 4930, - "name": { - "original": "Travesía da Devesa (Asociación Veciños)" - }, - "latitude": 42.246018558, - "longitude": -8.669287042, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 4940, - "name": { - "original": "Camiño da Devesa (fronte 55)" - }, - "latitude": 42.245450719, - "longitude": -8.672406783, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 4960, - "name": { - "original": "Rúa do Doutor Corbal 135" - }, - "latitude": 42.256210875, - "longitude": -8.696882723, - "lines": [ - "17" - ] - }, - { - "stopId": 4970, - "name": { - "original": "Rúa do Doutor Corbal 126" - }, - "latitude": 42.255883312, - "longitude": -8.696812986, - "lines": [ - "17" - ] - }, - { - "stopId": 4980, - "name": { - "original": "Rúa do Doutor Corbal 149" - }, - "latitude": 42.257539061, - "longitude": -8.697019814, - "lines": [ - "17" - ] - }, - { - "stopId": 5000, - "name": { - "original": "Rúa do Doutor Corbal 6" - }, - "latitude": 42.250121395, - "longitude": -8.696122376, - "lines": [ - "17" - ] - }, - { - "stopId": 5010, - "name": { - "original": "Rúa do Doutor Corbal 95" - }, - "latitude": 42.254169539, - "longitude": -8.697752273, - "lines": [ - "17" - ] - }, - { - "stopId": 5020, - "name": { - "original": "Rúa do Doutor Corbal 94" - }, - "latitude": 42.254104511, - "longitude": -8.697655199, - "lines": [ - "17" - ] - }, - { - "stopId": 5030, - "name": { - "original": "Avda. de Redondela (fronte 28)" - }, - "latitude": 42.272502528, - "longitude": -8.664787252, - "lines": [ - "C3i" - ] - }, - { - "stopId": 5040, - "name": { - "original": "Rúa da Salgueira Entrada 5" - }, - "latitude": 42.222543586, - "longitude": -8.717809812, - "lines": [ - "18A" - ] - }, - { - "stopId": 5060, - "name": { - "original": "Estadio de Balaídos (Avda. do Fragoso)" - }, - "latitude": 42.212676247, - "longitude": -8.739585545, - "lines": [ - "16", - "23", - "N4" - ] - }, - { - "stopId": 5070, - "name": { - "original": "Rúa da Estrada 10-12" - }, - "latitude": 42.220535836, - "longitude": -8.74141599, - "lines": [ - "C3i", - "5B" - ] - }, - { - "stopId": 5090, - "name": { - "original": "Rúa da Estrada 1" - }, - "latitude": 42.220359068, - "longitude": -8.738861999, - "lines": [ - "C3i", - "5B" - ] - }, - { - "stopId": 5120, - "name": { - "original": "Camiño da Falcoa 41" - }, - "latitude": 42.204935234, - "longitude": -8.722453969, - "lines": [ - "18B", - "18H", - "27" - ] - }, - { - "stopId": 5140, - "name": { - "original": "Camiño da Falcoa 15" - }, - "latitude": 42.207336295, - "longitude": -8.72129506, - "lines": [ - "18B", - "18H" - ] - }, - { - "stopId": 5160, - "name": { - "original": "Camiño da Falcoa 26" - }, - "latitude": 42.204783634, - "longitude": -8.722664062, - "lines": [ - "18B", - "18H", - "27" - ] - }, - { - "stopId": 5170, - "name": { - "original": "Rúa das Figueiras (Praza da Feira)" - }, - "latitude": 42.227529644, - "longitude": -8.66169041, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5180, - "name": { - "original": "Rúa das Figueiras 96" - }, - "latitude": 42.224562288, - "longitude": -8.66579419, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5190, - "name": { - "original": "Rúa das Figueiras 124" - }, - "latitude": 42.226051942, - "longitude": -8.663629647, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5200, - "name": { - "original": "Rúa das Figueiras 138" - }, - "latitude": 42.227533616, - "longitude": -8.661561664, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5220, - "name": { - "original": "Rúa das Figueiras 190" - }, - "latitude": 42.228984217, - "longitude": -8.658438326, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5230, - "name": { - "original": "Rúa das Figueiras 254" - }, - "latitude": 42.230261894, - "longitude": -8.653683012, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5250, - "name": { - "original": "Rúa das Figueiras 29" - }, - "latitude": 42.223048763, - "longitude": -8.667374011, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5260, - "name": { - "original": "Rúa das Figueiras 22" - }, - "latitude": 42.222838218, - "longitude": -8.667795118, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5270, - "name": { - "original": "Rúa das Figueiras 65" - }, - "latitude": 42.224367639, - "longitude": -8.665989991, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5280, - "name": { - "original": "Rúa das Figueiras 113" - }, - "latitude": 42.225940716, - "longitude": -8.663830813, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 5290, - "name": { - "original": "Avda. da Florida 60" - }, - "latitude": 42.215060936, - "longitude": -8.741309568, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5300, - "name": { - "original": "Avda. da Florida 117" - }, - "latitude": 42.214827343, - "longitude": -8.741319027, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5310, - "name": { - "original": "Avda. da Florida 140" - }, - "latitude": 42.208024308, - "longitude": -8.750412985, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5320, - "name": { - "original": "Avda. da Florida 145" - }, - "latitude": 42.213244058, - "longitude": -8.743657913, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5330, - "name": { - "original": "Avda. da Florida 3" - }, - "latitude": 42.220228436, - "longitude": -8.733426296, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5340, - "name": { - "original": "Avda. da Florida 197" - }, - "latitude": 42.208621114, - "longitude": -8.749572184, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5350, - "name": { - "original": "Avda. da Florida 40" - }, - "latitude": 42.216779248, - "longitude": -8.738705143, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5360, - "name": { - "original": "Avda. da Florida 70" - }, - "latitude": 42.212804215, - "longitude": -8.744506761, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5370, - "name": { - "original": "Avda. da Florida 69" - }, - "latitude": 42.216928527, - "longitude": -8.738268035, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5380, - "name": { - "original": "Avda. da Florida 8" - }, - "latitude": 42.219743053, - "longitude": -8.734322187, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 5390, - "name": { - "original": "Estrada de Fragoselo (cruce Camiño Río da Barxa)" - }, - "latitude": 42.179556959, - "longitude": -8.761854527, - "lines": [ - "29" - ] - }, - { - "stopId": 5400, - "name": { - "original": "Avda. do Fragoso 95" - }, - "latitude": 42.213518168, - "longitude": -8.737719785, - "lines": [ - "7", - "12B", - "17", - "N4", - "H1" - ] - }, - { - "stopId": 5410, - "name": { - "original": "Avda. do Fragoso 12" - }, - "latitude": 42.219689698, - "longitude": -8.733384686, - "lines": [ - "A", - "16", - "23", - "N4", - "U1", - "H1", - "H", - "LZH", - "PSA 1" - ] - }, - { - "stopId": 5420, - "name": { - "original": "Avda. do Fragoso 3" - }, - "latitude": 42.220297406, - "longitude": -8.732924981, - "lines": [ - "7", - "12B", - "17", - "N4", - "H1" - ] - }, - { - "stopId": 5430, - "name": { - "original": "Avda. do Fragoso 36" - }, - "latitude": 42.217381871, - "longitude": -8.734669814, - "lines": [ - "A", - "16", - "23", - "N4", - "U1", - "H1", - "H", - "LZH", - "PSA 1" - ] - }, - { - "stopId": 5440, - "name": { - "original": "Avda. do Fragoso 47" - }, - "latitude": 42.217288508, - "longitude": -8.73454375, - "lines": [ - "7", - "12B", - "17", - "N4", - "H1" - ] - }, - { - "stopId": 5450, - "name": { - "original": "Avda. do Fragoso 54" - }, - "latitude": 42.215348678, - "longitude": -8.736273638, - "lines": [ - "A", - "16", - "23", - "N4", - "U1", - "H1", - "H", - "LZH", - "PSA 1" - ] - }, - { - "stopId": 5460, - "name": { - "original": "Avda. do Fragoso 71" - }, - "latitude": 42.215301002, - "longitude": -8.736123434, - "lines": [ - "7", - "12B", - "17", - "N4", - "H1" - ] - }, - { - "stopId": 5470, - "name": { - "original": "Avda. do Fragoso 86" - }, - "latitude": 42.21315264, - "longitude": -8.738470803, - "lines": [ - "A", - "16", - "23", - "N4", - "U1", - "H1", - "H", - "LZH", - "PSA 1" - ] - }, - { - "stopId": 5480, - "name": { - "original": "Estrada de San Xoán 25" - }, - "latitude": 42.186179757, - "longitude": -8.748888329, - "lines": [ - "17" - ] - }, - { - "stopId": 5490, - "name": { - "original": "Avda. de García Barbón (fronte 120)" - }, - "latitude": 42.241557555, - "longitude": -8.707094861, - "lines": [ - "C3i", - "5B", - "10", - "17", - "N1", - "H3" - ] - }, - { - "stopId": 5500, - "name": { - "original": "Avda. de García Barbón 126" - }, - "latitude": 42.24178025, - "longitude": -8.706720936, - "lines": [ - "C3d", - "5B", - "10", - "17", - "31", - "U2", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 5510, - "name": { - "original": "Avda. de García Barbón 127" - }, - "latitude": 42.238290358, - "longitude": -8.71014103, - "lines": [ - "C3i", - "5B", - "10", - "17", - "N1" - ] - }, - { - "stopId": 5520, - "name": { - "original": "Avda. de García Barbón 7" - }, - "latitude": 42.237485586, - "longitude": -8.719397801, - "lines": [ - "C3i", - "A", - "4A", - "4C", - "5B", - "6", - "7", - "9B", - "10", - "12B", - "14", - "16", - "17", - "18A", - "18B", - "18H", - "28", - "N1", - "N4", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 5530, - "name": { - "original": "Avda. de García Barbón 18" - }, - "latitude": 42.23720456, - "longitude": -8.718680736, - "lines": [ - "C3d", - "5B", - "10", - "17", - "H2", - "PSA 1" - ] - }, - { - "stopId": 5540, - "name": { - "original": "Avda. de García Barbón 28" - }, - "latitude": 42.236759685, - "longitude": -8.716384581, - "lines": [ - "C3d", - "A", - "5B", - "10", - "16", - "17", - "24", - "H2", - "PSA 1" - ] - }, - { - "stopId": 5560, - "name": { - "original": "Avda. de García Barbón 60" - }, - "latitude": 42.236896919, - "longitude": -8.712902905, - "lines": [ - "C3d", - "A", - "5B", - "10", - "16", - "17", - "24", - "H2", - "PSA 1" - ] - }, - { - "stopId": 5570, - "name": { - "original": "Avda. de García Barbón 87" - }, - "latitude": 42.237003397, - "longitude": -8.713586994, - "lines": [ - "C3i", - "5B", - "10", - "17", - "N1" - ] - }, - { - "stopId": 5580, - "name": { - "original": "Avda. de García Barbón 90" - }, - "latitude": 42.238267348, - "longitude": -8.709873166, - "lines": [ - "C3d", - "5B", - "10", - "17", - "H2", - "PSA 1" - ] - }, - { - "stopId": 5590, - "name": { - "original": "Avda. da Ponte (Grupo S. Gorxal)" - }, - "latitude": 42.213057463, - "longitude": -8.670479203, - "lines": [ - "12B", - "15B", - "15C" - ] - }, - { - "stopId": 5600, - "name": { - "original": "Avda. da Gran Vía 107" - }, - "latitude": 42.225140059, - "longitude": -8.72184818, - "lines": [ - "C3i", - "7", - "11", - "13", - "15A", - "16", - "23", - "29", - "H2" - ] - }, - { - "stopId": 5610, - "name": { - "original": "Avda. da Gran Vía 12" - }, - "latitude": 42.233503531, - "longitude": -8.717236739, - "lines": [ - "C1", - "4A", - "4C", - "5B", - "7", - "12B", - "14", - "16", - "17", - "18A", - "18B", - "18H", - "PSA 4" - ] - }, - { - "stopId": 5620, - "name": { - "original": "Avda. da Gran Vía 148" - }, - "latitude": 42.222321607, - "longitude": -8.726440421, - "lines": [ - "C3d", - "13", - "15A", - "23", - "29", - "U1", - "H2", - "PSA 1" - ] - }, - { - "stopId": 5630, - "name": { - "original": "Avda. da Gran Vía 147" - }, - "latitude": 42.222790356, - "longitude": -8.724940076, - "lines": [ - "C3i", - "7", - "11", - "13", - "15A", - "16", - "23", - "29", - "U2", - "H2" - ] - }, - { - "stopId": 5640, - "name": { - "original": "Avda. da Gran Vía 176" - }, - "latitude": 42.220868033, - "longitude": -8.730264447, - "lines": [ - "C3d", - "13", - "15A", - "23", - "29", - "U2", - "H2", - "PSA 1" - ] - }, - { - "stopId": 5650, - "name": { - "original": "Avda. da Gran Vía 185" - }, - "latitude": 42.220971136, - "longitude": -8.729196245, - "lines": [ - "C3i", - "7", - "11", - "13", - "15A", - "16", - "23", - "29", - "H2" - ] - }, - { - "stopId": 5660, - "name": { - "original": "Avda. da Gran Vía 19" - }, - "latitude": 42.232957918, - "longitude": -8.717215735, - "lines": [ - "4A", - "4C", - "5B", - "7", - "11", - "12B", - "14", - "16", - "17", - "18A", - "18B", - "18H", - "N1" - ] - }, - { - "stopId": 5670, - "name": { - "original": "Avda. da Gran Vía 46" - }, - "latitude": 42.230988893, - "longitude": -8.71867283, - "lines": [ - "C1", - "12A", - "12B", - "14", - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 5680, - "name": { - "original": "Avda. da Gran Vía 66" - }, - "latitude": 42.228173802, - "longitude": -8.720267623, - "lines": [ - "C3d", - "13", - "15A", - "23", - "29", - "H2", - "PSA 1" - ] - }, - { - "stopId": 5690, - "name": { - "original": "Avda. da Gran Vía 85" - }, - "latitude": 42.226868266, - "longitude": -8.720637433, - "lines": [ - "C3i", - "7", - "11", - "13", - "15A", - "16", - "23", - "29", - "H2" - ] - }, - { - "stopId": 5700, - "name": { - "original": "Avda. da Gran Vía 104" - }, - "latitude": 42.225325884, - "longitude": -8.722106624, - "lines": [ - "C3d", - "13", - "15A", - "23", - "29", - "H2", - "PSA 1" - ] - }, - { - "stopId": 5710, - "name": { - "original": "Avda. do Alcalde Gregorio Espino 22" - }, - "latitude": 42.23003666347398, - "longitude": -8.707266671978003, - "lines": [ - "31" - ] - }, - { - "stopId": 5720, - "name": { - "original": "Avda. do Alcalde Gregorio Espino 33" - }, - "latitude": 42.23004933454558, - "longitude": -8.706947409683313, - "lines": [ - "4C", - "23", - "31", - "H2", - "PSA 4" - ] - }, - { - "stopId": 5730, - "name": { - "original": "Avda. do Alcalde Gregorio Espino 44" - }, - "latitude": 42.227850036119314, - "longitude": -8.708105429626789, - "lines": [ - "31", - "H2" - ] - }, - { - "stopId": 5740, - "name": { - "original": "Avda. do Alcalde Gregorio Espino 57" - }, - "latitude": 42.22783722597372, - "longitude": -8.707849091551859, - "lines": [ - "4C", - "23", - "31", - "N4", - "H2", - "PSA 4" - ] - }, - { - "stopId": 5750, - "name": { - "original": "Avda. do Alcalde Gregorio Espino 79" - }, - "latitude": 42.225785485, - "longitude": -8.708786105, - "lines": [ - "4C", - "23", - "31", - "N4", - "H2", - "PSA 4" - ] - }, - { - "stopId": 5760, - "name": { - "original": "Estrada de Valadares 377" - }, - "latitude": 42.16929549, - "longitude": -8.723249687, - "lines": [ - "7" - ] - }, - { - "stopId": 5770, - "name": { - "original": "Estrada de Valadares 310" - }, - "latitude": 42.16911061, - "longitude": -8.723904146, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 5790, - "name": { - "original": "Hospital do Meixoeiro" - }, - "latitude": 42.214534062, - "longitude": -8.684756053, - "lines": [ - "12A", - "12B", - "13", - "15B", - "15C", - "31" - ] - }, - { - "stopId": 5800, - "name": { - "original": "Rúa de Jenaro de la Fuente 29" - }, - "latitude": 42.232202275, - "longitude": -8.703792246, - "lines": [ - "A", - "4A", - "6", - "9B", - "11", - "15A", - "15B", - "15C", - "24", - "25", - "27", - "28" - ] - }, - { - "stopId": 5810, - "name": { - "original": "Rúa de Jenaro de la Fuente 10" - }, - "latitude": 42.232258514, - "longitude": -8.705770621, - "lines": [ - "A", - "4A", - "4C", - "6", - "9B", - "11", - "15A", - "15B", - "15C", - "23", - "24", - "25", - "27", - "28", - "N4", - "PSA 4" - ] - }, - { - "stopId": 5820, - "name": { - "original": "Rúa de Jenaro de la Fuente 22" - }, - "latitude": 42.232042043, - "longitude": -8.703616807, - "lines": [ - "A", - "4A", - "4C", - "6", - "9B", - "11", - "15A", - "15B", - "15C", - "23", - "24", - "25", - "27", - "28", - "N4", - "PSA 4" - ] - }, - { - "stopId": 5830, - "name": { - "original": "Rúa de Jenaro de la Fuente 11" - }, - "latitude": 42.23238699, - "longitude": -8.705610784, - "lines": [ - "A", - "4A", - "6", - "9B", - "11", - "15A", - "15B", - "15C", - "24", - "25", - "27", - "28" - ] - }, - { - "stopId": 5840, - "name": { - "original": "Rúa da Lagoa (cruce Rúa do Balde)" - }, - "latitude": 42.201360896, - "longitude": -8.702877394, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 5850, - "name": { - "original": "Rúa da Lagoa (fronte 21)" - }, - "latitude": 42.201154253, - "longitude": -8.702343635, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 5860, - "name": { - "original": "Baixada á Laxe (Centro Saúde)" - }, - "latitude": 42.21669522, - "longitude": -8.715884298, - "lines": [ - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 5870, - "name": { - "original": "Rúa de López Mora 10" - }, - "latitude": 42.226432697, - "longitude": -8.731262013, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 5880, - "name": { - "original": "Rúa de López Mora 19" - }, - "latitude": 42.226800566, - "longitude": -8.731799623, - "lines": [ - "5A", - "5B", - "12A" - ] - }, - { - "stopId": 5890, - "name": { - "original": "Rúa de López Mora 84" - }, - "latitude": 42.222420533, - "longitude": -8.731996938, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 5900, - "name": { - "original": "Rúa de Macal 8" - }, - "latitude": 42.202071034, - "longitude": -8.723541884, - "lines": [ - "18B", - "18H", - "27" - ] - }, - { - "stopId": 5910, - "name": { - "original": "Rúa de Macal 90" - }, - "latitude": 42.196213336, - "longitude": -8.721136467, - "lines": [ - "18B", - "18H", - "27" - ] - }, - { - "stopId": 5920, - "name": { - "original": "Rúa de Macal (cruce Rúa de Ramiro Pascual)" - }, - "latitude": 42.196173594, - "longitude": -8.721023814, - "lines": [ - "18B", - "18H", - "27" - ] - }, - { - "stopId": 5930, - "name": { - "original": "Rúa de Macal (frente 8)" - }, - "latitude": 42.202050775, - "longitude": -8.723454133, - "lines": [ - "18B", - "18H", - "27" - ] - }, - { - "stopId": 5940, - "name": { - "original": "Rúa de Macal 39" - }, - "latitude": 42.198347336, - "longitude": -8.721488003, - "lines": [ - "18B", - "18H", - "27" - ] - }, - { - "stopId": 5950, - "name": { - "original": "Rúa dos Mestres Goldar 62" - }, - "latitude": 42.207127325, - "longitude": -8.726636888, - "lines": [ - "27" - ] - }, - { - "stopId": 5960, - "name": { - "original": "Rúa dos Mestres Goldar 77" - }, - "latitude": 42.206757786, - "longitude": -8.730056705, - "lines": [ - "27" - ] - }, - { - "stopId": 5970, - "name": { - "original": "Rúa dos Mestres Goldar 96" - }, - "latitude": 42.206880283, - "longitude": -8.729978952, - "lines": [ - "27" - ] - }, - { - "stopId": 5980, - "name": { - "original": "Rúa dos Mestres Goldar 37" - }, - "latitude": 42.207198849, - "longitude": -8.726658346, - "lines": [ - "27" - ] - }, - { - "stopId": 6000, - "name": { - "original": "Rúa de Manuel Álvarez 185" - }, - "latitude": 42.220887532, - "longitude": -8.685059571, - "lines": [ - "31", - "H3" - ] - }, - { - "stopId": 6010, - "name": { - "original": "Rúa de Manuel Álvarez (cruce Camiño Sulevada)" - }, - "latitude": 42.223077231, - "longitude": -8.675499751, - "lines": [ - "25", - "31", - "H3" - ] - }, - { - "stopId": 6020, - "name": { - "original": "Rúa de Manuel Álvarez 58" - }, - "latitude": 42.223195307, - "longitude": -8.681872932, - "lines": [ - "25", - "31", - "H3" - ] - }, - { - "stopId": 6030, - "name": { - "original": "Rúa de Manuel Álvarez 102" - }, - "latitude": 42.220829925, - "longitude": -8.685158812, - "lines": [ - "31", - "H3" - ] - }, - { - "stopId": 6040, - "name": { - "original": "Rúa de Manuel Álvarez (fronte cruce Camiño Sulevada)" - }, - "latitude": 42.22320325, - "longitude": -8.675213007, - "lines": [ - "25", - "31", - "H3" - ] - }, - { - "stopId": 6050, - "name": { - "original": "Rúa de Manuel Cominges 22" - }, - "latitude": 42.19890849, - "longitude": -8.73623433, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 6060, - "name": { - "original": "Rúa de Manuel Cominges 135" - }, - "latitude": 42.196716802, - "longitude": -8.729966982, - "lines": [ - "12B" - ] - }, - { - "stopId": 6070, - "name": { - "original": "Rúa de Manuel Cominges 15" - }, - "latitude": 42.199197066, - "longitude": -8.736588816, - "lines": [ - "12B" - ] - }, - { - "stopId": 6080, - "name": { - "original": "Rúa de Manuel Cominges 64" - }, - "latitude": 42.197736144, - "longitude": -8.732267294, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 6090, - "name": { - "original": "Rúa de Manuel Cominges 77" - }, - "latitude": 42.197626151, - "longitude": -8.732546841, - "lines": [ - "12B" - ] - }, - { - "stopId": 6100, - "name": { - "original": "Rúa de Manuel Cominges 80" - }, - "latitude": 42.197066521, - "longitude": -8.730468609, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 6110, - "name": { - "original": "Camiño da Devesa 6" - }, - "latitude": 42.243941636, - "longitude": -8.669169025, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 6130, - "name": { - "original": "Estrada do Marco 105" - }, - "latitude": 42.207132591, - "longitude": -8.706967295, - "lines": [ - "18B", - "H3" - ] - }, - { - "stopId": 6140, - "name": { - "original": "Estrada do Marco (Colexio)" - }, - "latitude": 42.206925967, - "longitude": -8.707050443, - "lines": [ - "18B", - "H3" - ] - }, - { - "stopId": 6150, - "name": { - "original": "Estrada De Zamáns 233" - }, - "latitude": 42.160616846, - "longitude": -8.691088401, - "lines": [ - "7" - ] - }, - { - "stopId": 6160, - "name": { - "original": "Estrada De Zamáns 150" - }, - "latitude": 42.160635942, - "longitude": -8.69145083, - "lines": [ - "7" - ] - }, - { - "stopId": 6180, - "name": { - "original": "Rúa de Marín (fronte 30)" - }, - "latitude": 42.21850454, - "longitude": -8.753892634, - "lines": [ - "C3i", - "5B" - ] - }, - { - "stopId": 6187, - "name": { - "original": "Rúa de Martín Echegaray (Parque)" - }, - "latitude": 42.215244712, - "longitude": -8.74244225, - "lines": [ - "23", - "N4" - ] - }, - { - "stopId": 6200, - "name": { - "original": "Avda. de E. Martínez Garrido 11" - }, - "latitude": 42.229298043, - "longitude": -8.699760249, - "lines": [ - "6", - "25", - "31" - ] - }, - { - "stopId": 6210, - "name": { - "original": "Avda. de E. Martínez Garrido 16" - }, - "latitude": 42.229259529, - "longitude": -8.699964485, - "lines": [ - "4C", - "6", - "23", - "25", - "31", - "N4", - "PSA 4" - ] - }, - { - "stopId": 6220, - "name": { - "original": "Avda. de E. Martínez Garrido 45" - }, - "latitude": 42.226116269, - "longitude": -8.703346362, - "lines": [ - "31" - ] - }, - { - "stopId": 6230, - "name": { - "original": "Avda. de E. Martínez Garrido 69" - }, - "latitude": 42.224839145, - "longitude": -8.706082215, - "lines": [ - "31" - ] - }, - { - "stopId": 6240, - "name": { - "original": "Avda. de E. Martínez Garrido 77" - }, - "latitude": 42.224493844, - "longitude": -8.707734948, - "lines": [ - "31" - ] - }, - { - "stopId": 6250, - "name": { - "original": "Avda. de E. Martínez Garrido 80" - }, - "latitude": 42.22667463, - "longitude": -8.702581423, - "lines": [ - "4C", - "23", - "31", - "N4", - "PSA 4" - ] - }, - { - "stopId": 6260, - "name": { - "original": "Estrada da Balsa 3" - }, - "latitude": 42.199568643, - "longitude": -8.741030554, - "lines": [ - "12B", - "17" - ] - }, - { - "stopId": 6280, - "name": { - "original": "Rúa Molais (Parque da Grileira)" - }, - "latitude": 42.223843943, - "longitude": -8.65334865, - "lines": [ - "11" - ] - }, - { - "stopId": 6290, - "name": { - "original": "Rúa de San Paio (cruce Rúa Muíños)" - }, - "latitude": 42.202031781, - "longitude": -8.769502424, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 6300, - "name": { - "original": "Rúa de Cánovas del Castillo (Centro Comercial)" - }, - "latitude": 42.240129541, - "longitude": -8.727159759, - "lines": [ - "C3i", - "A", - "5A", - "5B", - "6", - "9B", - "10", - "11", - "15B", - "15C", - "28", - "N1", - "N4", - "H1" - ] - }, - { - "stopId": 6360, - "name": { - "original": "Rúa de Pablo Iglesias (Colexio)" - }, - "latitude": 42.211426266, - "longitude": -8.743166543, - "lines": [ - "16" - ] - }, - { - "stopId": 6370, - "name": { - "original": "Rúa de Pablo Iglesias (Río)" - }, - "latitude": 42.210130966, - "longitude": -8.744872428, - "lines": [ - "16" - ] - }, - { - "stopId": 6380, - "name": { - "original": "Rúa de Pablo Iglesias 2" - }, - "latitude": 42.211811672, - "longitude": -8.742420889, - "lines": [ - "16" - ] - }, - { - "stopId": 6390, - "name": { - "original": "Rúa de Pablo Iglesias 20" - }, - "latitude": 42.210204472, - "longitude": -8.74559126, - "lines": [ - "16" - ] - }, - { - "stopId": 6440, - "name": { - "original": "Camiño do Pino Manso 6" - }, - "latitude": 42.222951208, - "longitude": -8.635051581, - "lines": [ - "A" - ] - }, - { - "stopId": 6450, - "name": { - "original": "Praza de Suárez Llanos" - }, - "latitude": 42.224306065, - "longitude": -8.753090783, - "lines": [ - "C3d", - "C3i", - "13", - "U1", - "H" - ] - }, - { - "stopId": 6460, - "name": { - "original": "Rúa dos Pescadores 10" - }, - "latitude": 42.224853579, - "longitude": -8.752608542, - "lines": [ - "C3d", - "C3i" - ] - }, - { - "stopId": 6470, - "name": { - "original": "Rúa de Pi i Margall 108" - }, - "latitude": 42.228458938, - "longitude": -8.732202674, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 6480, - "name": { - "original": "Rúa de Pi i Margall 137" - }, - "latitude": 42.229149188, - "longitude": -8.731886908, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 6490, - "name": { - "original": "Rúa de Pi i Margall 32" - }, - "latitude": 42.233972514, - "longitude": -8.729963004, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 6500, - "name": { - "original": "Rúa de Pi i Margall 51" - }, - "latitude": 42.233690068, - "longitude": -8.730100174, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 6510, - "name": { - "original": "Rúa de Pi i Margall 86" - }, - "latitude": 42.230584487, - "longitude": -8.731459155, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 6520, - "name": { - "original": "Rúa de Pi i Margall 95" - }, - "latitude": 42.232285981, - "longitude": -8.730816324, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 6530, - "name": { - "original": "Rúa do Pintor Laxeiro 4" - }, - "latitude": 42.222480852, - "longitude": -8.729812967, - "lines": [ - "C1" - ] - }, - { - "stopId": 6550, - "name": { - "original": "Rúa de Pizarro 10" - }, - "latitude": 42.229886416, - "longitude": -8.717463365, - "lines": [ - "C3i", - "6", - "11", - "15A", - "23", - "25", - "28", - "29" - ] - }, - { - "stopId": 6560, - "name": { - "original": "Rúa de Pizarro 34" - }, - "latitude": 42.23113801, - "longitude": -8.711696824, - "lines": [ - "C3i", - "6", - "11", - "15A", - "23", - "25", - "27", - "28" - ] - }, - { - "stopId": 6570, - "name": { - "original": "Rúa de Pizarro 65" - }, - "latitude": 42.231357755, - "longitude": -8.71296778, - "lines": [ - "C3d", - "6", - "15A", - "23", - "25", - "27", - "28", - "U2", - "H2", - "PSA 1" - ] - }, - { - "stopId": 6580, - "name": { - "original": "Rúa de Pizarro 7" - }, - "latitude": 42.229860487, - "longitude": -8.717979137, - "lines": [ - "C3d", - "6", - "15A", - "23", - "25", - "27", - "28", - "U2", - "H2", - "PSA 1" - ] - }, - { - "stopId": 6620, - "name": { - "original": "Rúa de Policarpo Sanz 40" - }, - "latitude": 42.23757846151978, - "longitude": -8.721031378896738, - "lines": [ - "C1", - "A", - "5A", - "9B", - "15B", - "15C", - "24", - "28", - "N4" - ] - }, - { - "stopId": 6640, - "name": { - "original": "Rúa do Porriño (fronte Instituto)" - }, - "latitude": 42.215506175, - "longitude": -8.753186569, - "lines": [ - "C3d", - "C3i", - "4A", - "4C", - "15A", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 6650, - "name": { - "original": "Rúa do Porriño (Instituto)" - }, - "latitude": 42.215554055, - "longitude": -8.753042462, - "lines": [ - "C3d", - "C3i", - "5B", - "15B", - "U1" - ] - }, - { - "stopId": 6670, - "name": { - "original": "Estrada da Venda 109" - }, - "latitude": 42.183004832, - "longitude": -8.702601056, - "lines": [ - "A", - "6" - ] - }, - { - "stopId": 6680, - "name": { - "original": "Rúa do Portoloureiro 26" - }, - "latitude": 42.207311837, - "longitude": -8.718650635, - "lines": [ - "A" - ] - }, - { - "stopId": 6690, - "name": { - "original": "Rúa do Portoloureiro 52" - }, - "latitude": 42.20495956, - "longitude": -8.715695557, - "lines": [ - "A" - ] - }, - { - "stopId": 6700, - "name": { - "original": "Rúa do Portoloureiro 43" - }, - "latitude": 42.204947406, - "longitude": -8.715589643, - "lines": [ - "A" - ] - }, - { - "stopId": 6720, - "name": { - "original": "Rúa do Portoloureiro (fronte 28)" - }, - "latitude": 42.207385347, - "longitude": -8.718127604, - "lines": [ - "A" - ] - }, - { - "stopId": 6730, - "name": { - "original": "Rúa do Couto 29" - }, - "latitude": 42.199386411, - "longitude": -8.695417016, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 6740, - "name": { - "original": "Rúa da Vista do Mar 95" - }, - "latitude": 42.242957479, - "longitude": -8.691167762, - "lines": [ - "4A", - "24" - ] - }, - { - "stopId": 6750, - "name": { - "original": "Avda. de Samil (Praia da Fonte)" - }, - "latitude": 42.221783554, - "longitude": -8.773517669, - "lines": [ - "10", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 6760, - "name": { - "original": "Rúa de Canido (Praia da Calzoa)" - }, - "latitude": 42.201847037, - "longitude": -8.782205633, - "lines": [ - "10" - ] - }, - { - "stopId": 6780, - "name": { - "original": "Avda. de Samil (Dunas)" - }, - "latitude": 42.210256843, - "longitude": -8.774740625, - "lines": [ - "10" - ] - }, - { - "stopId": 6790, - "name": { - "original": "Avda. de Samil (fronte Hotel)" - }, - "latitude": 42.214772655, - "longitude": -8.774772363, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 6810, - "name": { - "original": "Avda. de Samil (Parking)" - }, - "latitude": 42.207405928, - "longitude": -8.776153122, - "lines": [ - "10" - ] - }, - { - "stopId": 6820, - "name": { - "original": "Avda. de Samil (Polideportivo)" - }, - "latitude": 42.20362713, - "longitude": -8.777027535, - "lines": [ - "10" - ] - }, - { - "stopId": 6830, - "name": { - "original": "Praia do Vao" - }, - "latitude": 42.197495083, - "longitude": -8.790235556, - "lines": [ - "10" - ] - }, - { - "stopId": 6860, - "name": { - "original": "Praza de Compostela" - }, - "latitude": 42.239118346, - "longitude": -8.722531274, - "lines": [ - "C3i", - "A", - "5A", - "5B", - "6", - "9B", - "10", - "11", - "15B", - "15C", - "24", - "28", - "N1", - "N4", - "H1" - ] - }, - { - "stopId": 6880, - "name": { - "original": "Praza do Cristo da Vitoria" - }, - "latitude": 42.215576278, - "longitude": -8.748885599, - "lines": [ - "4A", - "4C", - "11", - "15A", - "N4" - ] - }, - { - "stopId": 6890, - "name": { - "original": "Rúa da Cruz 36" - }, - "latitude": 42.198959642, - "longitude": -8.68628496, - "lines": [ - "14" - ] - }, - { - "stopId": 6900, - "name": { - "original": "Rúa da Cruz 49" - }, - "latitude": 42.199031443, - "longitude": -8.686165797, - "lines": [ - "14" - ] - }, - { - "stopId": 6930, - "name": { - "original": "Praza de América 1" - }, - "latitude": 42.220997313, - "longitude": -8.732835177, - "lines": [ - "C1", - "N4" - ] - }, - { - "stopId": 6940, - "name": { - "original": "Praza de América 3" - }, - "latitude": 42.220663902, - "longitude": -8.733419892, - "lines": [ - "C3d", - "4A", - "4C", - "5A", - "5B", - "10", - "11", - "12A", - "13", - "15A", - "29", - "N4", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 6950, - "name": { - "original": "Praza de España (cruce Rúa de Pizarro)" - }, - "latitude": 42.229280401, - "longitude": -8.719123549, - "lines": [ - "7", - "12A", - "12B", - "14", - "16", - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 6955, - "name": { - "original": "Praza de España (cruce Rúa de Fernando Conde)" - }, - "latitude": 42.229438377, - "longitude": -8.719781108, - "lines": [ - "6", - "13", - "18B", - "18H", - "25", - "29" - ] - }, - { - "stopId": 6960, - "name": { - "original": "Avda. das Camelias s/n ( Praza do Rei)" - }, - "latitude": 42.235056275, - "longitude": -8.726757514, - "lines": [ - "4A", - "4C", - "7", - "12B", - "16", - "17", - "27", - "PSA 4" - ] - }, - { - "stopId": 6970, - "name": { - "original": "Rúa da Coruña 52" - }, - "latitude": 42.223781999, - "longitude": -8.735258991, - "lines": [ - "C1", - "A", - "10", - "N4", - "H1" - ] - }, - { - "stopId": 6980, - "name": { - "original": "Praza Eugenio Fadrique 6" - }, - "latitude": 42.224471236, - "longitude": -8.73619635, - "lines": [ - "C3i", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 6990, - "name": { - "original": "Praza Eugenio Fadrique 9" - }, - "latitude": 42.224099613, - "longitude": -8.735838344, - "lines": [ - "C3d", - "A", - "9B", - "15B", - "15C" - ] - }, - { - "stopId": 7000, - "name": { - "original": "Praza de Fernando O Católico" - }, - "latitude": 42.232427317, - "longitude": -8.711371073, - "lines": [ - "A", - "4A", - "4C", - "5A", - "9B", - "11", - "15B", - "15C", - "24", - "28", - "N1", - "N4" - ] - }, - { - "stopId": 7030, - "name": { - "original": "Rúa de Manuel Castro 23" - }, - "latitude": 42.212808952, - "longitude": -8.740022994, - "lines": [ - "16", - "23", - "N4" - ] - }, - { - "stopId": 7040, - "name": { - "original": "Estrada de Miraflores 1" - }, - "latitude": 42.218435348, - "longitude": -8.709924429, - "lines": [ - "14", - "18A" - ] - }, - { - "stopId": 7050, - "name": { - "original": "Praza de Miraflores 4" - }, - "latitude": 42.218502886, - "longitude": -8.710133641, - "lines": [ - "14" - ] - }, - { - "stopId": 7060, - "name": { - "original": "Estrada de Moledo 70" - }, - "latitude": 42.210499286, - "longitude": -8.703983192, - "lines": [ - "14", - "18A", - "H3" - ] - }, - { - "stopId": 7070, - "name": { - "original": "Estrada de Moledo 109" - }, - "latitude": 42.210620188, - "longitude": -8.704177049, - "lines": [ - "14", - "18A", - "H3" - ] - }, - { - "stopId": 7080, - "name": { - "original": "Rúa da Rabadeira 95" - }, - "latitude": 42.238797018, - "longitude": -8.650399429, - "lines": [ - "9B", - "28" - ] - }, - { - "stopId": 7090, - "name": { - "original": "Rúa de Ramiro Pascual 108" - }, - "latitude": 42.191918475, - "longitude": -8.706869692, - "lines": [ - "27" - ] - }, - { - "stopId": 7100, - "name": { - "original": "Rúa de Ramiro Pascual 16" - }, - "latitude": 42.1952442, - "longitude": -8.71956212, - "lines": [ - "12B", - "18B", - "18H", - "27" - ] - }, - { - "stopId": 7110, - "name": { - "original": "Rúa de Ramiro Pascual 30" - }, - "latitude": 42.195709195, - "longitude": -8.716896004, - "lines": [ - "27" - ] - }, - { - "stopId": 7120, - "name": { - "original": "Rúa de Ramiro Pascual 33" - }, - "latitude": 42.195795442, - "longitude": -8.716893641, - "lines": [ - "27" - ] - }, - { - "stopId": 7130, - "name": { - "original": "Rúa de Ramiro Pascual 46" - }, - "latitude": 42.19350247, - "longitude": -8.715219623, - "lines": [ - "27" - ] - }, - { - "stopId": 7140, - "name": { - "original": "Rúa de Ramiro Pascual 71" - }, - "latitude": 42.193601829, - "longitude": -8.715157933, - "lines": [ - "27" - ] - }, - { - "stopId": 7150, - "name": { - "original": "Rúa de Ramiro Pascual 74" - }, - "latitude": 42.192415468, - "longitude": -8.71184004, - "lines": [ - "27" - ] - }, - { - "stopId": 7160, - "name": { - "original": "Rúa de Ramiro Pascual 97" - }, - "latitude": 42.192526527, - "longitude": -8.712588696, - "lines": [ - "27" - ] - }, - { - "stopId": 7170, - "name": { - "original": "Rúa de Ramiro Pascual 9" - }, - "latitude": 42.195322512, - "longitude": -8.719460515, - "lines": [ - "12B", - "18B", - "18H", - "27" - ] - }, - { - "stopId": 7200, - "name": { - "original": "Avda. de Ramón Nieto 125" - }, - "latitude": 42.231023929, - "longitude": -8.69459232, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7210, - "name": { - "original": "Avda. de Ramón Nieto 136" - }, - "latitude": 42.229661504, - "longitude": -8.691416585, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7220, - "name": { - "original": "Avda. de Ramón Nieto 173" - }, - "latitude": 42.229736581, - "longitude": -8.691879077, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7230, - "name": { - "original": "Avda. de Ramón Nieto 198" - }, - "latitude": 42.229560215, - "longitude": -8.687854611, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7240, - "name": { - "original": "Avda. de Ramón Nieto 252" - }, - "latitude": 42.229454954, - "longitude": -8.684539401, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7250, - "name": { - "original": "Avda. de Ramón Nieto 273" - }, - "latitude": 42.229533333, - "longitude": -8.684593198, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7260, - "name": { - "original": "Avda. de Ramón Nieto 308" - }, - "latitude": 42.22953241, - "longitude": -8.681347572, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7270, - "name": { - "original": "Avda. de Ramón Nieto 341" - }, - "latitude": 42.229570145, - "longitude": -8.681232237, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7280, - "name": { - "original": "Avda. de Ramón Nieto 355" - }, - "latitude": 42.228432118, - "longitude": -8.67827376, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7290, - "name": { - "original": "Avda. de Ramón Nieto 360" - }, - "latitude": 42.228411862, - "longitude": -8.678489489, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7300, - "name": { - "original": "Avda. de Ramón Nieto 390" - }, - "latitude": 42.223957681, - "longitude": -8.673451332, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7310, - "name": { - "original": "Avda. de Ramón Nieto 406" - }, - "latitude": 42.223219273, - "longitude": -8.672272983, - "lines": [ - "11", - "15A", - "15B", - "15C", - "25" - ] - }, - { - "stopId": 7320, - "name": { - "original": "Avda. de Ramón Nieto 475" - }, - "latitude": 42.224462184, - "longitude": -8.673842935, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7330, - "name": { - "original": "Avda. de Ramón Nieto 50" - }, - "latitude": 42.231776636, - "longitude": -8.697735869, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7340, - "name": { - "original": "Avda. de Ramón Nieto 503" - }, - "latitude": 42.223272423, - "longitude": -8.67216119, - "lines": [ - "11", - "15A", - "15B", - "15C", - "25" - ] - }, - { - "stopId": 7350, - "name": { - "original": "Avda. de Ramón Nieto 57" - }, - "latitude": 42.231927571, - "longitude": -8.697668814, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7360, - "name": { - "original": "Avda. de Ramón Nieto 96" - }, - "latitude": 42.230432101, - "longitude": -8.694045149, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7370, - "name": { - "original": "Avda. de Ramón Nieto 247" - }, - "latitude": 42.229607881, - "longitude": -8.686980211, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 7380, - "name": { - "original": "Camiño do Raviso 8" - }, - "latitude": 42.220087856, - "longitude": -8.707014826, - "lines": [ - "14" - ] - }, - { - "stopId": 7390, - "name": { - "original": "Camiño do Raviso 35" - }, - "latitude": 42.220167311, - "longitude": -8.706963864, - "lines": [ - "14" - ] - }, - { - "stopId": 7410, - "name": { - "original": "Rúa de Eduardo Cabello (Igrexa)" - }, - "latitude": 42.226366639, - "longitude": -8.752928216, - "lines": [ - "C3d", - "C3i", - "13", - "U1", - "H" - ] - }, - { - "stopId": 7440, - "name": { - "original": "Rúa Da Cruz 18" - }, - "latitude": 42.200640474, - "longitude": -8.684744444, - "lines": [ - "14" - ] - }, - { - "stopId": 7450, - "name": { - "original": "Rúa da Cruz 2" - }, - "latitude": 42.202168422, - "longitude": -8.68473908, - "lines": [ - "14" - ] - }, - { - "stopId": 7460, - "name": { - "original": "Rúa da Cruz 46" - }, - "latitude": 42.19807525, - "longitude": -8.684800771, - "lines": [ - "14" - ] - }, - { - "stopId": 7470, - "name": { - "original": "Rúa Da Cruz 63" - }, - "latitude": 42.198206824, - "longitude": -8.684878336, - "lines": [ - "14" - ] - }, - { - "stopId": 7480, - "name": { - "original": "Rúa Da Cruz 19" - }, - "latitude": 42.200729887, - "longitude": -8.684258964, - "lines": [ - "14" - ] - }, - { - "stopId": 7490, - "name": { - "original": "Rúa do Carballal 52" - }, - "latitude": 42.194091099, - "longitude": -8.683392611, - "lines": [ - "14" - ] - }, - { - "stopId": 7500, - "name": { - "original": "Rúa do Carballal 18" - }, - "latitude": 42.196388225, - "longitude": -8.684151676, - "lines": [ - "14" - ] - }, - { - "stopId": 7540, - "name": { - "original": "Avda. do Tranvía 100" - }, - "latitude": 42.226657624, - "longitude": -8.659447983, - "lines": [ - "11", - "15A" - ] - }, - { - "stopId": 7590, - "name": { - "original": "Avda. do Tranvía 40" - }, - "latitude": 42.225201551, - "longitude": -8.667101684, - "lines": [ - "11", - "15A" - ] - }, - { - "stopId": 7600, - "name": { - "original": "Rúa dos Chans (cruce Subida Chans)" - }, - "latitude": 42.198544554, - "longitude": -8.677824939, - "lines": [ - "14" - ] - }, - { - "stopId": 7610, - "name": { - "original": "Rúa das Chans (Colexio)" - }, - "latitude": 42.196647395, - "longitude": -8.677801904, - "lines": [ - "14" - ] - }, - { - "stopId": 7620, - "name": { - "original": "Rúa das Chans 97" - }, - "latitude": 42.189146758, - "longitude": -8.678708548, - "lines": [ - "14" - ] - }, - { - "stopId": 7630, - "name": { - "original": "Rúa do Salgueiro 6" - }, - "latitude": 42.243135911, - "longitude": -8.66173721, - "lines": [ - "9B", - "28" - ] - }, - { - "stopId": 7640, - "name": { - "original": "Rúa da Rabadeira 135" - }, - "latitude": 42.241620781, - "longitude": -8.652000054, - "lines": [ - "9B", - "28" - ] - }, - { - "stopId": 7650, - "name": { - "original": "Rúa da Rabadeira 64" - }, - "latitude": 42.239043121, - "longitude": -8.650247888, - "lines": [ - "9B", - "27", - "28" - ] - }, - { - "stopId": 7660, - "name": { - "original": "Rúa da Rabadeira 104" - }, - "latitude": 42.241610852, - "longitude": -8.651865944, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 7662, - "name": { - "original": "Rúa de Recaré 6" - }, - "latitude": 42.211013462, - "longitude": -8.68554295, - "lines": [ - "14" - ] - }, - { - "stopId": 7664, - "name": { - "original": "Rúa de Recaré (cruce Segade)" - }, - "latitude": 42.211201327, - "longitude": -8.688838517, - "lines": [ - "14" - ] - }, - { - "stopId": 7666, - "name": { - "original": "Rúa de Recaré 3" - }, - "latitude": 42.210514541, - "longitude": -8.685349777, - "lines": [ - "14" - ] - }, - { - "stopId": 7668, - "name": { - "original": "Rúa de Recaré 39" - }, - "latitude": 42.211022529, - "longitude": -8.688318168, - "lines": [ - "14" - ] - }, - { - "stopId": 7670, - "name": { - "original": "Rúa San Cristobo 6" - }, - "latitude": 42.235169136, - "longitude": -8.671176685, - "lines": [ - "9B" - ] - }, - { - "stopId": 7680, - "name": { - "original": "Rúa San Cristobo 117" - }, - "latitude": 42.240866745, - "longitude": -8.669273191, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 7690, - "name": { - "original": "Rúa San Cristobo 11" - }, - "latitude": 42.235468446, - "longitude": -8.670649153, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 7700, - "name": { - "original": "Rúa San Cristobo 30" - }, - "latitude": 42.236478263, - "longitude": -8.669194381, - "lines": [ - "9B" - ] - }, - { - "stopId": 7710, - "name": { - "original": "Rúa San Cristobo 41" - }, - "latitude": 42.236825775, - "longitude": -8.669313413, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 7720, - "name": { - "original": "Rúa San Cristobo 80" - }, - "latitude": 42.24099726, - "longitude": -8.669077286, - "lines": [ - "9B" - ] - }, - { - "stopId": 7730, - "name": { - "original": "Rúa do Salgueiro 24" - }, - "latitude": 42.241580812, - "longitude": -8.658065611, - "lines": [ - "9B", - "28" - ] - }, - { - "stopId": 7740, - "name": { - "original": "Rúa de Salgueiro 23" - }, - "latitude": 42.241658253, - "longitude": -8.658202403, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 7750, - "name": { - "original": "Rúa do Salgueiro 1" - }, - "latitude": 42.243330503, - "longitude": -8.661852545, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 7760, - "name": { - "original": "Camiño das Cunchadas (cruce Rúa da Senra)" - }, - "latitude": 42.193300199, - "longitude": -8.681021538, - "lines": [ - "14" - ] - }, - { - "stopId": 7762, - "name": { - "original": "Rúa de Segade 41" - }, - "latitude": 42.209575101, - "longitude": -8.690548833, - "lines": [ - "14" - ] - }, - { - "stopId": 7764, - "name": { - "original": "Rúa de Segade 86" - }, - "latitude": 42.209654568, - "longitude": -8.690495189, - "lines": [ - "14" - ] - }, - { - "stopId": 7810, - "name": { - "original": "Estrada Miraflores (Parque Parróco Xesús Alonso)" - }, - "latitude": 42.217817959, - "longitude": -8.710940668, - "lines": [ - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 7830, - "name": { - "original": "Rúa de Saa 72" - }, - "latitude": 42.20297089, - "longitude": -8.707945762, - "lines": [ - "18B", - "H3" - ] - }, - { - "stopId": 7840, - "name": { - "original": "Rúa da Saa do Monte 73" - }, - "latitude": 42.203039989, - "longitude": -8.710936623, - "lines": [ - "18B" - ] - }, - { - "stopId": 7850, - "name": { - "original": "Rúa de Saa 57" - }, - "latitude": 42.202923204, - "longitude": -8.708085237, - "lines": [ - "18B", - "H3" - ] - }, - { - "stopId": 7860, - "name": { - "original": "Rúa de Severino Cobas 73" - }, - "latitude": 42.225436283, - "longitude": -8.68893946, - "lines": [ - "25" - ] - }, - { - "stopId": 7870, - "name": { - "original": "Baixada á Praia 4" - }, - "latitude": 42.166897971, - "longitude": -8.802204658, - "lines": [ - "C3d", - "10", - "12A" - ] - }, - { - "stopId": 7880, - "name": { - "original": "Barrio da Salgueira 106" - }, - "latitude": 42.222364236, - "longitude": -8.718898254, - "lines": [ - "18A" - ] - }, - { - "stopId": 7890, - "name": { - "original": "Avda. de Cesáreo Vázquez 61" - }, - "latitude": 42.180764289, - "longitude": -8.80256063, - "lines": [ - "11", - "12A" - ] - }, - { - "stopId": 7900, - "name": { - "original": "Rúa de San Paio (cruce Camiño da Quintela)" - }, - "latitude": 42.20492472, - "longitude": -8.768904292, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 7910, - "name": { - "original": "Rúa de San Paio (Igrexa)" - }, - "latitude": 42.208040013, - "longitude": -8.767458581, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 7920, - "name": { - "original": "Rúa de San Paio (Torreiro)" - }, - "latitude": 42.208926096, - "longitude": -8.765294038, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 7930, - "name": { - "original": "Rúa de San Paio 136" - }, - "latitude": 42.208999211, - "longitude": -8.765346753, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 7940, - "name": { - "original": "Rúa de San Paio 220" - }, - "latitude": 42.207987966, - "longitude": -8.767688321, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 7950, - "name": { - "original": "Rúa de San Paio 242" - }, - "latitude": 42.206253649, - "longitude": -8.768742472, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 7960, - "name": { - "original": "Rúa de San Paio 284" - }, - "latitude": 42.202111343, - "longitude": -8.769560881, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 7970, - "name": { - "original": "Rúa de San Paio (fronte 58)" - }, - "latitude": 42.213820465, - "longitude": -8.760651176, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 7980, - "name": { - "original": "Rúa de San Paio 54" - }, - "latitude": 42.21430717, - "longitude": -8.760710185, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 7990, - "name": { - "original": "Rúa de San Paio 76" - }, - "latitude": 42.212612622, - "longitude": -8.760868435, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 8000, - "name": { - "original": "Rúa de San Paio 83" - }, - "latitude": 42.212034517, - "longitude": -8.760916715, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 8010, - "name": { - "original": "Rúa de Sanjurjo Badía 106" - }, - "latitude": 42.245018172, - "longitude": -8.703349646, - "lines": [ - "C3d", - "5B", - "10", - "17", - "31", - "U2", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 8020, - "name": { - "original": "Rúa de Sanjurjo Badía 123" - }, - "latitude": 42.246941664, - "longitude": -8.700376378, - "lines": [ - "C3i", - "5B", - "10", - "N1", - "H3" - ] - }, - { - "stopId": 8030, - "name": { - "original": "Rúa de Sanjurjo Badía 136" - }, - "latitude": 42.246056261, - "longitude": -8.701684825, - "lines": [ - "C3d", - "5B", - "10", - "17", - "31", - "U2", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 8040, - "name": { - "original": "Rúa de Sanjurjo Badía 167" - }, - "latitude": 42.24874024, - "longitude": -8.697546209, - "lines": [ - "C3i", - "5B", - "10", - "N1", - "H3" - ] - }, - { - "stopId": 8050, - "name": { - "original": "Rúa de Sanjurjo Badía 202" - }, - "latitude": 42.247765296, - "longitude": -8.698918203, - "lines": [ - "C3d", - "5B", - "10", - "17", - "31", - "U2", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 8060, - "name": { - "original": "Rúa de Sanjurjo Badía 79" - }, - "latitude": 42.244926864, - "longitude": -8.703642393, - "lines": [ - "C3i", - "5B", - "10", - "N1", - "H3" - ] - }, - { - "stopId": 8090, - "name": { - "original": "Estrada Miraflores (Centro Saúde)" - }, - "latitude": 42.216151643, - "longitude": -8.715616477, - "lines": [ - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 8100, - "name": { - "original": "Estrada da Gándara 79" - }, - "latitude": 42.160735669, - "longitude": -8.709771124, - "lines": [ - "7" - ] - }, - { - "stopId": 8110, - "name": { - "original": "Estrada da Gándara (Seoane)" - }, - "latitude": 42.160670051, - "longitude": -8.709878412, - "lines": [ - "7" - ] - }, - { - "stopId": 8120, - "name": { - "original": "Rúa de Severino Cobas (cruce Trav. de Santa Cristina)" - }, - "latitude": 42.22493632, - "longitude": -8.694369092, - "lines": [ - "25" - ] - }, - { - "stopId": 8130, - "name": { - "original": "Rúa de Severino Cobas 51" - }, - "latitude": 42.225485938, - "longitude": -8.692235895, - "lines": [ - "25" - ] - }, - { - "stopId": 8140, - "name": { - "original": "Rúa de Severino Cobas 14" - }, - "latitude": 42.224657696, - "longitude": -8.696532794, - "lines": [ - "25" - ] - }, - { - "stopId": 8150, - "name": { - "original": "Rúa de Severino Cobas 3" - }, - "latitude": 42.225076787, - "longitude": -8.697168477, - "lines": [ - "25" - ] - }, - { - "stopId": 8160, - "name": { - "original": "Rúa de Severino Cobas 88" - }, - "latitude": 42.224884679, - "longitude": -8.694275214, - "lines": [ - "25" - ] - }, - { - "stopId": 8170, - "name": { - "original": "Rúa de Severino Cobas 140" - }, - "latitude": 42.225428901, - "longitude": -8.688744499, - "lines": [ - "25" - ] - }, - { - "stopId": 8180, - "name": { - "original": "Estrada da Garrida 291" - }, - "latitude": 42.173993336, - "longitude": -8.70329684, - "lines": [ - "7" - ] - }, - { - "stopId": 8190, - "name": { - "original": "Subida da Costa (Colina)" - }, - "latitude": 42.214660701, - "longitude": -8.722840401, - "lines": [ - "A" - ] - }, - { - "stopId": 8200, - "name": { - "original": "Subida da Costa 21" - }, - "latitude": 42.214714337, - "longitude": -8.723068388, - "lines": [ - "A" - ] - }, - { - "stopId": 8210, - "name": { - "original": "Subida da Costa 3" - }, - "latitude": 42.214377129, - "longitude": -8.725964538, - "lines": [ - "A" - ] - }, - { - "stopId": 8220, - "name": { - "original": "Camiño da Corredoura 3" - }, - "latitude": 42.213993258, - "longitude": -8.726740824, - "lines": [ - "A" - ] - }, - { - "stopId": 8230, - "name": { - "original": "Rúa dos Chans (cruce Camiño Regada)" - }, - "latitude": 42.199146625, - "longitude": -8.676419461, - "lines": [ - "14" - ] - }, - { - "stopId": 8240, - "name": { - "original": "Subida á Madroa (Urbanización)" - }, - "latitude": 42.243382567, - "longitude": -8.674125307, - "lines": [ - "9B", - "27", - "28" - ] - }, - { - "stopId": 8250, - "name": { - "original": "Subida á Madroa 15" - }, - "latitude": 42.242669731, - "longitude": -8.670096629, - "lines": [ - "9B", - "27", - "28" - ] - }, - { - "stopId": 8282, - "name": { - "original": "Subida á Mouteira 6" - }, - "latitude": 42.206854901, - "longitude": -8.686031058, - "lines": [ - "14" - ] - }, - { - "stopId": 8284, - "name": { - "original": "Subida á Mouteira (Parque Monte Calvario)" - }, - "latitude": 42.206779403, - "longitude": -8.686218813, - "lines": [ - "14" - ] - }, - { - "stopId": 8290, - "name": { - "original": "Subida das Ánimas 31" - }, - "latitude": 42.235646525, - "longitude": -8.685908988, - "lines": [ - "27", - "28" - ] - }, - { - "stopId": 8300, - "name": { - "original": "Subida das Ánimas 32" - }, - "latitude": 42.23556225, - "longitude": -8.686044366, - "lines": [ - "27", - "28" - ] - }, - { - "stopId": 8330, - "name": { - "original": "Rúa de Tomás A. Alonso 86" - }, - "latitude": 42.223897608, - "longitude": -8.740424721, - "lines": [ - "C3i", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 8340, - "name": { - "original": "Rúa de Tomás A. Alonso 137" - }, - "latitude": 42.223840474, - "longitude": -8.740432891, - "lines": [ - "C3d", - "13", - "15B", - "15C", - "U1", - "H" - ] - }, - { - "stopId": 8370, - "name": { - "original": "Rúa de Tomás A. Alonso 220" - }, - "latitude": 42.223984208, - "longitude": -8.751326546, - "lines": [ - "C3d", - "C3i" - ] - }, - { - "stopId": 8390, - "name": { - "original": "Rúa de Tomás A. Alonso 251" - }, - "latitude": 42.223510532, - "longitude": -8.748903264, - "lines": [ - "C3d", - "13", - "15B", - "15C", - "U1", - "H" - ] - }, - { - "stopId": 8410, - "name": { - "original": "Rúa de Tomás Paredes (fronte 108)" - }, - "latitude": 42.218006346, - "longitude": -8.754154367, - "lines": [ - "C3d", - "10", - "15B" - ] - }, - { - "stopId": 8420, - "name": { - "original": "Rúa de Tomás Paredes 114" - }, - "latitude": 42.218031265, - "longitude": -8.754258995, - "lines": [ - "C3i", - "10" - ] - }, - { - "stopId": 8430, - "name": { - "original": "Rúa de Tomás Paredes 9" - }, - "latitude": 42.221229518, - "longitude": -8.753411657, - "lines": [ - "C3d", - "10", - "15B" - ] - }, - { - "stopId": 8440, - "name": { - "original": "Rúa de Tomás Paredes 86" - }, - "latitude": 42.220192578, - "longitude": -8.754164587, - "lines": [ - "C3i", - "10" - ] - }, - { - "stopId": 8450, - "name": { - "original": "Rúa do Conde de Torrecedeira (Parque)" - }, - "latitude": 42.231511437, - "longitude": -8.732178, - "lines": [ - "C1", - "C3d", - "A", - "5A", - "9B", - "15C", - "N4", - "H1" - ] - }, - { - "stopId": 8460, - "name": { - "original": "Rúa do Conde de Torrecedeira 105" - }, - "latitude": 42.227500225, - "longitude": -8.734096707, - "lines": [ - "C1", - "C3d", - "A", - "9B", - "15C", - "N4", - "H1" - ] - }, - { - "stopId": 8470, - "name": { - "original": "Rúa do Conde de Torrecedeira 21" - }, - "latitude": 42.234106639, - "longitude": -8.731302569, - "lines": [ - "C1", - "C3d", - "A", - "5A", - "9B", - "15C", - "N4", - "H1" - ] - }, - { - "stopId": 8480, - "name": { - "original": "Rúa do Conde de Torrecedeira 81" - }, - "latitude": 42.229616766, - "longitude": -8.732861043, - "lines": [ - "C1", - "C3d", - "A", - "5A", - "9B", - "15C", - "N4", - "H1" - ] - }, - { - "stopId": 8490, - "name": { - "original": "Rúa da Travesía de Vigo 202" - }, - "latitude": 42.244366441, - "longitude": -8.695452075, - "lines": [ - "C3i", - "5A", - "N1", - "H3" - ] - }, - { - "stopId": 8500, - "name": { - "original": "Rúa da Travesía de Vigo 105" - }, - "latitude": 42.238455548, - "longitude": -8.703814812, - "lines": [ - "C3d", - "5A", - "31", - "U2", - "H2", - "PSA 1" - ] - }, - { - "stopId": 8510, - "name": { - "original": "Rúa da Travesía de Vigo 124" - }, - "latitude": 42.238413145, - "longitude": -8.703563202, - "lines": [ - "C3i", - "5A", - "N1" - ] - }, - { - "stopId": 8520, - "name": { - "original": "Rúa da Travesía de Vigo 153" - }, - "latitude": 42.241332883, - "longitude": -8.702059906, - "lines": [ - "C3d", - "5A", - "31", - "U2", - "H2", - "PSA 1" - ] - }, - { - "stopId": 8530, - "name": { - "original": "Rúa da Travesía de Vigo 158" - }, - "latitude": 42.241101222, - "longitude": -8.701974032, - "lines": [ - "C3i", - "5A", - "N1" - ] - }, - { - "stopId": 8540, - "name": { - "original": "Rúa da Travesía de Vigo 193" - }, - "latitude": 42.242844316, - "longitude": -8.698295825, - "lines": [ - "C3d", - "5A", - "31", - "U2", - "H2", - "PSA 1" - ] - }, - { - "stopId": 8550, - "name": { - "original": "Rúa da Travesía de Vigo 220" - }, - "latitude": 42.246425568, - "longitude": -8.692950624, - "lines": [ - "C3i", - "5A", - "5B", - "N1", - "H3" - ] - }, - { - "stopId": 8560, - "name": { - "original": "Rúa da Travesía de Vigo 213" - }, - "latitude": 42.24409871, - "longitude": -8.69614733, - "lines": [ - "C3d", - "5A", - "31", - "U2", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 8570, - "name": { - "original": "Rúa da Travesía de Vigo 239" - }, - "latitude": 42.246143319, - "longitude": -8.69359937, - "lines": [ - "C3d", - "5A", - "31", - "U2", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 8580, - "name": { - "original": "Rúa da Travesía de Vigo 32" - }, - "latitude": 42.233828086, - "longitude": -8.706311242, - "lines": [ - "C3i", - "5A", - "31", - "N1" - ] - }, - { - "stopId": 8590, - "name": { - "original": "Rúa da Travesía de Vigo 37" - }, - "latitude": 42.233681224, - "longitude": -8.706702136, - "lines": [ - "C3d", - "5A", - "31", - "U2", - "H2", - "PSA 1" - ] - }, - { - "stopId": 8600, - "name": { - "original": "Rúa da Travesía de Vigo 71" - }, - "latitude": 42.236350093, - "longitude": -8.70429745, - "lines": [ - "C3d", - "5A", - "31", - "U2", - "H2", - "PSA 1" - ] - }, - { - "stopId": 8610, - "name": { - "original": "Rúa da Travesía de Vigo 8" - }, - "latitude": 42.232028188, - "longitude": -8.708203776, - "lines": [ - "C3i", - "A", - "4A", - "4C", - "5A", - "6", - "9B", - "11", - "15A", - "15B", - "15C", - "23", - "24", - "25", - "27", - "28", - "N1", - "N4" - ] - }, - { - "stopId": 8620, - "name": { - "original": "Rúa da Travesía de Vigo 82" - }, - "latitude": 42.236261792, - "longitude": -8.703994979, - "lines": [ - "C3i", - "5A", - "N1" - ] - }, - { - "stopId": 8630, - "name": { - "original": "Rúa da Travesía de Vigo 7" - }, - "latitude": 42.232045931, - "longitude": -8.708603793, - "lines": [ - "C3d", - "A", - "4A", - "4C", - "5A", - "6", - "9B", - "11", - "15A", - "15B", - "15C", - "23", - "25", - "27", - "28", - "N4", - "U2", - "H2", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 8660, - "name": { - "original": "Química (CUVI)" - }, - "latitude": 42.168290977, - "longitude": -8.68342947, - "lines": [ - "A", - "15C", - "U1", - "U2" - ] - }, - { - "stopId": 8670, - "name": { - "original": "Bioloxía (CUVI)" - }, - "latitude": 42.167687661, - "longitude": -8.685994335, - "lines": [ - "A", - "15C", - "U1", - "U2" - ] - }, - { - "stopId": 8680, - "name": { - "original": "Económicas e Empresariais (CUVI)" - }, - "latitude": 42.169603028, - "longitude": -8.680108895, - "lines": [ - "A", - "15C", - "U1", - "U2" - ] - }, - { - "stopId": 8700, - "name": { - "original": "Enxeñeiros (CUVI)" - }, - "latitude": 42.167963445, - "longitude": -8.688421342, - "lines": [ - "A", - "15C", - "U1", - "U2" - ] - }, - { - "stopId": 8710, - "name": { - "original": "Universidade." - }, - "latitude": 42.167985106, - "longitude": -8.688425395, - "lines": [ - "A" - ] - }, - { - "stopId": 8720, - "name": { - "original": "Humanidades (CUVI)" - }, - "latitude": 42.169678809, - "longitude": -8.679104749, - "lines": [ - "A", - "15C", - "U1", - "U2" - ] - }, - { - "stopId": 8721, - "name": { - "original": "Universidade.." - }, - "latitude": 42.169776602, - "longitude": -8.678942156, - "lines": [ - "A" - ] - }, - { - "stopId": 8730, - "name": { - "original": "Telecomunicacións (CUVI) B" - }, - "latitude": 42.170159671, - "longitude": -8.68735086, - "lines": [ - "A" - ] - }, - { - "stopId": 8740, - "name": { - "original": "Telecomunicacións (CUVI)" - }, - "latitude": 42.170123888, - "longitude": -8.687270393, - "lines": [ - "A", - "15C", - "U1", - "U2" - ] - }, - { - "stopId": 8750, - "name": { - "original": "Rúa de Urzáiz - Est. Intermodal - C.C." - }, - "latitude": 42.233722977, - "longitude": -8.714502762, - "lines": [ - "A", - "4A", - "4C", - "5A", - "6", - "9B", - "11", - "15B", - "15C", - "24", - "28", - "N4", - "PSA 4" - ] - }, - { - "stopId": 8770, - "name": { - "original": "Rúa de Urzáiz 13" - }, - "latitude": 42.235420929, - "longitude": -8.718721877, - "lines": [ - "A", - "4A", - "4C", - "5A", - "6", - "7", - "9B", - "11", - "12B", - "14", - "15B", - "15C", - "16", - "17", - "18A", - "18B", - "18H", - "24", - "28", - "N1", - "N4", - "PSA 4" - ] - }, - { - "stopId": 8820, - "name": { - "original": "Rúa de Urzáiz 28" - }, - "latitude": 42.23516998, - "longitude": -8.718398782, - "lines": [ - "C1", - "A", - "4A", - "4C", - "5A", - "7", - "9B", - "12B", - "14", - "15B", - "15C", - "16", - "17", - "18A", - "18B", - "18H", - "24", - "28", - "N1", - "N4" - ] - }, - { - "stopId": 8840, - "name": { - "original": "Rúa de Urzáiz 60 - Est. Intermodal - C.C." - }, - "latitude": 42.233986283, - "longitude": -8.71541048, - "lines": [ - "A", - "4A", - "4C", - "5A", - "9B", - "11", - "15B", - "15C", - "24", - "28", - "N1", - "N4" - ] - }, - { - "stopId": 8850, - "name": { - "original": "Rúa de Urzáiz 97" - }, - "latitude": 42.232341315, - "longitude": -8.710892054, - "lines": [ - "A", - "4A", - "4C", - "5A", - "6", - "9B", - "11", - "15B", - "15C", - "28", - "N4", - "PSA 4" - ] - }, - { - "stopId": 8870, - "name": { - "original": "Rúa de Venezuela 4" - }, - "latitude": 42.234250043, - "longitude": -8.724361531, - "lines": [ - "4A", - "4C", - "5B", - "11", - "12A", - "12B", - "17", - "27", - "N1" - ] - }, - { - "stopId": 8880, - "name": { - "original": "Rúa de Venezuela 20" - }, - "latitude": 42.233188126, - "longitude": -8.72155331, - "lines": [ - "4A", - "4C", - "5B", - "11", - "12A", - "12B", - "17", - "27", - "N1" - ] - }, - { - "stopId": 8890, - "name": { - "original": "Rúa de Venezuela 21" - }, - "latitude": 42.233283503, - "longitude": -8.721378959, - "lines": [ - "4A", - "4C", - "5B", - "7", - "12B", - "16", - "17", - "PSA 4" - ] - }, - { - "stopId": 8900, - "name": { - "original": "Rúa de Venezuela 45" - }, - "latitude": 42.232243383, - "longitude": -8.718524158, - "lines": [ - "4A", - "4C", - "5B", - "7", - "12B", - "16", - "17", - "PSA 4" - ] - }, - { - "stopId": 8910, - "name": { - "original": "Rúa de Venezuela 42" - }, - "latitude": 42.232224046, - "longitude": -8.718985824, - "lines": [ - "4A", - "4C", - "5B", - "11", - "12A", - "12B", - "17", - "27", - "N1" - ] - }, - { - "stopId": 8916, - "name": { - "original": "Rúa de Venezuela 60" - }, - "latitude": 42.231593651, - "longitude": -8.71714227, - "lines": [ - "27" - ] - }, - { - "stopId": 8930, - "name": { - "original": "Rúa de Vilagarcía de Arousa (cruce Rúa do Grove)" - }, - "latitude": 42.22014115, - "longitude": -8.745082757, - "lines": [ - "C3i", - "5B" - ] - }, - { - "stopId": 8950, - "name": { - "original": "Rúa de Marín 5" - }, - "latitude": 42.218712573, - "longitude": -8.75011435, - "lines": [ - "C3i", - "5B" - ] - }, - { - "stopId": 8970, - "name": { - "original": "Rúa do Seixo 45" - }, - "latitude": 42.197425383, - "longitude": -8.713700535, - "lines": [ - "A", - "H3" - ] - }, - { - "stopId": 8980, - "name": { - "original": "Rúa do Seixo 38" - }, - "latitude": 42.197532685, - "longitude": -8.713614705, - "lines": [ - "A", - "H3" - ] - }, - { - "stopId": 8990, - "name": { - "original": "Rúa do Seixo 75" - }, - "latitude": 42.200673849, - "longitude": -8.714185609, - "lines": [ - "A", - "18B", - "H3" - ] - }, - { - "stopId": 9000, - "name": { - "original": "Rúa do Seixo (Parque)" - }, - "latitude": 42.200719549, - "longitude": -8.714115872, - "lines": [ - "A", - "H3" - ] - }, - { - "stopId": 9010, - "name": { - "original": "Rúa de Xeme 71" - }, - "latitude": 42.203157887, - "longitude": -8.694293108, - "lines": [ - "14" - ] - }, - { - "stopId": 9020, - "name": { - "original": "Xestoso" - }, - "latitude": 42.207584622, - "longitude": -8.670108196, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 9040, - "name": { - "original": "Estrada das Plantas (cruce Camiño Monte Vello)" - }, - "latitude": 42.20831564, - "longitude": -8.670282438, - "lines": [ - "15B", - "15C", - "U2" - ] - }, - { - "stopId": 9050, - "name": { - "original": "Estrada da Igrexa 45" - }, - "latitude": 42.154646971, - "longitude": -8.688349062, - "lines": [ - "7" - ] - }, - { - "stopId": 10061, - "name": { - "original": "Estrada de San Xoán 193" - }, - "latitude": 42.185277472, - "longitude": -8.741558953, - "lines": [ - "17" - ] - }, - { - "stopId": 14101, - "name": { - "original": "Estrada da Garrida 165" - }, - "latitude": 42.168008539, - "longitude": -8.710415438, - "lines": [ - "7" - ] - }, - { - "stopId": 14102, - "name": { - "original": "Estrada da Garrida 108" - }, - "latitude": 42.168282882, - "longitude": -8.710066751, - "lines": [ - "7" - ] - }, - { - "stopId": 14105, - "name": { - "original": "Ciencias Xurídicas (CUVI)" - }, - "latitude": 42.167237978, - "longitude": -8.681135704, - "lines": [ - "A", - "15C", - "U1", - "U2" - ] - }, - { - "stopId": 14106, - "name": { - "original": "Avda. do Aeroporto 92" - }, - "latitude": 42.234161582, - "longitude": -8.695074564, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 14107, - "name": { - "original": "Camiño Padín (Rotonda Autoestrada)" - }, - "latitude": 42.257847205, - "longitude": -8.677696507, - "lines": [ - "10" - ] - }, - { - "stopId": 14108, - "name": { - "original": "Avda. da Ponte (antes desvío Autovía)" - }, - "latitude": 42.21401741, - "longitude": -8.67133083, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 14111, - "name": { - "original": "Estrada de Bembrive (Centro Saúde)" - }, - "latitude": 42.204262657, - "longitude": -8.684801801, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 14112, - "name": { - "original": "Estrada de Bembrive (Alameda)" - }, - "latitude": 42.204047198, - "longitude": -8.684697288, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 14113, - "name": { - "original": "Estrada da Coutada 20" - }, - "latitude": 42.193458577, - "longitude": -8.702065856, - "lines": [ - "6", - "27" - ] - }, - { - "stopId": 14117, - "name": { - "original": "Rúa do Couto de San Honorato 26" - }, - "latitude": 42.228574702, - "longitude": -8.712864548, - "lines": [ - "H2" - ] - }, - { - "stopId": 14119, - "name": { - "original": "Rúa do Couto de San Honorato 80" - }, - "latitude": 42.229320789, - "longitude": -8.710390551, - "lines": [ - "H2" - ] - }, - { - "stopId": 14121, - "name": { - "original": "Rúa da Reconquista 2" - }, - "latitude": 42.238625474, - "longitude": -8.723242095, - "lines": [ - "C1", - "C3d", - "A", - "5A", - "9B", - "10", - "15B", - "15C", - "24", - "28", - "N4" - ] - }, - { - "stopId": 14122, - "name": { - "original": "Avda. do Alcalde Gregorio Espino 9" - }, - "latitude": 42.231584097, - "longitude": -8.706968521, - "lines": [ - "4C", - "23", - "31", - "H2", - "PSA 4" - ] - }, - { - "stopId": 14123, - "name": { - "original": "Rúa do Porriño 9" - }, - "latitude": 42.214127819, - "longitude": -8.752027594, - "lines": [ - "C3d", - "C3i", - "4A", - "4C", - "5B", - "11", - "15A", - "15B", - "N4", - "U1" - ] - }, - { - "stopId": 14124, - "name": { - "original": "Rúa de Eduardo Cabello (fronte Igrexa)" - }, - "latitude": 42.226569499, - "longitude": -8.752773946, - "lines": [ - "C3d", - "C3i", - "6" - ] - }, - { - "stopId": 14125, - "name": { - "original": "Rúa do Porriño (fronte 9)" - }, - "latitude": 42.213869651, - "longitude": -8.751990789, - "lines": [ - "C3d", - "C3i", - "4A", - "4C", - "15A", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 14126, - "name": { - "original": "Rúa da Travesía de Vigo 194" - }, - "latitude": 42.242494425, - "longitude": -8.699249038, - "lines": [ - "C3i", - "5A", - "N1" - ] - }, - { - "stopId": 14127, - "name": { - "original": "Avda. de Buenos Aires 13" - }, - "latitude": 42.249306896, - "longitude": -8.695179916, - "lines": [ - "5B", - "10", - "N1", - "H3" - ] - }, - { - "stopId": 14128, - "name": { - "original": "Camiño do Caramuxo (fronte 9)" - }, - "latitude": 42.20733292, - "longitude": -8.752159103, - "lines": [ - "5A" - ] - }, - { - "stopId": 14129, - "name": { - "original": "Camiño do Caramuxo 11" - }, - "latitude": 42.20723039, - "longitude": -8.752592351, - "lines": [ - "5A" - ] - }, - { - "stopId": 14131, - "name": { - "original": "Rúa de Tomás Paredes 4" - }, - "latitude": 42.221948768, - "longitude": -8.753171211, - "lines": [ - "C3i", - "10" - ] - }, - { - "stopId": 14132, - "name": { - "original": "Rúa de Sanjurjo Badía 252" - }, - "latitude": 42.249307631, - "longitude": -8.696542008, - "lines": [ - "C3d", - "5A", - "5B", - "10", - "17", - "31", - "U2", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 14133, - "name": { - "original": "Avda. de Galicia 37" - }, - "latitude": 42.250977575, - "longitude": -8.694471881, - "lines": [ - "C3i", - "17" - ] - }, - { - "stopId": 14134, - "name": { - "original": "Avda. de Galicia 182" - }, - "latitude": 42.253208793, - "longitude": -8.686995591, - "lines": [ - "C3d" - ] - }, - { - "stopId": 14135, - "name": { - "original": "Rúa de Santo Amaro (Praza de España)" - }, - "latitude": 42.229174145, - "longitude": -8.720143055, - "lines": [ - "C1" - ] - }, - { - "stopId": 14136, - "name": { - "original": "Avda. de Galicia 18" - }, - "latitude": 42.250484372, - "longitude": -8.694878804, - "lines": [ - "C3d", - "17" - ] - }, - { - "stopId": 14137, - "name": { - "original": "Estrada Matamá Pazo (Igrexa)" - }, - "latitude": 42.200003406, - "longitude": -8.753169, - "lines": [ - "29" - ] - }, - { - "stopId": 14138, - "name": { - "original": "Estrada de Madrid (Campo de Fútbol)" - }, - "latitude": 42.216459201, - "longitude": -8.678591709, - "lines": [ - "12B", - "15B", - "15C" - ] - }, - { - "stopId": 14139, - "name": { - "original": "Avda. de E. Martínez Garrido 27" - }, - "latitude": 42.227492758, - "longitude": -8.700413366, - "lines": [ - "6", - "25", - "31" - ] - }, - { - "stopId": 14140, - "name": { - "original": "Avda. de E. Martínez Garrido 30" - }, - "latitude": 42.228210877, - "longitude": -8.699999354, - "lines": [ - "4C", - "6", - "23", - "25", - "31", - "N4", - "PSA 4" - ] - }, - { - "stopId": 14141, - "name": { - "original": "Rúa de Jenaro de la Fuente 43" - }, - "latitude": 42.231379202, - "longitude": -8.699876213, - "lines": [ - "11", - "15A", - "15B", - "15C", - "H3" - ] - }, - { - "stopId": 14142, - "name": { - "original": "Avda. da Hispanidade 22" - }, - "latitude": 42.231463434, - "longitude": -8.728844425, - "lines": [ - "16" - ] - }, - { - "stopId": 14143, - "name": { - "original": "Avda. da Hispanidade 38" - }, - "latitude": 42.229753483, - "longitude": -8.729002675, - "lines": [ - "16" - ] - }, - { - "stopId": 14144, - "name": { - "original": "Avda. da Hispanidade 82" - }, - "latitude": 42.226760436, - "longitude": -8.727385303, - "lines": [ - "16" - ] - }, - { - "stopId": 14150, - "name": { - "original": "Rúa do Padre Don Rúa 1" - }, - "latitude": 42.232076561, - "longitude": -8.719055236, - "lines": [ - "14" - ] - }, - { - "stopId": 14152, - "name": { - "original": "Rúa do Monte Calvario 4" - }, - "latitude": 42.204815402, - "longitude": -8.687168969, - "lines": [ - "14" - ] - }, - { - "stopId": 14153, - "name": { - "original": "Estrada de Bembrive 173" - }, - "latitude": 42.205357233, - "longitude": -8.692495739, - "lines": [ - "6", - "14" - ] - }, - { - "stopId": 14154, - "name": { - "original": "Rúa das Chans (fronte 56)" - }, - "latitude": 42.19360258, - "longitude": -8.677258993, - "lines": [ - "14" - ] - }, - { - "stopId": 14156, - "name": { - "original": "Rúa de Xeme (cruce Camiño da Carballeira)" - }, - "latitude": 42.203378431, - "longitude": -8.696666863, - "lines": [ - "14" - ] - }, - { - "stopId": 14157, - "name": { - "original": "Rúa do Xeme (cruce Rúa de Eifonso)" - }, - "latitude": 42.202979066, - "longitude": -8.694065121, - "lines": [ - "14" - ] - }, - { - "stopId": 14161, - "name": { - "original": "Rúa de López Mora 62" - }, - "latitude": 42.224130699, - "longitude": -8.732568248, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 14162, - "name": { - "original": "Avda. da Florida 82" - }, - "latitude": 42.211371871, - "longitude": -8.746523782, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 14163, - "name": { - "original": "Avda. da Florida (fronte 82)" - }, - "latitude": 42.211442202, - "longitude": -8.746227469, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 14164, - "name": { - "original": "Rúa de Tomás A. Alonso 136" - }, - "latitude": 42.225172437, - "longitude": -8.744777354, - "lines": [ - "C3i", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 14165, - "name": { - "original": "Rúa de Tomás A. Alonso 193" - }, - "latitude": 42.224905029, - "longitude": -8.745285775, - "lines": [ - "C3d", - "13", - "15B", - "15C", - "U1", - "H" - ] - }, - { - "stopId": 14166, - "name": { - "original": "Avda. das Camelias 114" - }, - "latitude": 42.225142981, - "longitude": -8.729707944, - "lines": [ - "4A", - "4C", - "7", - "12B", - "17", - "27", - "PSA 4" - ] - }, - { - "stopId": 14167, - "name": { - "original": "Beiramar - Pescadores" - }, - "latitude": 42.225279021, - "longitude": -8.751908648, - "lines": [ - "6", - "9B", - "28" - ] - }, - { - "stopId": 14168, - "name": { - "original": "Avda. das Camelias 113" - }, - "latitude": 42.224928285, - "longitude": -8.729631509, - "lines": [ - "4A", - "4C", - "11", - "12B", - "17", - "27", - "N1" - ] - }, - { - "stopId": 14169, - "name": { - "original": "Avda. das Camelias 136" - }, - "latitude": 42.22244224, - "longitude": -8.731271052, - "lines": [ - "C1", - "4A", - "4C", - "7", - "12B", - "16", - "17", - "27", - "LZH", - "PSA 4" - ] - }, - { - "stopId": 14170, - "name": { - "original": "Avda. de Samil (Praia da Punta)" - }, - "latitude": 42.218831744, - "longitude": -8.77571001, - "lines": [ - "10", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 14171, - "name": { - "original": "Avda. de Samil (fronte Praia da Punta)" - }, - "latitude": 42.218844713, - "longitude": -8.775459221, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 14173, - "name": { - "original": "Rúa do Gaiteiro de Ricardo Portela (fronte Pavillón)" - }, - "latitude": 42.235900754, - "longitude": -8.731391435, - "lines": [ - "C1", - "C3d", - "A", - "5A", - "9B", - "15C", - "N4", - "H1" - ] - }, - { - "stopId": 14174, - "name": { - "original": "Rúa do Padre Seixas (Parque da Bouza)" - }, - "latitude": 42.211844516, - "longitude": -8.749287921, - "lines": [ - "11", - "16" - ] - }, - { - "stopId": 14175, - "name": { - "original": "Rúa do Padre Seixas 32" - }, - "latitude": 42.211792864, - "longitude": -8.749617832, - "lines": [ - "16" - ] - }, - { - "stopId": 14177, - "name": { - "original": "Rúa de Fernando Conde (cruce Avda. da Gran Vía)" - }, - "latitude": 42.22985125, - "longitude": -8.71972059, - "lines": [ - "12A", - "14", - "27" - ] - }, - { - "stopId": 14178, - "name": { - "original": "Rúa do Marqués de Alcedo (Parque)" - }, - "latitude": 42.233009005, - "longitude": -8.724497604, - "lines": [ - "12A", - "27" - ] - }, - { - "stopId": 14179, - "name": { - "original": "Rúa da Costa 4" - }, - "latitude": 42.213260612, - "longitude": -8.722562576, - "lines": [ - "A", - "18B", - "18H" - ] - }, - { - "stopId": 14180, - "name": { - "original": "Avda. de E. Martínez Garrido 108" - }, - "latitude": 42.224749197, - "longitude": -8.707320585, - "lines": [ - "4C", - "23", - "31", - "N4", - "PSA 4" - ] - }, - { - "stopId": 14181, - "name": { - "original": "Camiño da Corredoura (Igrexa)" - }, - "latitude": 42.210954716, - "longitude": -8.727776522, - "lines": [ - "A" - ] - }, - { - "stopId": 14182, - "name": { - "original": "Rúa da Costa 39" - }, - "latitude": 42.211618245, - "longitude": -8.72147159, - "lines": [ - "A", - "18B", - "18H" - ] - }, - { - "stopId": 14183, - "name": { - "original": "Rúa do Xalón (Colexio)" - }, - "latitude": 42.220622235, - "longitude": -8.654888024, - "lines": [ - "11" - ] - }, - { - "stopId": 14184, - "name": { - "original": "Rúa do Xalón 5" - }, - "latitude": 42.217384986, - "longitude": -8.657082399, - "lines": [ - "11" - ] - }, - { - "stopId": 14185, - "name": { - "original": "Rúa da Becerreira 81" - }, - "latitude": 42.219667098, - "longitude": -8.659470523, - "lines": [ - "11" - ] - }, - { - "stopId": 14186, - "name": { - "original": "Rúa da Becerreira (fronte 64)" - }, - "latitude": 42.218044517, - "longitude": -8.662618478, - "lines": [ - "11" - ] - }, - { - "stopId": 14187, - "name": { - "original": "Rúa da Becerreira 1" - }, - "latitude": 42.221588029, - "longitude": -8.662035851, - "lines": [ - "11" - ] - }, - { - "stopId": 14188, - "name": { - "original": "Rúa da Becerreira 41" - }, - "latitude": 42.217595578, - "longitude": -8.661414166, - "lines": [ - "11" - ] - }, - { - "stopId": 14189, - "name": { - "original": "Rúa Molais 84" - }, - "latitude": 42.226081487, - "longitude": -8.654133203, - "lines": [ - "11" - ] - }, - { - "stopId": 14190, - "name": { - "original": "Rúa de Severino Cobas 196" - }, - "latitude": 42.225080876, - "longitude": -8.683314171, - "lines": [ - "25" - ] - }, - { - "stopId": 14191, - "name": { - "original": "Camiño da Bouciña 76" - }, - "latitude": 42.223737557, - "longitude": -8.682141153, - "lines": [ - "25" - ] - }, - { - "stopId": 14192, - "name": { - "original": "Rúa das Figueiras 282" - }, - "latitude": 42.231625599, - "longitude": -8.652046516, - "lines": [ - "25" - ] - }, - { - "stopId": 14193, - "name": { - "original": "Avda. de Santa Mariña 443" - }, - "latitude": 42.230916628, - "longitude": -8.641628816, - "lines": [ - "25" - ] - }, - { - "stopId": 14194, - "name": { - "original": "Avda. de Santa Mariña 425" - }, - "latitude": 42.228639377, - "longitude": -8.640978361, - "lines": [ - "25" - ] - }, - { - "stopId": 14195, - "name": { - "original": "Avda. de Santa Mariña 249" - }, - "latitude": 42.226263256, - "longitude": -8.644091084, - "lines": [ - "25" - ] - }, - { - "stopId": 14196, - "name": { - "original": "Avda. de Santa Mariña 229" - }, - "latitude": 42.225296, - "longitude": -8.649527921, - "lines": [ - "25" - ] - }, - { - "stopId": 14197, - "name": { - "original": "Rúa Molais (cruce Rúa das Carballas)" - }, - "latitude": 42.225912491, - "longitude": -8.653698801, - "lines": [ - "25" - ] - }, - { - "stopId": 14198, - "name": { - "original": "Rúa do Riomao 21" - }, - "latitude": 42.227231301, - "longitude": -8.659997969, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 14199, - "name": { - "original": "Camiño da Bouciña 79" - }, - "latitude": 42.223755464, - "longitude": -8.682041911, - "lines": [ - "25" - ] - }, - { - "stopId": 14200, - "name": { - "original": "Rúa de Severino Cobas 119" - }, - "latitude": 42.225112655, - "longitude": -8.683402684, - "lines": [ - "25" - ] - }, - { - "stopId": 14201, - "name": { - "original": "Avda. de Santa Mariña (cruce Avda. do Tranvía)" - }, - "latitude": 42.226291056, - "longitude": -8.641647591, - "lines": [ - "25" - ] - }, - { - "stopId": 14202, - "name": { - "original": "Rúa de Jenaro de la Fuente 58" - }, - "latitude": 42.231273786, - "longitude": -8.700145645, - "lines": [ - "11", - "15A", - "15B", - "15C", - "H3" - ] - }, - { - "stopId": 14203, - "name": { - "original": "Avda. do Tranvía S/N (despois Camiño Lugar)" - }, - "latitude": 42.226524401, - "longitude": -8.661251786, - "lines": [ - "11", - "15A" - ] - }, - { - "stopId": 14204, - "name": { - "original": "Rúa de Manuel Álvarez 151" - }, - "latitude": 42.22312688, - "longitude": -8.681864633, - "lines": [ - "25", - "31", - "H3" - ] - }, - { - "stopId": 14205, - "name": { - "original": "Estrada do Freixo (Cemiterio)" - }, - "latitude": 42.178408629, - "longitude": -8.733198549, - "lines": [ - "7" - ] - }, - { - "stopId": 14206, - "name": { - "original": "Avda. da Gran Vía (Instituto)" - }, - "latitude": 42.220514043, - "longitude": -8.731700217, - "lines": [ - "C3i", - "7", - "11", - "13", - "15A", - "16", - "23", - "29", - "H2" - ] - }, - { - "stopId": 14207, - "name": { - "original": "Camiño do Pinal 19" - }, - "latitude": 42.161212162, - "longitude": -8.716377433, - "lines": [ - "7" - ] - }, - { - "stopId": 14208, - "name": { - "original": "Estrada de Valadares 452" - }, - "latitude": 42.162237207, - "longitude": -8.71885531, - "lines": [ - "7" - ] - }, - { - "stopId": 14209, - "name": { - "original": "Estrada da Garrida 263" - }, - "latitude": 42.173333822, - "longitude": -8.705439803, - "lines": [ - "7" - ] - }, - { - "stopId": 14210, - "name": { - "original": "Estrada da Garrida (frente 243)" - }, - "latitude": 42.173077394, - "longitude": -8.705659744, - "lines": [ - "7" - ] - }, - { - "stopId": 14211, - "name": { - "original": "Estrada do Monte Alba 32" - }, - "latitude": 42.165479162, - "longitude": -8.721775005, - "lines": [ - "7" - ] - }, - { - "stopId": 14212, - "name": { - "original": "Estrada do Monte Alba 54" - }, - "latitude": 42.164694101, - "longitude": -8.724472962, - "lines": [ - "7" - ] - }, - { - "stopId": 14213, - "name": { - "original": "Estrada do Freixo (Campo Fútbol)" - }, - "latitude": 42.169153241, - "longitude": -8.729001464, - "lines": [ - "7" - ] - }, - { - "stopId": 14214, - "name": { - "original": "Estrada do Freixo 191" - }, - "latitude": 42.175760907, - "longitude": -8.734516924, - "lines": [ - "7" - ] - }, - { - "stopId": 14215, - "name": { - "original": "Estrada do Freixo 90" - }, - "latitude": 42.175592169, - "longitude": -8.734477788, - "lines": [ - "7" - ] - }, - { - "stopId": 14216, - "name": { - "original": "Estrada do Freixo (fronte Campo Fútbol)" - }, - "latitude": 42.169143301, - "longitude": -8.729076566, - "lines": [ - "7" - ] - }, - { - "stopId": 14217, - "name": { - "original": "Estrada do Monte Alba (frente 54)" - }, - "latitude": 42.164570839, - "longitude": -8.724561475, - "lines": [ - "7" - ] - }, - { - "stopId": 14218, - "name": { - "original": "Estrada do Monte Alba 21" - }, - "latitude": 42.165288305, - "longitude": -8.721367309, - "lines": [ - "7" - ] - }, - { - "stopId": 14219, - "name": { - "original": "Camiño do Pinal 59" - }, - "latitude": 42.159500512, - "longitude": -8.718247279, - "lines": [ - "7" - ] - }, - { - "stopId": 14220, - "name": { - "original": "Camiño da Bouciña 14" - }, - "latitude": 42.225657321, - "longitude": -8.681467666, - "lines": [ - "25" - ] - }, - { - "stopId": 14221, - "name": { - "original": "Camiño da Bouciña 3" - }, - "latitude": 42.225809218, - "longitude": -8.681652991, - "lines": [ - "25" - ] - }, - { - "stopId": 14222, - "name": { - "original": "Camiño do Pinal 5" - }, - "latitude": 42.162959525, - "longitude": -8.716541365, - "lines": [ - "7" - ] - }, - { - "stopId": 14223, - "name": { - "original": "Avda. Beiramar \"Porto Pesqueiro Berbés\"" - }, - "latitude": 42.236650106, - "longitude": -8.73161427, - "lines": [ - "C3i", - "A", - "5A", - "5B", - "10", - "11", - "15C", - "N1", - "N4", - "H1" - ] - }, - { - "stopId": 14224, - "name": { - "original": "Rúa do Conde de Torrecedeira 16" - }, - "latitude": 42.234285927, - "longitude": -8.731266507, - "lines": [ - "C3i", - "A", - "5A", - "5B", - "10", - "11", - "15C", - "N1", - "N4", - "H1" - ] - }, - { - "stopId": 14225, - "name": { - "original": "Rúa do Conde de Torrecedeira 50" - }, - "latitude": 42.231716574, - "longitude": -8.732308737, - "lines": [ - "C3i", - "A", - "5A", - "5B", - "10", - "11", - "15C", - "N1", - "N4", - "H1" - ] - }, - { - "stopId": 14226, - "name": { - "original": "Rúa do Conde de Torrecedeira 70" - }, - "latitude": 42.229574859, - "longitude": -8.733073973, - "lines": [ - "C3i", - "A", - "5A", - "5B", - "10", - "11", - "15C", - "N1", - "N4", - "H1" - ] - }, - { - "stopId": 14227, - "name": { - "original": "Rúa do Conde de Torrecedeira 86" - }, - "latitude": 42.22696657, - "longitude": -8.734559706, - "lines": [ - "C3i", - "A", - "5A", - "5B", - "10", - "11", - "15C", - "N1", - "N4", - "H1" - ] - }, - { - "stopId": 14228, - "name": { - "original": "Avda. de Peinador 100" - }, - "latitude": 42.221696342, - "longitude": -8.632840997, - "lines": [ - "A" - ] - }, - { - "stopId": 14231, - "name": { - "original": "Rúa da Rabadeira 39" - }, - "latitude": 42.235542066, - "longitude": -8.652196565, - "lines": [ - "9B" - ] - }, - { - "stopId": 14232, - "name": { - "original": "Rúa da Rabadeira (fronte 33)" - }, - "latitude": 42.235317662, - "longitude": -8.652094641, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 14233, - "name": { - "original": "Rúa San Cristobo 90" - }, - "latitude": 42.241037275, - "longitude": -8.668947597, - "lines": [ - "9B", - "28" - ] - }, - { - "stopId": 14236, - "name": { - "original": "Rúa de Manuel Cominges (fronte 112)" - }, - "latitude": 42.196308523, - "longitude": -8.723526935, - "lines": [ - "12B" - ] - }, - { - "stopId": 14237, - "name": { - "original": "Rúa de Manuel Cominges 134" - }, - "latitude": 42.196119748, - "longitude": -8.723457198, - "lines": [ - "12B" - ] - }, - { - "stopId": 14238, - "name": { - "original": "Rúa da Saa do Monte 5" - }, - "latitude": 42.20458802, - "longitude": -8.714617309, - "lines": [ - "18B" - ] - }, - { - "stopId": 14240, - "name": { - "original": "Rúa das Chabarras 21" - }, - "latitude": 42.197985091, - "longitude": -8.714523201, - "lines": [ - "18B" - ] - }, - { - "stopId": 14241, - "name": { - "original": "Rúa das Chabarras 60" - }, - "latitude": 42.197842023, - "longitude": -8.71471632, - "lines": [ - "18B" - ] - }, - { - "stopId": 14242, - "name": { - "original": "Rúa das Chabarras (cruce Camiño dos Pasais)" - }, - "latitude": 42.196378259, - "longitude": -8.716979043, - "lines": [ - "18B" - ] - }, - { - "stopId": 14243, - "name": { - "original": "Rúa das Chabarras 24" - }, - "latitude": 42.196539214, - "longitude": -8.716874437, - "lines": [ - "18B" - ] - }, - { - "stopId": 14244, - "name": { - "original": "Rúa de Macal 60" - }, - "latitude": 42.198216234, - "longitude": -8.721498041, - "lines": [ - "18B", - "18H", - "27" - ] - }, - { - "stopId": 14245, - "name": { - "original": "Avda. de García Barbón 43" - }, - "latitude": 42.23691728, - "longitude": -8.716743143, - "lines": [ - "C3i", - "5B", - "10", - "16", - "17", - "N1" - ] - }, - { - "stopId": 14247, - "name": { - "original": "Camiño dos Muíños 69" - }, - "latitude": 42.200511179, - "longitude": -8.769110573, - "lines": [ - "12A" - ] - }, - { - "stopId": 14248, - "name": { - "original": "Camiño dos Muíños 74" - }, - "latitude": 42.200580723, - "longitude": -8.76911862, - "lines": [ - "12A" - ] - }, - { - "stopId": 14249, - "name": { - "original": "Avda. de Cesáreo Vázquez 5" - }, - "latitude": 42.177662554, - "longitude": -8.800157923, - "lines": [ - "12A" - ] - }, - { - "stopId": 14250, - "name": { - "original": "Avda. do Aeroporto 463" - }, - "latitude": 42.234914814, - "longitude": -8.658983411, - "lines": [ - "A", - "9B" - ] - }, - { - "stopId": 14251, - "name": { - "original": "Avda. do Aeroporto (fronte 463)" - }, - "latitude": 42.234817602, - "longitude": -8.65882027, - "lines": [ - "A", - "9B", - "27" - ] - }, - { - "stopId": 14252, - "name": { - "original": "Estrada Clara Campoamor (Instituto)" - }, - "latitude": 42.165934208, - "longitude": -8.707243001, - "lines": [ - "U1" - ] - }, - { - "stopId": 14253, - "name": { - "original": "Estrada Clara Campoamor (cruce Rúa do Padrón do Couto)" - }, - "latitude": 42.164455564, - "longitude": -8.707223843, - "lines": [ - "U1" - ] - }, - { - "stopId": 14255, - "name": { - "original": "Rúa do Pintor Colmeiro (Parque do Pintor Colmeiro)" - }, - "latitude": 42.225111918, - "longitude": -8.726733526, - "lines": [ - "16" - ] - }, - { - "stopId": 14256, - "name": { - "original": "Rúa de Zamora 89" - }, - "latitude": 42.222198901, - "longitude": -8.728317834, - "lines": [ - "16" - ] - }, - { - "stopId": 14257, - "name": { - "original": "Rúa de Zamora 71" - }, - "latitude": 42.223448271, - "longitude": -8.725547112, - "lines": [ - "16" - ] - }, - { - "stopId": 14258, - "name": { - "original": "Rúa de Zamora 51" - }, - "latitude": 42.224870416, - "longitude": -8.723632015, - "lines": [ - "16" - ] - }, - { - "stopId": 14259, - "name": { - "original": "Rúa de Zamora 31" - }, - "latitude": 42.227088982, - "longitude": -8.721545256, - "lines": [ - "16" - ] - }, - { - "stopId": 14260, - "name": { - "original": "Avda. da Gran Vía (fronte Avda. de Madrid)" - }, - "latitude": 42.228741057, - "longitude": -8.71961914, - "lines": [ - "7", - "14", - "15A", - "16", - "18A", - "18B", - "18H", - "H2" - ] - }, - { - "stopId": 14261, - "name": { - "original": "Rúa de Zamora 1" - }, - "latitude": 42.228644118, - "longitude": -8.720692314, - "lines": [ - "16" - ] - }, - { - "stopId": 14264, - "name": { - "original": "Rúa de Urzáiz - Príncipe" - }, - "latitude": 42.235873545, - "longitude": -8.720083317, - "lines": [ - "C1", - "A", - "4A", - "4C", - "5A", - "7", - "9B", - "12B", - "14", - "15B", - "15C", - "16", - "17", - "18A", - "18B", - "18H", - "24", - "28", - "N1", - "N4" - ] - }, - { - "stopId": 14267, - "name": { - "original": "Avda. da Atlántida 64" - }, - "latitude": 42.221892792, - "longitude": -8.758191526, - "lines": [ - "10", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 14268, - "name": { - "original": "Avda. da Atlántida 49" - }, - "latitude": 42.221731945, - "longitude": -8.758417175, - "lines": [ - "10", - "15B", - "15C" - ] - }, - { - "stopId": 14270, - "name": { - "original": "Estrada da Balsa 67" - }, - "latitude": 42.196619218, - "longitude": -8.743240048, - "lines": [ - "17" - ] - }, - { - "stopId": 14271, - "name": { - "original": "Estrada da Balsa 103" - }, - "latitude": 42.196050474, - "longitude": -8.745105715, - "lines": [ - "17" - ] - }, - { - "stopId": 14273, - "name": { - "original": "Rúa do Xalón 41" - }, - "latitude": 42.219274062, - "longitude": -8.656419893, - "lines": [ - "11" - ] - }, - { - "stopId": 14277, - "name": { - "original": "Avda. da Mariña Española 8" - }, - "latitude": 42.251776399, - "longitude": -8.69414009, - "lines": [ - "17" - ] - }, - { - "stopId": 14278, - "name": { - "original": "Avda. da Mariña Española 44" - }, - "latitude": 42.25430173, - "longitude": -8.692915616, - "lines": [ - "17" - ] - }, - { - "stopId": 14279, - "name": { - "original": "Riós (Rotonda)" - }, - "latitude": 42.257069093, - "longitude": -8.690786611, - "lines": [ - "17" - ] - }, - { - "stopId": 14280, - "name": { - "original": "Avda. da Mariña Española (ETEA)" - }, - "latitude": 42.254604716, - "longitude": -8.692539681, - "lines": [ - "17" - ] - }, - { - "stopId": 14281, - "name": { - "original": "Avda. da Mariña Española (Praia de Ríos)" - }, - "latitude": 42.251596707, - "longitude": -8.69420171, - "lines": [ - "17" - ] - }, - { - "stopId": 14287, - "name": { - "original": "Rúa Santa Tegra 67" - }, - "latitude": 42.25020334, - "longitude": -8.701924083, - "lines": [ - "17" - ] - }, - { - "stopId": 14288, - "name": { - "original": "Avda. de Guixar (fronte 28)" - }, - "latitude": 42.249218849, - "longitude": -8.704807605, - "lines": [ - "17" - ] - }, - { - "stopId": 14289, - "name": { - "original": "Rúa de Xulián Estévez (fronte 58)" - }, - "latitude": 42.246484972, - "longitude": -8.705864005, - "lines": [ - "17" - ] - }, - { - "stopId": 14290, - "name": { - "original": "Rúa de Xulián Estévez (fronte 18)" - }, - "latitude": 42.244107542, - "longitude": -8.706343638, - "lines": [ - "17" - ] - }, - { - "stopId": 14291, - "name": { - "original": "Avda. da Ponte (Vigo Memorial)" - }, - "latitude": 42.209935219, - "longitude": -8.671464542, - "lines": [ - "12B", - "15B", - "15C", - "U2" - ] - }, - { - "stopId": 14294, - "name": { - "original": "Avda. de Ricardo Mella 406" - }, - "latitude": 42.190684424876565, - "longitude": -8.799308812770041, - "lines": [ - "12A" - ] - }, - { - "stopId": 14295, - "name": { - "original": "Rúa de Pi i Margall 121" - }, - "latitude": 42.230436358, - "longitude": -8.731437473, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 14296, - "name": { - "original": "Praza dos Leóns (Vigozoo)" - }, - "latitude": 42.248375604, - "longitude": -8.675578666, - "lines": [ - "28" - ] - }, - { - "stopId": 14299, - "name": { - "original": "Avda. de Samil (frente Verbum)" - }, - "latitude": 42.213644883, - "longitude": -8.774567214, - "lines": [ - "C3i", - "15A", - "N1" - ] - }, - { - "stopId": 14300, - "name": { - "original": "Avda. da Florida 30" - }, - "latitude": 42.217907548, - "longitude": -8.73707436, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 14301, - "name": { - "original": "Avda. da Florida 47" - }, - "latitude": 42.218257459, - "longitude": -8.736328798, - "lines": [ - "5A", - "11", - "29" - ] - }, - { - "stopId": 14302, - "name": { - "original": "Estrada Vella de Madrid 7" - }, - "latitude": 42.214542094, - "longitude": -8.696431619, - "lines": [ - "12A", - "12B", - "13", - "H3" - ] - }, - { - "stopId": 14304, - "name": { - "original": "Estrada Vella de Madrid 145" - }, - "latitude": 42.221313975, - "longitude": -8.681944471, - "lines": [ - "12A", - "12B", - "13", - "31" - ] - }, - { - "stopId": 14307, - "name": { - "original": "Rúa do Pintor Colmeiro 11" - }, - "latitude": 42.224464416, - "longitude": -8.727967343, - "lines": [ - "16" - ] - }, - { - "stopId": 14308, - "name": { - "original": "Camiño do Pinal 6" - }, - "latitude": 42.16328558, - "longitude": -8.716707662, - "lines": [ - "7" - ] - }, - { - "stopId": 14309, - "name": { - "original": "Camiño do Pinal 28" - }, - "latitude": 42.161067029, - "longitude": -8.716468628, - "lines": [ - "7" - ] - }, - { - "stopId": 14310, - "name": { - "original": "Camiño do Pinal (fronte 57)" - }, - "latitude": 42.159564137, - "longitude": -8.718295559, - "lines": [ - "7" - ] - }, - { - "stopId": 14311, - "name": { - "original": "Estrada de Valadares 505" - }, - "latitude": 42.162720337, - "longitude": -8.718900908, - "lines": [ - "7" - ] - }, - { - "stopId": 14314, - "name": { - "original": "Rúa das Mantelas (cruce Avda. da Gran Vía)" - }, - "latitude": 42.227212568, - "longitude": -8.720183032, - "lines": [ - "18A" - ] - }, - { - "stopId": 14315, - "name": { - "original": "Rúa das Mantelas 92" - }, - "latitude": 42.22393338, - "longitude": -8.716924148, - "lines": [ - "18A" - ] - }, - { - "stopId": 14317, - "name": { - "original": "Rúa da Salgueira Entrada (Igrexa)" - }, - "latitude": 42.222723933, - "longitude": -8.719150283, - "lines": [ - "18A" - ] - }, - { - "stopId": 14318, - "name": { - "original": "Rúa da Salguera Entrada (fronte 5)" - }, - "latitude": 42.222591256, - "longitude": -8.717753486, - "lines": [ - "18A" - ] - }, - { - "stopId": 14319, - "name": { - "original": "Rúa das Coutadas (Fonte)" - }, - "latitude": 42.221002214, - "longitude": -8.72027208, - "lines": [ - "18A" - ] - }, - { - "stopId": 14320, - "name": { - "original": "Rúa do Miradoiro (Rotonda Centro Comercial)" - }, - "latitude": 42.220799025, - "longitude": -8.723345356, - "lines": [ - "18A" - ] - }, - { - "stopId": 14321, - "name": { - "original": "Camiño do Freixeiro 74" - }, - "latitude": 42.218131641, - "longitude": -8.723120057, - "lines": [ - "18A" - ] - }, - { - "stopId": 14322, - "name": { - "original": "Rúa da Fonte Santa 4" - }, - "latitude": 42.217813814, - "longitude": -8.721352482, - "lines": [ - "18A" - ] - }, - { - "stopId": 14323, - "name": { - "original": "Rúa Finca dos Aires (cruce Rúa da Fonte Santa)" - }, - "latitude": 42.217059742, - "longitude": -8.720340235, - "lines": [ - "18A" - ] - }, - { - "stopId": 14324, - "name": { - "original": "Rúa Finca dos Aires (Urbanización)" - }, - "latitude": 42.217256401, - "longitude": -8.720101519, - "lines": [ - "18A" - ] - }, - { - "stopId": 14325, - "name": { - "original": "Rúa da Fonte Santa (fronte 4)" - }, - "latitude": 42.217848286, - "longitude": -8.7214811, - "lines": [ - "18A" - ] - }, - { - "stopId": 14326, - "name": { - "original": "Baixada á Ponte Nova 61" - }, - "latitude": 42.218038279, - "longitude": -8.722489738, - "lines": [ - "18A" - ] - }, - { - "stopId": 14328, - "name": { - "original": "Citroën - PSA" - }, - "latitude": 42.208988415, - "longitude": -8.746151897, - "lines": [ - "LZH", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 14329, - "name": { - "original": "Citroën (Puerta Principal)" - }, - "latitude": 42.210124372, - "longitude": -8.741139991, - "lines": [ - "LZH", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 14330, - "name": { - "original": "Subida ás Chans (fronte cruce Rúa Senra)" - }, - "latitude": 42.198072667, - "longitude": -8.682624653, - "lines": [ - "14" - ] - }, - { - "stopId": 14331, - "name": { - "original": "Rúa de Álvaro Cunqueiro 30" - }, - "latitude": 42.223769828, - "longitude": -8.728938728, - "lines": [ - "4A", - "4C", - "5A", - "5B", - "11", - "12A", - "12B", - "17", - "27", - "N1", - "LZH" - ] - }, - { - "stopId": 14333, - "name": { - "original": "Rúa de Cánovas del Castillo 18" - }, - "latitude": 42.240189011, - "longitude": -8.726765331, - "lines": [ - "C1", - "C3d", - "A", - "5A", - "9B", - "10", - "15B", - "15C", - "28", - "N4" - ] - }, - { - "stopId": 14335, - "name": { - "original": "Camiño do Arieiro (Residencia de Maiores)" - }, - "latitude": 42.212692269, - "longitude": -8.675661599, - "lines": [ - "31" - ] - }, - { - "stopId": 14336, - "name": { - "original": "Rúa das Teixugueiras 8" - }, - "latitude": 42.21447626, - "longitude": -8.75600551, - "lines": [ - "13", - "15A" - ] - }, - { - "stopId": 14337, - "name": { - "original": "Rúa do Limpiño (Rotonda Rúa Teixugueiras)" - }, - "latitude": 42.213080218, - "longitude": -8.754660224, - "lines": [ - "5A", - "5B", - "13", - "15A", - "15B", - "N4", - "U1", - "H", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 14345, - "name": { - "original": "Rúa do Areiro 49" - }, - "latitude": 42.237269816, - "longitude": -8.685138009, - "lines": [ - "28" - ] - }, - { - "stopId": 14346, - "name": { - "original": "Rúa do Areiro 52" - }, - "latitude": 42.237287688, - "longitude": -8.685019992, - "lines": [ - "28" - ] - }, - { - "stopId": 14347, - "name": { - "original": "Rúa do Areiro (cruce Salcides)" - }, - "latitude": 42.23913765, - "longitude": -8.683873934, - "lines": [ - "28" - ] - }, - { - "stopId": 14348, - "name": { - "original": "Rúa do Areiro 76" - }, - "latitude": 42.238950988, - "longitude": -8.683793467, - "lines": [ - "28" - ] - }, - { - "stopId": 14349, - "name": { - "original": "Rúa do Areiro (Campo de Fútbol)" - }, - "latitude": 42.244717312, - "longitude": -8.678473607, - "lines": [ - "28" - ] - }, - { - "stopId": 14350, - "name": { - "original": "Rúa do Areiro (fronte Campo de Fútbol)" - }, - "latitude": 42.244849353, - "longitude": -8.678366319, - "lines": [ - "28" - ] - }, - { - "stopId": 14353, - "name": { - "original": "Praza dos Leóns (fronte Vigozoo)" - }, - "latitude": 42.248151648, - "longitude": -8.675976097, - "lines": [ - "28" - ] - }, - { - "stopId": 14354, - "name": { - "original": "Avda. de Ramón Nieto (fronte Igrexa)" - }, - "latitude": 42.225911433, - "longitude": -8.675526243, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 14355, - "name": { - "original": "Avda. de Ramón Nieto 409" - }, - "latitude": 42.226638363, - "longitude": -8.676135104, - "lines": [ - "11", - "15A", - "15B", - "15C", - "31", - "H3" - ] - }, - { - "stopId": 14356, - "name": { - "original": "Avda. de Ricardo Mella 314" - }, - "latitude": 42.192009114, - "longitude": -8.783993123, - "lines": [ - "12A" - ] - }, - { - "stopId": 14357, - "name": { - "original": "Avda. de Ricardo Mella (cruce Camiño do Río)" - }, - "latitude": 42.191796473, - "longitude": -8.784014088, - "lines": [ - "12A" - ] - }, - { - "stopId": 14358, - "name": { - "original": "Rúa das Teixugueiras 28" - }, - "latitude": 42.209054557, - "longitude": -8.75715865, - "lines": [ - "5A", - "5B", - "13", - "N4" - ] - }, - { - "stopId": 14359, - "name": { - "original": "Rúa das Teixugueiras 16-Portal 2" - }, - "latitude": 42.212235738, - "longitude": -8.755011746, - "lines": [ - "5A", - "5B", - "13", - "N4" - ] - }, - { - "stopId": 14360, - "name": { - "original": "Rúa das Teixugueiras 19-Portal 5" - }, - "latitude": 42.208965857, - "longitude": -8.757020567, - "lines": [ - "5A", - "5B", - "13", - "N4", - "U1", - "H", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 14361, - "name": { - "original": "Rúa das Teixugueiras 17" - }, - "latitude": 42.209770472, - "longitude": -8.755295907, - "lines": [ - "5A", - "5B", - "13", - "15A", - "N4", - "U1", - "H", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 14362, - "name": { - "original": "Avda. de Samil 101" - }, - "latitude": 42.202937872, - "longitude": -8.776830486, - "lines": [ - "C3d", - "4C", - "10" - ] - }, - { - "stopId": 14364, - "name": { - "original": "Estrada das Plantas (fronte Cidade Deportiva)" - }, - "latitude": 42.175757186, - "longitude": -8.671074371, - "lines": [ - "15C" - ] - }, - { - "stopId": 14365, - "name": { - "original": "Estrada das Plantas (Viveiros)" - }, - "latitude": 42.181650197, - "longitude": -8.667515723, - "lines": [ - "15C" - ] - }, - { - "stopId": 14372, - "name": { - "original": "Barrio da Salgueira 22" - }, - "latitude": 42.221887526, - "longitude": -8.720011371, - "lines": [ - "18A" - ] - }, - { - "stopId": 14376, - "name": { - "original": "Rúa da Pateira 20" - }, - "latitude": 42.226612651, - "longitude": -8.699658408, - "lines": [ - "25" - ] - }, - { - "stopId": 14377, - "name": { - "original": "Rúa da Pateira 5" - }, - "latitude": 42.226582661, - "longitude": -8.700385762, - "lines": [ - "25" - ] - }, - { - "stopId": 14378, - "name": { - "original": "Rúa Molais 83" - }, - "latitude": 42.22396201, - "longitude": -8.653340726, - "lines": [ - "25" - ] - }, - { - "stopId": 14381, - "name": { - "original": "Rúa do Abade Juan de Bastos 6" - }, - "latitude": 42.195647685, - "longitude": -8.728974153, - "lines": [ - "17" - ] - }, - { - "stopId": 14383, - "name": { - "original": "Estrada Clara Campoamor (cruce Estrada do Portal)" - }, - "latitude": 42.174718265, - "longitude": -8.713684656, - "lines": [ - "U1" - ] - }, - { - "stopId": 14384, - "name": { - "original": "Estrada Clara Campoamor (Parque Tecnolóxico)" - }, - "latitude": 42.175073486, - "longitude": -8.713494654, - "lines": [ - "U1" - ] - }, - { - "stopId": 14385, - "name": { - "original": "Rúa da Vista do Mar 45" - }, - "latitude": 42.240712912, - "longitude": -8.6919418, - "lines": [ - "4A", - "24" - ] - }, - { - "stopId": 14386, - "name": { - "original": "Rúa da Vista do Mar (Embalse)" - }, - "latitude": 42.238020208, - "longitude": -8.691543884, - "lines": [ - "4A", - "24" - ] - }, - { - "stopId": 14387, - "name": { - "original": "Rúa da Vista do Mar 1" - }, - "latitude": 42.237167043, - "longitude": -8.693243792, - "lines": [ - "4A", - "24" - ] - }, - { - "stopId": 14388, - "name": { - "original": "Rúa das Teixugueiras 11" - }, - "latitude": 42.211610124, - "longitude": -8.754550253, - "lines": [ - "5A", - "5B", - "13", - "15A", - "N4", - "U1", - "H", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 14389, - "name": { - "original": "Rúa das Teixugueiras 22" - }, - "latitude": 42.210212603, - "longitude": -8.755079989, - "lines": [ - "5A", - "5B", - "13", - "N4" - ] - }, - { - "stopId": 14390, - "name": { - "original": "Rúa do Salgueiro (cruce Camiño Sanatorio)" - }, - "latitude": 42.241570883, - "longitude": -8.655380719, - "lines": [ - "9B", - "28" - ] - }, - { - "stopId": 14391, - "name": { - "original": "Rúa do Salgueiro (fronte 38)" - }, - "latitude": 42.241652296, - "longitude": -8.655302935, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 14392, - "name": { - "original": "Rúa da Pedra Seixa (Colexio)" - }, - "latitude": 42.209458591, - "longitude": -8.760561083, - "lines": [ - "5A" - ] - }, - { - "stopId": 14393, - "name": { - "original": "Rúa da Pedra Seixa (fronte Colexio)" - }, - "latitude": 42.209568936, - "longitude": -8.760777001, - "lines": [ - "5A" - ] - }, - { - "stopId": 14395, - "name": { - "original": "Estrada de Madrid 217" - }, - "latitude": 42.215601037, - "longitude": -8.675477665, - "lines": [ - "12B", - "15B", - "15C" - ] - }, - { - "stopId": 14396, - "name": { - "original": "Avda. de García Barbón 106" - }, - "latitude": 42.239965365, - "longitude": -8.708024282, - "lines": [ - "C3d", - "5B", - "10", - "17", - "31", - "H2", - "H3", - "PSA 1" - ] - }, - { - "stopId": 14397, - "name": { - "original": "Avda. de García Barbón (fronte 104)" - }, - "latitude": 42.23973713, - "longitude": -8.708397682, - "lines": [ - "C3i", - "5B", - "10", - "17", - "N1", - "H3" - ] - }, - { - "stopId": 14398, - "name": { - "original": "Avda. da Gran Vía 116" - }, - "latitude": 42.22406594, - "longitude": -8.723691036, - "lines": [ - "C3d", - "13", - "15A", - "23", - "29", - "H2", - "PSA 1" - ] - }, - { - "stopId": 14401, - "name": { - "original": "Rúa de San Paio (cruce Camiño Barroca)" - }, - "latitude": 42.21072167, - "longitude": -8.76212542, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 14402, - "name": { - "original": "Rúa de San Paio 111" - }, - "latitude": 42.210791203, - "longitude": -8.761940347, - "lines": [ - "4A", - "12A" - ] - }, - { - "stopId": 14403, - "name": { - "original": "Rúa de Pedro Alvarado (cruce Camiño das Maceiras)" - }, - "latitude": 42.25049654, - "longitude": -8.698390035, - "lines": [ - "17" - ] - }, - { - "stopId": 14404, - "name": { - "original": "Rúa do Doutor Corbal 58" - }, - "latitude": 42.251785642, - "longitude": -8.696871994, - "lines": [ - "17" - ] - }, - { - "stopId": 14406, - "name": { - "original": "Rúa de Enrique Lorenzo 32" - }, - "latitude": 42.249462772, - "longitude": -8.699772952, - "lines": [ - "17" - ] - }, - { - "stopId": 14408, - "name": { - "original": "Rúa de Pedro Alvarado 5" - }, - "latitude": 42.248885006, - "longitude": -8.698128758, - "lines": [ - "17" - ] - }, - { - "stopId": 14409, - "name": { - "original": "Estrada das Plantas (fronte cruce Avda. do Rebullón)" - }, - "latitude": 42.204188441, - "longitude": -8.670257126, - "lines": [ - "15B", - "15C" - ] - }, - { - "stopId": 14410, - "name": { - "original": "Estrada das Plantas (cruce Avda. do Rebullón)" - }, - "latitude": 42.204639457, - "longitude": -8.670329545, - "lines": [ - "15C" - ] - }, - { - "stopId": 14411, - "name": { - "original": "Rúa de Xeme 1" - }, - "latitude": 42.205174543, - "longitude": -8.698209134, - "lines": [ - "14" - ] - }, - { - "stopId": 14412, - "name": { - "original": "Rúa de Xeme 6" - }, - "latitude": 42.20497586, - "longitude": -8.697957006, - "lines": [ - "14" - ] - }, - { - "stopId": 14413, - "name": { - "original": "Estrada da Garrida (cruce Camiño Fabas)" - }, - "latitude": 42.173955568, - "longitude": -8.703050076, - "lines": [ - "7" - ] - }, - { - "stopId": 14414, - "name": { - "original": "Avda. de Santa Mariña 40" - }, - "latitude": 42.221587211, - "longitude": -8.665078444, - "lines": [ - "11" - ] - }, - { - "stopId": 14415, - "name": { - "original": "Avda. de Santa Mariña (antes 49)" - }, - "latitude": 42.221557416, - "longitude": -8.665381534, - "lines": [ - "11" - ] - }, - { - "stopId": 14416, - "name": { - "original": "Rúa de Severino Cobas 118" - }, - "latitude": 42.225468623, - "longitude": -8.691491081, - "lines": [ - "25" - ] - }, - { - "stopId": 14419, - "name": { - "original": "Estrada de Bembrive (cruce Camiño dos Rapadouros)" - }, - "latitude": 42.201138734, - "longitude": -8.688585073, - "lines": [ - "6" - ] - }, - { - "stopId": 14420, - "name": { - "original": "Estrada de Bembrive 318" - }, - "latitude": 42.201419233, - "longitude": -8.688526069, - "lines": [ - "6" - ] - }, - { - "stopId": 14421, - "name": { - "original": "Estrada das Prantas (fronte Campo de Béisbol)" - }, - "latitude": 42.186683264, - "longitude": -8.669320703, - "lines": [ - "15C" - ] - }, - { - "stopId": 14422, - "name": { - "original": "Estrada das Plantas (Campo de Béisbol)" - }, - "latitude": 42.18695315, - "longitude": -8.669514066, - "lines": [ - "15C" - ] - }, - { - "stopId": 14425, - "name": { - "original": "Avda. do Alcalde Gregorio Espino 2" - }, - "latitude": 42.232253792, - "longitude": -8.707208575, - "lines": [ - "31" - ] - }, - { - "stopId": 14475, - "name": { - "original": "Rúa de Barcelona 78" - }, - "latitude": 42.222992354, - "longitude": -8.728300382, - "lines": [ - "C1" - ] - }, - { - "stopId": 14890, - "name": { - "original": "Rúa das Teixugueiras 25" - }, - "latitude": 42.207545331, - "longitude": -8.758718406, - "lines": [ - "5B", - "13", - "N4", - "U1", - "H", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 14892, - "name": { - "original": "Rúa do Conde de Torrecedeira 123" - }, - "latitude": 42.224929414, - "longitude": -8.735414067, - "lines": [ - "C1", - "C3d", - "A", - "9B", - "15C", - "N4", - "H1" - ] - }, - { - "stopId": 14893, - "name": { - "original": "Rúa de Manuel Costas Bastos 26" - }, - "latitude": 42.243157956, - "longitude": -8.666962176, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 14894, - "name": { - "original": "Avda. do Alcalde Portanet 8" - }, - "latitude": 42.211736934, - "longitude": -8.733337505, - "lines": [ - "7", - "12B", - "17", - "H1" - ] - }, - { - "stopId": 14895, - "name": { - "original": "Rúa do Areiro (cruce Camiño das Laxes)" - }, - "latitude": 42.241392275, - "longitude": -8.681203235, - "lines": [ - "28" - ] - }, - { - "stopId": 14896, - "name": { - "original": "Rúa do Areiro 93" - }, - "latitude": 42.241385532, - "longitude": -8.681400937, - "lines": [ - "28" - ] - }, - { - "stopId": 14897, - "name": { - "original": "Camiño do Arieiro (fronte 13)" - }, - "latitude": 42.213239161, - "longitude": -8.67854147, - "lines": [ - "31" - ] - }, - { - "stopId": 14898, - "name": { - "original": "Camiño do Arieiro 13" - }, - "latitude": 42.213239161, - "longitude": -8.678369808, - "lines": [ - "31" - ] - }, - { - "stopId": 14899, - "name": { - "original": "Rúa de López Mora 33" - }, - "latitude": 42.225485719, - "longitude": -8.730501434, - "lines": [ - "5A", - "5B", - "12A" - ] - }, - { - "stopId": 14900, - "name": { - "original": "Rúa de Martín Echegaray 24" - }, - "latitude": 42.217196117, - "longitude": -8.743726669, - "lines": [ - "23", - "N4" - ] - }, - { - "stopId": 14901, - "name": { - "original": "Avda. de Castelao 1" - }, - "latitude": 42.220211003, - "longitude": -8.734183023, - "lines": [ - "C3i", - "10", - "11", - "15A", - "U1" - ] - }, - { - "stopId": 14903, - "name": { - "original": "Rúa de Pi i Margall 66" - }, - "latitude": 42.23174719, - "longitude": -8.731081308, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 14905, - "name": { - "original": "Camiño da Devesa (Cemiterio)" - }, - "latitude": 42.249981353, - "longitude": -8.667186504, - "lines": [ - "9B" - ] - }, - { - "stopId": 14906, - "name": { - "original": "Rúa da Rabadeira 6" - }, - "latitude": 42.232479787, - "longitude": -8.654890792, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 14907, - "name": { - "original": "Rúa da Rabadeira 24" - }, - "latitude": 42.233655479, - "longitude": -8.653300242, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 14908, - "name": { - "original": "Rúa da Rabadeira 17" - }, - "latitude": 42.233829075, - "longitude": -8.653458259, - "lines": [ - "9B" - ] - }, - { - "stopId": 14909, - "name": { - "original": "Rúa da Rabadeira 11" - }, - "latitude": 42.232663198, - "longitude": -8.655097059, - "lines": [ - "9B" - ] - }, - { - "stopId": 14910, - "name": { - "original": "Estrada do Marco 4" - }, - "latitude": 42.21025095, - "longitude": -8.704036986, - "lines": [ - "18A", - "18B", - "H3" - ] - }, - { - "stopId": 14911, - "name": { - "original": "Estrada do Marco 16" - }, - "latitude": 42.208830737, - "longitude": -8.706971174, - "lines": [ - "18A", - "18B", - "H3" - ] - }, - { - "stopId": 15001, - "name": { - "original": "Rúa Regueiro do Forno (Vial C) Centro de Servicios" - }, - "latitude": 42.176053629, - "longitude": -8.709460132, - "lines": [ - "PTL" - ] - }, - { - "stopId": 15002, - "name": { - "original": "PTL 2" - }, - "latitude": 42.177194637, - "longitude": -8.707850807, - "lines": [ - "PTL" - ] - }, - { - "stopId": 15003, - "name": { - "original": "PTL 3" - }, - "latitude": 42.178124939, - "longitude": -8.706606262, - "lines": [ - "PTL" - ] - }, - { - "stopId": 15004, - "name": { - "original": "PTL 4" - }, - "latitude": 42.176503017, - "longitude": -8.710007303, - "lines": [ - "PTL" - ] - }, - { - "stopId": 20009, - "name": { - "original": "Estrada Herville 16" - }, - "latitude": 42.154843231, - "longitude": -8.67357438, - "lines": [ - "7" - ] - }, - { - "stopId": 20010, - "name": { - "original": "Avda. de Balaídos 69" - }, - "latitude": 42.212824845, - "longitude": -8.737161077, - "lines": [ - "16", - "23", - "H" - ] - }, - { - "stopId": 20011, - "name": { - "original": "Avda. de Balaídos 11" - }, - "latitude": 42.213089061, - "longitude": -8.733392573, - "lines": [ - "16", - "23", - "H" - ] - }, - { - "stopId": 20012, - "name": { - "original": "Avda. de Castrelos 33" - }, - "latitude": 42.215888032, - "longitude": -8.732331627, - "lines": [ - "A", - "16", - "23", - "27", - "H2" - ] - }, - { - "stopId": 20013, - "name": { - "original": "Avda. de Castrelos 116" - }, - "latitude": 42.215905917, - "longitude": -8.732471102, - "lines": [ - "7", - "12B", - "17", - "27", - "H2", - "PTL" - ] - }, - { - "stopId": 20018, - "name": { - "original": "Estrada Herville 70" - }, - "latitude": 42.151451604, - "longitude": -8.673803367, - "lines": [ - "7" - ] - }, - { - "stopId": 20019, - "name": { - "original": "Subida aos Padróns 165" - }, - "latitude": 42.149222193, - "longitude": -8.679363987, - "lines": [ - "7" - ] - }, - { - "stopId": 20020, - "name": { - "original": "Subida aos Padróns (cruce Parque Forestal)" - }, - "latitude": 42.151606055, - "longitude": -8.679299082, - "lines": [ - "7" - ] - }, - { - "stopId": 20021, - "name": { - "original": "Subida aos Padróns (fronte 34)" - }, - "latitude": 42.152770176, - "longitude": -8.686251828, - "lines": [ - "7" - ] - }, - { - "stopId": 20022, - "name": { - "original": "Rúa da Vía Norte (Hospital)" - }, - "latitude": 42.234622237, - "longitude": -8.707758443, - "lines": [ - "24" - ] - }, - { - "stopId": 20023, - "name": { - "original": "Rúa da Vía Norte - Est. Intermodal - C.C." - }, - "latitude": 42.234062973, - "longitude": -8.712195759, - "lines": [ - "24" - ] - }, - { - "stopId": 20024, - "name": { - "original": "Rúa das Teixugueiras 34" - }, - "latitude": 42.207634066, - "longitude": -8.758920861, - "lines": [ - "5B", - "13", - "N4" - ] - }, - { - "stopId": 20025, - "name": { - "original": "Rúa das Teixugueiras 38" - }, - "latitude": 42.206553268, - "longitude": -8.760122491, - "lines": [ - "5B", - "13", - "N4" - ] - }, - { - "stopId": 20026, - "name": { - "original": "Rúa das Teixugueiras 29" - }, - "latitude": 42.206488366, - "longitude": -8.759906624, - "lines": [ - "5B", - "13", - "N4", - "U1", - "H", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 20027, - "name": { - "original": "Avda. de Castelao 64" - }, - "latitude": 42.217691983, - "longitude": -8.749585877, - "lines": [ - "C3d", - "4A", - "4C", - "5B", - "10", - "12A", - "13", - "15A", - "N4", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 20029, - "name": { - "original": "Subida á Madroa (fronte Campo Fútbol)" - }, - "latitude": 42.245921506, - "longitude": -8.673014474, - "lines": [ - "9B", - "28" - ] - }, - { - "stopId": 20030, - "name": { - "original": "Subida á Madroa (Campo Fútbol)" - }, - "latitude": 42.247859379, - "longitude": -8.674363625, - "lines": [ - "9B", - "28" - ] - }, - { - "stopId": 20041, - "name": { - "original": "Rúa da Cabalaría 91" - }, - "latitude": 42.233622103, - "longitude": -8.689209566, - "lines": [ - "27", - "28" - ] - }, - { - "stopId": 20042, - "name": { - "original": "Rúa da Cabalaría 148" - }, - "latitude": 42.233723398, - "longitude": -8.689094231, - "lines": [ - "28" - ] - }, - { - "stopId": 20043, - "name": { - "original": "Rúa do Areiro 20" - }, - "latitude": 42.236036786, - "longitude": -8.686656768, - "lines": [ - "28" - ] - }, - { - "stopId": 20044, - "name": { - "original": "Rúa de Martín Echegaray 7" - }, - "latitude": 42.215220874, - "longitude": -8.742680967, - "lines": [ - "23", - "N4" - ] - }, - { - "stopId": 20045, - "name": { - "original": "Rúa de Xestoso 4" - }, - "latitude": 42.200532989, - "longitude": -8.674075447, - "lines": [ - "15B" - ] - }, - { - "stopId": 20046, - "name": { - "original": "Rúa de Xestoso 12" - }, - "latitude": 42.201968444, - "longitude": -8.67477879, - "lines": [ - "15B" - ] - }, - { - "stopId": 20047, - "name": { - "original": "Rúa do Xestoso 72" - }, - "latitude": 42.204330306, - "longitude": -8.674670483, - "lines": [ - "15B" - ] - }, - { - "stopId": 20048, - "name": { - "original": "Avda. de Cesáreo Vázquez (cruce Camiño Amariz Lourenzo)" - }, - "latitude": 42.182684406, - "longitude": -8.802402364, - "lines": [ - "11", - "12A" - ] - }, - { - "stopId": 20049, - "name": { - "original": "Avda. de Cesáreo Vázquez 62" - }, - "latitude": 42.18238342, - "longitude": -8.802126069, - "lines": [ - "11" - ] - }, - { - "stopId": 20050, - "name": { - "original": "Rúa de Severino Cobas 186" - }, - "latitude": 42.225550059, - "longitude": -8.686684563, - "lines": [ - "25" - ] - }, - { - "stopId": 20051, - "name": { - "original": "Rúa de Severino Cobas 89" - }, - "latitude": 42.225652904, - "longitude": -8.686624017, - "lines": [ - "25" - ] - }, - { - "stopId": 20052, - "name": { - "original": "Rúa de Aragón 21" - }, - "latitude": 42.232748414, - "longitude": -8.702539655, - "lines": [ - "4A", - "H3" - ] - }, - { - "stopId": 20053, - "name": { - "original": "Rúa de Ángel de Lema (cruce Paraixal)" - }, - "latitude": 42.248962858, - "longitude": -8.688272303, - "lines": [ - "C3i", - "10" - ] - }, - { - "stopId": 20054, - "name": { - "original": "Rúa de Ángel de Lema 33" - }, - "latitude": 42.248897377, - "longitude": -8.689150714, - "lines": [ - "C3d", - "10" - ] - }, - { - "stopId": 20057, - "name": { - "original": "Estación Ferrocarril Guixar" - }, - "latitude": 42.238843911, - "longitude": -8.713008504, - "lines": [ - "A", - "5B", - "16", - "24" - ] - }, - { - "stopId": 20058, - "name": { - "original": "Rúa do Canceleiro 6" - }, - "latitude": 42.238435471, - "longitude": -8.714413687, - "lines": [ - "5B", - "16" - ] - }, - { - "stopId": 20059, - "name": { - "original": "Rúa de Manuel Álvarez (fronte 10)" - }, - "latitude": 42.222745522, - "longitude": -8.677932515, - "lines": [ - "25", - "31", - "H3" - ] - }, - { - "stopId": 20060, - "name": { - "original": "Rúa de Manuel Álvarez 10" - }, - "latitude": 42.22282586, - "longitude": -8.678077606, - "lines": [ - "25", - "31", - "H3" - ] - }, - { - "stopId": 20061, - "name": { - "original": "Rúa de Martín Echegaray (Colexio)" - }, - "latitude": 42.217568173, - "longitude": -8.744018511, - "lines": [ - "23", - "N4" - ] - }, - { - "stopId": 20062, - "name": { - "original": "Avda. de Beiramar 1" - }, - "latitude": 42.236143706, - "longitude": -8.73180718, - "lines": [ - "10", - "15B" - ] - }, - { - "stopId": 20071, - "name": { - "original": "Rúa de Xestoso (fronte 105)" - }, - "latitude": 42.205511653, - "longitude": -8.672824803, - "lines": [ - "15B" - ] - }, - { - "stopId": 20072, - "name": { - "original": "Camiño do Pouso" - }, - "latitude": 42.196643694, - "longitude": -8.671663218, - "lines": [ - "15B" - ] - }, - { - "stopId": 20075, - "name": { - "original": "Avda. de Castelao 65" - }, - "latitude": 42.218011215, - "longitude": -8.745369728, - "lines": [ - "C3i", - "4A", - "4C", - "10", - "11", - "12A", - "15A", - "N1", - "N4", - "U1" - ] - }, - { - "stopId": 20076, - "name": { - "original": "Avda. de Castelao 25" - }, - "latitude": 42.21901679, - "longitude": -8.739919147, - "lines": [ - "C3i", - "4A", - "4C", - "10", - "11", - "12A", - "15A", - "N1", - "U1" - ] - }, - { - "stopId": 20077, - "name": { - "original": "Avda. de Castelao 40" - }, - "latitude": 42.219259727, - "longitude": -8.739809435, - "lines": [ - "C3d", - "4A", - "4C", - "5B", - "10", - "12A", - "13", - "15A", - "PSA 1", - "PSA 4" - ] - }, - { - "stopId": 20078, - "name": { - "original": "Avda. das Camelias 3" - }, - "latitude": 42.233341329, - "longitude": -8.728967219, - "lines": [ - "4A", - "4C", - "11", - "12B", - "17", - "27", - "N1" - ] - }, - { - "stopId": 20079, - "name": { - "original": "Avda. das Camelias 8" - }, - "latitude": 42.23341294, - "longitude": -8.729045156, - "lines": [ - "4A", - "4C", - "7", - "12B", - "17", - "27", - "PSA 4" - ] - }, - { - "stopId": 20080, - "name": { - "original": "Avda. de Santa Mariña 68" - }, - "latitude": 42.221674556, - "longitude": -8.660937347, - "lines": [ - "11" - ] - }, - { - "stopId": 20081, - "name": { - "original": "Subida aos Padróns (cruce Camiño da Chan da Rabicha)" - }, - "latitude": 42.151852858, - "longitude": -8.684956786, - "lines": [ - "7" - ] - }, - { - "stopId": 20082, - "name": { - "original": "Avda. de Santa Mariña (fronte 66)" - }, - "latitude": 42.221758032, - "longitude": -8.661135597, - "lines": [ - "11" - ] - }, - { - "stopId": 20083, - "name": { - "original": "Rúa Castañal 6" - }, - "latitude": 42.188074669, - "longitude": -8.701928367, - "lines": [ - "27" - ] - }, - { - "stopId": 20084, - "name": { - "original": "Rúa Castañal 26" - }, - "latitude": 42.18711079, - "longitude": -8.699519743, - "lines": [ - "27" - ] - }, - { - "stopId": 20085, - "name": { - "original": "Rúa Castañal (cruce Camiño das Presas)" - }, - "latitude": 42.185852445, - "longitude": -8.696410892, - "lines": [ - "27" - ] - }, - { - "stopId": 20086, - "name": { - "original": "Estrada dos Seixiños 67" - }, - "latitude": 42.190645281, - "longitude": -8.696150583, - "lines": [ - "27" - ] - }, - { - "stopId": 20087, - "name": { - "original": "Estrada dos Seixiños 23" - }, - "latitude": 42.194639373, - "longitude": -8.696795357, - "lines": [ - "27" - ] - }, - { - "stopId": 20089, - "name": { - "original": "Porriño - Padre Seixas ©" - }, - "latitude": 42.213044566, - "longitude": -8.751396835, - "lines": [ - "16" - ] - }, - { - "stopId": 20091, - "name": { - "original": "Camiño da Miragaia 11-13" - }, - "latitude": 42.238164803, - "longitude": -8.711212761, - "lines": [ - "A", - "5B", - "16", - "24" - ] - }, - { - "stopId": 20094, - "name": { - "original": "Rúa das Mantelas (fronte 63)" - }, - "latitude": 42.22518736, - "longitude": -8.717399288, - "lines": [ - "18A" - ] - }, - { - "stopId": 20095, - "name": { - "original": "Estrada Vella de Madrid 107A" - }, - "latitude": 42.219212419, - "longitude": -8.685836356, - "lines": [ - "12A", - "12B", - "13", - "H3" - ] - }, - { - "stopId": 20096, - "name": { - "original": "Estrada Vella de Madrid (fronte 107A)" - }, - "latitude": 42.219128991, - "longitude": -8.685753208, - "lines": [ - "12A", - "12B", - "13", - "U2", - "H3" - ] - }, - { - "stopId": 20099, - "name": { - "original": "Rúa de Camilo Veiga 48" - }, - "latitude": 42.222390674, - "longitude": -8.752507356, - "lines": [ - "C3i", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 20100, - "name": { - "original": "Rúa de Camilo Veiga 6" - }, - "latitude": 42.223195763, - "longitude": -8.749650702, - "lines": [ - "C3i", - "15B", - "15C", - "N1" - ] - }, - { - "stopId": 20102, - "name": { - "original": "H. A. Cunqueiro (Porta Principal)" - }, - "latitude": 42.191034002, - "longitude": -8.714303116, - "lines": [ - "6", - "12B", - "18H", - "27", - "H1", - "H2", - "H3", - "H" - ] - }, - { - "stopId": 20103, - "name": { - "original": "Avda. do Fragoso 21" - }, - "latitude": 42.218946899, - "longitude": -8.733670293, - "lines": [ - "7", - "12B", - "17", - "N4", - "H1" - ] - }, - { - "stopId": 20104, - "name": { - "original": "Rúa de Emilia Pardo Bazán 134" - }, - "latitude": 42.220938435, - "longitude": -8.709621883, - "lines": [ - "14" - ] - }, - { - "stopId": 20105, - "name": { - "original": "Rúa de Emilia Pardo Bazán 121" - }, - "latitude": 42.221232035, - "longitude": -8.709808647, - "lines": [ - "14" - ] - }, - { - "stopId": 20107, - "name": { - "original": "Estrada do Porto (Lavadero)" - }, - "latitude": 42.188244696, - "longitude": -8.703164368, - "lines": [ - "6", - "27" - ] - }, - { - "stopId": 20110, - "name": { - "original": "Rúa de Manuel Castro 10" - }, - "latitude": 42.213797254, - "longitude": -8.741472696, - "lines": [ - "23", - "N4" - ] - }, - { - "stopId": 20111, - "name": { - "original": "H. A. Cunqueiro (Hospital de Día)" - }, - "latitude": 42.187585838, - "longitude": -8.716278919, - "lines": [ - "A", - "6", - "12B", - "18H", - "27", - "H1", - "H2", - "H3", - "H" - ] - }, - { - "stopId": 20112, - "name": { - "original": "H. A. Cunqueiro (Urxencias)" - }, - "latitude": 42.188578188, - "longitude": -8.713087125, - "lines": [ - "6", - "12B", - "18H", - "H1", - "H3", - "H" - ] - }, - { - "stopId": 20113, - "name": { - "original": "Praza de América 3 (Dirección Hospital)" - }, - "latitude": 42.220876566, - "longitude": -8.733367644, - "lines": [ - "12B", - "H1", - "H2", - "PTL" - ] - }, - { - "stopId": 20114, - "name": { - "original": "Estrada do Porto (fronte Lavadero)" - }, - "latitude": 42.18846205, - "longitude": -8.703352711, - "lines": [ - "6" - ] - }, - { - "stopId": 20115, - "name": { - "original": "Estrada do Porto (fronte cruce Rúa das Sueiras)" - }, - "latitude": 42.190100441, - "longitude": -8.705453204, - "lines": [ - "6" - ] - }, - { - "stopId": 20116, - "name": { - "original": "Estrada da Coutada-Beade 2" - }, - "latitude": 42.19202547, - "longitude": -8.705712064, - "lines": [ - "6", - "27" - ] - }, - { - "stopId": 20117, - "name": { - "original": "Estrada do Porto (cruce Camiño do Frascuelo)" - }, - "latitude": 42.191616209, - "longitude": -8.706277831, - "lines": [ - "6", - "27" - ] - }, - { - "stopId": 20118, - "name": { - "original": "Rúa Conde de Gondomar" - }, - "latitude": 42.228358488, - "longitude": -8.719490904, - "lines": [ - "H2" - ] - }, - { - "stopId": 20119, - "name": { - "original": "H. A. Cunqueiro (chegada)" - }, - "latitude": 42.190930878, - "longitude": -8.71409354, - "lines": [ - "6", - "12B", - "H3" - ] - }, - { - "stopId": 20124, - "name": { - "original": "Estrada Clara Campoamor 6" - }, - "latitude": 42.208989468, - "longitude": -8.729330619, - "lines": [ - "A", - "12B", - "U1", - "H1", - "H2", - "H", - "PTL" - ] - }, - { - "stopId": 20125, - "name": { - "original": "Estrada Clara Campoamor (fronte 6)" - }, - "latitude": 42.209126911, - "longitude": -8.729344197, - "lines": [ - "12B", - "H1", - "H2" - ] - }, - { - "stopId": 20126, - "name": { - "original": "Estrada Clara Campoamor (Rotonda HAC)" - }, - "latitude": 42.190252452, - "longitude": -8.717998617, - "lines": [ - "12B", - "18H", - "H1", - "H2" - ] - }, - { - "stopId": 20127, - "name": { - "original": "Estrada Clara Campoamor (fronte Rotonda HAC)" - }, - "latitude": 42.19007538, - "longitude": -8.718125045, - "lines": [ - "A", - "12B", - "18H", - "27", - "U1", - "H1", - "H2", - "H", - "PTL" - ] - }, - { - "stopId": 20130, - "name": { - "original": "Parque Forestal de Zamáns (Proba Andaina)" - }, - "latitude": 42.152788309, - "longitude": -8.681902684, - "lines": [ - "7" - ] - }, - { - "stopId": 20132, - "name": { - "original": "Avda. de Galicia 341" - }, - "latitude": 42.260473187, - "longitude": -8.67881466, - "lines": [ - "C3i" - ] - }, - { - "stopId": 20136, - "name": { - "original": "Avda. de E. Martínez Garrido 98" - }, - "latitude": 42.225764699, - "longitude": -8.704499864, - "lines": [ - "4C", - "23", - "31", - "N4", - "PSA 4" - ] - }, - { - "stopId": 20137, - "name": { - "original": "Camiño da Devesa (Asociación Veciños)" - }, - "latitude": 42.246563041, - "longitude": -8.669395817, - "lines": [ - "9B" - ] - }, - { - "stopId": 20139, - "name": { - "original": "Estrada Matamá Pazo (fronte 162)" - }, - "latitude": 42.199144892, - "longitude": -8.758506717, - "lines": [ - "29" - ] - }, - { - "stopId": 20141, - "name": { - "original": "Avda. da Ponte (fronte Vigo Memorial)" - }, - "latitude": 42.21057897, - "longitude": -8.671171189, - "lines": [ - "12B", - "15B", - "15C" - ] - }, - { - "stopId": 20142, - "name": { - "original": "Camiño do Outeiro 3" - }, - "latitude": 42.200738188, - "longitude": -8.714882876, - "lines": [ - "18B" - ] - }, - { - "stopId": 20143, - "name": { - "original": "Rúa das Teixugueiras (fronte 1)" - }, - "latitude": 42.215448094, - "longitude": -8.756474306, - "lines": [ - "15A" - ] - }, - { - "stopId": 20154, - "name": { - "original": "Rúa de Ramiro Pascual (fronte 127)" - }, - "latitude": 42.192089689, - "longitude": -8.709245389, - "lines": [ - "27" - ] - }, - { - "stopId": 20155, - "name": { - "original": "Rúa de Ramiro Pascual 131" - }, - "latitude": 42.19217626, - "longitude": -8.708899009, - "lines": [ - "27" - ] - }, - { - "stopId": 20156, - "name": { - "original": "Económicas e Empresariais (CUVI 2)" - }, - "latitude": 42.169602007, - "longitude": -8.680122554, - "lines": [ - "A" - ] - }, - { - "stopId": 20157, - "name": { - "original": "Estrada do Porto 88" - }, - "latitude": 42.185615419, - "longitude": -8.702424678, - "lines": [ - "6" - ] - }, - { - "stopId": 20158, - "name": { - "original": "Estrada do Porto 81" - }, - "latitude": 42.185593055, - "longitude": -8.702377974, - "lines": [ - "6" - ] - }, - { - "stopId": 20159, - "name": { - "original": "Estrada de Valadares 571" - }, - "latitude": 42.160348044, - "longitude": -8.718706355, - "lines": [ - "7" - ] - }, - { - "stopId": 20160, - "name": { - "original": "Estrada de Valadares 522" - }, - "latitude": 42.160066796, - "longitude": -8.718938239, - "lines": [ - "7" - ] - }, - { - "stopId": 20166, - "name": { - "original": "Camiño da Brea 2" - }, - "latitude": 42.202134841, - "longitude": -8.70572793, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 20167, - "name": { - "original": "Camiño da Brea 3" - }, - "latitude": 42.202095058, - "longitude": -8.705814233, - "lines": [ - "18A", - "18B" - ] - }, - { - "stopId": 20168, - "name": { - "original": "Estrada do Freixo (despois 118)" - }, - "latitude": 42.173596087, - "longitude": -8.730918928, - "lines": [ - "7" - ] - }, - { - "stopId": 20169, - "name": { - "original": "Estrada do Freixo (despois 235)" - }, - "latitude": 42.173616782, - "longitude": -8.730810863, - "lines": [ - "7" - ] - }, - { - "stopId": 20170, - "name": { - "original": "Rúa de Álvaro Cunqueiro 4" - }, - "latitude": 42.224544805, - "longitude": -8.730413561, - "lines": [ - "5A", - "5B", - "12A" - ] - }, - { - "stopId": 20171, - "name": { - "original": "Estrada Clara Campoamor (cruce Camiño da Pousa)" - }, - "latitude": 42.204380762, - "longitude": -8.726688445, - "lines": [ - "12B", - "H1", - "H2" - ] - }, - { - "stopId": 20172, - "name": { - "original": "Estrada Clara Campoamor (cruce Camiño da Nogueira)" - }, - "latitude": 42.203736336, - "longitude": -8.726617869, - "lines": [ - "A", - "12B", - "U1", - "H1", - "H2", - "H", - "PTL" - ] - }, - { - "stopId": 20173, - "name": { - "original": "Avda. de Castrelos 502" - }, - "latitude": 42.192504056, - "longitude": -8.721215121, - "lines": [ - "7", - "U1" - ] - }, - { - "stopId": 20174, - "name": { - "original": "Baixada ao Pontillón S/N" - }, - "latitude": 42.21519917, - "longitude": -8.726793773, - "lines": [ - "A" - ] - }, - { - "stopId": 20177, - "name": { - "original": "Rúa de Pizarro 16" - }, - "latitude": 42.230767817, - "longitude": -8.715105964, - "lines": [ - "C3i", - "6", - "11", - "15A", - "23", - "25", - "28" - ] - }, - { - "stopId": 20178, - "name": { - "original": "Estrada de Camposancos (cruce Camiño da Estea)" - }, - "latitude": 42.172412443, - "longitude": -8.799591567, - "lines": [ - "12A" - ] - }, - { - "stopId": 20180, - "name": { - "original": "Rúa do Reiseñor 10" - }, - "latitude": 42.229527407, - "longitude": -8.70843784, - "lines": [ - "H2" - ] - }, - { - "stopId": 20186, - "name": { - "original": "Rúa da Rabadeira 71" - }, - "latitude": 42.23755404, - "longitude": -8.651558138, - "lines": [ - "9B" - ] - }, - { - "stopId": 20187, - "name": { - "original": "Rúa da Rabadeira 46" - }, - "latitude": 42.237422128, - "longitude": -8.65153195, - "lines": [ - "9B", - "27" - ] - }, - { - "stopId": 20188, - "name": { - "original": "Rúa da Saa (fronte 43)" - }, - "latitude": 42.201670402, - "longitude": -8.708928464, - "lines": [ - "18B", - "H3" - ] - }, - { - "stopId": 20189, - "name": { - "original": "Rúa da Saa 10" - }, - "latitude": 42.201625853, - "longitude": -8.712945043, - "lines": [ - "18B", - "H3" - ] - }, - { - "stopId": 20190, - "name": { - "original": "Avda. das Camelias (fronte Praza do Rei)" - }, - "latitude": 42.234906013, - "longitude": -8.72662052, - "lines": [ - "4A", - "4C", - "11", - "12B", - "17", - "27", - "N1" - ] - }, - { - "stopId": 20191, - "name": { - "original": "Rúa das Figueiras 200" - }, - "latitude": 42.229676205, - "longitude": -8.657383392, - "lines": [ - "15A", - "25" - ] - }, - { - "stopId": 20192, - "name": { - "original": "Rúa de Colón 26" - }, - "latitude": 42.237168511, - "longitude": -8.720373767, - "lines": [ - "4A", - "4C", - "5B", - "7", - "12B", - "16", - "17", - "PSA 4" - ] - }, - { - "stopId": 20193, - "name": { - "original": "Rúa de Policarpo Sanz 25" - }, - "latitude": 42.23767601188501, - "longitude": -8.721582630122455, - "lines": [ - "C3i", - "A", - "5A", - "5B", - "10", - "11", - "15B", - "15C", - "N1", - "N4", - "H1" - ] - }, - { - "stopId": 20194, - "name": { - "original": "Rúa de Cánovas del Castillo 28" - }, - "latitude": 42.240364985, - "longitude": -8.724530974, - "lines": [ - "C1", - "C3d", - "A", - "5A", - "9B", - "10", - "15B", - "15C", - "28", - "N4" - ] - }, - { - "stopId": 20195, - "name": { - "original": "Praza de Compostela (fronte 35)" - }, - "latitude": 42.2393606, - "longitude": -8.724131464, - "lines": [ - "C3i", - "A", - "5A", - "5B", - "6", - "9B", - "10", - "11", - "15B", - "15C", - "28", - "N1", - "N4", - "H1" - ] - }, - { - "stopId": 20196, - "name": { - "original": "Estrada de Camposancos 498" - }, - "latitude": 42.175325155, - "longitude": -8.799594139, - "lines": [ - "12A" - ] - }, - { - "stopId": 20197, - "name": { - "original": "Rúa de Pi i Margall 3-5" - }, - "latitude": 42.23558703, - "longitude": -8.728830897, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 20198, - "name": { - "original": "Rúa de Policarpo Sanz 26" - }, - "latitude": 42.237533428, - "longitude": -8.722195046, - "lines": [ - "C1", - "C3d", - "A", - "5A", - "9B", - "10", - "15B", - "15C", - "24", - "28", - "N4" - ] - }, - { - "stopId": 20199, - "name": { - "original": "Rúa de Puerto Rico 12" - }, - "latitude": 42.228802205, - "longitude": -8.718136653, - "lines": [ - "H2" - ] - }, - { - "stopId": 20200, - "name": { - "original": "Rúa de Pi i Margall (fronte 5)" - }, - "latitude": 42.235482452, - "longitude": -8.728981431, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 20201, - "name": { - "original": "Paseo de Granada S/N" - }, - "latitude": 42.235701104, - "longitude": -8.726054911, - "lines": [ - "5B", - "12A" - ] - }, - { - "stopId": 20203, - "name": { - "original": "Avda. da Gran Vía 47" - }, - "latitude": 42.230881062, - "longitude": -8.718397577, - "lines": [ - "7", - "12B", - "14", - "16", - "18A", - "18B", - "18H" - ] - }, - { - "stopId": 20209, - "name": { - "original": "Avda. do Alcalde Portanet 23" - }, - "latitude": 42.211481651, - "longitude": -8.734440746, - "lines": [ - "H1" - ] - }, - { - "stopId": 20210, - "name": { - "original": "Estrada de Camposancos 108" - }, - "latitude": 42.19824056, - "longitude": -8.763182189, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 20211, - "name": { - "original": "Estrada de Camposancos 109" - }, - "latitude": 42.198422825, - "longitude": -8.762538026, - "lines": [ - "11", - "29" - ] - }, - { - "stopId": 20212, - "name": { - "original": "Rúa do Canabido 18" - }, - "latitude": 42.188388732, - "longitude": -8.805956864, - "lines": [ - "10" - ] - }, - { - "stopId": 20215, - "name": { - "original": "Rúa da Coruña 21" - }, - "latitude": 42.223880296, - "longitude": -8.735520196, - "lines": [ - "A", - "5A", - "5B", - "10", - "11", - "13", - "N4", - "U1", - "H1", - "H" - ] - }, - { - "stopId": 20216, - "name": { - "original": "Avda. de Cesáreo Vázquez (fronte 43)" - }, - "latitude": 42.179747589, - "longitude": -8.802157388, - "lines": [ - "11" - ] - }, - { - "stopId": 20219, - "name": { - "original": "Avda. do Aeroporto (fronte 90)" - }, - "latitude": 42.234830699, - "longitude": -8.695443515, - "lines": [ - "A", - "9B", - "27", - "28" - ] - } -] \ No newline at end of file diff --git a/public/sw.js b/public/sw.js deleted file mode 100644 index 70ca169..0000000 --- a/public/sw.js +++ /dev/null @@ -1,51 +0,0 @@ -const API_CACHE_NAME = 'api-cache-v1' -const API_URL_PATTERN = /\/api\/(GetStopList)/; -const API_MAX_AGE = 24 * 60 * 60 * 1000; // 24 hours - -self.addEventListener('install', (event) => { - event.waitUntil(self.skipWaiting()); -}); - -self.addEventListener('activate', (event) => { - event.waitUntil(self.clients.claim()); -}); - -self.addEventListener('fetch', async (event) => { - const url = new URL(event.request.url); - - if (event.request.method !== "GET" || !API_URL_PATTERN.test(url.pathname)) { - return; - } - - event.respondWith(apiCacheFirst(event.request)); -}); - -async function apiCacheFirst(request) { - const cache = await caches.open(API_CACHE_NAME); - const cachedResponse = await cache.match(request); - - if (cachedResponse) { - const age = Date.now() - new Date(cachedResponse.headers.get('date')).getTime(); - if (age < API_MAX_AGE) { - console.debug(`SW: Cache HIT for ${request.url}`); - return cachedResponse; - } - - // Cache is too old, fetch a fresh copy - cache.delete(request); - } - - try { - const netResponse = await fetch(request); - - const responseToCache = netResponse.clone(); - - cache.put(request, responseToCache); - - console.debug(`SW: Cache MISS for ${request.url}`); - - return netResponse; - } catch (error) { - throw error; - } -} \ No newline at end of file diff --git a/src/AppContext.tsx b/src/AppContext.tsx deleted file mode 100644 index 8b4ffe2..0000000 --- a/src/AppContext.tsx +++ /dev/null @@ -1,234 +0,0 @@ -/* eslint-disable react-refresh/only-export-components */ -import { createContext, useContext, useEffect, useState, ReactNode } from 'react'; -import { LatLngTuple } from 'leaflet'; - -type Theme = 'light' | 'dark'; -type TableStyle = 'regular'|'grouped'; -type MapPositionMode = 'gps' | 'last'; - -interface MapState { - center: LatLngTuple; - zoom: number; - userLocation: LatLngTuple | null; - hasLocationPermission: boolean; -} - -interface AppContextProps { - theme: Theme; - setTheme: React.Dispatch>; - toggleTheme: () => void; - - tableStyle: TableStyle; - setTableStyle: React.Dispatch>; - toggleTableStyle: () => void; - - mapState: MapState; - setMapCenter: (center: LatLngTuple) => void; - setMapZoom: (zoom: number) => void; - setUserLocation: (location: LatLngTuple | null) => void; - setLocationPermission: (hasPermission: boolean) => void; - updateMapState: (center: LatLngTuple, zoom: number) => void; - - mapPositionMode: MapPositionMode; - setMapPositionMode: (mode: MapPositionMode) => void; -} - -// Coordenadas por defecto centradas en Vigo -const DEFAULT_CENTER: LatLngTuple = [42.229188855975046, -8.72246955783102]; -const DEFAULT_ZOOM = 14; - -const AppContext = createContext(undefined); - -export const AppProvider = ({ children }: { children: ReactNode }) => { - //#region Theme - const [theme, setTheme] = useState(() => { - const savedTheme = localStorage.getItem('theme'); - if (savedTheme) { - return savedTheme as Theme; - } - const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; - return prefersDark ? 'dark' : 'light'; - }); - - const toggleTheme = () => { - setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light')); - }; - - useEffect(() => { - document.documentElement.setAttribute('data-theme', theme); - localStorage.setItem('theme', theme); - }, [theme]); - //#endregion - - //#region Table Style - const [tableStyle, setTableStyle] = useState(() => { - const savedTableStyle = localStorage.getItem('tableStyle'); - if (savedTableStyle) { - return savedTableStyle as TableStyle; - } - return 'regular'; - }); - - const toggleTableStyle = () => { - setTableStyle((prevTableStyle) => (prevTableStyle === 'regular' ? 'grouped' : 'regular')); - } - - useEffect(() => { - localStorage.setItem('tableStyle', tableStyle); - }, [tableStyle]); - //#endregion - - //#region Map Position Mode - const [mapPositionMode, setMapPositionMode] = useState(() => { - const saved = localStorage.getItem('mapPositionMode'); - return saved === 'last' ? 'last' : 'gps'; - }); - - useEffect(() => { - localStorage.setItem('mapPositionMode', mapPositionMode); - }, [mapPositionMode]); - //#endregion - - //#region Map State - const [mapState, setMapState] = useState(() => { - const savedMapState = localStorage.getItem('mapState'); - if (savedMapState) { - try { - const parsed = JSON.parse(savedMapState); - return { - center: parsed.center || DEFAULT_CENTER, - zoom: parsed.zoom || DEFAULT_ZOOM, - userLocation: parsed.userLocation || null, - hasLocationPermission: parsed.hasLocationPermission || false - }; - } catch (e) { - console.error('Error parsing saved map state', e); - } - } - return { - center: DEFAULT_CENTER, - zoom: DEFAULT_ZOOM, - userLocation: null, - hasLocationPermission: false - }; - }); - - // Helper: check if coordinates are within Vigo bounds - function isWithinVigo([lat, lng]: LatLngTuple): boolean { - // Rough bounding box for Vigo - return lat >= 42.18 && lat <= 42.30 && lng >= -8.78 && lng <= -8.65; - } - - // On app load, if mapPositionMode is 'gps', try to get GPS and set map center - useEffect(() => { - if (mapPositionMode === 'gps') { - if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition( - (position) => { - const { latitude, longitude } = position.coords; - const coords: LatLngTuple = [latitude, longitude]; - if (isWithinVigo(coords)) { - setMapState(prev => { - const newState = { ...prev, center: coords, zoom: 16, userLocation: coords }; - localStorage.setItem('mapState', JSON.stringify(newState)); - return newState; - }); - } - }, - () => { - // Ignore error, fallback to last - } - ); - } - } - // If 'last', do nothing (already loaded from localStorage) - }, [mapPositionMode]); - - const setMapCenter = (center: LatLngTuple) => { - setMapState(prev => { - const newState = { ...prev, center }; - localStorage.setItem('mapState', JSON.stringify(newState)); - return newState; - }); - }; - - const setMapZoom = (zoom: number) => { - setMapState(prev => { - const newState = { ...prev, zoom }; - localStorage.setItem('mapState', JSON.stringify(newState)); - return newState; - }); - }; - - const setUserLocation = (userLocation: LatLngTuple | null) => { - setMapState(prev => { - const newState = { ...prev, userLocation }; - localStorage.setItem('mapState', JSON.stringify(newState)); - return newState; - }); - }; - - const setLocationPermission = (hasLocationPermission: boolean) => { - setMapState(prev => { - const newState = { ...prev, hasLocationPermission }; - localStorage.setItem('mapState', JSON.stringify(newState)); - return newState; - }); - }; - - const updateMapState = (center: LatLngTuple, zoom: number) => { - setMapState(prev => { - const newState = { ...prev, center, zoom }; - localStorage.setItem('mapState', JSON.stringify(newState)); - return newState; - }); - }; - //#endregion - - // Tratar de obtener la ubicación del usuario cuando se carga la aplicación si ya se había concedido permiso antes - useEffect(() => { - if (mapState.hasLocationPermission && !mapState.userLocation) { - if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition( - (position) => { - const { latitude, longitude } = position.coords; - setUserLocation([latitude, longitude]); - }, - (error) => { - console.error('Error getting location:', error); - setLocationPermission(false); - } - ); - } - } - }, [mapState.hasLocationPermission, mapState.userLocation]); - - return ( - - {children} - - ); -}; - -export const useApp = () => { - const context = useContext(AppContext); - if (!context) { - throw new Error('useApp must be used within a AppProvider'); - } - return context; -}; \ No newline at end of file diff --git a/src/Costasdev.Busurbano.Backend/.gitignore b/src/Costasdev.Busurbano.Backend/.gitignore new file mode 100644 index 0000000..ff5b00c --- /dev/null +++ b/src/Costasdev.Busurbano.Backend/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/src/Costasdev.Busurbano.Backend/Costasdev.Busurbano.Backend.csproj b/src/Costasdev.Busurbano.Backend/Costasdev.Busurbano.Backend.csproj new file mode 100644 index 0000000..517a253 --- /dev/null +++ b/src/Costasdev.Busurbano.Backend/Costasdev.Busurbano.Backend.csproj @@ -0,0 +1,13 @@ + + + net9.0 + enable + enable + Costasdev.Busurbano.Backend + 0eff397c-f98e-4c3a-95ec-9d900f1b938c + + + + + + \ No newline at end of file diff --git a/src/Costasdev.Busurbano.Backend/GetStopEstimates.cs b/src/Costasdev.Busurbano.Backend/GetStopEstimates.cs new file mode 100644 index 0000000..7fe77e1 --- /dev/null +++ b/src/Costasdev.Busurbano.Backend/GetStopEstimates.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Mvc; +using Costasdev.VigoTransitApi; + +namespace Costasdev.Busurbano.Backend; + +[ApiController] +[Route("api")] +public class ApiController : ControllerBase +{ + private readonly VigoTransitApiClient _api; + + public ApiController(HttpClient http) + { + _api = new VigoTransitApiClient(http); + } + + [HttpGet("GetStopEstimates")] + public async Task Run() + { + var argumentAvailable = Request.Query.TryGetValue("id", out var requestedStopIdString); + if (!argumentAvailable) + { + return new BadRequestObjectResult("Please provide a stop id"); + } + + var argumentNumber = int.TryParse(requestedStopIdString, out var requestedStopId); + if (!argumentNumber) + { + return new BadRequestObjectResult("Please provide a valid stop id"); + } + + try + { + var estimates = await _api.GetStopEstimates(requestedStopId); + return new OkObjectResult(estimates); + } + catch (InvalidOperationException) + { + return new BadRequestObjectResult("Stop not found"); + } + } +} + diff --git a/src/Costasdev.Busurbano.Backend/Program.cs b/src/Costasdev.Busurbano.Backend/Program.cs new file mode 100644 index 0000000..a394282 --- /dev/null +++ b/src/Costasdev.Busurbano.Backend/Program.cs @@ -0,0 +1,10 @@ +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllers(); +builder.Services.AddHttpClient(); + +var app = builder.Build(); + +app.MapControllers(); + +app.Run(); diff --git a/src/Costasdev.Busurbano.Backend/Properties/launchSettings.json b/src/Costasdev.Busurbano.Backend/Properties/launchSettings.json new file mode 100644 index 0000000..783d5cc --- /dev/null +++ b/src/Costasdev.Busurbano.Backend/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "urbanovigoWeb": { + "commandName": "Project", + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7240", + "hotReloadEnabled": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + } + } + } +} diff --git a/src/Costasdev.Busurbano.Backend/appsettings.json b/src/Costasdev.Busurbano.Backend/appsettings.json new file mode 100644 index 0000000..23160a4 --- /dev/null +++ b/src/Costasdev.Busurbano.Backend/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/ErrorBoundary.tsx b/src/ErrorBoundary.tsx deleted file mode 100644 index 2372f9b..0000000 --- a/src/ErrorBoundary.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React, { Component, ReactNode } from 'react'; - -interface ErrorBoundaryProps { - children: ReactNode; -} - -interface ErrorBoundaryState { - hasError: boolean; - error: Error | null; -} - -class ErrorBoundary extends Component { - constructor(props: ErrorBoundaryProps) { - super(props); - this.state = { - hasError: false, - error: null - }; - } - - static getDerivedStateFromError(error: Error): ErrorBoundaryState { - return { - hasError: true, - error - }; - } - - componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { - console.error("Uncaught error:", error, errorInfo); - } - - render() { - if (this.state.hasError) { - return <> -

Something went wrong.

-
-          {this.state.error?.stack}
-        
- ; - } - - return this.props.children; - } -} - -export default ErrorBoundary; \ No newline at end of file diff --git a/src/Layout.css b/src/Layout.css deleted file mode 100644 index 0148da4..0000000 --- a/src/Layout.css +++ /dev/null @@ -1,60 +0,0 @@ -.app-container { - display: flex; - flex-direction: column; - height: 100vh; - width: 100%; - overflow: hidden; -} - -.main-content { - flex: 1; - overflow: auto; - padding-bottom: 60px; /* Extra padding to ensure content isn't hidden behind navbar */ -} - -.nav-bar { - position: fixed; - bottom: 0; - left: 0; - right: 0; - z-index: 5; - - background-color: var(--background-color); - display: flex; - justify-content: space-around; - align-items: center; - height: 60px; - border-top: 1px solid var(--border-color); - box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); -} - -.nav-item { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 8px; - color: #616161; - text-decoration: none; - width: 33.3%; - font-size: 14px; -} - -.nav-item.active { - color: var(--button-background-color); -} - -.theme-toggle { - background: none; - border: none; - cursor: pointer; - color: inherit; - display: flex; - align-items: center; - justify-content: center; - padding: 8px; -} - -.theme-toggle:hover { - color: var(--button-hover-background-color); -} \ No newline at end of file diff --git a/src/Layout.tsx b/src/Layout.tsx deleted file mode 100644 index 2a7816c..0000000 --- a/src/Layout.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { ReactNode } from 'react'; -import { Link, useLocation } from 'react-router'; -import { MapPin, Map, Settings } from 'lucide-react'; -import './Layout.css'; - -interface LayoutProps { - children: ReactNode; -} - -export function Layout({ children }: LayoutProps) { - const location = useLocation(); - - const navItems = [ - { - name: 'Paradas', - icon: MapPin, - path: '/stops' - }, - { - name: 'Mapa', - icon: Map, - path: '/map' - }, - { - name: 'Ajustes', - icon: Settings, - path: '/settings' - } - ]; - - return ( -
-
- {children} -
- -
- ); -} \ No newline at end of file diff --git a/src/components/GroupedTable.tsx b/src/components/GroupedTable.tsx deleted file mode 100644 index 58bb5ed..0000000 --- a/src/components/GroupedTable.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { StopDetails } from "../pages/Estimates"; -import LineIcon from "./LineIcon"; - -interface GroupedTable { - data: StopDetails; - dataDate: Date | null; -} - -export const GroupedTable: React.FC = ({ data, dataDate }) => { - const formatDistance = (meters: number) => { - if (meters > 1024) { - return `${(meters / 1000).toFixed(1)} km`; - } else { - return `${meters} m`; - } - } - - const groupedEstimates = data.estimates.reduce((acc, estimate) => { - if (!acc[estimate.line]) { - acc[estimate.line] = []; - } - acc[estimate.line].push(estimate); - return acc; - }, {} as Record); - - const sortedLines = Object.keys(groupedEstimates).sort((a, b) => { - const firstArrivalA = groupedEstimates[a][0].minutes; - const firstArrivalB = groupedEstimates[b][0].minutes; - return firstArrivalA - firstArrivalB; - }); - - return - - - - - - - - - - - - - {sortedLines.map((line) => ( - groupedEstimates[line].map((estimate, idx) => ( - - {idx === 0 && ( - - )} - - - - - )) - ))} - - - {data?.estimates.length === 0 && ( - - - - - - )} -
Estimaciones de llegadas a las {dataDate?.toLocaleTimeString()}
LíneaRutaLlegadaDistancia
- - {estimate.route}{`${estimate.minutes} min`} - {estimate.meters > -1 - ? formatDistance(estimate.meters) - : "No disponible" - } -
No hay estimaciones disponibles
-} \ No newline at end of file diff --git a/src/components/LineIcon.css b/src/components/LineIcon.css deleted file mode 100644 index e7e8949..0000000 --- a/src/components/LineIcon.css +++ /dev/null @@ -1,239 +0,0 @@ -:root { - --line-c1: rgb(237, 71, 19); - --line-c3d: rgb(255, 204, 0); - --line-c3i: rgb(255, 204, 0); - --line-l4a: rgb(0, 153, 0); - --line-l4c: rgb(0, 153, 0); - --line-l5a: rgb(0, 176, 240); - --line-l5b: rgb(0, 176, 240); - --line-l6: rgb(204, 51, 153); - --line-l7: rgb(150, 220, 153); - --line-l9b: rgb(244, 202, 140); - --line-l10: rgb(153, 51, 0); - --line-l11: rgb(226, 0, 38); - --line-l12a: rgb(106, 150, 190); - --line-l12b: rgb(106, 150, 190); - --line-l13: rgb(0, 176, 240); - --line-l14: rgb(129, 142, 126); - --line-l15a: rgb(216, 168, 206); - --line-l15b: rgb(216, 168, 206); - --line-l15c: rgb(216, 168, 168); - --line-l16: rgb(129, 142, 126); - --line-l17: rgb(214, 245, 31); - --line-l18a: rgb(212, 80, 168); - --line-l18b: rgb(0, 0, 0); - --line-l18h: rgb(0, 0, 0); - --line-l23: rgb(0, 70, 210); - --line-l24: rgb(191, 191, 191); - --line-l25: rgb(172, 100, 4); - --line-l27: rgb(112, 74, 42); - --line-l28: rgb(176, 189, 254); - --line-l29: rgb(248, 184, 90); - --line-l31: rgb(255, 255, 0); - --line-a: rgb(119, 41, 143); - --line-h: rgb(0, 96, 168); - --line-h1: rgb(0, 96, 168); - --line-h2: rgb(0, 96, 168); - --line-h3: rgb(0, 96, 168); - --line-lzd: rgb(61, 78, 167); - --line-n1: rgb(191, 191, 191); - --line-n4: rgb(102, 51, 102); - --line-psa1: rgb(0, 153, 0); - --line-psa4: rgb(0, 153, 0); - --line-ptl: rgb(150, 220, 153); - --line-turistico: rgb(102, 51, 102); - --line-u1: rgb(172, 100, 4); - --line-u2: rgb(172, 100, 4); -} - -.line-icon { - display: inline-block; - padding: 0.25rem 0.5rem; - margin-right: 0.5rem; - border-bottom: 3px solid; - font-size: 0.9rem; - font-weight: 600; - text-transform: uppercase; - color: inherit; - /* Prevent color change on hover */ -} - -.line-c1 { - border-color: var(--line-c1); -} - -.line-c3d { - border-color: var(--line-c3d); -} - -.line-c3i { - border-color: var(--line-c3i); -} - -.line-l4a { - border-color: var(--line-l4a); -} - -.line-l4c { - border-color: var(--line-l4c); -} - -.line-l5a { - border-color: var(--line-l5a); -} - -.line-l5b { - border-color: var(--line-l5b); -} - -.line-l6 { - border-color: var(--line-l6); -} - -.line-l7 { - border-color: var(--line-l7); -} - -.line-l9b { - border-color: var(--line-l9b); -} - -.line-l10 { - border-color: var(--line-l10); -} - -.line-l11 { - border-color: var(--line-l11); -} - -.line-l12a { - border-color: var(--line-l12a); -} - -.line-l12b { - border-color: var(--line-l12b); -} - -.line-l13 { - border-color: var(--line-l13); -} - -.line-l14 { - border-color: var(--line-l14); -} - -.line-l15a { - border-color: var(--line-l15a); -} - -.line-l15b { - border-color: var(--line-l15b); -} - -.line-l15c { - border-color: var(--line-l15c); -} - -.line-l16 { - border-color: var(--line-l16); -} - -.line-l17 { - border-color: var(--line-l17); -} - -.line-l18a { - border-color: var(--line-l18a); -} - -.line-l18b { - border-color: var(--line-l18b); -} - -.line-l18h { - border-color: var(--line-l18h); -} - -.line-l23 { - border-color: var(--line-l23); -} - -.line-l24 { - border-color: var(--line-l24); -} - -.line-l25 { - border-color: var(--line-l25); -} - -.line-l27 { - border-color: var(--line-l27); -} - -.line-l28 { - border-color: var(--line-l28); -} - -.line-l29 { - border-color: var(--line-l29); -} - -.line-l31 { - border-color: var(--line-l31); -} - -.line-a { - border-color: var(--line-a); -} - -.line-h { - border-color: var(--line-h); -} - -.line-h1 { - border-color: var(--line-h1); -} - -.line-h2 { - border-color: var(--line-h2); -} - -.line-h3 { - border-color: var(--line-h3); -} - -.line-lzd { - border-color: var(--line-lzd); -} - -.line-n1 { - border-color: var(--line-n1); -} - -.line-n4 { - border-color: var(--line-n4); -} - -.line-psa1 { - border-color: var(--line-psa1); -} - -.line-psa4 { - border-color: var(--line-psa4); -} - -.line-ptl { - border-color: var(--line-ptl); -} - -.line-turistico { - border-color: var(--line-turistico); -} - -.line-u1 { - border-color: var(--line-u1); -} - -.line-u2 { - border-color: var(--line-u2); -} \ No newline at end of file diff --git a/src/components/LineIcon.tsx b/src/components/LineIcon.tsx deleted file mode 100644 index 50fd1ec..0000000 --- a/src/components/LineIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import './LineIcon.css'; - -interface LineIconProps { - line: string; -} - -const LineIcon: React.FC = ({ line }) => { - const formattedLine = /^[a-zA-Z]/.test(line) ? line : `L${line}`; - return ( - - {formattedLine} - - ); -}; - -export default LineIcon; \ No newline at end of file diff --git a/src/components/RegularTable.tsx b/src/components/RegularTable.tsx deleted file mode 100644 index 8f0605f..0000000 --- a/src/components/RegularTable.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { StopDetails } from "../pages/Estimates"; -import LineIcon from "./LineIcon"; - -interface RegularTableProps { - data: StopDetails; - dataDate: Date | null; -} - -export const RegularTable: React.FC = ({ data, dataDate }) => { - - const absoluteArrivalTime = (minutes: number) => { - const now = new Date() - const arrival = new Date(now.getTime() + minutes * 60000) - return Intl.DateTimeFormat(navigator.language, { - hour: '2-digit', - minute: '2-digit' - }).format(arrival) - } - - const formatDistance = (meters: number) => { - if (meters > 1024) { - return `${(meters / 1000).toFixed(1)} km`; - } else { - return `${meters} m`; - } - } - - return - - - - - - - - - - - - - {data.estimates - .sort((a, b) => a.minutes - b.minutes) - .map((estimate, idx) => ( - - - - - - - ))} - - - {data?.estimates.length === 0 && ( - - - - - - )} -
Estimaciones de llegadas a las {dataDate?.toLocaleTimeString()}
LíneaRutaLlegadaDistancia
{estimate.route} - {estimate.minutes > 15 - ? absoluteArrivalTime(estimate.minutes) - : `${estimate.minutes} min`} - - {estimate.meters > -1 - ? formatDistance(estimate.meters) - : "No disponible" - } -
No hay estimaciones disponibles
-} \ No newline at end of file diff --git a/src/components/StopItem.css b/src/components/StopItem.css deleted file mode 100644 index 9feb2d1..0000000 --- a/src/components/StopItem.css +++ /dev/null @@ -1,54 +0,0 @@ -/* Stop Item Styling */ - -.stop-notes { - font-size: 0.85rem; - font-style: italic; - color: #666; - margin: 2px 0; -} - -.stop-amenities { - display: flex; - flex-wrap: wrap; - gap: 4px; - margin-top: 4px; -} - -.amenity-tag { - font-size: 0.75rem; - background-color: #e8f4f8; - color: #0078d4; - border-radius: 4px; - padding: 2px 6px; - display: inline-block; -} - -/* Different colors for different amenity types */ -.amenity-tag[data-amenity="shelter"] { - background-color: #e3f1df; - color: #107c41; -} - -.amenity-tag[data-amenity="bench"] { - background-color: #f0e8fc; - color: #5c2e91; -} - -.amenity-tag[data-amenity="real-time display"] { - background-color: #fff4ce; - color: #986f0b; -} - -/* When there are alternate names available, show an indicator */ -.has-alternate-names { - position: relative; -} - -.has-alternate-names::after { - content: "⋯"; - position: absolute; - right: -15px; - top: 0; - color: #0078d4; - font-weight: bold; -} \ No newline at end of file diff --git a/src/components/StopItem.tsx b/src/components/StopItem.tsx deleted file mode 100644 index cf9ccfc..0000000 --- a/src/components/StopItem.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router'; -import StopDataProvider, { Stop } from '../data/StopDataProvider'; -import LineIcon from './LineIcon'; - -interface StopItemProps { - stop: Stop; -} - -const StopItem: React.FC = ({ stop }) => { - - return ( -
  • - - {stop.favourite && } ({stop.stopId}) {StopDataProvider.getDisplayName(stop)} -
    - {stop.lines?.map(line => )} -
    - - -
  • - ); -}; - -export default StopItem; \ No newline at end of file diff --git a/src/controls/LocateControl.ts b/src/controls/LocateControl.ts deleted file mode 100644 index b8c2d1d..0000000 --- a/src/controls/LocateControl.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { createControlComponent } from '@react-leaflet/core'; -import { LocateControl as LeafletLocateControl, LocateOptions } from 'leaflet.locatecontrol'; -import "leaflet.locatecontrol/dist/L.Control.Locate.min.css"; -import { useEffect } from 'react'; -import { useMap } from 'react-leaflet'; -import { useApp } from '../AppContext'; - -interface EnhancedLocateControlProps { - options?: LocateOptions; -} - -// Componente que usa el contexto para manejar la localización -export const EnhancedLocateControl = (props: EnhancedLocateControlProps) => { - const map = useMap(); - const { mapState, setUserLocation, setLocationPermission } = useApp(); - - useEffect(() => { - // Configuración por defecto del control de localización - const defaultOptions: LocateOptions = { - position: 'topright', - strings: { - title: 'Mostrar mi ubicación', - }, - flyTo: true, - onLocationError: (err) => { - console.error('Error en la localización:', err); - setLocationPermission(false); - }, - returnToPrevBounds: true, - showPopup: false, - }; - - // Combinamos las opciones por defecto con las personalizadas - const options = { ...defaultOptions, ...props.options }; - - // Creamos la instancia del control - const locateControl = new LeafletLocateControl(options); - - // Añadimos el control al mapa - locateControl.addTo(map); - - // Si tenemos permiso de ubicación y ya conocemos la ubicación del usuario, - // podemos activarla automáticamente - if (mapState.hasLocationPermission && mapState.userLocation) { - // Esperamos a que el mapa esté listo - setTimeout(() => { - try { - locateControl.start(); - } catch (e) { - console.error('Error al iniciar la localización automática', e); - } - }, 1000); - } - - return () => { - // Limpieza al desmontar el componente - locateControl.remove(); - }; - }, [map, mapState.hasLocationPermission, mapState.userLocation, props.options, setLocationPermission, setUserLocation]); - - return null; -}; - -// Exportamos también el control base por compatibilidad -export const LocateControl = createControlComponent( - (props) => new LeafletLocateControl(props) -); \ No newline at end of file diff --git a/src/data/StopDataProvider.ts b/src/data/StopDataProvider.ts deleted file mode 100644 index 0c1e46e..0000000 --- a/src/data/StopDataProvider.ts +++ /dev/null @@ -1,160 +0,0 @@ -export interface CachedStopList { - timestamp: number; - data: Stop[]; -} - -export type StopName = { - original: string; - intersect?: string; -} - -export interface Stop { - stopId: number; - name: StopName; - latitude?: number; - longitude?: number; - lines: string[]; - favourite?: boolean; -} - -// In-memory cache and lookup map -let cachedStops: Stop[] | null = null; -let stopsMap: Record = {}; -// Custom names loaded from localStorage -let customNames: Record = {}; - -// Initialize cachedStops and customNames once -async function initStops() { - if (!cachedStops) { - const response = await fetch('/stops.json'); - const stops = await response.json() as Stop[]; - // build array and map - stopsMap = {}; - cachedStops = stops.map(stop => { - const entry = { ...stop, favourite: false } as Stop; - stopsMap[stop.stopId] = entry; - return entry; - }); - // load custom names - const rawCustom = localStorage.getItem('customStopNames'); - if (rawCustom) customNames = JSON.parse(rawCustom) as Record; - } -} - -async function getStops(): Promise { - await initStops(); - // update favourites - const rawFav = localStorage.getItem('favouriteStops'); - const favouriteStops = rawFav ? JSON.parse(rawFav) as number[] : []; - cachedStops!.forEach(stop => stop.favourite = favouriteStops.includes(stop.stopId)); - return cachedStops!; -} - -// New: get single stop by id -async function getStopById(stopId: number): Promise { - await initStops(); - const stop = stopsMap[stopId]; - if (stop) { - const rawFav = localStorage.getItem('favouriteStops'); - const favouriteStops = rawFav ? JSON.parse(rawFav) as number[] : []; - stop.favourite = favouriteStops.includes(stopId); - } - return stop; -} - -// Updated display name to include custom names -function getDisplayName(stop: Stop): string { - if (customNames[stop.stopId]) return customNames[stop.stopId]; - const nameObj = stop.name; - return nameObj.intersect || nameObj.original; -} - -// New: set or remove custom names -function setCustomName(stopId: number, label: string) { - customNames[stopId] = label; - localStorage.setItem('customStopNames', JSON.stringify(customNames)); -} - -function removeCustomName(stopId: number) { - delete customNames[stopId]; - localStorage.setItem('customStopNames', JSON.stringify(customNames)); -} - -// New: get custom label for a stop -function getCustomName(stopId: number): string | undefined { - return customNames[stopId]; -} - -function addFavourite(stopId: number) { - const rawFavouriteStops = localStorage.getItem('favouriteStops'); - let favouriteStops: number[] = []; - if (rawFavouriteStops) { - favouriteStops = JSON.parse(rawFavouriteStops) as number[]; - } - - if (!favouriteStops.includes(stopId)) { - favouriteStops.push(stopId); - localStorage.setItem('favouriteStops', JSON.stringify(favouriteStops)); - } -} - -function removeFavourite(stopId: number) { - const rawFavouriteStops = localStorage.getItem('favouriteStops'); - let favouriteStops: number[] = []; - if (rawFavouriteStops) { - favouriteStops = JSON.parse(rawFavouriteStops) as number[]; - } - - const newFavouriteStops = favouriteStops.filter(id => id !== stopId); - localStorage.setItem('favouriteStops', JSON.stringify(newFavouriteStops)); -} - -function isFavourite(stopId: number): boolean { - const rawFavouriteStops = localStorage.getItem('favouriteStops'); - if (rawFavouriteStops) { - const favouriteStops = JSON.parse(rawFavouriteStops) as number[]; - return favouriteStops.includes(stopId); - } - return false; -} - -const RECENT_STOPS_LIMIT = 10; - -function pushRecent(stopId: number) { - const rawRecentStops = localStorage.getItem('recentStops'); - let recentStops: Set = new Set(); - if (rawRecentStops) { - recentStops = new Set(JSON.parse(rawRecentStops) as number[]); - } - - recentStops.add(stopId); - if (recentStops.size > RECENT_STOPS_LIMIT) { - const iterator = recentStops.values(); - const val = iterator.next().value as number; - recentStops.delete(val); - } - - localStorage.setItem('recentStops', JSON.stringify(Array.from(recentStops))); -} - -function getRecent(): number[] { - const rawRecentStops = localStorage.getItem('recentStops'); - if (rawRecentStops) { - return JSON.parse(rawRecentStops) as number[]; - } - return []; -} - -export default { - getStops, - getStopById, - getCustomName, - getDisplayName, - setCustomName, - removeCustomName, - addFavourite, - removeFavourite, - isFavourite, - pushRecent, - getRecent -}; diff --git a/src/frontend/frontend.esproj b/src/frontend/frontend.esproj new file mode 100644 index 0000000..1afb3fb --- /dev/null +++ b/src/frontend/frontend.esproj @@ -0,0 +1,22 @@ + + + npm run dev + npm run build + $(MSBuildProjectDirectory)\build + + + + + + + + + + + + + + + + + diff --git a/src/frontend/index.html b/src/frontend/index.html new file mode 100644 index 0000000..4812ce5 --- /dev/null +++ b/src/frontend/index.html @@ -0,0 +1,55 @@ + + + + + + + + UrbanoVigo Web + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + \ No newline at end of file diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json new file mode 100644 index 0000000..b18eeb4 --- /dev/null +++ b/src/frontend/package-lock.json @@ -0,0 +1,4083 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "@fontsource-variable/outfit": "^5.2.5", + "fuse.js": "^7.1.0", + "leaflet": "^1.9.4", + "leaflet.locatecontrol": "^0.84.2", + "leaflet.markercluster": "^1.5.3", + "lucide-react": "^0.510.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-leaflet": "^5.0.0", + "react-leaflet-markercluster": "^5.0.0-rc.0", + "react-router": "^7.6.0" + }, + "devDependencies": { + "@eslint/js": "^9.26.0", + "@types/leaflet": "^1.9.17", + "@types/node": "^22.15.17", + "@types/react": "^19.1.3", + "@types/react-dom": "^19.1.4", + "@vitejs/plugin-react-swc": "^3.9.0", + "eslint": "^9.26.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.1.0", + "jiti": "^2.4.2", + "typescript": "^5.8.3", + "typescript-eslint": "^8.32.0", + "vite": "^6.3.5" + }, + "engines": { + "node": ">=20.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "*" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "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/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "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" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "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" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", + "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.26.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.26.0.tgz", + "integrity": "sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@fontsource-variable/outfit": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@fontsource-variable/outfit/-/outfit-5.2.5.tgz", + "integrity": "sha512-MejrIp6Cbmd3u5AZtsot8kmhZiyQM5CATsdcBB2hktYIrv5CVekRSUmFDXL4FpF7K70IvFp2ZMfImm5VhnVf7Q==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.2.tgz", + "integrity": "sha512-H9vwztj5OAqHg9GockCQC06k1natgcxWQSRpQcPJf6i5+MWBzfKkRtxGbjQf0X2ihii0ffLZCRGbYV2f2bjNCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.3", + "eventsource": "^3.0.2", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.24.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "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" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "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" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "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" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@react-leaflet/core": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-3.0.0.tgz", + "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", + "license": "Hippocratic-2.1", + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", + "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", + "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", + "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", + "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", + "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", + "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", + "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", + "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", + "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", + "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", + "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", + "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", + "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", + "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", + "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", + "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", + "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", + "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", + "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", + "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/core": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.24.tgz", + "integrity": "sha512-MaQEIpfcEMzx3VWWopbofKJvaraqmL6HbLlw2bFZ7qYqYw3rkhM0cQVEgyzbHtTWwCwPMFZSC2DUbhlZgrMfLg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.21" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.11.24", + "@swc/core-darwin-x64": "1.11.24", + "@swc/core-linux-arm-gnueabihf": "1.11.24", + "@swc/core-linux-arm64-gnu": "1.11.24", + "@swc/core-linux-arm64-musl": "1.11.24", + "@swc/core-linux-x64-gnu": "1.11.24", + "@swc/core-linux-x64-musl": "1.11.24", + "@swc/core-win32-arm64-msvc": "1.11.24", + "@swc/core-win32-ia32-msvc": "1.11.24", + "@swc/core-win32-x64-msvc": "1.11.24" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.11.24.tgz", + "integrity": "sha512-dhtVj0PC1APOF4fl5qT2neGjRLgHAAYfiVP8poJelhzhB/318bO+QCFWAiimcDoyMgpCXOhTp757gnoJJrheWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.11.24.tgz", + "integrity": "sha512-H/3cPs8uxcj2Fe3SoLlofN5JG6Ny5bl8DuZ6Yc2wr7gQFBmyBkbZEz+sPVgsID7IXuz7vTP95kMm1VL74SO5AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.24.tgz", + "integrity": "sha512-PHJgWEpCsLo/NGj+A2lXZ2mgGjsr96ULNW3+T3Bj2KTc8XtMUkE8tmY2Da20ItZOvPNC/69KroU7edyo1Flfbw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.24.tgz", + "integrity": "sha512-C2FJb08+n5SD4CYWCTZx1uR88BN41ZieoHvI8A55hfVf2woT8+6ZiBzt74qW2g+ntZ535Jts5VwXAKdu41HpBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.24.tgz", + "integrity": "sha512-ypXLIdszRo0re7PNNaXN0+2lD454G8l9LPK/rbfRXnhLWDBPURxzKlLlU/YGd2zP98wPcVooMmegRSNOKfvErw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.24.tgz", + "integrity": "sha512-IM7d+STVZD48zxcgo69L0yYptfhaaE9cMZ+9OoMxirNafhKKXwoZuufol1+alEFKc+Wbwp+aUPe/DeWC/Lh3dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.24.tgz", + "integrity": "sha512-DZByJaMVzSfjQKKQn3cqSeqwy6lpMaQDQQ4HPlch9FWtDx/dLcpdIhxssqZXcR2rhaQVIaRQsCqwV6orSDGAGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.24.tgz", + "integrity": "sha512-Q64Ytn23y9aVDKN5iryFi8mRgyHw3/kyjTjT4qFCa8AEb5sGUuSj//AUZ6c0J7hQKMHlg9do5Etvoe61V98/JQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.24.tgz", + "integrity": "sha512-9pKLIisE/Hh2vJhGIPvSoTK4uBSPxNVyXHmOrtdDot4E1FUUI74Vi8tFdlwNbaj8/vusVnb8xPXsxF1uB0VgiQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.11.24", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.24.tgz", + "integrity": "sha512-sybnXtOsdB+XvzVFlBVGgRHLqp3yRpHK7CrmpuDKszhj/QhmsaZzY/GHSeALlMtLup13M0gqbcQvsTNlAHTg3w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.21.tgz", + "integrity": "sha512-2YEtj5HJVbKivud9N4bpPBAyZhj4S2Ipe5LkUG94alTpr7in/GU/EARgPAd3BwU+YOmFVJC2+kjqhGRi3r0ZpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "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, + "license": "MIT" + }, + "node_modules/@types/leaflet": { + "version": "1.9.17", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.17.tgz", + "integrity": "sha512-IJ4K6t7I3Fh5qXbQ1uwL3CFVbCi6haW9+53oLWgdKlLP7EaS21byWFJxxqOx9y8I0AP0actXSJLVMbyvxhkUTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/node": { + "version": "22.15.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz", + "integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.1.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.3.tgz", + "integrity": "sha512-dLWQ+Z0CkIvK1J8+wrDPwGxEYFA4RAyHoZPxHVGspYmFVnwGSNT24cGIhFJrtfRnWVuW8X7NO52gCXmhkVUWGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.4.tgz", + "integrity": "sha512-WxYAszDYgsMV31OVyoG4jbAgJI1Gw0Xq9V19zwhy6+hUUJlJIdZ3r/cbdmTqFv++SktQkZ/X+46yGFxp5XJBEg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz", + "integrity": "sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.32.0", + "@typescript-eslint/type-utils": "8.32.0", + "@typescript-eslint/utils": "8.32.0", + "@typescript-eslint/visitor-keys": "8.32.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.0.tgz", + "integrity": "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.32.0", + "@typescript-eslint/types": "8.32.0", + "@typescript-eslint/typescript-estree": "8.32.0", + "@typescript-eslint/visitor-keys": "8.32.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.0.tgz", + "integrity": "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.32.0", + "@typescript-eslint/visitor-keys": "8.32.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.0.tgz", + "integrity": "sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.32.0", + "@typescript-eslint/utils": "8.32.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.0.tgz", + "integrity": "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.0.tgz", + "integrity": "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.32.0", + "@typescript-eslint/visitor-keys": "8.32.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "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" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "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" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.0.tgz", + "integrity": "sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.32.0", + "@typescript-eslint/types": "8.32.0", + "@typescript-eslint/typescript-estree": "8.32.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.0.tgz", + "integrity": "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.32.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.9.0.tgz", + "integrity": "sha512-jYFUSXhwMCYsh/aQTgSGLIN3Foz5wMbH9ahb0Zva//UzwZYbMiZd7oT3AU9jHT9DLswYDswsRwPU9jVF3yA48Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/core": "^1.11.21" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "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" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "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", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "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" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "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" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "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, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.26.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.26.0.tgz", + "integrity": "sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.13.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.26.0", + "@eslint/plugin-kit": "^0.2.8", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@modelcontextprotocol/sdk": "^1.8.0", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "zod": "^3.24.2" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "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" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "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" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "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" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "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" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz", + "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", + "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": "^4.11 || 5 || ^5.0.0-beta.1" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fast-deep-equal": { + "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, + "license": "MIT" + }, + "node_modules/fast-glob": { + "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.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "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" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "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, + "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, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuse.js": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", + "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "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" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.1.0.tgz", + "integrity": "sha512-aibexHNbb/jiUSObBgpHLj+sIuUmJnYcgXBlrfsiDZ9rt4aF2TFRbyLgZ2iFQuVZ1K5Mx3FVkbKRSgKrbK3K2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "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" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "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" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "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" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "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-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" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "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, + "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, + "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, + "license": "MIT" + }, + "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" + } + }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "license": "BSD-2-Clause" + }, + "node_modules/leaflet.locatecontrol": { + "version": "0.84.2", + "resolved": "https://registry.npmjs.org/leaflet.locatecontrol/-/leaflet.locatecontrol-0.84.2.tgz", + "integrity": "sha512-Tv0S2bAhpFgZYyyfPgeVhb3hPr9CnlcP15EpMQd9m5vA+aALhM6key1ucfnnD7n09AEeNEmIFe71T4V18Kpu7g==", + "license": "MIT" + }, + "node_modules/leaflet.markercluster": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz", + "integrity": "sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==", + "license": "MIT", + "peerDependencies": { + "leaflet": "^1.3.1" + } + }, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "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, + "license": "MIT" + }, + "node_modules/lucide-react": { + "version": "0.510.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.510.0.tgz", + "integrity": "sha512-p8SQRAMVh7NhsAIETokSqDrc5CHnDLbV29mMnzaXx+Vc/hnqQzwI2r0FMWCcoTXnbw2KEjy48xwpGdEL+ck06Q==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "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" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "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, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "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" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "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", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "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" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", + "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "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/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-leaflet": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-5.0.0.tgz", + "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", + "license": "Hippocratic-2.1", + "dependencies": { + "@react-leaflet/core": "^3.0.0" + }, + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/react-leaflet-markercluster": { + "version": "5.0.0-rc.0", + "resolved": "https://registry.npmjs.org/react-leaflet-markercluster/-/react-leaflet-markercluster-5.0.0-rc.0.tgz", + "integrity": "sha512-jWa4bPD5LfLV3Lid1RWgl+yKUuQtnqeYtJzzLb/fiRjvX+rtwzY8pMoUFuygqyxNrWxMTQlWKBHxkpI7Sxvu4Q==", + "license": "MIT", + "dependencies": { + "@react-leaflet/core": "^3.0.0", + "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", + "react-leaflet": "^5.0.0" + }, + "peerDependencies": { + "leaflet": "^1.9.4", + "leaflet.markercluster": "^1.5.3", + "react": "^19.0.0", + "react-leaflet": "^5.0.0" + } + }, + "node_modules/react-router": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.0.tgz", + "integrity": "sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "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" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", + "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.7" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.40.0", + "@rollup/rollup-android-arm64": "4.40.0", + "@rollup/rollup-darwin-arm64": "4.40.0", + "@rollup/rollup-darwin-x64": "4.40.0", + "@rollup/rollup-freebsd-arm64": "4.40.0", + "@rollup/rollup-freebsd-x64": "4.40.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", + "@rollup/rollup-linux-arm-musleabihf": "4.40.0", + "@rollup/rollup-linux-arm64-gnu": "4.40.0", + "@rollup/rollup-linux-arm64-musl": "4.40.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", + "@rollup/rollup-linux-riscv64-gnu": "4.40.0", + "@rollup/rollup-linux-riscv64-musl": "4.40.0", + "@rollup/rollup-linux-s390x-gnu": "4.40.0", + "@rollup/rollup-linux-x64-gnu": "4.40.0", + "@rollup/rollup-linux-x64-musl": "4.40.0", + "@rollup/rollup-win32-arm64-msvc": "4.40.0", + "@rollup/rollup-win32-ia32-msvc": "4.40.0", + "@rollup/rollup-win32-x64-msvc": "4.40.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/set-cookie-parser": { + "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==", + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "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" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "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" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.32.0.tgz", + "integrity": "sha512-UMq2kxdXCzinFFPsXc9o2ozIpYCCOiEC46MG3yEh5Vipq6BO27otTtEBZA1fQ66DulEUgE97ucQ/3YY66CPg0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.32.0", + "@typescript-eslint/parser": "8.32.0", + "@typescript-eslint/utils": "8.32.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "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" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "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" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.24.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.4.tgz", + "integrity": "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.5", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", + "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } + } + } +} diff --git a/src/frontend/package.json b/src/frontend/package.json new file mode 100644 index 0000000..546b9cf --- /dev/null +++ b/src/frontend/package.json @@ -0,0 +1,47 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "engines": { + "node": ">=20.0.0" + }, + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@fontsource-variable/outfit": "^5.2.5", + "fuse.js": "^7.1.0", + "leaflet": "^1.9.4", + "leaflet.locatecontrol": "^0.84.2", + "leaflet.markercluster": "^1.5.3", + "lucide-react": "^0.510.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-leaflet": "^5.0.0", + "react-leaflet-markercluster": "^5.0.0-rc.0", + "react-router": "^7.6.0" + }, + "devDependencies": { + "@eslint/js": "^9.26.0", + "@types/leaflet": "^1.9.17", + "@types/node": "^22.15.17", + "@types/react": "^19.1.3", + "@types/react-dom": "^19.1.4", + "@vitejs/plugin-react-swc": "^3.9.0", + "eslint": "^9.26.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.1.0", + "jiti": "^2.4.2", + "typescript": "^5.8.3", + "typescript-eslint": "^8.32.0", + "vite": "^6.3.5" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "*" + } +} diff --git a/src/frontend/public/favicon.ico b/src/frontend/public/favicon.ico new file mode 100644 index 0000000..b81c323 Binary files /dev/null and b/src/frontend/public/favicon.ico differ diff --git a/src/frontend/public/logo-256.jpg b/src/frontend/public/logo-256.jpg new file mode 100644 index 0000000..c823056 Binary files /dev/null and b/src/frontend/public/logo-256.jpg differ diff --git a/src/frontend/public/logo-256.png b/src/frontend/public/logo-256.png new file mode 100644 index 0000000..a1d6c25 Binary files /dev/null and b/src/frontend/public/logo-256.png differ diff --git a/src/frontend/public/logo-512.jpg b/src/frontend/public/logo-512.jpg new file mode 100644 index 0000000..cf45e80 Binary files /dev/null and b/src/frontend/public/logo-512.jpg differ diff --git a/src/frontend/public/manifest.webmanifest b/src/frontend/public/manifest.webmanifest new file mode 100644 index 0000000..59fbab1 --- /dev/null +++ b/src/frontend/public/manifest.webmanifest @@ -0,0 +1,84 @@ +{ + "$schema": "https://raw.githubusercontent.com/SchemaStore/schemastore/refs/heads/master/src/schemas/json/web-manifest.json", + "id": "https://busurbano.costas.dev/", + "name": "UrbanoVigo Web", + "description": "Aplicación web para encontrar paradas y tiempos de llegada de los autobuses urbanos de Vigo, España.", + "short_name": "UrbanoVigo", + "start_url": "/", + "display": "standalone", + "orientation": "portrait-primary", + "lang": "es", + "background_color": "#ffffff", + "theme_color": "#007bff", + "icons": [ + { + "src": "/logo-512.jpg", + "sizes": "512x512", + "type": "image/jpg", + "purpose": "any maskable" + }, + { + "src": "/logo-256.jpg", + "sizes": "256x256", + "type": "image/jpg", + "purpose": "any maskable" + }, + { + "src": "/logo-256.png", + "sizes": "256x256", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/favicon.ico", + "sizes": "64x64", + "type": "image/x-icon", + "purpose": "any maskable" + } + ], + "screenshots": [ + { + "src": "/screenshots/stoplist-narrow.png", + "sizes": "1440x2960", + "type": "image/png", + "form_factor": "narrow", + "label": "Lista de paradas" + }, + { + "src": "/screenshots/map-narrow.png", + "sizes": "1440x2960", + "type": "image/png", + "form_factor": "narrow", + "label": "Mapa de paradas" + }, + { + "src": "/screenshots/estimates-narrow.png", + "sizes": "1440x2960", + "type": "image/png", + "form_factor": "narrow", + "label": "Estimaciones de llegada a parada" + }, + + { + "src": "/screenshots/stoplist-wide.jpeg", + "sizes": "1788x891", + "type": "image/jpeg", + "form_factor": "wide", + "label": "Lista de paradas" + }, + { + "src": "/screenshots/map-wide.jpeg", + "sizes": "1788x891", + "type": "image/jpeg", + "form_factor": "wide", + "label": "Mapa de paradas" + }, + { + "src": "/screenshots/estimates-wide.jpeg", + "sizes": "1788x891", + "type": "image/jpeg", + "form_factor": "wide", + "label": "Estimaciones de llegada a parada" + } + ] +} \ No newline at end of file diff --git a/src/frontend/public/map-pin-icon.png b/src/frontend/public/map-pin-icon.png new file mode 100644 index 0000000..0015b64 Binary files /dev/null and b/src/frontend/public/map-pin-icon.png differ diff --git a/src/frontend/public/screenshots/estimates-narrow.png b/src/frontend/public/screenshots/estimates-narrow.png new file mode 100644 index 0000000..0337442 Binary files /dev/null and b/src/frontend/public/screenshots/estimates-narrow.png differ diff --git a/src/frontend/public/screenshots/estimates-wide.jpeg b/src/frontend/public/screenshots/estimates-wide.jpeg new file mode 100644 index 0000000..e81f094 Binary files /dev/null and b/src/frontend/public/screenshots/estimates-wide.jpeg differ diff --git a/src/frontend/public/screenshots/map-narrow.png b/src/frontend/public/screenshots/map-narrow.png new file mode 100644 index 0000000..14199c4 Binary files /dev/null and b/src/frontend/public/screenshots/map-narrow.png differ diff --git a/src/frontend/public/screenshots/map-wide.jpeg b/src/frontend/public/screenshots/map-wide.jpeg new file mode 100644 index 0000000..6d3ca64 Binary files /dev/null and b/src/frontend/public/screenshots/map-wide.jpeg differ diff --git a/src/frontend/public/screenshots/stoplist-narrow.png b/src/frontend/public/screenshots/stoplist-narrow.png new file mode 100644 index 0000000..c1d9f25 Binary files /dev/null and b/src/frontend/public/screenshots/stoplist-narrow.png differ diff --git a/src/frontend/public/screenshots/stoplist-wide.jpeg b/src/frontend/public/screenshots/stoplist-wide.jpeg new file mode 100644 index 0000000..264e1a7 Binary files /dev/null and b/src/frontend/public/screenshots/stoplist-wide.jpeg differ diff --git a/src/frontend/public/stops.json b/src/frontend/public/stops.json new file mode 100644 index 0000000..f64dff8 --- /dev/null +++ b/src/frontend/public/stops.json @@ -0,0 +1,15037 @@ +[ + { + "stopId": 20, + "name": { + "original": "Rúa do Abade Juan de Bastos (fronte Asociación Veciños)" + }, + "latitude": 42.187593499, + "longitude": -8.741246641, + "lines": [ + "17" + ] + }, + { + "stopId": 40, + "name": { + "original": "Rúa do Abade Juan de Bastos (cruce Baixada da Moo)" + }, + "latitude": 42.192126677, + "longitude": -8.72901589, + "lines": [ + "17" + ] + }, + { + "stopId": 50, + "name": { + "original": "Rúa do Abade Juan de Bastos 24" + }, + "latitude": 42.19287042, + "longitude": -8.727513924, + "lines": [ + "17" + ] + }, + { + "stopId": 70, + "name": { + "original": "Rúa da Lagoa (cruce Camiño do Casmarcelo)" + }, + "latitude": 42.20020175, + "longitude": -8.700621608, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 80, + "name": { + "original": "Rúa da Lagoa 46" + }, + "latitude": 42.200132216, + "longitude": -8.700535777, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 90, + "name": { + "original": "Aeroporto de Peinador" + }, + "latitude": 42.225956918, + "longitude": -8.63286469, + "lines": [ + "A" + ] + }, + { + "stopId": 100, + "name": { + "original": "Avda. do Alcalde Lavadores 125" + }, + "latitude": 42.219008975, + "longitude": -8.69606935, + "lines": [ + "6" + ] + }, + { + "stopId": 110, + "name": { + "original": "Avda. do Alcalde Lavadores 171" + }, + "latitude": 42.215074591, + "longitude": -8.696738405, + "lines": [ + "6" + ] + }, + { + "stopId": 120, + "name": { + "original": "Avda. do Alcalde Lavadores 8" + }, + "latitude": 42.223288295, + "longitude": -8.700954873, + "lines": [ + "6" + ] + }, + { + "stopId": 130, + "name": { + "original": "Avda. do Alcalde Lavadores 102" + }, + "latitude": 42.219001694, + "longitude": -8.696198267, + "lines": [ + "6" + ] + }, + { + "stopId": 140, + "name": { + "original": "Avda. do Alcalde Lavadores 29" + }, + "latitude": 42.223444913, + "longitude": -8.700801996, + "lines": [ + "6" + ] + }, + { + "stopId": 150, + "name": { + "original": "Avda. do Alcalde Lavadores 48" + }, + "latitude": 42.222636676, + "longitude": -8.697201413, + "lines": [ + "6" + ] + }, + { + "stopId": 160, + "name": { + "original": "Avda. do Alcalde Lavadores 67" + }, + "latitude": 42.222830286, + "longitude": -8.697231476, + "lines": [ + "6" + ] + }, + { + "stopId": 170, + "name": { + "original": "Avda. do Alcalde Lavadores 152" + }, + "latitude": 42.215084316, + "longitude": -8.696854931, + "lines": [ + "6" + ] + }, + { + "stopId": 180, + "name": { + "original": "Estrada de Valadares 451" + }, + "latitude": 42.166144986, + "longitude": -8.720162371, + "lines": [ + "7" + ] + }, + { + "stopId": 190, + "name": { + "original": "Rúa de Ángel de Lema 58" + }, + "latitude": 42.250539537, + "longitude": -8.685179363, + "lines": [ + "C3i", + "10" + ] + }, + { + "stopId": 195, + "name": { + "original": "Rúa de Ángel de Lema 247" + }, + "latitude": 42.256624708, + "longitude": -8.677490797, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 200, + "name": { + "original": "Rúa de Ángel de Lema 100" + }, + "latitude": 42.252115803, + "longitude": -8.683374373, + "lines": [ + "C3i", + "10" + ] + }, + { + "stopId": 210, + "name": { + "original": "Rúa de Ángel de Lema 140" + }, + "latitude": 42.255798748, + "longitude": -8.678507526, + "lines": [ + "C3i", + "10" + ] + }, + { + "stopId": 220, + "name": { + "original": "Rúa de Ángel de Lema 163" + }, + "latitude": 42.252694363, + "longitude": -8.68302903, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 230, + "name": { + "original": "Rúa de Ángel de Lema 14" + }, + "latitude": 42.248041601, + "longitude": -8.691024475, + "lines": [ + "C3i", + "10" + ] + }, + { + "stopId": 240, + "name": { + "original": "Rúa de Ángel de Lema 19" + }, + "latitude": 42.247513476, + "longitude": -8.691874301, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 250, + "name": { + "original": "Rúa de Ángel de Lema 221" + }, + "latitude": 42.255252085, + "longitude": -8.679480662, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 260, + "name": { + "original": "Rúa de Ángel de Lema 91" + }, + "latitude": 42.250421216, + "longitude": -8.685464716, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 270, + "name": { + "original": "Rúa de Desiderio Pernas Arquitecto 1" + }, + "latitude": 42.18920151, + "longitude": -8.810340862, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 280, + "name": { + "original": "Rúa do Arquitecto Antonio Cominges 38" + }, + "latitude": 42.189490674, + "longitude": -8.808107114, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 290, + "name": { + "original": "Rúa do Arquitecto Gómez Román 37" + }, + "latitude": 42.190149471, + "longitude": -8.803788225, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 310, + "name": { + "original": "Rúa do Arquitecto Antonio Cominges 4" + }, + "latitude": 42.190850463, + "longitude": -8.80358845, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 320, + "name": { + "original": "Rúa do Arquitecto Antonio Cominges 70" + }, + "latitude": 42.189221331, + "longitude": -8.811730246, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 330, + "name": { + "original": "Rúa do Arquitecto Antonio Cominges 90" + }, + "latitude": 42.187213169, + "longitude": -8.813069201, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 340, + "name": { + "original": "Rúa de Aragón 116" + }, + "latitude": 42.238036494, + "longitude": -8.700921187, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 350, + "name": { + "original": "Rúa de Aragón 162" + }, + "latitude": 42.240488915, + "longitude": -8.700357923, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 360, + "name": { + "original": "Rúa de Aragón 193" + }, + "latitude": 42.24013184, + "longitude": -8.700947033, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 370, + "name": { + "original": "Rúa de Aragón 212" + }, + "latitude": 42.242101304, + "longitude": -8.698394546, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 380, + "name": { + "original": "Rúa de Aragón 221" + }, + "latitude": 42.242091376, + "longitude": -8.698668131, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 390, + "name": { + "original": "Rúa de Aragón 26" + }, + "latitude": 42.233174046, + "longitude": -8.702380309, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 400, + "name": { + "original": "Rúa de Aragón 91" + }, + "latitude": 42.235598195, + "longitude": -8.701426538, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 410, + "name": { + "original": "Rúa de Aragón 82" + }, + "latitude": 42.235524387, + "longitude": -8.701248417, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 420, + "name": { + "original": "Rúa de Aragón 147" + }, + "latitude": 42.238092485, + "longitude": -8.701156245, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 430, + "name": { + "original": "Rúa do Areal (Aduana)" + }, + "latitude": 42.239341996, + "longitude": -8.720234413, + "lines": [ + "A", + "6", + "9B", + "18A", + "24", + "28", + "H1" + ] + }, + { + "stopId": 530, + "name": { + "original": "Avda. de Ricardo Mella (Estación Coruxo)" + }, + "latitude": 42.193562859, + "longitude": -8.78173994, + "lines": [ + "12A" + ] + }, + { + "stopId": 540, + "name": { + "original": "Avda. de Ricardo Mella (fronte 223)" + }, + "latitude": 42.189424424, + "longitude": -8.790733064, + "lines": [ + "12A" + ] + }, + { + "stopId": 560, + "name": { + "original": "Avda. de Ricardo Mella 518" + }, + "latitude": 42.181015915, + "longitude": -8.807696921, + "lines": [ + "10" + ] + }, + { + "stopId": 570, + "name": { + "original": "Avda. de Ricardo Mella 250" + }, + "latitude": 42.195225102, + "longitude": -8.775226375, + "lines": [ + "12A" + ] + }, + { + "stopId": 572, + "name": { + "original": "Estrada de Madrid 210" + }, + "latitude": 42.214058797, + "longitude": -8.672946954, + "lines": [ + "12B", + "15B", + "15C", + "U2" + ] + }, + { + "stopId": 580, + "name": { + "original": "Avda. de Ricardo Mella 135" + }, + "latitude": 42.195766012, + "longitude": -8.773648966, + "lines": [ + "12A" + ] + }, + { + "stopId": 600, + "name": { + "original": "Avda. de Ricardo Mella 273" + }, + "latitude": 42.189927171, + "longitude": -8.800634184, + "lines": [ + "C3d", + "10", + "12A" + ] + }, + { + "stopId": 620, + "name": { + "original": "Avda. de Ricado Mella 165" + }, + "latitude": 42.1935678, + "longitude": -8.781529566, + "lines": [ + "12A" + ] + }, + { + "stopId": 630, + "name": { + "original": "Avda. de Ricardo Mella 223" + }, + "latitude": 42.189304527, + "longitude": -8.79068363, + "lines": [ + "12A" + ] + }, + { + "stopId": 650, + "name": { + "original": "Avda. de Ricardo Mella 289" + }, + "latitude": 42.181065441, + "longitude": -8.807509871, + "lines": [ + "C3d", + "10", + "12A" + ] + }, + { + "stopId": 660, + "name": { + "original": "Avda. do Alcalde Portanet 34" + }, + "latitude": 42.211494566, + "longitude": -8.736022397, + "lines": [ + "7", + "12B", + "17", + "H1" + ] + }, + { + "stopId": 680, + "name": { + "original": "Avda. do Aeroporto (Aeroclub)" + }, + "latitude": 42.229005723, + "longitude": -8.634356866, + "lines": [ + "A" + ] + }, + { + "stopId": 690, + "name": { + "original": "Avda. do Aeroporto 656" + }, + "latitude": 42.233064093, + "longitude": -8.642742935, + "lines": [ + "A", + "25" + ] + }, + { + "stopId": 700, + "name": { + "original": "Avda. do Aeroporto (Colexio)" + }, + "latitude": 42.228674047, + "longitude": -8.633340309, + "lines": [ + "A" + ] + }, + { + "stopId": 710, + "name": { + "original": "Rúa de Aragón (Instituto)" + }, + "latitude": 42.232478958, + "longitude": -8.701988706, + "lines": [ + "A", + "4A", + "9B", + "24", + "27", + "28" + ] + }, + { + "stopId": 720, + "name": { + "original": "Avda. do Aeroporto 215" + }, + "latitude": 42.235739016, + "longitude": -8.684254232, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 730, + "name": { + "original": "Avda. do Aeroporto 130" + }, + "latitude": 42.231109162, + "longitude": -8.690501398, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 740, + "name": { + "original": "Avda. do Aeroporto 181" + }, + "latitude": 42.233560754, + "longitude": -8.686937524, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 750, + "name": { + "original": "Avda. do Aeroporto 184" + }, + "latitude": 42.233103986, + "longitude": -8.68716283, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 760, + "name": { + "original": "Avda. do Aeroporto 240" + }, + "latitude": 42.236775611, + "longitude": -8.683736566, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 770, + "name": { + "original": "Avda. do Aeroporto 273" + }, + "latitude": 42.238939528, + "longitude": -8.681422497, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 780, + "name": { + "original": "Avda. do Aeroporto 298" + }, + "latitude": 42.238554288, + "longitude": -8.680663432, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 790, + "name": { + "original": "Avda. do Aeroporto 325" + }, + "latitude": 42.237426811, + "longitude": -8.675474476, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 800, + "name": { + "original": "Avda. do Aeroporto 328" + }, + "latitude": 42.237801674, + "longitude": -8.676524783, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 810, + "name": { + "original": "Avda. do Aeroporto 350" + }, + "latitude": 42.235521261, + "longitude": -8.67465521, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 820, + "name": { + "original": "Avda. do Aeroporto 377" + }, + "latitude": 42.234766626, + "longitude": -8.671305131, + "lines": [ + "A", + "9B" + ] + }, + { + "stopId": 830, + "name": { + "original": "Avda. do Aeroporto 378" + }, + "latitude": 42.234673289, + "longitude": -8.671348046, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 840, + "name": { + "original": "Avda. do Aeroporto 43" + }, + "latitude": 42.234904325, + "longitude": -8.699245802, + "lines": [ + "A", + "4A", + "9B", + "24", + "27", + "28" + ] + }, + { + "stopId": 850, + "name": { + "original": "Avda. do Aeroporto 423" + }, + "latitude": 42.23630176, + "longitude": -8.665791599, + "lines": [ + "A", + "9B" + ] + }, + { + "stopId": 860, + "name": { + "original": "Avda. do Aeroporto 446" + }, + "latitude": 42.235612667, + "longitude": -8.666529207, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 870, + "name": { + "original": "Avda. do Aeroporto 447" + }, + "latitude": 42.23543058, + "longitude": -8.66197943, + "lines": [ + "A", + "9B" + ] + }, + { + "stopId": 880, + "name": { + "original": "Avda. do Aeroporto 484" + }, + "latitude": 42.23544051, + "longitude": -8.662354939, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 890, + "name": { + "original": "Avda. do Aeroporto 491" + }, + "latitude": 42.232066419, + "longitude": -8.653842977, + "lines": [ + "A" + ] + }, + { + "stopId": 900, + "name": { + "original": "Avda. do Aeroporto 531" + }, + "latitude": 42.233527998, + "longitude": -8.648237616, + "lines": [ + "A" + ] + }, + { + "stopId": 910, + "name": { + "original": "Avda. do Aeroporto 54" + }, + "latitude": 42.234679919, + "longitude": -8.699623994, + "lines": [ + "A", + "4A", + "9B", + "24", + "27", + "28" + ] + }, + { + "stopId": 920, + "name": { + "original": "Avda. do Aeroporto (cruce Camiño das Cereixeiras)" + }, + "latitude": 42.233499069, + "longitude": -8.643325214, + "lines": [ + "A" + ] + }, + { + "stopId": 930, + "name": { + "original": "Avda. do Aeroporto 570" + }, + "latitude": 42.231979036, + "longitude": -8.65372496, + "lines": [ + "A" + ] + }, + { + "stopId": 940, + "name": { + "original": "Avda. do Aeroporto 605" + }, + "latitude": 42.230493878, + "longitude": -8.638023273, + "lines": [ + "A" + ] + }, + { + "stopId": 950, + "name": { + "original": "Avda. do Aeroporto 614" + }, + "latitude": 42.233626818, + "longitude": -8.647811163, + "lines": [ + "A", + "25" + ] + }, + { + "stopId": 960, + "name": { + "original": "Avda. do Aeroporto 686" + }, + "latitude": 42.230918888, + "longitude": -8.638532893, + "lines": [ + "A" + ] + }, + { + "stopId": 970, + "name": { + "original": "Avda. do Aeroporto 91" + }, + "latitude": 42.232787318, + "longitude": -8.693473285, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 980, + "name": { + "original": "Avda. da Atlántida 99" + }, + "latitude": 42.221170087, + "longitude": -8.763656977, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 990, + "name": { + "original": "Avda. da Atlántida (fronte 148)" + }, + "latitude": 42.222451366, + "longitude": -8.769134894, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 1000, + "name": { + "original": "Avda. da Atlántida 109" + }, + "latitude": 42.221220508, + "longitude": -8.767194468, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 1010, + "name": { + "original": "Avda. da Atlántida 136" + }, + "latitude": 42.221479642, + "longitude": -8.767482698, + "lines": [ + "10", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 1020, + "name": { + "original": "Avda. da Atlántida 150" + }, + "latitude": 42.222764778, + "longitude": -8.769405842, + "lines": [ + "10", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 1030, + "name": { + "original": "Avda. da Atlántida 25" + }, + "latitude": 42.223219677, + "longitude": -8.754753277, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 1040, + "name": { + "original": "Avda. da Atlántida 32" + }, + "latitude": 42.223237503, + "longitude": -8.755707801, + "lines": [ + "10", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 1050, + "name": { + "original": "Avda. da Atlántida 71" + }, + "latitude": 42.221875354, + "longitude": -8.760935381, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 1060, + "name": { + "original": "Avda. da Atlántida 84" + }, + "latitude": 42.221789505, + "longitude": -8.759905458, + "lines": [ + "10", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 1070, + "name": { + "original": "Avda. da Atlántida 114" + }, + "latitude": 42.221148357, + "longitude": -8.764660969, + "lines": [ + "10", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 1110, + "name": { + "original": "Praza Ribeira do Berbés" + }, + "latitude": 42.237821273, + "longitude": -8.729666379, + "lines": [ + "A", + "5B", + "6" + ] + }, + { + "stopId": 1120, + "name": { + "original": "Avda. de Beiramar (fronte Casa do Mar)" + }, + "latitude": 42.23416729, + "longitude": -8.733331094, + "lines": [ + "6", + "9B", + "15B", + "28" + ] + }, + { + "stopId": 1130, + "name": { + "original": "Avda. de Beiramar (Peiraos auxiliares)" + }, + "latitude": 42.231238831, + "longitude": -8.735255297, + "lines": [ + "6", + "9B", + "15B", + "28" + ] + }, + { + "stopId": 1140, + "name": { + "original": "Avda. de Beiramar (Freire)" + }, + "latitude": 42.225068475, + "longitude": -8.74774586, + "lines": [ + "6", + "9B", + "28" + ] + }, + { + "stopId": 1150, + "name": { + "original": "Rúa da Ribeira do Berbés" + }, + "latitude": 42.237384264, + "longitude": -8.729603006, + "lines": [ + "C1", + "C3d", + "A", + "5A", + "9B", + "10", + "15B", + "15C", + "28", + "N4" + ] + }, + { + "stopId": 1160, + "name": { + "original": "Avda. de Beiramar (Sto. Domingo)" + }, + "latitude": 42.225759663, + "longitude": -8.743239749, + "lines": [ + "6", + "9B", + "28" + ] + }, + { + "stopId": 1200, + "name": { + "original": "Avda. de Beiramar 51" + }, + "latitude": 42.234233798, + "longitude": -8.73312316, + "lines": [ + "10", + "15B" + ] + }, + { + "stopId": 1210, + "name": { + "original": "Avda. de Beiramar 61" + }, + "latitude": 42.230811976, + "longitude": -8.735364934, + "lines": [ + "10", + "15B" + ] + }, + { + "stopId": 1220, + "name": { + "original": "Avda. de Buenos Aires 46" + }, + "latitude": 42.247097055, + "longitude": -8.693109251, + "lines": [ + "5A", + "10", + "31", + "U2", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 1230, + "name": { + "original": "Avda. de Buenos Aires 49" + }, + "latitude": 42.247251925, + "longitude": -8.693122662, + "lines": [ + "5B", + "10", + "N1", + "H3" + ] + }, + { + "stopId": 1240, + "name": { + "original": "Avda. de Buenos Aires 8" + }, + "latitude": 42.249128205, + "longitude": -8.69514773, + "lines": [ + "5A", + "10", + "31", + "U2", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 1250, + "name": { + "original": "Avda. de Castelao 16" + }, + "latitude": 42.219730396, + "longitude": -8.737456513, + "lines": [ + "C3d", + "4A", + "4C", + "5B", + "10", + "12A", + "13", + "15A", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 1260, + "name": { + "original": "Avda. de Castelao 21" + }, + "latitude": 42.219775977, + "longitude": -8.736255523, + "lines": [ + "C3i", + "4A", + "4C", + "5B", + "10", + "11", + "12A", + "15A", + "N1", + "U1" + ] + }, + { + "stopId": 1270, + "name": { + "original": "Avda. de Castelao 50" + }, + "latitude": 42.218704937, + "longitude": -8.74254446, + "lines": [ + "C3d", + "4A", + "4C", + "5B", + "10", + "12A", + "13", + "15A", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 1280, + "name": { + "original": "Avda. de Castelao 41" + }, + "latitude": 42.218523315, + "longitude": -8.74223465, + "lines": [ + "C3i", + "4A", + "4C", + "10", + "11", + "12A", + "15A", + "N1", + "U1" + ] + }, + { + "stopId": 1290, + "name": { + "original": "Avda. de Castelao 54" + }, + "latitude": 42.218158263, + "longitude": -8.745797727, + "lines": [ + "C3d", + "4A", + "4C", + "5B", + "10", + "12A", + "13", + "15A", + "N4", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 1300, + "name": { + "original": "Avda. de Castelao 68" + }, + "latitude": 42.217466378, + "longitude": -8.751245499, + "lines": [ + "C3d", + "4A", + "4C", + "5B", + "10", + "12A", + "13", + "15A", + "N4", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 1310, + "name": { + "original": "Avda. de Castelao 73" + }, + "latitude": 42.217705528, + "longitude": -8.747753325, + "lines": [ + "C3i", + "4A", + "4C", + "10", + "11", + "12A", + "15A", + "N1", + "N4", + "U1" + ] + }, + { + "stopId": 1320, + "name": { + "original": "Avda. de Castelao 87" + }, + "latitude": 42.217302224, + "longitude": -8.751104752, + "lines": [ + "C3i", + "10", + "12A", + "N1", + "U1" + ] + }, + { + "stopId": 1330, + "name": { + "original": "Avda. de Castrelos (Pavillón)" + }, + "latitude": 42.219553947, + "longitude": -8.732509436, + "lines": [ + "A", + "16", + "23", + "27", + "H2" + ] + }, + { + "stopId": 1340, + "name": { + "original": "Avda. de Castrelos (Parque)" + }, + "latitude": 42.212870645, + "longitude": -8.732131792, + "lines": [ + "27", + "H2" + ] + }, + { + "stopId": 1350, + "name": { + "original": "Avda. de Castrelos 121" + }, + "latitude": 42.208026488, + "longitude": -8.7312098, + "lines": [ + "7", + "12B", + "17", + "27" + ] + }, + { + "stopId": 1360, + "name": { + "original": "Avda. de Castrelos 16" + }, + "latitude": 42.219613217, + "longitude": -8.732629194, + "lines": [ + "7", + "12B", + "17", + "27", + "H2", + "PTL" + ] + }, + { + "stopId": 1380, + "name": { + "original": "Avda. de Castrelos 179" + }, + "latitude": 42.20533568, + "longitude": -8.730078621, + "lines": [ + "7", + "12B", + "17", + "U1" + ] + }, + { + "stopId": 1390, + "name": { + "original": "Avda. de Castrelos 186" + }, + "latitude": 42.212735556, + "longitude": -8.732314182, + "lines": [ + "A", + "7", + "12B", + "17", + "27", + "U1", + "H2", + "H", + "PTL" + ] + }, + { + "stopId": 1400, + "name": { + "original": "Avda. de Castrelos 202" + }, + "latitude": 42.210706683, + "longitude": -8.732237372, + "lines": [ + "A", + "7", + "12B", + "17", + "27", + "U1", + "H1", + "H2", + "H", + "PTL" + ] + }, + { + "stopId": 1410, + "name": { + "original": "Avda. de Castrelos 13" + }, + "latitude": 42.218060161, + "longitude": -8.732450427, + "lines": [ + "A", + "16", + "23", + "27", + "H2" + ] + }, + { + "stopId": 1420, + "name": { + "original": "Avda. de Castrelos 297" + }, + "latitude": 42.201440099, + "longitude": -8.726409762, + "lines": [ + "7" + ] + }, + { + "stopId": 1430, + "name": { + "original": "Avda. de Castrelos 318" + }, + "latitude": 42.203408408, + "longitude": -8.728817983, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 1440, + "name": { + "original": "Avda. de Castrelos 339" + }, + "latitude": 42.198480135, + "longitude": -8.723827649, + "lines": [ + "7" + ] + }, + { + "stopId": 1450, + "name": { + "original": "Avda. de Castrelos 366" + }, + "latitude": 42.201044695, + "longitude": -8.726112037, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 1460, + "name": { + "original": "Avda. de Castrelos 396" + }, + "latitude": 42.198867605, + "longitude": -8.72460549, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 1470, + "name": { + "original": "Avda. de Castrelos 399" + }, + "latitude": 42.194996678, + "longitude": -8.72097155, + "lines": [ + "7" + ] + }, + { + "stopId": 1480, + "name": { + "original": "Avda. de Castrelos 526" + }, + "latitude": 42.19015727, + "longitude": -8.72109012, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 1490, + "name": { + "original": "Avda. de Castrelos 67" + }, + "latitude": 42.210613294, + "longitude": -8.732057664, + "lines": [ + "7", + "12B", + "17", + "27", + "H1", + "H2" + ] + }, + { + "stopId": 1500, + "name": { + "original": "Avda. de Castrelos 58" + }, + "latitude": 42.217084821, + "longitude": -8.732530893, + "lines": [ + "7", + "12B", + "17", + "27", + "H2", + "PTL" + ] + }, + { + "stopId": 1510, + "name": { + "original": "Avda. da Ponte 80" + }, + "latitude": 42.215203365, + "longitude": -8.670416197, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 1520, + "name": { + "original": "Avda. da Ponte 83" + }, + "latitude": 42.215400704, + "longitude": -8.671308533, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 1530, + "name": { + "original": "Avda. da Ponte (fronte Grupo S. Gorxal)" + }, + "latitude": 42.212814417, + "longitude": -8.670537674, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 1540, + "name": { + "original": "Avda. da Ponte 15" + }, + "latitude": 42.221677429, + "longitude": -8.66978207, + "lines": [ + "11", + "15A", + "15B", + "15C" + ] + }, + { + "stopId": 1550, + "name": { + "original": "Avda. da Ponte 18" + }, + "latitude": 42.221299207, + "longitude": -8.670013709, + "lines": [ + "11", + "15A", + "15B", + "15C" + ] + }, + { + "stopId": 1560, + "name": { + "original": "Avda. da Ponte 31" + }, + "latitude": 42.219388605, + "longitude": -8.669172606, + "lines": [ + "15A", + "15B" + ] + }, + { + "stopId": 1570, + "name": { + "original": "Avda. da Ponte 47" + }, + "latitude": 42.217957539, + "longitude": -8.669369577, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 1580, + "name": { + "original": "Avda. da Ponte 54" + }, + "latitude": 42.218393587, + "longitude": -8.669480106, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 1590, + "name": { + "original": "Avda. de Galicia (Parque Riouxa)" + }, + "latitude": 42.256667905, + "longitude": -8.682575386, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1600, + "name": { + "original": "Avda. de Galicia 103" + }, + "latitude": 42.251389209, + "longitude": -8.689369833, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1610, + "name": { + "original": "Avda. de Galicia 146" + }, + "latitude": 42.251376198, + "longitude": -8.68920404, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1620, + "name": { + "original": "Avda. de Galicia 139" + }, + "latitude": 42.253987165, + "longitude": -8.686196616, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1630, + "name": { + "original": "Avda. de Galicia 165" + }, + "latitude": 42.255177674, + "longitude": -8.684734482, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1640, + "name": { + "original": "Avda. de Galicia 200" + }, + "latitude": 42.254950083, + "longitude": -8.684862748, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1650, + "name": { + "original": "Avda. de Galicia 238" + }, + "latitude": 42.256910715, + "longitude": -8.68201353, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1660, + "name": { + "original": "Avda. de Galicia 280" + }, + "latitude": 42.259217959, + "longitude": -8.679666503, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1670, + "name": { + "original": "Avda. de Galicia 285" + }, + "latitude": 42.258365967, + "longitude": -8.680508997, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1680, + "name": { + "original": "Avda. de Galicia (Parque Cruce Balbarda)" + }, + "latitude": 42.251327471, + "longitude": -8.69260735, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1690, + "name": { + "original": "Avda. de Galicia 71" + }, + "latitude": 42.251420909, + "longitude": -8.692153216, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1710, + "name": { + "original": "Avda. de Vigo 6" + }, + "latitude": 42.274450823, + "longitude": -8.667138233, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1720, + "name": { + "original": "Avda. de Vigo 95" + }, + "latitude": 42.270480988, + "longitude": -8.667726374, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1730, + "name": { + "original": "Avda. de Vigo 129" + }, + "latitude": 42.267833798, + "longitude": -8.671345739, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1740, + "name": { + "original": "Avda. de Vigo 120" + }, + "latitude": 42.27068743, + "longitude": -8.668057842, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1750, + "name": { + "original": "Avda. de Vigo 161" + }, + "latitude": 42.266305919, + "longitude": -8.672818918, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1760, + "name": { + "original": "Avda. de Vigo 201" + }, + "latitude": 42.26408966, + "longitude": -8.674082239, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1770, + "name": { + "original": "Avda. de Vigo (Alameda de Rosalía de Castro)" + }, + "latitude": 42.26785896, + "longitude": -8.671440263, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1780, + "name": { + "original": "Avda. de Vigo 230" + }, + "latitude": 42.266245291, + "longitude": -8.672965754, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1790, + "name": { + "original": "Avda. de Vigo 261 (Cuatro Puentes)" + }, + "latitude": 42.261621089, + "longitude": -8.677207279, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1800, + "name": { + "original": "Avda. de Vigo 266" + }, + "latitude": 42.263995234, + "longitude": -8.674224503, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1810, + "name": { + "original": "Avda. de Vigo 320" + }, + "latitude": 42.262068498, + "longitude": -8.676736193, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1820, + "name": { + "original": "Avda. de Vigo 49" + }, + "latitude": 42.271878394, + "longitude": -8.666356304, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1830, + "name": { + "original": "Avda. de Vigo 11" + }, + "latitude": 42.274038501, + "longitude": -8.666949932, + "lines": [ + "C3d" + ] + }, + { + "stopId": 1840, + "name": { + "original": "Avda. de Vigo 72" + }, + "latitude": 42.27159436, + "longitude": -8.666389735, + "lines": [ + "C3i" + ] + }, + { + "stopId": 1850, + "name": { + "original": "Avda. de Europa (antes Camiño Freixeiro)" + }, + "latitude": 42.216135691, + "longitude": -8.759632243, + "lines": [ + "C3d", + "C3i", + "4A", + "12A", + "15A" + ] + }, + { + "stopId": 1860, + "name": { + "original": "Avda. de Europa (cruce Rúa da Pardaíña)" + }, + "latitude": 42.216741568, + "longitude": -8.757129742, + "lines": [ + "C3d", + "C3i", + "4A", + "12A", + "15A" + ] + }, + { + "stopId": 1870, + "name": { + "original": "Avda. de Europa 102" + }, + "latitude": 42.211235082, + "longitude": -8.773459294, + "lines": [ + "C3d", + "C3i", + "15A" + ] + }, + { + "stopId": 1880, + "name": { + "original": "Avda. de Europa (cruce Rúa das Teixugueiras)" + }, + "latitude": 42.216687933, + "longitude": -8.756794466, + "lines": [ + "C3d", + "C3i", + "4A", + "4C", + "12A", + "15A", + "N1" + ] + }, + { + "stopId": 1890, + "name": { + "original": "Avda. de Europa 23" + }, + "latitude": 42.215913672, + "longitude": -8.759904797, + "lines": [ + "C3d", + "C3i", + "4A", + "4C", + "12A", + "15A", + "N1" + ] + }, + { + "stopId": 1900, + "name": { + "original": "Avda. de Europa (cruce Rúa do Bravo)" + }, + "latitude": 42.211855119, + "longitude": -8.766755158, + "lines": [ + "C3d", + "C3i", + "4C", + "15A", + "N1" + ] + }, + { + "stopId": 1910, + "name": { + "original": "Avda. de Europa (fronte cruce Rúa do Bravo)" + }, + "latitude": 42.211905694, + "longitude": -8.766999036, + "lines": [ + "C3d", + "C3i", + "15A" + ] + }, + { + "stopId": 1920, + "name": { + "original": "Avda. de Europa 101" + }, + "latitude": 42.211066417, + "longitude": -8.772953743, + "lines": [ + "C3d", + "C3i", + "4C", + "15A", + "N1" + ] + }, + { + "stopId": 1930, + "name": { + "original": "Estrada de Madrid (fronte Seminario)" + }, + "latitude": 42.21474886, + "longitude": -8.69897918, + "lines": [ + "12A", + "12B", + "13", + "U2" + ] + }, + { + "stopId": 1940, + "name": { + "original": "Avda. de Madrid 136" + }, + "latitude": 42.218338954, + "longitude": -8.703817429, + "lines": [ + "12A", + "12B", + "13" + ] + }, + { + "stopId": 1950, + "name": { + "original": "Avda. de Madrid 124" + }, + "latitude": 42.220567154, + "longitude": -8.706419628, + "lines": [ + "12A", + "12B", + "13" + ] + }, + { + "stopId": 1960, + "name": { + "original": "Avda. de Madrid 62" + }, + "latitude": 42.224676782, + "longitude": -8.711832326, + "lines": [ + "12A", + "12B", + "13", + "U2", + "H2" + ] + }, + { + "stopId": 1970, + "name": { + "original": "Avda. de Madrid 57" + }, + "latitude": 42.223965709, + "longitude": -8.710062068, + "lines": [ + "12A", + "12B", + "13" + ] + }, + { + "stopId": 1980, + "name": { + "original": "Estrada de Madrid (Seminario)" + }, + "latitude": 42.214703324, + "longitude": -8.699378397, + "lines": [ + "12A", + "12B", + "13", + "U2" + ] + }, + { + "stopId": 1990, + "name": { + "original": "Avda. de Madrid (cruce Camiño do Raviso)" + }, + "latitude": 42.222130198, + "longitude": -8.708300774, + "lines": [ + "12A", + "12B", + "13", + "U2" + ] + }, + { + "stopId": 2000, + "name": { + "original": "Avda. de Madrid 133" + }, + "latitude": 42.220728012, + "longitude": -8.70612292, + "lines": [ + "12A", + "12B", + "13" + ] + }, + { + "stopId": 2010, + "name": { + "original": "Avda. de Madrid 195" + }, + "latitude": 42.218213283, + "longitude": -8.703163426, + "lines": [ + "12A", + "12B", + "13" + ] + }, + { + "stopId": 2020, + "name": { + "original": "Avda. de Madrid 2" + }, + "latitude": 42.228518615, + "longitude": -8.719214126, + "lines": [ + "12A", + "12B", + "13", + "U2" + ] + }, + { + "stopId": 2030, + "name": { + "original": "Avda. de Madrid 28" + }, + "latitude": 42.226744428, + "longitude": -8.716268699, + "lines": [ + "12A", + "12B", + "13", + "H2" + ] + }, + { + "stopId": 2040, + "name": { + "original": "Avda. de Madrid (trasera Colexio Hogar)" + }, + "latitude": 42.226835791, + "longitude": -8.715823453, + "lines": [ + "12A", + "12B", + "13" + ] + }, + { + "stopId": 2060, + "name": { + "original": "Avda. de Redondela 122" + }, + "latitude": 42.259945558, + "longitude": -8.672608434, + "lines": [ + "C3d" + ] + }, + { + "stopId": 2070, + "name": { + "original": "Avda. de Redondela 109" + }, + "latitude": 42.259481393, + "longitude": -8.67292487, + "lines": [ + "C3i" + ] + }, + { + "stopId": 2080, + "name": { + "original": "Avda. de Redondela 19" + }, + "latitude": 42.266569717, + "longitude": -8.667160768, + "lines": [ + "C3i" + ] + }, + { + "stopId": 2090, + "name": { + "original": "Avda. de Redondela 32" + }, + "latitude": 42.272074281, + "longitude": -8.664593691, + "lines": [ + "C3d" + ] + }, + { + "stopId": 2100, + "name": { + "original": "Avda. de Redondela 47" + }, + "latitude": 42.263186001, + "longitude": -8.668939094, + "lines": [ + "C3i" + ] + }, + { + "stopId": 2110, + "name": { + "original": "Avda. de Redondela 70" + }, + "latitude": 42.263286688, + "longitude": -8.668985036, + "lines": [ + "C3d" + ] + }, + { + "stopId": 2130, + "name": { + "original": "Avda. de Redondela (Instituto)" + }, + "latitude": 42.266758811, + "longitude": -8.667247828, + "lines": [ + "C3d" + ] + }, + { + "stopId": 2140, + "name": { + "original": "Avda. de Samil (Verbum)" + }, + "latitude": 42.213799707, + "longitude": -8.774374426, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 2150, + "name": { + "original": "Avda. de Samil (fronte Praia da Fonte)" + }, + "latitude": 42.221416498, + "longitude": -8.773724153, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 2160, + "name": { + "original": "Avda. de Samil 15" + }, + "latitude": 42.215907608, + "longitude": -8.774702031, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 2170, + "name": { + "original": "Avda. de Samil 35" + }, + "latitude": 42.210171416, + "longitude": -8.774585056, + "lines": [ + "C3d", + "4C", + "10" + ] + }, + { + "stopId": 2180, + "name": { + "original": "Avda. de Samil 67" + }, + "latitude": 42.206809895, + "longitude": -8.776206766, + "lines": [ + "C3d", + "4C", + "10" + ] + }, + { + "stopId": 2190, + "name": { + "original": "Avda. de Samil 81" + }, + "latitude": 42.205147646, + "longitude": -8.77674534, + "lines": [ + "C3d", + "4C", + "10" + ] + }, + { + "stopId": 2200, + "name": { + "original": "Avda. de Santa Mariña 110" + }, + "latitude": 42.22271748, + "longitude": -8.656176614, + "lines": [ + "11" + ] + }, + { + "stopId": 2210, + "name": { + "original": "Avda. de Santa Mariña 137" + }, + "latitude": 42.222538699, + "longitude": -8.656616496, + "lines": [ + "11" + ] + }, + { + "stopId": 2220, + "name": { + "original": "Avda. de Santa Mariña 17" + }, + "latitude": 42.220338634, + "longitude": -8.668666271, + "lines": [ + "11" + ] + }, + { + "stopId": 2230, + "name": { + "original": "Avda. de Santa Mariña 52" + }, + "latitude": 42.222347963, + "longitude": -8.662841482, + "lines": [ + "11" + ] + }, + { + "stopId": 2240, + "name": { + "original": "Avda. de Santa Mariña 77" + }, + "latitude": 42.222432209, + "longitude": -8.662773458, + "lines": [ + "11" + ] + }, + { + "stopId": 2250, + "name": { + "original": "Avda. de Santa Mariña (cruce Camiño do Narxo)" + }, + "latitude": 42.220826115, + "longitude": -8.659651094, + "lines": [ + "11" + ] + }, + { + "stopId": 2260, + "name": { + "original": "Avda. de Santa Mariña 18" + }, + "latitude": 42.220504663, + "longitude": -8.668053014, + "lines": [ + "11" + ] + }, + { + "stopId": 2270, + "name": { + "original": "Avda. de Santa Mariña 103" + }, + "latitude": 42.22113201, + "longitude": -8.658591621, + "lines": [ + "11" + ] + }, + { + "stopId": 2280, + "name": { + "original": "Baixada á Laxe 31" + }, + "latitude": 42.21650849, + "longitude": -8.719175368, + "lines": [ + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 2290, + "name": { + "original": "Baixada á Laxe 44" + }, + "latitude": 42.216415126, + "longitude": -8.719355076, + "lines": [ + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 2300, + "name": { + "original": "Baixada á Ponte Nova 13" + }, + "latitude": 42.22078735, + "longitude": -8.722722261, + "lines": [ + "18A" + ] + }, + { + "stopId": 2310, + "name": { + "original": "Baixada á Praia (fronte 187)" + }, + "latitude": 42.173398721, + "longitude": -8.811050666, + "lines": [ + "C3d", + "10", + "12A" + ] + }, + { + "stopId": 2320, + "name": { + "original": "Baixada á Praia 121" + }, + "latitude": 42.172541892, + "longitude": -8.809133287, + "lines": [ + "10" + ] + }, + { + "stopId": 2330, + "name": { + "original": "Avda. de Ricardo Mella 357" + }, + "latitude": 42.173316968, + "longitude": -8.81100291, + "lines": [ + "10" + ] + }, + { + "stopId": 2340, + "name": { + "original": "Baixada á Praia 44" + }, + "latitude": 42.167981444, + "longitude": -8.806504239, + "lines": [ + "C3d", + "10", + "12A" + ] + }, + { + "stopId": 2350, + "name": { + "original": "Baixada á Praia 74" + }, + "latitude": 42.169850316, + "longitude": -8.808861828, + "lines": [ + "C3d", + "10", + "12A" + ] + }, + { + "stopId": 2360, + "name": { + "original": "Baixada á Praia (Parque C.Cívico)" + }, + "latitude": 42.167825345, + "longitude": -8.806386831, + "lines": [ + "10" + ] + }, + { + "stopId": 2370, + "name": { + "original": "Baixada á Praia 94" + }, + "latitude": 42.172705652, + "longitude": -8.809114415, + "lines": [ + "C3d", + "10", + "12A" + ] + }, + { + "stopId": 2380, + "name": { + "original": "Baixada á Praia 101" + }, + "latitude": 42.169719111, + "longitude": -8.808832324, + "lines": [ + "10" + ] + }, + { + "stopId": 2390, + "name": { + "original": "Baixada á Salgueira 49" + }, + "latitude": 42.224020371, + "longitude": -8.716787891, + "lines": [ + "18A" + ] + }, + { + "stopId": 2410, + "name": { + "original": "Baixada ao Río 31" + }, + "latitude": 42.209020914, + "longitude": -8.702331689, + "lines": [ + "14" + ] + }, + { + "stopId": 2420, + "name": { + "original": "Rúa do Cacheno (Lavadero)" + }, + "latitude": 42.208468606, + "longitude": -8.702143934, + "lines": [ + "14" + ] + }, + { + "stopId": 2430, + "name": { + "original": "Rúa de Barcelona 64" + }, + "latitude": 42.223917068, + "longitude": -8.726168827, + "lines": [ + "C1" + ] + }, + { + "stopId": 2440, + "name": { + "original": "Rúa de Barcelona 2" + }, + "latitude": 42.228315534, + "longitude": -8.721741958, + "lines": [ + "C1" + ] + }, + { + "stopId": 2450, + "name": { + "original": "Rúa de Barcelona 32" + }, + "latitude": 42.226024692, + "longitude": -8.723390804, + "lines": [ + "C1" + ] + }, + { + "stopId": 2460, + "name": { + "original": "Rúa de Xeme 59" + }, + "latitude": 42.203300943, + "longitude": -8.696320858, + "lines": [ + "14" + ] + }, + { + "stopId": 2490, + "name": { + "original": "Rúa das Coutadas 57" + }, + "latitude": 42.194635725, + "longitude": -8.699504032, + "lines": [ + "6", + "27" + ] + }, + { + "stopId": 2500, + "name": { + "original": "Rúa de Ramiro Pascual (Igrexa)" + }, + "latitude": 42.191950062, + "longitude": -8.707193511, + "lines": [ + "27" + ] + }, + { + "stopId": 2510, + "name": { + "original": "Avda. de Castrelos 439" + }, + "latitude": 42.191323803, + "longitude": -8.721049887, + "lines": [ + "7" + ] + }, + { + "stopId": 2520, + "name": { + "original": "Estrada de Bembrive 238" + }, + "latitude": 42.204563665, + "longitude": -8.687025359, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 2540, + "name": { + "original": "Bouzas (Rotonda de Las Anclas)" + }, + "latitude": 42.22513153, + "longitude": -8.751597027, + "lines": [ + "6", + "9B", + "28" + ] + }, + { + "stopId": 2550, + "name": { + "original": "Camiño da Brea 10" + }, + "latitude": 42.204086577, + "longitude": -8.704832445, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 2560, + "name": { + "original": "Camiño da Brea 37" + }, + "latitude": 42.204297185, + "longitude": -8.704942415, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 2570, + "name": { + "original": "Camiño da Brea 54" + }, + "latitude": 42.207146083, + "longitude": -8.704526775, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 2580, + "name": { + "original": "Camiño da Brea 69" + }, + "latitude": 42.207235488, + "longitude": -8.704631381, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 2590, + "name": { + "original": "Rúa da Cabalaría 94" + }, + "latitude": 42.232442621, + "longitude": -8.689558541, + "lines": [ + "28" + ] + }, + { + "stopId": 2600, + "name": { + "original": "Rúa da Cabalaría 153" + }, + "latitude": 42.235437997, + "longitude": -8.689019794, + "lines": [ + "27", + "28" + ] + }, + { + "stopId": 2610, + "name": { + "original": "Rúa da Cabalaría 14" + }, + "latitude": 42.233426101, + "longitude": -8.693298639, + "lines": [ + "28" + ] + }, + { + "stopId": 2620, + "name": { + "original": "Rúa da Cabalaría 186" + }, + "latitude": 42.235420737, + "longitude": -8.68894034, + "lines": [ + "28" + ] + }, + { + "stopId": 2630, + "name": { + "original": "Rúa da Cabalaría (cruce Subida ao Rosal Florido)" + }, + "latitude": 42.233483693, + "longitude": -8.693266452, + "lines": [ + "27", + "28" + ] + }, + { + "stopId": 2640, + "name": { + "original": "Rúa da Cabalaría 67" + }, + "latitude": 42.232559793, + "longitude": -8.689848219, + "lines": [ + "27", + "28" + ] + }, + { + "stopId": 2735, + "name": { + "original": "Rúa da Cachamuíña (Concello)" + }, + "latitude": 42.235033314, + "longitude": -8.727202198, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 2740, + "name": { + "original": "Rúa do Cacheno 75" + }, + "latitude": 42.207451401, + "longitude": -8.701194432, + "lines": [ + "14" + ] + }, + { + "stopId": 2750, + "name": { + "original": "Rúa do Cacheno 28" + }, + "latitude": 42.20671834, + "longitude": -8.699160127, + "lines": [ + "14" + ] + }, + { + "stopId": 2760, + "name": { + "original": "Rúa do Cacheno 66" + }, + "latitude": 42.208194443, + "longitude": -8.701518979, + "lines": [ + "14" + ] + }, + { + "stopId": 2770, + "name": { + "original": "Rúa do Cacheno 49" + }, + "latitude": 42.20648703, + "longitude": -8.698760561, + "lines": [ + "14" + ] + }, + { + "stopId": 2780, + "name": { + "original": "Avda. das Camelias 135" + }, + "latitude": 42.222387178, + "longitude": -8.731207698, + "lines": [ + "4A", + "4C", + "5A", + "5B", + "11", + "12A", + "12B", + "16", + "17", + "27", + "N1", + "LZH" + ] + }, + { + "stopId": 2790, + "name": { + "original": "Avda. das Camelias 37" + }, + "latitude": 42.230566426, + "longitude": -8.730086804, + "lines": [ + "4A", + "4C", + "11", + "12B", + "17", + "27", + "N1" + ] + }, + { + "stopId": 2800, + "name": { + "original": "Avda. das Camelias 46" + }, + "latitude": 42.230291959, + "longitude": -8.730279255, + "lines": [ + "4A", + "4C", + "7", + "12B", + "17", + "27", + "PSA 4" + ] + }, + { + "stopId": 2810, + "name": { + "original": "Avda. das Camelias 80" + }, + "latitude": 42.227601839, + "longitude": -8.730236339, + "lines": [ + "4A", + "4C", + "7", + "12B", + "17", + "27", + "PSA 4" + ] + }, + { + "stopId": 2820, + "name": { + "original": "Avda. das Camelias (Praza 8 de Marzo)" + }, + "latitude": 42.227403959, + "longitude": -8.729948584, + "lines": [ + "4A", + "4C", + "11", + "12B", + "17", + "27", + "N1" + ] + }, + { + "stopId": 2830, + "name": { + "original": "Rúa de Camilo Veiga 33" + }, + "latitude": 42.22243855, + "longitude": -8.751978552, + "lines": [ + "C3d", + "13", + "15B", + "15C", + "U1", + "H" + ] + }, + { + "stopId": 2840, + "name": { + "original": "Rúa da Goleta 3" + }, + "latitude": 42.241698248, + "longitude": -8.665209215, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 2850, + "name": { + "original": "Rúa da Goleta 2" + }, + "latitude": 42.241676405, + "longitude": -8.665026825, + "lines": [ + "9B", + "28" + ] + }, + { + "stopId": 2870, + "name": { + "original": "Rúa de Cantabria (Compañía Suministradora de Auga)" + }, + "latitude": 42.237397409, + "longitude": -8.694169154, + "lines": [ + "4A", + "24" + ] + }, + { + "stopId": 2880, + "name": { + "original": "Rúa de Cantabria 148" + }, + "latitude": 42.239331582, + "longitude": -8.692983618, + "lines": [ + "4A", + "24" + ] + }, + { + "stopId": 2910, + "name": { + "original": "Rúa de Cantabria 212" + }, + "latitude": 42.241655974, + "longitude": -8.692827561, + "lines": [ + "4A", + "24" + ] + }, + { + "stopId": 2920, + "name": { + "original": "Rúa de Cantabria 45" + }, + "latitude": 42.235852081, + "longitude": -8.695592417, + "lines": [ + "4A", + "24" + ] + }, + { + "stopId": 2930, + "name": { + "original": "Rúa de Cantabria 58" + }, + "latitude": 42.235377808, + "longitude": -8.695695331, + "lines": [ + "4A", + "24" + ] + }, + { + "stopId": 2950, + "name": { + "original": "Rúa dos Canteiros 4" + }, + "latitude": 42.204307169, + "longitude": -8.729719236, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 2960, + "name": { + "original": "Rúa dos Canteiros 101" + }, + "latitude": 42.20073699, + "longitude": -8.738895516, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 2970, + "name": { + "original": "Rúa dos Canteiros 116" + }, + "latitude": 42.201317829, + "longitude": -8.735636365, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 2980, + "name": { + "original": "Rúa dos Canteiros 164" + }, + "latitude": 42.200758846, + "longitude": -8.739043037, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 2990, + "name": { + "original": "Rúa dos Canteiros 9" + }, + "latitude": 42.203792573, + "longitude": -8.729630723, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 3000, + "name": { + "original": "Rúa dos Canteiros 49" + }, + "latitude": 42.201188677, + "longitude": -8.733208966, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 3010, + "name": { + "original": "Rúa dos Canteiros 73" + }, + "latitude": 42.20121252, + "longitude": -8.735711467, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 3020, + "name": { + "original": "Rúa dos Canteiros 76" + }, + "latitude": 42.201218481, + "longitude": -8.733509374, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 3030, + "name": { + "original": "Avda. de Castrelos 458" + }, + "latitude": 42.194702579, + "longitude": -8.721025195, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 3050, + "name": { + "original": "Estrada de Casás (cruce Camiño da Pedra Branca)" + }, + "latitude": 42.192360267, + "longitude": -8.756680959, + "lines": [ + "29" + ] + }, + { + "stopId": 3052, + "name": { + "original": "Avda. Arquitecto Antonio Palacios (cruce Rúa Ricardo Torres)" + }, + "latitude": 42.216966631, + "longitude": -8.729813845, + "lines": [ + "A" + ] + }, + { + "stopId": 3060, + "name": { + "original": "Rúa da Ceboleira 30" + }, + "latitude": 42.224698049, + "longitude": -8.701749123, + "lines": [ + "6" + ] + }, + { + "stopId": 3070, + "name": { + "original": "Rúa da Ceboleira 49" + }, + "latitude": 42.224816342, + "longitude": -8.701565998, + "lines": [ + "6" + ] + }, + { + "stopId": 3080, + "name": { + "original": "Avda. de Cesáreo Vázquez 136" + }, + "latitude": 42.1873653089623, + "longitude": -8.800886236766305, + "lines": [ + "11" + ] + }, + { + "stopId": 3090, + "name": { + "original": "Avda. de Cesáreo Vázquez 182" + }, + "latitude": 42.191019711713736, + "longitude": -8.799628565094565, + "lines": [ + "C3d", + "10", + "11" + ] + }, + { + "stopId": 3100, + "name": { + "original": "Avda. de Cesáreo Vázquez 99" + }, + "latitude": 42.184766843, + "longitude": -8.802180879, + "lines": [ + "11", + "12A" + ] + }, + { + "stopId": 3110, + "name": { + "original": "Avda. de Cesáreo Vázquez 74" + }, + "latitude": 42.184416675, + "longitude": -8.802179713, + "lines": [ + "11" + ] + }, + { + "stopId": 3120, + "name": { + "original": "Avda. de Cesáreo Vázquez 141" + }, + "latitude": 42.187488521491225, + "longitude": -8.801226626055183, + "lines": [ + "11", + "12A" + ] + }, + { + "stopId": 3130, + "name": { + "original": "Avda. de Cesáreo Vázquez 169" + }, + "latitude": 42.191024803868736, + "longitude": -8.799397387002196, + "lines": [ + "11" + ] + }, + { + "stopId": 3140, + "name": { + "original": "Estrada De Zamáns 255" + }, + "latitude": 42.15800346, + "longitude": -8.686134691, + "lines": [ + "7" + ] + }, + { + "stopId": 3150, + "name": { + "original": "Estrada de Zamáns (cruce Igrexa)" + }, + "latitude": 42.157661469, + "longitude": -8.685973759, + "lines": [ + "7" + ] + }, + { + "stopId": 3160, + "name": { + "original": "Camiño da Falcoa 10" + }, + "latitude": 42.206593246, + "longitude": -8.721651793, + "lines": [ + "18B", + "18H" + ] + }, + { + "stopId": 3170, + "name": { + "original": "Rúa das Coutadas 76" + }, + "latitude": 42.220968446, + "longitude": -8.720400826, + "lines": [ + "18A" + ] + }, + { + "stopId": 3180, + "name": { + "original": "Camiño de Quirós 106" + }, + "latitude": 42.21955863, + "longitude": -8.711410119, + "lines": [ + "18B", + "18H" + ] + }, + { + "stopId": 3190, + "name": { + "original": "Camiño de Quirós (cruce Rúa de Dona Cristina)" + }, + "latitude": 42.219681782, + "longitude": -8.711385979, + "lines": [ + "18B", + "18H" + ] + }, + { + "stopId": 3230, + "name": { + "original": "Rúa de Colón 27" + }, + "latitude": 42.236471452, + "longitude": -8.720164905, + "lines": [ + "A", + "5A", + "9B", + "11", + "15B", + "15C", + "16", + "17" + ] + }, + { + "stopId": 3240, + "name": { + "original": "Rúa da Coruña 5" + }, + "latitude": 42.22214729, + "longitude": -8.734167916, + "lines": [ + "A", + "5A", + "5B", + "10", + "11", + "13", + "N4", + "U1", + "H1", + "H" + ] + }, + { + "stopId": 3250, + "name": { + "original": "Rúa da Coruña 26" + }, + "latitude": 42.222378625, + "longitude": -8.734134247, + "lines": [ + "C1", + "A", + "10", + "N4", + "H1" + ] + }, + { + "stopId": 3260, + "name": { + "original": "Rúa da Coruña 37" + }, + "latitude": 42.226287696, + "longitude": -8.737475832, + "lines": [ + "15B" + ] + }, + { + "stopId": 3270, + "name": { + "original": "Rúa da Coruña (fronte 39)" + }, + "latitude": 42.226490285, + "longitude": -8.73744901, + "lines": [ + "10", + "15B" + ] + }, + { + "stopId": 3280, + "name": { + "original": "Rúa de Manuel Lago Lago 1" + }, + "latitude": 42.188898503, + "longitude": -8.776299224, + "lines": [ + "29" + ] + }, + { + "stopId": 3290, + "name": { + "original": "Rúa da Costa 13" + }, + "latitude": 42.213397685, + "longitude": -8.72248211, + "lines": [ + "A", + "18B", + "18H" + ] + }, + { + "stopId": 3300, + "name": { + "original": "Rúa da Costa 22" + }, + "latitude": 42.211751348, + "longitude": -8.721691531, + "lines": [ + "A", + "18B", + "18H" + ] + }, + { + "stopId": 3310, + "name": { + "original": "Rúa da Costa 74" + }, + "latitude": 42.209233023, + "longitude": -8.720666368, + "lines": [ + "A", + "18B", + "18H" + ] + }, + { + "stopId": 3320, + "name": { + "original": "Rúa da Costa 63" + }, + "latitude": 42.210154848, + "longitude": -8.720902403, + "lines": [ + "A", + "18B", + "18H" + ] + }, + { + "stopId": 3350, + "name": { + "original": "Rúa do Couto 1" + }, + "latitude": 42.230911796, + "longitude": -8.722711253, + "lines": [ + "12A", + "27" + ] + }, + { + "stopId": 3360, + "name": { + "original": "Rúa do Doutor Canoa 8" + }, + "latitude": 42.237803518, + "longitude": -8.704409031, + "lines": [ + "31" + ] + }, + { + "stopId": 3370, + "name": { + "original": "Estrada de Bembrive (cruce Rúa Eifonso)" + }, + "latitude": 42.205676226, + "longitude": -8.693112047, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 3380, + "name": { + "original": "Cruce Eifonso" + }, + "latitude": 42.205623108, + "longitude": -8.693239335, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 3390, + "name": { + "original": "Estrada de Bembrive 160" + }, + "latitude": 42.205296644, + "longitude": -8.692558914, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 3400, + "name": { + "original": "Estrada da Gándara 22" + }, + "latitude": 42.163584451, + "longitude": -8.716088728, + "lines": [ + "7" + ] + }, + { + "stopId": 3420, + "name": { + "original": "Avda. de Castrelos (Cemiterio de Pereiró)" + }, + "latitude": 42.208071495, + "longitude": -8.731366082, + "lines": [ + "7", + "12B", + "17", + "27", + "U1" + ] + }, + { + "stopId": 3430, + "name": { + "original": "Avda. da Ponte 86 (Cemiterio)" + }, + "latitude": 42.215621206, + "longitude": -8.67221512, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 3450, + "name": { + "original": "Estrada de Camposancos 155" + }, + "latitude": 42.194732286, + "longitude": -8.769245322, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3460, + "name": { + "original": "Estrada de Camposancos 19" + }, + "latitude": 42.203197031, + "longitude": -8.753437723, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3470, + "name": { + "original": "Estrada de Camposancos 214" + }, + "latitude": 42.193581709, + "longitude": -8.772496159, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3480, + "name": { + "original": "Estrada de Camposancos 141" + }, + "latitude": 42.196095467, + "longitude": -8.766230519, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3490, + "name": { + "original": "Estrada de Camposancos 171" + }, + "latitude": 42.193613504, + "longitude": -8.772222574, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3500, + "name": { + "original": "Estrada de Camposancos 190" + }, + "latitude": 42.194553241, + "longitude": -8.770325583, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3510, + "name": { + "original": "Estrada de Camposancos 28" + }, + "latitude": 42.202849227, + "longitude": -8.753870291, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3520, + "name": { + "original": "Estrada de Camposancos 75" + }, + "latitude": 42.200000035, + "longitude": -8.759107913, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3530, + "name": { + "original": "Estrada de Camposancos 88" + }, + "latitude": 42.199773285, + "longitude": -8.759958845, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3540, + "name": { + "original": "Estrada de Camposancos 138" + }, + "latitude": 42.19617384, + "longitude": -8.766295392, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 3550, + "name": { + "original": "Estrada de Bembrive (cruce Camiño Cova)" + }, + "latitude": 42.19747765, + "longitude": -8.688158543, + "lines": [ + "6" + ] + }, + { + "stopId": 3560, + "name": { + "original": "Estrada de Bembrive 104" + }, + "latitude": 42.209126518, + "longitude": -8.695599845, + "lines": [ + "6" + ] + }, + { + "stopId": 3570, + "name": { + "original": "Estrada de Bembrive 109" + }, + "latitude": 42.209576972, + "longitude": -8.695580071, + "lines": [ + "6" + ] + }, + { + "stopId": 3572, + "name": { + "original": "Estrada de Bembrive 110" + }, + "latitude": 42.208457815, + "longitude": -8.695017358, + "lines": [ + "14" + ] + }, + { + "stopId": 3574, + "name": { + "original": "Estrada de Bembrive 129" + }, + "latitude": 42.208533311, + "longitude": -8.694987854, + "lines": [ + "14" + ] + }, + { + "stopId": 3580, + "name": { + "original": "Estrada de Bembrive 180" + }, + "latitude": 42.204440318, + "longitude": -8.690871804, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 3590, + "name": { + "original": "Estrada de Bembrive 195" + }, + "latitude": 42.204458432, + "longitude": -8.690765895, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 3600, + "name": { + "original": "Estrada de Bembrive 22" + }, + "latitude": 42.21246424, + "longitude": -8.697218847, + "lines": [ + "6" + ] + }, + { + "stopId": 3610, + "name": { + "original": "Estrada de Bembrive 237" + }, + "latitude": 42.204446407, + "longitude": -8.68809021, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 3620, + "name": { + "original": "Estrada de Bembrive 278" + }, + "latitude": 42.202562995, + "longitude": -8.685437577, + "lines": [ + "6" + ] + }, + { + "stopId": 3630, + "name": { + "original": "Estrada de Bembrive 269" + }, + "latitude": 42.20274418, + "longitude": -8.684443742, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 3640, + "name": { + "original": "Estrada de Bembrive 315" + }, + "latitude": 42.197359418, + "longitude": -8.688113004, + "lines": [ + "6" + ] + }, + { + "stopId": 3650, + "name": { + "original": "Estrada de Bembrive 346" + }, + "latitude": 42.199275919, + "longitude": -8.689032944, + "lines": [ + "6" + ] + }, + { + "stopId": 3660, + "name": { + "original": "Estrada de Bembrive 39" + }, + "latitude": 42.212227656, + "longitude": -8.697028614, + "lines": [ + "6" + ] + }, + { + "stopId": 3670, + "name": { + "original": "Estrada de Bembrive 398" + }, + "latitude": 42.194968863, + "longitude": -8.689201981, + "lines": [ + "6" + ] + }, + { + "stopId": 3680, + "name": { + "original": "Estrada de Bembrive 64" + }, + "latitude": 42.211144971, + "longitude": -8.69652789, + "lines": [ + "6" + ] + }, + { + "stopId": 3690, + "name": { + "original": "Estrada de Bembrive 73" + }, + "latitude": 42.210947345, + "longitude": -8.69627482, + "lines": [ + "6" + ] + }, + { + "stopId": 3700, + "name": { + "original": "Estrada de Bembrive (cruce Camiño Riomao)" + }, + "latitude": 42.194055385, + "longitude": -8.692079677, + "lines": [ + "6" + ] + }, + { + "stopId": 3710, + "name": { + "original": "Estrada de Bembrive 363" + }, + "latitude": 42.193846109, + "longitude": -8.69200489, + "lines": [ + "6" + ] + }, + { + "stopId": 3720, + "name": { + "original": "Estrada de Bembrive 341" + }, + "latitude": 42.1948986, + "longitude": -8.689213754, + "lines": [ + "6" + ] + }, + { + "stopId": 3730, + "name": { + "original": "Estrada de Bembrive 301" + }, + "latitude": 42.199203404, + "longitude": -8.688880116, + "lines": [ + "6" + ] + }, + { + "stopId": 3740, + "name": { + "original": "Rúa de Canido (Igrexa)" + }, + "latitude": 42.197431882, + "longitude": -8.790144971, + "lines": [ + "C3d", + "4C", + "10" + ] + }, + { + "stopId": 3750, + "name": { + "original": "Rúa de Canido (Praia de Canido)" + }, + "latitude": 42.193128934, + "longitude": -8.797957944, + "lines": [ + "10", + "11" + ] + }, + { + "stopId": 3760, + "name": { + "original": "Rúa de Canido (fronte 119)" + }, + "latitude": 42.1957321, + "longitude": -8.795211362, + "lines": [ + "10", + "11" + ] + }, + { + "stopId": 3770, + "name": { + "original": "Rúa de Canido 135" + }, + "latitude": 42.1950348, + "longitude": -8.795701844, + "lines": [ + "C3d", + "10", + "11" + ] + }, + { + "stopId": 3780, + "name": { + "original": "Rúa de Canido 217" + }, + "latitude": 42.193041793, + "longitude": -8.797590453, + "lines": [ + "C3d", + "10", + "11" + ] + }, + { + "stopId": 3790, + "name": { + "original": "Rúa de Canido 15" + }, + "latitude": 42.201898697, + "longitude": -8.781706742, + "lines": [ + "C3d", + "4C", + "10" + ] + }, + { + "stopId": 3800, + "name": { + "original": "Rúa de Canido 26" + }, + "latitude": 42.199639519, + "longitude": -8.785727373, + "lines": [ + "10" + ] + }, + { + "stopId": 3810, + "name": { + "original": "Rúa de Canido 55" + }, + "latitude": 42.200106486, + "longitude": -8.785121194, + "lines": [ + "C3d", + "4C", + "10" + ] + }, + { + "stopId": 3820, + "name": { + "original": "Rúa do Falcoído 16" + }, + "latitude": 42.182659954, + "longitude": -8.699663442, + "lines": [ + "A" + ] + }, + { + "stopId": 3830, + "name": { + "original": "Rúa do Falcoído (cruce Camiño Goaldino)" + }, + "latitude": 42.180635405, + "longitude": -8.696958243, + "lines": [ + "A" + ] + }, + { + "stopId": 3840, + "name": { + "original": "Rúa do Falcoído (cruce Camiño das Presas)" + }, + "latitude": 42.181019011, + "longitude": -8.696918009, + "lines": [ + "A" + ] + }, + { + "stopId": 3850, + "name": { + "original": "Estrada Clara Campoamor (cruce Estrada Marcosende)" + }, + "latitude": 42.167933917, + "longitude": -8.692758811, + "lines": [ + "A", + "U1" + ] + }, + { + "stopId": 3860, + "name": { + "original": "Estrada Clara Campoamor (cruce Rúa do Falcoído)" + }, + "latitude": 42.168248021, + "longitude": -8.692608608, + "lines": [ + "A", + "U1" + ] + }, + { + "stopId": 3870, + "name": { + "original": "Rúa do Falcoído 13" + }, + "latitude": 42.182749988, + "longitude": -8.699953254, + "lines": [ + "A" + ] + }, + { + "stopId": 3880, + "name": { + "original": "Estrada da Coutada 44" + }, + "latitude": 42.194829735, + "longitude": -8.699040324, + "lines": [ + "6" + ] + }, + { + "stopId": 3890, + "name": { + "original": "Estrada da Coutada 39" + }, + "latitude": 42.193625246, + "longitude": -8.7014263, + "lines": [ + "6", + "27" + ] + }, + { + "stopId": 3900, + "name": { + "original": "Estrada da Coutada 19" + }, + "latitude": 42.19232927, + "longitude": -8.704749414, + "lines": [ + "6", + "27" + ] + }, + { + "stopId": 3910, + "name": { + "original": "Estrada da Coutada 68" + }, + "latitude": 42.195404022, + "longitude": -8.695794851, + "lines": [ + "6" + ] + }, + { + "stopId": 3920, + "name": { + "original": "Estrada da Coutada 65" + }, + "latitude": 42.195725689, + "longitude": -8.697154293, + "lines": [ + "6", + "27" + ] + }, + { + "stopId": 3930, + "name": { + "original": "Estrada da Coutada 12" + }, + "latitude": 42.19287831, + "longitude": -8.703506202, + "lines": [ + "6", + "27" + ] + }, + { + "stopId": 3940, + "name": { + "original": "Estrada de Casás 83" + }, + "latitude": 42.196165214, + "longitude": -8.759890011, + "lines": [ + "29" + ] + }, + { + "stopId": 3950, + "name": { + "original": "Estrada de Casás (cruce Camiño do Rial)" + }, + "latitude": 42.196014193, + "longitude": -8.759919516, + "lines": [ + "29" + ] + }, + { + "stopId": 3960, + "name": { + "original": "Baixada do Castelo" + }, + "latitude": 42.213984907, + "longitude": -8.682160511, + "lines": [ + "12A", + "12B", + "13", + "15B", + "15C", + "31" + ] + }, + { + "stopId": 3970, + "name": { + "original": "Estrada Vella de Madrid 190" + }, + "latitude": 42.215872123, + "longitude": -8.679765298, + "lines": [ + "12B", + "15B", + "15C", + "U2" + ] + }, + { + "stopId": 3980, + "name": { + "original": "Estrada Vella de Madrid (cruce Hospital)" + }, + "latitude": 42.21620386, + "longitude": -8.681570425, + "lines": [ + "12A", + "12B", + "13", + "15B", + "15C", + "31", + "U2" + ] + }, + { + "stopId": 4000, + "name": { + "original": "Estrada de Fragoselo 143" + }, + "latitude": 42.182434997, + "longitude": -8.764713761, + "lines": [ + "29" + ] + }, + { + "stopId": 4010, + "name": { + "original": "Estrada de Fragoselo 170" + }, + "latitude": 42.184148566, + "longitude": -8.767237312, + "lines": [ + "29" + ] + }, + { + "stopId": 4020, + "name": { + "original": "Estrada de Fragoselo 79" + }, + "latitude": 42.187056187, + "longitude": -8.769605703, + "lines": [ + "29" + ] + }, + { + "stopId": 4030, + "name": { + "original": "Estrada de Fragoselo 111" + }, + "latitude": 42.184118753, + "longitude": -8.767049558, + "lines": [ + "29" + ] + }, + { + "stopId": 4040, + "name": { + "original": "Estrada de Fragoselo 108" + }, + "latitude": 42.18661248, + "longitude": -8.769574881, + "lines": [ + "29" + ] + }, + { + "stopId": 4050, + "name": { + "original": "Estrada de Fragoselo 196" + }, + "latitude": 42.182111026, + "longitude": -8.76479691, + "lines": [ + "29" + ] + }, + { + "stopId": 4060, + "name": { + "original": "Estrada da Gándara 7" + }, + "latitude": 42.164326088, + "longitude": -8.716892619, + "lines": [ + "7" + ] + }, + { + "stopId": 4070, + "name": { + "original": "Estrada da Gándara 55" + }, + "latitude": 42.162254659, + "longitude": -8.713740793, + "lines": [ + "7" + ] + }, + { + "stopId": 4080, + "name": { + "original": "Estrada da Gándara 48" + }, + "latitude": 42.162252671, + "longitude": -8.71400365, + "lines": [ + "7" + ] + }, + { + "stopId": 4090, + "name": { + "original": "Estrada da Garrida 124" + }, + "latitude": 42.170369621, + "longitude": -8.708506123, + "lines": [ + "7" + ] + }, + { + "stopId": 4100, + "name": { + "original": "Estrada da Garrida 199" + }, + "latitude": 42.16978602, + "longitude": -8.708967287, + "lines": [ + "7" + ] + }, + { + "stopId": 4110, + "name": { + "original": "Estrada da Garrida 40" + }, + "latitude": 42.165331611, + "longitude": -8.714862589, + "lines": [ + "7" + ] + }, + { + "stopId": 4120, + "name": { + "original": "Estrada da Garrida 84" + }, + "latitude": 42.166399713, + "longitude": -8.711237684, + "lines": [ + "7" + ] + }, + { + "stopId": 4130, + "name": { + "original": "Estrada da Garrida 83" + }, + "latitude": 42.16561193, + "longitude": -8.714589004, + "lines": [ + "7" + ] + }, + { + "stopId": 4140, + "name": { + "original": "Estrada da Garrida (frente 80)" + }, + "latitude": 42.166208944, + "longitude": -8.711992518, + "lines": [ + "7" + ] + }, + { + "stopId": 4150, + "name": { + "original": "Estrada de Miraflores 69" + }, + "latitude": 42.217620909, + "longitude": -8.712429612, + "lines": [ + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 4160, + "name": { + "original": "Estrada de Miraflores 36" + }, + "latitude": 42.217849364, + "longitude": -8.710994711, + "lines": [ + "18A" + ] + }, + { + "stopId": 4170, + "name": { + "original": "Estrada de Miraflores 64" + }, + "latitude": 42.217345186, + "longitude": -8.713011334, + "lines": [ + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 4200, + "name": { + "original": "Estrada de Moledo 6" + }, + "latitude": 42.215236994, + "longitude": -8.707384971, + "lines": [ + "14", + "18A" + ] + }, + { + "stopId": 4210, + "name": { + "original": "Estrada de Moledo 42" + }, + "latitude": 42.212141078, + "longitude": -8.704563545, + "lines": [ + "14", + "18A" + ] + }, + { + "stopId": 4220, + "name": { + "original": "Estrada de Moledo 22" + }, + "latitude": 42.213737557, + "longitude": -8.706283115, + "lines": [ + "14", + "18A" + ] + }, + { + "stopId": 4230, + "name": { + "original": "Estrada de Moledo 1" + }, + "latitude": 42.215373761, + "longitude": -8.707378349, + "lines": [ + "14", + "18A" + ] + }, + { + "stopId": 4240, + "name": { + "original": "Estrada de Moledo 73" + }, + "latitude": 42.212378349, + "longitude": -8.704729584, + "lines": [ + "14", + "18A" + ] + }, + { + "stopId": 4250, + "name": { + "original": "Estrada de Moledo 25" + }, + "latitude": 42.213377597, + "longitude": -8.70601168, + "lines": [ + "14", + "18A" + ] + }, + { + "stopId": 4280, + "name": { + "original": "Rúa de Emilia Pardo Bazán 80" + }, + "latitude": 42.224507337, + "longitude": -8.713465538, + "lines": [ + "14", + "18B", + "18H" + ] + }, + { + "stopId": 4290, + "name": { + "original": "Rúa de Emilia Pardo Bazán 3" + }, + "latitude": 42.227785739, + "longitude": -8.719460889, + "lines": [ + "14", + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 4300, + "name": { + "original": "Rúa de Emilia Pardo Bazán 104" + }, + "latitude": 42.22278924, + "longitude": -8.711754289, + "lines": [ + "14", + "18B", + "18H" + ] + }, + { + "stopId": 4310, + "name": { + "original": "Rúa de Emilia Pardo Bazán 111" + }, + "latitude": 42.222713762, + "longitude": -8.711555806, + "lines": [ + "14", + "18B", + "18H" + ] + }, + { + "stopId": 4320, + "name": { + "original": "Rúa de Emilia Pardo Bazán 2" + }, + "latitude": 42.227716225, + "longitude": -8.719750568, + "lines": [ + "14", + "18B", + "18H" + ] + }, + { + "stopId": 4330, + "name": { + "original": "Rúa de Emilia Pardo Bazán (cruce Baixada á Salgueira)" + }, + "latitude": 42.226463146, + "longitude": -8.71614062, + "lines": [ + "14", + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 4340, + "name": { + "original": "Rúa de Emilia Pardo Bazán 54" + }, + "latitude": 42.226112503, + "longitude": -8.715718376, + "lines": [ + "14", + "18B", + "18H" + ] + }, + { + "stopId": 4350, + "name": { + "original": "Rúa de Emilia Pardo Bazán 43" + }, + "latitude": 42.224562952, + "longitude": -8.713390437, + "lines": [ + "14", + "18B", + "18H" + ] + }, + { + "stopId": 4440, + "name": { + "original": "Estrada de San Xoán 169" + }, + "latitude": 42.183275038, + "longitude": -8.742437444, + "lines": [ + "17" + ] + }, + { + "stopId": 4450, + "name": { + "original": "Estrada de San Xoán 61" + }, + "latitude": 42.185081179, + "longitude": -8.748029634, + "lines": [ + "17" + ] + }, + { + "stopId": 4460, + "name": { + "original": "Estrada de San Xoán 141" + }, + "latitude": 42.18366712, + "longitude": -8.744402777, + "lines": [ + "17" + ] + }, + { + "stopId": 4490, + "name": { + "original": "Rúa de Manuel Lago Lago (fronte Colexio)" + }, + "latitude": 42.187522648, + "longitude": -8.772977937, + "lines": [ + "29" + ] + }, + { + "stopId": 4500, + "name": { + "original": "Rúa de Manuel Lago Lago 20" + }, + "latitude": 42.188761213, + "longitude": -8.775973652, + "lines": [ + "29" + ] + }, + { + "stopId": 4510, + "name": { + "original": "Rúa de Manuel Lago Lago (Colexio)" + }, + "latitude": 42.187542924, + "longitude": -8.772887753, + "lines": [ + "29" + ] + }, + { + "stopId": 4520, + "name": { + "original": "Estrada das Plantas (Cidade Deportiva)" + }, + "latitude": 42.175884385, + "longitude": -8.670789023, + "lines": [ + "15C" + ] + }, + { + "stopId": 4530, + "name": { + "original": "Estrada das Plantas (fronte cruce Camiño do Pouso)" + }, + "latitude": 42.199681015, + "longitude": -8.668860289, + "lines": [ + "15C" + ] + }, + { + "stopId": 4540, + "name": { + "original": "Estrada das Plantas (fronte Viveiros)" + }, + "latitude": 42.181370416, + "longitude": -8.667861084, + "lines": [ + "15C" + ] + }, + { + "stopId": 4550, + "name": { + "original": "Estrada das Plantas (cruce Camiño do Pouso)" + }, + "latitude": 42.199945182, + "longitude": -8.669085873, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 4560, + "name": { + "original": "Estrada de Valadares 233" + }, + "latitude": 42.177017792, + "longitude": -8.721519832, + "lines": [ + "7" + ] + }, + { + "stopId": 4570, + "name": { + "original": "Estrada de Valadares 100" + }, + "latitude": 42.183987864, + "longitude": -8.724154939, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 4580, + "name": { + "original": "Estrada de Valadares 146" + }, + "latitude": 42.180249473, + "longitude": -8.721850007, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 4590, + "name": { + "original": "Estrada de Valadares 173" + }, + "latitude": 42.180670846, + "longitude": -8.721533506, + "lines": [ + "7" + ] + }, + { + "stopId": 4600, + "name": { + "original": "Estrada de Valadares 212" + }, + "latitude": 42.176419487, + "longitude": -8.72197849, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 4610, + "name": { + "original": "Estrada de Valadares 262" + }, + "latitude": 42.172481228, + "longitude": -8.723905842, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 4620, + "name": { + "original": "Estrada de Valadares 329" + }, + "latitude": 42.172330151, + "longitude": -8.723766367, + "lines": [ + "7" + ] + }, + { + "stopId": 4630, + "name": { + "original": "Estrada de Valadares 406" + }, + "latitude": 42.165721529, + "longitude": -8.720146278, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 4640, + "name": { + "original": "Estrada de Valadares (cruce Camiño do Canizo)" + }, + "latitude": 42.18659932, + "longitude": -8.719619913, + "lines": [ + "7" + ] + }, + { + "stopId": 4650, + "name": { + "original": "Estrada de Valadares 48" + }, + "latitude": 42.186641056, + "longitude": -8.719853265, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 4660, + "name": { + "original": "Estrada de Valadares 99" + }, + "latitude": 42.183997801, + "longitude": -8.723857214, + "lines": [ + "7" + ] + }, + { + "stopId": 4670, + "name": { + "original": "Estrada do Vao 27" + }, + "latitude": 42.193836069, + "longitude": -8.776441689, + "lines": [ + "11" + ] + }, + { + "stopId": 4680, + "name": { + "original": "Estrada do Vao 116" + }, + "latitude": 42.19429691, + "longitude": -8.786574405, + "lines": [ + "11" + ] + }, + { + "stopId": 4690, + "name": { + "original": "Estrada do Vao 153" + }, + "latitude": 42.196307191, + "longitude": -8.790777973, + "lines": [ + "11" + ] + }, + { + "stopId": 4700, + "name": { + "original": "Estrada do Vao 46" + }, + "latitude": 42.194014721, + "longitude": -8.777055245, + "lines": [ + "11" + ] + }, + { + "stopId": 4710, + "name": { + "original": "Estrada do Vao 65" + }, + "latitude": 42.194064592, + "longitude": -8.781224067, + "lines": [ + "11" + ] + }, + { + "stopId": 4720, + "name": { + "original": "Estrada do Vao 90" + }, + "latitude": 42.193937416, + "longitude": -8.781634173, + "lines": [ + "11" + ] + }, + { + "stopId": 4730, + "name": { + "original": "Estrada do Vao 91" + }, + "latitude": 42.19405266, + "longitude": -8.78551292, + "lines": [ + "11" + ] + }, + { + "stopId": 4740, + "name": { + "original": "Estrada do Vao (Praia do Vao)" + }, + "latitude": 42.196595321, + "longitude": -8.791019372, + "lines": [ + "11" + ] + }, + { + "stopId": 4750, + "name": { + "original": "Estrada Vella de Madrid 6" + }, + "latitude": 42.213983883, + "longitude": -8.697464269, + "lines": [ + "12A", + "12B", + "13", + "U2", + "H3" + ] + }, + { + "stopId": 4760, + "name": { + "original": "Estrada Vella de Madrid 34" + }, + "latitude": 42.216359908, + "longitude": -8.693040769, + "lines": [ + "12A", + "12B", + "13", + "U2", + "H3" + ] + }, + { + "stopId": 4770, + "name": { + "original": "Estrada Vella de Madrid 104" + }, + "latitude": 42.219822923, + "longitude": -8.684198247, + "lines": [ + "12A", + "12B", + "13", + "31", + "U2" + ] + }, + { + "stopId": 4780, + "name": { + "original": "Estrada Vella de Madrid 136" + }, + "latitude": 42.220845201, + "longitude": -8.680581909, + "lines": [ + "12A", + "12B", + "13", + "31", + "U2" + ] + }, + { + "stopId": 4790, + "name": { + "original": "Estrada Vella de Madrid 123" + }, + "latitude": 42.220436017, + "longitude": -8.683690589, + "lines": [ + "12A", + "12B", + "13", + "31" + ] + }, + { + "stopId": 4800, + "name": { + "original": "Estrada Vella de Madrid 160" + }, + "latitude": 42.218049288, + "longitude": -8.679899408, + "lines": [ + "12A", + "12B", + "13", + "31", + "U2" + ] + }, + { + "stopId": 4810, + "name": { + "original": "Estrada Vella de Madrid 177" + }, + "latitude": 42.21827574, + "longitude": -8.679588272, + "lines": [ + "12A", + "12B", + "13", + "31" + ] + }, + { + "stopId": 4820, + "name": { + "original": "Estrada Vella de Madrid 31" + }, + "latitude": 42.216687676, + "longitude": -8.693917852, + "lines": [ + "12A", + "12B", + "13", + "H3" + ] + }, + { + "stopId": 4830, + "name": { + "original": "Estrada Vella de Madrid 81" + }, + "latitude": 42.218719793, + "longitude": -8.690012555, + "lines": [ + "12A", + "12B", + "13", + "H3" + ] + }, + { + "stopId": 4840, + "name": { + "original": "Estrada Vella de Madrid 76" + }, + "latitude": 42.218745617, + "longitude": -8.689009409, + "lines": [ + "12A", + "12B", + "13", + "U2", + "H3" + ] + }, + { + "stopId": 4850, + "name": { + "original": "Estrada Vella de Madrid (frente Centro Comercial)" + }, + "latitude": 42.216448197, + "longitude": -8.68163748, + "lines": [ + "12A", + "13", + "31" + ] + }, + { + "stopId": 4860, + "name": { + "original": "Estrada da Venda (cruce Camiño da Coutadiña)" + }, + "latitude": 42.182744465, + "longitude": -8.70286123, + "lines": [ + "A", + "6" + ] + }, + { + "stopId": 4870, + "name": { + "original": "Estrada da Venda 5" + }, + "latitude": 42.192029809, + "longitude": -8.712623715, + "lines": [ + "A", + "27", + "H3" + ] + }, + { + "stopId": 4880, + "name": { + "original": "Estrada da Venda 240" + }, + "latitude": 42.188021902, + "longitude": -8.711457595, + "lines": [ + "A", + "H3" + ] + }, + { + "stopId": 4890, + "name": { + "original": "Estrada da Venda 238" + }, + "latitude": 42.186610014, + "longitude": -8.710023944, + "lines": [ + "A", + "6" + ] + }, + { + "stopId": 4900, + "name": { + "original": "Estrada da Venda 35" + }, + "latitude": 42.188304845, + "longitude": -8.711474749, + "lines": [ + "A", + "27", + "H3" + ] + }, + { + "stopId": 4910, + "name": { + "original": "Estrada da Venda 4" + }, + "latitude": 42.19205763, + "longitude": -8.712722956, + "lines": [ + "A", + "H3" + ] + }, + { + "stopId": 4920, + "name": { + "original": "Estrada da Venda 49" + }, + "latitude": 42.186610342, + "longitude": -8.709937804, + "lines": [ + "A", + "6" + ] + }, + { + "stopId": 4930, + "name": { + "original": "Travesía da Devesa (Asociación Veciños)" + }, + "latitude": 42.246018558, + "longitude": -8.669287042, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 4940, + "name": { + "original": "Camiño da Devesa (fronte 55)" + }, + "latitude": 42.245450719, + "longitude": -8.672406783, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 4960, + "name": { + "original": "Rúa do Doutor Corbal 135" + }, + "latitude": 42.256210875, + "longitude": -8.696882723, + "lines": [ + "17" + ] + }, + { + "stopId": 4970, + "name": { + "original": "Rúa do Doutor Corbal 126" + }, + "latitude": 42.255883312, + "longitude": -8.696812986, + "lines": [ + "17" + ] + }, + { + "stopId": 4980, + "name": { + "original": "Rúa do Doutor Corbal 149" + }, + "latitude": 42.257539061, + "longitude": -8.697019814, + "lines": [ + "17" + ] + }, + { + "stopId": 5000, + "name": { + "original": "Rúa do Doutor Corbal 6" + }, + "latitude": 42.250121395, + "longitude": -8.696122376, + "lines": [ + "17" + ] + }, + { + "stopId": 5010, + "name": { + "original": "Rúa do Doutor Corbal 95" + }, + "latitude": 42.254169539, + "longitude": -8.697752273, + "lines": [ + "17" + ] + }, + { + "stopId": 5020, + "name": { + "original": "Rúa do Doutor Corbal 94" + }, + "latitude": 42.254104511, + "longitude": -8.697655199, + "lines": [ + "17" + ] + }, + { + "stopId": 5030, + "name": { + "original": "Avda. de Redondela (fronte 28)" + }, + "latitude": 42.272502528, + "longitude": -8.664787252, + "lines": [ + "C3i" + ] + }, + { + "stopId": 5040, + "name": { + "original": "Rúa da Salgueira Entrada 5" + }, + "latitude": 42.222543586, + "longitude": -8.717809812, + "lines": [ + "18A" + ] + }, + { + "stopId": 5060, + "name": { + "original": "Estadio de Balaídos (Avda. do Fragoso)" + }, + "latitude": 42.212676247, + "longitude": -8.739585545, + "lines": [ + "16", + "23", + "N4" + ] + }, + { + "stopId": 5070, + "name": { + "original": "Rúa da Estrada 10-12" + }, + "latitude": 42.220535836, + "longitude": -8.74141599, + "lines": [ + "C3i", + "5B" + ] + }, + { + "stopId": 5090, + "name": { + "original": "Rúa da Estrada 1" + }, + "latitude": 42.220359068, + "longitude": -8.738861999, + "lines": [ + "C3i", + "5B" + ] + }, + { + "stopId": 5120, + "name": { + "original": "Camiño da Falcoa 41" + }, + "latitude": 42.204935234, + "longitude": -8.722453969, + "lines": [ + "18B", + "18H", + "27" + ] + }, + { + "stopId": 5140, + "name": { + "original": "Camiño da Falcoa 15" + }, + "latitude": 42.207336295, + "longitude": -8.72129506, + "lines": [ + "18B", + "18H" + ] + }, + { + "stopId": 5160, + "name": { + "original": "Camiño da Falcoa 26" + }, + "latitude": 42.204783634, + "longitude": -8.722664062, + "lines": [ + "18B", + "18H", + "27" + ] + }, + { + "stopId": 5170, + "name": { + "original": "Rúa das Figueiras (Praza da Feira)" + }, + "latitude": 42.227529644, + "longitude": -8.66169041, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5180, + "name": { + "original": "Rúa das Figueiras 96" + }, + "latitude": 42.224562288, + "longitude": -8.66579419, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5190, + "name": { + "original": "Rúa das Figueiras 124" + }, + "latitude": 42.226051942, + "longitude": -8.663629647, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5200, + "name": { + "original": "Rúa das Figueiras 138" + }, + "latitude": 42.227533616, + "longitude": -8.661561664, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5220, + "name": { + "original": "Rúa das Figueiras 190" + }, + "latitude": 42.228984217, + "longitude": -8.658438326, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5230, + "name": { + "original": "Rúa das Figueiras 254" + }, + "latitude": 42.230261894, + "longitude": -8.653683012, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5250, + "name": { + "original": "Rúa das Figueiras 29" + }, + "latitude": 42.223048763, + "longitude": -8.667374011, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5260, + "name": { + "original": "Rúa das Figueiras 22" + }, + "latitude": 42.222838218, + "longitude": -8.667795118, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5270, + "name": { + "original": "Rúa das Figueiras 65" + }, + "latitude": 42.224367639, + "longitude": -8.665989991, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5280, + "name": { + "original": "Rúa das Figueiras 113" + }, + "latitude": 42.225940716, + "longitude": -8.663830813, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 5290, + "name": { + "original": "Avda. da Florida 60" + }, + "latitude": 42.215060936, + "longitude": -8.741309568, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5300, + "name": { + "original": "Avda. da Florida 117" + }, + "latitude": 42.214827343, + "longitude": -8.741319027, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5310, + "name": { + "original": "Avda. da Florida 140" + }, + "latitude": 42.208024308, + "longitude": -8.750412985, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5320, + "name": { + "original": "Avda. da Florida 145" + }, + "latitude": 42.213244058, + "longitude": -8.743657913, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5330, + "name": { + "original": "Avda. da Florida 3" + }, + "latitude": 42.220228436, + "longitude": -8.733426296, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5340, + "name": { + "original": "Avda. da Florida 197" + }, + "latitude": 42.208621114, + "longitude": -8.749572184, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5350, + "name": { + "original": "Avda. da Florida 40" + }, + "latitude": 42.216779248, + "longitude": -8.738705143, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5360, + "name": { + "original": "Avda. da Florida 70" + }, + "latitude": 42.212804215, + "longitude": -8.744506761, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5370, + "name": { + "original": "Avda. da Florida 69" + }, + "latitude": 42.216928527, + "longitude": -8.738268035, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5380, + "name": { + "original": "Avda. da Florida 8" + }, + "latitude": 42.219743053, + "longitude": -8.734322187, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 5390, + "name": { + "original": "Estrada de Fragoselo (cruce Camiño Río da Barxa)" + }, + "latitude": 42.179556959, + "longitude": -8.761854527, + "lines": [ + "29" + ] + }, + { + "stopId": 5400, + "name": { + "original": "Avda. do Fragoso 95" + }, + "latitude": 42.213518168, + "longitude": -8.737719785, + "lines": [ + "7", + "12B", + "17", + "N4", + "H1" + ] + }, + { + "stopId": 5410, + "name": { + "original": "Avda. do Fragoso 12" + }, + "latitude": 42.219689698, + "longitude": -8.733384686, + "lines": [ + "A", + "16", + "23", + "N4", + "U1", + "H1", + "H", + "LZH", + "PSA 1" + ] + }, + { + "stopId": 5420, + "name": { + "original": "Avda. do Fragoso 3" + }, + "latitude": 42.220297406, + "longitude": -8.732924981, + "lines": [ + "7", + "12B", + "17", + "N4", + "H1" + ] + }, + { + "stopId": 5430, + "name": { + "original": "Avda. do Fragoso 36" + }, + "latitude": 42.217381871, + "longitude": -8.734669814, + "lines": [ + "A", + "16", + "23", + "N4", + "U1", + "H1", + "H", + "LZH", + "PSA 1" + ] + }, + { + "stopId": 5440, + "name": { + "original": "Avda. do Fragoso 47" + }, + "latitude": 42.217288508, + "longitude": -8.73454375, + "lines": [ + "7", + "12B", + "17", + "N4", + "H1" + ] + }, + { + "stopId": 5450, + "name": { + "original": "Avda. do Fragoso 54" + }, + "latitude": 42.215348678, + "longitude": -8.736273638, + "lines": [ + "A", + "16", + "23", + "N4", + "U1", + "H1", + "H", + "LZH", + "PSA 1" + ] + }, + { + "stopId": 5460, + "name": { + "original": "Avda. do Fragoso 71" + }, + "latitude": 42.215301002, + "longitude": -8.736123434, + "lines": [ + "7", + "12B", + "17", + "N4", + "H1" + ] + }, + { + "stopId": 5470, + "name": { + "original": "Avda. do Fragoso 86" + }, + "latitude": 42.21315264, + "longitude": -8.738470803, + "lines": [ + "A", + "16", + "23", + "N4", + "U1", + "H1", + "H", + "LZH", + "PSA 1" + ] + }, + { + "stopId": 5480, + "name": { + "original": "Estrada de San Xoán 25" + }, + "latitude": 42.186179757, + "longitude": -8.748888329, + "lines": [ + "17" + ] + }, + { + "stopId": 5490, + "name": { + "original": "Avda. de García Barbón (fronte 120)" + }, + "latitude": 42.241557555, + "longitude": -8.707094861, + "lines": [ + "C3i", + "5B", + "10", + "17", + "N1", + "H3" + ] + }, + { + "stopId": 5500, + "name": { + "original": "Avda. de García Barbón 126" + }, + "latitude": 42.24178025, + "longitude": -8.706720936, + "lines": [ + "C3d", + "5B", + "10", + "17", + "31", + "U2", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 5510, + "name": { + "original": "Avda. de García Barbón 127" + }, + "latitude": 42.238290358, + "longitude": -8.71014103, + "lines": [ + "C3i", + "5B", + "10", + "17", + "N1" + ] + }, + { + "stopId": 5520, + "name": { + "original": "Avda. de García Barbón 7" + }, + "latitude": 42.237485586, + "longitude": -8.719397801, + "lines": [ + "C3i", + "A", + "4A", + "4C", + "5B", + "6", + "7", + "9B", + "10", + "12B", + "14", + "16", + "17", + "18A", + "18B", + "18H", + "28", + "N1", + "N4", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 5530, + "name": { + "original": "Avda. de García Barbón 18" + }, + "latitude": 42.23720456, + "longitude": -8.718680736, + "lines": [ + "C3d", + "5B", + "10", + "17", + "H2", + "PSA 1" + ] + }, + { + "stopId": 5540, + "name": { + "original": "Avda. de García Barbón 28" + }, + "latitude": 42.236759685, + "longitude": -8.716384581, + "lines": [ + "C3d", + "A", + "5B", + "10", + "16", + "17", + "24", + "H2", + "PSA 1" + ] + }, + { + "stopId": 5560, + "name": { + "original": "Avda. de García Barbón 60" + }, + "latitude": 42.236896919, + "longitude": -8.712902905, + "lines": [ + "C3d", + "A", + "5B", + "10", + "16", + "17", + "24", + "H2", + "PSA 1" + ] + }, + { + "stopId": 5570, + "name": { + "original": "Avda. de García Barbón 87" + }, + "latitude": 42.237003397, + "longitude": -8.713586994, + "lines": [ + "C3i", + "5B", + "10", + "17", + "N1" + ] + }, + { + "stopId": 5580, + "name": { + "original": "Avda. de García Barbón 90" + }, + "latitude": 42.238267348, + "longitude": -8.709873166, + "lines": [ + "C3d", + "5B", + "10", + "17", + "H2", + "PSA 1" + ] + }, + { + "stopId": 5590, + "name": { + "original": "Avda. da Ponte (Grupo S. Gorxal)" + }, + "latitude": 42.213057463, + "longitude": -8.670479203, + "lines": [ + "12B", + "15B", + "15C" + ] + }, + { + "stopId": 5600, + "name": { + "original": "Avda. da Gran Vía 107" + }, + "latitude": 42.225140059, + "longitude": -8.72184818, + "lines": [ + "C3i", + "7", + "11", + "13", + "15A", + "16", + "23", + "29", + "H2" + ] + }, + { + "stopId": 5610, + "name": { + "original": "Avda. da Gran Vía 12" + }, + "latitude": 42.233503531, + "longitude": -8.717236739, + "lines": [ + "C1", + "4A", + "4C", + "5B", + "7", + "12B", + "14", + "16", + "17", + "18A", + "18B", + "18H", + "PSA 4" + ] + }, + { + "stopId": 5620, + "name": { + "original": "Avda. da Gran Vía 148" + }, + "latitude": 42.222321607, + "longitude": -8.726440421, + "lines": [ + "C3d", + "13", + "15A", + "23", + "29", + "U1", + "H2", + "PSA 1" + ] + }, + { + "stopId": 5630, + "name": { + "original": "Avda. da Gran Vía 147" + }, + "latitude": 42.222790356, + "longitude": -8.724940076, + "lines": [ + "C3i", + "7", + "11", + "13", + "15A", + "16", + "23", + "29", + "U2", + "H2" + ] + }, + { + "stopId": 5640, + "name": { + "original": "Avda. da Gran Vía 176" + }, + "latitude": 42.220868033, + "longitude": -8.730264447, + "lines": [ + "C3d", + "13", + "15A", + "23", + "29", + "U2", + "H2", + "PSA 1" + ] + }, + { + "stopId": 5650, + "name": { + "original": "Avda. da Gran Vía 185" + }, + "latitude": 42.220971136, + "longitude": -8.729196245, + "lines": [ + "C3i", + "7", + "11", + "13", + "15A", + "16", + "23", + "29", + "H2" + ] + }, + { + "stopId": 5660, + "name": { + "original": "Avda. da Gran Vía 19" + }, + "latitude": 42.232957918, + "longitude": -8.717215735, + "lines": [ + "4A", + "4C", + "5B", + "7", + "11", + "12B", + "14", + "16", + "17", + "18A", + "18B", + "18H", + "N1" + ] + }, + { + "stopId": 5670, + "name": { + "original": "Avda. da Gran Vía 46" + }, + "latitude": 42.230988893, + "longitude": -8.71867283, + "lines": [ + "C1", + "12A", + "12B", + "14", + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 5680, + "name": { + "original": "Avda. da Gran Vía 66" + }, + "latitude": 42.228173802, + "longitude": -8.720267623, + "lines": [ + "C3d", + "13", + "15A", + "23", + "29", + "H2", + "PSA 1" + ] + }, + { + "stopId": 5690, + "name": { + "original": "Avda. da Gran Vía 85" + }, + "latitude": 42.226868266, + "longitude": -8.720637433, + "lines": [ + "C3i", + "7", + "11", + "13", + "15A", + "16", + "23", + "29", + "H2" + ] + }, + { + "stopId": 5700, + "name": { + "original": "Avda. da Gran Vía 104" + }, + "latitude": 42.225325884, + "longitude": -8.722106624, + "lines": [ + "C3d", + "13", + "15A", + "23", + "29", + "H2", + "PSA 1" + ] + }, + { + "stopId": 5710, + "name": { + "original": "Avda. do Alcalde Gregorio Espino 22" + }, + "latitude": 42.23003666347398, + "longitude": -8.707266671978003, + "lines": [ + "31" + ] + }, + { + "stopId": 5720, + "name": { + "original": "Avda. do Alcalde Gregorio Espino 33" + }, + "latitude": 42.23004933454558, + "longitude": -8.706947409683313, + "lines": [ + "4C", + "23", + "31", + "H2", + "PSA 4" + ] + }, + { + "stopId": 5730, + "name": { + "original": "Avda. do Alcalde Gregorio Espino 44" + }, + "latitude": 42.227850036119314, + "longitude": -8.708105429626789, + "lines": [ + "31", + "H2" + ] + }, + { + "stopId": 5740, + "name": { + "original": "Avda. do Alcalde Gregorio Espino 57" + }, + "latitude": 42.22783722597372, + "longitude": -8.707849091551859, + "lines": [ + "4C", + "23", + "31", + "N4", + "H2", + "PSA 4" + ] + }, + { + "stopId": 5750, + "name": { + "original": "Avda. do Alcalde Gregorio Espino 79" + }, + "latitude": 42.225785485, + "longitude": -8.708786105, + "lines": [ + "4C", + "23", + "31", + "N4", + "H2", + "PSA 4" + ] + }, + { + "stopId": 5760, + "name": { + "original": "Estrada de Valadares 377" + }, + "latitude": 42.16929549, + "longitude": -8.723249687, + "lines": [ + "7" + ] + }, + { + "stopId": 5770, + "name": { + "original": "Estrada de Valadares 310" + }, + "latitude": 42.16911061, + "longitude": -8.723904146, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 5790, + "name": { + "original": "Hospital do Meixoeiro" + }, + "latitude": 42.214534062, + "longitude": -8.684756053, + "lines": [ + "12A", + "12B", + "13", + "15B", + "15C", + "31" + ] + }, + { + "stopId": 5800, + "name": { + "original": "Rúa de Jenaro de la Fuente 29" + }, + "latitude": 42.232202275, + "longitude": -8.703792246, + "lines": [ + "A", + "4A", + "6", + "9B", + "11", + "15A", + "15B", + "15C", + "24", + "25", + "27", + "28" + ] + }, + { + "stopId": 5810, + "name": { + "original": "Rúa de Jenaro de la Fuente 10" + }, + "latitude": 42.232258514, + "longitude": -8.705770621, + "lines": [ + "A", + "4A", + "4C", + "6", + "9B", + "11", + "15A", + "15B", + "15C", + "23", + "24", + "25", + "27", + "28", + "N4", + "PSA 4" + ] + }, + { + "stopId": 5820, + "name": { + "original": "Rúa de Jenaro de la Fuente 22" + }, + "latitude": 42.232042043, + "longitude": -8.703616807, + "lines": [ + "A", + "4A", + "4C", + "6", + "9B", + "11", + "15A", + "15B", + "15C", + "23", + "24", + "25", + "27", + "28", + "N4", + "PSA 4" + ] + }, + { + "stopId": 5830, + "name": { + "original": "Rúa de Jenaro de la Fuente 11" + }, + "latitude": 42.23238699, + "longitude": -8.705610784, + "lines": [ + "A", + "4A", + "6", + "9B", + "11", + "15A", + "15B", + "15C", + "24", + "25", + "27", + "28" + ] + }, + { + "stopId": 5840, + "name": { + "original": "Rúa da Lagoa (cruce Rúa do Balde)" + }, + "latitude": 42.201360896, + "longitude": -8.702877394, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 5850, + "name": { + "original": "Rúa da Lagoa (fronte 21)" + }, + "latitude": 42.201154253, + "longitude": -8.702343635, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 5860, + "name": { + "original": "Baixada á Laxe (Centro Saúde)" + }, + "latitude": 42.21669522, + "longitude": -8.715884298, + "lines": [ + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 5870, + "name": { + "original": "Rúa de López Mora 10" + }, + "latitude": 42.226432697, + "longitude": -8.731262013, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 5880, + "name": { + "original": "Rúa de López Mora 19" + }, + "latitude": 42.226800566, + "longitude": -8.731799623, + "lines": [ + "5A", + "5B", + "12A" + ] + }, + { + "stopId": 5890, + "name": { + "original": "Rúa de López Mora 84" + }, + "latitude": 42.222420533, + "longitude": -8.731996938, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 5900, + "name": { + "original": "Rúa de Macal 8" + }, + "latitude": 42.202071034, + "longitude": -8.723541884, + "lines": [ + "18B", + "18H", + "27" + ] + }, + { + "stopId": 5910, + "name": { + "original": "Rúa de Macal 90" + }, + "latitude": 42.196213336, + "longitude": -8.721136467, + "lines": [ + "18B", + "18H", + "27" + ] + }, + { + "stopId": 5920, + "name": { + "original": "Rúa de Macal (cruce Rúa de Ramiro Pascual)" + }, + "latitude": 42.196173594, + "longitude": -8.721023814, + "lines": [ + "18B", + "18H", + "27" + ] + }, + { + "stopId": 5930, + "name": { + "original": "Rúa de Macal (frente 8)" + }, + "latitude": 42.202050775, + "longitude": -8.723454133, + "lines": [ + "18B", + "18H", + "27" + ] + }, + { + "stopId": 5940, + "name": { + "original": "Rúa de Macal 39" + }, + "latitude": 42.198347336, + "longitude": -8.721488003, + "lines": [ + "18B", + "18H", + "27" + ] + }, + { + "stopId": 5950, + "name": { + "original": "Rúa dos Mestres Goldar 62" + }, + "latitude": 42.207127325, + "longitude": -8.726636888, + "lines": [ + "27" + ] + }, + { + "stopId": 5960, + "name": { + "original": "Rúa dos Mestres Goldar 77" + }, + "latitude": 42.206757786, + "longitude": -8.730056705, + "lines": [ + "27" + ] + }, + { + "stopId": 5970, + "name": { + "original": "Rúa dos Mestres Goldar 96" + }, + "latitude": 42.206880283, + "longitude": -8.729978952, + "lines": [ + "27" + ] + }, + { + "stopId": 5980, + "name": { + "original": "Rúa dos Mestres Goldar 37" + }, + "latitude": 42.207198849, + "longitude": -8.726658346, + "lines": [ + "27" + ] + }, + { + "stopId": 6000, + "name": { + "original": "Rúa de Manuel Álvarez 185" + }, + "latitude": 42.220887532, + "longitude": -8.685059571, + "lines": [ + "31", + "H3" + ] + }, + { + "stopId": 6010, + "name": { + "original": "Rúa de Manuel Álvarez (cruce Camiño Sulevada)" + }, + "latitude": 42.223077231, + "longitude": -8.675499751, + "lines": [ + "25", + "31", + "H3" + ] + }, + { + "stopId": 6020, + "name": { + "original": "Rúa de Manuel Álvarez 58" + }, + "latitude": 42.223195307, + "longitude": -8.681872932, + "lines": [ + "25", + "31", + "H3" + ] + }, + { + "stopId": 6030, + "name": { + "original": "Rúa de Manuel Álvarez 102" + }, + "latitude": 42.220829925, + "longitude": -8.685158812, + "lines": [ + "31", + "H3" + ] + }, + { + "stopId": 6040, + "name": { + "original": "Rúa de Manuel Álvarez (fronte cruce Camiño Sulevada)" + }, + "latitude": 42.22320325, + "longitude": -8.675213007, + "lines": [ + "25", + "31", + "H3" + ] + }, + { + "stopId": 6050, + "name": { + "original": "Rúa de Manuel Cominges 22" + }, + "latitude": 42.19890849, + "longitude": -8.73623433, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 6060, + "name": { + "original": "Rúa de Manuel Cominges 135" + }, + "latitude": 42.196716802, + "longitude": -8.729966982, + "lines": [ + "12B" + ] + }, + { + "stopId": 6070, + "name": { + "original": "Rúa de Manuel Cominges 15" + }, + "latitude": 42.199197066, + "longitude": -8.736588816, + "lines": [ + "12B" + ] + }, + { + "stopId": 6080, + "name": { + "original": "Rúa de Manuel Cominges 64" + }, + "latitude": 42.197736144, + "longitude": -8.732267294, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 6090, + "name": { + "original": "Rúa de Manuel Cominges 77" + }, + "latitude": 42.197626151, + "longitude": -8.732546841, + "lines": [ + "12B" + ] + }, + { + "stopId": 6100, + "name": { + "original": "Rúa de Manuel Cominges 80" + }, + "latitude": 42.197066521, + "longitude": -8.730468609, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 6110, + "name": { + "original": "Camiño da Devesa 6" + }, + "latitude": 42.243941636, + "longitude": -8.669169025, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 6130, + "name": { + "original": "Estrada do Marco 105" + }, + "latitude": 42.207132591, + "longitude": -8.706967295, + "lines": [ + "18B", + "H3" + ] + }, + { + "stopId": 6140, + "name": { + "original": "Estrada do Marco (Colexio)" + }, + "latitude": 42.206925967, + "longitude": -8.707050443, + "lines": [ + "18B", + "H3" + ] + }, + { + "stopId": 6150, + "name": { + "original": "Estrada De Zamáns 233" + }, + "latitude": 42.160616846, + "longitude": -8.691088401, + "lines": [ + "7" + ] + }, + { + "stopId": 6160, + "name": { + "original": "Estrada De Zamáns 150" + }, + "latitude": 42.160635942, + "longitude": -8.69145083, + "lines": [ + "7" + ] + }, + { + "stopId": 6180, + "name": { + "original": "Rúa de Marín (fronte 30)" + }, + "latitude": 42.21850454, + "longitude": -8.753892634, + "lines": [ + "C3i", + "5B" + ] + }, + { + "stopId": 6187, + "name": { + "original": "Rúa de Martín Echegaray (Parque)" + }, + "latitude": 42.215244712, + "longitude": -8.74244225, + "lines": [ + "23", + "N4" + ] + }, + { + "stopId": 6200, + "name": { + "original": "Avda. de E. Martínez Garrido 11" + }, + "latitude": 42.229298043, + "longitude": -8.699760249, + "lines": [ + "6", + "25", + "31" + ] + }, + { + "stopId": 6210, + "name": { + "original": "Avda. de E. Martínez Garrido 16" + }, + "latitude": 42.229259529, + "longitude": -8.699964485, + "lines": [ + "4C", + "6", + "23", + "25", + "31", + "N4", + "PSA 4" + ] + }, + { + "stopId": 6220, + "name": { + "original": "Avda. de E. Martínez Garrido 45" + }, + "latitude": 42.226116269, + "longitude": -8.703346362, + "lines": [ + "31" + ] + }, + { + "stopId": 6230, + "name": { + "original": "Avda. de E. Martínez Garrido 69" + }, + "latitude": 42.224839145, + "longitude": -8.706082215, + "lines": [ + "31" + ] + }, + { + "stopId": 6240, + "name": { + "original": "Avda. de E. Martínez Garrido 77" + }, + "latitude": 42.224493844, + "longitude": -8.707734948, + "lines": [ + "31" + ] + }, + { + "stopId": 6250, + "name": { + "original": "Avda. de E. Martínez Garrido 80" + }, + "latitude": 42.22667463, + "longitude": -8.702581423, + "lines": [ + "4C", + "23", + "31", + "N4", + "PSA 4" + ] + }, + { + "stopId": 6260, + "name": { + "original": "Estrada da Balsa 3" + }, + "latitude": 42.199568643, + "longitude": -8.741030554, + "lines": [ + "12B", + "17" + ] + }, + { + "stopId": 6280, + "name": { + "original": "Rúa Molais (Parque da Grileira)" + }, + "latitude": 42.223843943, + "longitude": -8.65334865, + "lines": [ + "11" + ] + }, + { + "stopId": 6290, + "name": { + "original": "Rúa de San Paio (cruce Rúa Muíños)" + }, + "latitude": 42.202031781, + "longitude": -8.769502424, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 6300, + "name": { + "original": "Rúa de Cánovas del Castillo (Centro Comercial)" + }, + "latitude": 42.240129541, + "longitude": -8.727159759, + "lines": [ + "C3i", + "A", + "5A", + "5B", + "6", + "9B", + "10", + "11", + "15B", + "15C", + "28", + "N1", + "N4", + "H1" + ] + }, + { + "stopId": 6360, + "name": { + "original": "Rúa de Pablo Iglesias (Colexio)" + }, + "latitude": 42.211426266, + "longitude": -8.743166543, + "lines": [ + "16" + ] + }, + { + "stopId": 6370, + "name": { + "original": "Rúa de Pablo Iglesias (Río)" + }, + "latitude": 42.210130966, + "longitude": -8.744872428, + "lines": [ + "16" + ] + }, + { + "stopId": 6380, + "name": { + "original": "Rúa de Pablo Iglesias 2" + }, + "latitude": 42.211811672, + "longitude": -8.742420889, + "lines": [ + "16" + ] + }, + { + "stopId": 6390, + "name": { + "original": "Rúa de Pablo Iglesias 20" + }, + "latitude": 42.210204472, + "longitude": -8.74559126, + "lines": [ + "16" + ] + }, + { + "stopId": 6440, + "name": { + "original": "Camiño do Pino Manso 6" + }, + "latitude": 42.222951208, + "longitude": -8.635051581, + "lines": [ + "A" + ] + }, + { + "stopId": 6450, + "name": { + "original": "Praza de Suárez Llanos" + }, + "latitude": 42.224306065, + "longitude": -8.753090783, + "lines": [ + "C3d", + "C3i", + "13", + "U1", + "H" + ] + }, + { + "stopId": 6460, + "name": { + "original": "Rúa dos Pescadores 10" + }, + "latitude": 42.224853579, + "longitude": -8.752608542, + "lines": [ + "C3d", + "C3i" + ] + }, + { + "stopId": 6470, + "name": { + "original": "Rúa de Pi i Margall 108" + }, + "latitude": 42.228458938, + "longitude": -8.732202674, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 6480, + "name": { + "original": "Rúa de Pi i Margall 137" + }, + "latitude": 42.229149188, + "longitude": -8.731886908, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 6490, + "name": { + "original": "Rúa de Pi i Margall 32" + }, + "latitude": 42.233972514, + "longitude": -8.729963004, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 6500, + "name": { + "original": "Rúa de Pi i Margall 51" + }, + "latitude": 42.233690068, + "longitude": -8.730100174, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 6510, + "name": { + "original": "Rúa de Pi i Margall 86" + }, + "latitude": 42.230584487, + "longitude": -8.731459155, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 6520, + "name": { + "original": "Rúa de Pi i Margall 95" + }, + "latitude": 42.232285981, + "longitude": -8.730816324, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 6530, + "name": { + "original": "Rúa do Pintor Laxeiro 4" + }, + "latitude": 42.222480852, + "longitude": -8.729812967, + "lines": [ + "C1" + ] + }, + { + "stopId": 6550, + "name": { + "original": "Rúa de Pizarro 10" + }, + "latitude": 42.229886416, + "longitude": -8.717463365, + "lines": [ + "C3i", + "6", + "11", + "15A", + "23", + "25", + "28", + "29" + ] + }, + { + "stopId": 6560, + "name": { + "original": "Rúa de Pizarro 34" + }, + "latitude": 42.23113801, + "longitude": -8.711696824, + "lines": [ + "C3i", + "6", + "11", + "15A", + "23", + "25", + "27", + "28" + ] + }, + { + "stopId": 6570, + "name": { + "original": "Rúa de Pizarro 65" + }, + "latitude": 42.231357755, + "longitude": -8.71296778, + "lines": [ + "C3d", + "6", + "15A", + "23", + "25", + "27", + "28", + "U2", + "H2", + "PSA 1" + ] + }, + { + "stopId": 6580, + "name": { + "original": "Rúa de Pizarro 7" + }, + "latitude": 42.229860487, + "longitude": -8.717979137, + "lines": [ + "C3d", + "6", + "15A", + "23", + "25", + "27", + "28", + "U2", + "H2", + "PSA 1" + ] + }, + { + "stopId": 6620, + "name": { + "original": "Rúa de Policarpo Sanz 40" + }, + "latitude": 42.23757846151978, + "longitude": -8.721031378896738, + "lines": [ + "C1", + "A", + "5A", + "9B", + "15B", + "15C", + "24", + "28", + "N4" + ] + }, + { + "stopId": 6640, + "name": { + "original": "Rúa do Porriño (fronte Instituto)" + }, + "latitude": 42.215506175, + "longitude": -8.753186569, + "lines": [ + "C3d", + "C3i", + "4A", + "4C", + "15A", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 6650, + "name": { + "original": "Rúa do Porriño (Instituto)" + }, + "latitude": 42.215554055, + "longitude": -8.753042462, + "lines": [ + "C3d", + "C3i", + "5B", + "15B", + "U1" + ] + }, + { + "stopId": 6670, + "name": { + "original": "Estrada da Venda 109" + }, + "latitude": 42.183004832, + "longitude": -8.702601056, + "lines": [ + "A", + "6" + ] + }, + { + "stopId": 6680, + "name": { + "original": "Rúa do Portoloureiro 26" + }, + "latitude": 42.207311837, + "longitude": -8.718650635, + "lines": [ + "A" + ] + }, + { + "stopId": 6690, + "name": { + "original": "Rúa do Portoloureiro 52" + }, + "latitude": 42.20495956, + "longitude": -8.715695557, + "lines": [ + "A" + ] + }, + { + "stopId": 6700, + "name": { + "original": "Rúa do Portoloureiro 43" + }, + "latitude": 42.204947406, + "longitude": -8.715589643, + "lines": [ + "A" + ] + }, + { + "stopId": 6720, + "name": { + "original": "Rúa do Portoloureiro (fronte 28)" + }, + "latitude": 42.207385347, + "longitude": -8.718127604, + "lines": [ + "A" + ] + }, + { + "stopId": 6730, + "name": { + "original": "Rúa do Couto 29" + }, + "latitude": 42.199386411, + "longitude": -8.695417016, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 6740, + "name": { + "original": "Rúa da Vista do Mar 95" + }, + "latitude": 42.242957479, + "longitude": -8.691167762, + "lines": [ + "4A", + "24" + ] + }, + { + "stopId": 6750, + "name": { + "original": "Avda. de Samil (Praia da Fonte)" + }, + "latitude": 42.221783554, + "longitude": -8.773517669, + "lines": [ + "10", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 6760, + "name": { + "original": "Rúa de Canido (Praia da Calzoa)" + }, + "latitude": 42.201847037, + "longitude": -8.782205633, + "lines": [ + "10" + ] + }, + { + "stopId": 6780, + "name": { + "original": "Avda. de Samil (Dunas)" + }, + "latitude": 42.210256843, + "longitude": -8.774740625, + "lines": [ + "10" + ] + }, + { + "stopId": 6790, + "name": { + "original": "Avda. de Samil (fronte Hotel)" + }, + "latitude": 42.214772655, + "longitude": -8.774772363, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 6810, + "name": { + "original": "Avda. de Samil (Parking)" + }, + "latitude": 42.207405928, + "longitude": -8.776153122, + "lines": [ + "10" + ] + }, + { + "stopId": 6820, + "name": { + "original": "Avda. de Samil (Polideportivo)" + }, + "latitude": 42.20362713, + "longitude": -8.777027535, + "lines": [ + "10" + ] + }, + { + "stopId": 6830, + "name": { + "original": "Praia do Vao" + }, + "latitude": 42.197495083, + "longitude": -8.790235556, + "lines": [ + "10" + ] + }, + { + "stopId": 6860, + "name": { + "original": "Praza de Compostela" + }, + "latitude": 42.239118346, + "longitude": -8.722531274, + "lines": [ + "C3i", + "A", + "5A", + "5B", + "6", + "9B", + "10", + "11", + "15B", + "15C", + "24", + "28", + "N1", + "N4", + "H1" + ] + }, + { + "stopId": 6880, + "name": { + "original": "Praza do Cristo da Vitoria" + }, + "latitude": 42.215576278, + "longitude": -8.748885599, + "lines": [ + "4A", + "4C", + "11", + "15A", + "N4" + ] + }, + { + "stopId": 6890, + "name": { + "original": "Rúa da Cruz 36" + }, + "latitude": 42.198959642, + "longitude": -8.68628496, + "lines": [ + "14" + ] + }, + { + "stopId": 6900, + "name": { + "original": "Rúa da Cruz 49" + }, + "latitude": 42.199031443, + "longitude": -8.686165797, + "lines": [ + "14" + ] + }, + { + "stopId": 6930, + "name": { + "original": "Praza de América 1" + }, + "latitude": 42.220997313, + "longitude": -8.732835177, + "lines": [ + "C1", + "N4" + ] + }, + { + "stopId": 6940, + "name": { + "original": "Praza de América 3" + }, + "latitude": 42.220663902, + "longitude": -8.733419892, + "lines": [ + "C3d", + "4A", + "4C", + "5A", + "5B", + "10", + "11", + "12A", + "13", + "15A", + "29", + "N4", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 6950, + "name": { + "original": "Praza de España (cruce Rúa de Pizarro)" + }, + "latitude": 42.229280401, + "longitude": -8.719123549, + "lines": [ + "7", + "12A", + "12B", + "14", + "16", + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 6955, + "name": { + "original": "Praza de España (cruce Rúa de Fernando Conde)" + }, + "latitude": 42.229438377, + "longitude": -8.719781108, + "lines": [ + "6", + "13", + "18B", + "18H", + "25", + "29" + ] + }, + { + "stopId": 6960, + "name": { + "original": "Avda. das Camelias s/n ( Praza do Rei)" + }, + "latitude": 42.235056275, + "longitude": -8.726757514, + "lines": [ + "4A", + "4C", + "7", + "12B", + "16", + "17", + "27", + "PSA 4" + ] + }, + { + "stopId": 6970, + "name": { + "original": "Rúa da Coruña 52" + }, + "latitude": 42.223781999, + "longitude": -8.735258991, + "lines": [ + "C1", + "A", + "10", + "N4", + "H1" + ] + }, + { + "stopId": 6980, + "name": { + "original": "Praza Eugenio Fadrique 6" + }, + "latitude": 42.224471236, + "longitude": -8.73619635, + "lines": [ + "C3i", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 6990, + "name": { + "original": "Praza Eugenio Fadrique 9" + }, + "latitude": 42.224099613, + "longitude": -8.735838344, + "lines": [ + "C3d", + "A", + "9B", + "15B", + "15C" + ] + }, + { + "stopId": 7000, + "name": { + "original": "Praza de Fernando O Católico" + }, + "latitude": 42.232427317, + "longitude": -8.711371073, + "lines": [ + "A", + "4A", + "4C", + "5A", + "9B", + "11", + "15B", + "15C", + "24", + "28", + "N1", + "N4" + ] + }, + { + "stopId": 7030, + "name": { + "original": "Rúa de Manuel Castro 23" + }, + "latitude": 42.212808952, + "longitude": -8.740022994, + "lines": [ + "16", + "23", + "N4" + ] + }, + { + "stopId": 7040, + "name": { + "original": "Estrada de Miraflores 1" + }, + "latitude": 42.218435348, + "longitude": -8.709924429, + "lines": [ + "14", + "18A" + ] + }, + { + "stopId": 7050, + "name": { + "original": "Praza de Miraflores 4" + }, + "latitude": 42.218502886, + "longitude": -8.710133641, + "lines": [ + "14" + ] + }, + { + "stopId": 7060, + "name": { + "original": "Estrada de Moledo 70" + }, + "latitude": 42.210499286, + "longitude": -8.703983192, + "lines": [ + "14", + "18A", + "H3" + ] + }, + { + "stopId": 7070, + "name": { + "original": "Estrada de Moledo 109" + }, + "latitude": 42.210620188, + "longitude": -8.704177049, + "lines": [ + "14", + "18A", + "H3" + ] + }, + { + "stopId": 7080, + "name": { + "original": "Rúa da Rabadeira 95" + }, + "latitude": 42.238797018, + "longitude": -8.650399429, + "lines": [ + "9B", + "28" + ] + }, + { + "stopId": 7090, + "name": { + "original": "Rúa de Ramiro Pascual 108" + }, + "latitude": 42.191918475, + "longitude": -8.706869692, + "lines": [ + "27" + ] + }, + { + "stopId": 7100, + "name": { + "original": "Rúa de Ramiro Pascual 16" + }, + "latitude": 42.1952442, + "longitude": -8.71956212, + "lines": [ + "12B", + "18B", + "18H", + "27" + ] + }, + { + "stopId": 7110, + "name": { + "original": "Rúa de Ramiro Pascual 30" + }, + "latitude": 42.195709195, + "longitude": -8.716896004, + "lines": [ + "27" + ] + }, + { + "stopId": 7120, + "name": { + "original": "Rúa de Ramiro Pascual 33" + }, + "latitude": 42.195795442, + "longitude": -8.716893641, + "lines": [ + "27" + ] + }, + { + "stopId": 7130, + "name": { + "original": "Rúa de Ramiro Pascual 46" + }, + "latitude": 42.19350247, + "longitude": -8.715219623, + "lines": [ + "27" + ] + }, + { + "stopId": 7140, + "name": { + "original": "Rúa de Ramiro Pascual 71" + }, + "latitude": 42.193601829, + "longitude": -8.715157933, + "lines": [ + "27" + ] + }, + { + "stopId": 7150, + "name": { + "original": "Rúa de Ramiro Pascual 74" + }, + "latitude": 42.192415468, + "longitude": -8.71184004, + "lines": [ + "27" + ] + }, + { + "stopId": 7160, + "name": { + "original": "Rúa de Ramiro Pascual 97" + }, + "latitude": 42.192526527, + "longitude": -8.712588696, + "lines": [ + "27" + ] + }, + { + "stopId": 7170, + "name": { + "original": "Rúa de Ramiro Pascual 9" + }, + "latitude": 42.195322512, + "longitude": -8.719460515, + "lines": [ + "12B", + "18B", + "18H", + "27" + ] + }, + { + "stopId": 7200, + "name": { + "original": "Avda. de Ramón Nieto 125" + }, + "latitude": 42.231023929, + "longitude": -8.69459232, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7210, + "name": { + "original": "Avda. de Ramón Nieto 136" + }, + "latitude": 42.229661504, + "longitude": -8.691416585, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7220, + "name": { + "original": "Avda. de Ramón Nieto 173" + }, + "latitude": 42.229736581, + "longitude": -8.691879077, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7230, + "name": { + "original": "Avda. de Ramón Nieto 198" + }, + "latitude": 42.229560215, + "longitude": -8.687854611, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7240, + "name": { + "original": "Avda. de Ramón Nieto 252" + }, + "latitude": 42.229454954, + "longitude": -8.684539401, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7250, + "name": { + "original": "Avda. de Ramón Nieto 273" + }, + "latitude": 42.229533333, + "longitude": -8.684593198, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7260, + "name": { + "original": "Avda. de Ramón Nieto 308" + }, + "latitude": 42.22953241, + "longitude": -8.681347572, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7270, + "name": { + "original": "Avda. de Ramón Nieto 341" + }, + "latitude": 42.229570145, + "longitude": -8.681232237, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7280, + "name": { + "original": "Avda. de Ramón Nieto 355" + }, + "latitude": 42.228432118, + "longitude": -8.67827376, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7290, + "name": { + "original": "Avda. de Ramón Nieto 360" + }, + "latitude": 42.228411862, + "longitude": -8.678489489, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7300, + "name": { + "original": "Avda. de Ramón Nieto 390" + }, + "latitude": 42.223957681, + "longitude": -8.673451332, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7310, + "name": { + "original": "Avda. de Ramón Nieto 406" + }, + "latitude": 42.223219273, + "longitude": -8.672272983, + "lines": [ + "11", + "15A", + "15B", + "15C", + "25" + ] + }, + { + "stopId": 7320, + "name": { + "original": "Avda. de Ramón Nieto 475" + }, + "latitude": 42.224462184, + "longitude": -8.673842935, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7330, + "name": { + "original": "Avda. de Ramón Nieto 50" + }, + "latitude": 42.231776636, + "longitude": -8.697735869, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7340, + "name": { + "original": "Avda. de Ramón Nieto 503" + }, + "latitude": 42.223272423, + "longitude": -8.67216119, + "lines": [ + "11", + "15A", + "15B", + "15C", + "25" + ] + }, + { + "stopId": 7350, + "name": { + "original": "Avda. de Ramón Nieto 57" + }, + "latitude": 42.231927571, + "longitude": -8.697668814, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7360, + "name": { + "original": "Avda. de Ramón Nieto 96" + }, + "latitude": 42.230432101, + "longitude": -8.694045149, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7370, + "name": { + "original": "Avda. de Ramón Nieto 247" + }, + "latitude": 42.229607881, + "longitude": -8.686980211, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 7380, + "name": { + "original": "Camiño do Raviso 8" + }, + "latitude": 42.220087856, + "longitude": -8.707014826, + "lines": [ + "14" + ] + }, + { + "stopId": 7390, + "name": { + "original": "Camiño do Raviso 35" + }, + "latitude": 42.220167311, + "longitude": -8.706963864, + "lines": [ + "14" + ] + }, + { + "stopId": 7410, + "name": { + "original": "Rúa de Eduardo Cabello (Igrexa)" + }, + "latitude": 42.226366639, + "longitude": -8.752928216, + "lines": [ + "C3d", + "C3i", + "13", + "U1", + "H" + ] + }, + { + "stopId": 7440, + "name": { + "original": "Rúa Da Cruz 18" + }, + "latitude": 42.200640474, + "longitude": -8.684744444, + "lines": [ + "14" + ] + }, + { + "stopId": 7450, + "name": { + "original": "Rúa da Cruz 2" + }, + "latitude": 42.202168422, + "longitude": -8.68473908, + "lines": [ + "14" + ] + }, + { + "stopId": 7460, + "name": { + "original": "Rúa da Cruz 46" + }, + "latitude": 42.19807525, + "longitude": -8.684800771, + "lines": [ + "14" + ] + }, + { + "stopId": 7470, + "name": { + "original": "Rúa Da Cruz 63" + }, + "latitude": 42.198206824, + "longitude": -8.684878336, + "lines": [ + "14" + ] + }, + { + "stopId": 7480, + "name": { + "original": "Rúa Da Cruz 19" + }, + "latitude": 42.200729887, + "longitude": -8.684258964, + "lines": [ + "14" + ] + }, + { + "stopId": 7490, + "name": { + "original": "Rúa do Carballal 52" + }, + "latitude": 42.194091099, + "longitude": -8.683392611, + "lines": [ + "14" + ] + }, + { + "stopId": 7500, + "name": { + "original": "Rúa do Carballal 18" + }, + "latitude": 42.196388225, + "longitude": -8.684151676, + "lines": [ + "14" + ] + }, + { + "stopId": 7540, + "name": { + "original": "Avda. do Tranvía 100" + }, + "latitude": 42.226657624, + "longitude": -8.659447983, + "lines": [ + "11", + "15A" + ] + }, + { + "stopId": 7590, + "name": { + "original": "Avda. do Tranvía 40" + }, + "latitude": 42.225201551, + "longitude": -8.667101684, + "lines": [ + "11", + "15A" + ] + }, + { + "stopId": 7600, + "name": { + "original": "Rúa dos Chans (cruce Subida Chans)" + }, + "latitude": 42.198544554, + "longitude": -8.677824939, + "lines": [ + "14" + ] + }, + { + "stopId": 7610, + "name": { + "original": "Rúa das Chans (Colexio)" + }, + "latitude": 42.196647395, + "longitude": -8.677801904, + "lines": [ + "14" + ] + }, + { + "stopId": 7620, + "name": { + "original": "Rúa das Chans 97" + }, + "latitude": 42.189146758, + "longitude": -8.678708548, + "lines": [ + "14" + ] + }, + { + "stopId": 7630, + "name": { + "original": "Rúa do Salgueiro 6" + }, + "latitude": 42.243135911, + "longitude": -8.66173721, + "lines": [ + "9B", + "28" + ] + }, + { + "stopId": 7640, + "name": { + "original": "Rúa da Rabadeira 135" + }, + "latitude": 42.241620781, + "longitude": -8.652000054, + "lines": [ + "9B", + "28" + ] + }, + { + "stopId": 7650, + "name": { + "original": "Rúa da Rabadeira 64" + }, + "latitude": 42.239043121, + "longitude": -8.650247888, + "lines": [ + "9B", + "27", + "28" + ] + }, + { + "stopId": 7660, + "name": { + "original": "Rúa da Rabadeira 104" + }, + "latitude": 42.241610852, + "longitude": -8.651865944, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 7662, + "name": { + "original": "Rúa de Recaré 6" + }, + "latitude": 42.211013462, + "longitude": -8.68554295, + "lines": [ + "14" + ] + }, + { + "stopId": 7664, + "name": { + "original": "Rúa de Recaré (cruce Segade)" + }, + "latitude": 42.211201327, + "longitude": -8.688838517, + "lines": [ + "14" + ] + }, + { + "stopId": 7666, + "name": { + "original": "Rúa de Recaré 3" + }, + "latitude": 42.210514541, + "longitude": -8.685349777, + "lines": [ + "14" + ] + }, + { + "stopId": 7668, + "name": { + "original": "Rúa de Recaré 39" + }, + "latitude": 42.211022529, + "longitude": -8.688318168, + "lines": [ + "14" + ] + }, + { + "stopId": 7670, + "name": { + "original": "Rúa San Cristobo 6" + }, + "latitude": 42.235169136, + "longitude": -8.671176685, + "lines": [ + "9B" + ] + }, + { + "stopId": 7680, + "name": { + "original": "Rúa San Cristobo 117" + }, + "latitude": 42.240866745, + "longitude": -8.669273191, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 7690, + "name": { + "original": "Rúa San Cristobo 11" + }, + "latitude": 42.235468446, + "longitude": -8.670649153, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 7700, + "name": { + "original": "Rúa San Cristobo 30" + }, + "latitude": 42.236478263, + "longitude": -8.669194381, + "lines": [ + "9B" + ] + }, + { + "stopId": 7710, + "name": { + "original": "Rúa San Cristobo 41" + }, + "latitude": 42.236825775, + "longitude": -8.669313413, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 7720, + "name": { + "original": "Rúa San Cristobo 80" + }, + "latitude": 42.24099726, + "longitude": -8.669077286, + "lines": [ + "9B" + ] + }, + { + "stopId": 7730, + "name": { + "original": "Rúa do Salgueiro 24" + }, + "latitude": 42.241580812, + "longitude": -8.658065611, + "lines": [ + "9B", + "28" + ] + }, + { + "stopId": 7740, + "name": { + "original": "Rúa de Salgueiro 23" + }, + "latitude": 42.241658253, + "longitude": -8.658202403, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 7750, + "name": { + "original": "Rúa do Salgueiro 1" + }, + "latitude": 42.243330503, + "longitude": -8.661852545, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 7760, + "name": { + "original": "Camiño das Cunchadas (cruce Rúa da Senra)" + }, + "latitude": 42.193300199, + "longitude": -8.681021538, + "lines": [ + "14" + ] + }, + { + "stopId": 7762, + "name": { + "original": "Rúa de Segade 41" + }, + "latitude": 42.209575101, + "longitude": -8.690548833, + "lines": [ + "14" + ] + }, + { + "stopId": 7764, + "name": { + "original": "Rúa de Segade 86" + }, + "latitude": 42.209654568, + "longitude": -8.690495189, + "lines": [ + "14" + ] + }, + { + "stopId": 7810, + "name": { + "original": "Estrada Miraflores (Parque Parróco Xesús Alonso)" + }, + "latitude": 42.217817959, + "longitude": -8.710940668, + "lines": [ + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 7830, + "name": { + "original": "Rúa de Saa 72" + }, + "latitude": 42.20297089, + "longitude": -8.707945762, + "lines": [ + "18B", + "H3" + ] + }, + { + "stopId": 7840, + "name": { + "original": "Rúa da Saa do Monte 73" + }, + "latitude": 42.203039989, + "longitude": -8.710936623, + "lines": [ + "18B" + ] + }, + { + "stopId": 7850, + "name": { + "original": "Rúa de Saa 57" + }, + "latitude": 42.202923204, + "longitude": -8.708085237, + "lines": [ + "18B", + "H3" + ] + }, + { + "stopId": 7860, + "name": { + "original": "Rúa de Severino Cobas 73" + }, + "latitude": 42.225436283, + "longitude": -8.68893946, + "lines": [ + "25" + ] + }, + { + "stopId": 7870, + "name": { + "original": "Baixada á Praia 4" + }, + "latitude": 42.166897971, + "longitude": -8.802204658, + "lines": [ + "C3d", + "10", + "12A" + ] + }, + { + "stopId": 7880, + "name": { + "original": "Barrio da Salgueira 106" + }, + "latitude": 42.222364236, + "longitude": -8.718898254, + "lines": [ + "18A" + ] + }, + { + "stopId": 7890, + "name": { + "original": "Avda. de Cesáreo Vázquez 61" + }, + "latitude": 42.180764289, + "longitude": -8.80256063, + "lines": [ + "11", + "12A" + ] + }, + { + "stopId": 7900, + "name": { + "original": "Rúa de San Paio (cruce Camiño da Quintela)" + }, + "latitude": 42.20492472, + "longitude": -8.768904292, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 7910, + "name": { + "original": "Rúa de San Paio (Igrexa)" + }, + "latitude": 42.208040013, + "longitude": -8.767458581, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 7920, + "name": { + "original": "Rúa de San Paio (Torreiro)" + }, + "latitude": 42.208926096, + "longitude": -8.765294038, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 7930, + "name": { + "original": "Rúa de San Paio 136" + }, + "latitude": 42.208999211, + "longitude": -8.765346753, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 7940, + "name": { + "original": "Rúa de San Paio 220" + }, + "latitude": 42.207987966, + "longitude": -8.767688321, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 7950, + "name": { + "original": "Rúa de San Paio 242" + }, + "latitude": 42.206253649, + "longitude": -8.768742472, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 7960, + "name": { + "original": "Rúa de San Paio 284" + }, + "latitude": 42.202111343, + "longitude": -8.769560881, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 7970, + "name": { + "original": "Rúa de San Paio (fronte 58)" + }, + "latitude": 42.213820465, + "longitude": -8.760651176, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 7980, + "name": { + "original": "Rúa de San Paio 54" + }, + "latitude": 42.21430717, + "longitude": -8.760710185, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 7990, + "name": { + "original": "Rúa de San Paio 76" + }, + "latitude": 42.212612622, + "longitude": -8.760868435, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 8000, + "name": { + "original": "Rúa de San Paio 83" + }, + "latitude": 42.212034517, + "longitude": -8.760916715, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 8010, + "name": { + "original": "Rúa de Sanjurjo Badía 106" + }, + "latitude": 42.245018172, + "longitude": -8.703349646, + "lines": [ + "C3d", + "5B", + "10", + "17", + "31", + "U2", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 8020, + "name": { + "original": "Rúa de Sanjurjo Badía 123" + }, + "latitude": 42.246941664, + "longitude": -8.700376378, + "lines": [ + "C3i", + "5B", + "10", + "N1", + "H3" + ] + }, + { + "stopId": 8030, + "name": { + "original": "Rúa de Sanjurjo Badía 136" + }, + "latitude": 42.246056261, + "longitude": -8.701684825, + "lines": [ + "C3d", + "5B", + "10", + "17", + "31", + "U2", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 8040, + "name": { + "original": "Rúa de Sanjurjo Badía 167" + }, + "latitude": 42.24874024, + "longitude": -8.697546209, + "lines": [ + "C3i", + "5B", + "10", + "N1", + "H3" + ] + }, + { + "stopId": 8050, + "name": { + "original": "Rúa de Sanjurjo Badía 202" + }, + "latitude": 42.247765296, + "longitude": -8.698918203, + "lines": [ + "C3d", + "5B", + "10", + "17", + "31", + "U2", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 8060, + "name": { + "original": "Rúa de Sanjurjo Badía 79" + }, + "latitude": 42.244926864, + "longitude": -8.703642393, + "lines": [ + "C3i", + "5B", + "10", + "N1", + "H3" + ] + }, + { + "stopId": 8090, + "name": { + "original": "Estrada Miraflores (Centro Saúde)" + }, + "latitude": 42.216151643, + "longitude": -8.715616477, + "lines": [ + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 8100, + "name": { + "original": "Estrada da Gándara 79" + }, + "latitude": 42.160735669, + "longitude": -8.709771124, + "lines": [ + "7" + ] + }, + { + "stopId": 8110, + "name": { + "original": "Estrada da Gándara (Seoane)" + }, + "latitude": 42.160670051, + "longitude": -8.709878412, + "lines": [ + "7" + ] + }, + { + "stopId": 8120, + "name": { + "original": "Rúa de Severino Cobas (cruce Trav. de Santa Cristina)" + }, + "latitude": 42.22493632, + "longitude": -8.694369092, + "lines": [ + "25" + ] + }, + { + "stopId": 8130, + "name": { + "original": "Rúa de Severino Cobas 51" + }, + "latitude": 42.225485938, + "longitude": -8.692235895, + "lines": [ + "25" + ] + }, + { + "stopId": 8140, + "name": { + "original": "Rúa de Severino Cobas 14" + }, + "latitude": 42.224657696, + "longitude": -8.696532794, + "lines": [ + "25" + ] + }, + { + "stopId": 8150, + "name": { + "original": "Rúa de Severino Cobas 3" + }, + "latitude": 42.225076787, + "longitude": -8.697168477, + "lines": [ + "25" + ] + }, + { + "stopId": 8160, + "name": { + "original": "Rúa de Severino Cobas 88" + }, + "latitude": 42.224884679, + "longitude": -8.694275214, + "lines": [ + "25" + ] + }, + { + "stopId": 8170, + "name": { + "original": "Rúa de Severino Cobas 140" + }, + "latitude": 42.225428901, + "longitude": -8.688744499, + "lines": [ + "25" + ] + }, + { + "stopId": 8180, + "name": { + "original": "Estrada da Garrida 291" + }, + "latitude": 42.173993336, + "longitude": -8.70329684, + "lines": [ + "7" + ] + }, + { + "stopId": 8190, + "name": { + "original": "Subida da Costa (Colina)" + }, + "latitude": 42.214660701, + "longitude": -8.722840401, + "lines": [ + "A" + ] + }, + { + "stopId": 8200, + "name": { + "original": "Subida da Costa 21" + }, + "latitude": 42.214714337, + "longitude": -8.723068388, + "lines": [ + "A" + ] + }, + { + "stopId": 8210, + "name": { + "original": "Subida da Costa 3" + }, + "latitude": 42.214377129, + "longitude": -8.725964538, + "lines": [ + "A" + ] + }, + { + "stopId": 8220, + "name": { + "original": "Camiño da Corredoura 3" + }, + "latitude": 42.213993258, + "longitude": -8.726740824, + "lines": [ + "A" + ] + }, + { + "stopId": 8230, + "name": { + "original": "Rúa dos Chans (cruce Camiño Regada)" + }, + "latitude": 42.199146625, + "longitude": -8.676419461, + "lines": [ + "14" + ] + }, + { + "stopId": 8240, + "name": { + "original": "Subida á Madroa (Urbanización)" + }, + "latitude": 42.243382567, + "longitude": -8.674125307, + "lines": [ + "9B", + "27", + "28" + ] + }, + { + "stopId": 8250, + "name": { + "original": "Subida á Madroa 15" + }, + "latitude": 42.242669731, + "longitude": -8.670096629, + "lines": [ + "9B", + "27", + "28" + ] + }, + { + "stopId": 8282, + "name": { + "original": "Subida á Mouteira 6" + }, + "latitude": 42.206854901, + "longitude": -8.686031058, + "lines": [ + "14" + ] + }, + { + "stopId": 8284, + "name": { + "original": "Subida á Mouteira (Parque Monte Calvario)" + }, + "latitude": 42.206779403, + "longitude": -8.686218813, + "lines": [ + "14" + ] + }, + { + "stopId": 8290, + "name": { + "original": "Subida das Ánimas 31" + }, + "latitude": 42.235646525, + "longitude": -8.685908988, + "lines": [ + "27", + "28" + ] + }, + { + "stopId": 8300, + "name": { + "original": "Subida das Ánimas 32" + }, + "latitude": 42.23556225, + "longitude": -8.686044366, + "lines": [ + "27", + "28" + ] + }, + { + "stopId": 8330, + "name": { + "original": "Rúa de Tomás A. Alonso 86" + }, + "latitude": 42.223897608, + "longitude": -8.740424721, + "lines": [ + "C3i", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 8340, + "name": { + "original": "Rúa de Tomás A. Alonso 137" + }, + "latitude": 42.223840474, + "longitude": -8.740432891, + "lines": [ + "C3d", + "13", + "15B", + "15C", + "U1", + "H" + ] + }, + { + "stopId": 8370, + "name": { + "original": "Rúa de Tomás A. Alonso 220" + }, + "latitude": 42.223984208, + "longitude": -8.751326546, + "lines": [ + "C3d", + "C3i" + ] + }, + { + "stopId": 8390, + "name": { + "original": "Rúa de Tomás A. Alonso 251" + }, + "latitude": 42.223510532, + "longitude": -8.748903264, + "lines": [ + "C3d", + "13", + "15B", + "15C", + "U1", + "H" + ] + }, + { + "stopId": 8410, + "name": { + "original": "Rúa de Tomás Paredes (fronte 108)" + }, + "latitude": 42.218006346, + "longitude": -8.754154367, + "lines": [ + "C3d", + "10", + "15B" + ] + }, + { + "stopId": 8420, + "name": { + "original": "Rúa de Tomás Paredes 114" + }, + "latitude": 42.218031265, + "longitude": -8.754258995, + "lines": [ + "C3i", + "10" + ] + }, + { + "stopId": 8430, + "name": { + "original": "Rúa de Tomás Paredes 9" + }, + "latitude": 42.221229518, + "longitude": -8.753411657, + "lines": [ + "C3d", + "10", + "15B" + ] + }, + { + "stopId": 8440, + "name": { + "original": "Rúa de Tomás Paredes 86" + }, + "latitude": 42.220192578, + "longitude": -8.754164587, + "lines": [ + "C3i", + "10" + ] + }, + { + "stopId": 8450, + "name": { + "original": "Rúa do Conde de Torrecedeira (Parque)" + }, + "latitude": 42.231511437, + "longitude": -8.732178, + "lines": [ + "C1", + "C3d", + "A", + "5A", + "9B", + "15C", + "N4", + "H1" + ] + }, + { + "stopId": 8460, + "name": { + "original": "Rúa do Conde de Torrecedeira 105" + }, + "latitude": 42.227500225, + "longitude": -8.734096707, + "lines": [ + "C1", + "C3d", + "A", + "9B", + "15C", + "N4", + "H1" + ] + }, + { + "stopId": 8470, + "name": { + "original": "Rúa do Conde de Torrecedeira 21" + }, + "latitude": 42.234106639, + "longitude": -8.731302569, + "lines": [ + "C1", + "C3d", + "A", + "5A", + "9B", + "15C", + "N4", + "H1" + ] + }, + { + "stopId": 8480, + "name": { + "original": "Rúa do Conde de Torrecedeira 81" + }, + "latitude": 42.229616766, + "longitude": -8.732861043, + "lines": [ + "C1", + "C3d", + "A", + "5A", + "9B", + "15C", + "N4", + "H1" + ] + }, + { + "stopId": 8490, + "name": { + "original": "Rúa da Travesía de Vigo 202" + }, + "latitude": 42.244366441, + "longitude": -8.695452075, + "lines": [ + "C3i", + "5A", + "N1", + "H3" + ] + }, + { + "stopId": 8500, + "name": { + "original": "Rúa da Travesía de Vigo 105" + }, + "latitude": 42.238455548, + "longitude": -8.703814812, + "lines": [ + "C3d", + "5A", + "31", + "U2", + "H2", + "PSA 1" + ] + }, + { + "stopId": 8510, + "name": { + "original": "Rúa da Travesía de Vigo 124" + }, + "latitude": 42.238413145, + "longitude": -8.703563202, + "lines": [ + "C3i", + "5A", + "N1" + ] + }, + { + "stopId": 8520, + "name": { + "original": "Rúa da Travesía de Vigo 153" + }, + "latitude": 42.241332883, + "longitude": -8.702059906, + "lines": [ + "C3d", + "5A", + "31", + "U2", + "H2", + "PSA 1" + ] + }, + { + "stopId": 8530, + "name": { + "original": "Rúa da Travesía de Vigo 158" + }, + "latitude": 42.241101222, + "longitude": -8.701974032, + "lines": [ + "C3i", + "5A", + "N1" + ] + }, + { + "stopId": 8540, + "name": { + "original": "Rúa da Travesía de Vigo 193" + }, + "latitude": 42.242844316, + "longitude": -8.698295825, + "lines": [ + "C3d", + "5A", + "31", + "U2", + "H2", + "PSA 1" + ] + }, + { + "stopId": 8550, + "name": { + "original": "Rúa da Travesía de Vigo 220" + }, + "latitude": 42.246425568, + "longitude": -8.692950624, + "lines": [ + "C3i", + "5A", + "5B", + "N1", + "H3" + ] + }, + { + "stopId": 8560, + "name": { + "original": "Rúa da Travesía de Vigo 213" + }, + "latitude": 42.24409871, + "longitude": -8.69614733, + "lines": [ + "C3d", + "5A", + "31", + "U2", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 8570, + "name": { + "original": "Rúa da Travesía de Vigo 239" + }, + "latitude": 42.246143319, + "longitude": -8.69359937, + "lines": [ + "C3d", + "5A", + "31", + "U2", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 8580, + "name": { + "original": "Rúa da Travesía de Vigo 32" + }, + "latitude": 42.233828086, + "longitude": -8.706311242, + "lines": [ + "C3i", + "5A", + "31", + "N1" + ] + }, + { + "stopId": 8590, + "name": { + "original": "Rúa da Travesía de Vigo 37" + }, + "latitude": 42.233681224, + "longitude": -8.706702136, + "lines": [ + "C3d", + "5A", + "31", + "U2", + "H2", + "PSA 1" + ] + }, + { + "stopId": 8600, + "name": { + "original": "Rúa da Travesía de Vigo 71" + }, + "latitude": 42.236350093, + "longitude": -8.70429745, + "lines": [ + "C3d", + "5A", + "31", + "U2", + "H2", + "PSA 1" + ] + }, + { + "stopId": 8610, + "name": { + "original": "Rúa da Travesía de Vigo 8" + }, + "latitude": 42.232028188, + "longitude": -8.708203776, + "lines": [ + "C3i", + "A", + "4A", + "4C", + "5A", + "6", + "9B", + "11", + "15A", + "15B", + "15C", + "23", + "24", + "25", + "27", + "28", + "N1", + "N4" + ] + }, + { + "stopId": 8620, + "name": { + "original": "Rúa da Travesía de Vigo 82" + }, + "latitude": 42.236261792, + "longitude": -8.703994979, + "lines": [ + "C3i", + "5A", + "N1" + ] + }, + { + "stopId": 8630, + "name": { + "original": "Rúa da Travesía de Vigo 7" + }, + "latitude": 42.232045931, + "longitude": -8.708603793, + "lines": [ + "C3d", + "A", + "4A", + "4C", + "5A", + "6", + "9B", + "11", + "15A", + "15B", + "15C", + "23", + "25", + "27", + "28", + "N4", + "U2", + "H2", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 8660, + "name": { + "original": "Química (CUVI)" + }, + "latitude": 42.168290977, + "longitude": -8.68342947, + "lines": [ + "A", + "15C", + "U1", + "U2" + ] + }, + { + "stopId": 8670, + "name": { + "original": "Bioloxía (CUVI)" + }, + "latitude": 42.167687661, + "longitude": -8.685994335, + "lines": [ + "A", + "15C", + "U1", + "U2" + ] + }, + { + "stopId": 8680, + "name": { + "original": "Económicas e Empresariais (CUVI)" + }, + "latitude": 42.169603028, + "longitude": -8.680108895, + "lines": [ + "A", + "15C", + "U1", + "U2" + ] + }, + { + "stopId": 8700, + "name": { + "original": "Enxeñeiros (CUVI)" + }, + "latitude": 42.167963445, + "longitude": -8.688421342, + "lines": [ + "A", + "15C", + "U1", + "U2" + ] + }, + { + "stopId": 8710, + "name": { + "original": "Universidade." + }, + "latitude": 42.167985106, + "longitude": -8.688425395, + "lines": [ + "A" + ] + }, + { + "stopId": 8720, + "name": { + "original": "Humanidades (CUVI)" + }, + "latitude": 42.169678809, + "longitude": -8.679104749, + "lines": [ + "A", + "15C", + "U1", + "U2" + ] + }, + { + "stopId": 8721, + "name": { + "original": "Universidade.." + }, + "latitude": 42.169776602, + "longitude": -8.678942156, + "lines": [ + "A" + ] + }, + { + "stopId": 8730, + "name": { + "original": "Telecomunicacións (CUVI) B" + }, + "latitude": 42.170159671, + "longitude": -8.68735086, + "lines": [ + "A" + ] + }, + { + "stopId": 8740, + "name": { + "original": "Telecomunicacións (CUVI)" + }, + "latitude": 42.170123888, + "longitude": -8.687270393, + "lines": [ + "A", + "15C", + "U1", + "U2" + ] + }, + { + "stopId": 8750, + "name": { + "original": "Rúa de Urzáiz - Est. Intermodal - C.C." + }, + "latitude": 42.233722977, + "longitude": -8.714502762, + "lines": [ + "A", + "4A", + "4C", + "5A", + "6", + "9B", + "11", + "15B", + "15C", + "24", + "28", + "N4", + "PSA 4" + ] + }, + { + "stopId": 8770, + "name": { + "original": "Rúa de Urzáiz 13" + }, + "latitude": 42.235420929, + "longitude": -8.718721877, + "lines": [ + "A", + "4A", + "4C", + "5A", + "6", + "7", + "9B", + "11", + "12B", + "14", + "15B", + "15C", + "16", + "17", + "18A", + "18B", + "18H", + "24", + "28", + "N1", + "N4", + "PSA 4" + ] + }, + { + "stopId": 8820, + "name": { + "original": "Rúa de Urzáiz 28" + }, + "latitude": 42.23516998, + "longitude": -8.718398782, + "lines": [ + "C1", + "A", + "4A", + "4C", + "5A", + "7", + "9B", + "12B", + "14", + "15B", + "15C", + "16", + "17", + "18A", + "18B", + "18H", + "24", + "28", + "N1", + "N4" + ] + }, + { + "stopId": 8840, + "name": { + "original": "Rúa de Urzáiz 60 - Est. Intermodal - C.C." + }, + "latitude": 42.233986283, + "longitude": -8.71541048, + "lines": [ + "A", + "4A", + "4C", + "5A", + "9B", + "11", + "15B", + "15C", + "24", + "28", + "N1", + "N4" + ] + }, + { + "stopId": 8850, + "name": { + "original": "Rúa de Urzáiz 97" + }, + "latitude": 42.232341315, + "longitude": -8.710892054, + "lines": [ + "A", + "4A", + "4C", + "5A", + "6", + "9B", + "11", + "15B", + "15C", + "28", + "N4", + "PSA 4" + ] + }, + { + "stopId": 8870, + "name": { + "original": "Rúa de Venezuela 4" + }, + "latitude": 42.234250043, + "longitude": -8.724361531, + "lines": [ + "4A", + "4C", + "5B", + "11", + "12A", + "12B", + "17", + "27", + "N1" + ] + }, + { + "stopId": 8880, + "name": { + "original": "Rúa de Venezuela 20" + }, + "latitude": 42.233188126, + "longitude": -8.72155331, + "lines": [ + "4A", + "4C", + "5B", + "11", + "12A", + "12B", + "17", + "27", + "N1" + ] + }, + { + "stopId": 8890, + "name": { + "original": "Rúa de Venezuela 21" + }, + "latitude": 42.233283503, + "longitude": -8.721378959, + "lines": [ + "4A", + "4C", + "5B", + "7", + "12B", + "16", + "17", + "PSA 4" + ] + }, + { + "stopId": 8900, + "name": { + "original": "Rúa de Venezuela 45" + }, + "latitude": 42.232243383, + "longitude": -8.718524158, + "lines": [ + "4A", + "4C", + "5B", + "7", + "12B", + "16", + "17", + "PSA 4" + ] + }, + { + "stopId": 8910, + "name": { + "original": "Rúa de Venezuela 42" + }, + "latitude": 42.232224046, + "longitude": -8.718985824, + "lines": [ + "4A", + "4C", + "5B", + "11", + "12A", + "12B", + "17", + "27", + "N1" + ] + }, + { + "stopId": 8916, + "name": { + "original": "Rúa de Venezuela 60" + }, + "latitude": 42.231593651, + "longitude": -8.71714227, + "lines": [ + "27" + ] + }, + { + "stopId": 8930, + "name": { + "original": "Rúa de Vilagarcía de Arousa (cruce Rúa do Grove)" + }, + "latitude": 42.22014115, + "longitude": -8.745082757, + "lines": [ + "C3i", + "5B" + ] + }, + { + "stopId": 8950, + "name": { + "original": "Rúa de Marín 5" + }, + "latitude": 42.218712573, + "longitude": -8.75011435, + "lines": [ + "C3i", + "5B" + ] + }, + { + "stopId": 8970, + "name": { + "original": "Rúa do Seixo 45" + }, + "latitude": 42.197425383, + "longitude": -8.713700535, + "lines": [ + "A", + "H3" + ] + }, + { + "stopId": 8980, + "name": { + "original": "Rúa do Seixo 38" + }, + "latitude": 42.197532685, + "longitude": -8.713614705, + "lines": [ + "A", + "H3" + ] + }, + { + "stopId": 8990, + "name": { + "original": "Rúa do Seixo 75" + }, + "latitude": 42.200673849, + "longitude": -8.714185609, + "lines": [ + "A", + "18B", + "H3" + ] + }, + { + "stopId": 9000, + "name": { + "original": "Rúa do Seixo (Parque)" + }, + "latitude": 42.200719549, + "longitude": -8.714115872, + "lines": [ + "A", + "H3" + ] + }, + { + "stopId": 9010, + "name": { + "original": "Rúa de Xeme 71" + }, + "latitude": 42.203157887, + "longitude": -8.694293108, + "lines": [ + "14" + ] + }, + { + "stopId": 9020, + "name": { + "original": "Xestoso" + }, + "latitude": 42.207584622, + "longitude": -8.670108196, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 9040, + "name": { + "original": "Estrada das Plantas (cruce Camiño Monte Vello)" + }, + "latitude": 42.20831564, + "longitude": -8.670282438, + "lines": [ + "15B", + "15C", + "U2" + ] + }, + { + "stopId": 9050, + "name": { + "original": "Estrada da Igrexa 45" + }, + "latitude": 42.154646971, + "longitude": -8.688349062, + "lines": [ + "7" + ] + }, + { + "stopId": 10061, + "name": { + "original": "Estrada de San Xoán 193" + }, + "latitude": 42.185277472, + "longitude": -8.741558953, + "lines": [ + "17" + ] + }, + { + "stopId": 14101, + "name": { + "original": "Estrada da Garrida 165" + }, + "latitude": 42.168008539, + "longitude": -8.710415438, + "lines": [ + "7" + ] + }, + { + "stopId": 14102, + "name": { + "original": "Estrada da Garrida 108" + }, + "latitude": 42.168282882, + "longitude": -8.710066751, + "lines": [ + "7" + ] + }, + { + "stopId": 14105, + "name": { + "original": "Ciencias Xurídicas (CUVI)" + }, + "latitude": 42.167237978, + "longitude": -8.681135704, + "lines": [ + "A", + "15C", + "U1", + "U2" + ] + }, + { + "stopId": 14106, + "name": { + "original": "Avda. do Aeroporto 92" + }, + "latitude": 42.234161582, + "longitude": -8.695074564, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 14107, + "name": { + "original": "Camiño Padín (Rotonda Autoestrada)" + }, + "latitude": 42.257847205, + "longitude": -8.677696507, + "lines": [ + "10" + ] + }, + { + "stopId": 14108, + "name": { + "original": "Avda. da Ponte (antes desvío Autovía)" + }, + "latitude": 42.21401741, + "longitude": -8.67133083, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 14111, + "name": { + "original": "Estrada de Bembrive (Centro Saúde)" + }, + "latitude": 42.204262657, + "longitude": -8.684801801, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 14112, + "name": { + "original": "Estrada de Bembrive (Alameda)" + }, + "latitude": 42.204047198, + "longitude": -8.684697288, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 14113, + "name": { + "original": "Estrada da Coutada 20" + }, + "latitude": 42.193458577, + "longitude": -8.702065856, + "lines": [ + "6", + "27" + ] + }, + { + "stopId": 14117, + "name": { + "original": "Rúa do Couto de San Honorato 26" + }, + "latitude": 42.228574702, + "longitude": -8.712864548, + "lines": [ + "H2" + ] + }, + { + "stopId": 14119, + "name": { + "original": "Rúa do Couto de San Honorato 80" + }, + "latitude": 42.229320789, + "longitude": -8.710390551, + "lines": [ + "H2" + ] + }, + { + "stopId": 14121, + "name": { + "original": "Rúa da Reconquista 2" + }, + "latitude": 42.238625474, + "longitude": -8.723242095, + "lines": [ + "C1", + "C3d", + "A", + "5A", + "9B", + "10", + "15B", + "15C", + "24", + "28", + "N4" + ] + }, + { + "stopId": 14122, + "name": { + "original": "Avda. do Alcalde Gregorio Espino 9" + }, + "latitude": 42.231584097, + "longitude": -8.706968521, + "lines": [ + "4C", + "23", + "31", + "H2", + "PSA 4" + ] + }, + { + "stopId": 14123, + "name": { + "original": "Rúa do Porriño 9" + }, + "latitude": 42.214127819, + "longitude": -8.752027594, + "lines": [ + "C3d", + "C3i", + "4A", + "4C", + "5B", + "11", + "15A", + "15B", + "N4", + "U1" + ] + }, + { + "stopId": 14124, + "name": { + "original": "Rúa de Eduardo Cabello (fronte Igrexa)" + }, + "latitude": 42.226569499, + "longitude": -8.752773946, + "lines": [ + "C3d", + "C3i", + "6" + ] + }, + { + "stopId": 14125, + "name": { + "original": "Rúa do Porriño (fronte 9)" + }, + "latitude": 42.213869651, + "longitude": -8.751990789, + "lines": [ + "C3d", + "C3i", + "4A", + "4C", + "15A", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 14126, + "name": { + "original": "Rúa da Travesía de Vigo 194" + }, + "latitude": 42.242494425, + "longitude": -8.699249038, + "lines": [ + "C3i", + "5A", + "N1" + ] + }, + { + "stopId": 14127, + "name": { + "original": "Avda. de Buenos Aires 13" + }, + "latitude": 42.249306896, + "longitude": -8.695179916, + "lines": [ + "5B", + "10", + "N1", + "H3" + ] + }, + { + "stopId": 14128, + "name": { + "original": "Camiño do Caramuxo (fronte 9)" + }, + "latitude": 42.20733292, + "longitude": -8.752159103, + "lines": [ + "5A" + ] + }, + { + "stopId": 14129, + "name": { + "original": "Camiño do Caramuxo 11" + }, + "latitude": 42.20723039, + "longitude": -8.752592351, + "lines": [ + "5A" + ] + }, + { + "stopId": 14131, + "name": { + "original": "Rúa de Tomás Paredes 4" + }, + "latitude": 42.221948768, + "longitude": -8.753171211, + "lines": [ + "C3i", + "10" + ] + }, + { + "stopId": 14132, + "name": { + "original": "Rúa de Sanjurjo Badía 252" + }, + "latitude": 42.249307631, + "longitude": -8.696542008, + "lines": [ + "C3d", + "5A", + "5B", + "10", + "17", + "31", + "U2", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 14133, + "name": { + "original": "Avda. de Galicia 37" + }, + "latitude": 42.250977575, + "longitude": -8.694471881, + "lines": [ + "C3i", + "17" + ] + }, + { + "stopId": 14134, + "name": { + "original": "Avda. de Galicia 182" + }, + "latitude": 42.253208793, + "longitude": -8.686995591, + "lines": [ + "C3d" + ] + }, + { + "stopId": 14135, + "name": { + "original": "Rúa de Santo Amaro (Praza de España)" + }, + "latitude": 42.229174145, + "longitude": -8.720143055, + "lines": [ + "C1" + ] + }, + { + "stopId": 14136, + "name": { + "original": "Avda. de Galicia 18" + }, + "latitude": 42.250484372, + "longitude": -8.694878804, + "lines": [ + "C3d", + "17" + ] + }, + { + "stopId": 14137, + "name": { + "original": "Estrada Matamá Pazo (Igrexa)" + }, + "latitude": 42.200003406, + "longitude": -8.753169, + "lines": [ + "29" + ] + }, + { + "stopId": 14138, + "name": { + "original": "Estrada de Madrid (Campo de Fútbol)" + }, + "latitude": 42.216459201, + "longitude": -8.678591709, + "lines": [ + "12B", + "15B", + "15C" + ] + }, + { + "stopId": 14139, + "name": { + "original": "Avda. de E. Martínez Garrido 27" + }, + "latitude": 42.227492758, + "longitude": -8.700413366, + "lines": [ + "6", + "25", + "31" + ] + }, + { + "stopId": 14140, + "name": { + "original": "Avda. de E. Martínez Garrido 30" + }, + "latitude": 42.228210877, + "longitude": -8.699999354, + "lines": [ + "4C", + "6", + "23", + "25", + "31", + "N4", + "PSA 4" + ] + }, + { + "stopId": 14141, + "name": { + "original": "Rúa de Jenaro de la Fuente 43" + }, + "latitude": 42.231379202, + "longitude": -8.699876213, + "lines": [ + "11", + "15A", + "15B", + "15C", + "H3" + ] + }, + { + "stopId": 14142, + "name": { + "original": "Avda. da Hispanidade 22" + }, + "latitude": 42.231463434, + "longitude": -8.728844425, + "lines": [ + "16" + ] + }, + { + "stopId": 14143, + "name": { + "original": "Avda. da Hispanidade 38" + }, + "latitude": 42.229753483, + "longitude": -8.729002675, + "lines": [ + "16" + ] + }, + { + "stopId": 14144, + "name": { + "original": "Avda. da Hispanidade 82" + }, + "latitude": 42.226760436, + "longitude": -8.727385303, + "lines": [ + "16" + ] + }, + { + "stopId": 14150, + "name": { + "original": "Rúa do Padre Don Rúa 1" + }, + "latitude": 42.232076561, + "longitude": -8.719055236, + "lines": [ + "14" + ] + }, + { + "stopId": 14152, + "name": { + "original": "Rúa do Monte Calvario 4" + }, + "latitude": 42.204815402, + "longitude": -8.687168969, + "lines": [ + "14" + ] + }, + { + "stopId": 14153, + "name": { + "original": "Estrada de Bembrive 173" + }, + "latitude": 42.205357233, + "longitude": -8.692495739, + "lines": [ + "6", + "14" + ] + }, + { + "stopId": 14154, + "name": { + "original": "Rúa das Chans (fronte 56)" + }, + "latitude": 42.19360258, + "longitude": -8.677258993, + "lines": [ + "14" + ] + }, + { + "stopId": 14156, + "name": { + "original": "Rúa de Xeme (cruce Camiño da Carballeira)" + }, + "latitude": 42.203378431, + "longitude": -8.696666863, + "lines": [ + "14" + ] + }, + { + "stopId": 14157, + "name": { + "original": "Rúa do Xeme (cruce Rúa de Eifonso)" + }, + "latitude": 42.202979066, + "longitude": -8.694065121, + "lines": [ + "14" + ] + }, + { + "stopId": 14161, + "name": { + "original": "Rúa de López Mora 62" + }, + "latitude": 42.224130699, + "longitude": -8.732568248, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 14162, + "name": { + "original": "Avda. da Florida 82" + }, + "latitude": 42.211371871, + "longitude": -8.746523782, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 14163, + "name": { + "original": "Avda. da Florida (fronte 82)" + }, + "latitude": 42.211442202, + "longitude": -8.746227469, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 14164, + "name": { + "original": "Rúa de Tomás A. Alonso 136" + }, + "latitude": 42.225172437, + "longitude": -8.744777354, + "lines": [ + "C3i", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 14165, + "name": { + "original": "Rúa de Tomás A. Alonso 193" + }, + "latitude": 42.224905029, + "longitude": -8.745285775, + "lines": [ + "C3d", + "13", + "15B", + "15C", + "U1", + "H" + ] + }, + { + "stopId": 14166, + "name": { + "original": "Avda. das Camelias 114" + }, + "latitude": 42.225142981, + "longitude": -8.729707944, + "lines": [ + "4A", + "4C", + "7", + "12B", + "17", + "27", + "PSA 4" + ] + }, + { + "stopId": 14167, + "name": { + "original": "Beiramar - Pescadores" + }, + "latitude": 42.225279021, + "longitude": -8.751908648, + "lines": [ + "6", + "9B", + "28" + ] + }, + { + "stopId": 14168, + "name": { + "original": "Avda. das Camelias 113" + }, + "latitude": 42.224928285, + "longitude": -8.729631509, + "lines": [ + "4A", + "4C", + "11", + "12B", + "17", + "27", + "N1" + ] + }, + { + "stopId": 14169, + "name": { + "original": "Avda. das Camelias 136" + }, + "latitude": 42.22244224, + "longitude": -8.731271052, + "lines": [ + "C1", + "4A", + "4C", + "7", + "12B", + "16", + "17", + "27", + "LZH", + "PSA 4" + ] + }, + { + "stopId": 14170, + "name": { + "original": "Avda. de Samil (Praia da Punta)" + }, + "latitude": 42.218831744, + "longitude": -8.77571001, + "lines": [ + "10", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 14171, + "name": { + "original": "Avda. de Samil (fronte Praia da Punta)" + }, + "latitude": 42.218844713, + "longitude": -8.775459221, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 14173, + "name": { + "original": "Rúa do Gaiteiro de Ricardo Portela (fronte Pavillón)" + }, + "latitude": 42.235900754, + "longitude": -8.731391435, + "lines": [ + "C1", + "C3d", + "A", + "5A", + "9B", + "15C", + "N4", + "H1" + ] + }, + { + "stopId": 14174, + "name": { + "original": "Rúa do Padre Seixas (Parque da Bouza)" + }, + "latitude": 42.211844516, + "longitude": -8.749287921, + "lines": [ + "11", + "16" + ] + }, + { + "stopId": 14175, + "name": { + "original": "Rúa do Padre Seixas 32" + }, + "latitude": 42.211792864, + "longitude": -8.749617832, + "lines": [ + "16" + ] + }, + { + "stopId": 14177, + "name": { + "original": "Rúa de Fernando Conde (cruce Avda. da Gran Vía)" + }, + "latitude": 42.22985125, + "longitude": -8.71972059, + "lines": [ + "12A", + "14", + "27" + ] + }, + { + "stopId": 14178, + "name": { + "original": "Rúa do Marqués de Alcedo (Parque)" + }, + "latitude": 42.233009005, + "longitude": -8.724497604, + "lines": [ + "12A", + "27" + ] + }, + { + "stopId": 14179, + "name": { + "original": "Rúa da Costa 4" + }, + "latitude": 42.213260612, + "longitude": -8.722562576, + "lines": [ + "A", + "18B", + "18H" + ] + }, + { + "stopId": 14180, + "name": { + "original": "Avda. de E. Martínez Garrido 108" + }, + "latitude": 42.224749197, + "longitude": -8.707320585, + "lines": [ + "4C", + "23", + "31", + "N4", + "PSA 4" + ] + }, + { + "stopId": 14181, + "name": { + "original": "Camiño da Corredoura (Igrexa)" + }, + "latitude": 42.210954716, + "longitude": -8.727776522, + "lines": [ + "A" + ] + }, + { + "stopId": 14182, + "name": { + "original": "Rúa da Costa 39" + }, + "latitude": 42.211618245, + "longitude": -8.72147159, + "lines": [ + "A", + "18B", + "18H" + ] + }, + { + "stopId": 14183, + "name": { + "original": "Rúa do Xalón (Colexio)" + }, + "latitude": 42.220622235, + "longitude": -8.654888024, + "lines": [ + "11" + ] + }, + { + "stopId": 14184, + "name": { + "original": "Rúa do Xalón 5" + }, + "latitude": 42.217384986, + "longitude": -8.657082399, + "lines": [ + "11" + ] + }, + { + "stopId": 14185, + "name": { + "original": "Rúa da Becerreira 81" + }, + "latitude": 42.219667098, + "longitude": -8.659470523, + "lines": [ + "11" + ] + }, + { + "stopId": 14186, + "name": { + "original": "Rúa da Becerreira (fronte 64)" + }, + "latitude": 42.218044517, + "longitude": -8.662618478, + "lines": [ + "11" + ] + }, + { + "stopId": 14187, + "name": { + "original": "Rúa da Becerreira 1" + }, + "latitude": 42.221588029, + "longitude": -8.662035851, + "lines": [ + "11" + ] + }, + { + "stopId": 14188, + "name": { + "original": "Rúa da Becerreira 41" + }, + "latitude": 42.217595578, + "longitude": -8.661414166, + "lines": [ + "11" + ] + }, + { + "stopId": 14189, + "name": { + "original": "Rúa Molais 84" + }, + "latitude": 42.226081487, + "longitude": -8.654133203, + "lines": [ + "11" + ] + }, + { + "stopId": 14190, + "name": { + "original": "Rúa de Severino Cobas 196" + }, + "latitude": 42.225080876, + "longitude": -8.683314171, + "lines": [ + "25" + ] + }, + { + "stopId": 14191, + "name": { + "original": "Camiño da Bouciña 76" + }, + "latitude": 42.223737557, + "longitude": -8.682141153, + "lines": [ + "25" + ] + }, + { + "stopId": 14192, + "name": { + "original": "Rúa das Figueiras 282" + }, + "latitude": 42.231625599, + "longitude": -8.652046516, + "lines": [ + "25" + ] + }, + { + "stopId": 14193, + "name": { + "original": "Avda. de Santa Mariña 443" + }, + "latitude": 42.230916628, + "longitude": -8.641628816, + "lines": [ + "25" + ] + }, + { + "stopId": 14194, + "name": { + "original": "Avda. de Santa Mariña 425" + }, + "latitude": 42.228639377, + "longitude": -8.640978361, + "lines": [ + "25" + ] + }, + { + "stopId": 14195, + "name": { + "original": "Avda. de Santa Mariña 249" + }, + "latitude": 42.226263256, + "longitude": -8.644091084, + "lines": [ + "25" + ] + }, + { + "stopId": 14196, + "name": { + "original": "Avda. de Santa Mariña 229" + }, + "latitude": 42.225296, + "longitude": -8.649527921, + "lines": [ + "25" + ] + }, + { + "stopId": 14197, + "name": { + "original": "Rúa Molais (cruce Rúa das Carballas)" + }, + "latitude": 42.225912491, + "longitude": -8.653698801, + "lines": [ + "25" + ] + }, + { + "stopId": 14198, + "name": { + "original": "Rúa do Riomao 21" + }, + "latitude": 42.227231301, + "longitude": -8.659997969, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 14199, + "name": { + "original": "Camiño da Bouciña 79" + }, + "latitude": 42.223755464, + "longitude": -8.682041911, + "lines": [ + "25" + ] + }, + { + "stopId": 14200, + "name": { + "original": "Rúa de Severino Cobas 119" + }, + "latitude": 42.225112655, + "longitude": -8.683402684, + "lines": [ + "25" + ] + }, + { + "stopId": 14201, + "name": { + "original": "Avda. de Santa Mariña (cruce Avda. do Tranvía)" + }, + "latitude": 42.226291056, + "longitude": -8.641647591, + "lines": [ + "25" + ] + }, + { + "stopId": 14202, + "name": { + "original": "Rúa de Jenaro de la Fuente 58" + }, + "latitude": 42.231273786, + "longitude": -8.700145645, + "lines": [ + "11", + "15A", + "15B", + "15C", + "H3" + ] + }, + { + "stopId": 14203, + "name": { + "original": "Avda. do Tranvía S/N (despois Camiño Lugar)" + }, + "latitude": 42.226524401, + "longitude": -8.661251786, + "lines": [ + "11", + "15A" + ] + }, + { + "stopId": 14204, + "name": { + "original": "Rúa de Manuel Álvarez 151" + }, + "latitude": 42.22312688, + "longitude": -8.681864633, + "lines": [ + "25", + "31", + "H3" + ] + }, + { + "stopId": 14205, + "name": { + "original": "Estrada do Freixo (Cemiterio)" + }, + "latitude": 42.178408629, + "longitude": -8.733198549, + "lines": [ + "7" + ] + }, + { + "stopId": 14206, + "name": { + "original": "Avda. da Gran Vía (Instituto)" + }, + "latitude": 42.220514043, + "longitude": -8.731700217, + "lines": [ + "C3i", + "7", + "11", + "13", + "15A", + "16", + "23", + "29", + "H2" + ] + }, + { + "stopId": 14207, + "name": { + "original": "Camiño do Pinal 19" + }, + "latitude": 42.161212162, + "longitude": -8.716377433, + "lines": [ + "7" + ] + }, + { + "stopId": 14208, + "name": { + "original": "Estrada de Valadares 452" + }, + "latitude": 42.162237207, + "longitude": -8.71885531, + "lines": [ + "7" + ] + }, + { + "stopId": 14209, + "name": { + "original": "Estrada da Garrida 263" + }, + "latitude": 42.173333822, + "longitude": -8.705439803, + "lines": [ + "7" + ] + }, + { + "stopId": 14210, + "name": { + "original": "Estrada da Garrida (frente 243)" + }, + "latitude": 42.173077394, + "longitude": -8.705659744, + "lines": [ + "7" + ] + }, + { + "stopId": 14211, + "name": { + "original": "Estrada do Monte Alba 32" + }, + "latitude": 42.165479162, + "longitude": -8.721775005, + "lines": [ + "7" + ] + }, + { + "stopId": 14212, + "name": { + "original": "Estrada do Monte Alba 54" + }, + "latitude": 42.164694101, + "longitude": -8.724472962, + "lines": [ + "7" + ] + }, + { + "stopId": 14213, + "name": { + "original": "Estrada do Freixo (Campo Fútbol)" + }, + "latitude": 42.169153241, + "longitude": -8.729001464, + "lines": [ + "7" + ] + }, + { + "stopId": 14214, + "name": { + "original": "Estrada do Freixo 191" + }, + "latitude": 42.175760907, + "longitude": -8.734516924, + "lines": [ + "7" + ] + }, + { + "stopId": 14215, + "name": { + "original": "Estrada do Freixo 90" + }, + "latitude": 42.175592169, + "longitude": -8.734477788, + "lines": [ + "7" + ] + }, + { + "stopId": 14216, + "name": { + "original": "Estrada do Freixo (fronte Campo Fútbol)" + }, + "latitude": 42.169143301, + "longitude": -8.729076566, + "lines": [ + "7" + ] + }, + { + "stopId": 14217, + "name": { + "original": "Estrada do Monte Alba (frente 54)" + }, + "latitude": 42.164570839, + "longitude": -8.724561475, + "lines": [ + "7" + ] + }, + { + "stopId": 14218, + "name": { + "original": "Estrada do Monte Alba 21" + }, + "latitude": 42.165288305, + "longitude": -8.721367309, + "lines": [ + "7" + ] + }, + { + "stopId": 14219, + "name": { + "original": "Camiño do Pinal 59" + }, + "latitude": 42.159500512, + "longitude": -8.718247279, + "lines": [ + "7" + ] + }, + { + "stopId": 14220, + "name": { + "original": "Camiño da Bouciña 14" + }, + "latitude": 42.225657321, + "longitude": -8.681467666, + "lines": [ + "25" + ] + }, + { + "stopId": 14221, + "name": { + "original": "Camiño da Bouciña 3" + }, + "latitude": 42.225809218, + "longitude": -8.681652991, + "lines": [ + "25" + ] + }, + { + "stopId": 14222, + "name": { + "original": "Camiño do Pinal 5" + }, + "latitude": 42.162959525, + "longitude": -8.716541365, + "lines": [ + "7" + ] + }, + { + "stopId": 14223, + "name": { + "original": "Avda. Beiramar \"Porto Pesqueiro Berbés\"" + }, + "latitude": 42.236650106, + "longitude": -8.73161427, + "lines": [ + "C3i", + "A", + "5A", + "5B", + "10", + "11", + "15C", + "N1", + "N4", + "H1" + ] + }, + { + "stopId": 14224, + "name": { + "original": "Rúa do Conde de Torrecedeira 16" + }, + "latitude": 42.234285927, + "longitude": -8.731266507, + "lines": [ + "C3i", + "A", + "5A", + "5B", + "10", + "11", + "15C", + "N1", + "N4", + "H1" + ] + }, + { + "stopId": 14225, + "name": { + "original": "Rúa do Conde de Torrecedeira 50" + }, + "latitude": 42.231716574, + "longitude": -8.732308737, + "lines": [ + "C3i", + "A", + "5A", + "5B", + "10", + "11", + "15C", + "N1", + "N4", + "H1" + ] + }, + { + "stopId": 14226, + "name": { + "original": "Rúa do Conde de Torrecedeira 70" + }, + "latitude": 42.229574859, + "longitude": -8.733073973, + "lines": [ + "C3i", + "A", + "5A", + "5B", + "10", + "11", + "15C", + "N1", + "N4", + "H1" + ] + }, + { + "stopId": 14227, + "name": { + "original": "Rúa do Conde de Torrecedeira 86" + }, + "latitude": 42.22696657, + "longitude": -8.734559706, + "lines": [ + "C3i", + "A", + "5A", + "5B", + "10", + "11", + "15C", + "N1", + "N4", + "H1" + ] + }, + { + "stopId": 14228, + "name": { + "original": "Avda. de Peinador 100" + }, + "latitude": 42.221696342, + "longitude": -8.632840997, + "lines": [ + "A" + ] + }, + { + "stopId": 14231, + "name": { + "original": "Rúa da Rabadeira 39" + }, + "latitude": 42.235542066, + "longitude": -8.652196565, + "lines": [ + "9B" + ] + }, + { + "stopId": 14232, + "name": { + "original": "Rúa da Rabadeira (fronte 33)" + }, + "latitude": 42.235317662, + "longitude": -8.652094641, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 14233, + "name": { + "original": "Rúa San Cristobo 90" + }, + "latitude": 42.241037275, + "longitude": -8.668947597, + "lines": [ + "9B", + "28" + ] + }, + { + "stopId": 14236, + "name": { + "original": "Rúa de Manuel Cominges (fronte 112)" + }, + "latitude": 42.196308523, + "longitude": -8.723526935, + "lines": [ + "12B" + ] + }, + { + "stopId": 14237, + "name": { + "original": "Rúa de Manuel Cominges 134" + }, + "latitude": 42.196119748, + "longitude": -8.723457198, + "lines": [ + "12B" + ] + }, + { + "stopId": 14238, + "name": { + "original": "Rúa da Saa do Monte 5" + }, + "latitude": 42.20458802, + "longitude": -8.714617309, + "lines": [ + "18B" + ] + }, + { + "stopId": 14240, + "name": { + "original": "Rúa das Chabarras 21" + }, + "latitude": 42.197985091, + "longitude": -8.714523201, + "lines": [ + "18B" + ] + }, + { + "stopId": 14241, + "name": { + "original": "Rúa das Chabarras 60" + }, + "latitude": 42.197842023, + "longitude": -8.71471632, + "lines": [ + "18B" + ] + }, + { + "stopId": 14242, + "name": { + "original": "Rúa das Chabarras (cruce Camiño dos Pasais)" + }, + "latitude": 42.196378259, + "longitude": -8.716979043, + "lines": [ + "18B" + ] + }, + { + "stopId": 14243, + "name": { + "original": "Rúa das Chabarras 24" + }, + "latitude": 42.196539214, + "longitude": -8.716874437, + "lines": [ + "18B" + ] + }, + { + "stopId": 14244, + "name": { + "original": "Rúa de Macal 60" + }, + "latitude": 42.198216234, + "longitude": -8.721498041, + "lines": [ + "18B", + "18H", + "27" + ] + }, + { + "stopId": 14245, + "name": { + "original": "Avda. de García Barbón 43" + }, + "latitude": 42.23691728, + "longitude": -8.716743143, + "lines": [ + "C3i", + "5B", + "10", + "16", + "17", + "N1" + ] + }, + { + "stopId": 14247, + "name": { + "original": "Camiño dos Muíños 69" + }, + "latitude": 42.200511179, + "longitude": -8.769110573, + "lines": [ + "12A" + ] + }, + { + "stopId": 14248, + "name": { + "original": "Camiño dos Muíños 74" + }, + "latitude": 42.200580723, + "longitude": -8.76911862, + "lines": [ + "12A" + ] + }, + { + "stopId": 14249, + "name": { + "original": "Avda. de Cesáreo Vázquez 5" + }, + "latitude": 42.177662554, + "longitude": -8.800157923, + "lines": [ + "12A" + ] + }, + { + "stopId": 14250, + "name": { + "original": "Avda. do Aeroporto 463" + }, + "latitude": 42.234914814, + "longitude": -8.658983411, + "lines": [ + "A", + "9B" + ] + }, + { + "stopId": 14251, + "name": { + "original": "Avda. do Aeroporto (fronte 463)" + }, + "latitude": 42.234817602, + "longitude": -8.65882027, + "lines": [ + "A", + "9B", + "27" + ] + }, + { + "stopId": 14252, + "name": { + "original": "Estrada Clara Campoamor (Instituto)" + }, + "latitude": 42.165934208, + "longitude": -8.707243001, + "lines": [ + "U1" + ] + }, + { + "stopId": 14253, + "name": { + "original": "Estrada Clara Campoamor (cruce Rúa do Padrón do Couto)" + }, + "latitude": 42.164455564, + "longitude": -8.707223843, + "lines": [ + "U1" + ] + }, + { + "stopId": 14255, + "name": { + "original": "Rúa do Pintor Colmeiro (Parque do Pintor Colmeiro)" + }, + "latitude": 42.225111918, + "longitude": -8.726733526, + "lines": [ + "16" + ] + }, + { + "stopId": 14256, + "name": { + "original": "Rúa de Zamora 89" + }, + "latitude": 42.222198901, + "longitude": -8.728317834, + "lines": [ + "16" + ] + }, + { + "stopId": 14257, + "name": { + "original": "Rúa de Zamora 71" + }, + "latitude": 42.223448271, + "longitude": -8.725547112, + "lines": [ + "16" + ] + }, + { + "stopId": 14258, + "name": { + "original": "Rúa de Zamora 51" + }, + "latitude": 42.224870416, + "longitude": -8.723632015, + "lines": [ + "16" + ] + }, + { + "stopId": 14259, + "name": { + "original": "Rúa de Zamora 31" + }, + "latitude": 42.227088982, + "longitude": -8.721545256, + "lines": [ + "16" + ] + }, + { + "stopId": 14260, + "name": { + "original": "Avda. da Gran Vía (fronte Avda. de Madrid)" + }, + "latitude": 42.228741057, + "longitude": -8.71961914, + "lines": [ + "7", + "14", + "15A", + "16", + "18A", + "18B", + "18H", + "H2" + ] + }, + { + "stopId": 14261, + "name": { + "original": "Rúa de Zamora 1" + }, + "latitude": 42.228644118, + "longitude": -8.720692314, + "lines": [ + "16" + ] + }, + { + "stopId": 14264, + "name": { + "original": "Rúa de Urzáiz - Príncipe" + }, + "latitude": 42.235873545, + "longitude": -8.720083317, + "lines": [ + "C1", + "A", + "4A", + "4C", + "5A", + "7", + "9B", + "12B", + "14", + "15B", + "15C", + "16", + "17", + "18A", + "18B", + "18H", + "24", + "28", + "N1", + "N4" + ] + }, + { + "stopId": 14267, + "name": { + "original": "Avda. da Atlántida 64" + }, + "latitude": 42.221892792, + "longitude": -8.758191526, + "lines": [ + "10", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 14268, + "name": { + "original": "Avda. da Atlántida 49" + }, + "latitude": 42.221731945, + "longitude": -8.758417175, + "lines": [ + "10", + "15B", + "15C" + ] + }, + { + "stopId": 14270, + "name": { + "original": "Estrada da Balsa 67" + }, + "latitude": 42.196619218, + "longitude": -8.743240048, + "lines": [ + "17" + ] + }, + { + "stopId": 14271, + "name": { + "original": "Estrada da Balsa 103" + }, + "latitude": 42.196050474, + "longitude": -8.745105715, + "lines": [ + "17" + ] + }, + { + "stopId": 14273, + "name": { + "original": "Rúa do Xalón 41" + }, + "latitude": 42.219274062, + "longitude": -8.656419893, + "lines": [ + "11" + ] + }, + { + "stopId": 14277, + "name": { + "original": "Avda. da Mariña Española 8" + }, + "latitude": 42.251776399, + "longitude": -8.69414009, + "lines": [ + "17" + ] + }, + { + "stopId": 14278, + "name": { + "original": "Avda. da Mariña Española 44" + }, + "latitude": 42.25430173, + "longitude": -8.692915616, + "lines": [ + "17" + ] + }, + { + "stopId": 14279, + "name": { + "original": "Riós (Rotonda)" + }, + "latitude": 42.257069093, + "longitude": -8.690786611, + "lines": [ + "17" + ] + }, + { + "stopId": 14280, + "name": { + "original": "Avda. da Mariña Española (ETEA)" + }, + "latitude": 42.254604716, + "longitude": -8.692539681, + "lines": [ + "17" + ] + }, + { + "stopId": 14281, + "name": { + "original": "Avda. da Mariña Española (Praia de Ríos)" + }, + "latitude": 42.251596707, + "longitude": -8.69420171, + "lines": [ + "17" + ] + }, + { + "stopId": 14287, + "name": { + "original": "Rúa Santa Tegra 67" + }, + "latitude": 42.25020334, + "longitude": -8.701924083, + "lines": [ + "17" + ] + }, + { + "stopId": 14288, + "name": { + "original": "Avda. de Guixar (fronte 28)" + }, + "latitude": 42.249218849, + "longitude": -8.704807605, + "lines": [ + "17" + ] + }, + { + "stopId": 14289, + "name": { + "original": "Rúa de Xulián Estévez (fronte 58)" + }, + "latitude": 42.246484972, + "longitude": -8.705864005, + "lines": [ + "17" + ] + }, + { + "stopId": 14290, + "name": { + "original": "Rúa de Xulián Estévez (fronte 18)" + }, + "latitude": 42.244107542, + "longitude": -8.706343638, + "lines": [ + "17" + ] + }, + { + "stopId": 14291, + "name": { + "original": "Avda. da Ponte (Vigo Memorial)" + }, + "latitude": 42.209935219, + "longitude": -8.671464542, + "lines": [ + "12B", + "15B", + "15C", + "U2" + ] + }, + { + "stopId": 14294, + "name": { + "original": "Avda. de Ricardo Mella 406" + }, + "latitude": 42.190684424876565, + "longitude": -8.799308812770041, + "lines": [ + "12A" + ] + }, + { + "stopId": 14295, + "name": { + "original": "Rúa de Pi i Margall 121" + }, + "latitude": 42.230436358, + "longitude": -8.731437473, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 14296, + "name": { + "original": "Praza dos Leóns (Vigozoo)" + }, + "latitude": 42.248375604, + "longitude": -8.675578666, + "lines": [ + "28" + ] + }, + { + "stopId": 14299, + "name": { + "original": "Avda. de Samil (frente Verbum)" + }, + "latitude": 42.213644883, + "longitude": -8.774567214, + "lines": [ + "C3i", + "15A", + "N1" + ] + }, + { + "stopId": 14300, + "name": { + "original": "Avda. da Florida 30" + }, + "latitude": 42.217907548, + "longitude": -8.73707436, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 14301, + "name": { + "original": "Avda. da Florida 47" + }, + "latitude": 42.218257459, + "longitude": -8.736328798, + "lines": [ + "5A", + "11", + "29" + ] + }, + { + "stopId": 14302, + "name": { + "original": "Estrada Vella de Madrid 7" + }, + "latitude": 42.214542094, + "longitude": -8.696431619, + "lines": [ + "12A", + "12B", + "13", + "H3" + ] + }, + { + "stopId": 14304, + "name": { + "original": "Estrada Vella de Madrid 145" + }, + "latitude": 42.221313975, + "longitude": -8.681944471, + "lines": [ + "12A", + "12B", + "13", + "31" + ] + }, + { + "stopId": 14307, + "name": { + "original": "Rúa do Pintor Colmeiro 11" + }, + "latitude": 42.224464416, + "longitude": -8.727967343, + "lines": [ + "16" + ] + }, + { + "stopId": 14308, + "name": { + "original": "Camiño do Pinal 6" + }, + "latitude": 42.16328558, + "longitude": -8.716707662, + "lines": [ + "7" + ] + }, + { + "stopId": 14309, + "name": { + "original": "Camiño do Pinal 28" + }, + "latitude": 42.161067029, + "longitude": -8.716468628, + "lines": [ + "7" + ] + }, + { + "stopId": 14310, + "name": { + "original": "Camiño do Pinal (fronte 57)" + }, + "latitude": 42.159564137, + "longitude": -8.718295559, + "lines": [ + "7" + ] + }, + { + "stopId": 14311, + "name": { + "original": "Estrada de Valadares 505" + }, + "latitude": 42.162720337, + "longitude": -8.718900908, + "lines": [ + "7" + ] + }, + { + "stopId": 14314, + "name": { + "original": "Rúa das Mantelas (cruce Avda. da Gran Vía)" + }, + "latitude": 42.227212568, + "longitude": -8.720183032, + "lines": [ + "18A" + ] + }, + { + "stopId": 14315, + "name": { + "original": "Rúa das Mantelas 92" + }, + "latitude": 42.22393338, + "longitude": -8.716924148, + "lines": [ + "18A" + ] + }, + { + "stopId": 14317, + "name": { + "original": "Rúa da Salgueira Entrada (Igrexa)" + }, + "latitude": 42.222723933, + "longitude": -8.719150283, + "lines": [ + "18A" + ] + }, + { + "stopId": 14318, + "name": { + "original": "Rúa da Salguera Entrada (fronte 5)" + }, + "latitude": 42.222591256, + "longitude": -8.717753486, + "lines": [ + "18A" + ] + }, + { + "stopId": 14319, + "name": { + "original": "Rúa das Coutadas (Fonte)" + }, + "latitude": 42.221002214, + "longitude": -8.72027208, + "lines": [ + "18A" + ] + }, + { + "stopId": 14320, + "name": { + "original": "Rúa do Miradoiro (Rotonda Centro Comercial)" + }, + "latitude": 42.220799025, + "longitude": -8.723345356, + "lines": [ + "18A" + ] + }, + { + "stopId": 14321, + "name": { + "original": "Camiño do Freixeiro 74" + }, + "latitude": 42.218131641, + "longitude": -8.723120057, + "lines": [ + "18A" + ] + }, + { + "stopId": 14322, + "name": { + "original": "Rúa da Fonte Santa 4" + }, + "latitude": 42.217813814, + "longitude": -8.721352482, + "lines": [ + "18A" + ] + }, + { + "stopId": 14323, + "name": { + "original": "Rúa Finca dos Aires (cruce Rúa da Fonte Santa)" + }, + "latitude": 42.217059742, + "longitude": -8.720340235, + "lines": [ + "18A" + ] + }, + { + "stopId": 14324, + "name": { + "original": "Rúa Finca dos Aires (Urbanización)" + }, + "latitude": 42.217256401, + "longitude": -8.720101519, + "lines": [ + "18A" + ] + }, + { + "stopId": 14325, + "name": { + "original": "Rúa da Fonte Santa (fronte 4)" + }, + "latitude": 42.217848286, + "longitude": -8.7214811, + "lines": [ + "18A" + ] + }, + { + "stopId": 14326, + "name": { + "original": "Baixada á Ponte Nova 61" + }, + "latitude": 42.218038279, + "longitude": -8.722489738, + "lines": [ + "18A" + ] + }, + { + "stopId": 14328, + "name": { + "original": "Citroën - PSA" + }, + "latitude": 42.208988415, + "longitude": -8.746151897, + "lines": [ + "LZH", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 14329, + "name": { + "original": "Citroën (Puerta Principal)" + }, + "latitude": 42.210124372, + "longitude": -8.741139991, + "lines": [ + "LZH", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 14330, + "name": { + "original": "Subida ás Chans (fronte cruce Rúa Senra)" + }, + "latitude": 42.198072667, + "longitude": -8.682624653, + "lines": [ + "14" + ] + }, + { + "stopId": 14331, + "name": { + "original": "Rúa de Álvaro Cunqueiro 30" + }, + "latitude": 42.223769828, + "longitude": -8.728938728, + "lines": [ + "4A", + "4C", + "5A", + "5B", + "11", + "12A", + "12B", + "17", + "27", + "N1", + "LZH" + ] + }, + { + "stopId": 14333, + "name": { + "original": "Rúa de Cánovas del Castillo 18" + }, + "latitude": 42.240189011, + "longitude": -8.726765331, + "lines": [ + "C1", + "C3d", + "A", + "5A", + "9B", + "10", + "15B", + "15C", + "28", + "N4" + ] + }, + { + "stopId": 14335, + "name": { + "original": "Camiño do Arieiro (Residencia de Maiores)" + }, + "latitude": 42.212692269, + "longitude": -8.675661599, + "lines": [ + "31" + ] + }, + { + "stopId": 14336, + "name": { + "original": "Rúa das Teixugueiras 8" + }, + "latitude": 42.21447626, + "longitude": -8.75600551, + "lines": [ + "13", + "15A" + ] + }, + { + "stopId": 14337, + "name": { + "original": "Rúa do Limpiño (Rotonda Rúa Teixugueiras)" + }, + "latitude": 42.213080218, + "longitude": -8.754660224, + "lines": [ + "5A", + "5B", + "13", + "15A", + "15B", + "N4", + "U1", + "H", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 14345, + "name": { + "original": "Rúa do Areiro 49" + }, + "latitude": 42.237269816, + "longitude": -8.685138009, + "lines": [ + "28" + ] + }, + { + "stopId": 14346, + "name": { + "original": "Rúa do Areiro 52" + }, + "latitude": 42.237287688, + "longitude": -8.685019992, + "lines": [ + "28" + ] + }, + { + "stopId": 14347, + "name": { + "original": "Rúa do Areiro (cruce Salcides)" + }, + "latitude": 42.23913765, + "longitude": -8.683873934, + "lines": [ + "28" + ] + }, + { + "stopId": 14348, + "name": { + "original": "Rúa do Areiro 76" + }, + "latitude": 42.238950988, + "longitude": -8.683793467, + "lines": [ + "28" + ] + }, + { + "stopId": 14349, + "name": { + "original": "Rúa do Areiro (Campo de Fútbol)" + }, + "latitude": 42.244717312, + "longitude": -8.678473607, + "lines": [ + "28" + ] + }, + { + "stopId": 14350, + "name": { + "original": "Rúa do Areiro (fronte Campo de Fútbol)" + }, + "latitude": 42.244849353, + "longitude": -8.678366319, + "lines": [ + "28" + ] + }, + { + "stopId": 14353, + "name": { + "original": "Praza dos Leóns (fronte Vigozoo)" + }, + "latitude": 42.248151648, + "longitude": -8.675976097, + "lines": [ + "28" + ] + }, + { + "stopId": 14354, + "name": { + "original": "Avda. de Ramón Nieto (fronte Igrexa)" + }, + "latitude": 42.225911433, + "longitude": -8.675526243, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 14355, + "name": { + "original": "Avda. de Ramón Nieto 409" + }, + "latitude": 42.226638363, + "longitude": -8.676135104, + "lines": [ + "11", + "15A", + "15B", + "15C", + "31", + "H3" + ] + }, + { + "stopId": 14356, + "name": { + "original": "Avda. de Ricardo Mella 314" + }, + "latitude": 42.192009114, + "longitude": -8.783993123, + "lines": [ + "12A" + ] + }, + { + "stopId": 14357, + "name": { + "original": "Avda. de Ricardo Mella (cruce Camiño do Río)" + }, + "latitude": 42.191796473, + "longitude": -8.784014088, + "lines": [ + "12A" + ] + }, + { + "stopId": 14358, + "name": { + "original": "Rúa das Teixugueiras 28" + }, + "latitude": 42.209054557, + "longitude": -8.75715865, + "lines": [ + "5A", + "5B", + "13", + "N4" + ] + }, + { + "stopId": 14359, + "name": { + "original": "Rúa das Teixugueiras 16-Portal 2" + }, + "latitude": 42.212235738, + "longitude": -8.755011746, + "lines": [ + "5A", + "5B", + "13", + "N4" + ] + }, + { + "stopId": 14360, + "name": { + "original": "Rúa das Teixugueiras 19-Portal 5" + }, + "latitude": 42.208965857, + "longitude": -8.757020567, + "lines": [ + "5A", + "5B", + "13", + "N4", + "U1", + "H", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 14361, + "name": { + "original": "Rúa das Teixugueiras 17" + }, + "latitude": 42.209770472, + "longitude": -8.755295907, + "lines": [ + "5A", + "5B", + "13", + "15A", + "N4", + "U1", + "H", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 14362, + "name": { + "original": "Avda. de Samil 101" + }, + "latitude": 42.202937872, + "longitude": -8.776830486, + "lines": [ + "C3d", + "4C", + "10" + ] + }, + { + "stopId": 14364, + "name": { + "original": "Estrada das Plantas (fronte Cidade Deportiva)" + }, + "latitude": 42.175757186, + "longitude": -8.671074371, + "lines": [ + "15C" + ] + }, + { + "stopId": 14365, + "name": { + "original": "Estrada das Plantas (Viveiros)" + }, + "latitude": 42.181650197, + "longitude": -8.667515723, + "lines": [ + "15C" + ] + }, + { + "stopId": 14372, + "name": { + "original": "Barrio da Salgueira 22" + }, + "latitude": 42.221887526, + "longitude": -8.720011371, + "lines": [ + "18A" + ] + }, + { + "stopId": 14376, + "name": { + "original": "Rúa da Pateira 20" + }, + "latitude": 42.226612651, + "longitude": -8.699658408, + "lines": [ + "25" + ] + }, + { + "stopId": 14377, + "name": { + "original": "Rúa da Pateira 5" + }, + "latitude": 42.226582661, + "longitude": -8.700385762, + "lines": [ + "25" + ] + }, + { + "stopId": 14378, + "name": { + "original": "Rúa Molais 83" + }, + "latitude": 42.22396201, + "longitude": -8.653340726, + "lines": [ + "25" + ] + }, + { + "stopId": 14381, + "name": { + "original": "Rúa do Abade Juan de Bastos 6" + }, + "latitude": 42.195647685, + "longitude": -8.728974153, + "lines": [ + "17" + ] + }, + { + "stopId": 14383, + "name": { + "original": "Estrada Clara Campoamor (cruce Estrada do Portal)" + }, + "latitude": 42.174718265, + "longitude": -8.713684656, + "lines": [ + "U1" + ] + }, + { + "stopId": 14384, + "name": { + "original": "Estrada Clara Campoamor (Parque Tecnolóxico)" + }, + "latitude": 42.175073486, + "longitude": -8.713494654, + "lines": [ + "U1" + ] + }, + { + "stopId": 14385, + "name": { + "original": "Rúa da Vista do Mar 45" + }, + "latitude": 42.240712912, + "longitude": -8.6919418, + "lines": [ + "4A", + "24" + ] + }, + { + "stopId": 14386, + "name": { + "original": "Rúa da Vista do Mar (Embalse)" + }, + "latitude": 42.238020208, + "longitude": -8.691543884, + "lines": [ + "4A", + "24" + ] + }, + { + "stopId": 14387, + "name": { + "original": "Rúa da Vista do Mar 1" + }, + "latitude": 42.237167043, + "longitude": -8.693243792, + "lines": [ + "4A", + "24" + ] + }, + { + "stopId": 14388, + "name": { + "original": "Rúa das Teixugueiras 11" + }, + "latitude": 42.211610124, + "longitude": -8.754550253, + "lines": [ + "5A", + "5B", + "13", + "15A", + "N4", + "U1", + "H", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 14389, + "name": { + "original": "Rúa das Teixugueiras 22" + }, + "latitude": 42.210212603, + "longitude": -8.755079989, + "lines": [ + "5A", + "5B", + "13", + "N4" + ] + }, + { + "stopId": 14390, + "name": { + "original": "Rúa do Salgueiro (cruce Camiño Sanatorio)" + }, + "latitude": 42.241570883, + "longitude": -8.655380719, + "lines": [ + "9B", + "28" + ] + }, + { + "stopId": 14391, + "name": { + "original": "Rúa do Salgueiro (fronte 38)" + }, + "latitude": 42.241652296, + "longitude": -8.655302935, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 14392, + "name": { + "original": "Rúa da Pedra Seixa (Colexio)" + }, + "latitude": 42.209458591, + "longitude": -8.760561083, + "lines": [ + "5A" + ] + }, + { + "stopId": 14393, + "name": { + "original": "Rúa da Pedra Seixa (fronte Colexio)" + }, + "latitude": 42.209568936, + "longitude": -8.760777001, + "lines": [ + "5A" + ] + }, + { + "stopId": 14395, + "name": { + "original": "Estrada de Madrid 217" + }, + "latitude": 42.215601037, + "longitude": -8.675477665, + "lines": [ + "12B", + "15B", + "15C" + ] + }, + { + "stopId": 14396, + "name": { + "original": "Avda. de García Barbón 106" + }, + "latitude": 42.239965365, + "longitude": -8.708024282, + "lines": [ + "C3d", + "5B", + "10", + "17", + "31", + "H2", + "H3", + "PSA 1" + ] + }, + { + "stopId": 14397, + "name": { + "original": "Avda. de García Barbón (fronte 104)" + }, + "latitude": 42.23973713, + "longitude": -8.708397682, + "lines": [ + "C3i", + "5B", + "10", + "17", + "N1", + "H3" + ] + }, + { + "stopId": 14398, + "name": { + "original": "Avda. da Gran Vía 116" + }, + "latitude": 42.22406594, + "longitude": -8.723691036, + "lines": [ + "C3d", + "13", + "15A", + "23", + "29", + "H2", + "PSA 1" + ] + }, + { + "stopId": 14401, + "name": { + "original": "Rúa de San Paio (cruce Camiño Barroca)" + }, + "latitude": 42.21072167, + "longitude": -8.76212542, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 14402, + "name": { + "original": "Rúa de San Paio 111" + }, + "latitude": 42.210791203, + "longitude": -8.761940347, + "lines": [ + "4A", + "12A" + ] + }, + { + "stopId": 14403, + "name": { + "original": "Rúa de Pedro Alvarado (cruce Camiño das Maceiras)" + }, + "latitude": 42.25049654, + "longitude": -8.698390035, + "lines": [ + "17" + ] + }, + { + "stopId": 14404, + "name": { + "original": "Rúa do Doutor Corbal 58" + }, + "latitude": 42.251785642, + "longitude": -8.696871994, + "lines": [ + "17" + ] + }, + { + "stopId": 14406, + "name": { + "original": "Rúa de Enrique Lorenzo 32" + }, + "latitude": 42.249462772, + "longitude": -8.699772952, + "lines": [ + "17" + ] + }, + { + "stopId": 14408, + "name": { + "original": "Rúa de Pedro Alvarado 5" + }, + "latitude": 42.248885006, + "longitude": -8.698128758, + "lines": [ + "17" + ] + }, + { + "stopId": 14409, + "name": { + "original": "Estrada das Plantas (fronte cruce Avda. do Rebullón)" + }, + "latitude": 42.204188441, + "longitude": -8.670257126, + "lines": [ + "15B", + "15C" + ] + }, + { + "stopId": 14410, + "name": { + "original": "Estrada das Plantas (cruce Avda. do Rebullón)" + }, + "latitude": 42.204639457, + "longitude": -8.670329545, + "lines": [ + "15C" + ] + }, + { + "stopId": 14411, + "name": { + "original": "Rúa de Xeme 1" + }, + "latitude": 42.205174543, + "longitude": -8.698209134, + "lines": [ + "14" + ] + }, + { + "stopId": 14412, + "name": { + "original": "Rúa de Xeme 6" + }, + "latitude": 42.20497586, + "longitude": -8.697957006, + "lines": [ + "14" + ] + }, + { + "stopId": 14413, + "name": { + "original": "Estrada da Garrida (cruce Camiño Fabas)" + }, + "latitude": 42.173955568, + "longitude": -8.703050076, + "lines": [ + "7" + ] + }, + { + "stopId": 14414, + "name": { + "original": "Avda. de Santa Mariña 40" + }, + "latitude": 42.221587211, + "longitude": -8.665078444, + "lines": [ + "11" + ] + }, + { + "stopId": 14415, + "name": { + "original": "Avda. de Santa Mariña (antes 49)" + }, + "latitude": 42.221557416, + "longitude": -8.665381534, + "lines": [ + "11" + ] + }, + { + "stopId": 14416, + "name": { + "original": "Rúa de Severino Cobas 118" + }, + "latitude": 42.225468623, + "longitude": -8.691491081, + "lines": [ + "25" + ] + }, + { + "stopId": 14419, + "name": { + "original": "Estrada de Bembrive (cruce Camiño dos Rapadouros)" + }, + "latitude": 42.201138734, + "longitude": -8.688585073, + "lines": [ + "6" + ] + }, + { + "stopId": 14420, + "name": { + "original": "Estrada de Bembrive 318" + }, + "latitude": 42.201419233, + "longitude": -8.688526069, + "lines": [ + "6" + ] + }, + { + "stopId": 14421, + "name": { + "original": "Estrada das Prantas (fronte Campo de Béisbol)" + }, + "latitude": 42.186683264, + "longitude": -8.669320703, + "lines": [ + "15C" + ] + }, + { + "stopId": 14422, + "name": { + "original": "Estrada das Plantas (Campo de Béisbol)" + }, + "latitude": 42.18695315, + "longitude": -8.669514066, + "lines": [ + "15C" + ] + }, + { + "stopId": 14425, + "name": { + "original": "Avda. do Alcalde Gregorio Espino 2" + }, + "latitude": 42.232253792, + "longitude": -8.707208575, + "lines": [ + "31" + ] + }, + { + "stopId": 14475, + "name": { + "original": "Rúa de Barcelona 78" + }, + "latitude": 42.222992354, + "longitude": -8.728300382, + "lines": [ + "C1" + ] + }, + { + "stopId": 14890, + "name": { + "original": "Rúa das Teixugueiras 25" + }, + "latitude": 42.207545331, + "longitude": -8.758718406, + "lines": [ + "5B", + "13", + "N4", + "U1", + "H", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 14892, + "name": { + "original": "Rúa do Conde de Torrecedeira 123" + }, + "latitude": 42.224929414, + "longitude": -8.735414067, + "lines": [ + "C1", + "C3d", + "A", + "9B", + "15C", + "N4", + "H1" + ] + }, + { + "stopId": 14893, + "name": { + "original": "Rúa de Manuel Costas Bastos 26" + }, + "latitude": 42.243157956, + "longitude": -8.666962176, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 14894, + "name": { + "original": "Avda. do Alcalde Portanet 8" + }, + "latitude": 42.211736934, + "longitude": -8.733337505, + "lines": [ + "7", + "12B", + "17", + "H1" + ] + }, + { + "stopId": 14895, + "name": { + "original": "Rúa do Areiro (cruce Camiño das Laxes)" + }, + "latitude": 42.241392275, + "longitude": -8.681203235, + "lines": [ + "28" + ] + }, + { + "stopId": 14896, + "name": { + "original": "Rúa do Areiro 93" + }, + "latitude": 42.241385532, + "longitude": -8.681400937, + "lines": [ + "28" + ] + }, + { + "stopId": 14897, + "name": { + "original": "Camiño do Arieiro (fronte 13)" + }, + "latitude": 42.213239161, + "longitude": -8.67854147, + "lines": [ + "31" + ] + }, + { + "stopId": 14898, + "name": { + "original": "Camiño do Arieiro 13" + }, + "latitude": 42.213239161, + "longitude": -8.678369808, + "lines": [ + "31" + ] + }, + { + "stopId": 14899, + "name": { + "original": "Rúa de López Mora 33" + }, + "latitude": 42.225485719, + "longitude": -8.730501434, + "lines": [ + "5A", + "5B", + "12A" + ] + }, + { + "stopId": 14900, + "name": { + "original": "Rúa de Martín Echegaray 24" + }, + "latitude": 42.217196117, + "longitude": -8.743726669, + "lines": [ + "23", + "N4" + ] + }, + { + "stopId": 14901, + "name": { + "original": "Avda. de Castelao 1" + }, + "latitude": 42.220211003, + "longitude": -8.734183023, + "lines": [ + "C3i", + "10", + "11", + "15A", + "U1" + ] + }, + { + "stopId": 14903, + "name": { + "original": "Rúa de Pi i Margall 66" + }, + "latitude": 42.23174719, + "longitude": -8.731081308, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 14905, + "name": { + "original": "Camiño da Devesa (Cemiterio)" + }, + "latitude": 42.249981353, + "longitude": -8.667186504, + "lines": [ + "9B" + ] + }, + { + "stopId": 14906, + "name": { + "original": "Rúa da Rabadeira 6" + }, + "latitude": 42.232479787, + "longitude": -8.654890792, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 14907, + "name": { + "original": "Rúa da Rabadeira 24" + }, + "latitude": 42.233655479, + "longitude": -8.653300242, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 14908, + "name": { + "original": "Rúa da Rabadeira 17" + }, + "latitude": 42.233829075, + "longitude": -8.653458259, + "lines": [ + "9B" + ] + }, + { + "stopId": 14909, + "name": { + "original": "Rúa da Rabadeira 11" + }, + "latitude": 42.232663198, + "longitude": -8.655097059, + "lines": [ + "9B" + ] + }, + { + "stopId": 14910, + "name": { + "original": "Estrada do Marco 4" + }, + "latitude": 42.21025095, + "longitude": -8.704036986, + "lines": [ + "18A", + "18B", + "H3" + ] + }, + { + "stopId": 14911, + "name": { + "original": "Estrada do Marco 16" + }, + "latitude": 42.208830737, + "longitude": -8.706971174, + "lines": [ + "18A", + "18B", + "H3" + ] + }, + { + "stopId": 15001, + "name": { + "original": "Rúa Regueiro do Forno (Vial C) Centro de Servicios" + }, + "latitude": 42.176053629, + "longitude": -8.709460132, + "lines": [ + "PTL" + ] + }, + { + "stopId": 15002, + "name": { + "original": "PTL 2" + }, + "latitude": 42.177194637, + "longitude": -8.707850807, + "lines": [ + "PTL" + ] + }, + { + "stopId": 15003, + "name": { + "original": "PTL 3" + }, + "latitude": 42.178124939, + "longitude": -8.706606262, + "lines": [ + "PTL" + ] + }, + { + "stopId": 15004, + "name": { + "original": "PTL 4" + }, + "latitude": 42.176503017, + "longitude": -8.710007303, + "lines": [ + "PTL" + ] + }, + { + "stopId": 20009, + "name": { + "original": "Estrada Herville 16" + }, + "latitude": 42.154843231, + "longitude": -8.67357438, + "lines": [ + "7" + ] + }, + { + "stopId": 20010, + "name": { + "original": "Avda. de Balaídos 69" + }, + "latitude": 42.212824845, + "longitude": -8.737161077, + "lines": [ + "16", + "23", + "H" + ] + }, + { + "stopId": 20011, + "name": { + "original": "Avda. de Balaídos 11" + }, + "latitude": 42.213089061, + "longitude": -8.733392573, + "lines": [ + "16", + "23", + "H" + ] + }, + { + "stopId": 20012, + "name": { + "original": "Avda. de Castrelos 33" + }, + "latitude": 42.215888032, + "longitude": -8.732331627, + "lines": [ + "A", + "16", + "23", + "27", + "H2" + ] + }, + { + "stopId": 20013, + "name": { + "original": "Avda. de Castrelos 116" + }, + "latitude": 42.215905917, + "longitude": -8.732471102, + "lines": [ + "7", + "12B", + "17", + "27", + "H2", + "PTL" + ] + }, + { + "stopId": 20018, + "name": { + "original": "Estrada Herville 70" + }, + "latitude": 42.151451604, + "longitude": -8.673803367, + "lines": [ + "7" + ] + }, + { + "stopId": 20019, + "name": { + "original": "Subida aos Padróns 165" + }, + "latitude": 42.149222193, + "longitude": -8.679363987, + "lines": [ + "7" + ] + }, + { + "stopId": 20020, + "name": { + "original": "Subida aos Padróns (cruce Parque Forestal)" + }, + "latitude": 42.151606055, + "longitude": -8.679299082, + "lines": [ + "7" + ] + }, + { + "stopId": 20021, + "name": { + "original": "Subida aos Padróns (fronte 34)" + }, + "latitude": 42.152770176, + "longitude": -8.686251828, + "lines": [ + "7" + ] + }, + { + "stopId": 20022, + "name": { + "original": "Rúa da Vía Norte (Hospital)" + }, + "latitude": 42.234622237, + "longitude": -8.707758443, + "lines": [ + "24" + ] + }, + { + "stopId": 20023, + "name": { + "original": "Rúa da Vía Norte - Est. Intermodal - C.C." + }, + "latitude": 42.234062973, + "longitude": -8.712195759, + "lines": [ + "24" + ] + }, + { + "stopId": 20024, + "name": { + "original": "Rúa das Teixugueiras 34" + }, + "latitude": 42.207634066, + "longitude": -8.758920861, + "lines": [ + "5B", + "13", + "N4" + ] + }, + { + "stopId": 20025, + "name": { + "original": "Rúa das Teixugueiras 38" + }, + "latitude": 42.206553268, + "longitude": -8.760122491, + "lines": [ + "5B", + "13", + "N4" + ] + }, + { + "stopId": 20026, + "name": { + "original": "Rúa das Teixugueiras 29" + }, + "latitude": 42.206488366, + "longitude": -8.759906624, + "lines": [ + "5B", + "13", + "N4", + "U1", + "H", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 20027, + "name": { + "original": "Avda. de Castelao 64" + }, + "latitude": 42.217691983, + "longitude": -8.749585877, + "lines": [ + "C3d", + "4A", + "4C", + "5B", + "10", + "12A", + "13", + "15A", + "N4", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 20029, + "name": { + "original": "Subida á Madroa (fronte Campo Fútbol)" + }, + "latitude": 42.245921506, + "longitude": -8.673014474, + "lines": [ + "9B", + "28" + ] + }, + { + "stopId": 20030, + "name": { + "original": "Subida á Madroa (Campo Fútbol)" + }, + "latitude": 42.247859379, + "longitude": -8.674363625, + "lines": [ + "9B", + "28" + ] + }, + { + "stopId": 20041, + "name": { + "original": "Rúa da Cabalaría 91" + }, + "latitude": 42.233622103, + "longitude": -8.689209566, + "lines": [ + "27", + "28" + ] + }, + { + "stopId": 20042, + "name": { + "original": "Rúa da Cabalaría 148" + }, + "latitude": 42.233723398, + "longitude": -8.689094231, + "lines": [ + "28" + ] + }, + { + "stopId": 20043, + "name": { + "original": "Rúa do Areiro 20" + }, + "latitude": 42.236036786, + "longitude": -8.686656768, + "lines": [ + "28" + ] + }, + { + "stopId": 20044, + "name": { + "original": "Rúa de Martín Echegaray 7" + }, + "latitude": 42.215220874, + "longitude": -8.742680967, + "lines": [ + "23", + "N4" + ] + }, + { + "stopId": 20045, + "name": { + "original": "Rúa de Xestoso 4" + }, + "latitude": 42.200532989, + "longitude": -8.674075447, + "lines": [ + "15B" + ] + }, + { + "stopId": 20046, + "name": { + "original": "Rúa de Xestoso 12" + }, + "latitude": 42.201968444, + "longitude": -8.67477879, + "lines": [ + "15B" + ] + }, + { + "stopId": 20047, + "name": { + "original": "Rúa do Xestoso 72" + }, + "latitude": 42.204330306, + "longitude": -8.674670483, + "lines": [ + "15B" + ] + }, + { + "stopId": 20048, + "name": { + "original": "Avda. de Cesáreo Vázquez (cruce Camiño Amariz Lourenzo)" + }, + "latitude": 42.182684406, + "longitude": -8.802402364, + "lines": [ + "11", + "12A" + ] + }, + { + "stopId": 20049, + "name": { + "original": "Avda. de Cesáreo Vázquez 62" + }, + "latitude": 42.18238342, + "longitude": -8.802126069, + "lines": [ + "11" + ] + }, + { + "stopId": 20050, + "name": { + "original": "Rúa de Severino Cobas 186" + }, + "latitude": 42.225550059, + "longitude": -8.686684563, + "lines": [ + "25" + ] + }, + { + "stopId": 20051, + "name": { + "original": "Rúa de Severino Cobas 89" + }, + "latitude": 42.225652904, + "longitude": -8.686624017, + "lines": [ + "25" + ] + }, + { + "stopId": 20052, + "name": { + "original": "Rúa de Aragón 21" + }, + "latitude": 42.232748414, + "longitude": -8.702539655, + "lines": [ + "4A", + "H3" + ] + }, + { + "stopId": 20053, + "name": { + "original": "Rúa de Ángel de Lema (cruce Paraixal)" + }, + "latitude": 42.248962858, + "longitude": -8.688272303, + "lines": [ + "C3i", + "10" + ] + }, + { + "stopId": 20054, + "name": { + "original": "Rúa de Ángel de Lema 33" + }, + "latitude": 42.248897377, + "longitude": -8.689150714, + "lines": [ + "C3d", + "10" + ] + }, + { + "stopId": 20057, + "name": { + "original": "Estación Ferrocarril Guixar" + }, + "latitude": 42.238843911, + "longitude": -8.713008504, + "lines": [ + "A", + "5B", + "16", + "24" + ] + }, + { + "stopId": 20058, + "name": { + "original": "Rúa do Canceleiro 6" + }, + "latitude": 42.238435471, + "longitude": -8.714413687, + "lines": [ + "5B", + "16" + ] + }, + { + "stopId": 20059, + "name": { + "original": "Rúa de Manuel Álvarez (fronte 10)" + }, + "latitude": 42.222745522, + "longitude": -8.677932515, + "lines": [ + "25", + "31", + "H3" + ] + }, + { + "stopId": 20060, + "name": { + "original": "Rúa de Manuel Álvarez 10" + }, + "latitude": 42.22282586, + "longitude": -8.678077606, + "lines": [ + "25", + "31", + "H3" + ] + }, + { + "stopId": 20061, + "name": { + "original": "Rúa de Martín Echegaray (Colexio)" + }, + "latitude": 42.217568173, + "longitude": -8.744018511, + "lines": [ + "23", + "N4" + ] + }, + { + "stopId": 20062, + "name": { + "original": "Avda. de Beiramar 1" + }, + "latitude": 42.236143706, + "longitude": -8.73180718, + "lines": [ + "10", + "15B" + ] + }, + { + "stopId": 20071, + "name": { + "original": "Rúa de Xestoso (fronte 105)" + }, + "latitude": 42.205511653, + "longitude": -8.672824803, + "lines": [ + "15B" + ] + }, + { + "stopId": 20072, + "name": { + "original": "Camiño do Pouso" + }, + "latitude": 42.196643694, + "longitude": -8.671663218, + "lines": [ + "15B" + ] + }, + { + "stopId": 20075, + "name": { + "original": "Avda. de Castelao 65" + }, + "latitude": 42.218011215, + "longitude": -8.745369728, + "lines": [ + "C3i", + "4A", + "4C", + "10", + "11", + "12A", + "15A", + "N1", + "N4", + "U1" + ] + }, + { + "stopId": 20076, + "name": { + "original": "Avda. de Castelao 25" + }, + "latitude": 42.21901679, + "longitude": -8.739919147, + "lines": [ + "C3i", + "4A", + "4C", + "10", + "11", + "12A", + "15A", + "N1", + "U1" + ] + }, + { + "stopId": 20077, + "name": { + "original": "Avda. de Castelao 40" + }, + "latitude": 42.219259727, + "longitude": -8.739809435, + "lines": [ + "C3d", + "4A", + "4C", + "5B", + "10", + "12A", + "13", + "15A", + "PSA 1", + "PSA 4" + ] + }, + { + "stopId": 20078, + "name": { + "original": "Avda. das Camelias 3" + }, + "latitude": 42.233341329, + "longitude": -8.728967219, + "lines": [ + "4A", + "4C", + "11", + "12B", + "17", + "27", + "N1" + ] + }, + { + "stopId": 20079, + "name": { + "original": "Avda. das Camelias 8" + }, + "latitude": 42.23341294, + "longitude": -8.729045156, + "lines": [ + "4A", + "4C", + "7", + "12B", + "17", + "27", + "PSA 4" + ] + }, + { + "stopId": 20080, + "name": { + "original": "Avda. de Santa Mariña 68" + }, + "latitude": 42.221674556, + "longitude": -8.660937347, + "lines": [ + "11" + ] + }, + { + "stopId": 20081, + "name": { + "original": "Subida aos Padróns (cruce Camiño da Chan da Rabicha)" + }, + "latitude": 42.151852858, + "longitude": -8.684956786, + "lines": [ + "7" + ] + }, + { + "stopId": 20082, + "name": { + "original": "Avda. de Santa Mariña (fronte 66)" + }, + "latitude": 42.221758032, + "longitude": -8.661135597, + "lines": [ + "11" + ] + }, + { + "stopId": 20083, + "name": { + "original": "Rúa Castañal 6" + }, + "latitude": 42.188074669, + "longitude": -8.701928367, + "lines": [ + "27" + ] + }, + { + "stopId": 20084, + "name": { + "original": "Rúa Castañal 26" + }, + "latitude": 42.18711079, + "longitude": -8.699519743, + "lines": [ + "27" + ] + }, + { + "stopId": 20085, + "name": { + "original": "Rúa Castañal (cruce Camiño das Presas)" + }, + "latitude": 42.185852445, + "longitude": -8.696410892, + "lines": [ + "27" + ] + }, + { + "stopId": 20086, + "name": { + "original": "Estrada dos Seixiños 67" + }, + "latitude": 42.190645281, + "longitude": -8.696150583, + "lines": [ + "27" + ] + }, + { + "stopId": 20087, + "name": { + "original": "Estrada dos Seixiños 23" + }, + "latitude": 42.194639373, + "longitude": -8.696795357, + "lines": [ + "27" + ] + }, + { + "stopId": 20089, + "name": { + "original": "Porriño - Padre Seixas ©" + }, + "latitude": 42.213044566, + "longitude": -8.751396835, + "lines": [ + "16" + ] + }, + { + "stopId": 20091, + "name": { + "original": "Camiño da Miragaia 11-13" + }, + "latitude": 42.238164803, + "longitude": -8.711212761, + "lines": [ + "A", + "5B", + "16", + "24" + ] + }, + { + "stopId": 20094, + "name": { + "original": "Rúa das Mantelas (fronte 63)" + }, + "latitude": 42.22518736, + "longitude": -8.717399288, + "lines": [ + "18A" + ] + }, + { + "stopId": 20095, + "name": { + "original": "Estrada Vella de Madrid 107A" + }, + "latitude": 42.219212419, + "longitude": -8.685836356, + "lines": [ + "12A", + "12B", + "13", + "H3" + ] + }, + { + "stopId": 20096, + "name": { + "original": "Estrada Vella de Madrid (fronte 107A)" + }, + "latitude": 42.219128991, + "longitude": -8.685753208, + "lines": [ + "12A", + "12B", + "13", + "U2", + "H3" + ] + }, + { + "stopId": 20099, + "name": { + "original": "Rúa de Camilo Veiga 48" + }, + "latitude": 42.222390674, + "longitude": -8.752507356, + "lines": [ + "C3i", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 20100, + "name": { + "original": "Rúa de Camilo Veiga 6" + }, + "latitude": 42.223195763, + "longitude": -8.749650702, + "lines": [ + "C3i", + "15B", + "15C", + "N1" + ] + }, + { + "stopId": 20102, + "name": { + "original": "H. A. Cunqueiro (Porta Principal)" + }, + "latitude": 42.191034002, + "longitude": -8.714303116, + "lines": [ + "6", + "12B", + "18H", + "27", + "H1", + "H2", + "H3", + "H" + ] + }, + { + "stopId": 20103, + "name": { + "original": "Avda. do Fragoso 21" + }, + "latitude": 42.218946899, + "longitude": -8.733670293, + "lines": [ + "7", + "12B", + "17", + "N4", + "H1" + ] + }, + { + "stopId": 20104, + "name": { + "original": "Rúa de Emilia Pardo Bazán 134" + }, + "latitude": 42.220938435, + "longitude": -8.709621883, + "lines": [ + "14" + ] + }, + { + "stopId": 20105, + "name": { + "original": "Rúa de Emilia Pardo Bazán 121" + }, + "latitude": 42.221232035, + "longitude": -8.709808647, + "lines": [ + "14" + ] + }, + { + "stopId": 20107, + "name": { + "original": "Estrada do Porto (Lavadero)" + }, + "latitude": 42.188244696, + "longitude": -8.703164368, + "lines": [ + "6", + "27" + ] + }, + { + "stopId": 20110, + "name": { + "original": "Rúa de Manuel Castro 10" + }, + "latitude": 42.213797254, + "longitude": -8.741472696, + "lines": [ + "23", + "N4" + ] + }, + { + "stopId": 20111, + "name": { + "original": "H. A. Cunqueiro (Hospital de Día)" + }, + "latitude": 42.187585838, + "longitude": -8.716278919, + "lines": [ + "A", + "6", + "12B", + "18H", + "27", + "H1", + "H2", + "H3", + "H" + ] + }, + { + "stopId": 20112, + "name": { + "original": "H. A. Cunqueiro (Urxencias)" + }, + "latitude": 42.188578188, + "longitude": -8.713087125, + "lines": [ + "6", + "12B", + "18H", + "H1", + "H3", + "H" + ] + }, + { + "stopId": 20113, + "name": { + "original": "Praza de América 3 (Dirección Hospital)" + }, + "latitude": 42.220876566, + "longitude": -8.733367644, + "lines": [ + "12B", + "H1", + "H2", + "PTL" + ] + }, + { + "stopId": 20114, + "name": { + "original": "Estrada do Porto (fronte Lavadero)" + }, + "latitude": 42.18846205, + "longitude": -8.703352711, + "lines": [ + "6" + ] + }, + { + "stopId": 20115, + "name": { + "original": "Estrada do Porto (fronte cruce Rúa das Sueiras)" + }, + "latitude": 42.190100441, + "longitude": -8.705453204, + "lines": [ + "6" + ] + }, + { + "stopId": 20116, + "name": { + "original": "Estrada da Coutada-Beade 2" + }, + "latitude": 42.19202547, + "longitude": -8.705712064, + "lines": [ + "6", + "27" + ] + }, + { + "stopId": 20117, + "name": { + "original": "Estrada do Porto (cruce Camiño do Frascuelo)" + }, + "latitude": 42.191616209, + "longitude": -8.706277831, + "lines": [ + "6", + "27" + ] + }, + { + "stopId": 20118, + "name": { + "original": "Rúa Conde de Gondomar" + }, + "latitude": 42.228358488, + "longitude": -8.719490904, + "lines": [ + "H2" + ] + }, + { + "stopId": 20119, + "name": { + "original": "H. A. Cunqueiro (chegada)" + }, + "latitude": 42.190930878, + "longitude": -8.71409354, + "lines": [ + "6", + "12B", + "H3" + ] + }, + { + "stopId": 20124, + "name": { + "original": "Estrada Clara Campoamor 6" + }, + "latitude": 42.208989468, + "longitude": -8.729330619, + "lines": [ + "A", + "12B", + "U1", + "H1", + "H2", + "H", + "PTL" + ] + }, + { + "stopId": 20125, + "name": { + "original": "Estrada Clara Campoamor (fronte 6)" + }, + "latitude": 42.209126911, + "longitude": -8.729344197, + "lines": [ + "12B", + "H1", + "H2" + ] + }, + { + "stopId": 20126, + "name": { + "original": "Estrada Clara Campoamor (Rotonda HAC)" + }, + "latitude": 42.190252452, + "longitude": -8.717998617, + "lines": [ + "12B", + "18H", + "H1", + "H2" + ] + }, + { + "stopId": 20127, + "name": { + "original": "Estrada Clara Campoamor (fronte Rotonda HAC)" + }, + "latitude": 42.19007538, + "longitude": -8.718125045, + "lines": [ + "A", + "12B", + "18H", + "27", + "U1", + "H1", + "H2", + "H", + "PTL" + ] + }, + { + "stopId": 20130, + "name": { + "original": "Parque Forestal de Zamáns (Proba Andaina)" + }, + "latitude": 42.152788309, + "longitude": -8.681902684, + "lines": [ + "7" + ] + }, + { + "stopId": 20132, + "name": { + "original": "Avda. de Galicia 341" + }, + "latitude": 42.260473187, + "longitude": -8.67881466, + "lines": [ + "C3i" + ] + }, + { + "stopId": 20136, + "name": { + "original": "Avda. de E. Martínez Garrido 98" + }, + "latitude": 42.225764699, + "longitude": -8.704499864, + "lines": [ + "4C", + "23", + "31", + "N4", + "PSA 4" + ] + }, + { + "stopId": 20137, + "name": { + "original": "Camiño da Devesa (Asociación Veciños)" + }, + "latitude": 42.246563041, + "longitude": -8.669395817, + "lines": [ + "9B" + ] + }, + { + "stopId": 20139, + "name": { + "original": "Estrada Matamá Pazo (fronte 162)" + }, + "latitude": 42.199144892, + "longitude": -8.758506717, + "lines": [ + "29" + ] + }, + { + "stopId": 20141, + "name": { + "original": "Avda. da Ponte (fronte Vigo Memorial)" + }, + "latitude": 42.21057897, + "longitude": -8.671171189, + "lines": [ + "12B", + "15B", + "15C" + ] + }, + { + "stopId": 20142, + "name": { + "original": "Camiño do Outeiro 3" + }, + "latitude": 42.200738188, + "longitude": -8.714882876, + "lines": [ + "18B" + ] + }, + { + "stopId": 20143, + "name": { + "original": "Rúa das Teixugueiras (fronte 1)" + }, + "latitude": 42.215448094, + "longitude": -8.756474306, + "lines": [ + "15A" + ] + }, + { + "stopId": 20154, + "name": { + "original": "Rúa de Ramiro Pascual (fronte 127)" + }, + "latitude": 42.192089689, + "longitude": -8.709245389, + "lines": [ + "27" + ] + }, + { + "stopId": 20155, + "name": { + "original": "Rúa de Ramiro Pascual 131" + }, + "latitude": 42.19217626, + "longitude": -8.708899009, + "lines": [ + "27" + ] + }, + { + "stopId": 20156, + "name": { + "original": "Económicas e Empresariais (CUVI 2)" + }, + "latitude": 42.169602007, + "longitude": -8.680122554, + "lines": [ + "A" + ] + }, + { + "stopId": 20157, + "name": { + "original": "Estrada do Porto 88" + }, + "latitude": 42.185615419, + "longitude": -8.702424678, + "lines": [ + "6" + ] + }, + { + "stopId": 20158, + "name": { + "original": "Estrada do Porto 81" + }, + "latitude": 42.185593055, + "longitude": -8.702377974, + "lines": [ + "6" + ] + }, + { + "stopId": 20159, + "name": { + "original": "Estrada de Valadares 571" + }, + "latitude": 42.160348044, + "longitude": -8.718706355, + "lines": [ + "7" + ] + }, + { + "stopId": 20160, + "name": { + "original": "Estrada de Valadares 522" + }, + "latitude": 42.160066796, + "longitude": -8.718938239, + "lines": [ + "7" + ] + }, + { + "stopId": 20166, + "name": { + "original": "Camiño da Brea 2" + }, + "latitude": 42.202134841, + "longitude": -8.70572793, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 20167, + "name": { + "original": "Camiño da Brea 3" + }, + "latitude": 42.202095058, + "longitude": -8.705814233, + "lines": [ + "18A", + "18B" + ] + }, + { + "stopId": 20168, + "name": { + "original": "Estrada do Freixo (despois 118)" + }, + "latitude": 42.173596087, + "longitude": -8.730918928, + "lines": [ + "7" + ] + }, + { + "stopId": 20169, + "name": { + "original": "Estrada do Freixo (despois 235)" + }, + "latitude": 42.173616782, + "longitude": -8.730810863, + "lines": [ + "7" + ] + }, + { + "stopId": 20170, + "name": { + "original": "Rúa de Álvaro Cunqueiro 4" + }, + "latitude": 42.224544805, + "longitude": -8.730413561, + "lines": [ + "5A", + "5B", + "12A" + ] + }, + { + "stopId": 20171, + "name": { + "original": "Estrada Clara Campoamor (cruce Camiño da Pousa)" + }, + "latitude": 42.204380762, + "longitude": -8.726688445, + "lines": [ + "12B", + "H1", + "H2" + ] + }, + { + "stopId": 20172, + "name": { + "original": "Estrada Clara Campoamor (cruce Camiño da Nogueira)" + }, + "latitude": 42.203736336, + "longitude": -8.726617869, + "lines": [ + "A", + "12B", + "U1", + "H1", + "H2", + "H", + "PTL" + ] + }, + { + "stopId": 20173, + "name": { + "original": "Avda. de Castrelos 502" + }, + "latitude": 42.192504056, + "longitude": -8.721215121, + "lines": [ + "7", + "U1" + ] + }, + { + "stopId": 20174, + "name": { + "original": "Baixada ao Pontillón S/N" + }, + "latitude": 42.21519917, + "longitude": -8.726793773, + "lines": [ + "A" + ] + }, + { + "stopId": 20177, + "name": { + "original": "Rúa de Pizarro 16" + }, + "latitude": 42.230767817, + "longitude": -8.715105964, + "lines": [ + "C3i", + "6", + "11", + "15A", + "23", + "25", + "28" + ] + }, + { + "stopId": 20178, + "name": { + "original": "Estrada de Camposancos (cruce Camiño da Estea)" + }, + "latitude": 42.172412443, + "longitude": -8.799591567, + "lines": [ + "12A" + ] + }, + { + "stopId": 20180, + "name": { + "original": "Rúa do Reiseñor 10" + }, + "latitude": 42.229527407, + "longitude": -8.70843784, + "lines": [ + "H2" + ] + }, + { + "stopId": 20186, + "name": { + "original": "Rúa da Rabadeira 71" + }, + "latitude": 42.23755404, + "longitude": -8.651558138, + "lines": [ + "9B" + ] + }, + { + "stopId": 20187, + "name": { + "original": "Rúa da Rabadeira 46" + }, + "latitude": 42.237422128, + "longitude": -8.65153195, + "lines": [ + "9B", + "27" + ] + }, + { + "stopId": 20188, + "name": { + "original": "Rúa da Saa (fronte 43)" + }, + "latitude": 42.201670402, + "longitude": -8.708928464, + "lines": [ + "18B", + "H3" + ] + }, + { + "stopId": 20189, + "name": { + "original": "Rúa da Saa 10" + }, + "latitude": 42.201625853, + "longitude": -8.712945043, + "lines": [ + "18B", + "H3" + ] + }, + { + "stopId": 20190, + "name": { + "original": "Avda. das Camelias (fronte Praza do Rei)" + }, + "latitude": 42.234906013, + "longitude": -8.72662052, + "lines": [ + "4A", + "4C", + "11", + "12B", + "17", + "27", + "N1" + ] + }, + { + "stopId": 20191, + "name": { + "original": "Rúa das Figueiras 200" + }, + "latitude": 42.229676205, + "longitude": -8.657383392, + "lines": [ + "15A", + "25" + ] + }, + { + "stopId": 20192, + "name": { + "original": "Rúa de Colón 26" + }, + "latitude": 42.237168511, + "longitude": -8.720373767, + "lines": [ + "4A", + "4C", + "5B", + "7", + "12B", + "16", + "17", + "PSA 4" + ] + }, + { + "stopId": 20193, + "name": { + "original": "Rúa de Policarpo Sanz 25" + }, + "latitude": 42.23767601188501, + "longitude": -8.721582630122455, + "lines": [ + "C3i", + "A", + "5A", + "5B", + "10", + "11", + "15B", + "15C", + "N1", + "N4", + "H1" + ] + }, + { + "stopId": 20194, + "name": { + "original": "Rúa de Cánovas del Castillo 28" + }, + "latitude": 42.240364985, + "longitude": -8.724530974, + "lines": [ + "C1", + "C3d", + "A", + "5A", + "9B", + "10", + "15B", + "15C", + "28", + "N4" + ] + }, + { + "stopId": 20195, + "name": { + "original": "Praza de Compostela (fronte 35)" + }, + "latitude": 42.2393606, + "longitude": -8.724131464, + "lines": [ + "C3i", + "A", + "5A", + "5B", + "6", + "9B", + "10", + "11", + "15B", + "15C", + "28", + "N1", + "N4", + "H1" + ] + }, + { + "stopId": 20196, + "name": { + "original": "Estrada de Camposancos 498" + }, + "latitude": 42.175325155, + "longitude": -8.799594139, + "lines": [ + "12A" + ] + }, + { + "stopId": 20197, + "name": { + "original": "Rúa de Pi i Margall 3-5" + }, + "latitude": 42.23558703, + "longitude": -8.728830897, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 20198, + "name": { + "original": "Rúa de Policarpo Sanz 26" + }, + "latitude": 42.237533428, + "longitude": -8.722195046, + "lines": [ + "C1", + "C3d", + "A", + "5A", + "9B", + "10", + "15B", + "15C", + "24", + "28", + "N4" + ] + }, + { + "stopId": 20199, + "name": { + "original": "Rúa de Puerto Rico 12" + }, + "latitude": 42.228802205, + "longitude": -8.718136653, + "lines": [ + "H2" + ] + }, + { + "stopId": 20200, + "name": { + "original": "Rúa de Pi i Margall (fronte 5)" + }, + "latitude": 42.235482452, + "longitude": -8.728981431, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 20201, + "name": { + "original": "Paseo de Granada S/N" + }, + "latitude": 42.235701104, + "longitude": -8.726054911, + "lines": [ + "5B", + "12A" + ] + }, + { + "stopId": 20203, + "name": { + "original": "Avda. da Gran Vía 47" + }, + "latitude": 42.230881062, + "longitude": -8.718397577, + "lines": [ + "7", + "12B", + "14", + "16", + "18A", + "18B", + "18H" + ] + }, + { + "stopId": 20209, + "name": { + "original": "Avda. do Alcalde Portanet 23" + }, + "latitude": 42.211481651, + "longitude": -8.734440746, + "lines": [ + "H1" + ] + }, + { + "stopId": 20210, + "name": { + "original": "Estrada de Camposancos 108" + }, + "latitude": 42.19824056, + "longitude": -8.763182189, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 20211, + "name": { + "original": "Estrada de Camposancos 109" + }, + "latitude": 42.198422825, + "longitude": -8.762538026, + "lines": [ + "11", + "29" + ] + }, + { + "stopId": 20212, + "name": { + "original": "Rúa do Canabido 18" + }, + "latitude": 42.188388732, + "longitude": -8.805956864, + "lines": [ + "10" + ] + }, + { + "stopId": 20215, + "name": { + "original": "Rúa da Coruña 21" + }, + "latitude": 42.223880296, + "longitude": -8.735520196, + "lines": [ + "A", + "5A", + "5B", + "10", + "11", + "13", + "N4", + "U1", + "H1", + "H" + ] + }, + { + "stopId": 20216, + "name": { + "original": "Avda. de Cesáreo Vázquez (fronte 43)" + }, + "latitude": 42.179747589, + "longitude": -8.802157388, + "lines": [ + "11" + ] + }, + { + "stopId": 20219, + "name": { + "original": "Avda. do Aeroporto (fronte 90)" + }, + "latitude": 42.234830699, + "longitude": -8.695443515, + "lines": [ + "A", + "9B", + "27", + "28" + ] + } +] diff --git a/src/frontend/public/sw.js b/src/frontend/public/sw.js new file mode 100644 index 0000000..70ca169 --- /dev/null +++ b/src/frontend/public/sw.js @@ -0,0 +1,51 @@ +const API_CACHE_NAME = 'api-cache-v1' +const API_URL_PATTERN = /\/api\/(GetStopList)/; +const API_MAX_AGE = 24 * 60 * 60 * 1000; // 24 hours + +self.addEventListener('install', (event) => { + event.waitUntil(self.skipWaiting()); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil(self.clients.claim()); +}); + +self.addEventListener('fetch', async (event) => { + const url = new URL(event.request.url); + + if (event.request.method !== "GET" || !API_URL_PATTERN.test(url.pathname)) { + return; + } + + event.respondWith(apiCacheFirst(event.request)); +}); + +async function apiCacheFirst(request) { + const cache = await caches.open(API_CACHE_NAME); + const cachedResponse = await cache.match(request); + + if (cachedResponse) { + const age = Date.now() - new Date(cachedResponse.headers.get('date')).getTime(); + if (age < API_MAX_AGE) { + console.debug(`SW: Cache HIT for ${request.url}`); + return cachedResponse; + } + + // Cache is too old, fetch a fresh copy + cache.delete(request); + } + + try { + const netResponse = await fetch(request); + + const responseToCache = netResponse.clone(); + + cache.put(request, responseToCache); + + console.debug(`SW: Cache MISS for ${request.url}`); + + return netResponse; + } catch (error) { + throw error; + } +} \ No newline at end of file diff --git a/src/frontend/src/AppContext.tsx b/src/frontend/src/AppContext.tsx new file mode 100644 index 0000000..ecba9e2 --- /dev/null +++ b/src/frontend/src/AppContext.tsx @@ -0,0 +1,234 @@ +/* eslint-disable react-refresh/only-export-components */ +import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'; +import { type LatLngTuple } from 'leaflet'; + +type Theme = 'light' | 'dark'; +type TableStyle = 'regular'|'grouped'; +type MapPositionMode = 'gps' | 'last'; + +interface MapState { + center: LatLngTuple; + zoom: number; + userLocation: LatLngTuple | null; + hasLocationPermission: boolean; +} + +interface AppContextProps { + theme: Theme; + setTheme: React.Dispatch>; + toggleTheme: () => void; + + tableStyle: TableStyle; + setTableStyle: React.Dispatch>; + toggleTableStyle: () => void; + + mapState: MapState; + setMapCenter: (center: LatLngTuple) => void; + setMapZoom: (zoom: number) => void; + setUserLocation: (location: LatLngTuple | null) => void; + setLocationPermission: (hasPermission: boolean) => void; + updateMapState: (center: LatLngTuple, zoom: number) => void; + + mapPositionMode: MapPositionMode; + setMapPositionMode: (mode: MapPositionMode) => void; +} + +// Coordenadas por defecto centradas en Vigo +const DEFAULT_CENTER: LatLngTuple = [42.229188855975046, -8.72246955783102]; +const DEFAULT_ZOOM = 14; + +const AppContext = createContext(undefined); + +export const AppProvider = ({ children }: { children: ReactNode }) => { + //#region Theme + const [theme, setTheme] = useState(() => { + const savedTheme = localStorage.getItem('theme'); + if (savedTheme) { + return savedTheme as Theme; + } + const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; + return prefersDark ? 'dark' : 'light'; + }); + + const toggleTheme = () => { + setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light')); + }; + + useEffect(() => { + document.documentElement.setAttribute('data-theme', theme); + localStorage.setItem('theme', theme); + }, [theme]); + //#endregion + + //#region Table Style + const [tableStyle, setTableStyle] = useState(() => { + const savedTableStyle = localStorage.getItem('tableStyle'); + if (savedTableStyle) { + return savedTableStyle as TableStyle; + } + return 'regular'; + }); + + const toggleTableStyle = () => { + setTableStyle((prevTableStyle) => (prevTableStyle === 'regular' ? 'grouped' : 'regular')); + } + + useEffect(() => { + localStorage.setItem('tableStyle', tableStyle); + }, [tableStyle]); + //#endregion + + //#region Map Position Mode + const [mapPositionMode, setMapPositionMode] = useState(() => { + const saved = localStorage.getItem('mapPositionMode'); + return saved === 'last' ? 'last' : 'gps'; + }); + + useEffect(() => { + localStorage.setItem('mapPositionMode', mapPositionMode); + }, [mapPositionMode]); + //#endregion + + //#region Map State + const [mapState, setMapState] = useState(() => { + const savedMapState = localStorage.getItem('mapState'); + if (savedMapState) { + try { + const parsed = JSON.parse(savedMapState); + return { + center: parsed.center || DEFAULT_CENTER, + zoom: parsed.zoom || DEFAULT_ZOOM, + userLocation: parsed.userLocation || null, + hasLocationPermission: parsed.hasLocationPermission || false + }; + } catch (e) { + console.error('Error parsing saved map state', e); + } + } + return { + center: DEFAULT_CENTER, + zoom: DEFAULT_ZOOM, + userLocation: null, + hasLocationPermission: false + }; + }); + + // Helper: check if coordinates are within Vigo bounds + function isWithinVigo([lat, lng]: LatLngTuple): boolean { + // Rough bounding box for Vigo + return lat >= 42.18 && lat <= 42.30 && lng >= -8.78 && lng <= -8.65; + } + + // On app load, if mapPositionMode is 'gps', try to get GPS and set map center + useEffect(() => { + if (mapPositionMode === 'gps') { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + (position) => { + const { latitude, longitude } = position.coords; + const coords: LatLngTuple = [latitude, longitude]; + if (isWithinVigo(coords)) { + setMapState(prev => { + const newState = { ...prev, center: coords, zoom: 16, userLocation: coords }; + localStorage.setItem('mapState', JSON.stringify(newState)); + return newState; + }); + } + }, + () => { + // Ignore error, fallback to last + } + ); + } + } + // If 'last', do nothing (already loaded from localStorage) + }, [mapPositionMode]); + + const setMapCenter = (center: LatLngTuple) => { + setMapState(prev => { + const newState = { ...prev, center }; + localStorage.setItem('mapState', JSON.stringify(newState)); + return newState; + }); + }; + + const setMapZoom = (zoom: number) => { + setMapState(prev => { + const newState = { ...prev, zoom }; + localStorage.setItem('mapState', JSON.stringify(newState)); + return newState; + }); + }; + + const setUserLocation = (userLocation: LatLngTuple | null) => { + setMapState(prev => { + const newState = { ...prev, userLocation }; + localStorage.setItem('mapState', JSON.stringify(newState)); + return newState; + }); + }; + + const setLocationPermission = (hasLocationPermission: boolean) => { + setMapState(prev => { + const newState = { ...prev, hasLocationPermission }; + localStorage.setItem('mapState', JSON.stringify(newState)); + return newState; + }); + }; + + const updateMapState = (center: LatLngTuple, zoom: number) => { + setMapState(prev => { + const newState = { ...prev, center, zoom }; + localStorage.setItem('mapState', JSON.stringify(newState)); + return newState; + }); + }; + //#endregion + + // Tratar de obtener la ubicación del usuario cuando se carga la aplicación si ya se había concedido permiso antes + useEffect(() => { + if (mapState.hasLocationPermission && !mapState.userLocation) { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + (position) => { + const { latitude, longitude } = position.coords; + setUserLocation([latitude, longitude]); + }, + (error) => { + console.error('Error getting location:', error); + setLocationPermission(false); + } + ); + } + } + }, [mapState.hasLocationPermission, mapState.userLocation]); + + return ( + + {children} + + ); +}; + +export const useApp = () => { + const context = useContext(AppContext); + if (!context) { + throw new Error('useApp must be used within a AppProvider'); + } + return context; +}; diff --git a/src/frontend/src/ErrorBoundary.tsx b/src/frontend/src/ErrorBoundary.tsx new file mode 100644 index 0000000..5c877b7 --- /dev/null +++ b/src/frontend/src/ErrorBoundary.tsx @@ -0,0 +1,46 @@ +import React, { Component, type ReactNode } from 'react'; + +interface ErrorBoundaryProps { + children: ReactNode; +} + +interface ErrorBoundaryState { + hasError: boolean; + error: Error | null; +} + +class ErrorBoundary extends Component { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { + hasError: false, + error: null + }; + } + + static getDerivedStateFromError(error: Error): ErrorBoundaryState { + return { + hasError: true, + error + }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error("Uncaught error:", error, errorInfo); + } + + render() { + if (this.state.hasError) { + return <> +

    Something went wrong.

    +
    +          {this.state.error?.stack}
    +        
    + ; + } + + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/src/frontend/src/Layout.css b/src/frontend/src/Layout.css new file mode 100644 index 0000000..601794b --- /dev/null +++ b/src/frontend/src/Layout.css @@ -0,0 +1,60 @@ +#root { + display: flex; + flex-direction: column; + height: 100vh; + width: 100%; + overflow: hidden; +} + +.main-content { + flex: 1; + overflow: auto; + padding-bottom: 60px; /* Extra padding to ensure content isn't hidden behind navbar */ +} + +.nav-bar { + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: 5; + + background-color: var(--background-color); + display: flex; + justify-content: space-around; + align-items: center; + height: 60px; + border-top: 1px solid var(--border-color); + box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); +} + +.nav-item { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 8px; + color: #616161; + text-decoration: none; + width: 33.3%; + font-size: 14px; +} + +.nav-item.active { + color: var(--button-background-color); +} + +.theme-toggle { + background: none; + border: none; + cursor: pointer; + color: inherit; + display: flex; + align-items: center; + justify-content: center; + padding: 8px; +} + +.theme-toggle:hover { + color: var(--button-hover-background-color); +} diff --git a/src/frontend/src/Layout.tsx b/src/frontend/src/Layout.tsx new file mode 100644 index 0000000..f933ddc --- /dev/null +++ b/src/frontend/src/Layout.tsx @@ -0,0 +1,55 @@ +import { type ReactNode } from 'react'; +import { Link, useLocation } from 'react-router'; +import { MapPin, Map, Settings } from 'lucide-react'; +import './Layout.css'; + +interface LayoutProps { + children: ReactNode; +} + +export function Layout({ children }: LayoutProps) { + const location = useLocation(); + + const navItems = [ + { + name: 'Paradas', + icon: MapPin, + path: '/stops' + }, + { + name: 'Mapa', + icon: Map, + path: '/map' + }, + { + name: 'Ajustes', + icon: Settings, + path: '/settings' + } + ]; + + return ( + <> +
    + {children} +
    + + + ); +} diff --git a/src/frontend/src/components/GroupedTable.tsx b/src/frontend/src/components/GroupedTable.tsx new file mode 100644 index 0000000..b7f990d --- /dev/null +++ b/src/frontend/src/components/GroupedTable.tsx @@ -0,0 +1,74 @@ +import { type StopDetails } from "../pages/Estimates"; +import LineIcon from "./LineIcon"; + +interface GroupedTable { + data: StopDetails; + dataDate: Date | null; +} + +export const GroupedTable: React.FC = ({ data, dataDate }) => { + const formatDistance = (meters: number) => { + if (meters > 1024) { + return `${(meters / 1000).toFixed(1)} km`; + } else { + return `${meters} m`; + } + } + + const groupedEstimates = data.estimates.reduce((acc, estimate) => { + if (!acc[estimate.line]) { + acc[estimate.line] = []; + } + acc[estimate.line].push(estimate); + return acc; + }, {} as Record); + + const sortedLines = Object.keys(groupedEstimates).sort((a, b) => { + const firstArrivalA = groupedEstimates[a][0].minutes; + const firstArrivalB = groupedEstimates[b][0].minutes; + return firstArrivalA - firstArrivalB; + }); + + return + + + + + + + + + + + + + {sortedLines.map((line) => ( + groupedEstimates[line].map((estimate, idx) => ( + + {idx === 0 && ( + + )} + + + + + )) + ))} + + + {data?.estimates.length === 0 && ( + + + + + + )} +
    Estimaciones de llegadas a las {dataDate?.toLocaleTimeString()}
    LíneaRutaLlegadaDistancia
    + + {estimate.route}{`${estimate.minutes} min`} + {estimate.meters > -1 + ? formatDistance(estimate.meters) + : "No disponible" + } +
    No hay estimaciones disponibles
    +} diff --git a/src/frontend/src/components/LineIcon.css b/src/frontend/src/components/LineIcon.css new file mode 100644 index 0000000..e7e8949 --- /dev/null +++ b/src/frontend/src/components/LineIcon.css @@ -0,0 +1,239 @@ +:root { + --line-c1: rgb(237, 71, 19); + --line-c3d: rgb(255, 204, 0); + --line-c3i: rgb(255, 204, 0); + --line-l4a: rgb(0, 153, 0); + --line-l4c: rgb(0, 153, 0); + --line-l5a: rgb(0, 176, 240); + --line-l5b: rgb(0, 176, 240); + --line-l6: rgb(204, 51, 153); + --line-l7: rgb(150, 220, 153); + --line-l9b: rgb(244, 202, 140); + --line-l10: rgb(153, 51, 0); + --line-l11: rgb(226, 0, 38); + --line-l12a: rgb(106, 150, 190); + --line-l12b: rgb(106, 150, 190); + --line-l13: rgb(0, 176, 240); + --line-l14: rgb(129, 142, 126); + --line-l15a: rgb(216, 168, 206); + --line-l15b: rgb(216, 168, 206); + --line-l15c: rgb(216, 168, 168); + --line-l16: rgb(129, 142, 126); + --line-l17: rgb(214, 245, 31); + --line-l18a: rgb(212, 80, 168); + --line-l18b: rgb(0, 0, 0); + --line-l18h: rgb(0, 0, 0); + --line-l23: rgb(0, 70, 210); + --line-l24: rgb(191, 191, 191); + --line-l25: rgb(172, 100, 4); + --line-l27: rgb(112, 74, 42); + --line-l28: rgb(176, 189, 254); + --line-l29: rgb(248, 184, 90); + --line-l31: rgb(255, 255, 0); + --line-a: rgb(119, 41, 143); + --line-h: rgb(0, 96, 168); + --line-h1: rgb(0, 96, 168); + --line-h2: rgb(0, 96, 168); + --line-h3: rgb(0, 96, 168); + --line-lzd: rgb(61, 78, 167); + --line-n1: rgb(191, 191, 191); + --line-n4: rgb(102, 51, 102); + --line-psa1: rgb(0, 153, 0); + --line-psa4: rgb(0, 153, 0); + --line-ptl: rgb(150, 220, 153); + --line-turistico: rgb(102, 51, 102); + --line-u1: rgb(172, 100, 4); + --line-u2: rgb(172, 100, 4); +} + +.line-icon { + display: inline-block; + padding: 0.25rem 0.5rem; + margin-right: 0.5rem; + border-bottom: 3px solid; + font-size: 0.9rem; + font-weight: 600; + text-transform: uppercase; + color: inherit; + /* Prevent color change on hover */ +} + +.line-c1 { + border-color: var(--line-c1); +} + +.line-c3d { + border-color: var(--line-c3d); +} + +.line-c3i { + border-color: var(--line-c3i); +} + +.line-l4a { + border-color: var(--line-l4a); +} + +.line-l4c { + border-color: var(--line-l4c); +} + +.line-l5a { + border-color: var(--line-l5a); +} + +.line-l5b { + border-color: var(--line-l5b); +} + +.line-l6 { + border-color: var(--line-l6); +} + +.line-l7 { + border-color: var(--line-l7); +} + +.line-l9b { + border-color: var(--line-l9b); +} + +.line-l10 { + border-color: var(--line-l10); +} + +.line-l11 { + border-color: var(--line-l11); +} + +.line-l12a { + border-color: var(--line-l12a); +} + +.line-l12b { + border-color: var(--line-l12b); +} + +.line-l13 { + border-color: var(--line-l13); +} + +.line-l14 { + border-color: var(--line-l14); +} + +.line-l15a { + border-color: var(--line-l15a); +} + +.line-l15b { + border-color: var(--line-l15b); +} + +.line-l15c { + border-color: var(--line-l15c); +} + +.line-l16 { + border-color: var(--line-l16); +} + +.line-l17 { + border-color: var(--line-l17); +} + +.line-l18a { + border-color: var(--line-l18a); +} + +.line-l18b { + border-color: var(--line-l18b); +} + +.line-l18h { + border-color: var(--line-l18h); +} + +.line-l23 { + border-color: var(--line-l23); +} + +.line-l24 { + border-color: var(--line-l24); +} + +.line-l25 { + border-color: var(--line-l25); +} + +.line-l27 { + border-color: var(--line-l27); +} + +.line-l28 { + border-color: var(--line-l28); +} + +.line-l29 { + border-color: var(--line-l29); +} + +.line-l31 { + border-color: var(--line-l31); +} + +.line-a { + border-color: var(--line-a); +} + +.line-h { + border-color: var(--line-h); +} + +.line-h1 { + border-color: var(--line-h1); +} + +.line-h2 { + border-color: var(--line-h2); +} + +.line-h3 { + border-color: var(--line-h3); +} + +.line-lzd { + border-color: var(--line-lzd); +} + +.line-n1 { + border-color: var(--line-n1); +} + +.line-n4 { + border-color: var(--line-n4); +} + +.line-psa1 { + border-color: var(--line-psa1); +} + +.line-psa4 { + border-color: var(--line-psa4); +} + +.line-ptl { + border-color: var(--line-ptl); +} + +.line-turistico { + border-color: var(--line-turistico); +} + +.line-u1 { + border-color: var(--line-u1); +} + +.line-u2 { + border-color: var(--line-u2); +} \ No newline at end of file diff --git a/src/frontend/src/components/LineIcon.tsx b/src/frontend/src/components/LineIcon.tsx new file mode 100644 index 0000000..50fd1ec --- /dev/null +++ b/src/frontend/src/components/LineIcon.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import './LineIcon.css'; + +interface LineIconProps { + line: string; +} + +const LineIcon: React.FC = ({ line }) => { + const formattedLine = /^[a-zA-Z]/.test(line) ? line : `L${line}`; + return ( + + {formattedLine} + + ); +}; + +export default LineIcon; \ No newline at end of file diff --git a/src/frontend/src/components/RegularTable.tsx b/src/frontend/src/components/RegularTable.tsx new file mode 100644 index 0000000..211a47c --- /dev/null +++ b/src/frontend/src/components/RegularTable.tsx @@ -0,0 +1,70 @@ +import { type StopDetails } from "../pages/Estimates"; +import LineIcon from "./LineIcon"; + +interface RegularTableProps { + data: StopDetails; + dataDate: Date | null; +} + +export const RegularTable: React.FC = ({ data, dataDate }) => { + + const absoluteArrivalTime = (minutes: number) => { + const now = new Date() + const arrival = new Date(now.getTime() + minutes * 60000) + return Intl.DateTimeFormat(navigator.language, { + hour: '2-digit', + minute: '2-digit' + }).format(arrival) + } + + const formatDistance = (meters: number) => { + if (meters > 1024) { + return `${(meters / 1000).toFixed(1)} km`; + } else { + return `${meters} m`; + } + } + + return + + + + + + + + + + + + + {data.estimates + .sort((a, b) => a.minutes - b.minutes) + .map((estimate, idx) => ( + + + + + + + ))} + + + {data?.estimates.length === 0 && ( + + + + + + )} +
    Estimaciones de llegadas a las {dataDate?.toLocaleTimeString()}
    LíneaRutaLlegadaDistancia
    {estimate.route} + {estimate.minutes > 15 + ? absoluteArrivalTime(estimate.minutes) + : `${estimate.minutes} min`} + + {estimate.meters > -1 + ? formatDistance(estimate.meters) + : "No disponible" + } +
    No hay estimaciones disponibles
    +} diff --git a/src/frontend/src/components/StopItem.css b/src/frontend/src/components/StopItem.css new file mode 100644 index 0000000..9feb2d1 --- /dev/null +++ b/src/frontend/src/components/StopItem.css @@ -0,0 +1,54 @@ +/* Stop Item Styling */ + +.stop-notes { + font-size: 0.85rem; + font-style: italic; + color: #666; + margin: 2px 0; +} + +.stop-amenities { + display: flex; + flex-wrap: wrap; + gap: 4px; + margin-top: 4px; +} + +.amenity-tag { + font-size: 0.75rem; + background-color: #e8f4f8; + color: #0078d4; + border-radius: 4px; + padding: 2px 6px; + display: inline-block; +} + +/* Different colors for different amenity types */ +.amenity-tag[data-amenity="shelter"] { + background-color: #e3f1df; + color: #107c41; +} + +.amenity-tag[data-amenity="bench"] { + background-color: #f0e8fc; + color: #5c2e91; +} + +.amenity-tag[data-amenity="real-time display"] { + background-color: #fff4ce; + color: #986f0b; +} + +/* When there are alternate names available, show an indicator */ +.has-alternate-names { + position: relative; +} + +.has-alternate-names::after { + content: "⋯"; + position: absolute; + right: -15px; + top: 0; + color: #0078d4; + font-weight: bold; +} \ No newline at end of file diff --git a/src/frontend/src/components/StopItem.tsx b/src/frontend/src/components/StopItem.tsx new file mode 100644 index 0000000..29370b7 --- /dev/null +++ b/src/frontend/src/components/StopItem.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { Link } from 'react-router'; +import StopDataProvider, { type Stop } from '../data/StopDataProvider'; +import LineIcon from './LineIcon'; + +interface StopItemProps { + stop: Stop; +} + +const StopItem: React.FC = ({ stop }) => { + + return ( +
  • + + {stop.favourite && } ({stop.stopId}) {StopDataProvider.getDisplayName(stop)} +
    + {stop.lines?.map(line => )} +
    + + +
  • + ); +}; + +export default StopItem; diff --git a/src/frontend/src/controls/LocateControl.ts b/src/frontend/src/controls/LocateControl.ts new file mode 100644 index 0000000..26effa5 --- /dev/null +++ b/src/frontend/src/controls/LocateControl.ts @@ -0,0 +1,67 @@ +import { createControlComponent } from '@react-leaflet/core'; +import { LocateControl as LeafletLocateControl, type LocateOptions } from 'leaflet.locatecontrol'; +import "leaflet.locatecontrol/dist/L.Control.Locate.min.css"; +import { useEffect } from 'react'; +import { useMap } from 'react-leaflet'; +import { useApp } from '../AppContext'; + +interface EnhancedLocateControlProps { + options?: LocateOptions; +} + +// Componente que usa el contexto para manejar la localización +export const EnhancedLocateControl = (props: EnhancedLocateControlProps) => { + const map = useMap(); + const { mapState, setUserLocation, setLocationPermission } = useApp(); + + useEffect(() => { + // Configuración por defecto del control de localización + const defaultOptions: LocateOptions = { + position: 'topright', + strings: { + title: 'Mostrar mi ubicación', + }, + flyTo: true, + onLocationError: (err) => { + console.error('Error en la localización:', err); + setLocationPermission(false); + }, + returnToPrevBounds: true, + showPopup: false, + }; + + // Combinamos las opciones por defecto con las personalizadas + const options = { ...defaultOptions, ...props.options }; + + // Creamos la instancia del control + const locateControl = new LeafletLocateControl(options); + + // Añadimos el control al mapa + locateControl.addTo(map); + + // Si tenemos permiso de ubicación y ya conocemos la ubicación del usuario, + // podemos activarla automáticamente + if (mapState.hasLocationPermission && mapState.userLocation) { + // Esperamos a que el mapa esté listo + setTimeout(() => { + try { + locateControl.start(); + } catch (e) { + console.error('Error al iniciar la localización automática', e); + } + }, 1000); + } + + return () => { + // Limpieza al desmontar el componente + locateControl.remove(); + }; + }, [map, mapState.hasLocationPermission, mapState.userLocation, props.options, setLocationPermission, setUserLocation]); + + return null; +}; + +// Exportamos también el control base por compatibilidad +export const LocateControl = createControlComponent( + (props) => new LeafletLocateControl(props) +); diff --git a/src/frontend/src/data/StopDataProvider.ts b/src/frontend/src/data/StopDataProvider.ts new file mode 100644 index 0000000..0c1e46e --- /dev/null +++ b/src/frontend/src/data/StopDataProvider.ts @@ -0,0 +1,160 @@ +export interface CachedStopList { + timestamp: number; + data: Stop[]; +} + +export type StopName = { + original: string; + intersect?: string; +} + +export interface Stop { + stopId: number; + name: StopName; + latitude?: number; + longitude?: number; + lines: string[]; + favourite?: boolean; +} + +// In-memory cache and lookup map +let cachedStops: Stop[] | null = null; +let stopsMap: Record = {}; +// Custom names loaded from localStorage +let customNames: Record = {}; + +// Initialize cachedStops and customNames once +async function initStops() { + if (!cachedStops) { + const response = await fetch('/stops.json'); + const stops = await response.json() as Stop[]; + // build array and map + stopsMap = {}; + cachedStops = stops.map(stop => { + const entry = { ...stop, favourite: false } as Stop; + stopsMap[stop.stopId] = entry; + return entry; + }); + // load custom names + const rawCustom = localStorage.getItem('customStopNames'); + if (rawCustom) customNames = JSON.parse(rawCustom) as Record; + } +} + +async function getStops(): Promise { + await initStops(); + // update favourites + const rawFav = localStorage.getItem('favouriteStops'); + const favouriteStops = rawFav ? JSON.parse(rawFav) as number[] : []; + cachedStops!.forEach(stop => stop.favourite = favouriteStops.includes(stop.stopId)); + return cachedStops!; +} + +// New: get single stop by id +async function getStopById(stopId: number): Promise { + await initStops(); + const stop = stopsMap[stopId]; + if (stop) { + const rawFav = localStorage.getItem('favouriteStops'); + const favouriteStops = rawFav ? JSON.parse(rawFav) as number[] : []; + stop.favourite = favouriteStops.includes(stopId); + } + return stop; +} + +// Updated display name to include custom names +function getDisplayName(stop: Stop): string { + if (customNames[stop.stopId]) return customNames[stop.stopId]; + const nameObj = stop.name; + return nameObj.intersect || nameObj.original; +} + +// New: set or remove custom names +function setCustomName(stopId: number, label: string) { + customNames[stopId] = label; + localStorage.setItem('customStopNames', JSON.stringify(customNames)); +} + +function removeCustomName(stopId: number) { + delete customNames[stopId]; + localStorage.setItem('customStopNames', JSON.stringify(customNames)); +} + +// New: get custom label for a stop +function getCustomName(stopId: number): string | undefined { + return customNames[stopId]; +} + +function addFavourite(stopId: number) { + const rawFavouriteStops = localStorage.getItem('favouriteStops'); + let favouriteStops: number[] = []; + if (rawFavouriteStops) { + favouriteStops = JSON.parse(rawFavouriteStops) as number[]; + } + + if (!favouriteStops.includes(stopId)) { + favouriteStops.push(stopId); + localStorage.setItem('favouriteStops', JSON.stringify(favouriteStops)); + } +} + +function removeFavourite(stopId: number) { + const rawFavouriteStops = localStorage.getItem('favouriteStops'); + let favouriteStops: number[] = []; + if (rawFavouriteStops) { + favouriteStops = JSON.parse(rawFavouriteStops) as number[]; + } + + const newFavouriteStops = favouriteStops.filter(id => id !== stopId); + localStorage.setItem('favouriteStops', JSON.stringify(newFavouriteStops)); +} + +function isFavourite(stopId: number): boolean { + const rawFavouriteStops = localStorage.getItem('favouriteStops'); + if (rawFavouriteStops) { + const favouriteStops = JSON.parse(rawFavouriteStops) as number[]; + return favouriteStops.includes(stopId); + } + return false; +} + +const RECENT_STOPS_LIMIT = 10; + +function pushRecent(stopId: number) { + const rawRecentStops = localStorage.getItem('recentStops'); + let recentStops: Set = new Set(); + if (rawRecentStops) { + recentStops = new Set(JSON.parse(rawRecentStops) as number[]); + } + + recentStops.add(stopId); + if (recentStops.size > RECENT_STOPS_LIMIT) { + const iterator = recentStops.values(); + const val = iterator.next().value as number; + recentStops.delete(val); + } + + localStorage.setItem('recentStops', JSON.stringify(Array.from(recentStops))); +} + +function getRecent(): number[] { + const rawRecentStops = localStorage.getItem('recentStops'); + if (rawRecentStops) { + return JSON.parse(rawRecentStops) as number[]; + } + return []; +} + +export default { + getStops, + getStopById, + getCustomName, + getDisplayName, + setCustomName, + removeCustomName, + addFavourite, + removeFavourite, + isFavourite, + pushRecent, + getRecent +}; diff --git a/src/frontend/src/main.tsx b/src/frontend/src/main.tsx new file mode 100644 index 0000000..48ff63c --- /dev/null +++ b/src/frontend/src/main.tsx @@ -0,0 +1,43 @@ +import '@fontsource-variable/outfit' +import './styles/Pages.css' + +import { createRoot } from 'react-dom/client' +import { createBrowserRouter, Navigate, RouterProvider } from 'react-router' +import { StopList } from './pages/StopList' +import { Estimates } from './pages/Estimates' +import { StopMap } from './pages/Map' +import { Layout } from './Layout' +import { Settings } from './pages/Settings' +import { AppProvider } from './AppContext' +import ErrorBoundary from './ErrorBoundary' + +const router = createBrowserRouter([ + { + path: '/', + element: , + }, + { + path: '/stops', + element: , + }, + { + path: '/map', + element: , + }, + { + path: '/estimates/:stopId', + element: + }, + { + path: '/settings', + element: + } +]) + +createRoot(document.getElementById('root')!).render( + + + + + +) diff --git a/src/frontend/src/pages/Estimates.tsx b/src/frontend/src/pages/Estimates.tsx new file mode 100644 index 0000000..6a98731 --- /dev/null +++ b/src/frontend/src/pages/Estimates.tsx @@ -0,0 +1,99 @@ +import { type JSX, useEffect, useState } from "react"; +import { useParams } from "react-router"; +import StopDataProvider from "../data/StopDataProvider"; +import { Star, Edit2 } from 'lucide-react'; +import "../styles/Estimates.css"; +import { RegularTable } from "../components/RegularTable"; +import { useApp } from "../AppContext"; +import { GroupedTable } from "../components/GroupedTable"; + +export interface StopDetails { + stop: { + id: number; + name: string; + latitude: number; + longitude: number; + } + estimates: { + line: string; + route: string; + minutes: number; + meters: number; + }[] +} + +const loadData = async (stopId: string) => { + const resp = await fetch(`/api/GetStopEstimates?id=${stopId}`); + return await resp.json(); +}; + +export function Estimates() { + const params = useParams(); + const stopIdNum = parseInt(params.stopId ?? ""); + const [customName, setCustomName] = useState(undefined); + const [data, setData] = useState(null); + const [dataDate, setDataDate] = useState(null); + const [favourited, setFavourited] = useState(false); + const { tableStyle } = useApp(); + + useEffect(() => { + loadData(params.stopId!) + .then((body: StopDetails) => { + setData(body); + setDataDate(new Date()); + setCustomName(StopDataProvider.getCustomName(stopIdNum)); + }) + + + StopDataProvider.pushRecent(parseInt(params.stopId ?? "")); + + setFavourited( + StopDataProvider.isFavourite(parseInt(params.stopId ?? "")) + ); + }, [params.stopId]); + + + const toggleFavourite = () => { + if (favourited) { + StopDataProvider.removeFavourite(stopIdNum); + setFavourited(false); + } else { + StopDataProvider.addFavourite(stopIdNum); + setFavourited(true); + } + } + + const handleRename = () => { + const current = customName ?? data?.stop.name; + const input = window.prompt('Custom name for this stop:', current); + if (input === null) return; // cancelled + const trimmed = input.trim(); + if (trimmed === '') { + StopDataProvider.removeCustomName(stopIdNum); + setCustomName(undefined); + } else { + StopDataProvider.setCustomName(stopIdNum, trimmed); + setCustomName(trimmed); + } + }; + + if (data === null) return

    Cargando datos en tiempo real...

    + + return ( +
    +
    +

    + + + {(customName ?? data.stop.name)} ({data.stop.id}) +

    +
    + +
    + {tableStyle === 'grouped' ? + : + } +
    +
    + ) +} diff --git a/src/frontend/src/pages/Map.tsx b/src/frontend/src/pages/Map.tsx new file mode 100644 index 0000000..52c73f8 --- /dev/null +++ b/src/frontend/src/pages/Map.tsx @@ -0,0 +1,75 @@ +import StopDataProvider, { type Stop } from "../data/StopDataProvider"; + +import 'leaflet/dist/leaflet.css' +import 'react-leaflet-markercluster/styles' + +import { useEffect, useState } from 'react'; +import LineIcon from '../components/LineIcon'; +import { Link } from 'react-router'; +import { MapContainer, TileLayer, Marker, Popup, useMapEvents } from "react-leaflet"; +import MarkerClusterGroup from "react-leaflet-markercluster"; +import { Icon, type LatLngTuple } from "leaflet"; +import { EnhancedLocateControl } from "../controls/LocateControl"; +import { useApp } from "../AppContext"; + +const icon = new Icon({ + iconUrl: '/map-pin-icon.png', + iconSize: [25, 41], + iconAnchor: [12, 41], + popupAnchor: [1, -34], + shadowSize: [41, 41] +}); + +// Componente auxiliar para detectar cambios en el mapa +const MapEventHandler = () => { + const { updateMapState } = useApp(); + + const map = useMapEvents({ + moveend: () => { + const center = map.getCenter(); + const zoom = map.getZoom(); + updateMapState([center.lat, center.lng], zoom); + } + }); + + return null; +}; + +// Componente principal del mapa +export function StopMap() { + const [stops, setStops] = useState([]); + const { mapState } = useApp(); + + useEffect(() => { + StopDataProvider.getStops().then(setStops); + }, []); + + return ( + + + + + + {stops.map(stop => ( + + + {StopDataProvider.getDisplayName(stop)} +
    + {stop.lines.map((line) => ( + + ))} +
    +
    + ))} +
    +
    + ); +} diff --git a/src/frontend/src/pages/Settings.tsx b/src/frontend/src/pages/Settings.tsx new file mode 100644 index 0000000..1ad15ab --- /dev/null +++ b/src/frontend/src/pages/Settings.tsx @@ -0,0 +1,65 @@ +import { useApp } from "../AppContext"; +import "../styles/Settings.css"; + +export function Settings() { + const { theme, setTheme, tableStyle, setTableStyle, mapPositionMode, setMapPositionMode } = useApp(); + + return ( +
    +

    Sobre UrbanoVigo Web

    +

    + Aplicación web para encontrar paradas y tiempos de llegada de los autobuses + urbanos de Vigo, España. +

    +
    +

    Ajustes

    +
    + + +
    +
    + + +
    +
    + + +
    +
    + ¿Qué significa esto? +

    + La tabla de horarios puede mostrarse de dos formas: +

    +
    +
    Mostrar por orden
    +
    Las paradas se muestran en el orden en que se visitan. Aplicaciones como Infobus (Vitrasa) usan este estilo.
    +
    Agrupar por línea
    +
    Las paradas se agrupan por la línea de autobús. Aplicaciones como iTranvias (A Coruña) o Moovit (más o menos) usan este estilo.
    +
    +
    +
    +

    Créditos

    +

    + + Código en GitHub + - + Desarrollado por + Ariel Costas + +

    +

    + Datos obtenidos de datos.vigo.org bajo + licencia Open Data Commons Attribution License +

    +
    + ) +} \ No newline at end of file diff --git a/src/frontend/src/pages/StopList.tsx b/src/frontend/src/pages/StopList.tsx new file mode 100644 index 0000000..59a1942 --- /dev/null +++ b/src/frontend/src/pages/StopList.tsx @@ -0,0 +1,135 @@ +import { useEffect, useMemo, useRef, useState } from "react"; +import StopDataProvider, { type Stop } from "../data/StopDataProvider"; +import StopItem from "../components/StopItem"; +import Fuse from "fuse.js"; + +const placeholders = [ + "Urzaiz", + "Gran Vía", + "Castelao", + "García Barbón", + "Valladares", + "Florida", + "Pizarro", + "Estrada Madrid", + "Sanjurjo Badía" +]; + +export function StopList() { + const [data, setData] = useState(null) + const [searchResults, setSearchResults] = useState(null); + const searchTimeout = useRef(null); + + const randomPlaceholder = useMemo(() => placeholders[Math.floor(Math.random() * placeholders.length)], []); + const fuse = useMemo(() => new Fuse(data || [], { threshold: 0.3, keys: ['name.original'] }), [data]); + + useEffect(() => { + StopDataProvider.getStops().then((stops: Stop[]) => setData(stops)) + }, []); + + const handleStopSearch = (event: React.ChangeEvent) => { + const stopName = event.target.value || ""; + + if (searchTimeout.current) { + clearTimeout(searchTimeout.current); + } + + searchTimeout.current = setTimeout(() => { + if (stopName.length === 0) { + setSearchResults(null); + return; + } + + if (!data) { + console.error("No data available for search"); + return; + } + + const results = fuse.search(stopName); + const items = results.map(result => result.item); + setSearchResults(items); + }, 300); + } + + const favouritedStops = useMemo(() => { + return data?.filter(stop => stop.favourite) ?? [] + }, [data]) + + const recentStops = useMemo(() => { + // no recent items if data not loaded + if (!data) return null; + const recentIds = StopDataProvider.getRecent(); + if (recentIds.length === 0) return null; + // map and filter out missing entries + const stopsList = recentIds + .map(id => data.find(stop => stop.stopId === id)) + .filter((s): s is Stop => Boolean(s)); + return stopsList.reverse(); + }, [data]); + + if (data === null) return

    Loading...

    + + return ( +
    +

    UrbanoVigo Web

    + +
    +
    + + +
    +
    + + {searchResults && searchResults.length > 0 && ( +
    +

    Resultados de la búsqueda

    +
      + {searchResults.map((stop: Stop) => ( + + ))} +
    +
    + )} + +
    +

    Paradas favoritas

    + + {favouritedStops?.length === 0 && ( +

    + Accede a una parada y márcala como favorita para verla aquí. +

    + )} + +
      + {favouritedStops?.sort((a, b) => a.stopId - b.stopId).map((stop: Stop) => ( + + ))} +
    +
    + + {recentStops && recentStops.length > 0 && ( +
    +

    Recientes

    + +
      + {recentStops.map((stop: Stop) => ( + + ))} +
    +
    + )} + +
    +

    Paradas

    + +
      + {data?.sort((a, b) => a.stopId - b.stopId).map((stop: Stop) => ( + + ))} +
    +
    +
    + ) +} diff --git a/src/frontend/src/styles/Estimates.css b/src/frontend/src/styles/Estimates.css new file mode 100644 index 0000000..86ca09b --- /dev/null +++ b/src/frontend/src/styles/Estimates.css @@ -0,0 +1,105 @@ +.table-responsive { + overflow-x: auto; + margin-bottom: 1.5rem; +} + +.table { + width: 100%; + border-collapse: collapse; +} + +.table caption { + margin-bottom: 0.5rem; + font-weight: 500; +} + +.table th, +.table td { + padding: 0.75rem; + text-align: left; + border-bottom: 1px solid #eee; +} + +.table th { + border-bottom: 2px solid #ddd; +} + +.table tfoot td { + text-align: center; +} + +/* Estimates page specific styles */ +.estimates-header { + display: flex; + align-items: center; + margin-bottom: 1rem; +} + +.estimates-stop-id { + font-size: 1rem; + color: var(--subtitle-color); + margin-left: 0.5rem; +} + +.estimates-arrival { + color: #28a745; + font-weight: 500; +} + +.estimates-delayed { + color: #dc3545; +} + +.button-group { + display: flex; + gap: 1rem; + margin-bottom: 1.5rem; + flex-wrap: wrap; +} + +.button { + padding: 0.75rem 1rem; + background-color: var(--button-background-color); + color: white; + border: none; + border-radius: 8px; + font-size: 1rem; + font-weight: 500; + cursor: pointer; + text-align: center; + text-decoration: none; + display: inline-block; +} + +.button:hover { + background-color: var(--button-hover-background-color); +} + +.button:disabled { + background-color: var(--button-disabled-background-color); + cursor: not-allowed; +} + +.star-icon { + margin-right: 0.5rem; + color: #ccc; + fill: none; +} + +.star-icon.active { + color: var(--star-color); + /* Yellow color for active star */ + fill: var(--star-color); +} + +/* Pencil (edit) icon next to header */ +.edit-icon { + margin-right: 0.5rem; + color: #ccc; + cursor: pointer; + stroke-width: 2px; +} + +.edit-icon:hover { + color: var(--star-color); +} \ No newline at end of file diff --git a/src/frontend/src/styles/Map.css b/src/frontend/src/styles/Map.css new file mode 100644 index 0000000..3af112a --- /dev/null +++ b/src/frontend/src/styles/Map.css @@ -0,0 +1,86 @@ +/* Map page specific styles */ +.map-container { + height: calc(100vh - 140px); + margin: -16px; + margin-bottom: 1rem; + position: relative; +} + +/* Fullscreen map styles */ +.fullscreen-container { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + padding: 0; + margin: 0; + max-width: none; + overflow: hidden; +} + +.fullscreen-map { + width: 100%; + height: 100%; +} + +.fullscreen-loading { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + width: 100vw; + font-size: 1.8rem; + font-weight: 600; + color: var(--text-color); +} + +/* Map marker and popup styles */ +.stop-marker { + box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); + transition: all 0.2s ease-in-out; +} + +.stop-marker:hover { + transform: scale(1.2); +} + +.maplibregl-popup { + max-width: 250px; +} + +.maplibregl-popup-content { + padding: 12px; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +.popup-line-icons { + display: flex; + flex-wrap: wrap; + margin: 6px 0; + gap: 5px; +} + +.popup-line { + display: inline-block; + background-color: var(--button-background-color); + color: white; + padding: 2px 6px; + margin-right: 4px; + border-radius: 4px; + font-size: 0.8rem; + font-weight: 500; +} + +.popup-link { + display: block; + margin-top: 8px; + color: var(--button-background-color); + text-decoration: none; + font-weight: 500; +} + +.popup-link:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/src/frontend/src/styles/Pages.css b/src/frontend/src/styles/Pages.css new file mode 100644 index 0000000..90ffad2 --- /dev/null +++ b/src/frontend/src/styles/Pages.css @@ -0,0 +1,364 @@ +:root { + --background-color: #ffffff; + --text-color: #333333; + --subtitle-color: #444444; + --border-color: #eeeeee; + --button-background-color: #007bff; + --button-hover-background-color: #0069d9; + --button-disabled-background-color: #cccccc; + --star-color: #ffcc00; + --message-background-color: #f8f9fa; + + font-family: 'Outfit Variable', Roboto, Arial, sans-serif; +} + +[data-theme='dark'] { + --background-color: #121212; + --text-color: #ffffff; + --subtitle-color: #bbbbbb; + --border-color: #444444; + --button-background-color: #1e88e5; + --button-hover-background-color: #1565c0; + --button-disabled-background-color: #555555; + --star-color: #ffcc00; + --message-background-color: #333333; +} + +body { + background-color: var(--background-color); + color: var(--text-color); +} + +/* Mobile-first page styles */ + +/* Common page styles */ +.page-container { + max-width: 100%; + padding: 0 16px; + background-color: var(--background-color); + color: var(--text-color); +} + +.page-title { + font-size: 1.8rem; + margin-bottom: 1rem; + font-weight: 600; + color: var(--text-color); +} + +.page-subtitle { + font-size: 1.4rem; + margin-top: 1.5rem; + margin-bottom: 0.75rem; + font-weight: 500; + color: var(--subtitle-color); +} + +/* Form styles */ +.search-form { + margin-bottom: 1.5rem; +} + +.form-group { + margin-bottom: 1rem; + display: flex; + flex-direction: column; +} + +.form-label { + font-size: 0.9rem; + margin-bottom: 0.25rem; + font-weight: 500; +} + +.form-input { + padding: 0.75rem; + font-size: 1rem; + border: 1px solid var(--border-color); + border-radius: 8px; +} + +.form-button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 1rem; + + padding: 0.75rem 1rem; + background-color: var(--button-background-color); + color: white; + border: none; + border-radius: 8px; + font-size: 1rem; + font-weight: 500; + cursor: pointer; + width: 100%; + margin-top: 0.5rem; +} + +.form-button:hover { + background-color: var(--button-hover-background-color); +} + +/* List styles */ +.list-container { + margin-bottom: 1.5rem; +} + +.list { + list-style: none; + padding: 0; + margin: 0; +} + +.list-item { + padding: 1rem; + border-bottom: 1px solid var(--border-color); +} + +.list-item-link { + display: block; + color: var(--text-color); + text-decoration: none; + font-size: 1.1rem; /* Increased font size for stop name */ +} + +.list-item-link:hover { + color: var(--button-background-color); +} + +.list-item-link:hover .line-icon { + color: var(--text-color); +} + +.distance-info { + font-size: 0.9rem; + color: var(--subtitle-color); +} + +/* Message styles */ +.message { + padding: 1rem; + background-color: var(--message-background-color); + border-radius: 8px; + margin-bottom: 1rem; +} + +/* About page specific styles */ +.about-page { + text-align: center; + padding: 1rem; +} + +.about-version { + color: var(--subtitle-color); + font-size: 0.9rem; + margin-top: 2rem; +} + +.about-description { + margin-top: 1rem; + line-height: 1.6; +} + +/* Map page specific styles */ +.map-container { + height: calc(100vh - 140px); + margin: -16px; + margin-bottom: 1rem; + position: relative; +} + +/* Fullscreen map styles */ +.fullscreen-container { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + padding: 0; + margin: 0; + max-width: none; + overflow: hidden; +} + +.fullscreen-map { + width: 100%; + height: 100%; +} + +.fullscreen-loading { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + width: 100vw; + font-size: 1.8rem; + font-weight: 600; + color: var(--text-color); +} + +/* Map marker and popup styles */ +.stop-marker { + box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); + transition: all 0.2s ease-in-out; +} + +.stop-marker:hover { + transform: scale(1.2); +} + +.maplibregl-popup { + max-width: 250px; +} + +.maplibregl-popup-content { + padding: 12px; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +.popup-line-icons { + display: flex; + flex-wrap: wrap; + margin: 6px 0; + gap: 5px; +} + +.popup-line { + display: inline-block; + background-color: var(--button-background-color); + color: white; + padding: 2px 6px; + margin-right: 4px; + border-radius: 4px; + font-size: 0.8rem; + font-weight: 500; +} + +.popup-link { + display: block; + margin-top: 8px; + color: var(--button-background-color); + text-decoration: none; + font-weight: 500; +} + +.popup-link:hover { + text-decoration: underline; +} + +/* Estimates page specific styles */ +.estimates-header { + display: flex; + align-items: center; + margin-bottom: 1rem; +} + +.estimates-stop-id { + font-size: 1rem; + color: var(--subtitle-color); + margin-left: 0.5rem; +} + +.estimates-arrival { + color: #28a745; + font-weight: 500; +} + +.estimates-delayed { + color: #dc3545; +} + +.button-group { + display: flex; + gap: 1rem; + margin-bottom: 1.5rem; + flex-wrap: wrap; +} + +.button { + padding: 0.75rem 1rem; + background-color: var(--button-background-color); + color: white; + border: none; + border-radius: 8px; + font-size: 1rem; + font-weight: 500; + cursor: pointer; + text-align: center; + text-decoration: none; + display: inline-block; +} + +.button:hover { + background-color: var(--button-hover-background-color); +} + +.button:disabled { + background-color: var(--button-disabled-background-color); + cursor: not-allowed; +} + +.star-icon { + margin-right: 0.5rem; + color: #ccc; + fill: none; +} + +.star-icon.active { + color: var(--star-color); /* Yellow color for active star */ + fill: var(--star-color); +} + +/* Tablet and larger breakpoint */ +@media (min-width: 768px) { + .page-container { + width: 90%; + max-width: 768px; + margin: 0 auto; + } + + .page-title { + font-size: 2.2rem; + } + + .search-form { + display: flex; + align-items: flex-end; + gap: 1rem; + } + + .form-group { + flex: 1; + margin-bottom: 0; + } + + .form-button { + width: auto; + margin-top: 0; + } + + .list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 1rem; + } + + .list-item { + border: 1px solid var(--border-color); + border-radius: 8px; + margin-bottom: 0; + } +} + +/* Desktop breakpoint */ +@media (min-width: 1024px) { + .page-container { + max-width: 1024px; + } + + .list { + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + } +} \ No newline at end of file diff --git a/src/frontend/src/styles/Settings.css b/src/frontend/src/styles/Settings.css new file mode 100644 index 0000000..934577d --- /dev/null +++ b/src/frontend/src/styles/Settings.css @@ -0,0 +1,94 @@ +/* About page specific styles */ +.about-page { + text-align: center; + padding: 1rem; +} + +.about-version { + color: var(--subtitle-color); + font-size: 0.9rem; + margin-top: 2rem; +} + +.about-description { + margin-top: 1rem; + line-height: 1.6; +} + +.settings-section { + margin-bottom: 2em; + padding: 1rem; + border: 1px solid var(--border-color); + border-radius: 8px; + background-color: var(--message-background-color); + text-align: left; +} + +.settings-section h2 { + margin-bottom: 1em; +} + +.settings-content { + display: flex; + flex-direction: column; + align-items: flex-start; + margin-bottom: 1em; +} + +.settings-content-inline { + display: flex; + align-items: center; + margin-bottom: 1em; +} + +.settings-section .form-button { + margin-bottom: 1em; + padding: 0.75rem 1.5rem; + font-size: 1.1rem; +} + +.settings-section .form-select-inline { + margin-left: 0.5em; + padding: 0.5rem; + font-size: 1rem; + border: 1px solid var(--border-color); + border-radius: 8px; +} + +.settings-section .form-label-inline { + font-weight: 500; +} + +.settings-section .form-label { + display: block; + margin-bottom: 0.5em; + font-weight: 500; +} + +.settings-section .form-description { + margin-top: 0.5em; + font-size: 0.9rem; + color: var(--subtitle-color); +} + +.settings-section .form-details { + margin-top: 0.5em; + font-size: 0.9rem; + color: var(--subtitle-color); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 0.5rem; +} + +.settings-section .form-details summary { + cursor: pointer; + font-weight: 500; +} + +.settings-section .form-details p { + margin-top: 0.5em; +} + +.settings-section p { + margin-top: 0.5em; +} \ No newline at end of file diff --git a/src/frontend/src/vite-env.d.ts b/src/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/src/frontend/tsconfig.json b/src/frontend/tsconfig.json new file mode 100644 index 0000000..dc391a4 --- /dev/null +++ b/src/frontend/tsconfig.json @@ -0,0 +1,27 @@ +{ + "include": [ + "**/*", + "**/.server/**/*", + "**/.client/**/*", + ".react-router/types/**/*" + ], + "compilerOptions": { + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "types": ["node", "vite/client"], + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "rootDirs": [".", "./.react-router/types"], + "baseUrl": ".", + "paths": { + "~/*": ["./app/*"] + }, + "esModuleInterop": true, + "verbatimModuleSyntax": true, + "noEmit": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true + } +} diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts new file mode 100644 index 0000000..e7b5a95 --- /dev/null +++ b/src/frontend/vite.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + server: { + proxy: { + '^/api': { + target: 'https://localhost:7240', + secure: false + } + } + }, + build: { + rollupOptions: { + output: { + manualChunks: { + react: ['react', 'react-dom'], + router: ['react-router'], + leaflet: ['leaflet', 'react-leaflet', 'leaflet.locatecontrol', 'leaflet.markercluster'] + } + } + } + } +}) diff --git a/src/main.tsx b/src/main.tsx deleted file mode 100644 index c7a4db9..0000000 --- a/src/main.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import '@fontsource-variable/outfit' -import './styles/Pages.css' - -import { createRoot } from 'react-dom/client' -import { createBrowserRouter, Navigate, RouterProvider } from 'react-router' -import { StopList } from './pages/StopList.tsx' -import { Estimates } from './pages/Estimates.tsx' -import { StopMap } from './pages/Map.tsx' -import { Layout } from './Layout.tsx' -import { Settings } from './pages/Settings.tsx' -import { AppProvider } from './AppContext.tsx' -import ErrorBoundary from './ErrorBoundary' - -const router = createBrowserRouter([ - { - path: '/', - element: , - }, - { - path: '/stops', - element: , - }, - { - path: '/map', - element: , - }, - { - path: '/estimates/:stopId', - element: - }, - { - path: '/settings', - element: - } -]) - -createRoot(document.getElementById('root')!).render( - - - - - -) diff --git a/src/pages/Estimates.tsx b/src/pages/Estimates.tsx deleted file mode 100644 index 7cf941a..0000000 --- a/src/pages/Estimates.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { JSX, useEffect, useState } from "react"; -import { useParams } from "react-router"; -import StopDataProvider from "../data/StopDataProvider"; -import { Star, Edit2 } from 'lucide-react'; -import "../styles/Estimates.css"; -import { RegularTable } from "../components/RegularTable"; -import { useApp } from "../AppContext"; -import { GroupedTable } from "../components/GroupedTable"; - -export interface StopDetails { - stop: { - id: number; - name: string; - latitude: number; - longitude: number; - } - estimates: { - line: string; - route: string; - minutes: number; - meters: number; - }[] -} - -const loadData = async (stopId: string) => { - const resp = await fetch(`/api/GetStopEstimates?id=${stopId}`); - return await resp.json(); -}; - -export function Estimates(): JSX.Element { - const params = useParams(); - const stopIdNum = parseInt(params.stopId ?? ""); - const [customName, setCustomName] = useState(undefined); - const [data, setData] = useState(null); - const [dataDate, setDataDate] = useState(null); - const [favourited, setFavourited] = useState(false); - const { tableStyle } = useApp(); - - useEffect(() => { - loadData(params.stopId!) - .then((body: StopDetails) => { - setData(body); - setDataDate(new Date()); - setCustomName(StopDataProvider.getCustomName(stopIdNum)); - }) - - - StopDataProvider.pushRecent(parseInt(params.stopId ?? "")); - - setFavourited( - StopDataProvider.isFavourite(parseInt(params.stopId ?? "")) - ); - }, [params.stopId]); - - - const toggleFavourite = () => { - if (favourited) { - StopDataProvider.removeFavourite(stopIdNum); - setFavourited(false); - } else { - StopDataProvider.addFavourite(stopIdNum); - setFavourited(true); - } - } - - const handleRename = () => { - const current = customName ?? data?.stop.name; - const input = window.prompt('Custom name for this stop:', current); - if (input === null) return; // cancelled - const trimmed = input.trim(); - if (trimmed === '') { - StopDataProvider.removeCustomName(stopIdNum); - setCustomName(undefined); - } else { - StopDataProvider.setCustomName(stopIdNum, trimmed); - setCustomName(trimmed); - } - }; - - if (data === null) return

    Cargando datos en tiempo real...

    - - return ( -
    -
    -

    - - - {(customName ?? data.stop.name)} ({data.stop.id}) -

    -
    - -
    - {tableStyle === 'grouped' ? - : - } -
    -
    - ) -} diff --git a/src/pages/Map.tsx b/src/pages/Map.tsx deleted file mode 100644 index 1f0a9e0..0000000 --- a/src/pages/Map.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import StopDataProvider, { Stop } from "../data/StopDataProvider"; - -import 'leaflet/dist/leaflet.css' -import 'react-leaflet-markercluster/styles' - -import { useEffect, useState } from 'react'; -import LineIcon from '../components/LineIcon'; -import { Link } from 'react-router'; -import { MapContainer, TileLayer, Marker, Popup, useMapEvents } from "react-leaflet"; -import MarkerClusterGroup from "react-leaflet-markercluster"; -import { Icon, LatLngTuple } from "leaflet"; -import { EnhancedLocateControl } from "../controls/LocateControl"; -import { useApp } from "../AppContext"; - -const icon = new Icon({ - iconUrl: '/map-pin-icon.png', - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], - shadowSize: [41, 41] -}); - -// Componente auxiliar para detectar cambios en el mapa -const MapEventHandler = () => { - const { updateMapState } = useApp(); - - const map = useMapEvents({ - moveend: () => { - const center = map.getCenter(); - const zoom = map.getZoom(); - updateMapState([center.lat, center.lng], zoom); - } - }); - - return null; -}; - -// Componente principal del mapa -export function StopMap() { - const [stops, setStops] = useState([]); - const { mapState } = useApp(); - - useEffect(() => { - StopDataProvider.getStops().then(setStops); - }, []); - - return ( - - - - - - {stops.map(stop => ( - - - {StopDataProvider.getDisplayName(stop)} -
    - {stop.lines.map((line) => ( - - ))} -
    -
    - ))} -
    -
    - ); -} diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx deleted file mode 100644 index 1ad15ab..0000000 --- a/src/pages/Settings.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { useApp } from "../AppContext"; -import "../styles/Settings.css"; - -export function Settings() { - const { theme, setTheme, tableStyle, setTableStyle, mapPositionMode, setMapPositionMode } = useApp(); - - return ( -
    -

    Sobre UrbanoVigo Web

    -

    - Aplicación web para encontrar paradas y tiempos de llegada de los autobuses - urbanos de Vigo, España. -

    -
    -

    Ajustes

    -
    - - -
    -
    - - -
    -
    - - -
    -
    - ¿Qué significa esto? -

    - La tabla de horarios puede mostrarse de dos formas: -

    -
    -
    Mostrar por orden
    -
    Las paradas se muestran en el orden en que se visitan. Aplicaciones como Infobus (Vitrasa) usan este estilo.
    -
    Agrupar por línea
    -
    Las paradas se agrupan por la línea de autobús. Aplicaciones como iTranvias (A Coruña) o Moovit (más o menos) usan este estilo.
    -
    -
    -
    -

    Créditos

    -

    - - Código en GitHub - - - Desarrollado por - Ariel Costas - -

    -

    - Datos obtenidos de datos.vigo.org bajo - licencia Open Data Commons Attribution License -

    -
    - ) -} \ No newline at end of file diff --git a/src/pages/StopList.tsx b/src/pages/StopList.tsx deleted file mode 100644 index b965456..0000000 --- a/src/pages/StopList.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { useEffect, useMemo, useRef, useState } from "react"; -import StopDataProvider, { Stop } from "../data/StopDataProvider"; -import StopItem from "../components/StopItem"; -import Fuse from "fuse.js"; - -const placeholders = [ - "Urzaiz", - "Gran Vía", - "Castelao", - "García Barbón", - "Valladares", - "Florida", - "Pizarro", - "Estrada Madrid", - "Sanjurjo Badía" -]; - -export function StopList() { - const [data, setData] = useState(null) - const [searchResults, setSearchResults] = useState(null); - const searchTimeout = useRef(null); - - const randomPlaceholder = useMemo(() => placeholders[Math.floor(Math.random() * placeholders.length)], []); - const fuse = useMemo(() => new Fuse(data || [], { threshold: 0.3, keys: ['name.original'] }), [data]); - - useEffect(() => { - StopDataProvider.getStops().then((stops: Stop[]) => setData(stops)) - }, []); - - const handleStopSearch = (event: React.ChangeEvent) => { - const stopName = event.target.value || ""; - - if (searchTimeout.current) { - clearTimeout(searchTimeout.current); - } - - searchTimeout.current = setTimeout(() => { - if (stopName.length === 0) { - setSearchResults(null); - return; - } - - if (!data) { - console.error("No data available for search"); - return; - } - - const results = fuse.search(stopName); - const items = results.map(result => result.item); - setSearchResults(items); - }, 300); - } - - const favouritedStops = useMemo(() => { - return data?.filter(stop => stop.favourite) ?? [] - }, [data]) - - const recentStops = useMemo(() => { - // no recent items if data not loaded - if (!data) return null; - const recentIds = StopDataProvider.getRecent(); - if (recentIds.length === 0) return null; - // map and filter out missing entries - const stopsList = recentIds - .map(id => data.find(stop => stop.stopId === id)) - .filter((s): s is Stop => Boolean(s)); - return stopsList.reverse(); - }, [data]); - - if (data === null) return

    Loading...

    - - return ( -
    -

    UrbanoVigo Web

    - -
    -
    - - -
    -
    - - {searchResults && searchResults.length > 0 && ( -
    -

    Resultados de la búsqueda

    -
      - {searchResults.map((stop: Stop) => ( - - ))} -
    -
    - )} - -
    -

    Paradas favoritas

    - - {favouritedStops?.length === 0 && ( -

    - Accede a una parada y márcala como favorita para verla aquí. -

    - )} - -
      - {favouritedStops?.sort((a, b) => a.stopId - b.stopId).map((stop: Stop) => ( - - ))} -
    -
    - - {recentStops && recentStops.length > 0 && ( -
    -

    Recientes

    - -
      - {recentStops.map((stop: Stop) => ( - - ))} -
    -
    - )} - -
    -

    Paradas

    - -
      - {data?.sort((a, b) => a.stopId - b.stopId).map((stop: Stop) => ( - - ))} -
    -
    -
    - ) -} diff --git a/src/styles/Estimates.css b/src/styles/Estimates.css deleted file mode 100644 index 86ca09b..0000000 --- a/src/styles/Estimates.css +++ /dev/null @@ -1,105 +0,0 @@ -.table-responsive { - overflow-x: auto; - margin-bottom: 1.5rem; -} - -.table { - width: 100%; - border-collapse: collapse; -} - -.table caption { - margin-bottom: 0.5rem; - font-weight: 500; -} - -.table th, -.table td { - padding: 0.75rem; - text-align: left; - border-bottom: 1px solid #eee; -} - -.table th { - border-bottom: 2px solid #ddd; -} - -.table tfoot td { - text-align: center; -} - -/* Estimates page specific styles */ -.estimates-header { - display: flex; - align-items: center; - margin-bottom: 1rem; -} - -.estimates-stop-id { - font-size: 1rem; - color: var(--subtitle-color); - margin-left: 0.5rem; -} - -.estimates-arrival { - color: #28a745; - font-weight: 500; -} - -.estimates-delayed { - color: #dc3545; -} - -.button-group { - display: flex; - gap: 1rem; - margin-bottom: 1.5rem; - flex-wrap: wrap; -} - -.button { - padding: 0.75rem 1rem; - background-color: var(--button-background-color); - color: white; - border: none; - border-radius: 8px; - font-size: 1rem; - font-weight: 500; - cursor: pointer; - text-align: center; - text-decoration: none; - display: inline-block; -} - -.button:hover { - background-color: var(--button-hover-background-color); -} - -.button:disabled { - background-color: var(--button-disabled-background-color); - cursor: not-allowed; -} - -.star-icon { - margin-right: 0.5rem; - color: #ccc; - fill: none; -} - -.star-icon.active { - color: var(--star-color); - /* Yellow color for active star */ - fill: var(--star-color); -} - -/* Pencil (edit) icon next to header */ -.edit-icon { - margin-right: 0.5rem; - color: #ccc; - cursor: pointer; - stroke-width: 2px; -} - -.edit-icon:hover { - color: var(--star-color); -} \ No newline at end of file diff --git a/src/styles/Map.css b/src/styles/Map.css deleted file mode 100644 index 3af112a..0000000 --- a/src/styles/Map.css +++ /dev/null @@ -1,86 +0,0 @@ -/* Map page specific styles */ -.map-container { - height: calc(100vh - 140px); - margin: -16px; - margin-bottom: 1rem; - position: relative; -} - -/* Fullscreen map styles */ -.fullscreen-container { - position: absolute; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - padding: 0; - margin: 0; - max-width: none; - overflow: hidden; -} - -.fullscreen-map { - width: 100%; - height: 100%; -} - -.fullscreen-loading { - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - width: 100vw; - font-size: 1.8rem; - font-weight: 600; - color: var(--text-color); -} - -/* Map marker and popup styles */ -.stop-marker { - box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); - transition: all 0.2s ease-in-out; -} - -.stop-marker:hover { - transform: scale(1.2); -} - -.maplibregl-popup { - max-width: 250px; -} - -.maplibregl-popup-content { - padding: 12px; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); -} - -.popup-line-icons { - display: flex; - flex-wrap: wrap; - margin: 6px 0; - gap: 5px; -} - -.popup-line { - display: inline-block; - background-color: var(--button-background-color); - color: white; - padding: 2px 6px; - margin-right: 4px; - border-radius: 4px; - font-size: 0.8rem; - font-weight: 500; -} - -.popup-link { - display: block; - margin-top: 8px; - color: var(--button-background-color); - text-decoration: none; - font-weight: 500; -} - -.popup-link:hover { - text-decoration: underline; -} \ No newline at end of file diff --git a/src/styles/Pages.css b/src/styles/Pages.css deleted file mode 100644 index 90ffad2..0000000 --- a/src/styles/Pages.css +++ /dev/null @@ -1,364 +0,0 @@ -:root { - --background-color: #ffffff; - --text-color: #333333; - --subtitle-color: #444444; - --border-color: #eeeeee; - --button-background-color: #007bff; - --button-hover-background-color: #0069d9; - --button-disabled-background-color: #cccccc; - --star-color: #ffcc00; - --message-background-color: #f8f9fa; - - font-family: 'Outfit Variable', Roboto, Arial, sans-serif; -} - -[data-theme='dark'] { - --background-color: #121212; - --text-color: #ffffff; - --subtitle-color: #bbbbbb; - --border-color: #444444; - --button-background-color: #1e88e5; - --button-hover-background-color: #1565c0; - --button-disabled-background-color: #555555; - --star-color: #ffcc00; - --message-background-color: #333333; -} - -body { - background-color: var(--background-color); - color: var(--text-color); -} - -/* Mobile-first page styles */ - -/* Common page styles */ -.page-container { - max-width: 100%; - padding: 0 16px; - background-color: var(--background-color); - color: var(--text-color); -} - -.page-title { - font-size: 1.8rem; - margin-bottom: 1rem; - font-weight: 600; - color: var(--text-color); -} - -.page-subtitle { - font-size: 1.4rem; - margin-top: 1.5rem; - margin-bottom: 0.75rem; - font-weight: 500; - color: var(--subtitle-color); -} - -/* Form styles */ -.search-form { - margin-bottom: 1.5rem; -} - -.form-group { - margin-bottom: 1rem; - display: flex; - flex-direction: column; -} - -.form-label { - font-size: 0.9rem; - margin-bottom: 0.25rem; - font-weight: 500; -} - -.form-input { - padding: 0.75rem; - font-size: 1rem; - border: 1px solid var(--border-color); - border-radius: 8px; -} - -.form-button { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 1rem; - - padding: 0.75rem 1rem; - background-color: var(--button-background-color); - color: white; - border: none; - border-radius: 8px; - font-size: 1rem; - font-weight: 500; - cursor: pointer; - width: 100%; - margin-top: 0.5rem; -} - -.form-button:hover { - background-color: var(--button-hover-background-color); -} - -/* List styles */ -.list-container { - margin-bottom: 1.5rem; -} - -.list { - list-style: none; - padding: 0; - margin: 0; -} - -.list-item { - padding: 1rem; - border-bottom: 1px solid var(--border-color); -} - -.list-item-link { - display: block; - color: var(--text-color); - text-decoration: none; - font-size: 1.1rem; /* Increased font size for stop name */ -} - -.list-item-link:hover { - color: var(--button-background-color); -} - -.list-item-link:hover .line-icon { - color: var(--text-color); -} - -.distance-info { - font-size: 0.9rem; - color: var(--subtitle-color); -} - -/* Message styles */ -.message { - padding: 1rem; - background-color: var(--message-background-color); - border-radius: 8px; - margin-bottom: 1rem; -} - -/* About page specific styles */ -.about-page { - text-align: center; - padding: 1rem; -} - -.about-version { - color: var(--subtitle-color); - font-size: 0.9rem; - margin-top: 2rem; -} - -.about-description { - margin-top: 1rem; - line-height: 1.6; -} - -/* Map page specific styles */ -.map-container { - height: calc(100vh - 140px); - margin: -16px; - margin-bottom: 1rem; - position: relative; -} - -/* Fullscreen map styles */ -.fullscreen-container { - position: absolute; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - padding: 0; - margin: 0; - max-width: none; - overflow: hidden; -} - -.fullscreen-map { - width: 100%; - height: 100%; -} - -.fullscreen-loading { - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - width: 100vw; - font-size: 1.8rem; - font-weight: 600; - color: var(--text-color); -} - -/* Map marker and popup styles */ -.stop-marker { - box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); - transition: all 0.2s ease-in-out; -} - -.stop-marker:hover { - transform: scale(1.2); -} - -.maplibregl-popup { - max-width: 250px; -} - -.maplibregl-popup-content { - padding: 12px; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); -} - -.popup-line-icons { - display: flex; - flex-wrap: wrap; - margin: 6px 0; - gap: 5px; -} - -.popup-line { - display: inline-block; - background-color: var(--button-background-color); - color: white; - padding: 2px 6px; - margin-right: 4px; - border-radius: 4px; - font-size: 0.8rem; - font-weight: 500; -} - -.popup-link { - display: block; - margin-top: 8px; - color: var(--button-background-color); - text-decoration: none; - font-weight: 500; -} - -.popup-link:hover { - text-decoration: underline; -} - -/* Estimates page specific styles */ -.estimates-header { - display: flex; - align-items: center; - margin-bottom: 1rem; -} - -.estimates-stop-id { - font-size: 1rem; - color: var(--subtitle-color); - margin-left: 0.5rem; -} - -.estimates-arrival { - color: #28a745; - font-weight: 500; -} - -.estimates-delayed { - color: #dc3545; -} - -.button-group { - display: flex; - gap: 1rem; - margin-bottom: 1.5rem; - flex-wrap: wrap; -} - -.button { - padding: 0.75rem 1rem; - background-color: var(--button-background-color); - color: white; - border: none; - border-radius: 8px; - font-size: 1rem; - font-weight: 500; - cursor: pointer; - text-align: center; - text-decoration: none; - display: inline-block; -} - -.button:hover { - background-color: var(--button-hover-background-color); -} - -.button:disabled { - background-color: var(--button-disabled-background-color); - cursor: not-allowed; -} - -.star-icon { - margin-right: 0.5rem; - color: #ccc; - fill: none; -} - -.star-icon.active { - color: var(--star-color); /* Yellow color for active star */ - fill: var(--star-color); -} - -/* Tablet and larger breakpoint */ -@media (min-width: 768px) { - .page-container { - width: 90%; - max-width: 768px; - margin: 0 auto; - } - - .page-title { - font-size: 2.2rem; - } - - .search-form { - display: flex; - align-items: flex-end; - gap: 1rem; - } - - .form-group { - flex: 1; - margin-bottom: 0; - } - - .form-button { - width: auto; - margin-top: 0; - } - - .list { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 1rem; - } - - .list-item { - border: 1px solid var(--border-color); - border-radius: 8px; - margin-bottom: 0; - } -} - -/* Desktop breakpoint */ -@media (min-width: 1024px) { - .page-container { - max-width: 1024px; - } - - .list { - grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - } -} \ No newline at end of file diff --git a/src/styles/Settings.css b/src/styles/Settings.css deleted file mode 100644 index 934577d..0000000 --- a/src/styles/Settings.css +++ /dev/null @@ -1,94 +0,0 @@ -/* About page specific styles */ -.about-page { - text-align: center; - padding: 1rem; -} - -.about-version { - color: var(--subtitle-color); - font-size: 0.9rem; - margin-top: 2rem; -} - -.about-description { - margin-top: 1rem; - line-height: 1.6; -} - -.settings-section { - margin-bottom: 2em; - padding: 1rem; - border: 1px solid var(--border-color); - border-radius: 8px; - background-color: var(--message-background-color); - text-align: left; -} - -.settings-section h2 { - margin-bottom: 1em; -} - -.settings-content { - display: flex; - flex-direction: column; - align-items: flex-start; - margin-bottom: 1em; -} - -.settings-content-inline { - display: flex; - align-items: center; - margin-bottom: 1em; -} - -.settings-section .form-button { - margin-bottom: 1em; - padding: 0.75rem 1.5rem; - font-size: 1.1rem; -} - -.settings-section .form-select-inline { - margin-left: 0.5em; - padding: 0.5rem; - font-size: 1rem; - border: 1px solid var(--border-color); - border-radius: 8px; -} - -.settings-section .form-label-inline { - font-weight: 500; -} - -.settings-section .form-label { - display: block; - margin-bottom: 0.5em; - font-weight: 500; -} - -.settings-section .form-description { - margin-top: 0.5em; - font-size: 0.9rem; - color: var(--subtitle-color); -} - -.settings-section .form-details { - margin-top: 0.5em; - font-size: 0.9rem; - color: var(--subtitle-color); - border: 1px solid var(--border-color); - border-radius: 8px; - padding: 0.5rem; -} - -.settings-section .form-details summary { - cursor: pointer; - font-weight: 500; -} - -.settings-section .form-details p { - margin-top: 0.5em; -} - -.settings-section p { - margin-top: 0.5em; -} \ No newline at end of file diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/staticwebapp.config.json b/staticwebapp.config.json deleted file mode 100644 index 5eaaf6c..0000000 --- a/staticwebapp.config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "navigationFallback": { - "rewrite": "/index.html" - }, - "globalHeaders": { - "X-Content-Type-Options": "nosniff", - "X-Frame-Options": "DENY", - "X-XSS-Protection": "1; mode=block", - "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload", - "Referrer-Policy": "no-referrer", - "X-Robots-Tag": "none" - } -} diff --git a/swa-cli.config.json b/swa-cli.config.json deleted file mode 100644 index 5f8a3ac..0000000 --- a/swa-cli.config.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "https://aka.ms/azure/static-web-apps-cli/schema", - "configurations": { - "urbanovigo-web": { - "appLocation": ".", - "apiLocation": "Backend", - "outputLocation": "dist", - "apiLanguage": "dotnetisolated", - "apiVersion": "8.0", - "appBuildCommand": "npm run build", - "apiBuildCommand": "dotnet publish -c Release", - "run": "npm run dev", - "appDevserverUrl": "http://localhost:5173" - } - } -} \ No newline at end of file diff --git a/tsconfig.app.json b/tsconfig.app.json deleted file mode 100644 index 221fe26..0000000 --- a/tsconfig.app.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src", "public/sw.js"] -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 1ffef60..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/tsconfig.node.json b/tsconfig.node.json deleted file mode 100644 index 0d3d714..0000000 --- a/tsconfig.node.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "lib": ["ES2023"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["vite.config.ts"] -} diff --git a/vite.config.ts b/vite.config.ts deleted file mode 100644 index 4cb4be2..0000000 --- a/vite.config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react-swc' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], - server: { - proxy: { - '^/api': { - target: 'http://localhost:7071', - changeOrigin: true - } - } - }, - build: { - rollupOptions: { - output: { - manualChunks: { - react: ['react', 'react-dom'], - router: ['react-router'], - leaflet: ['leaflet', 'react-leaflet', 'leaflet.locatecontrol', 'leaflet.markercluster'] - } - } - } - } -}) -- cgit v1.3